Merge branch 'akpm' (patches from Andrew Morton)
Merge second patch-bomb from Andrew Morton: - a few hotfixes - drivers/dma updates - MAINTAINERS updates - Quite a lot of lib/ updates - checkpatch updates - binfmt updates - autofs4 - drivers/rtc/ - various small tweaks to less used filesystems - ipc/ updates - kernel/watchdog.c changes * emailed patches from Andrew Morton <akpm@linux-foundation.org>: (135 commits) mm: softdirty: enable write notifications on VMAs after VM_SOFTDIRTY cleared kernel/param: consolidate __{start,stop}___param[] in <linux/moduleparam.h> ia64: remove duplicate declarations of __per_cpu_start[] and __per_cpu_end[] frv: remove unused declarations of __start___ex_table and __stop___ex_table kvm: ensure hard lockup detection is disabled by default kernel/watchdog.c: control hard lockup detection default staging: rtl8192u: use %*pEn to escape buffer staging: rtl8192e: use %*pEn to escape buffer staging: wlan-ng: use %*pEhp to print SN lib80211: remove unused print_ssid() wireless: hostap: proc: print properly escaped SSID wireless: ipw2x00: print SSID via %*pE wireless: libertas: print esaped string via %*pE lib/vsprintf: add %*pE[achnops] format specifier lib / string_helpers: introduce string_escape_mem() lib / string_helpers: refactoring the test suite lib / string_helpers: move documentation to c-file include/linux: remove strict_strto* definitions arch/x86/mm/numa.c: fix boot failure when all nodes are hotpluggable fs: check bh blocknr earlier when searching lru ...
This commit is contained in:
commit
dfe2c6dcc8
@ -15,39 +15,50 @@ First you must mount binfmt_misc:
|
|||||||
mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc
|
mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc
|
||||||
|
|
||||||
To actually register a new binary type, you have to set up a string looking like
|
To actually register a new binary type, you have to set up a string looking like
|
||||||
:name:type:offset:magic:mask:interpreter:flags (where you can choose the ':' upon
|
:name:type:offset:magic:mask:interpreter:flags (where you can choose the ':'
|
||||||
your needs) and echo it to /proc/sys/fs/binfmt_misc/register.
|
upon your needs) and echo it to /proc/sys/fs/binfmt_misc/register.
|
||||||
|
|
||||||
Here is what the fields mean:
|
Here is what the fields mean:
|
||||||
- 'name' is an identifier string. A new /proc file will be created with this
|
- 'name' is an identifier string. A new /proc file will be created with this
|
||||||
name below /proc/sys/fs/binfmt_misc
|
name below /proc/sys/fs/binfmt_misc; cannot contain slashes '/' for obvious
|
||||||
|
reasons.
|
||||||
- 'type' is the type of recognition. Give 'M' for magic and 'E' for extension.
|
- 'type' is the type of recognition. Give 'M' for magic and 'E' for extension.
|
||||||
- 'offset' is the offset of the magic/mask in the file, counted in bytes. This
|
- 'offset' is the offset of the magic/mask in the file, counted in bytes. This
|
||||||
defaults to 0 if you omit it (i.e. you write ':name:type::magic...')
|
defaults to 0 if you omit it (i.e. you write ':name:type::magic...'). Ignored
|
||||||
|
when using filename extension matching.
|
||||||
- 'magic' is the byte sequence binfmt_misc is matching for. The magic string
|
- 'magic' is the byte sequence binfmt_misc is matching for. The magic string
|
||||||
may contain hex-encoded characters like \x0a or \xA4. In a shell environment
|
may contain hex-encoded characters like \x0a or \xA4. Note that you must
|
||||||
you will have to write \\x0a to prevent the shell from eating your \.
|
escape any NUL bytes; parsing halts at the first one. In a shell environment
|
||||||
|
you might have to write \\x0a to prevent the shell from eating your \.
|
||||||
If you chose filename extension matching, this is the extension to be
|
If you chose filename extension matching, this is the extension to be
|
||||||
recognised (without the '.', the \x0a specials are not allowed). Extension
|
recognised (without the '.', the \x0a specials are not allowed). Extension
|
||||||
matching is case sensitive!
|
matching is case sensitive, and slashes '/' are not allowed!
|
||||||
- 'mask' is an (optional, defaults to all 0xff) mask. You can mask out some
|
- 'mask' is an (optional, defaults to all 0xff) mask. You can mask out some
|
||||||
bits from matching by supplying a string like magic and as long as magic.
|
bits from matching by supplying a string like magic and as long as magic.
|
||||||
The mask is anded with the byte sequence of the file.
|
The mask is anded with the byte sequence of the file. Note that you must
|
||||||
|
escape any NUL bytes; parsing halts at the first one. Ignored when using
|
||||||
|
filename extension matching.
|
||||||
- 'interpreter' is the program that should be invoked with the binary as first
|
- 'interpreter' is the program that should be invoked with the binary as first
|
||||||
argument (specify the full path)
|
argument (specify the full path)
|
||||||
- 'flags' is an optional field that controls several aspects of the invocation
|
- 'flags' is an optional field that controls several aspects of the invocation
|
||||||
of the interpreter. It is a string of capital letters, each controls a certain
|
of the interpreter. It is a string of capital letters, each controls a
|
||||||
aspect. The following flags are supported -
|
certain aspect. The following flags are supported -
|
||||||
'P' - preserve-argv[0]. Legacy behavior of binfmt_misc is to overwrite the
|
'P' - preserve-argv[0]. Legacy behavior of binfmt_misc is to overwrite
|
||||||
original argv[0] with the full path to the binary. When this flag is
|
the original argv[0] with the full path to the binary. When this
|
||||||
included, binfmt_misc will add an argument to the argument vector for
|
flag is included, binfmt_misc will add an argument to the argument
|
||||||
this purpose, thus preserving the original argv[0].
|
vector for this purpose, thus preserving the original argv[0].
|
||||||
|
e.g. If your interp is set to /bin/foo and you run `blah` (which is
|
||||||
|
in /usr/local/bin), then the kernel will execute /bin/foo with
|
||||||
|
argv[] set to ["/bin/foo", "/usr/local/bin/blah", "blah"]. The
|
||||||
|
interp has to be aware of this so it can execute /usr/local/bin/blah
|
||||||
|
with argv[] set to ["blah"].
|
||||||
'O' - open-binary. Legacy behavior of binfmt_misc is to pass the full path
|
'O' - open-binary. Legacy behavior of binfmt_misc is to pass the full path
|
||||||
of the binary to the interpreter as an argument. When this flag is
|
of the binary to the interpreter as an argument. When this flag is
|
||||||
included, binfmt_misc will open the file for reading and pass its
|
included, binfmt_misc will open the file for reading and pass its
|
||||||
descriptor as an argument, instead of the full path, thus allowing
|
descriptor as an argument, instead of the full path, thus allowing
|
||||||
the interpreter to execute non-readable binaries. This feature should
|
the interpreter to execute non-readable binaries. This feature
|
||||||
be used with care - the interpreter has to be trusted not to emit
|
should be used with care - the interpreter has to be trusted not to
|
||||||
the contents of the non-readable binary.
|
emit the contents of the non-readable binary.
|
||||||
'C' - credentials. Currently, the behavior of binfmt_misc is to calculate
|
'C' - credentials. Currently, the behavior of binfmt_misc is to calculate
|
||||||
the credentials and security token of the new process according to
|
the credentials and security token of the new process according to
|
||||||
the interpreter. When this flag is included, these attributes are
|
the interpreter. When this flag is included, these attributes are
|
||||||
@ -58,7 +69,7 @@ Here is what the fields mean:
|
|||||||
|
|
||||||
|
|
||||||
There are some restrictions:
|
There are some restrictions:
|
||||||
- the whole register string may not exceed 255 characters
|
- the whole register string may not exceed 1920 characters
|
||||||
- the magic must reside in the first 128 bytes of the file, i.e.
|
- the magic must reside in the first 128 bytes of the file, i.e.
|
||||||
offset+size(magic) has to be less than 128
|
offset+size(magic) has to be less than 128
|
||||||
- the interpreter string may not exceed 127 characters
|
- the interpreter string may not exceed 127 characters
|
||||||
@ -110,7 +121,4 @@ passes it the full filename (or the file descriptor) to use. Using $PATH can
|
|||||||
cause unexpected behaviour and can be a security hazard.
|
cause unexpected behaviour and can be a security hazard.
|
||||||
|
|
||||||
|
|
||||||
There is a web page about binfmt_misc at
|
|
||||||
http://www.tat.physik.uni-tuebingen.de
|
|
||||||
|
|
||||||
Richard Günther <rguenth@tat.physik.uni-tuebingen.de>
|
Richard Günther <rguenth@tat.physik.uni-tuebingen.de>
|
||||||
|
18
Documentation/devicetree/bindings/i2c/ti,bq32k.txt
Normal file
18
Documentation/devicetree/bindings/i2c/ti,bq32k.txt
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
* TI BQ32000 I2C Serial Real-Time Clock
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: Should contain "ti,bq32000".
|
||||||
|
- reg: I2C address for chip
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
- trickle-resistor-ohms : Selected resistor for trickle charger
|
||||||
|
Values usable are 1120 and 20180
|
||||||
|
Should be given if trickle charger should be enabled
|
||||||
|
- trickle-diode-disable : Do not use internal trickle charger diode
|
||||||
|
Should be given if internal trickle charger diode should be disabled
|
||||||
|
Example:
|
||||||
|
bq32000: rtc@68 {
|
||||||
|
compatible = "ti,bq32000";
|
||||||
|
trickle-resistor-ohms = <1120>;
|
||||||
|
reg = <0x68>;
|
||||||
|
};
|
@ -35,7 +35,6 @@ catalyst,24c32 i2c serial eeprom
|
|||||||
cirrus,cs42l51 Cirrus Logic CS42L51 audio codec
|
cirrus,cs42l51 Cirrus Logic CS42L51 audio codec
|
||||||
dallas,ds1307 64 x 8, Serial, I2C Real-Time Clock
|
dallas,ds1307 64 x 8, Serial, I2C Real-Time Clock
|
||||||
dallas,ds1338 I2C RTC with 56-Byte NV RAM
|
dallas,ds1338 I2C RTC with 56-Byte NV RAM
|
||||||
dallas,ds1339 I2C Serial Real-Time Clock
|
|
||||||
dallas,ds1340 I2C RTC with Trickle Charger
|
dallas,ds1340 I2C RTC with Trickle Charger
|
||||||
dallas,ds1374 I2C, 32-Bit Binary Counter Watchdog RTC with Trickle Charger and Reset Input/Output
|
dallas,ds1374 I2C, 32-Bit Binary Counter Watchdog RTC with Trickle Charger and Reset Input/Output
|
||||||
dallas,ds1631 High-Precision Digital Thermometer
|
dallas,ds1631 High-Precision Digital Thermometer
|
||||||
|
18
Documentation/devicetree/bindings/rtc/dallas,ds1339.txt
Normal file
18
Documentation/devicetree/bindings/rtc/dallas,ds1339.txt
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
* Dallas DS1339 I2C Serial Real-Time Clock
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: Should contain "dallas,ds1339".
|
||||||
|
- reg: I2C address for chip
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
- trickle-resistor-ohms : Selected resistor for trickle charger
|
||||||
|
Values usable for ds1339 are 250, 2000, 4000
|
||||||
|
Should be given if trickle charger should be enabled
|
||||||
|
- trickle-diode-disable : Do not use internal trickle charger diode
|
||||||
|
Should be given if internal trickle charger diode should be disabled
|
||||||
|
Example:
|
||||||
|
ds1339: rtc@68 {
|
||||||
|
compatible = "dallas,ds1339";
|
||||||
|
trickle-resistor-ohms = <250>;
|
||||||
|
reg = <0x68>;
|
||||||
|
};
|
@ -3,7 +3,10 @@
|
|||||||
Required properties:
|
Required properties:
|
||||||
- compatible: should be one of the following.
|
- compatible: should be one of the following.
|
||||||
* "samsung,s3c2410-rtc" - for controllers compatible with s3c2410 rtc.
|
* "samsung,s3c2410-rtc" - for controllers compatible with s3c2410 rtc.
|
||||||
|
* "samsung,s3c2416-rtc" - for controllers compatible with s3c2416 rtc.
|
||||||
|
* "samsung,s3c2443-rtc" - for controllers compatible with s3c2443 rtc.
|
||||||
* "samsung,s3c6410-rtc" - for controllers compatible with s3c6410 rtc.
|
* "samsung,s3c6410-rtc" - for controllers compatible with s3c6410 rtc.
|
||||||
|
* "samsung,exynos3250-rtc" - for controllers compatible with exynos3250 rtc.
|
||||||
- reg: physical base address of the controller and length of memory mapped
|
- reg: physical base address of the controller and length of memory mapped
|
||||||
region.
|
region.
|
||||||
- interrupts: Two interrupt numbers to the cpu should be specified. First
|
- interrupts: Two interrupt numbers to the cpu should be specified. First
|
||||||
|
520
Documentation/filesystems/autofs4.txt
Normal file
520
Documentation/filesystems/autofs4.txt
Normal file
@ -0,0 +1,520 @@
|
|||||||
|
<head>
|
||||||
|
<style> p { max-width:50em} ol, ul {max-width: 40em}</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
autofs - how it works
|
||||||
|
=====================
|
||||||
|
|
||||||
|
Purpose
|
||||||
|
-------
|
||||||
|
|
||||||
|
The goal of autofs is to provide on-demand mounting and race free
|
||||||
|
automatic unmounting of various other filesystems. This provides two
|
||||||
|
key advantages:
|
||||||
|
|
||||||
|
1. There is no need to delay boot until all filesystems that
|
||||||
|
might be needed are mounted. Processes that try to access those
|
||||||
|
slow filesystems might be delayed but other processes can
|
||||||
|
continue freely. This is particularly important for
|
||||||
|
network filesystems (e.g. NFS) or filesystems stored on
|
||||||
|
media with a media-changing robot.
|
||||||
|
|
||||||
|
2. The names and locations of filesystems can be stored in
|
||||||
|
a remote database and can change at any time. The content
|
||||||
|
in that data base at the time of access will be used to provide
|
||||||
|
a target for the access. The interpretation of names in the
|
||||||
|
filesystem can even be programmatic rather than database-backed,
|
||||||
|
allowing wildcards for example, and can vary based on the user who
|
||||||
|
first accessed a name.
|
||||||
|
|
||||||
|
Context
|
||||||
|
-------
|
||||||
|
|
||||||
|
The "autofs4" filesystem module is only one part of an autofs system.
|
||||||
|
There also needs to be a user-space program which looks up names
|
||||||
|
and mounts filesystems. This will often be the "automount" program,
|
||||||
|
though other tools including "systemd" can make use of "autofs4".
|
||||||
|
This document describes only the kernel module and the interactions
|
||||||
|
required with any user-space program. Subsequent text refers to this
|
||||||
|
as the "automount daemon" or simply "the daemon".
|
||||||
|
|
||||||
|
"autofs4" is a Linux kernel module with provides the "autofs"
|
||||||
|
filesystem type. Several "autofs" filesystems can be mounted and they
|
||||||
|
can each be managed separately, or all managed by the same daemon.
|
||||||
|
|
||||||
|
Content
|
||||||
|
-------
|
||||||
|
|
||||||
|
An autofs filesystem can contain 3 sorts of objects: directories,
|
||||||
|
symbolic links and mount traps. Mount traps are directories with
|
||||||
|
extra properties as described in the next section.
|
||||||
|
|
||||||
|
Objects can only be created by the automount daemon: symlinks are
|
||||||
|
created with a regular `symlink` system call, while directories and
|
||||||
|
mount traps are created with `mkdir`. The determination of whether a
|
||||||
|
directory should be a mount trap or not is quite _ad hoc_, largely for
|
||||||
|
historical reasons, and is determined in part by the
|
||||||
|
*direct*/*indirect*/*offset* mount options, and the *maxproto* mount option.
|
||||||
|
|
||||||
|
If neither the *direct* or *offset* mount options are given (so the
|
||||||
|
mount is considered to be *indirect*), then the root directory is
|
||||||
|
always a regular directory, otherwise it is a mount trap when it is
|
||||||
|
empty and a regular directory when not empty. Note that *direct* and
|
||||||
|
*offset* are treated identically so a concise summary is that the root
|
||||||
|
directory is a mount trap only if the filesystem is mounted *direct*
|
||||||
|
and the root is empty.
|
||||||
|
|
||||||
|
Directories created in the root directory are mount traps only if the
|
||||||
|
filesystem is mounted *indirect* and they are empty.
|
||||||
|
|
||||||
|
Directories further down the tree depend on the *maxproto* mount
|
||||||
|
option and particularly whether it is less than five or not.
|
||||||
|
When *maxproto* is five, no directories further down the
|
||||||
|
tree are ever mount traps, they are always regular directories. When
|
||||||
|
the *maxproto* is four (or three), these directories are mount traps
|
||||||
|
precisely when they are empty.
|
||||||
|
|
||||||
|
So: non-empty (i.e. non-leaf) directories are never mount traps. Empty
|
||||||
|
directories are sometimes mount traps, and sometimes not depending on
|
||||||
|
where in the tree they are (root, top level, or lower), the *maxproto*,
|
||||||
|
and whether the mount was *indirect* or not.
|
||||||
|
|
||||||
|
Mount Traps
|
||||||
|
---------------
|
||||||
|
|
||||||
|
A core element of the implementation of autofs is the Mount Traps
|
||||||
|
which are provided by the Linux VFS. Any directory provided by a
|
||||||
|
filesystem can be designated as a trap. This involves two separate
|
||||||
|
features that work together to allow autofs to do its job.
|
||||||
|
|
||||||
|
**DCACHE_NEED_AUTOMOUNT**
|
||||||
|
|
||||||
|
If a dentry has the DCACHE_NEED_AUTOMOUNT flag set (which gets set if
|
||||||
|
the inode has S_AUTOMOUNT set, or can be set directly) then it is
|
||||||
|
(potentially) a mount trap. Any access to this directory beyond a
|
||||||
|
"`stat`" will (normally) cause the `d_op->d_automount()` dentry operation
|
||||||
|
to be called. The task of this method is to find the filesystem that
|
||||||
|
should be mounted on the directory and to return it. The VFS is
|
||||||
|
responsible for actually mounting the root of this filesystem on the
|
||||||
|
directory.
|
||||||
|
|
||||||
|
autofs doesn't find the filesystem itself but sends a message to the
|
||||||
|
automount daemon asking it to find and mount the filesystem. The
|
||||||
|
autofs `d_automount` method then waits for the daemon to report that
|
||||||
|
everything is ready. It will then return "`NULL`" indicating that the
|
||||||
|
mount has already happened. The VFS doesn't try to mount anything but
|
||||||
|
follows down the mount that is already there.
|
||||||
|
|
||||||
|
This functionality is sufficient for some users of mount traps such
|
||||||
|
as NFS which creates traps so that mountpoints on the server can be
|
||||||
|
reflected on the client. However it is not sufficient for autofs. As
|
||||||
|
mounting onto a directory is considered to be "beyond a `stat`", the
|
||||||
|
automount daemon would not be able to mount a filesystem on the 'trap'
|
||||||
|
directory without some way to avoid getting caught in the trap. For
|
||||||
|
that purpose there is another flag.
|
||||||
|
|
||||||
|
**DCACHE_MANAGE_TRANSIT**
|
||||||
|
|
||||||
|
If a dentry has DCACHE_MANAGE_TRANSIT set then two very different but
|
||||||
|
related behaviors are invoked, both using the `d_op->d_manage()`
|
||||||
|
dentry operation.
|
||||||
|
|
||||||
|
Firstly, before checking to see if any filesystem is mounted on the
|
||||||
|
directory, d_manage() will be called with the `rcu_walk` parameter set
|
||||||
|
to `false`. It may return one of three things:
|
||||||
|
|
||||||
|
- A return value of zero indicates that there is nothing special
|
||||||
|
about this dentry and normal checks for mounts and automounts
|
||||||
|
should proceed.
|
||||||
|
|
||||||
|
autofs normally returns zero, but first waits for any
|
||||||
|
expiry (automatic unmounting of the mounted filesystem) to
|
||||||
|
complete. This avoids races.
|
||||||
|
|
||||||
|
- A return value of `-EISDIR` tells the VFS to ignore any mounts
|
||||||
|
on the directory and to not consider calling `->d_automount()`.
|
||||||
|
This effectively disables the **DCACHE_NEED_AUTOMOUNT** flag
|
||||||
|
causing the directory not be a mount trap after all.
|
||||||
|
|
||||||
|
autofs returns this if it detects that the process performing the
|
||||||
|
lookup is the automount daemon and that the mount has been
|
||||||
|
requested but has not yet completed. How it determines this is
|
||||||
|
discussed later. This allows the automount daemon not to get
|
||||||
|
caught in the mount trap.
|
||||||
|
|
||||||
|
There is a subtlety here. It is possible that a second autofs
|
||||||
|
filesystem can be mounted below the first and for both of them to
|
||||||
|
be managed by the same daemon. For the daemon to be able to mount
|
||||||
|
something on the second it must be able to "walk" down past the
|
||||||
|
first. This means that d_manage cannot *always* return -EISDIR for
|
||||||
|
the automount daemon. It must only return it when a mount has
|
||||||
|
been requested, but has not yet completed.
|
||||||
|
|
||||||
|
`d_manage` also returns `-EISDIR` if the dentry shouldn't be a
|
||||||
|
mount trap, either because it is a symbolic link or because it is
|
||||||
|
not empty.
|
||||||
|
|
||||||
|
- Any other negative value is treated as an error and returned
|
||||||
|
to the caller.
|
||||||
|
|
||||||
|
autofs can return
|
||||||
|
|
||||||
|
- -ENOENT if the automount daemon failed to mount anything,
|
||||||
|
- -ENOMEM if it ran out of memory,
|
||||||
|
- -EINTR if a signal arrived while waiting for expiry to
|
||||||
|
complete
|
||||||
|
- or any other error sent down by the automount daemon.
|
||||||
|
|
||||||
|
|
||||||
|
The second use case only occurs during an "RCU-walk" and so `rcu_walk`
|
||||||
|
will be set.
|
||||||
|
|
||||||
|
An RCU-walk is a fast and lightweight process for walking down a
|
||||||
|
filename path (i.e. it is like running on tip-toes). RCU-walk cannot
|
||||||
|
cope with all situations so when it finds a difficulty it falls back
|
||||||
|
to "REF-walk", which is slower but more robust.
|
||||||
|
|
||||||
|
RCU-walk will never call `->d_automount`; the filesystems must already
|
||||||
|
be mounted or RCU-walk cannot handle the path.
|
||||||
|
To determine if a mount-trap is safe for RCU-walk mode it calls
|
||||||
|
`->d_manage()` with `rcu_walk` set to `true`.
|
||||||
|
|
||||||
|
In this case `d_manage()` must avoid blocking and should avoid taking
|
||||||
|
spinlocks if at all possible. Its sole purpose is to determine if it
|
||||||
|
would be safe to follow down into any mounted directory and the only
|
||||||
|
reason that it might not be is if an expiry of the mount is
|
||||||
|
underway.
|
||||||
|
|
||||||
|
In the `rcu_walk` case, `d_manage()` cannot return -EISDIR to tell the
|
||||||
|
VFS that this is a directory that doesn't require d_automount. If
|
||||||
|
`rcu_walk` sees a dentry with DCACHE_NEED_AUTOMOUNT set but nothing
|
||||||
|
mounted, it *will* fall back to REF-walk. `d_manage()` cannot make the
|
||||||
|
VFS remain in RCU-walk mode, but can only tell it to get out of
|
||||||
|
RCU-walk mode by returning `-ECHILD`.
|
||||||
|
|
||||||
|
So `d_manage()`, when called with `rcu_walk` set, should either return
|
||||||
|
-ECHILD if there is any reason to believe it is unsafe to end the
|
||||||
|
mounted filesystem, and otherwise should return 0.
|
||||||
|
|
||||||
|
autofs will return `-ECHILD` if an expiry of the filesystem has been
|
||||||
|
initiated or is being considered, otherwise it returns 0.
|
||||||
|
|
||||||
|
|
||||||
|
Mountpoint expiry
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
The VFS has a mechansim for automatically expiring unused mounts,
|
||||||
|
much as it can expire any unused dentry information from the dcache.
|
||||||
|
This is guided by the MNT_SHRINKABLE flag. This only applies to
|
||||||
|
mounts that were created by `d_automount()` returning a filesystem to be
|
||||||
|
mounted. As autofs doesn't return such a filesystem but leaves the
|
||||||
|
mounting to the automount daemon, it must involve the automount daemon
|
||||||
|
in unmounting as well. This also means that autofs has more control
|
||||||
|
of expiry.
|
||||||
|
|
||||||
|
The VFS also supports "expiry" of mounts using the MNT_EXPIRE flag to
|
||||||
|
the `umount` system call. Unmounting with MNT_EXPIRE will fail unless
|
||||||
|
a previous attempt had been made, and the filesystem has been inactive
|
||||||
|
and untouched since that previous attempt. autofs4 does not depend on
|
||||||
|
this but has its own internal tracking of whether filesystems were
|
||||||
|
recently used. This allows individual names in the autofs directory
|
||||||
|
to expire separately.
|
||||||
|
|
||||||
|
With version 4 of the protocol, the automount daemon can try to
|
||||||
|
unmount any filesystems mounted on the autofs filesystem or remove any
|
||||||
|
symbolic links or empty directories any time it likes. If the unmount
|
||||||
|
or removal is successful the filesystem will be returned to the state
|
||||||
|
it was before the mount or creation, so that any access of the name
|
||||||
|
will trigger normal auto-mount processing. In particlar, `rmdir` and
|
||||||
|
`unlink` do not leave negative entries in the dcache as a normal
|
||||||
|
filesystem would, so an attempt to access a recently-removed object is
|
||||||
|
passed to autofs for handling.
|
||||||
|
|
||||||
|
With version 5, this is not safe except for unmounting from top-level
|
||||||
|
directories. As lower-level directories are never mount traps, other
|
||||||
|
processes will see an empty directory as soon as the filesystem is
|
||||||
|
unmounted. So it is generally safest to use the autofs expiry
|
||||||
|
protocol described below.
|
||||||
|
|
||||||
|
Normally the daemon only wants to remove entries which haven't been
|
||||||
|
used for a while. For this purpose autofs maintains a "`last_used`"
|
||||||
|
time stamp on each directory or symlink. For symlinks it genuinely
|
||||||
|
does record the last time the symlink was "used" or followed to find
|
||||||
|
out where it points to. For directories the field is a slight
|
||||||
|
misnomer. It actually records the last time that autofs checked if
|
||||||
|
the directory or one of its descendents was busy and found that it
|
||||||
|
was. This is just as useful and doesn't require updating the field so
|
||||||
|
often.
|
||||||
|
|
||||||
|
The daemon is able to ask autofs if anything is due to be expired,
|
||||||
|
using an `ioctl` as discussed later. For a *direct* mount, autofs
|
||||||
|
considers if the entire mount-tree can be unmounted or not. For an
|
||||||
|
*indirect* mount, autofs considers each of the names in the top level
|
||||||
|
directory to determine if any of those can be unmounted and cleaned
|
||||||
|
up.
|
||||||
|
|
||||||
|
There is an option with indirect mounts to consider each of the leaves
|
||||||
|
that has been mounted on instead of considering the top-level names.
|
||||||
|
This is intended for compatability with version 4 of autofs and should
|
||||||
|
be considered as deprecated.
|
||||||
|
|
||||||
|
When autofs considers a directory it checks the `last_used` time and
|
||||||
|
compares it with the "timeout" value set when the filesystem was
|
||||||
|
mounted, though this check is ignored in some cases. It also checks if
|
||||||
|
the directory or anything below it is in use. For symbolic links,
|
||||||
|
only the `last_used` time is ever considered.
|
||||||
|
|
||||||
|
If both appear to support expiring the directory or symlink, an action
|
||||||
|
is taken.
|
||||||
|
|
||||||
|
There are two ways to ask autofs to consider expiry. The first is to
|
||||||
|
use the **AUTOFS_IOC_EXPIRE** ioctl. This only works for indirect
|
||||||
|
mounts. If it finds something in the root directory to expire it will
|
||||||
|
return the name of that thing. Once a name has been returned the
|
||||||
|
automount daemon needs to unmount any filesystems mounted below the
|
||||||
|
name normally. As described above, this is unsafe for non-toplevel
|
||||||
|
mounts in a version-5 autofs. For this reason the current `automountd`
|
||||||
|
does not use this ioctl.
|
||||||
|
|
||||||
|
The second mechanism uses either the **AUTOFS_DEV_IOCTL_EXPIRE_CMD** or
|
||||||
|
the **AUTOFS_IOC_EXPIRE_MULTI** ioctl. This will work for both direct and
|
||||||
|
indirect mounts. If it selects an object to expire, it will notify
|
||||||
|
the daemon using the notification mechanism described below. This
|
||||||
|
will block until the daemon acknowledges the expiry notification.
|
||||||
|
This implies that the "`EXPIRE`" ioctl must be sent from a different
|
||||||
|
thread than the one which handles notification.
|
||||||
|
|
||||||
|
While the ioctl is blocking, the entry is marked as "expiring" and
|
||||||
|
`d_manage` will block until the daemon affirms that the unmount has
|
||||||
|
completed (together with removing any directories that might have been
|
||||||
|
necessary), or has been aborted.
|
||||||
|
|
||||||
|
Communicating with autofs: detecting the daemon
|
||||||
|
-----------------------------------------------
|
||||||
|
|
||||||
|
There are several forms of communication between the automount daemon
|
||||||
|
and the filesystem. As we have already seen, the daemon can create and
|
||||||
|
remove directories and symlinks using normal filesystem operations.
|
||||||
|
autofs knows whether a process requesting some operation is the daemon
|
||||||
|
or not based on its process-group id number (see getpgid(1)).
|
||||||
|
|
||||||
|
When an autofs filesystem it mounted the pgid of the mounting
|
||||||
|
processes is recorded unless the "pgrp=" option is given, in which
|
||||||
|
case that number is recorded instead. Any request arriving from a
|
||||||
|
process in that process group is considered to come from the daemon.
|
||||||
|
If the daemon ever has to be stopped and restarted a new pgid can be
|
||||||
|
provided through an ioctl as will be described below.
|
||||||
|
|
||||||
|
Communicating with autofs: the event pipe
|
||||||
|
-----------------------------------------
|
||||||
|
|
||||||
|
When an autofs filesystem is mounted, the 'write' end of a pipe must
|
||||||
|
be passed using the 'fd=' mount option. autofs will write
|
||||||
|
notification messages to this pipe for the daemon to respond to.
|
||||||
|
For version 5, the format of the message is:
|
||||||
|
|
||||||
|
struct autofs_v5_packet {
|
||||||
|
int proto_version; /* Protocol version */
|
||||||
|
int type; /* Type of packet */
|
||||||
|
autofs_wqt_t wait_queue_token;
|
||||||
|
__u32 dev;
|
||||||
|
__u64 ino;
|
||||||
|
__u32 uid;
|
||||||
|
__u32 gid;
|
||||||
|
__u32 pid;
|
||||||
|
__u32 tgid;
|
||||||
|
__u32 len;
|
||||||
|
char name[NAME_MAX+1];
|
||||||
|
};
|
||||||
|
|
||||||
|
where the type is one of
|
||||||
|
|
||||||
|
autofs_ptype_missing_indirect
|
||||||
|
autofs_ptype_expire_indirect
|
||||||
|
autofs_ptype_missing_direct
|
||||||
|
autofs_ptype_expire_direct
|
||||||
|
|
||||||
|
so messages can indicate that a name is missing (something tried to
|
||||||
|
access it but it isn't there) or that it has been selected for expiry.
|
||||||
|
|
||||||
|
The pipe will be set to "packet mode" (equivalent to passing
|
||||||
|
`O_DIRECT`) to _pipe2(2)_ so that a read from the pipe will return at
|
||||||
|
most one packet, and any unread portion of a packet will be discarded.
|
||||||
|
|
||||||
|
The `wait_queue_token` is a unique number which can identify a
|
||||||
|
particular request to be acknowledged. When a message is sent over
|
||||||
|
the pipe the affected dentry is marked as either "active" or
|
||||||
|
"expiring" and other accesses to it block until the message is
|
||||||
|
acknowledged using one of the ioctls below and the relevant
|
||||||
|
`wait_queue_token`.
|
||||||
|
|
||||||
|
Communicating with autofs: root directory ioctls
|
||||||
|
------------------------------------------------
|
||||||
|
|
||||||
|
The root directory of an autofs filesystem will respond to a number of
|
||||||
|
ioctls. The process issuing the ioctl must have the CAP_SYS_ADMIN
|
||||||
|
capability, or must be the automount daemon.
|
||||||
|
|
||||||
|
The available ioctl commands are:
|
||||||
|
|
||||||
|
- **AUTOFS_IOC_READY**: a notification has been handled. The argument
|
||||||
|
to the ioctl command is the "wait_queue_token" number
|
||||||
|
corresponding to the notification being acknowledged.
|
||||||
|
- **AUTOFS_IOC_FAIL**: similar to above, but indicates failure with
|
||||||
|
the error code `ENOENT`.
|
||||||
|
- **AUTOFS_IOC_CATATONIC**: Causes the autofs to enter "catatonic"
|
||||||
|
mode meaning that it stops sending notifications to the daemon.
|
||||||
|
This mode is also entered if a write to the pipe fails.
|
||||||
|
- **AUTOFS_IOC_PROTOVER**: This returns the protocol version in use.
|
||||||
|
- **AUTOFS_IOC_PROTOSUBVER**: Returns the protocol sub-version which
|
||||||
|
is really a version number for the implementation. It is
|
||||||
|
currently 2.
|
||||||
|
- **AUTOFS_IOC_SETTIMEOUT**: This passes a pointer to an unsigned
|
||||||
|
long. The value is used to set the timeout for expiry, and
|
||||||
|
the current timeout value is stored back through the pointer.
|
||||||
|
- **AUTOFS_IOC_ASKUMOUNT**: Returns, in the pointed-to `int`, 1 if
|
||||||
|
the filesystem could be unmounted. This is only a hint as
|
||||||
|
the situation could change at any instant. This call can be
|
||||||
|
use to avoid a more expensive full unmount attempt.
|
||||||
|
- **AUTOFS_IOC_EXPIRE**: as described above, this asks if there is
|
||||||
|
anything suitable to expire. A pointer to a packet:
|
||||||
|
|
||||||
|
struct autofs_packet_expire_multi {
|
||||||
|
int proto_version; /* Protocol version */
|
||||||
|
int type; /* Type of packet */
|
||||||
|
autofs_wqt_t wait_queue_token;
|
||||||
|
int len;
|
||||||
|
char name[NAME_MAX+1];
|
||||||
|
};
|
||||||
|
|
||||||
|
is required. This is filled in with the name of something
|
||||||
|
that can be unmounted or removed. If nothing can be expired,
|
||||||
|
`errno` is set to `EAGAIN`. Even though a `wait_queue_token`
|
||||||
|
is present in the structure, no "wait queue" is established
|
||||||
|
and no acknowledgment is needed.
|
||||||
|
- **AUTOFS_IOC_EXPIRE_MULTI**: This is similar to
|
||||||
|
**AUTOFS_IOC_EXPIRE** except that it causes notification to be
|
||||||
|
sent to the daemon, and it blocks until the daemon acknowledges.
|
||||||
|
The argument is an integer which can contain two different flags.
|
||||||
|
|
||||||
|
**AUTOFS_EXP_IMMEDIATE** causes `last_used` time to be ignored
|
||||||
|
and objects are expired if the are not in use.
|
||||||
|
|
||||||
|
**AUTOFS_EXP_LEAVES** will select a leaf rather than a top-level
|
||||||
|
name to expire. This is only safe when *maxproto* is 4.
|
||||||
|
|
||||||
|
Communicating with autofs: char-device ioctls
|
||||||
|
---------------------------------------------
|
||||||
|
|
||||||
|
It is not always possible to open the root of an autofs filesystem,
|
||||||
|
particularly a *direct* mounted filesystem. If the automount daemon
|
||||||
|
is restarted there is no way for it to regain control of existing
|
||||||
|
mounts using any of the above communication channels. To address this
|
||||||
|
need there is a "miscellaneous" character device (major 10, minor 235)
|
||||||
|
which can be used to communicate directly with the autofs filesystem.
|
||||||
|
It requires CAP_SYS_ADMIN for access.
|
||||||
|
|
||||||
|
The `ioctl`s that can be used on this device are described in a separate
|
||||||
|
document `autofs4-mount-control.txt`, and are summarized briefly here.
|
||||||
|
Each ioctl is passed a pointer to an `autofs_dev_ioctl` structure:
|
||||||
|
|
||||||
|
struct autofs_dev_ioctl {
|
||||||
|
__u32 ver_major;
|
||||||
|
__u32 ver_minor;
|
||||||
|
__u32 size; /* total size of data passed in
|
||||||
|
* including this struct */
|
||||||
|
__s32 ioctlfd; /* automount command fd */
|
||||||
|
|
||||||
|
__u32 arg1; /* Command parameters */
|
||||||
|
__u32 arg2;
|
||||||
|
|
||||||
|
char path[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
For the **OPEN_MOUNT** and **IS_MOUNTPOINT** commands, the target
|
||||||
|
filesystem is identified by the `path`. All other commands identify
|
||||||
|
the filesystem by the `ioctlfd` which is a file descriptor open on the
|
||||||
|
root, and which can be returned by **OPEN_MOUNT**.
|
||||||
|
|
||||||
|
The `ver_major` and `ver_minor` are in/out parameters which check that
|
||||||
|
the requested version is supported, and report the maximum version
|
||||||
|
that the kernel module can support.
|
||||||
|
|
||||||
|
Commands are:
|
||||||
|
|
||||||
|
- **AUTOFS_DEV_IOCTL_VERSION_CMD**: does nothing, except validate and
|
||||||
|
set version numbers.
|
||||||
|
- **AUTOFS_DEV_IOCTL_OPENMOUNT_CMD**: return an open file descriptor
|
||||||
|
on the root of an autofs filesystem. The filesystem is identified
|
||||||
|
by name and device number, which is stored in `arg1`. Device
|
||||||
|
numbers for existing filesystems can be found in
|
||||||
|
`/proc/self/mountinfo`.
|
||||||
|
- **AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD**: same as `close(ioctlfd)`.
|
||||||
|
- **AUTOFS_DEV_IOCTL_SETPIPEFD_CMD**: if the filesystem is in
|
||||||
|
catatonic mode, this can provide the write end of a new pipe
|
||||||
|
in `arg1` to re-establish communication with a daemon. The
|
||||||
|
process group of the calling process is used to identify the
|
||||||
|
daemon.
|
||||||
|
- **AUTOFS_DEV_IOCTL_REQUESTER_CMD**: `path` should be a
|
||||||
|
name within the filesystem that has been auto-mounted on.
|
||||||
|
arg1 is the dev number of the underlying autofs. On successful
|
||||||
|
return, `arg1` and `arg2` will be the UID and GID of the process
|
||||||
|
which triggered that mount.
|
||||||
|
|
||||||
|
- **AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD**: Check if path is a
|
||||||
|
mountpoint of a particular type - see separate documentation for
|
||||||
|
details.
|
||||||
|
|
||||||
|
- **AUTOFS_DEV_IOCTL_PROTOVER_CMD**:
|
||||||
|
- **AUTOFS_DEV_IOCTL_PROTOSUBVER_CMD**:
|
||||||
|
- **AUTOFS_DEV_IOCTL_READY_CMD**:
|
||||||
|
- **AUTOFS_DEV_IOCTL_FAIL_CMD**:
|
||||||
|
- **AUTOFS_DEV_IOCTL_CATATONIC_CMD**:
|
||||||
|
- **AUTOFS_DEV_IOCTL_TIMEOUT_CMD**:
|
||||||
|
- **AUTOFS_DEV_IOCTL_EXPIRE_CMD**:
|
||||||
|
- **AUTOFS_DEV_IOCTL_ASKUMOUNT_CMD**: These all have the same
|
||||||
|
function as the similarly named **AUTOFS_IOC** ioctls, except
|
||||||
|
that **FAIL** can be given an explicit error number in `arg1`
|
||||||
|
instead of assuming `ENOENT`, and this **EXPIRE** command
|
||||||
|
corresponds to **AUTOFS_IOC_EXPIRE_MULTI**.
|
||||||
|
|
||||||
|
Catatonic mode
|
||||||
|
--------------
|
||||||
|
|
||||||
|
As mentioned, an autofs mount can enter "catatonic" mode. This
|
||||||
|
happens if a write to the notification pipe fails, or if it is
|
||||||
|
explicitly requested by an `ioctl`.
|
||||||
|
|
||||||
|
When entering catatonic mode, the pipe is closed and any pending
|
||||||
|
notifications are acknowledged with the error `ENOENT`.
|
||||||
|
|
||||||
|
Once in catatonic mode attempts to access non-existing names will
|
||||||
|
result in `ENOENT` while attempts to access existing directories will
|
||||||
|
be treated in the same way as if they came from the daemon, so mount
|
||||||
|
traps will not fire.
|
||||||
|
|
||||||
|
When the filesystem is mounted a _uid_ and _gid_ can be given which
|
||||||
|
set the ownership of directories and symbolic links. When the
|
||||||
|
filesystem is in catatonic mode, any process with a matching UID can
|
||||||
|
create directories or symlinks in the root directory, but not in other
|
||||||
|
directories.
|
||||||
|
|
||||||
|
Catatonic mode can only be left via the
|
||||||
|
**AUTOFS_DEV_IOCTL_OPENMOUNT_CMD** ioctl on the `/dev/autofs`.
|
||||||
|
|
||||||
|
autofs, name spaces, and shared mounts
|
||||||
|
--------------------------------------
|
||||||
|
|
||||||
|
With bind mounts and name spaces it is possible for an autofs
|
||||||
|
filesystem to appear at multiple places in one or more filesystem
|
||||||
|
name spaces. For this to work sensibly, the autofs filesystem should
|
||||||
|
always be mounted "shared". e.g.
|
||||||
|
|
||||||
|
> `mount --make-shared /autofs/mount/point`
|
||||||
|
|
||||||
|
The automount daemon is only able to mange a single mount location for
|
||||||
|
an autofs filesystem and if mounts on that are not 'shared', other
|
||||||
|
locations will not behave as expected. In particular access to those
|
||||||
|
other locations will likely result in the `ELOOP` error
|
||||||
|
|
||||||
|
> Too many levels of symbolic links
|
@ -70,6 +70,38 @@ DMA addresses types dma_addr_t:
|
|||||||
For printing a dma_addr_t type which can vary based on build options,
|
For printing a dma_addr_t type which can vary based on build options,
|
||||||
regardless of the width of the CPU data path. Passed by reference.
|
regardless of the width of the CPU data path. Passed by reference.
|
||||||
|
|
||||||
|
Raw buffer as an escaped string:
|
||||||
|
|
||||||
|
%*pE[achnops]
|
||||||
|
|
||||||
|
For printing raw buffer as an escaped string. For the following buffer
|
||||||
|
|
||||||
|
1b 62 20 5c 43 07 22 90 0d 5d
|
||||||
|
|
||||||
|
few examples show how the conversion would be done (the result string
|
||||||
|
without surrounding quotes):
|
||||||
|
|
||||||
|
%*pE "\eb \C\a"\220\r]"
|
||||||
|
%*pEhp "\x1bb \C\x07"\x90\x0d]"
|
||||||
|
%*pEa "\e\142\040\\\103\a\042\220\r\135"
|
||||||
|
|
||||||
|
The conversion rules are applied according to an optional combination
|
||||||
|
of flags (see string_escape_mem() kernel documentation for the
|
||||||
|
details):
|
||||||
|
a - ESCAPE_ANY
|
||||||
|
c - ESCAPE_SPECIAL
|
||||||
|
h - ESCAPE_HEX
|
||||||
|
n - ESCAPE_NULL
|
||||||
|
o - ESCAPE_OCTAL
|
||||||
|
p - ESCAPE_NP
|
||||||
|
s - ESCAPE_SPACE
|
||||||
|
By default ESCAPE_ANY_NP is used.
|
||||||
|
|
||||||
|
ESCAPE_ANY_NP is the sane choice for many cases, in particularly for
|
||||||
|
printing SSIDs.
|
||||||
|
|
||||||
|
If field width is omitted the 1 byte only will be escaped.
|
||||||
|
|
||||||
Raw buffer as a hex string:
|
Raw buffer as a hex string:
|
||||||
%*ph 00 01 02 ... 3f
|
%*ph 00 01 02 ... 3f
|
||||||
%*phC 00:01:02: ... :3f
|
%*phC 00:01:02: ... :3f
|
||||||
|
@ -190,6 +190,8 @@ core_pattern is used to specify a core dumpfile pattern name.
|
|||||||
%% output one '%'
|
%% output one '%'
|
||||||
%p pid
|
%p pid
|
||||||
%P global pid (init PID namespace)
|
%P global pid (init PID namespace)
|
||||||
|
%i tid
|
||||||
|
%I global tid (init PID namespace)
|
||||||
%u uid
|
%u uid
|
||||||
%g gid
|
%g gid
|
||||||
%d dump mode, matches PR_SET_DUMPABLE and
|
%d dump mode, matches PR_SET_DUMPABLE and
|
||||||
|
32
MAINTAINERS
32
MAINTAINERS
@ -1338,8 +1338,7 @@ ARM/SAMSUNG MOBILE MACHINE SUPPORT
|
|||||||
M: Kyungmin Park <kyungmin.park@samsung.com>
|
M: Kyungmin Park <kyungmin.park@samsung.com>
|
||||||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: arch/arm/mach-s5pv210/mach-aquila.c
|
F: arch/arm/mach-s5pv210/
|
||||||
F: arch/arm/mach-s5pv210/mach-goni.c
|
|
||||||
|
|
||||||
ARM/SAMSUNG S5P SERIES 2D GRAPHICS ACCELERATION (G2D) SUPPORT
|
ARM/SAMSUNG S5P SERIES 2D GRAPHICS ACCELERATION (G2D) SUPPORT
|
||||||
M: Kyungmin Park <kyungmin.park@samsung.com>
|
M: Kyungmin Park <kyungmin.park@samsung.com>
|
||||||
@ -1550,6 +1549,7 @@ T: git git://git.xilinx.com/linux-xlnx.git
|
|||||||
S: Supported
|
S: Supported
|
||||||
F: arch/arm/mach-zynq/
|
F: arch/arm/mach-zynq/
|
||||||
F: drivers/cpuidle/cpuidle-zynq.c
|
F: drivers/cpuidle/cpuidle-zynq.c
|
||||||
|
F: drivers/block/xsysace.c
|
||||||
N: zynq
|
N: zynq
|
||||||
N: xilinx
|
N: xilinx
|
||||||
F: drivers/clocksource/cadence_ttc_timer.c
|
F: drivers/clocksource/cadence_ttc_timer.c
|
||||||
@ -1738,6 +1738,12 @@ M: Nicolas Ferre <nicolas.ferre@atmel.com>
|
|||||||
S: Supported
|
S: Supported
|
||||||
F: drivers/net/ethernet/cadence/
|
F: drivers/net/ethernet/cadence/
|
||||||
|
|
||||||
|
ATMEL NAND DRIVER
|
||||||
|
M: Josh Wu <josh.wu@atmel.com>
|
||||||
|
L: linux-mtd@lists.infradead.org
|
||||||
|
S: Supported
|
||||||
|
F: drivers/mtd/nand/atmel_nand*
|
||||||
|
|
||||||
ATMEL SPI DRIVER
|
ATMEL SPI DRIVER
|
||||||
M: Nicolas Ferre <nicolas.ferre@atmel.com>
|
M: Nicolas Ferre <nicolas.ferre@atmel.com>
|
||||||
S: Supported
|
S: Supported
|
||||||
@ -3048,7 +3054,7 @@ M: Sumit Semwal <sumit.semwal@linaro.org>
|
|||||||
S: Maintained
|
S: Maintained
|
||||||
L: linux-media@vger.kernel.org
|
L: linux-media@vger.kernel.org
|
||||||
L: dri-devel@lists.freedesktop.org
|
L: dri-devel@lists.freedesktop.org
|
||||||
L: linaro-mm-sig@lists.linaro.org
|
L: linaro-mm-sig@lists.linaro.org (moderated for non-subscribers)
|
||||||
F: drivers/dma-buf/
|
F: drivers/dma-buf/
|
||||||
F: include/linux/dma-buf*
|
F: include/linux/dma-buf*
|
||||||
F: include/linux/reservation.h
|
F: include/linux/reservation.h
|
||||||
@ -4297,9 +4303,8 @@ S: Maintained
|
|||||||
F: drivers/media/dvb-frontends/hd29l2*
|
F: drivers/media/dvb-frontends/hd29l2*
|
||||||
|
|
||||||
HEWLETT-PACKARD SMART2 RAID DRIVER
|
HEWLETT-PACKARD SMART2 RAID DRIVER
|
||||||
M: Chirag Kantharia <chirag.kantharia@hp.com>
|
|
||||||
L: iss_storagedev@hp.com
|
L: iss_storagedev@hp.com
|
||||||
S: Maintained
|
S: Orphan
|
||||||
F: Documentation/blockdev/cpqarray.txt
|
F: Documentation/blockdev/cpqarray.txt
|
||||||
F: drivers/block/cpqarray.*
|
F: drivers/block/cpqarray.*
|
||||||
|
|
||||||
@ -5300,6 +5305,13 @@ F: include/linux/lockd/
|
|||||||
F: include/linux/sunrpc/
|
F: include/linux/sunrpc/
|
||||||
F: include/uapi/linux/sunrpc/
|
F: include/uapi/linux/sunrpc/
|
||||||
|
|
||||||
|
KERNEL SELFTEST FRAMEWORK
|
||||||
|
M: Shuah Khan <shuahkh@osg.samsung.com>
|
||||||
|
L: linux-api@vger.kernel.org
|
||||||
|
T: git git://git.kernel.org/pub/scm/shuah/linux-kselftest
|
||||||
|
S: Maintained
|
||||||
|
F: tools/testing/selftests
|
||||||
|
|
||||||
KERNEL VIRTUAL MACHINE (KVM)
|
KERNEL VIRTUAL MACHINE (KVM)
|
||||||
M: Gleb Natapov <gleb@kernel.org>
|
M: Gleb Natapov <gleb@kernel.org>
|
||||||
M: Paolo Bonzini <pbonzini@redhat.com>
|
M: Paolo Bonzini <pbonzini@redhat.com>
|
||||||
@ -5746,11 +5758,8 @@ T: git git://github.com/linux-test-project/ltp.git
|
|||||||
S: Maintained
|
S: Maintained
|
||||||
|
|
||||||
M32R ARCHITECTURE
|
M32R ARCHITECTURE
|
||||||
M: Hirokazu Takata <takata@linux-m32r.org>
|
|
||||||
L: linux-m32r@ml.linux-m32r.org (moderated for non-subscribers)
|
|
||||||
L: linux-m32r-ja@ml.linux-m32r.org (in Japanese)
|
|
||||||
W: http://www.linux-m32r.org/
|
W: http://www.linux-m32r.org/
|
||||||
S: Maintained
|
S: Orphan
|
||||||
F: arch/m32r/
|
F: arch/m32r/
|
||||||
|
|
||||||
M68K ARCHITECTURE
|
M68K ARCHITECTURE
|
||||||
@ -7974,7 +7983,6 @@ S: Supported
|
|||||||
F: drivers/mfd/sec*.c
|
F: drivers/mfd/sec*.c
|
||||||
F: drivers/regulator/s2m*.c
|
F: drivers/regulator/s2m*.c
|
||||||
F: drivers/regulator/s5m*.c
|
F: drivers/regulator/s5m*.c
|
||||||
F: drivers/rtc/rtc-sec.c
|
|
||||||
F: include/linux/mfd/samsung/
|
F: include/linux/mfd/samsung/
|
||||||
|
|
||||||
SAMSUNG S5P/EXYNOS4 SOC SERIES CAMERA SUBSYSTEM DRIVERS
|
SAMSUNG S5P/EXYNOS4 SOC SERIES CAMERA SUBSYSTEM DRIVERS
|
||||||
@ -10315,10 +10323,6 @@ M: John Linn <John.Linn@xilinx.com>
|
|||||||
S: Maintained
|
S: Maintained
|
||||||
F: drivers/net/ethernet/xilinx/xilinx_axienet*
|
F: drivers/net/ethernet/xilinx/xilinx_axienet*
|
||||||
|
|
||||||
XILINX SYSTEMACE DRIVER
|
|
||||||
S: Orphan
|
|
||||||
F: drivers/block/xsysace.c
|
|
||||||
|
|
||||||
XILINX UARTLITE SERIAL DRIVER
|
XILINX UARTLITE SERIAL DRIVER
|
||||||
M: Peter Korsgaard <jacmet@sunsite.dk>
|
M: Peter Korsgaard <jacmet@sunsite.dk>
|
||||||
L: linux-serial@vger.kernel.org
|
L: linux-serial@vger.kernel.org
|
||||||
|
@ -164,7 +164,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
rtc: rtc@10070000 {
|
rtc: rtc@10070000 {
|
||||||
compatible = "samsung,s3c6410-rtc";
|
compatible = "samsung,exynos3250-rtc";
|
||||||
reg = <0x10070000 0x100>;
|
reg = <0x10070000 0x100>;
|
||||||
interrupts = <0 73 0>, <0 74 0>;
|
interrupts = <0 73 0>, <0 74 0>;
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
|
@ -416,17 +416,17 @@ static struct pxafb_mach_info *lpd270_lcd_to_use;
|
|||||||
|
|
||||||
static int __init lpd270_set_lcd(char *str)
|
static int __init lpd270_set_lcd(char *str)
|
||||||
{
|
{
|
||||||
if (!strnicmp(str, "lq057q3dc02", 11)) {
|
if (!strncasecmp(str, "lq057q3dc02", 11)) {
|
||||||
lpd270_lcd_to_use = &sharp_lq057q3dc02;
|
lpd270_lcd_to_use = &sharp_lq057q3dc02;
|
||||||
} else if (!strnicmp(str, "lq121s1dg31", 11)) {
|
} else if (!strncasecmp(str, "lq121s1dg31", 11)) {
|
||||||
lpd270_lcd_to_use = &sharp_lq121s1dg31;
|
lpd270_lcd_to_use = &sharp_lq121s1dg31;
|
||||||
} else if (!strnicmp(str, "lq036q1da01", 11)) {
|
} else if (!strncasecmp(str, "lq036q1da01", 11)) {
|
||||||
lpd270_lcd_to_use = &sharp_lq036q1da01;
|
lpd270_lcd_to_use = &sharp_lq036q1da01;
|
||||||
} else if (!strnicmp(str, "lq64d343", 8)) {
|
} else if (!strncasecmp(str, "lq64d343", 8)) {
|
||||||
lpd270_lcd_to_use = &sharp_lq64d343;
|
lpd270_lcd_to_use = &sharp_lq64d343;
|
||||||
} else if (!strnicmp(str, "lq10d368", 8)) {
|
} else if (!strncasecmp(str, "lq10d368", 8)) {
|
||||||
lpd270_lcd_to_use = &sharp_lq10d368;
|
lpd270_lcd_to_use = &sharp_lq10d368;
|
||||||
} else if (!strnicmp(str, "lq035q7db02-20", 14)) {
|
} else if (!strncasecmp(str, "lq035q7db02-20", 14)) {
|
||||||
lpd270_lcd_to_use = &sharp_lq035q7db02_20;
|
lpd270_lcd_to_use = &sharp_lq035q7db02_20;
|
||||||
} else {
|
} else {
|
||||||
printk(KERN_INFO "lpd270: unknown lcd panel [%s]\n", str);
|
printk(KERN_INFO "lpd270: unknown lcd panel [%s]\n", str);
|
||||||
|
@ -6,8 +6,6 @@
|
|||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
|
|
||||||
extern const struct exception_table_entry __attribute__((aligned(8))) __start___ex_table[];
|
|
||||||
extern const struct exception_table_entry __attribute__((aligned(8))) __stop___ex_table[];
|
|
||||||
extern const void __memset_end, __memset_user_error_lr, __memset_user_error_handler;
|
extern const void __memset_end, __memset_user_error_lr, __memset_user_error_handler;
|
||||||
extern const void __memcpy_end, __memcpy_user_error_lr, __memcpy_user_error_handler;
|
extern const void __memcpy_end, __memcpy_user_error_lr, __memcpy_user_error_handler;
|
||||||
extern spinlock_t modlist_lock;
|
extern spinlock_t modlist_lock;
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
#include <asm-generic/sections.h>
|
#include <asm-generic/sections.h>
|
||||||
|
|
||||||
extern char __per_cpu_start[], __per_cpu_end[], __phys_per_cpu_start[];
|
extern char __phys_per_cpu_start[];
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
extern char __cpu0_per_cpu[];
|
extern char __cpu0_per_cpu[];
|
||||||
#endif
|
#endif
|
||||||
|
@ -964,6 +964,7 @@ static void vgetcpu_set_mode(void)
|
|||||||
vgetcpu_mode = VGETCPU_LSL;
|
vgetcpu_mode = VGETCPU_LSL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_IA32_EMULATION
|
||||||
/* May not be __init: called during resume */
|
/* May not be __init: called during resume */
|
||||||
static void syscall32_cpu_init(void)
|
static void syscall32_cpu_init(void)
|
||||||
{
|
{
|
||||||
@ -975,7 +976,8 @@ static void syscall32_cpu_init(void)
|
|||||||
|
|
||||||
wrmsrl(MSR_CSTAR, ia32_cstar_target);
|
wrmsrl(MSR_CSTAR, ia32_cstar_target);
|
||||||
}
|
}
|
||||||
#endif
|
#endif /* CONFIG_IA32_EMULATION */
|
||||||
|
#endif /* CONFIG_X86_64 */
|
||||||
|
|
||||||
#ifdef CONFIG_X86_32
|
#ifdef CONFIG_X86_32
|
||||||
void enable_sep_cpu(void)
|
void enable_sep_cpu(void)
|
||||||
|
@ -237,7 +237,7 @@ static void fill_up_crash_elf_data(struct crash_elf_data *ced,
|
|||||||
ced->max_nr_ranges++;
|
ced->max_nr_ranges++;
|
||||||
|
|
||||||
/* If crashk_low_res is not 0, another range split possible */
|
/* If crashk_low_res is not 0, another range split possible */
|
||||||
if (crashk_low_res.end != 0)
|
if (crashk_low_res.end)
|
||||||
ced->max_nr_ranges++;
|
ced->max_nr_ranges++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,9 +335,11 @@ static int elf_header_exclude_ranges(struct crash_elf_data *ced,
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = exclude_mem_range(cmem, crashk_low_res.start, crashk_low_res.end);
|
if (crashk_low_res.end) {
|
||||||
if (ret)
|
ret = exclude_mem_range(cmem, crashk_low_res.start, crashk_low_res.end);
|
||||||
return ret;
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* Exclude GART region */
|
/* Exclude GART region */
|
||||||
if (ced->gart_end) {
|
if (ced->gart_end) {
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include <asm/setup.h>
|
#include <asm/setup.h>
|
||||||
#include <asm/crash.h>
|
#include <asm/crash.h>
|
||||||
#include <asm/efi.h>
|
#include <asm/efi.h>
|
||||||
|
#include <asm/kexec-bzimage64.h>
|
||||||
|
|
||||||
#define MAX_ELFCOREHDR_STR_LEN 30 /* elfcorehdr=0x<64bit-value> */
|
#define MAX_ELFCOREHDR_STR_LEN 30 /* elfcorehdr=0x<64bit-value> */
|
||||||
|
|
||||||
@ -267,7 +268,7 @@ setup_boot_parameters(struct kimage *image, struct boot_params *params,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bzImage64_probe(const char *buf, unsigned long len)
|
static int bzImage64_probe(const char *buf, unsigned long len)
|
||||||
{
|
{
|
||||||
int ret = -ENOEXEC;
|
int ret = -ENOEXEC;
|
||||||
struct setup_header *header;
|
struct setup_header *header;
|
||||||
@ -325,10 +326,10 @@ int bzImage64_probe(const char *buf, unsigned long len)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *bzImage64_load(struct kimage *image, char *kernel,
|
static void *bzImage64_load(struct kimage *image, char *kernel,
|
||||||
unsigned long kernel_len, char *initrd,
|
unsigned long kernel_len, char *initrd,
|
||||||
unsigned long initrd_len, char *cmdline,
|
unsigned long initrd_len, char *cmdline,
|
||||||
unsigned long cmdline_len)
|
unsigned long cmdline_len)
|
||||||
{
|
{
|
||||||
|
|
||||||
struct setup_header *header;
|
struct setup_header *header;
|
||||||
@ -514,7 +515,7 @@ out_free_params:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* This cleanup function is called after various segments have been loaded */
|
/* This cleanup function is called after various segments have been loaded */
|
||||||
int bzImage64_cleanup(void *loader_data)
|
static int bzImage64_cleanup(void *loader_data)
|
||||||
{
|
{
|
||||||
struct bzimage64_data *ldata = loader_data;
|
struct bzimage64_data *ldata = loader_data;
|
||||||
|
|
||||||
@ -528,7 +529,7 @@ int bzImage64_cleanup(void *loader_data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_KEXEC_BZIMAGE_VERIFY_SIG
|
#ifdef CONFIG_KEXEC_BZIMAGE_VERIFY_SIG
|
||||||
int bzImage64_verify_sig(const char *kernel, unsigned long kernel_len)
|
static int bzImage64_verify_sig(const char *kernel, unsigned long kernel_len)
|
||||||
{
|
{
|
||||||
bool trusted;
|
bool trusted;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/kprobes.h>
|
#include <linux/kprobes.h>
|
||||||
#include <linux/debugfs.h>
|
#include <linux/debugfs.h>
|
||||||
|
#include <linux/nmi.h>
|
||||||
#include <asm/timer.h>
|
#include <asm/timer.h>
|
||||||
#include <asm/cpu.h>
|
#include <asm/cpu.h>
|
||||||
#include <asm/traps.h>
|
#include <asm/traps.h>
|
||||||
@ -499,6 +500,13 @@ void __init kvm_guest_init(void)
|
|||||||
#else
|
#else
|
||||||
kvm_guest_cpu_init();
|
kvm_guest_cpu_init();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hard lockup detection is enabled by default. Disable it, as guests
|
||||||
|
* can get false positives too easily, for example if the host is
|
||||||
|
* overcommitted.
|
||||||
|
*/
|
||||||
|
watchdog_enable_hardlockup_detector(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static noinline uint32_t __kvm_cpuid_base(void)
|
static noinline uint32_t __kvm_cpuid_base(void)
|
||||||
|
@ -86,6 +86,7 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr,
|
|||||||
pgprot_t prot;
|
pgprot_t prot;
|
||||||
int retval;
|
int retval;
|
||||||
void __iomem *ret_addr;
|
void __iomem *ret_addr;
|
||||||
|
int ram_region;
|
||||||
|
|
||||||
/* Don't allow wraparound or zero size */
|
/* Don't allow wraparound or zero size */
|
||||||
last_addr = phys_addr + size - 1;
|
last_addr = phys_addr + size - 1;
|
||||||
@ -108,12 +109,23 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr,
|
|||||||
/*
|
/*
|
||||||
* Don't allow anybody to remap normal RAM that we're using..
|
* Don't allow anybody to remap normal RAM that we're using..
|
||||||
*/
|
*/
|
||||||
pfn = phys_addr >> PAGE_SHIFT;
|
/* First check if whole region can be identified as RAM or not */
|
||||||
last_pfn = last_addr >> PAGE_SHIFT;
|
ram_region = region_is_ram(phys_addr, size);
|
||||||
if (walk_system_ram_range(pfn, last_pfn - pfn + 1, NULL,
|
if (ram_region > 0) {
|
||||||
__ioremap_check_ram) == 1)
|
WARN_ONCE(1, "ioremap on RAM at 0x%lx - 0x%lx\n",
|
||||||
|
(unsigned long int)phys_addr,
|
||||||
|
(unsigned long int)last_addr);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If could not be identified(-1), check page by page */
|
||||||
|
if (ram_region < 0) {
|
||||||
|
pfn = phys_addr >> PAGE_SHIFT;
|
||||||
|
last_pfn = last_addr >> PAGE_SHIFT;
|
||||||
|
if (walk_system_ram_range(pfn, last_pfn - pfn + 1, NULL,
|
||||||
|
__ioremap_check_ram) == 1)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* Mappings have to be page-aligned
|
* Mappings have to be page-aligned
|
||||||
*/
|
*/
|
||||||
|
@ -463,6 +463,42 @@ static bool __init numa_meminfo_cover_memory(const struct numa_meminfo *mi)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void __init numa_clear_kernel_node_hotplug(void)
|
||||||
|
{
|
||||||
|
int i, nid;
|
||||||
|
nodemask_t numa_kernel_nodes = NODE_MASK_NONE;
|
||||||
|
unsigned long start, end;
|
||||||
|
struct memblock_region *r;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* At this time, all memory regions reserved by memblock are
|
||||||
|
* used by the kernel. Set the nid in memblock.reserved will
|
||||||
|
* mark out all the nodes the kernel resides in.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < numa_meminfo.nr_blks; i++) {
|
||||||
|
struct numa_memblk *mb = &numa_meminfo.blk[i];
|
||||||
|
|
||||||
|
memblock_set_node(mb->start, mb->end - mb->start,
|
||||||
|
&memblock.reserved, mb->nid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mark all kernel nodes. */
|
||||||
|
for_each_memblock(reserved, r)
|
||||||
|
node_set(r->nid, numa_kernel_nodes);
|
||||||
|
|
||||||
|
/* Clear MEMBLOCK_HOTPLUG flag for memory in kernel nodes. */
|
||||||
|
for (i = 0; i < numa_meminfo.nr_blks; i++) {
|
||||||
|
nid = numa_meminfo.blk[i].nid;
|
||||||
|
if (!node_isset(nid, numa_kernel_nodes))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
start = numa_meminfo.blk[i].start;
|
||||||
|
end = numa_meminfo.blk[i].end;
|
||||||
|
|
||||||
|
memblock_clear_hotplug(start, end - start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int __init numa_register_memblks(struct numa_meminfo *mi)
|
static int __init numa_register_memblks(struct numa_meminfo *mi)
|
||||||
{
|
{
|
||||||
unsigned long uninitialized_var(pfn_align);
|
unsigned long uninitialized_var(pfn_align);
|
||||||
@ -480,6 +516,15 @@ static int __init numa_register_memblks(struct numa_meminfo *mi)
|
|||||||
&memblock.memory, mb->nid);
|
&memblock.memory, mb->nid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* At very early time, the kernel have to use some memory such as
|
||||||
|
* loading the kernel image. We cannot prevent this anyway. So any
|
||||||
|
* node the kernel resides in should be un-hotpluggable.
|
||||||
|
*
|
||||||
|
* And when we come here, alloc node data won't fail.
|
||||||
|
*/
|
||||||
|
numa_clear_kernel_node_hotplug();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If sections array is gonna be used for pfn -> nid mapping, check
|
* If sections array is gonna be used for pfn -> nid mapping, check
|
||||||
* whether its granularity is fine enough.
|
* whether its granularity is fine enough.
|
||||||
@ -548,41 +593,6 @@ static void __init numa_init_array(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __init numa_clear_kernel_node_hotplug(void)
|
|
||||||
{
|
|
||||||
int i, nid;
|
|
||||||
nodemask_t numa_kernel_nodes = NODE_MASK_NONE;
|
|
||||||
unsigned long start, end;
|
|
||||||
struct memblock_region *r;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* At this time, all memory regions reserved by memblock are
|
|
||||||
* used by the kernel. Set the nid in memblock.reserved will
|
|
||||||
* mark out all the nodes the kernel resides in.
|
|
||||||
*/
|
|
||||||
for (i = 0; i < numa_meminfo.nr_blks; i++) {
|
|
||||||
struct numa_memblk *mb = &numa_meminfo.blk[i];
|
|
||||||
memblock_set_node(mb->start, mb->end - mb->start,
|
|
||||||
&memblock.reserved, mb->nid);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Mark all kernel nodes. */
|
|
||||||
for_each_memblock(reserved, r)
|
|
||||||
node_set(r->nid, numa_kernel_nodes);
|
|
||||||
|
|
||||||
/* Clear MEMBLOCK_HOTPLUG flag for memory in kernel nodes. */
|
|
||||||
for (i = 0; i < numa_meminfo.nr_blks; i++) {
|
|
||||||
nid = numa_meminfo.blk[i].nid;
|
|
||||||
if (!node_isset(nid, numa_kernel_nodes))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
start = numa_meminfo.blk[i].start;
|
|
||||||
end = numa_meminfo.blk[i].end;
|
|
||||||
|
|
||||||
memblock_clear_hotplug(start, end - start);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __init numa_init(int (*init_func)(void))
|
static int __init numa_init(int (*init_func)(void))
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -637,15 +647,6 @@ static int __init numa_init(int (*init_func)(void))
|
|||||||
}
|
}
|
||||||
numa_init_array();
|
numa_init_array();
|
||||||
|
|
||||||
/*
|
|
||||||
* At very early time, the kernel have to use some memory such as
|
|
||||||
* loading the kernel image. We cannot prevent this anyway. So any
|
|
||||||
* node the kernel resides in should be un-hotpluggable.
|
|
||||||
*
|
|
||||||
* And when we come here, numa_init() won't fail.
|
|
||||||
*/
|
|
||||||
numa_clear_kernel_node_hotplug();
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,8 +18,9 @@ $(obj)/purgatory.ro: $(PURGATORY_OBJS) FORCE
|
|||||||
|
|
||||||
targets += kexec-purgatory.c
|
targets += kexec-purgatory.c
|
||||||
|
|
||||||
|
CMD_BIN2C = $(objtree)/scripts/basic/bin2c
|
||||||
quiet_cmd_bin2c = BIN2C $@
|
quiet_cmd_bin2c = BIN2C $@
|
||||||
cmd_bin2c = cat $(obj)/purgatory.ro | $(objtree)/scripts/basic/bin2c kexec_purgatory > $(obj)/kexec-purgatory.c
|
cmd_bin2c = $(CMD_BIN2C) kexec_purgatory < $< > $@
|
||||||
|
|
||||||
$(obj)/kexec-purgatory.c: $(obj)/purgatory.ro FORCE
|
$(obj)/kexec-purgatory.c: $(obj)/purgatory.ro FORCE
|
||||||
$(call if_changed,bin2c)
|
$(call if_changed,bin2c)
|
||||||
|
@ -14,11 +14,14 @@ struct dma_coherent_mem {
|
|||||||
int size;
|
int size;
|
||||||
int flags;
|
int flags;
|
||||||
unsigned long *bitmap;
|
unsigned long *bitmap;
|
||||||
|
spinlock_t spinlock;
|
||||||
};
|
};
|
||||||
|
|
||||||
int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr,
|
static int dma_init_coherent_memory(phys_addr_t phys_addr, dma_addr_t device_addr,
|
||||||
dma_addr_t device_addr, size_t size, int flags)
|
size_t size, int flags,
|
||||||
|
struct dma_coherent_mem **mem)
|
||||||
{
|
{
|
||||||
|
struct dma_coherent_mem *dma_mem = NULL;
|
||||||
void __iomem *mem_base = NULL;
|
void __iomem *mem_base = NULL;
|
||||||
int pages = size >> PAGE_SHIFT;
|
int pages = size >> PAGE_SHIFT;
|
||||||
int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long);
|
int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long);
|
||||||
@ -27,40 +30,77 @@ int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr,
|
|||||||
goto out;
|
goto out;
|
||||||
if (!size)
|
if (!size)
|
||||||
goto out;
|
goto out;
|
||||||
if (dev->dma_mem)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
/* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */
|
|
||||||
|
|
||||||
mem_base = ioremap(phys_addr, size);
|
mem_base = ioremap(phys_addr, size);
|
||||||
if (!mem_base)
|
if (!mem_base)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
dev->dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL);
|
dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL);
|
||||||
if (!dev->dma_mem)
|
if (!dma_mem)
|
||||||
|
goto out;
|
||||||
|
dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
|
||||||
|
if (!dma_mem->bitmap)
|
||||||
goto out;
|
goto out;
|
||||||
dev->dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
|
|
||||||
if (!dev->dma_mem->bitmap)
|
|
||||||
goto free1_out;
|
|
||||||
|
|
||||||
dev->dma_mem->virt_base = mem_base;
|
dma_mem->virt_base = mem_base;
|
||||||
dev->dma_mem->device_base = device_addr;
|
dma_mem->device_base = device_addr;
|
||||||
dev->dma_mem->pfn_base = PFN_DOWN(phys_addr);
|
dma_mem->pfn_base = PFN_DOWN(phys_addr);
|
||||||
dev->dma_mem->size = pages;
|
dma_mem->size = pages;
|
||||||
dev->dma_mem->flags = flags;
|
dma_mem->flags = flags;
|
||||||
|
spin_lock_init(&dma_mem->spinlock);
|
||||||
|
|
||||||
|
*mem = dma_mem;
|
||||||
|
|
||||||
if (flags & DMA_MEMORY_MAP)
|
if (flags & DMA_MEMORY_MAP)
|
||||||
return DMA_MEMORY_MAP;
|
return DMA_MEMORY_MAP;
|
||||||
|
|
||||||
return DMA_MEMORY_IO;
|
return DMA_MEMORY_IO;
|
||||||
|
|
||||||
free1_out:
|
out:
|
||||||
kfree(dev->dma_mem);
|
kfree(dma_mem);
|
||||||
out:
|
|
||||||
if (mem_base)
|
if (mem_base)
|
||||||
iounmap(mem_base);
|
iounmap(mem_base);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dma_release_coherent_memory(struct dma_coherent_mem *mem)
|
||||||
|
{
|
||||||
|
if (!mem)
|
||||||
|
return;
|
||||||
|
iounmap(mem->virt_base);
|
||||||
|
kfree(mem->bitmap);
|
||||||
|
kfree(mem);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dma_assign_coherent_memory(struct device *dev,
|
||||||
|
struct dma_coherent_mem *mem)
|
||||||
|
{
|
||||||
|
if (dev->dma_mem)
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
|
dev->dma_mem = mem;
|
||||||
|
/* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr,
|
||||||
|
dma_addr_t device_addr, size_t size, int flags)
|
||||||
|
{
|
||||||
|
struct dma_coherent_mem *mem;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = dma_init_coherent_memory(phys_addr, device_addr, size, flags,
|
||||||
|
&mem);
|
||||||
|
if (ret == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (dma_assign_coherent_memory(dev, mem) == 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
dma_release_coherent_memory(mem);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
EXPORT_SYMBOL(dma_declare_coherent_memory);
|
EXPORT_SYMBOL(dma_declare_coherent_memory);
|
||||||
|
|
||||||
void dma_release_declared_memory(struct device *dev)
|
void dma_release_declared_memory(struct device *dev)
|
||||||
@ -69,10 +109,8 @@ void dma_release_declared_memory(struct device *dev)
|
|||||||
|
|
||||||
if (!mem)
|
if (!mem)
|
||||||
return;
|
return;
|
||||||
|
dma_release_coherent_memory(mem);
|
||||||
dev->dma_mem = NULL;
|
dev->dma_mem = NULL;
|
||||||
iounmap(mem->virt_base);
|
|
||||||
kfree(mem->bitmap);
|
|
||||||
kfree(mem);
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(dma_release_declared_memory);
|
EXPORT_SYMBOL(dma_release_declared_memory);
|
||||||
|
|
||||||
@ -80,6 +118,7 @@ void *dma_mark_declared_memory_occupied(struct device *dev,
|
|||||||
dma_addr_t device_addr, size_t size)
|
dma_addr_t device_addr, size_t size)
|
||||||
{
|
{
|
||||||
struct dma_coherent_mem *mem = dev->dma_mem;
|
struct dma_coherent_mem *mem = dev->dma_mem;
|
||||||
|
unsigned long flags;
|
||||||
int pos, err;
|
int pos, err;
|
||||||
|
|
||||||
size += device_addr & ~PAGE_MASK;
|
size += device_addr & ~PAGE_MASK;
|
||||||
@ -87,8 +126,11 @@ void *dma_mark_declared_memory_occupied(struct device *dev,
|
|||||||
if (!mem)
|
if (!mem)
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&mem->spinlock, flags);
|
||||||
pos = (device_addr - mem->device_base) >> PAGE_SHIFT;
|
pos = (device_addr - mem->device_base) >> PAGE_SHIFT;
|
||||||
err = bitmap_allocate_region(mem->bitmap, pos, get_order(size));
|
err = bitmap_allocate_region(mem->bitmap, pos, get_order(size));
|
||||||
|
spin_unlock_irqrestore(&mem->spinlock, flags);
|
||||||
|
|
||||||
if (err != 0)
|
if (err != 0)
|
||||||
return ERR_PTR(err);
|
return ERR_PTR(err);
|
||||||
return mem->virt_base + (pos << PAGE_SHIFT);
|
return mem->virt_base + (pos << PAGE_SHIFT);
|
||||||
@ -115,6 +157,7 @@ int dma_alloc_from_coherent(struct device *dev, ssize_t size,
|
|||||||
{
|
{
|
||||||
struct dma_coherent_mem *mem;
|
struct dma_coherent_mem *mem;
|
||||||
int order = get_order(size);
|
int order = get_order(size);
|
||||||
|
unsigned long flags;
|
||||||
int pageno;
|
int pageno;
|
||||||
|
|
||||||
if (!dev)
|
if (!dev)
|
||||||
@ -124,6 +167,7 @@ int dma_alloc_from_coherent(struct device *dev, ssize_t size,
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
*ret = NULL;
|
*ret = NULL;
|
||||||
|
spin_lock_irqsave(&mem->spinlock, flags);
|
||||||
|
|
||||||
if (unlikely(size > (mem->size << PAGE_SHIFT)))
|
if (unlikely(size > (mem->size << PAGE_SHIFT)))
|
||||||
goto err;
|
goto err;
|
||||||
@ -138,10 +182,12 @@ int dma_alloc_from_coherent(struct device *dev, ssize_t size,
|
|||||||
*dma_handle = mem->device_base + (pageno << PAGE_SHIFT);
|
*dma_handle = mem->device_base + (pageno << PAGE_SHIFT);
|
||||||
*ret = mem->virt_base + (pageno << PAGE_SHIFT);
|
*ret = mem->virt_base + (pageno << PAGE_SHIFT);
|
||||||
memset(*ret, 0, size);
|
memset(*ret, 0, size);
|
||||||
|
spin_unlock_irqrestore(&mem->spinlock, flags);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
|
spin_unlock_irqrestore(&mem->spinlock, flags);
|
||||||
/*
|
/*
|
||||||
* In the case where the allocation can not be satisfied from the
|
* In the case where the allocation can not be satisfied from the
|
||||||
* per-device area, try to fall back to generic memory if the
|
* per-device area, try to fall back to generic memory if the
|
||||||
@ -171,8 +217,11 @@ int dma_release_from_coherent(struct device *dev, int order, void *vaddr)
|
|||||||
if (mem && vaddr >= mem->virt_base && vaddr <
|
if (mem && vaddr >= mem->virt_base && vaddr <
|
||||||
(mem->virt_base + (mem->size << PAGE_SHIFT))) {
|
(mem->virt_base + (mem->size << PAGE_SHIFT))) {
|
||||||
int page = (vaddr - mem->virt_base) >> PAGE_SHIFT;
|
int page = (vaddr - mem->virt_base) >> PAGE_SHIFT;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&mem->spinlock, flags);
|
||||||
bitmap_release_region(mem->bitmap, page, order);
|
bitmap_release_region(mem->bitmap, page, order);
|
||||||
|
spin_unlock_irqrestore(&mem->spinlock, flags);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -218,3 +267,61 @@ int dma_mmap_from_coherent(struct device *dev, struct vm_area_struct *vma,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(dma_mmap_from_coherent);
|
EXPORT_SYMBOL(dma_mmap_from_coherent);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Support for reserved memory regions defined in device tree
|
||||||
|
*/
|
||||||
|
#ifdef CONFIG_OF_RESERVED_MEM
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_fdt.h>
|
||||||
|
#include <linux/of_reserved_mem.h>
|
||||||
|
|
||||||
|
static int rmem_dma_device_init(struct reserved_mem *rmem, struct device *dev)
|
||||||
|
{
|
||||||
|
struct dma_coherent_mem *mem = rmem->priv;
|
||||||
|
|
||||||
|
if (!mem &&
|
||||||
|
dma_init_coherent_memory(rmem->base, rmem->base, rmem->size,
|
||||||
|
DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE,
|
||||||
|
&mem) != DMA_MEMORY_MAP) {
|
||||||
|
pr_err("Reserved memory: failed to init DMA memory pool at %pa, size %ld MiB\n",
|
||||||
|
&rmem->base, (unsigned long)rmem->size / SZ_1M);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
rmem->priv = mem;
|
||||||
|
dma_assign_coherent_memory(dev, mem);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rmem_dma_device_release(struct reserved_mem *rmem,
|
||||||
|
struct device *dev)
|
||||||
|
{
|
||||||
|
dev->dma_mem = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct reserved_mem_ops rmem_dma_ops = {
|
||||||
|
.device_init = rmem_dma_device_init,
|
||||||
|
.device_release = rmem_dma_device_release,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init rmem_dma_setup(struct reserved_mem *rmem)
|
||||||
|
{
|
||||||
|
unsigned long node = rmem->fdt_node;
|
||||||
|
|
||||||
|
if (of_get_flat_dt_prop(node, "reusable", NULL))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
#ifdef CONFIG_ARM
|
||||||
|
if (!of_get_flat_dt_prop(node, "no-map", NULL)) {
|
||||||
|
pr_err("Reserved memory: regions without no-map are not yet supported\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
rmem->ops = &rmem_dma_ops;
|
||||||
|
pr_info("Reserved memory: created DMA memory pool at %pa, size %ld MiB\n",
|
||||||
|
&rmem->base, (unsigned long)rmem->size / SZ_1M);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
RESERVEDMEM_OF_DECLARE(dma, "shared-dma-pool", rmem_dma_setup);
|
||||||
|
#endif
|
||||||
|
@ -211,3 +211,69 @@ bool dma_release_from_contiguous(struct device *dev, struct page *pages,
|
|||||||
{
|
{
|
||||||
return cma_release(dev_get_cma_area(dev), pages, count);
|
return cma_release(dev_get_cma_area(dev), pages, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Support for reserved memory regions defined in device tree
|
||||||
|
*/
|
||||||
|
#ifdef CONFIG_OF_RESERVED_MEM
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_fdt.h>
|
||||||
|
#include <linux/of_reserved_mem.h>
|
||||||
|
|
||||||
|
#undef pr_fmt
|
||||||
|
#define pr_fmt(fmt) fmt
|
||||||
|
|
||||||
|
static void rmem_cma_device_init(struct reserved_mem *rmem, struct device *dev)
|
||||||
|
{
|
||||||
|
dev_set_cma_area(dev, rmem->priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rmem_cma_device_release(struct reserved_mem *rmem,
|
||||||
|
struct device *dev)
|
||||||
|
{
|
||||||
|
dev_set_cma_area(dev, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct reserved_mem_ops rmem_cma_ops = {
|
||||||
|
.device_init = rmem_cma_device_init,
|
||||||
|
.device_release = rmem_cma_device_release,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init rmem_cma_setup(struct reserved_mem *rmem)
|
||||||
|
{
|
||||||
|
phys_addr_t align = PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order);
|
||||||
|
phys_addr_t mask = align - 1;
|
||||||
|
unsigned long node = rmem->fdt_node;
|
||||||
|
struct cma *cma;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!of_get_flat_dt_prop(node, "reusable", NULL) ||
|
||||||
|
of_get_flat_dt_prop(node, "no-map", NULL))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if ((rmem->base & mask) || (rmem->size & mask)) {
|
||||||
|
pr_err("Reserved memory: incorrect alignment of CMA region\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = cma_init_reserved_mem(rmem->base, rmem->size, 0, &cma);
|
||||||
|
if (err) {
|
||||||
|
pr_err("Reserved memory: unable to setup CMA region\n");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
/* Architecture specific contiguous memory fixup. */
|
||||||
|
dma_contiguous_early_fixup(rmem->base, rmem->size);
|
||||||
|
|
||||||
|
if (of_get_flat_dt_prop(node, "linux,cma-default", NULL))
|
||||||
|
dma_contiguous_set_default(cma);
|
||||||
|
|
||||||
|
rmem->ops = &rmem_cma_ops;
|
||||||
|
rmem->priv = cma;
|
||||||
|
|
||||||
|
pr_info("Reserved memory: created CMA memory pool at %pa, size %ld MiB\n",
|
||||||
|
&rmem->base, (unsigned long)rmem->size / SZ_1M);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
RESERVEDMEM_OF_DECLARE(cma, "shared-dma-pool", rmem_cma_setup);
|
||||||
|
#endif
|
||||||
|
@ -38,6 +38,15 @@ config COMMON_CLK_MAX77686
|
|||||||
---help---
|
---help---
|
||||||
This driver supports Maxim 77686 crystal oscillator clock.
|
This driver supports Maxim 77686 crystal oscillator clock.
|
||||||
|
|
||||||
|
config COMMON_CLK_RK808
|
||||||
|
tristate "Clock driver for RK808"
|
||||||
|
depends on MFD_RK808
|
||||||
|
---help---
|
||||||
|
This driver supports RK808 crystal oscillator clock. These
|
||||||
|
multi-function devices have two fixed-rate oscillators,
|
||||||
|
clocked at 32KHz each. Clkout1 is always on, Clkout2 can off
|
||||||
|
by control register.
|
||||||
|
|
||||||
config COMMON_CLK_SI5351
|
config COMMON_CLK_SI5351
|
||||||
tristate "Clock driver for SiLabs 5351A/B/C"
|
tristate "Clock driver for SiLabs 5351A/B/C"
|
||||||
depends on I2C
|
depends on I2C
|
||||||
|
@ -28,6 +28,7 @@ obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o
|
|||||||
obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o
|
obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o
|
||||||
obj-$(CONFIG_COMMON_CLK_PALMAS) += clk-palmas.o
|
obj-$(CONFIG_COMMON_CLK_PALMAS) += clk-palmas.o
|
||||||
obj-$(CONFIG_CLK_PPC_CORENET) += clk-ppc-corenet.o
|
obj-$(CONFIG_CLK_PPC_CORENET) += clk-ppc-corenet.o
|
||||||
|
obj-$(CONFIG_COMMON_CLK_RK808) += clk-rk808.o
|
||||||
obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o
|
obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o
|
||||||
obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o
|
obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o
|
||||||
obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o
|
obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o
|
||||||
|
170
drivers/clk/clk-rk808.c
Normal file
170
drivers/clk/clk-rk808.c
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
/*
|
||||||
|
* Clkout driver for Rockchip RK808
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
|
||||||
|
*
|
||||||
|
* Author:Chris Zhong <zyw@rock-chips.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/clk.h>
|
||||||
|
#include <linux/clk-provider.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/mfd/rk808.h>
|
||||||
|
#include <linux/i2c.h>
|
||||||
|
|
||||||
|
#define RK808_NR_OUTPUT 2
|
||||||
|
|
||||||
|
struct rk808_clkout {
|
||||||
|
struct rk808 *rk808;
|
||||||
|
struct clk_onecell_data clk_data;
|
||||||
|
struct clk_hw clkout1_hw;
|
||||||
|
struct clk_hw clkout2_hw;
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned long rk808_clkout_recalc_rate(struct clk_hw *hw,
|
||||||
|
unsigned long parent_rate)
|
||||||
|
{
|
||||||
|
return 32768;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rk808_clkout2_enable(struct clk_hw *hw, bool enable)
|
||||||
|
{
|
||||||
|
struct rk808_clkout *rk808_clkout = container_of(hw,
|
||||||
|
struct rk808_clkout,
|
||||||
|
clkout2_hw);
|
||||||
|
struct rk808 *rk808 = rk808_clkout->rk808;
|
||||||
|
|
||||||
|
return regmap_update_bits(rk808->regmap, RK808_CLK32OUT_REG,
|
||||||
|
CLK32KOUT2_EN, enable ? CLK32KOUT2_EN : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rk808_clkout2_prepare(struct clk_hw *hw)
|
||||||
|
{
|
||||||
|
return rk808_clkout2_enable(hw, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rk808_clkout2_unprepare(struct clk_hw *hw)
|
||||||
|
{
|
||||||
|
rk808_clkout2_enable(hw, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rk808_clkout2_is_prepared(struct clk_hw *hw)
|
||||||
|
{
|
||||||
|
struct rk808_clkout *rk808_clkout = container_of(hw,
|
||||||
|
struct rk808_clkout,
|
||||||
|
clkout2_hw);
|
||||||
|
struct rk808 *rk808 = rk808_clkout->rk808;
|
||||||
|
uint32_t val;
|
||||||
|
|
||||||
|
int ret = regmap_read(rk808->regmap, RK808_CLK32OUT_REG, &val);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return (val & CLK32KOUT2_EN) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct clk_ops rk808_clkout1_ops = {
|
||||||
|
.recalc_rate = rk808_clkout_recalc_rate,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct clk_ops rk808_clkout2_ops = {
|
||||||
|
.prepare = rk808_clkout2_prepare,
|
||||||
|
.unprepare = rk808_clkout2_unprepare,
|
||||||
|
.is_prepared = rk808_clkout2_is_prepared,
|
||||||
|
.recalc_rate = rk808_clkout_recalc_rate,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int rk808_clkout_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct rk808 *rk808 = dev_get_drvdata(pdev->dev.parent);
|
||||||
|
struct i2c_client *client = rk808->i2c;
|
||||||
|
struct device_node *node = client->dev.of_node;
|
||||||
|
struct clk_init_data init = {};
|
||||||
|
struct clk **clk_table;
|
||||||
|
struct rk808_clkout *rk808_clkout;
|
||||||
|
|
||||||
|
rk808_clkout = devm_kzalloc(&client->dev,
|
||||||
|
sizeof(*rk808_clkout), GFP_KERNEL);
|
||||||
|
if (!rk808_clkout)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
rk808_clkout->rk808 = rk808;
|
||||||
|
|
||||||
|
clk_table = devm_kcalloc(&client->dev, RK808_NR_OUTPUT,
|
||||||
|
sizeof(struct clk *), GFP_KERNEL);
|
||||||
|
if (!clk_table)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
init.flags = CLK_IS_ROOT;
|
||||||
|
init.parent_names = NULL;
|
||||||
|
init.num_parents = 0;
|
||||||
|
init.name = "rk808-clkout1";
|
||||||
|
init.ops = &rk808_clkout1_ops;
|
||||||
|
rk808_clkout->clkout1_hw.init = &init;
|
||||||
|
|
||||||
|
/* optional override of the clockname */
|
||||||
|
of_property_read_string_index(node, "clock-output-names",
|
||||||
|
0, &init.name);
|
||||||
|
|
||||||
|
clk_table[0] = devm_clk_register(&client->dev,
|
||||||
|
&rk808_clkout->clkout1_hw);
|
||||||
|
if (IS_ERR(clk_table[0]))
|
||||||
|
return PTR_ERR(clk_table[0]);
|
||||||
|
|
||||||
|
init.name = "rk808-clkout2";
|
||||||
|
init.ops = &rk808_clkout2_ops;
|
||||||
|
rk808_clkout->clkout2_hw.init = &init;
|
||||||
|
|
||||||
|
/* optional override of the clockname */
|
||||||
|
of_property_read_string_index(node, "clock-output-names",
|
||||||
|
1, &init.name);
|
||||||
|
|
||||||
|
clk_table[1] = devm_clk_register(&client->dev,
|
||||||
|
&rk808_clkout->clkout2_hw);
|
||||||
|
if (IS_ERR(clk_table[1]))
|
||||||
|
return PTR_ERR(clk_table[1]);
|
||||||
|
|
||||||
|
rk808_clkout->clk_data.clks = clk_table;
|
||||||
|
rk808_clkout->clk_data.clk_num = RK808_NR_OUTPUT;
|
||||||
|
|
||||||
|
return of_clk_add_provider(node, of_clk_src_onecell_get,
|
||||||
|
&rk808_clkout->clk_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rk808_clkout_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct rk808 *rk808 = dev_get_drvdata(pdev->dev.parent);
|
||||||
|
struct i2c_client *client = rk808->i2c;
|
||||||
|
struct device_node *node = client->dev.of_node;
|
||||||
|
|
||||||
|
of_clk_del_provider(node);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver rk808_clkout_driver = {
|
||||||
|
.probe = rk808_clkout_probe,
|
||||||
|
.remove = rk808_clkout_remove,
|
||||||
|
.driver = {
|
||||||
|
.name = "rk808-clkout",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module_platform_driver(rk808_clkout_driver);
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION("Clkout driver for the rk808 series PMICs");
|
||||||
|
MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_ALIAS("platform:rk808-clkout");
|
@ -3574,7 +3574,7 @@ static int srpt_parse_i_port_id(u8 i_port_id[16], const char *name)
|
|||||||
int ret, rc;
|
int ret, rc;
|
||||||
|
|
||||||
p = name;
|
p = name;
|
||||||
if (strnicmp(p, "0x", 2) == 0)
|
if (strncasecmp(p, "0x", 2) == 0)
|
||||||
p += 2;
|
p += 2;
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
len = strlen(p);
|
len = strlen(p);
|
||||||
|
@ -812,7 +812,7 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
|
|||||||
/* if we find something consistent, stay with that assumption
|
/* if we find something consistent, stay with that assumption
|
||||||
* at least M09 won't send 3 bytes here
|
* at least M09 won't send 3 bytes here
|
||||||
*/
|
*/
|
||||||
if (!(strnicmp(rdbuf + 1, "EP0", 3))) {
|
if (!(strncasecmp(rdbuf + 1, "EP0", 3))) {
|
||||||
tsdata->version = M06;
|
tsdata->version = M06;
|
||||||
|
|
||||||
/* remove last '$' end marker */
|
/* remove last '$' end marker */
|
||||||
|
@ -188,6 +188,7 @@ static void r592_host_reset(struct r592_device *dev)
|
|||||||
r592_set_mode(dev, dev->parallel_mode);
|
r592_set_mode(dev, dev->parallel_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM_SLEEP
|
||||||
/* Disable all hardware interrupts */
|
/* Disable all hardware interrupts */
|
||||||
static void r592_clear_interrupts(struct r592_device *dev)
|
static void r592_clear_interrupts(struct r592_device *dev)
|
||||||
{
|
{
|
||||||
@ -195,6 +196,7 @@ static void r592_clear_interrupts(struct r592_device *dev)
|
|||||||
r592_clear_reg_mask(dev, R592_REG_MSC, IRQ_ALL_ACK_MASK);
|
r592_clear_reg_mask(dev, R592_REG_MSC, IRQ_ALL_ACK_MASK);
|
||||||
r592_clear_reg_mask(dev, R592_REG_MSC, IRQ_ALL_EN_MASK);
|
r592_clear_reg_mask(dev, R592_REG_MSC, IRQ_ALL_EN_MASK);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Tests if there is an CRC error */
|
/* Tests if there is an CRC error */
|
||||||
static int r592_test_io_error(struct r592_device *dev)
|
static int r592_test_io_error(struct r592_device *dev)
|
||||||
|
@ -454,7 +454,7 @@ exit_done:
|
|||||||
|
|
||||||
name = &p[str_table + name_id];
|
name = &p[str_table + name_id];
|
||||||
|
|
||||||
if (strnicmp(aconf->action, name, strlen(name)) == 0) {
|
if (strncasecmp(aconf->action, name, strlen(name)) == 0) {
|
||||||
action_found = 1;
|
action_found = 1;
|
||||||
current_proc =
|
current_proc =
|
||||||
get_unaligned_be32(&p[action_table +
|
get_unaligned_be32(&p[action_table +
|
||||||
@ -2176,7 +2176,7 @@ static int altera_get_note(u8 *p, s32 program_size,
|
|||||||
key_ptr = &p[note_strings +
|
key_ptr = &p[note_strings +
|
||||||
get_unaligned_be32(
|
get_unaligned_be32(
|
||||||
&p[note_table + (8 * i)])];
|
&p[note_table + (8 * i)])];
|
||||||
if ((strnicmp(key, key_ptr, strlen(key_ptr)) == 0) &&
|
if ((strncasecmp(key, key_ptr, strlen(key_ptr)) == 0) &&
|
||||||
(key != NULL)) {
|
(key != NULL)) {
|
||||||
status = 0;
|
status = 0;
|
||||||
|
|
||||||
|
@ -168,7 +168,6 @@ static int prism2_bss_list_proc_show(struct seq_file *m, void *v)
|
|||||||
local_info_t *local = m->private;
|
local_info_t *local = m->private;
|
||||||
struct list_head *ptr = v;
|
struct list_head *ptr = v;
|
||||||
struct hostap_bss_info *bss;
|
struct hostap_bss_info *bss;
|
||||||
int i;
|
|
||||||
|
|
||||||
if (ptr == &local->bss_list) {
|
if (ptr == &local->bss_list) {
|
||||||
seq_printf(m, "#BSSID\tlast_update\tcount\tcapab_info\tSSID(txt)\t"
|
seq_printf(m, "#BSSID\tlast_update\tcount\tcapab_info\tSSID(txt)\t"
|
||||||
@ -181,9 +180,7 @@ static int prism2_bss_list_proc_show(struct seq_file *m, void *v)
|
|||||||
bss->bssid, bss->last_update,
|
bss->bssid, bss->last_update,
|
||||||
bss->count, bss->capab_info);
|
bss->count, bss->capab_info);
|
||||||
|
|
||||||
for (i = 0; i < bss->ssid_len; i++)
|
seq_printf(m, "%*pE", (int)bss->ssid_len, bss->ssid);
|
||||||
seq_putc(m,bss->ssid[i] >= 32 && bss->ssid[i] < 127 ?
|
|
||||||
bss->ssid[i] : '_');
|
|
||||||
|
|
||||||
seq_putc(m, '\t');
|
seq_putc(m, '\t');
|
||||||
seq_printf(m, "%*phN", (int)bss->ssid_len, bss->ssid);
|
seq_printf(m, "%*phN", (int)bss->ssid_len, bss->ssid);
|
||||||
|
@ -2005,7 +2005,6 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status)
|
|||||||
u32 chan;
|
u32 chan;
|
||||||
char *txratename;
|
char *txratename;
|
||||||
u8 bssid[ETH_ALEN];
|
u8 bssid[ETH_ALEN];
|
||||||
DECLARE_SSID_BUF(ssid);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TBD: BSSID is usually 00:00:00:00:00:00 here and not
|
* TBD: BSSID is usually 00:00:00:00:00:00 here and not
|
||||||
@ -2067,8 +2066,8 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPW_DEBUG_INFO("%s: Associated with '%s' at %s, channel %d (BSSID=%pM)\n",
|
IPW_DEBUG_INFO("%s: Associated with '%*pE' at %s, channel %d (BSSID=%pM)\n",
|
||||||
priv->net_dev->name, print_ssid(ssid, essid, essid_len),
|
priv->net_dev->name, essid_len, essid,
|
||||||
txratename, chan, bssid);
|
txratename, chan, bssid);
|
||||||
|
|
||||||
/* now we copy read ssid into dev */
|
/* now we copy read ssid into dev */
|
||||||
@ -2095,9 +2094,8 @@ static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid,
|
|||||||
.host_command_length = ssid_len
|
.host_command_length = ssid_len
|
||||||
};
|
};
|
||||||
int err;
|
int err;
|
||||||
DECLARE_SSID_BUF(ssid);
|
|
||||||
|
|
||||||
IPW_DEBUG_HC("SSID: '%s'\n", print_ssid(ssid, essid, ssid_len));
|
IPW_DEBUG_HC("SSID: '%*pE'\n", ssid_len, essid);
|
||||||
|
|
||||||
if (ssid_len)
|
if (ssid_len)
|
||||||
memcpy(cmd.host_command_parameters, essid, ssid_len);
|
memcpy(cmd.host_command_parameters, essid, ssid_len);
|
||||||
@ -2138,11 +2136,8 @@ static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid,
|
|||||||
|
|
||||||
static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status)
|
static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status)
|
||||||
{
|
{
|
||||||
DECLARE_SSID_BUF(ssid);
|
|
||||||
|
|
||||||
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC,
|
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC,
|
||||||
"disassociated: '%s' %pM\n",
|
"disassociated: '%*pE' %pM\n", priv->essid_len, priv->essid,
|
||||||
print_ssid(ssid, priv->essid, priv->essid_len),
|
|
||||||
priv->bssid);
|
priv->bssid);
|
||||||
|
|
||||||
priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
|
priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
|
||||||
@ -6975,7 +6970,6 @@ static int ipw2100_wx_set_essid(struct net_device *dev,
|
|||||||
char *essid = ""; /* ANY */
|
char *essid = ""; /* ANY */
|
||||||
int length = 0;
|
int length = 0;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
DECLARE_SSID_BUF(ssid);
|
|
||||||
|
|
||||||
mutex_lock(&priv->action_mutex);
|
mutex_lock(&priv->action_mutex);
|
||||||
if (!(priv->status & STATUS_INITIALIZED)) {
|
if (!(priv->status & STATUS_INITIALIZED)) {
|
||||||
@ -7005,8 +6999,7 @@ static int ipw2100_wx_set_essid(struct net_device *dev,
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n",
|
IPW_DEBUG_WX("Setting ESSID: '%*pE' (%d)\n", length, essid, length);
|
||||||
print_ssid(ssid, essid, length), length);
|
|
||||||
|
|
||||||
priv->essid_len = length;
|
priv->essid_len = length;
|
||||||
memcpy(priv->essid, essid, priv->essid_len);
|
memcpy(priv->essid, essid, priv->essid_len);
|
||||||
@ -7027,13 +7020,12 @@ static int ipw2100_wx_get_essid(struct net_device *dev,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
struct ipw2100_priv *priv = libipw_priv(dev);
|
struct ipw2100_priv *priv = libipw_priv(dev);
|
||||||
DECLARE_SSID_BUF(ssid);
|
|
||||||
|
|
||||||
/* If we are associated, trying to associate, or have a statically
|
/* If we are associated, trying to associate, or have a statically
|
||||||
* configured ESSID then return that; otherwise return ANY */
|
* configured ESSID then return that; otherwise return ANY */
|
||||||
if (priv->config & CFG_STATIC_ESSID || priv->status & STATUS_ASSOCIATED) {
|
if (priv->config & CFG_STATIC_ESSID || priv->status & STATUS_ASSOCIATED) {
|
||||||
IPW_DEBUG_WX("Getting essid: '%s'\n",
|
IPW_DEBUG_WX("Getting essid: '%*pE'\n",
|
||||||
print_ssid(ssid, priv->essid, priv->essid_len));
|
priv->essid_len, priv->essid);
|
||||||
memcpy(extra, priv->essid, priv->essid_len);
|
memcpy(extra, priv->essid, priv->essid_len);
|
||||||
wrqu->essid.length = priv->essid_len;
|
wrqu->essid.length = priv->essid_len;
|
||||||
wrqu->essid.flags = 1; /* active */
|
wrqu->essid.flags = 1; /* active */
|
||||||
|
@ -4496,7 +4496,6 @@ static void handle_scan_event(struct ipw_priv *priv)
|
|||||||
static void ipw_rx_notification(struct ipw_priv *priv,
|
static void ipw_rx_notification(struct ipw_priv *priv,
|
||||||
struct ipw_rx_notification *notif)
|
struct ipw_rx_notification *notif)
|
||||||
{
|
{
|
||||||
DECLARE_SSID_BUF(ssid);
|
|
||||||
u16 size = le16_to_cpu(notif->size);
|
u16 size = le16_to_cpu(notif->size);
|
||||||
|
|
||||||
IPW_DEBUG_NOTIF("type = %i (%d bytes)\n", notif->subtype, size);
|
IPW_DEBUG_NOTIF("type = %i (%d bytes)\n", notif->subtype, size);
|
||||||
@ -4509,9 +4508,8 @@ static void ipw_rx_notification(struct ipw_priv *priv,
|
|||||||
case CMAS_ASSOCIATED:{
|
case CMAS_ASSOCIATED:{
|
||||||
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
|
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
|
||||||
IPW_DL_ASSOC,
|
IPW_DL_ASSOC,
|
||||||
"associated: '%s' %pM\n",
|
"associated: '%*pE' %pM\n",
|
||||||
print_ssid(ssid, priv->essid,
|
priv->essid_len, priv->essid,
|
||||||
priv->essid_len),
|
|
||||||
priv->bssid);
|
priv->bssid);
|
||||||
|
|
||||||
switch (priv->ieee->iw_mode) {
|
switch (priv->ieee->iw_mode) {
|
||||||
@ -4585,14 +4583,9 @@ static void ipw_rx_notification(struct ipw_priv *priv,
|
|||||||
IPW_DEBUG(IPW_DL_NOTIF |
|
IPW_DEBUG(IPW_DL_NOTIF |
|
||||||
IPW_DL_STATE |
|
IPW_DL_STATE |
|
||||||
IPW_DL_ASSOC,
|
IPW_DL_ASSOC,
|
||||||
"deauthenticated: '%s' "
|
"deauthenticated: '%*pE' %pM: (0x%04X) - %s\n",
|
||||||
"%pM"
|
priv->essid_len,
|
||||||
": (0x%04X) - %s\n",
|
priv->essid,
|
||||||
print_ssid(ssid,
|
|
||||||
priv->
|
|
||||||
essid,
|
|
||||||
priv->
|
|
||||||
essid_len),
|
|
||||||
priv->bssid,
|
priv->bssid,
|
||||||
le16_to_cpu(auth->status),
|
le16_to_cpu(auth->status),
|
||||||
ipw_get_status_code
|
ipw_get_status_code
|
||||||
@ -4610,9 +4603,8 @@ static void ipw_rx_notification(struct ipw_priv *priv,
|
|||||||
|
|
||||||
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
|
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
|
||||||
IPW_DL_ASSOC,
|
IPW_DL_ASSOC,
|
||||||
"authenticated: '%s' %pM\n",
|
"authenticated: '%*pE' %pM\n",
|
||||||
print_ssid(ssid, priv->essid,
|
priv->essid_len, priv->essid,
|
||||||
priv->essid_len),
|
|
||||||
priv->bssid);
|
priv->bssid);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -4638,9 +4630,8 @@ static void ipw_rx_notification(struct ipw_priv *priv,
|
|||||||
|
|
||||||
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
|
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
|
||||||
IPW_DL_ASSOC,
|
IPW_DL_ASSOC,
|
||||||
"disassociated: '%s' %pM\n",
|
"disassociated: '%*pE' %pM\n",
|
||||||
print_ssid(ssid, priv->essid,
|
priv->essid_len, priv->essid,
|
||||||
priv->essid_len),
|
|
||||||
priv->bssid);
|
priv->bssid);
|
||||||
|
|
||||||
priv->status &=
|
priv->status &=
|
||||||
@ -4676,9 +4667,8 @@ static void ipw_rx_notification(struct ipw_priv *priv,
|
|||||||
switch (auth->state) {
|
switch (auth->state) {
|
||||||
case CMAS_AUTHENTICATED:
|
case CMAS_AUTHENTICATED:
|
||||||
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
|
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
|
||||||
"authenticated: '%s' %pM\n",
|
"authenticated: '%*pE' %pM\n",
|
||||||
print_ssid(ssid, priv->essid,
|
priv->essid_len, priv->essid,
|
||||||
priv->essid_len),
|
|
||||||
priv->bssid);
|
priv->bssid);
|
||||||
priv->status |= STATUS_AUTH;
|
priv->status |= STATUS_AUTH;
|
||||||
break;
|
break;
|
||||||
@ -4695,9 +4685,8 @@ static void ipw_rx_notification(struct ipw_priv *priv,
|
|||||||
}
|
}
|
||||||
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
|
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
|
||||||
IPW_DL_ASSOC,
|
IPW_DL_ASSOC,
|
||||||
"deauthenticated: '%s' %pM\n",
|
"deauthenticated: '%*pE' %pM\n",
|
||||||
print_ssid(ssid, priv->essid,
|
priv->essid_len, priv->essid,
|
||||||
priv->essid_len),
|
|
||||||
priv->bssid);
|
priv->bssid);
|
||||||
|
|
||||||
priv->status &= ~(STATUS_ASSOCIATING |
|
priv->status &= ~(STATUS_ASSOCIATING |
|
||||||
@ -5516,16 +5505,13 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
|
|||||||
int roaming)
|
int roaming)
|
||||||
{
|
{
|
||||||
struct ipw_supported_rates rates;
|
struct ipw_supported_rates rates;
|
||||||
DECLARE_SSID_BUF(ssid);
|
|
||||||
|
|
||||||
/* Verify that this network's capability is compatible with the
|
/* Verify that this network's capability is compatible with the
|
||||||
* current mode (AdHoc or Infrastructure) */
|
* current mode (AdHoc or Infrastructure) */
|
||||||
if ((priv->ieee->iw_mode == IW_MODE_ADHOC &&
|
if ((priv->ieee->iw_mode == IW_MODE_ADHOC &&
|
||||||
!(network->capability & WLAN_CAPABILITY_IBSS))) {
|
!(network->capability & WLAN_CAPABILITY_IBSS))) {
|
||||||
IPW_DEBUG_MERGE("Network '%s (%pM)' excluded due to "
|
IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded due to capability mismatch.\n",
|
||||||
"capability mismatch.\n",
|
network->ssid_len, network->ssid,
|
||||||
print_ssid(ssid, network->ssid,
|
|
||||||
network->ssid_len),
|
|
||||||
network->bssid);
|
network->bssid);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -5536,10 +5522,8 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
|
|||||||
if ((network->ssid_len != match->network->ssid_len) ||
|
if ((network->ssid_len != match->network->ssid_len) ||
|
||||||
memcmp(network->ssid, match->network->ssid,
|
memcmp(network->ssid, match->network->ssid,
|
||||||
network->ssid_len)) {
|
network->ssid_len)) {
|
||||||
IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
|
IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of non-network ESSID.\n",
|
||||||
"because of non-network ESSID.\n",
|
network->ssid_len, network->ssid,
|
||||||
print_ssid(ssid, network->ssid,
|
|
||||||
network->ssid_len),
|
|
||||||
network->bssid);
|
network->bssid);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -5550,17 +5534,10 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
|
|||||||
((network->ssid_len != priv->essid_len) ||
|
((network->ssid_len != priv->essid_len) ||
|
||||||
memcmp(network->ssid, priv->essid,
|
memcmp(network->ssid, priv->essid,
|
||||||
min(network->ssid_len, priv->essid_len)))) {
|
min(network->ssid_len, priv->essid_len)))) {
|
||||||
char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
|
IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of ESSID mismatch: '%*pE'.\n",
|
||||||
|
network->ssid_len, network->ssid,
|
||||||
strlcpy(escaped,
|
network->bssid, priv->essid_len,
|
||||||
print_ssid(ssid, network->ssid,
|
priv->essid);
|
||||||
network->ssid_len),
|
|
||||||
sizeof(escaped));
|
|
||||||
IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
|
|
||||||
"because of ESSID mismatch: '%s'.\n",
|
|
||||||
escaped, network->bssid,
|
|
||||||
print_ssid(ssid, priv->essid,
|
|
||||||
priv->essid_len));
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5569,26 +5546,20 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
|
|||||||
* testing everything else. */
|
* testing everything else. */
|
||||||
|
|
||||||
if (network->time_stamp[0] < match->network->time_stamp[0]) {
|
if (network->time_stamp[0] < match->network->time_stamp[0]) {
|
||||||
IPW_DEBUG_MERGE("Network '%s excluded because newer than "
|
IPW_DEBUG_MERGE("Network '%*pE excluded because newer than current network.\n",
|
||||||
"current network.\n",
|
match->network->ssid_len, match->network->ssid);
|
||||||
print_ssid(ssid, match->network->ssid,
|
|
||||||
match->network->ssid_len));
|
|
||||||
return 0;
|
return 0;
|
||||||
} else if (network->time_stamp[1] < match->network->time_stamp[1]) {
|
} else if (network->time_stamp[1] < match->network->time_stamp[1]) {
|
||||||
IPW_DEBUG_MERGE("Network '%s excluded because newer than "
|
IPW_DEBUG_MERGE("Network '%*pE excluded because newer than current network.\n",
|
||||||
"current network.\n",
|
match->network->ssid_len, match->network->ssid);
|
||||||
print_ssid(ssid, match->network->ssid,
|
|
||||||
match->network->ssid_len));
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now go through and see if the requested network is valid... */
|
/* Now go through and see if the requested network is valid... */
|
||||||
if (priv->ieee->scan_age != 0 &&
|
if (priv->ieee->scan_age != 0 &&
|
||||||
time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) {
|
time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) {
|
||||||
IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
|
IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of age: %ums.\n",
|
||||||
"because of age: %ums.\n",
|
network->ssid_len, network->ssid,
|
||||||
print_ssid(ssid, network->ssid,
|
|
||||||
network->ssid_len),
|
|
||||||
network->bssid,
|
network->bssid,
|
||||||
jiffies_to_msecs(jiffies -
|
jiffies_to_msecs(jiffies -
|
||||||
network->last_scanned));
|
network->last_scanned));
|
||||||
@ -5597,10 +5568,8 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
|
|||||||
|
|
||||||
if ((priv->config & CFG_STATIC_CHANNEL) &&
|
if ((priv->config & CFG_STATIC_CHANNEL) &&
|
||||||
(network->channel != priv->channel)) {
|
(network->channel != priv->channel)) {
|
||||||
IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
|
IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of channel mismatch: %d != %d.\n",
|
||||||
"because of channel mismatch: %d != %d.\n",
|
network->ssid_len, network->ssid,
|
||||||
print_ssid(ssid, network->ssid,
|
|
||||||
network->ssid_len),
|
|
||||||
network->bssid,
|
network->bssid,
|
||||||
network->channel, priv->channel);
|
network->channel, priv->channel);
|
||||||
return 0;
|
return 0;
|
||||||
@ -5609,10 +5578,8 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
|
|||||||
/* Verify privacy compatibility */
|
/* Verify privacy compatibility */
|
||||||
if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) !=
|
if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) !=
|
||||||
((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) {
|
((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) {
|
||||||
IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
|
IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of privacy mismatch: %s != %s.\n",
|
||||||
"because of privacy mismatch: %s != %s.\n",
|
network->ssid_len, network->ssid,
|
||||||
print_ssid(ssid, network->ssid,
|
|
||||||
network->ssid_len),
|
|
||||||
network->bssid,
|
network->bssid,
|
||||||
priv->
|
priv->
|
||||||
capability & CAP_PRIVACY_ON ? "on" : "off",
|
capability & CAP_PRIVACY_ON ? "on" : "off",
|
||||||
@ -5623,22 +5590,16 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ether_addr_equal(network->bssid, priv->bssid)) {
|
if (ether_addr_equal(network->bssid, priv->bssid)) {
|
||||||
IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
|
IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of the same BSSID match: %pM.\n",
|
||||||
"because of the same BSSID match: %pM"
|
network->ssid_len, network->ssid,
|
||||||
".\n", print_ssid(ssid, network->ssid,
|
network->bssid, priv->bssid);
|
||||||
network->ssid_len),
|
|
||||||
network->bssid,
|
|
||||||
priv->bssid);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Filter out any incompatible freq / mode combinations */
|
/* Filter out any incompatible freq / mode combinations */
|
||||||
if (!libipw_is_valid_mode(priv->ieee, network->mode)) {
|
if (!libipw_is_valid_mode(priv->ieee, network->mode)) {
|
||||||
IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
|
IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of invalid frequency/mode combination.\n",
|
||||||
"because of invalid frequency/mode "
|
network->ssid_len, network->ssid,
|
||||||
"combination.\n",
|
|
||||||
print_ssid(ssid, network->ssid,
|
|
||||||
network->ssid_len),
|
|
||||||
network->bssid);
|
network->bssid);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -5646,20 +5607,15 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
|
|||||||
/* Ensure that the rates supported by the driver are compatible with
|
/* Ensure that the rates supported by the driver are compatible with
|
||||||
* this AP, including verification of basic rates (mandatory) */
|
* this AP, including verification of basic rates (mandatory) */
|
||||||
if (!ipw_compatible_rates(priv, network, &rates)) {
|
if (!ipw_compatible_rates(priv, network, &rates)) {
|
||||||
IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
|
IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because configured rate mask excludes AP mandatory rate.\n",
|
||||||
"because configured rate mask excludes "
|
network->ssid_len, network->ssid,
|
||||||
"AP mandatory rate.\n",
|
|
||||||
print_ssid(ssid, network->ssid,
|
|
||||||
network->ssid_len),
|
|
||||||
network->bssid);
|
network->bssid);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rates.num_rates == 0) {
|
if (rates.num_rates == 0) {
|
||||||
IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
|
IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of no compatible rates.\n",
|
||||||
"because of no compatible rates.\n",
|
network->ssid_len, network->ssid,
|
||||||
print_ssid(ssid, network->ssid,
|
|
||||||
network->ssid_len),
|
|
||||||
network->bssid);
|
network->bssid);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -5671,16 +5627,14 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
|
|||||||
/* Set up 'new' AP to this network */
|
/* Set up 'new' AP to this network */
|
||||||
ipw_copy_rates(&match->rates, &rates);
|
ipw_copy_rates(&match->rates, &rates);
|
||||||
match->network = network;
|
match->network = network;
|
||||||
IPW_DEBUG_MERGE("Network '%s (%pM)' is a viable match.\n",
|
IPW_DEBUG_MERGE("Network '%*pE (%pM)' is a viable match.\n",
|
||||||
print_ssid(ssid, network->ssid, network->ssid_len),
|
network->ssid_len, network->ssid, network->bssid);
|
||||||
network->bssid);
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ipw_merge_adhoc_network(struct work_struct *work)
|
static void ipw_merge_adhoc_network(struct work_struct *work)
|
||||||
{
|
{
|
||||||
DECLARE_SSID_BUF(ssid);
|
|
||||||
struct ipw_priv *priv =
|
struct ipw_priv *priv =
|
||||||
container_of(work, struct ipw_priv, merge_networks);
|
container_of(work, struct ipw_priv, merge_networks);
|
||||||
struct libipw_network *network = NULL;
|
struct libipw_network *network = NULL;
|
||||||
@ -5710,9 +5664,8 @@ static void ipw_merge_adhoc_network(struct work_struct *work)
|
|||||||
|
|
||||||
mutex_lock(&priv->mutex);
|
mutex_lock(&priv->mutex);
|
||||||
if ((priv->ieee->iw_mode == IW_MODE_ADHOC)) {
|
if ((priv->ieee->iw_mode == IW_MODE_ADHOC)) {
|
||||||
IPW_DEBUG_MERGE("remove network %s\n",
|
IPW_DEBUG_MERGE("remove network %*pE\n",
|
||||||
print_ssid(ssid, priv->essid,
|
priv->essid_len, priv->essid);
|
||||||
priv->essid_len));
|
|
||||||
ipw_remove_current_network(priv);
|
ipw_remove_current_network(priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5728,7 +5681,6 @@ static int ipw_best_network(struct ipw_priv *priv,
|
|||||||
struct libipw_network *network, int roaming)
|
struct libipw_network *network, int roaming)
|
||||||
{
|
{
|
||||||
struct ipw_supported_rates rates;
|
struct ipw_supported_rates rates;
|
||||||
DECLARE_SSID_BUF(ssid);
|
|
||||||
|
|
||||||
/* Verify that this network's capability is compatible with the
|
/* Verify that this network's capability is compatible with the
|
||||||
* current mode (AdHoc or Infrastructure) */
|
* current mode (AdHoc or Infrastructure) */
|
||||||
@ -5736,10 +5688,8 @@ static int ipw_best_network(struct ipw_priv *priv,
|
|||||||
!(network->capability & WLAN_CAPABILITY_ESS)) ||
|
!(network->capability & WLAN_CAPABILITY_ESS)) ||
|
||||||
(priv->ieee->iw_mode == IW_MODE_ADHOC &&
|
(priv->ieee->iw_mode == IW_MODE_ADHOC &&
|
||||||
!(network->capability & WLAN_CAPABILITY_IBSS))) {
|
!(network->capability & WLAN_CAPABILITY_IBSS))) {
|
||||||
IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded due to "
|
IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded due to capability mismatch.\n",
|
||||||
"capability mismatch.\n",
|
network->ssid_len, network->ssid,
|
||||||
print_ssid(ssid, network->ssid,
|
|
||||||
network->ssid_len),
|
|
||||||
network->bssid);
|
network->bssid);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -5750,10 +5700,8 @@ static int ipw_best_network(struct ipw_priv *priv,
|
|||||||
if ((network->ssid_len != match->network->ssid_len) ||
|
if ((network->ssid_len != match->network->ssid_len) ||
|
||||||
memcmp(network->ssid, match->network->ssid,
|
memcmp(network->ssid, match->network->ssid,
|
||||||
network->ssid_len)) {
|
network->ssid_len)) {
|
||||||
IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
|
IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of non-network ESSID.\n",
|
||||||
"because of non-network ESSID.\n",
|
network->ssid_len, network->ssid,
|
||||||
print_ssid(ssid, network->ssid,
|
|
||||||
network->ssid_len),
|
|
||||||
network->bssid);
|
network->bssid);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -5764,16 +5712,10 @@ static int ipw_best_network(struct ipw_priv *priv,
|
|||||||
((network->ssid_len != priv->essid_len) ||
|
((network->ssid_len != priv->essid_len) ||
|
||||||
memcmp(network->ssid, priv->essid,
|
memcmp(network->ssid, priv->essid,
|
||||||
min(network->ssid_len, priv->essid_len)))) {
|
min(network->ssid_len, priv->essid_len)))) {
|
||||||
char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
|
IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of ESSID mismatch: '%*pE'.\n",
|
||||||
strlcpy(escaped,
|
network->ssid_len, network->ssid,
|
||||||
print_ssid(ssid, network->ssid,
|
network->bssid, priv->essid_len,
|
||||||
network->ssid_len),
|
priv->essid);
|
||||||
sizeof(escaped));
|
|
||||||
IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
|
|
||||||
"because of ESSID mismatch: '%s'.\n",
|
|
||||||
escaped, network->bssid,
|
|
||||||
print_ssid(ssid, priv->essid,
|
|
||||||
priv->essid_len));
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5781,16 +5723,10 @@ static int ipw_best_network(struct ipw_priv *priv,
|
|||||||
/* If the old network rate is better than this one, don't bother
|
/* If the old network rate is better than this one, don't bother
|
||||||
* testing everything else. */
|
* testing everything else. */
|
||||||
if (match->network && match->network->stats.rssi > network->stats.rssi) {
|
if (match->network && match->network->stats.rssi > network->stats.rssi) {
|
||||||
char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
|
IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because '%*pE (%pM)' has a stronger signal.\n",
|
||||||
strlcpy(escaped,
|
network->ssid_len, network->ssid,
|
||||||
print_ssid(ssid, network->ssid, network->ssid_len),
|
network->bssid, match->network->ssid_len,
|
||||||
sizeof(escaped));
|
match->network->ssid, match->network->bssid);
|
||||||
IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded because "
|
|
||||||
"'%s (%pM)' has a stronger signal.\n",
|
|
||||||
escaped, network->bssid,
|
|
||||||
print_ssid(ssid, match->network->ssid,
|
|
||||||
match->network->ssid_len),
|
|
||||||
match->network->bssid);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5798,11 +5734,8 @@ static int ipw_best_network(struct ipw_priv *priv,
|
|||||||
* last 3 seconds, do not try and associate again... */
|
* last 3 seconds, do not try and associate again... */
|
||||||
if (network->last_associate &&
|
if (network->last_associate &&
|
||||||
time_after(network->last_associate + (HZ * 3UL), jiffies)) {
|
time_after(network->last_associate + (HZ * 3UL), jiffies)) {
|
||||||
IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
|
IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of storming (%ums since last assoc attempt).\n",
|
||||||
"because of storming (%ums since last "
|
network->ssid_len, network->ssid,
|
||||||
"assoc attempt).\n",
|
|
||||||
print_ssid(ssid, network->ssid,
|
|
||||||
network->ssid_len),
|
|
||||||
network->bssid,
|
network->bssid,
|
||||||
jiffies_to_msecs(jiffies -
|
jiffies_to_msecs(jiffies -
|
||||||
network->last_associate));
|
network->last_associate));
|
||||||
@ -5812,10 +5745,8 @@ static int ipw_best_network(struct ipw_priv *priv,
|
|||||||
/* Now go through and see if the requested network is valid... */
|
/* Now go through and see if the requested network is valid... */
|
||||||
if (priv->ieee->scan_age != 0 &&
|
if (priv->ieee->scan_age != 0 &&
|
||||||
time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) {
|
time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) {
|
||||||
IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
|
IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of age: %ums.\n",
|
||||||
"because of age: %ums.\n",
|
network->ssid_len, network->ssid,
|
||||||
print_ssid(ssid, network->ssid,
|
|
||||||
network->ssid_len),
|
|
||||||
network->bssid,
|
network->bssid,
|
||||||
jiffies_to_msecs(jiffies -
|
jiffies_to_msecs(jiffies -
|
||||||
network->last_scanned));
|
network->last_scanned));
|
||||||
@ -5824,10 +5755,8 @@ static int ipw_best_network(struct ipw_priv *priv,
|
|||||||
|
|
||||||
if ((priv->config & CFG_STATIC_CHANNEL) &&
|
if ((priv->config & CFG_STATIC_CHANNEL) &&
|
||||||
(network->channel != priv->channel)) {
|
(network->channel != priv->channel)) {
|
||||||
IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
|
IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of channel mismatch: %d != %d.\n",
|
||||||
"because of channel mismatch: %d != %d.\n",
|
network->ssid_len, network->ssid,
|
||||||
print_ssid(ssid, network->ssid,
|
|
||||||
network->ssid_len),
|
|
||||||
network->bssid,
|
network->bssid,
|
||||||
network->channel, priv->channel);
|
network->channel, priv->channel);
|
||||||
return 0;
|
return 0;
|
||||||
@ -5836,10 +5765,8 @@ static int ipw_best_network(struct ipw_priv *priv,
|
|||||||
/* Verify privacy compatibility */
|
/* Verify privacy compatibility */
|
||||||
if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) !=
|
if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) !=
|
||||||
((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) {
|
((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) {
|
||||||
IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
|
IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of privacy mismatch: %s != %s.\n",
|
||||||
"because of privacy mismatch: %s != %s.\n",
|
network->ssid_len, network->ssid,
|
||||||
print_ssid(ssid, network->ssid,
|
|
||||||
network->ssid_len),
|
|
||||||
network->bssid,
|
network->bssid,
|
||||||
priv->capability & CAP_PRIVACY_ON ? "on" :
|
priv->capability & CAP_PRIVACY_ON ? "on" :
|
||||||
"off",
|
"off",
|
||||||
@ -5850,31 +5777,24 @@ static int ipw_best_network(struct ipw_priv *priv,
|
|||||||
|
|
||||||
if ((priv->config & CFG_STATIC_BSSID) &&
|
if ((priv->config & CFG_STATIC_BSSID) &&
|
||||||
!ether_addr_equal(network->bssid, priv->bssid)) {
|
!ether_addr_equal(network->bssid, priv->bssid)) {
|
||||||
IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
|
IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of BSSID mismatch: %pM.\n",
|
||||||
"because of BSSID mismatch: %pM.\n",
|
network->ssid_len, network->ssid,
|
||||||
print_ssid(ssid, network->ssid,
|
|
||||||
network->ssid_len),
|
|
||||||
network->bssid, priv->bssid);
|
network->bssid, priv->bssid);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Filter out any incompatible freq / mode combinations */
|
/* Filter out any incompatible freq / mode combinations */
|
||||||
if (!libipw_is_valid_mode(priv->ieee, network->mode)) {
|
if (!libipw_is_valid_mode(priv->ieee, network->mode)) {
|
||||||
IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
|
IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of invalid frequency/mode combination.\n",
|
||||||
"because of invalid frequency/mode "
|
network->ssid_len, network->ssid,
|
||||||
"combination.\n",
|
|
||||||
print_ssid(ssid, network->ssid,
|
|
||||||
network->ssid_len),
|
|
||||||
network->bssid);
|
network->bssid);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Filter out invalid channel in current GEO */
|
/* Filter out invalid channel in current GEO */
|
||||||
if (!libipw_is_valid_channel(priv->ieee, network->channel)) {
|
if (!libipw_is_valid_channel(priv->ieee, network->channel)) {
|
||||||
IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
|
IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of invalid channel in current GEO\n",
|
||||||
"because of invalid channel in current GEO\n",
|
network->ssid_len, network->ssid,
|
||||||
print_ssid(ssid, network->ssid,
|
|
||||||
network->ssid_len),
|
|
||||||
network->bssid);
|
network->bssid);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -5882,20 +5802,15 @@ static int ipw_best_network(struct ipw_priv *priv,
|
|||||||
/* Ensure that the rates supported by the driver are compatible with
|
/* Ensure that the rates supported by the driver are compatible with
|
||||||
* this AP, including verification of basic rates (mandatory) */
|
* this AP, including verification of basic rates (mandatory) */
|
||||||
if (!ipw_compatible_rates(priv, network, &rates)) {
|
if (!ipw_compatible_rates(priv, network, &rates)) {
|
||||||
IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
|
IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because configured rate mask excludes AP mandatory rate.\n",
|
||||||
"because configured rate mask excludes "
|
network->ssid_len, network->ssid,
|
||||||
"AP mandatory rate.\n",
|
|
||||||
print_ssid(ssid, network->ssid,
|
|
||||||
network->ssid_len),
|
|
||||||
network->bssid);
|
network->bssid);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rates.num_rates == 0) {
|
if (rates.num_rates == 0) {
|
||||||
IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
|
IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of no compatible rates.\n",
|
||||||
"because of no compatible rates.\n",
|
network->ssid_len, network->ssid,
|
||||||
print_ssid(ssid, network->ssid,
|
|
||||||
network->ssid_len),
|
|
||||||
network->bssid);
|
network->bssid);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -5908,9 +5823,8 @@ static int ipw_best_network(struct ipw_priv *priv,
|
|||||||
ipw_copy_rates(&match->rates, &rates);
|
ipw_copy_rates(&match->rates, &rates);
|
||||||
match->network = network;
|
match->network = network;
|
||||||
|
|
||||||
IPW_DEBUG_ASSOC("Network '%s (%pM)' is a viable match.\n",
|
IPW_DEBUG_ASSOC("Network '%*pE (%pM)' is a viable match.\n",
|
||||||
print_ssid(ssid, network->ssid, network->ssid_len),
|
network->ssid_len, network->ssid, network->bssid);
|
||||||
network->bssid);
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -6152,7 +6066,6 @@ static void ipw_bg_adhoc_check(struct work_struct *work)
|
|||||||
|
|
||||||
static void ipw_debug_config(struct ipw_priv *priv)
|
static void ipw_debug_config(struct ipw_priv *priv)
|
||||||
{
|
{
|
||||||
DECLARE_SSID_BUF(ssid);
|
|
||||||
IPW_DEBUG_INFO("Scan completed, no valid APs matched "
|
IPW_DEBUG_INFO("Scan completed, no valid APs matched "
|
||||||
"[CFG 0x%08X]\n", priv->config);
|
"[CFG 0x%08X]\n", priv->config);
|
||||||
if (priv->config & CFG_STATIC_CHANNEL)
|
if (priv->config & CFG_STATIC_CHANNEL)
|
||||||
@ -6160,8 +6073,8 @@ static void ipw_debug_config(struct ipw_priv *priv)
|
|||||||
else
|
else
|
||||||
IPW_DEBUG_INFO("Channel unlocked.\n");
|
IPW_DEBUG_INFO("Channel unlocked.\n");
|
||||||
if (priv->config & CFG_STATIC_ESSID)
|
if (priv->config & CFG_STATIC_ESSID)
|
||||||
IPW_DEBUG_INFO("ESSID locked to '%s'\n",
|
IPW_DEBUG_INFO("ESSID locked to '%*pE'\n",
|
||||||
print_ssid(ssid, priv->essid, priv->essid_len));
|
priv->essid_len, priv->essid);
|
||||||
else
|
else
|
||||||
IPW_DEBUG_INFO("ESSID unlocked.\n");
|
IPW_DEBUG_INFO("ESSID unlocked.\n");
|
||||||
if (priv->config & CFG_STATIC_BSSID)
|
if (priv->config & CFG_STATIC_BSSID)
|
||||||
@ -7385,7 +7298,6 @@ static int ipw_associate_network(struct ipw_priv *priv,
|
|||||||
struct ipw_supported_rates *rates, int roaming)
|
struct ipw_supported_rates *rates, int roaming)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
DECLARE_SSID_BUF(ssid);
|
|
||||||
|
|
||||||
if (priv->config & CFG_FIXED_RATE)
|
if (priv->config & CFG_FIXED_RATE)
|
||||||
ipw_set_fixed_rate(priv, network->mode);
|
ipw_set_fixed_rate(priv, network->mode);
|
||||||
@ -7451,10 +7363,9 @@ static int ipw_associate_network(struct ipw_priv *priv,
|
|||||||
priv->assoc_request.capability &=
|
priv->assoc_request.capability &=
|
||||||
~cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME);
|
~cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME);
|
||||||
|
|
||||||
IPW_DEBUG_ASSOC("%ssociation attempt: '%s', channel %d, "
|
IPW_DEBUG_ASSOC("%ssociation attempt: '%*pE', channel %d, 802.11%c [%d], %s[:%s], enc=%s%s%s%c%c\n",
|
||||||
"802.11%c [%d], %s[:%s], enc=%s%s%s%c%c\n",
|
|
||||||
roaming ? "Rea" : "A",
|
roaming ? "Rea" : "A",
|
||||||
print_ssid(ssid, priv->essid, priv->essid_len),
|
priv->essid_len, priv->essid,
|
||||||
network->channel,
|
network->channel,
|
||||||
ipw_modes[priv->assoc_request.ieee_mode],
|
ipw_modes[priv->assoc_request.ieee_mode],
|
||||||
rates->num_rates,
|
rates->num_rates,
|
||||||
@ -7553,9 +7464,8 @@ static int ipw_associate_network(struct ipw_priv *priv,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPW_DEBUG(IPW_DL_STATE, "associating: '%s' %pM\n",
|
IPW_DEBUG(IPW_DL_STATE, "associating: '%*pE' %pM\n",
|
||||||
print_ssid(ssid, priv->essid, priv->essid_len),
|
priv->essid_len, priv->essid, priv->bssid);
|
||||||
priv->bssid);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -7645,7 +7555,6 @@ static int ipw_associate(void *data)
|
|||||||
struct ipw_supported_rates *rates;
|
struct ipw_supported_rates *rates;
|
||||||
struct list_head *element;
|
struct list_head *element;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
DECLARE_SSID_BUF(ssid);
|
|
||||||
|
|
||||||
if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
|
if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
|
||||||
IPW_DEBUG_ASSOC("Not attempting association (monitor mode)\n");
|
IPW_DEBUG_ASSOC("Not attempting association (monitor mode)\n");
|
||||||
@ -7704,10 +7613,8 @@ static int ipw_associate(void *data)
|
|||||||
/* If there are no more slots, expire the oldest */
|
/* If there are no more slots, expire the oldest */
|
||||||
list_del(&oldest->list);
|
list_del(&oldest->list);
|
||||||
target = oldest;
|
target = oldest;
|
||||||
IPW_DEBUG_ASSOC("Expired '%s' (%pM) from "
|
IPW_DEBUG_ASSOC("Expired '%*pE' (%pM) from network list.\n",
|
||||||
"network list.\n",
|
target->ssid_len, target->ssid,
|
||||||
print_ssid(ssid, target->ssid,
|
|
||||||
target->ssid_len),
|
|
||||||
target->bssid);
|
target->bssid);
|
||||||
list_add_tail(&target->list,
|
list_add_tail(&target->list,
|
||||||
&priv->ieee->network_free_list);
|
&priv->ieee->network_free_list);
|
||||||
@ -9093,7 +9000,6 @@ static int ipw_wx_set_essid(struct net_device *dev,
|
|||||||
{
|
{
|
||||||
struct ipw_priv *priv = libipw_priv(dev);
|
struct ipw_priv *priv = libipw_priv(dev);
|
||||||
int length;
|
int length;
|
||||||
DECLARE_SSID_BUF(ssid);
|
|
||||||
|
|
||||||
mutex_lock(&priv->mutex);
|
mutex_lock(&priv->mutex);
|
||||||
|
|
||||||
@ -9118,8 +9024,7 @@ static int ipw_wx_set_essid(struct net_device *dev,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n",
|
IPW_DEBUG_WX("Setting ESSID: '%*pE' (%d)\n", length, extra, length);
|
||||||
print_ssid(ssid, extra, length), length);
|
|
||||||
|
|
||||||
priv->essid_len = length;
|
priv->essid_len = length;
|
||||||
memcpy(priv->essid, extra, priv->essid_len);
|
memcpy(priv->essid, extra, priv->essid_len);
|
||||||
@ -9138,15 +9043,14 @@ static int ipw_wx_get_essid(struct net_device *dev,
|
|||||||
union iwreq_data *wrqu, char *extra)
|
union iwreq_data *wrqu, char *extra)
|
||||||
{
|
{
|
||||||
struct ipw_priv *priv = libipw_priv(dev);
|
struct ipw_priv *priv = libipw_priv(dev);
|
||||||
DECLARE_SSID_BUF(ssid);
|
|
||||||
|
|
||||||
/* If we are associated, trying to associate, or have a statically
|
/* If we are associated, trying to associate, or have a statically
|
||||||
* configured ESSID then return that; otherwise return ANY */
|
* configured ESSID then return that; otherwise return ANY */
|
||||||
mutex_lock(&priv->mutex);
|
mutex_lock(&priv->mutex);
|
||||||
if (priv->config & CFG_STATIC_ESSID ||
|
if (priv->config & CFG_STATIC_ESSID ||
|
||||||
priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
|
priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
|
||||||
IPW_DEBUG_WX("Getting essid: '%s'\n",
|
IPW_DEBUG_WX("Getting essid: '%*pE'\n",
|
||||||
print_ssid(ssid, priv->essid, priv->essid_len));
|
priv->essid_len, priv->essid);
|
||||||
memcpy(extra, priv->essid, priv->essid_len);
|
memcpy(extra, priv->essid, priv->essid_len);
|
||||||
wrqu->essid.length = priv->essid_len;
|
wrqu->essid.length = priv->essid_len;
|
||||||
wrqu->essid.flags = 1; /* active */
|
wrqu->essid.flags = 1; /* active */
|
||||||
|
@ -1120,7 +1120,6 @@ static int libipw_parse_info_param(struct libipw_info_element
|
|||||||
*info_element, u16 length,
|
*info_element, u16 length,
|
||||||
struct libipw_network *network)
|
struct libipw_network *network)
|
||||||
{
|
{
|
||||||
DECLARE_SSID_BUF(ssid);
|
|
||||||
u8 i;
|
u8 i;
|
||||||
#ifdef CONFIG_LIBIPW_DEBUG
|
#ifdef CONFIG_LIBIPW_DEBUG
|
||||||
char rates_str[64];
|
char rates_str[64];
|
||||||
@ -1151,10 +1150,9 @@ static int libipw_parse_info_param(struct libipw_info_element
|
|||||||
memset(network->ssid + network->ssid_len, 0,
|
memset(network->ssid + network->ssid_len, 0,
|
||||||
IW_ESSID_MAX_SIZE - network->ssid_len);
|
IW_ESSID_MAX_SIZE - network->ssid_len);
|
||||||
|
|
||||||
LIBIPW_DEBUG_MGMT("WLAN_EID_SSID: '%s' len=%d.\n",
|
LIBIPW_DEBUG_MGMT("WLAN_EID_SSID: '%*pE' len=%d.\n",
|
||||||
print_ssid(ssid, network->ssid,
|
network->ssid_len, network->ssid,
|
||||||
network->ssid_len),
|
network->ssid_len);
|
||||||
network->ssid_len);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WLAN_EID_SUPP_RATES:
|
case WLAN_EID_SUPP_RATES:
|
||||||
@ -1399,8 +1397,6 @@ static int libipw_network_init(struct libipw_device *ieee, struct libipw_probe_r
|
|||||||
struct libipw_network *network,
|
struct libipw_network *network,
|
||||||
struct libipw_rx_stats *stats)
|
struct libipw_rx_stats *stats)
|
||||||
{
|
{
|
||||||
DECLARE_SSID_BUF(ssid);
|
|
||||||
|
|
||||||
network->qos_data.active = 0;
|
network->qos_data.active = 0;
|
||||||
network->qos_data.supported = 0;
|
network->qos_data.supported = 0;
|
||||||
network->qos_data.param_count = 0;
|
network->qos_data.param_count = 0;
|
||||||
@ -1447,11 +1443,9 @@ static int libipw_network_init(struct libipw_device *ieee, struct libipw_probe_r
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (network->mode == 0) {
|
if (network->mode == 0) {
|
||||||
LIBIPW_DEBUG_SCAN("Filtered out '%s (%pM)' "
|
LIBIPW_DEBUG_SCAN("Filtered out '%*pE (%pM)' network.\n",
|
||||||
"network.\n",
|
network->ssid_len, network->ssid,
|
||||||
print_ssid(ssid, network->ssid,
|
network->bssid);
|
||||||
network->ssid_len),
|
|
||||||
network->bssid);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1563,11 +1557,9 @@ static void libipw_process_probe_response(struct libipw_device
|
|||||||
struct libipw_info_element *info_element = beacon->info_element;
|
struct libipw_info_element *info_element = beacon->info_element;
|
||||||
#endif
|
#endif
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
DECLARE_SSID_BUF(ssid);
|
|
||||||
|
|
||||||
LIBIPW_DEBUG_SCAN("'%s' (%pM"
|
LIBIPW_DEBUG_SCAN("'%*pE' (%pM): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n",
|
||||||
"): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n",
|
info_element->len, info_element->data,
|
||||||
print_ssid(ssid, info_element->data, info_element->len),
|
|
||||||
beacon->header.addr3,
|
beacon->header.addr3,
|
||||||
(beacon->capability & cpu_to_le16(1 << 0xf)) ? '1' : '0',
|
(beacon->capability & cpu_to_le16(1 << 0xf)) ? '1' : '0',
|
||||||
(beacon->capability & cpu_to_le16(1 << 0xe)) ? '1' : '0',
|
(beacon->capability & cpu_to_le16(1 << 0xe)) ? '1' : '0',
|
||||||
@ -1587,12 +1579,11 @@ static void libipw_process_probe_response(struct libipw_device
|
|||||||
(beacon->capability & cpu_to_le16(1 << 0x0)) ? '1' : '0');
|
(beacon->capability & cpu_to_le16(1 << 0x0)) ? '1' : '0');
|
||||||
|
|
||||||
if (libipw_network_init(ieee, beacon, &network, stats)) {
|
if (libipw_network_init(ieee, beacon, &network, stats)) {
|
||||||
LIBIPW_DEBUG_SCAN("Dropped '%s' (%pM) via %s.\n",
|
LIBIPW_DEBUG_SCAN("Dropped '%*pE' (%pM) via %s.\n",
|
||||||
print_ssid(ssid, info_element->data,
|
info_element->len, info_element->data,
|
||||||
info_element->len),
|
beacon->header.addr3,
|
||||||
beacon->header.addr3,
|
is_beacon(beacon->header.frame_ctl) ?
|
||||||
is_beacon(beacon->header.frame_ctl) ?
|
"BEACON" : "PROBE RESPONSE");
|
||||||
"BEACON" : "PROBE RESPONSE");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1624,11 +1615,9 @@ static void libipw_process_probe_response(struct libipw_device
|
|||||||
/* If there are no more slots, expire the oldest */
|
/* If there are no more slots, expire the oldest */
|
||||||
list_del(&oldest->list);
|
list_del(&oldest->list);
|
||||||
target = oldest;
|
target = oldest;
|
||||||
LIBIPW_DEBUG_SCAN("Expired '%s' (%pM) from "
|
LIBIPW_DEBUG_SCAN("Expired '%*pE' (%pM) from network list.\n",
|
||||||
"network list.\n",
|
target->ssid_len, target->ssid,
|
||||||
print_ssid(ssid, target->ssid,
|
target->bssid);
|
||||||
target->ssid_len),
|
|
||||||
target->bssid);
|
|
||||||
libipw_network_reset(target);
|
libipw_network_reset(target);
|
||||||
} else {
|
} else {
|
||||||
/* Otherwise just pull from the free list */
|
/* Otherwise just pull from the free list */
|
||||||
@ -1638,23 +1627,21 @@ static void libipw_process_probe_response(struct libipw_device
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_LIBIPW_DEBUG
|
#ifdef CONFIG_LIBIPW_DEBUG
|
||||||
LIBIPW_DEBUG_SCAN("Adding '%s' (%pM) via %s.\n",
|
LIBIPW_DEBUG_SCAN("Adding '%*pE' (%pM) via %s.\n",
|
||||||
print_ssid(ssid, network.ssid,
|
network.ssid_len, network.ssid,
|
||||||
network.ssid_len),
|
network.bssid,
|
||||||
network.bssid,
|
is_beacon(beacon->header.frame_ctl) ?
|
||||||
is_beacon(beacon->header.frame_ctl) ?
|
"BEACON" : "PROBE RESPONSE");
|
||||||
"BEACON" : "PROBE RESPONSE");
|
|
||||||
#endif
|
#endif
|
||||||
memcpy(target, &network, sizeof(*target));
|
memcpy(target, &network, sizeof(*target));
|
||||||
network.ibss_dfs = NULL;
|
network.ibss_dfs = NULL;
|
||||||
list_add_tail(&target->list, &ieee->network_list);
|
list_add_tail(&target->list, &ieee->network_list);
|
||||||
} else {
|
} else {
|
||||||
LIBIPW_DEBUG_SCAN("Updating '%s' (%pM) via %s.\n",
|
LIBIPW_DEBUG_SCAN("Updating '%*pE' (%pM) via %s.\n",
|
||||||
print_ssid(ssid, target->ssid,
|
target->ssid_len, target->ssid,
|
||||||
target->ssid_len),
|
target->bssid,
|
||||||
target->bssid,
|
is_beacon(beacon->header.frame_ctl) ?
|
||||||
is_beacon(beacon->header.frame_ctl) ?
|
"BEACON" : "PROBE RESPONSE");
|
||||||
"BEACON" : "PROBE RESPONSE");
|
|
||||||
update_network(target, &network);
|
update_network(target, &network);
|
||||||
network.ibss_dfs = NULL;
|
network.ibss_dfs = NULL;
|
||||||
}
|
}
|
||||||
|
@ -272,7 +272,6 @@ int libipw_wx_get_scan(struct libipw_device *ieee,
|
|||||||
char *ev = extra;
|
char *ev = extra;
|
||||||
char *stop = ev + wrqu->data.length;
|
char *stop = ev + wrqu->data.length;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
DECLARE_SSID_BUF(ssid);
|
|
||||||
|
|
||||||
LIBIPW_DEBUG_WX("Getting scan\n");
|
LIBIPW_DEBUG_WX("Getting scan\n");
|
||||||
|
|
||||||
@ -290,12 +289,10 @@ int libipw_wx_get_scan(struct libipw_device *ieee,
|
|||||||
ev = libipw_translate_scan(ieee, ev, stop, network,
|
ev = libipw_translate_scan(ieee, ev, stop, network,
|
||||||
info);
|
info);
|
||||||
else {
|
else {
|
||||||
LIBIPW_DEBUG_SCAN("Not showing network '%s ("
|
LIBIPW_DEBUG_SCAN("Not showing network '%*pE (%pM)' due to age (%ums).\n",
|
||||||
"%pM)' due to age (%ums).\n",
|
network->ssid_len, network->ssid,
|
||||||
print_ssid(ssid, network->ssid,
|
network->bssid,
|
||||||
network->ssid_len),
|
elapsed_jiffies_msecs(
|
||||||
network->bssid,
|
|
||||||
elapsed_jiffies_msecs(
|
|
||||||
network->last_scanned));
|
network->last_scanned));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -322,7 +319,6 @@ int libipw_wx_set_encode(struct libipw_device *ieee,
|
|||||||
int i, key, key_provided, len;
|
int i, key, key_provided, len;
|
||||||
struct lib80211_crypt_data **crypt;
|
struct lib80211_crypt_data **crypt;
|
||||||
int host_crypto = ieee->host_encrypt || ieee->host_decrypt;
|
int host_crypto = ieee->host_encrypt || ieee->host_decrypt;
|
||||||
DECLARE_SSID_BUF(ssid);
|
|
||||||
|
|
||||||
LIBIPW_DEBUG_WX("SET_ENCODE\n");
|
LIBIPW_DEBUG_WX("SET_ENCODE\n");
|
||||||
|
|
||||||
@ -417,8 +413,8 @@ int libipw_wx_set_encode(struct libipw_device *ieee,
|
|||||||
if (len > erq->length)
|
if (len > erq->length)
|
||||||
memset(sec.keys[key] + erq->length, 0,
|
memset(sec.keys[key] + erq->length, 0,
|
||||||
len - erq->length);
|
len - erq->length);
|
||||||
LIBIPW_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
|
LIBIPW_DEBUG_WX("Setting key %d to '%*pE' (%d:%d bytes)\n",
|
||||||
key, print_ssid(ssid, sec.keys[key], len),
|
key, len, sec.keys[key],
|
||||||
erq->length, len);
|
erq->length, len);
|
||||||
sec.key_sizes[key] = len;
|
sec.key_sizes[key] = len;
|
||||||
if (*crypt)
|
if (*crypt)
|
||||||
|
@ -590,7 +590,6 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
|
|||||||
int chan_no = -1;
|
int chan_no = -1;
|
||||||
const u8 *ssid = NULL;
|
const u8 *ssid = NULL;
|
||||||
u8 ssid_len = 0;
|
u8 ssid_len = 0;
|
||||||
DECLARE_SSID_BUF(ssid_buf);
|
|
||||||
|
|
||||||
int len = get_unaligned_le16(pos);
|
int len = get_unaligned_le16(pos);
|
||||||
pos += 2;
|
pos += 2;
|
||||||
@ -644,10 +643,8 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
|
|||||||
struct ieee80211_channel *channel =
|
struct ieee80211_channel *channel =
|
||||||
ieee80211_get_channel(wiphy, freq);
|
ieee80211_get_channel(wiphy, freq);
|
||||||
|
|
||||||
lbs_deb_scan("scan: %pM, capa %04x, chan %2d, %s, "
|
lbs_deb_scan("scan: %pM, capa %04x, chan %2d, %*pE, %d dBm\n",
|
||||||
"%d dBm\n",
|
bssid, capa, chan_no, ssid_len, ssid,
|
||||||
bssid, capa, chan_no,
|
|
||||||
print_ssid(ssid_buf, ssid, ssid_len),
|
|
||||||
LBS_SCAN_RSSI_TO_MBM(rssi)/100);
|
LBS_SCAN_RSSI_TO_MBM(rssi)/100);
|
||||||
|
|
||||||
if (channel &&
|
if (channel &&
|
||||||
@ -1984,7 +1981,6 @@ static int lbs_join_ibss(struct wiphy *wiphy, struct net_device *dev,
|
|||||||
struct lbs_private *priv = wiphy_priv(wiphy);
|
struct lbs_private *priv = wiphy_priv(wiphy);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct cfg80211_bss *bss;
|
struct cfg80211_bss *bss;
|
||||||
DECLARE_SSID_BUF(ssid_buf);
|
|
||||||
|
|
||||||
if (dev == priv->mesh_dev)
|
if (dev == priv->mesh_dev)
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
@ -93,7 +93,6 @@ static int lbs_mesh_config(struct lbs_private *priv, uint16_t action,
|
|||||||
{
|
{
|
||||||
struct cmd_ds_mesh_config cmd;
|
struct cmd_ds_mesh_config cmd;
|
||||||
struct mrvl_meshie *ie;
|
struct mrvl_meshie *ie;
|
||||||
DECLARE_SSID_BUF(ssid);
|
|
||||||
|
|
||||||
memset(&cmd, 0, sizeof(cmd));
|
memset(&cmd, 0, sizeof(cmd));
|
||||||
cmd.channel = cpu_to_le16(chan);
|
cmd.channel = cpu_to_le16(chan);
|
||||||
@ -122,9 +121,9 @@ static int lbs_mesh_config(struct lbs_private *priv, uint16_t action,
|
|||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
lbs_deb_cmd("mesh config action %d type %x channel %d SSID %s\n",
|
lbs_deb_cmd("mesh config action %d type %x channel %d SSID %*pE\n",
|
||||||
action, priv->mesh_tlv, chan,
|
action, priv->mesh_tlv, chan, priv->mesh_ssid_len,
|
||||||
print_ssid(ssid, priv->mesh_ssid, priv->mesh_ssid_len));
|
priv->mesh_ssid);
|
||||||
|
|
||||||
return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
|
return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
|
||||||
}
|
}
|
||||||
|
@ -8878,13 +8878,13 @@ static int __must_check __init get_thinkpad_model_data(
|
|||||||
}
|
}
|
||||||
|
|
||||||
s = dmi_get_system_info(DMI_PRODUCT_VERSION);
|
s = dmi_get_system_info(DMI_PRODUCT_VERSION);
|
||||||
if (s && !(strnicmp(s, "ThinkPad", 8) && strnicmp(s, "Lenovo", 6))) {
|
if (s && !(strncasecmp(s, "ThinkPad", 8) && strncasecmp(s, "Lenovo", 6))) {
|
||||||
tp->model_str = kstrdup(s, GFP_KERNEL);
|
tp->model_str = kstrdup(s, GFP_KERNEL);
|
||||||
if (!tp->model_str)
|
if (!tp->model_str)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
} else {
|
} else {
|
||||||
s = dmi_get_system_info(DMI_BIOS_VENDOR);
|
s = dmi_get_system_info(DMI_BIOS_VENDOR);
|
||||||
if (s && !(strnicmp(s, "Lenovo", 6))) {
|
if (s && !(strncasecmp(s, "Lenovo", 6))) {
|
||||||
tp->model_str = kstrdup(s, GFP_KERNEL);
|
tp->model_str = kstrdup(s, GFP_KERNEL);
|
||||||
if (!tp->model_str)
|
if (!tp->model_str)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -346,41 +346,41 @@ static ssize_t resources_store(struct device *dmdev,
|
|||||||
}
|
}
|
||||||
|
|
||||||
buf = skip_spaces(buf);
|
buf = skip_spaces(buf);
|
||||||
if (!strnicmp(buf, "disable", 7)) {
|
if (!strncasecmp(buf, "disable", 7)) {
|
||||||
retval = pnp_disable_dev(dev);
|
retval = pnp_disable_dev(dev);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (!strnicmp(buf, "activate", 8)) {
|
if (!strncasecmp(buf, "activate", 8)) {
|
||||||
retval = pnp_activate_dev(dev);
|
retval = pnp_activate_dev(dev);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (!strnicmp(buf, "fill", 4)) {
|
if (!strncasecmp(buf, "fill", 4)) {
|
||||||
if (dev->active)
|
if (dev->active)
|
||||||
goto done;
|
goto done;
|
||||||
retval = pnp_auto_config_dev(dev);
|
retval = pnp_auto_config_dev(dev);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (!strnicmp(buf, "auto", 4)) {
|
if (!strncasecmp(buf, "auto", 4)) {
|
||||||
if (dev->active)
|
if (dev->active)
|
||||||
goto done;
|
goto done;
|
||||||
pnp_init_resources(dev);
|
pnp_init_resources(dev);
|
||||||
retval = pnp_auto_config_dev(dev);
|
retval = pnp_auto_config_dev(dev);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (!strnicmp(buf, "clear", 5)) {
|
if (!strncasecmp(buf, "clear", 5)) {
|
||||||
if (dev->active)
|
if (dev->active)
|
||||||
goto done;
|
goto done;
|
||||||
pnp_init_resources(dev);
|
pnp_init_resources(dev);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (!strnicmp(buf, "get", 3)) {
|
if (!strncasecmp(buf, "get", 3)) {
|
||||||
mutex_lock(&pnp_res_mutex);
|
mutex_lock(&pnp_res_mutex);
|
||||||
if (pnp_can_read(dev))
|
if (pnp_can_read(dev))
|
||||||
dev->protocol->get(dev);
|
dev->protocol->get(dev);
|
||||||
mutex_unlock(&pnp_res_mutex);
|
mutex_unlock(&pnp_res_mutex);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (!strnicmp(buf, "set", 3)) {
|
if (!strncasecmp(buf, "set", 3)) {
|
||||||
resource_size_t start;
|
resource_size_t start;
|
||||||
resource_size_t end;
|
resource_size_t end;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
@ -392,31 +392,31 @@ static ssize_t resources_store(struct device *dmdev,
|
|||||||
mutex_lock(&pnp_res_mutex);
|
mutex_lock(&pnp_res_mutex);
|
||||||
while (1) {
|
while (1) {
|
||||||
buf = skip_spaces(buf);
|
buf = skip_spaces(buf);
|
||||||
if (!strnicmp(buf, "io", 2)) {
|
if (!strncasecmp(buf, "io", 2)) {
|
||||||
buf = pnp_get_resource_value(buf + 2,
|
buf = pnp_get_resource_value(buf + 2,
|
||||||
IORESOURCE_IO,
|
IORESOURCE_IO,
|
||||||
&start, &end,
|
&start, &end,
|
||||||
&flags);
|
&flags);
|
||||||
pnp_add_io_resource(dev, start, end, flags);
|
pnp_add_io_resource(dev, start, end, flags);
|
||||||
} else if (!strnicmp(buf, "mem", 3)) {
|
} else if (!strncasecmp(buf, "mem", 3)) {
|
||||||
buf = pnp_get_resource_value(buf + 3,
|
buf = pnp_get_resource_value(buf + 3,
|
||||||
IORESOURCE_MEM,
|
IORESOURCE_MEM,
|
||||||
&start, &end,
|
&start, &end,
|
||||||
&flags);
|
&flags);
|
||||||
pnp_add_mem_resource(dev, start, end, flags);
|
pnp_add_mem_resource(dev, start, end, flags);
|
||||||
} else if (!strnicmp(buf, "irq", 3)) {
|
} else if (!strncasecmp(buf, "irq", 3)) {
|
||||||
buf = pnp_get_resource_value(buf + 3,
|
buf = pnp_get_resource_value(buf + 3,
|
||||||
IORESOURCE_IRQ,
|
IORESOURCE_IRQ,
|
||||||
&start, NULL,
|
&start, NULL,
|
||||||
&flags);
|
&flags);
|
||||||
pnp_add_irq_resource(dev, start, flags);
|
pnp_add_irq_resource(dev, start, flags);
|
||||||
} else if (!strnicmp(buf, "dma", 3)) {
|
} else if (!strncasecmp(buf, "dma", 3)) {
|
||||||
buf = pnp_get_resource_value(buf + 3,
|
buf = pnp_get_resource_value(buf + 3,
|
||||||
IORESOURCE_DMA,
|
IORESOURCE_DMA,
|
||||||
&start, NULL,
|
&start, NULL,
|
||||||
&flags);
|
&flags);
|
||||||
pnp_add_dma_resource(dev, start, flags);
|
pnp_add_dma_resource(dev, start, flags);
|
||||||
} else if (!strnicmp(buf, "bus", 3)) {
|
} else if (!strncasecmp(buf, "bus", 3)) {
|
||||||
buf = pnp_get_resource_value(buf + 3,
|
buf = pnp_get_resource_value(buf + 3,
|
||||||
IORESOURCE_BUS,
|
IORESOURCE_BUS,
|
||||||
&start, &end,
|
&start, &end,
|
||||||
|
@ -288,6 +288,26 @@ config RTC_DRV_MAX77686
|
|||||||
This driver can also be built as a module. If so, the module
|
This driver can also be built as a module. If so, the module
|
||||||
will be called rtc-max77686.
|
will be called rtc-max77686.
|
||||||
|
|
||||||
|
config RTC_DRV_RK808
|
||||||
|
tristate "Rockchip RK808 RTC"
|
||||||
|
depends on MFD_RK808
|
||||||
|
help
|
||||||
|
If you say yes here you will get support for the
|
||||||
|
RTC of RK808 PMIC.
|
||||||
|
|
||||||
|
This driver can also be built as a module. If so, the module
|
||||||
|
will be called rk808-rtc.
|
||||||
|
|
||||||
|
config RTC_DRV_MAX77802
|
||||||
|
tristate "Maxim 77802 RTC"
|
||||||
|
depends on MFD_MAX77686
|
||||||
|
help
|
||||||
|
If you say yes here you will get support for the
|
||||||
|
RTC of Maxim MAX77802 PMIC.
|
||||||
|
|
||||||
|
This driver can also be built as a module. If so, the module
|
||||||
|
will be called rtc-max77802.
|
||||||
|
|
||||||
config RTC_DRV_RS5C372
|
config RTC_DRV_RS5C372
|
||||||
tristate "Ricoh R2025S/D, RS5C372A/B, RV5C386, RV5C387A"
|
tristate "Ricoh R2025S/D, RS5C372A/B, RV5C386, RV5C387A"
|
||||||
help
|
help
|
||||||
@ -732,6 +752,7 @@ config RTC_DRV_DS1216
|
|||||||
|
|
||||||
config RTC_DRV_DS1286
|
config RTC_DRV_DS1286
|
||||||
tristate "Dallas DS1286"
|
tristate "Dallas DS1286"
|
||||||
|
depends on HAS_IOMEM
|
||||||
help
|
help
|
||||||
If you say yes here you get support for the Dallas DS1286 RTC chips.
|
If you say yes here you get support for the Dallas DS1286 RTC chips.
|
||||||
|
|
||||||
@ -743,6 +764,7 @@ config RTC_DRV_DS1302
|
|||||||
|
|
||||||
config RTC_DRV_DS1511
|
config RTC_DRV_DS1511
|
||||||
tristate "Dallas DS1511"
|
tristate "Dallas DS1511"
|
||||||
|
depends on HAS_IOMEM
|
||||||
help
|
help
|
||||||
If you say yes here you get support for the
|
If you say yes here you get support for the
|
||||||
Dallas DS1511 timekeeping/watchdog chip.
|
Dallas DS1511 timekeeping/watchdog chip.
|
||||||
@ -752,6 +774,7 @@ config RTC_DRV_DS1511
|
|||||||
|
|
||||||
config RTC_DRV_DS1553
|
config RTC_DRV_DS1553
|
||||||
tristate "Maxim/Dallas DS1553"
|
tristate "Maxim/Dallas DS1553"
|
||||||
|
depends on HAS_IOMEM
|
||||||
help
|
help
|
||||||
If you say yes here you get support for the
|
If you say yes here you get support for the
|
||||||
Maxim/Dallas DS1553 timekeeping chip.
|
Maxim/Dallas DS1553 timekeeping chip.
|
||||||
@ -761,6 +784,7 @@ config RTC_DRV_DS1553
|
|||||||
|
|
||||||
config RTC_DRV_DS1742
|
config RTC_DRV_DS1742
|
||||||
tristate "Maxim/Dallas DS1742/1743"
|
tristate "Maxim/Dallas DS1742/1743"
|
||||||
|
depends on HAS_IOMEM
|
||||||
help
|
help
|
||||||
If you say yes here you get support for the
|
If you say yes here you get support for the
|
||||||
Maxim/Dallas DS1742/1743 timekeeping chip.
|
Maxim/Dallas DS1742/1743 timekeeping chip.
|
||||||
@ -816,6 +840,7 @@ config RTC_DRV_EFI
|
|||||||
|
|
||||||
config RTC_DRV_STK17TA8
|
config RTC_DRV_STK17TA8
|
||||||
tristate "Simtek STK17TA8"
|
tristate "Simtek STK17TA8"
|
||||||
|
depends on HAS_IOMEM
|
||||||
help
|
help
|
||||||
If you say yes here you get support for the
|
If you say yes here you get support for the
|
||||||
Simtek STK17TA8 timekeeping chip.
|
Simtek STK17TA8 timekeeping chip.
|
||||||
@ -834,6 +859,7 @@ config RTC_DRV_M48T86
|
|||||||
|
|
||||||
config RTC_DRV_M48T35
|
config RTC_DRV_M48T35
|
||||||
tristate "ST M48T35"
|
tristate "ST M48T35"
|
||||||
|
depends on HAS_IOMEM
|
||||||
help
|
help
|
||||||
If you say Y here you will get support for the
|
If you say Y here you will get support for the
|
||||||
ST M48T35 RTC chip.
|
ST M48T35 RTC chip.
|
||||||
@ -843,6 +869,7 @@ config RTC_DRV_M48T35
|
|||||||
|
|
||||||
config RTC_DRV_M48T59
|
config RTC_DRV_M48T59
|
||||||
tristate "ST M48T59/M48T08/M48T02"
|
tristate "ST M48T59/M48T08/M48T02"
|
||||||
|
depends on HAS_IOMEM
|
||||||
help
|
help
|
||||||
If you say Y here you will get support for the
|
If you say Y here you will get support for the
|
||||||
ST M48T59 RTC chip and compatible ST M48T08 and M48T02.
|
ST M48T59 RTC chip and compatible ST M48T08 and M48T02.
|
||||||
@ -855,6 +882,7 @@ config RTC_DRV_M48T59
|
|||||||
|
|
||||||
config RTC_DRV_MSM6242
|
config RTC_DRV_MSM6242
|
||||||
tristate "Oki MSM6242"
|
tristate "Oki MSM6242"
|
||||||
|
depends on HAS_IOMEM
|
||||||
help
|
help
|
||||||
If you say yes here you get support for the Oki MSM6242
|
If you say yes here you get support for the Oki MSM6242
|
||||||
timekeeping chip. It is used in some Amiga models (e.g. A2000).
|
timekeeping chip. It is used in some Amiga models (e.g. A2000).
|
||||||
@ -864,6 +892,7 @@ config RTC_DRV_MSM6242
|
|||||||
|
|
||||||
config RTC_DRV_BQ4802
|
config RTC_DRV_BQ4802
|
||||||
tristate "TI BQ4802"
|
tristate "TI BQ4802"
|
||||||
|
depends on HAS_IOMEM
|
||||||
help
|
help
|
||||||
If you say Y here you will get support for the TI
|
If you say Y here you will get support for the TI
|
||||||
BQ4802 RTC chip.
|
BQ4802 RTC chip.
|
||||||
@ -873,6 +902,7 @@ config RTC_DRV_BQ4802
|
|||||||
|
|
||||||
config RTC_DRV_RP5C01
|
config RTC_DRV_RP5C01
|
||||||
tristate "Ricoh RP5C01"
|
tristate "Ricoh RP5C01"
|
||||||
|
depends on HAS_IOMEM
|
||||||
help
|
help
|
||||||
If you say yes here you get support for the Ricoh RP5C01
|
If you say yes here you get support for the Ricoh RP5C01
|
||||||
timekeeping chip. It is used in some Amiga models (e.g. A3000
|
timekeeping chip. It is used in some Amiga models (e.g. A3000
|
||||||
@ -1374,6 +1404,7 @@ config RTC_DRV_MOXART
|
|||||||
|
|
||||||
config RTC_DRV_XGENE
|
config RTC_DRV_XGENE
|
||||||
tristate "APM X-Gene RTC"
|
tristate "APM X-Gene RTC"
|
||||||
|
depends on HAS_IOMEM
|
||||||
help
|
help
|
||||||
If you say yes here you get support for the APM X-Gene SoC real time
|
If you say yes here you get support for the APM X-Gene SoC real time
|
||||||
clock.
|
clock.
|
||||||
|
@ -85,6 +85,7 @@ obj-$(CONFIG_RTC_DRV_MAX8998) += rtc-max8998.o
|
|||||||
obj-$(CONFIG_RTC_DRV_MAX8997) += rtc-max8997.o
|
obj-$(CONFIG_RTC_DRV_MAX8997) += rtc-max8997.o
|
||||||
obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o
|
obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o
|
||||||
obj-$(CONFIG_RTC_DRV_MAX77686) += rtc-max77686.o
|
obj-$(CONFIG_RTC_DRV_MAX77686) += rtc-max77686.o
|
||||||
|
obj-$(CONFIG_RTC_DRV_MAX77802) += rtc-max77802.o
|
||||||
obj-$(CONFIG_RTC_DRV_MC13XXX) += rtc-mc13xxx.o
|
obj-$(CONFIG_RTC_DRV_MC13XXX) += rtc-mc13xxx.o
|
||||||
obj-$(CONFIG_RTC_DRV_MCP795) += rtc-mcp795.o
|
obj-$(CONFIG_RTC_DRV_MCP795) += rtc-mcp795.o
|
||||||
obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o
|
obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o
|
||||||
@ -109,6 +110,7 @@ obj-$(CONFIG_RTC_DRV_PUV3) += rtc-puv3.o
|
|||||||
obj-$(CONFIG_RTC_DRV_PXA) += rtc-pxa.o
|
obj-$(CONFIG_RTC_DRV_PXA) += rtc-pxa.o
|
||||||
obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o
|
obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o
|
||||||
obj-$(CONFIG_RTC_DRV_RC5T583) += rtc-rc5t583.o
|
obj-$(CONFIG_RTC_DRV_RC5T583) += rtc-rc5t583.o
|
||||||
|
obj-$(CONFIG_RTC_DRV_RK808) += rtc-rk808.o
|
||||||
obj-$(CONFIG_RTC_DRV_RP5C01) += rtc-rp5c01.o
|
obj-$(CONFIG_RTC_DRV_RP5C01) += rtc-rp5c01.o
|
||||||
obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o
|
obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o
|
||||||
obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o
|
obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o
|
||||||
|
@ -2,10 +2,14 @@
|
|||||||
* Driver for TI BQ32000 RTC.
|
* Driver for TI BQ32000 RTC.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2009 Semihalf.
|
* Copyright (C) 2009 Semihalf.
|
||||||
|
* Copyright (C) 2014 Pavel Machek <pavel@denx.de>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
* published by the Free Software Foundation.
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* You can get hardware description at
|
||||||
|
* http://www.ti.com/lit/ds/symlink/bq32000.pdf
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
@ -27,6 +31,10 @@
|
|||||||
#define BQ32K_CENT 0x40 /* Century flag */
|
#define BQ32K_CENT 0x40 /* Century flag */
|
||||||
#define BQ32K_CENT_EN 0x80 /* Century flag enable bit */
|
#define BQ32K_CENT_EN 0x80 /* Century flag enable bit */
|
||||||
|
|
||||||
|
#define BQ32K_CALIBRATION 0x07 /* CAL_CFG1, calibration and control */
|
||||||
|
#define BQ32K_TCH2 0x08 /* Trickle charge enable */
|
||||||
|
#define BQ32K_CFG2 0x09 /* Trickle charger control */
|
||||||
|
|
||||||
struct bq32k_regs {
|
struct bq32k_regs {
|
||||||
uint8_t seconds;
|
uint8_t seconds;
|
||||||
uint8_t minutes;
|
uint8_t minutes;
|
||||||
@ -122,6 +130,57 @@ static const struct rtc_class_ops bq32k_rtc_ops = {
|
|||||||
.set_time = bq32k_rtc_set_time,
|
.set_time = bq32k_rtc_set_time,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int trickle_charger_of_init(struct device *dev, struct device_node *node)
|
||||||
|
{
|
||||||
|
unsigned char reg;
|
||||||
|
int error;
|
||||||
|
u32 ohms = 0;
|
||||||
|
|
||||||
|
if (of_property_read_u32(node, "trickle-resistor-ohms" , &ohms))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
switch (ohms) {
|
||||||
|
case 180+940:
|
||||||
|
/*
|
||||||
|
* TCHE[3:0] == 0x05, TCH2 == 1, TCFE == 0 (charging
|
||||||
|
* over diode and 940ohm resistor)
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (of_property_read_bool(node, "trickle-diode-disable")) {
|
||||||
|
dev_err(dev, "diode and resistor mismatch\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
reg = 0x05;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 180+20000:
|
||||||
|
/* diode disabled */
|
||||||
|
|
||||||
|
if (!of_property_read_bool(node, "trickle-diode-disable")) {
|
||||||
|
dev_err(dev, "bq32k: diode and resistor mismatch\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
reg = 0x25;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
dev_err(dev, "invalid resistor value (%d)\n", ohms);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = bq32k_write(dev, ®, BQ32K_CFG2, 1);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
reg = 0x20;
|
||||||
|
error = bq32k_write(dev, ®, BQ32K_TCH2, 1);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
dev_info(dev, "Enabled trickle RTC battery charge.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int bq32k_probe(struct i2c_client *client,
|
static int bq32k_probe(struct i2c_client *client,
|
||||||
const struct i2c_device_id *id)
|
const struct i2c_device_id *id)
|
||||||
{
|
{
|
||||||
@ -153,6 +212,9 @@ static int bq32k_probe(struct i2c_client *client,
|
|||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
|
if (client && client->dev.of_node)
|
||||||
|
trickle_charger_of_init(dev, client->dev.of_node);
|
||||||
|
|
||||||
rtc = devm_rtc_device_register(&client->dev, bq32k_driver.driver.name,
|
rtc = devm_rtc_device_register(&client->dev, bq32k_driver.driver.name,
|
||||||
&bq32k_rtc_ops, THIS_MODULE);
|
&bq32k_rtc_ops, THIS_MODULE);
|
||||||
if (IS_ERR(rtc))
|
if (IS_ERR(rtc))
|
||||||
|
@ -856,7 +856,7 @@ static void __exit cmos_do_remove(struct device *dev)
|
|||||||
cmos->dev = NULL;
|
cmos->dev = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM_SLEEP
|
#ifdef CONFIG_PM
|
||||||
|
|
||||||
static int cmos_suspend(struct device *dev)
|
static int cmos_suspend(struct device *dev)
|
||||||
{
|
{
|
||||||
@ -907,6 +907,8 @@ static inline int cmos_poweroff(struct device *dev)
|
|||||||
return cmos_suspend(dev);
|
return cmos_suspend(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM_SLEEP
|
||||||
|
|
||||||
static int cmos_resume(struct device *dev)
|
static int cmos_resume(struct device *dev)
|
||||||
{
|
{
|
||||||
struct cmos_rtc *cmos = dev_get_drvdata(dev);
|
struct cmos_rtc *cmos = dev_get_drvdata(dev);
|
||||||
@ -954,6 +956,7 @@ static int cmos_resume(struct device *dev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
|
|
||||||
static inline int cmos_poweroff(struct device *dev)
|
static inline int cmos_poweroff(struct device *dev)
|
||||||
|
@ -126,9 +126,14 @@ struct chip_desc {
|
|||||||
u16 nvram_offset;
|
u16 nvram_offset;
|
||||||
u16 nvram_size;
|
u16 nvram_size;
|
||||||
u16 trickle_charger_reg;
|
u16 trickle_charger_reg;
|
||||||
|
u8 trickle_charger_setup;
|
||||||
|
u8 (*do_trickle_setup)(struct i2c_client *, uint32_t, bool);
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct chip_desc chips[last_ds_type] = {
|
static u8 do_trickle_setup_ds1339(struct i2c_client *,
|
||||||
|
uint32_t ohms, bool diode);
|
||||||
|
|
||||||
|
static struct chip_desc chips[last_ds_type] = {
|
||||||
[ds_1307] = {
|
[ds_1307] = {
|
||||||
.nvram_offset = 8,
|
.nvram_offset = 8,
|
||||||
.nvram_size = 56,
|
.nvram_size = 56,
|
||||||
@ -143,6 +148,7 @@ static const struct chip_desc chips[last_ds_type] = {
|
|||||||
[ds_1339] = {
|
[ds_1339] = {
|
||||||
.alarm = 1,
|
.alarm = 1,
|
||||||
.trickle_charger_reg = 0x10,
|
.trickle_charger_reg = 0x10,
|
||||||
|
.do_trickle_setup = &do_trickle_setup_ds1339,
|
||||||
},
|
},
|
||||||
[ds_1340] = {
|
[ds_1340] = {
|
||||||
.trickle_charger_reg = 0x08,
|
.trickle_charger_reg = 0x08,
|
||||||
@ -833,15 +839,58 @@ ds1307_nvram_write(struct file *filp, struct kobject *kobj,
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*----------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
static u8 do_trickle_setup_ds1339(struct i2c_client *client,
|
||||||
|
uint32_t ohms, bool diode)
|
||||||
|
{
|
||||||
|
u8 setup = (diode) ? DS1307_TRICKLE_CHARGER_DIODE :
|
||||||
|
DS1307_TRICKLE_CHARGER_NO_DIODE;
|
||||||
|
|
||||||
|
switch (ohms) {
|
||||||
|
case 250:
|
||||||
|
setup |= DS1307_TRICKLE_CHARGER_250_OHM;
|
||||||
|
break;
|
||||||
|
case 2000:
|
||||||
|
setup |= DS1307_TRICKLE_CHARGER_2K_OHM;
|
||||||
|
break;
|
||||||
|
case 4000:
|
||||||
|
setup |= DS1307_TRICKLE_CHARGER_4K_OHM;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dev_warn(&client->dev,
|
||||||
|
"Unsupported ohm value %u in dt\n", ohms);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return setup;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ds1307_trickle_of_init(struct i2c_client *client,
|
||||||
|
struct chip_desc *chip)
|
||||||
|
{
|
||||||
|
uint32_t ohms = 0;
|
||||||
|
bool diode = true;
|
||||||
|
|
||||||
|
if (!chip->do_trickle_setup)
|
||||||
|
goto out;
|
||||||
|
if (of_property_read_u32(client->dev.of_node, "trickle-resistor-ohms" , &ohms))
|
||||||
|
goto out;
|
||||||
|
if (of_property_read_bool(client->dev.of_node, "trickle-diode-disable"))
|
||||||
|
diode = false;
|
||||||
|
chip->trickle_charger_setup = chip->do_trickle_setup(client,
|
||||||
|
ohms, diode);
|
||||||
|
out:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
static int ds1307_probe(struct i2c_client *client,
|
static int ds1307_probe(struct i2c_client *client,
|
||||||
const struct i2c_device_id *id)
|
const struct i2c_device_id *id)
|
||||||
{
|
{
|
||||||
struct ds1307 *ds1307;
|
struct ds1307 *ds1307;
|
||||||
int err = -ENODEV;
|
int err = -ENODEV;
|
||||||
int tmp;
|
int tmp;
|
||||||
const struct chip_desc *chip = &chips[id->driver_data];
|
struct chip_desc *chip = &chips[id->driver_data];
|
||||||
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
|
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
|
||||||
bool want_irq = false;
|
bool want_irq = false;
|
||||||
unsigned char *buf;
|
unsigned char *buf;
|
||||||
@ -866,9 +915,19 @@ static int ds1307_probe(struct i2c_client *client,
|
|||||||
ds1307->client = client;
|
ds1307->client = client;
|
||||||
ds1307->type = id->driver_data;
|
ds1307->type = id->driver_data;
|
||||||
|
|
||||||
if (pdata && pdata->trickle_charger_setup && chip->trickle_charger_reg)
|
if (!pdata && client->dev.of_node)
|
||||||
|
ds1307_trickle_of_init(client, chip);
|
||||||
|
else if (pdata && pdata->trickle_charger_setup)
|
||||||
|
chip->trickle_charger_setup = pdata->trickle_charger_setup;
|
||||||
|
|
||||||
|
if (chip->trickle_charger_setup && chip->trickle_charger_reg) {
|
||||||
|
dev_dbg(&client->dev, "writing trickle charger info 0x%x to 0x%x\n",
|
||||||
|
DS13XX_TRICKLE_CHARGER_MAGIC | chip->trickle_charger_setup,
|
||||||
|
chip->trickle_charger_reg);
|
||||||
i2c_smbus_write_byte_data(client, chip->trickle_charger_reg,
|
i2c_smbus_write_byte_data(client, chip->trickle_charger_reg,
|
||||||
DS13XX_TRICKLE_CHARGER_MAGIC | pdata->trickle_charger_setup);
|
DS13XX_TRICKLE_CHARGER_MAGIC |
|
||||||
|
chip->trickle_charger_setup);
|
||||||
|
}
|
||||||
|
|
||||||
buf = ds1307->regs;
|
buf = ds1307->regs;
|
||||||
if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) {
|
if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) {
|
||||||
|
@ -274,7 +274,7 @@ static int isl12022_probe(struct i2c_client *client,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_OF
|
#ifdef CONFIG_OF
|
||||||
static struct of_device_id isl12022_dt_match[] = {
|
static const struct of_device_id isl12022_dt_match[] = {
|
||||||
{ .compatible = "isl,isl12022" },
|
{ .compatible = "isl,isl12022" },
|
||||||
{ },
|
{ },
|
||||||
};
|
};
|
||||||
|
@ -32,15 +32,6 @@
|
|||||||
#define RTC_UDR_MASK (1 << RTC_UDR_SHIFT)
|
#define RTC_UDR_MASK (1 << RTC_UDR_SHIFT)
|
||||||
#define RTC_RBUDR_SHIFT 4
|
#define RTC_RBUDR_SHIFT 4
|
||||||
#define RTC_RBUDR_MASK (1 << RTC_RBUDR_SHIFT)
|
#define RTC_RBUDR_MASK (1 << RTC_RBUDR_SHIFT)
|
||||||
/* WTSR and SMPL Register */
|
|
||||||
#define WTSRT_SHIFT 0
|
|
||||||
#define SMPLT_SHIFT 2
|
|
||||||
#define WTSR_EN_SHIFT 6
|
|
||||||
#define SMPL_EN_SHIFT 7
|
|
||||||
#define WTSRT_MASK (3 << WTSRT_SHIFT)
|
|
||||||
#define SMPLT_MASK (3 << SMPLT_SHIFT)
|
|
||||||
#define WTSR_EN_MASK (1 << WTSR_EN_SHIFT)
|
|
||||||
#define SMPL_EN_MASK (1 << SMPL_EN_SHIFT)
|
|
||||||
/* RTC Hour register */
|
/* RTC Hour register */
|
||||||
#define HOUR_PM_SHIFT 6
|
#define HOUR_PM_SHIFT 6
|
||||||
#define HOUR_PM_MASK (1 << HOUR_PM_SHIFT)
|
#define HOUR_PM_MASK (1 << HOUR_PM_SHIFT)
|
||||||
@ -49,7 +40,6 @@
|
|||||||
#define ALARM_ENABLE_MASK (1 << ALARM_ENABLE_SHIFT)
|
#define ALARM_ENABLE_MASK (1 << ALARM_ENABLE_SHIFT)
|
||||||
|
|
||||||
#define MAX77686_RTC_UPDATE_DELAY 16
|
#define MAX77686_RTC_UPDATE_DELAY 16
|
||||||
#undef MAX77686_RTC_WTSR_SMPL
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
RTC_SEC = 0,
|
RTC_SEC = 0,
|
||||||
@ -80,16 +70,6 @@ enum MAX77686_RTC_OP {
|
|||||||
MAX77686_RTC_READ,
|
MAX77686_RTC_READ,
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline int max77686_rtc_calculate_wday(u8 shifted)
|
|
||||||
{
|
|
||||||
int counter = -1;
|
|
||||||
while (shifted) {
|
|
||||||
shifted >>= 1;
|
|
||||||
counter++;
|
|
||||||
}
|
|
||||||
return counter;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void max77686_rtc_data_to_tm(u8 *data, struct rtc_time *tm,
|
static void max77686_rtc_data_to_tm(u8 *data, struct rtc_time *tm,
|
||||||
int rtc_24hr_mode)
|
int rtc_24hr_mode)
|
||||||
{
|
{
|
||||||
@ -103,7 +83,8 @@ static void max77686_rtc_data_to_tm(u8 *data, struct rtc_time *tm,
|
|||||||
tm->tm_hour += 12;
|
tm->tm_hour += 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
tm->tm_wday = max77686_rtc_calculate_wday(data[RTC_WEEKDAY] & 0x7f);
|
/* Only a single bit is set in data[], so fls() would be equivalent */
|
||||||
|
tm->tm_wday = ffs(data[RTC_WEEKDAY] & 0x7f) - 1;
|
||||||
tm->tm_mday = data[RTC_DATE] & 0x1f;
|
tm->tm_mday = data[RTC_DATE] & 0x1f;
|
||||||
tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1;
|
tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1;
|
||||||
tm->tm_year = (data[RTC_YEAR] & 0x7f) + 100;
|
tm->tm_year = (data[RTC_YEAR] & 0x7f) + 100;
|
||||||
@ -412,64 +393,6 @@ static const struct rtc_class_ops max77686_rtc_ops = {
|
|||||||
.alarm_irq_enable = max77686_rtc_alarm_irq_enable,
|
.alarm_irq_enable = max77686_rtc_alarm_irq_enable,
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef MAX77686_RTC_WTSR_SMPL
|
|
||||||
static void max77686_rtc_enable_wtsr(struct max77686_rtc_info *info, bool enable)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
unsigned int val, mask;
|
|
||||||
|
|
||||||
if (enable)
|
|
||||||
val = (1 << WTSR_EN_SHIFT) | (3 << WTSRT_SHIFT);
|
|
||||||
else
|
|
||||||
val = 0;
|
|
||||||
|
|
||||||
mask = WTSR_EN_MASK | WTSRT_MASK;
|
|
||||||
|
|
||||||
dev_info(info->dev, "%s: %s WTSR\n", __func__,
|
|
||||||
enable ? "enable" : "disable");
|
|
||||||
|
|
||||||
ret = regmap_update_bits(info->max77686->rtc_regmap,
|
|
||||||
MAX77686_WTSR_SMPL_CNTL, mask, val);
|
|
||||||
if (ret < 0) {
|
|
||||||
dev_err(info->dev, "%s: fail to update WTSR reg(%d)\n",
|
|
||||||
__func__, ret);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
max77686_rtc_update(info, MAX77686_RTC_WRITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void max77686_rtc_enable_smpl(struct max77686_rtc_info *info, bool enable)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
unsigned int val, mask;
|
|
||||||
|
|
||||||
if (enable)
|
|
||||||
val = (1 << SMPL_EN_SHIFT) | (0 << SMPLT_SHIFT);
|
|
||||||
else
|
|
||||||
val = 0;
|
|
||||||
|
|
||||||
mask = SMPL_EN_MASK | SMPLT_MASK;
|
|
||||||
|
|
||||||
dev_info(info->dev, "%s: %s SMPL\n", __func__,
|
|
||||||
enable ? "enable" : "disable");
|
|
||||||
|
|
||||||
ret = regmap_update_bits(info->max77686->rtc_regmap,
|
|
||||||
MAX77686_WTSR_SMPL_CNTL, mask, val);
|
|
||||||
if (ret < 0) {
|
|
||||||
dev_err(info->dev, "%s: fail to update SMPL reg(%d)\n",
|
|
||||||
__func__, ret);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
max77686_rtc_update(info, MAX77686_RTC_WRITE);
|
|
||||||
|
|
||||||
val = 0;
|
|
||||||
regmap_read(info->max77686->rtc_regmap, MAX77686_WTSR_SMPL_CNTL, &val);
|
|
||||||
dev_info(info->dev, "%s: WTSR_SMPL(0x%02x)\n", __func__, val);
|
|
||||||
}
|
|
||||||
#endif /* MAX77686_RTC_WTSR_SMPL */
|
|
||||||
|
|
||||||
static int max77686_rtc_init_reg(struct max77686_rtc_info *info)
|
static int max77686_rtc_init_reg(struct max77686_rtc_info *info)
|
||||||
{
|
{
|
||||||
u8 data[2];
|
u8 data[2];
|
||||||
@ -519,19 +442,12 @@ static int max77686_rtc_probe(struct platform_device *pdev)
|
|||||||
goto err_rtc;
|
goto err_rtc;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MAX77686_RTC_WTSR_SMPL
|
|
||||||
max77686_rtc_enable_wtsr(info, true);
|
|
||||||
max77686_rtc_enable_smpl(info, true);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
device_init_wakeup(&pdev->dev, 1);
|
device_init_wakeup(&pdev->dev, 1);
|
||||||
|
|
||||||
info->rtc_dev = devm_rtc_device_register(&pdev->dev, "max77686-rtc",
|
info->rtc_dev = devm_rtc_device_register(&pdev->dev, "max77686-rtc",
|
||||||
&max77686_rtc_ops, THIS_MODULE);
|
&max77686_rtc_ops, THIS_MODULE);
|
||||||
|
|
||||||
if (IS_ERR(info->rtc_dev)) {
|
if (IS_ERR(info->rtc_dev)) {
|
||||||
dev_info(&pdev->dev, "%s: fail\n", __func__);
|
|
||||||
|
|
||||||
ret = PTR_ERR(info->rtc_dev);
|
ret = PTR_ERR(info->rtc_dev);
|
||||||
dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
|
dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
@ -539,6 +455,12 @@ static int max77686_rtc_probe(struct platform_device *pdev)
|
|||||||
goto err_rtc;
|
goto err_rtc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!max77686->rtc_irq_data) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
dev_err(&pdev->dev, "%s: no RTC regmap IRQ chip\n", __func__);
|
||||||
|
goto err_rtc;
|
||||||
|
}
|
||||||
|
|
||||||
info->virq = regmap_irq_get_virq(max77686->rtc_irq_data,
|
info->virq = regmap_irq_get_virq(max77686->rtc_irq_data,
|
||||||
MAX77686_RTCIRQ_RTCA1);
|
MAX77686_RTCIRQ_RTCA1);
|
||||||
if (!info->virq) {
|
if (!info->virq) {
|
||||||
@ -556,33 +478,33 @@ err_rtc:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void max77686_rtc_shutdown(struct platform_device *pdev)
|
#ifdef CONFIG_PM_SLEEP
|
||||||
|
static int max77686_rtc_suspend(struct device *dev)
|
||||||
{
|
{
|
||||||
#ifdef MAX77686_RTC_WTSR_SMPL
|
if (device_may_wakeup(dev)) {
|
||||||
struct max77686_rtc_info *info = platform_get_drvdata(pdev);
|
struct max77686_rtc_info *info = dev_get_drvdata(dev);
|
||||||
int i;
|
|
||||||
u8 val = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < 3; i++) {
|
return enable_irq_wake(info->virq);
|
||||||
max77686_rtc_enable_wtsr(info, false);
|
|
||||||
regmap_read(info->max77686->rtc_regmap, MAX77686_WTSR_SMPL_CNTL, &val);
|
|
||||||
dev_info(info->dev, "%s: WTSR_SMPL reg(0x%02x)\n", __func__,
|
|
||||||
val);
|
|
||||||
if (val & WTSR_EN_MASK) {
|
|
||||||
dev_emerg(info->dev, "%s: fail to disable WTSR\n",
|
|
||||||
__func__);
|
|
||||||
} else {
|
|
||||||
dev_info(info->dev, "%s: success to disable WTSR\n",
|
|
||||||
__func__);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Disable SMPL when power off */
|
return 0;
|
||||||
max77686_rtc_enable_smpl(info, false);
|
|
||||||
#endif /* MAX77686_RTC_WTSR_SMPL */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int max77686_rtc_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
if (device_may_wakeup(dev)) {
|
||||||
|
struct max77686_rtc_info *info = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
return disable_irq_wake(info->virq);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static SIMPLE_DEV_PM_OPS(max77686_rtc_pm_ops,
|
||||||
|
max77686_rtc_suspend, max77686_rtc_resume);
|
||||||
|
|
||||||
static const struct platform_device_id rtc_id[] = {
|
static const struct platform_device_id rtc_id[] = {
|
||||||
{ "max77686-rtc", 0 },
|
{ "max77686-rtc", 0 },
|
||||||
{},
|
{},
|
||||||
@ -592,9 +514,9 @@ static struct platform_driver max77686_rtc_driver = {
|
|||||||
.driver = {
|
.driver = {
|
||||||
.name = "max77686-rtc",
|
.name = "max77686-rtc",
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
|
.pm = &max77686_rtc_pm_ops,
|
||||||
},
|
},
|
||||||
.probe = max77686_rtc_probe,
|
.probe = max77686_rtc_probe,
|
||||||
.shutdown = max77686_rtc_shutdown,
|
|
||||||
.id_table = rtc_id,
|
.id_table = rtc_id,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
502
drivers/rtc/rtc-max77802.c
Normal file
502
drivers/rtc/rtc-max77802.c
Normal file
@ -0,0 +1,502 @@
|
|||||||
|
/*
|
||||||
|
* RTC driver for Maxim MAX77802
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 Google, Inc
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Samsung Electronics Co.Ltd
|
||||||
|
*
|
||||||
|
* based on rtc-max8997.c
|
||||||
|
*
|
||||||
|
* 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 <linux/slab.h>
|
||||||
|
#include <linux/rtc.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/mfd/max77686-private.h>
|
||||||
|
#include <linux/irqdomain.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
|
||||||
|
/* RTC Control Register */
|
||||||
|
#define BCD_EN_SHIFT 0
|
||||||
|
#define BCD_EN_MASK (1 << BCD_EN_SHIFT)
|
||||||
|
#define MODEL24_SHIFT 1
|
||||||
|
#define MODEL24_MASK (1 << MODEL24_SHIFT)
|
||||||
|
/* RTC Update Register1 */
|
||||||
|
#define RTC_UDR_SHIFT 0
|
||||||
|
#define RTC_UDR_MASK (1 << RTC_UDR_SHIFT)
|
||||||
|
#define RTC_RBUDR_SHIFT 4
|
||||||
|
#define RTC_RBUDR_MASK (1 << RTC_RBUDR_SHIFT)
|
||||||
|
/* RTC Hour register */
|
||||||
|
#define HOUR_PM_SHIFT 6
|
||||||
|
#define HOUR_PM_MASK (1 << HOUR_PM_SHIFT)
|
||||||
|
/* RTC Alarm Enable */
|
||||||
|
#define ALARM_ENABLE_SHIFT 7
|
||||||
|
#define ALARM_ENABLE_MASK (1 << ALARM_ENABLE_SHIFT)
|
||||||
|
|
||||||
|
/* For the RTCAE1 register, we write this value to enable the alarm */
|
||||||
|
#define ALARM_ENABLE_VALUE 0x77
|
||||||
|
|
||||||
|
#define MAX77802_RTC_UPDATE_DELAY_US 200
|
||||||
|
|
||||||
|
enum {
|
||||||
|
RTC_SEC = 0,
|
||||||
|
RTC_MIN,
|
||||||
|
RTC_HOUR,
|
||||||
|
RTC_WEEKDAY,
|
||||||
|
RTC_MONTH,
|
||||||
|
RTC_YEAR,
|
||||||
|
RTC_DATE,
|
||||||
|
RTC_NR_TIME
|
||||||
|
};
|
||||||
|
|
||||||
|
struct max77802_rtc_info {
|
||||||
|
struct device *dev;
|
||||||
|
struct max77686_dev *max77802;
|
||||||
|
struct i2c_client *rtc;
|
||||||
|
struct rtc_device *rtc_dev;
|
||||||
|
struct mutex lock;
|
||||||
|
|
||||||
|
struct regmap *regmap;
|
||||||
|
|
||||||
|
int virq;
|
||||||
|
int rtc_24hr_mode;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum MAX77802_RTC_OP {
|
||||||
|
MAX77802_RTC_WRITE,
|
||||||
|
MAX77802_RTC_READ,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void max77802_rtc_data_to_tm(u8 *data, struct rtc_time *tm,
|
||||||
|
int rtc_24hr_mode)
|
||||||
|
{
|
||||||
|
tm->tm_sec = data[RTC_SEC] & 0xff;
|
||||||
|
tm->tm_min = data[RTC_MIN] & 0xff;
|
||||||
|
if (rtc_24hr_mode)
|
||||||
|
tm->tm_hour = data[RTC_HOUR] & 0x1f;
|
||||||
|
else {
|
||||||
|
tm->tm_hour = data[RTC_HOUR] & 0x0f;
|
||||||
|
if (data[RTC_HOUR] & HOUR_PM_MASK)
|
||||||
|
tm->tm_hour += 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only a single bit is set in data[], so fls() would be equivalent */
|
||||||
|
tm->tm_wday = ffs(data[RTC_WEEKDAY] & 0xff) - 1;
|
||||||
|
tm->tm_mday = data[RTC_DATE] & 0x1f;
|
||||||
|
tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1;
|
||||||
|
|
||||||
|
tm->tm_year = data[RTC_YEAR] & 0xff;
|
||||||
|
tm->tm_yday = 0;
|
||||||
|
tm->tm_isdst = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int max77802_rtc_tm_to_data(struct rtc_time *tm, u8 *data)
|
||||||
|
{
|
||||||
|
data[RTC_SEC] = tm->tm_sec;
|
||||||
|
data[RTC_MIN] = tm->tm_min;
|
||||||
|
data[RTC_HOUR] = tm->tm_hour;
|
||||||
|
data[RTC_WEEKDAY] = 1 << tm->tm_wday;
|
||||||
|
data[RTC_DATE] = tm->tm_mday;
|
||||||
|
data[RTC_MONTH] = tm->tm_mon + 1;
|
||||||
|
data[RTC_YEAR] = tm->tm_year;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int max77802_rtc_update(struct max77802_rtc_info *info,
|
||||||
|
enum MAX77802_RTC_OP op)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
unsigned int data;
|
||||||
|
|
||||||
|
if (op == MAX77802_RTC_WRITE)
|
||||||
|
data = 1 << RTC_UDR_SHIFT;
|
||||||
|
else
|
||||||
|
data = 1 << RTC_RBUDR_SHIFT;
|
||||||
|
|
||||||
|
ret = regmap_update_bits(info->max77802->regmap,
|
||||||
|
MAX77802_RTC_UPDATE0, data, data);
|
||||||
|
if (ret < 0)
|
||||||
|
dev_err(info->dev, "%s: fail to write update reg(ret=%d, data=0x%x)\n",
|
||||||
|
__func__, ret, data);
|
||||||
|
else {
|
||||||
|
/* Minimum delay required before RTC update. */
|
||||||
|
usleep_range(MAX77802_RTC_UPDATE_DELAY_US,
|
||||||
|
MAX77802_RTC_UPDATE_DELAY_US * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int max77802_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||||
|
{
|
||||||
|
struct max77802_rtc_info *info = dev_get_drvdata(dev);
|
||||||
|
u8 data[RTC_NR_TIME];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
mutex_lock(&info->lock);
|
||||||
|
|
||||||
|
ret = max77802_rtc_update(info, MAX77802_RTC_READ);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = regmap_bulk_read(info->max77802->regmap,
|
||||||
|
MAX77802_RTC_SEC, data, RTC_NR_TIME);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(info->dev, "%s: fail to read time reg(%d)\n", __func__,
|
||||||
|
ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
max77802_rtc_data_to_tm(data, tm, info->rtc_24hr_mode);
|
||||||
|
|
||||||
|
ret = rtc_valid_tm(tm);
|
||||||
|
|
||||||
|
out:
|
||||||
|
mutex_unlock(&info->lock);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int max77802_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||||
|
{
|
||||||
|
struct max77802_rtc_info *info = dev_get_drvdata(dev);
|
||||||
|
u8 data[RTC_NR_TIME];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = max77802_rtc_tm_to_data(tm, data);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
mutex_lock(&info->lock);
|
||||||
|
|
||||||
|
ret = regmap_bulk_write(info->max77802->regmap,
|
||||||
|
MAX77802_RTC_SEC, data, RTC_NR_TIME);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(info->dev, "%s: fail to write time reg(%d)\n", __func__,
|
||||||
|
ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = max77802_rtc_update(info, MAX77802_RTC_WRITE);
|
||||||
|
|
||||||
|
out:
|
||||||
|
mutex_unlock(&info->lock);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int max77802_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||||
|
{
|
||||||
|
struct max77802_rtc_info *info = dev_get_drvdata(dev);
|
||||||
|
u8 data[RTC_NR_TIME];
|
||||||
|
unsigned int val;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
mutex_lock(&info->lock);
|
||||||
|
|
||||||
|
ret = max77802_rtc_update(info, MAX77802_RTC_READ);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = regmap_bulk_read(info->max77802->regmap,
|
||||||
|
MAX77802_ALARM1_SEC, data, RTC_NR_TIME);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(info->dev, "%s:%d fail to read alarm reg(%d)\n",
|
||||||
|
__func__, __LINE__, ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
max77802_rtc_data_to_tm(data, &alrm->time, info->rtc_24hr_mode);
|
||||||
|
|
||||||
|
alrm->enabled = 0;
|
||||||
|
ret = regmap_read(info->max77802->regmap,
|
||||||
|
MAX77802_RTC_AE1, &val);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(info->dev, "%s:%d fail to read alarm enable(%d)\n",
|
||||||
|
__func__, __LINE__, ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (val)
|
||||||
|
alrm->enabled = 1;
|
||||||
|
|
||||||
|
alrm->pending = 0;
|
||||||
|
ret = regmap_read(info->max77802->regmap, MAX77802_REG_STATUS2, &val);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(info->dev, "%s:%d fail to read status2 reg(%d)\n",
|
||||||
|
__func__, __LINE__, ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val & (1 << 2)) /* RTCA1 */
|
||||||
|
alrm->pending = 1;
|
||||||
|
|
||||||
|
out:
|
||||||
|
mutex_unlock(&info->lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int max77802_rtc_stop_alarm(struct max77802_rtc_info *info)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!mutex_is_locked(&info->lock))
|
||||||
|
dev_warn(info->dev, "%s: should have mutex locked\n", __func__);
|
||||||
|
|
||||||
|
ret = max77802_rtc_update(info, MAX77802_RTC_READ);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = regmap_write(info->max77802->regmap,
|
||||||
|
MAX77802_RTC_AE1, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
|
||||||
|
__func__, ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = max77802_rtc_update(info, MAX77802_RTC_WRITE);
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int max77802_rtc_start_alarm(struct max77802_rtc_info *info)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!mutex_is_locked(&info->lock))
|
||||||
|
dev_warn(info->dev, "%s: should have mutex locked\n",
|
||||||
|
__func__);
|
||||||
|
|
||||||
|
ret = max77802_rtc_update(info, MAX77802_RTC_READ);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = regmap_write(info->max77802->regmap,
|
||||||
|
MAX77802_RTC_AE1,
|
||||||
|
ALARM_ENABLE_VALUE);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(info->dev, "%s: fail to read alarm reg(%d)\n",
|
||||||
|
__func__, ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = max77802_rtc_update(info, MAX77802_RTC_WRITE);
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int max77802_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||||
|
{
|
||||||
|
struct max77802_rtc_info *info = dev_get_drvdata(dev);
|
||||||
|
u8 data[RTC_NR_TIME];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = max77802_rtc_tm_to_data(&alrm->time, data);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
mutex_lock(&info->lock);
|
||||||
|
|
||||||
|
ret = max77802_rtc_stop_alarm(info);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = regmap_bulk_write(info->max77802->regmap,
|
||||||
|
MAX77802_ALARM1_SEC, data, RTC_NR_TIME);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
|
||||||
|
__func__, ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = max77802_rtc_update(info, MAX77802_RTC_WRITE);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (alrm->enabled)
|
||||||
|
ret = max77802_rtc_start_alarm(info);
|
||||||
|
out:
|
||||||
|
mutex_unlock(&info->lock);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int max77802_rtc_alarm_irq_enable(struct device *dev,
|
||||||
|
unsigned int enabled)
|
||||||
|
{
|
||||||
|
struct max77802_rtc_info *info = dev_get_drvdata(dev);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
mutex_lock(&info->lock);
|
||||||
|
if (enabled)
|
||||||
|
ret = max77802_rtc_start_alarm(info);
|
||||||
|
else
|
||||||
|
ret = max77802_rtc_stop_alarm(info);
|
||||||
|
mutex_unlock(&info->lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static irqreturn_t max77802_rtc_alarm_irq(int irq, void *data)
|
||||||
|
{
|
||||||
|
struct max77802_rtc_info *info = data;
|
||||||
|
|
||||||
|
dev_dbg(info->dev, "%s:irq(%d)\n", __func__, irq);
|
||||||
|
|
||||||
|
rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF);
|
||||||
|
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct rtc_class_ops max77802_rtc_ops = {
|
||||||
|
.read_time = max77802_rtc_read_time,
|
||||||
|
.set_time = max77802_rtc_set_time,
|
||||||
|
.read_alarm = max77802_rtc_read_alarm,
|
||||||
|
.set_alarm = max77802_rtc_set_alarm,
|
||||||
|
.alarm_irq_enable = max77802_rtc_alarm_irq_enable,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int max77802_rtc_init_reg(struct max77802_rtc_info *info)
|
||||||
|
{
|
||||||
|
u8 data[2];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
max77802_rtc_update(info, MAX77802_RTC_READ);
|
||||||
|
|
||||||
|
/* Set RTC control register : Binary mode, 24hour mdoe */
|
||||||
|
data[0] = (1 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
|
||||||
|
data[1] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
|
||||||
|
|
||||||
|
info->rtc_24hr_mode = 1;
|
||||||
|
|
||||||
|
ret = regmap_bulk_write(info->max77802->regmap,
|
||||||
|
MAX77802_RTC_CONTROLM, data, ARRAY_SIZE(data));
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(info->dev, "%s: fail to write controlm reg(%d)\n",
|
||||||
|
__func__, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = max77802_rtc_update(info, MAX77802_RTC_WRITE);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int max77802_rtc_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct max77686_dev *max77802 = dev_get_drvdata(pdev->dev.parent);
|
||||||
|
struct max77802_rtc_info *info;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
dev_dbg(&pdev->dev, "%s\n", __func__);
|
||||||
|
|
||||||
|
info = devm_kzalloc(&pdev->dev, sizeof(struct max77802_rtc_info),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!info)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
mutex_init(&info->lock);
|
||||||
|
info->dev = &pdev->dev;
|
||||||
|
info->max77802 = max77802;
|
||||||
|
info->rtc = max77802->i2c;
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, info);
|
||||||
|
|
||||||
|
ret = max77802_rtc_init_reg(info);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(&pdev->dev, "Failed to initialize RTC reg:%d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
device_init_wakeup(&pdev->dev, 1);
|
||||||
|
|
||||||
|
info->rtc_dev = devm_rtc_device_register(&pdev->dev, "max77802-rtc",
|
||||||
|
&max77802_rtc_ops, THIS_MODULE);
|
||||||
|
|
||||||
|
if (IS_ERR(info->rtc_dev)) {
|
||||||
|
ret = PTR_ERR(info->rtc_dev);
|
||||||
|
dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
|
||||||
|
if (ret == 0)
|
||||||
|
ret = -EINVAL;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!max77802->rtc_irq_data) {
|
||||||
|
dev_err(&pdev->dev, "No RTC regmap IRQ chip\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
info->virq = regmap_irq_get_virq(max77802->rtc_irq_data,
|
||||||
|
MAX77686_RTCIRQ_RTCA1);
|
||||||
|
|
||||||
|
if (info->virq <= 0) {
|
||||||
|
dev_err(&pdev->dev, "Failed to get virtual IRQ %d\n",
|
||||||
|
MAX77686_RTCIRQ_RTCA1);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = devm_request_threaded_irq(&pdev->dev, info->virq, NULL,
|
||||||
|
max77802_rtc_alarm_irq, 0, "rtc-alarm1",
|
||||||
|
info);
|
||||||
|
if (ret < 0)
|
||||||
|
dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
|
||||||
|
info->virq, ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM_SLEEP
|
||||||
|
static int max77802_rtc_suspend(struct device *dev)
|
||||||
|
{
|
||||||
|
if (device_may_wakeup(dev)) {
|
||||||
|
struct max77802_rtc_info *info = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
return enable_irq_wake(info->virq);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int max77802_rtc_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
if (device_may_wakeup(dev)) {
|
||||||
|
struct max77802_rtc_info *info = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
return disable_irq_wake(info->virq);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static SIMPLE_DEV_PM_OPS(max77802_rtc_pm_ops,
|
||||||
|
max77802_rtc_suspend, max77802_rtc_resume);
|
||||||
|
|
||||||
|
static const struct platform_device_id rtc_id[] = {
|
||||||
|
{ "max77802-rtc", 0 },
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_driver max77802_rtc_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "max77802-rtc",
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.pm = &max77802_rtc_pm_ops,
|
||||||
|
},
|
||||||
|
.probe = max77802_rtc_probe,
|
||||||
|
.id_table = rtc_id,
|
||||||
|
};
|
||||||
|
|
||||||
|
module_platform_driver(max77802_rtc_driver);
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION("Maxim MAX77802 RTC driver");
|
||||||
|
MODULE_AUTHOR("Simon Glass <sjg@chromium.org>");
|
||||||
|
MODULE_LICENSE("GPL");
|
@ -401,7 +401,7 @@ static int mpc5121_rtc_remove(struct platform_device *op)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_OF
|
#ifdef CONFIG_OF
|
||||||
static struct of_device_id mpc5121_rtc_match[] = {
|
static const struct of_device_id mpc5121_rtc_match[] = {
|
||||||
{ .compatible = "fsl,mpc5121-rtc", },
|
{ .compatible = "fsl,mpc5121-rtc", },
|
||||||
{ .compatible = "fsl,mpc5200-rtc", },
|
{ .compatible = "fsl,mpc5200-rtc", },
|
||||||
{},
|
{},
|
||||||
|
@ -167,8 +167,8 @@ static irqreturn_t pcf8563_irq(int irq, void *dev_id)
|
|||||||
char pending;
|
char pending;
|
||||||
|
|
||||||
err = pcf8563_get_alarm_mode(pcf8563->client, NULL, &pending);
|
err = pcf8563_get_alarm_mode(pcf8563->client, NULL, &pending);
|
||||||
if (err < 0)
|
if (err)
|
||||||
return err;
|
return IRQ_NONE;
|
||||||
|
|
||||||
if (pending) {
|
if (pending) {
|
||||||
rtc_update_irq(pcf8563->rtc, 1, RTC_IRQF | RTC_AF);
|
rtc_update_irq(pcf8563->rtc, 1, RTC_IRQF | RTC_AF);
|
||||||
|
@ -176,7 +176,11 @@ static int pcf8583_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
|||||||
{
|
{
|
||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
unsigned char ctrl, year[2];
|
unsigned char ctrl, year[2];
|
||||||
struct rtc_mem mem = { CMOS_YEAR, sizeof(year), year };
|
struct rtc_mem mem = {
|
||||||
|
.loc = CMOS_YEAR,
|
||||||
|
.nr = sizeof(year),
|
||||||
|
.data = year
|
||||||
|
};
|
||||||
int real_year, year_offset, err;
|
int real_year, year_offset, err;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -222,8 +226,16 @@ static int pcf8583_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
|||||||
{
|
{
|
||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
unsigned char year[2], chk;
|
unsigned char year[2], chk;
|
||||||
struct rtc_mem cmos_year = { CMOS_YEAR, sizeof(year), year };
|
struct rtc_mem cmos_year = {
|
||||||
struct rtc_mem cmos_check = { CMOS_CHECKSUM, 1, &chk };
|
.loc = CMOS_YEAR,
|
||||||
|
.nr = sizeof(year),
|
||||||
|
.data = year
|
||||||
|
};
|
||||||
|
struct rtc_mem cmos_check = {
|
||||||
|
.loc = CMOS_CHECKSUM,
|
||||||
|
.nr = 1,
|
||||||
|
.data = &chk
|
||||||
|
};
|
||||||
unsigned int proper_year = tm->tm_year + 1900;
|
unsigned int proper_year = tm->tm_year + 1900;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
414
drivers/rtc/rtc-rk808.c
Normal file
414
drivers/rtc/rtc-rk808.c
Normal file
@ -0,0 +1,414 @@
|
|||||||
|
/*
|
||||||
|
* RTC driver for Rockchip RK808
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
|
||||||
|
*
|
||||||
|
* Author: Chris Zhong <zyw@rock-chips.com>
|
||||||
|
* Author: Zhang Qing <zhangqing@rock-chips.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/rtc.h>
|
||||||
|
#include <linux/bcd.h>
|
||||||
|
#include <linux/mfd/rk808.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/i2c.h>
|
||||||
|
|
||||||
|
/* RTC_CTRL_REG bitfields */
|
||||||
|
#define BIT_RTC_CTRL_REG_STOP_RTC_M BIT(0)
|
||||||
|
|
||||||
|
/* RK808 has a shadowed register for saving a "frozen" RTC time.
|
||||||
|
* When user setting "GET_TIME" to 1, the time will save in this shadowed
|
||||||
|
* register. If set "READSEL" to 1, user read rtc time register, actually
|
||||||
|
* get the time of that moment. If we need the real time, clr this bit.
|
||||||
|
*/
|
||||||
|
#define BIT_RTC_CTRL_REG_RTC_GET_TIME BIT(6)
|
||||||
|
#define BIT_RTC_CTRL_REG_RTC_READSEL_M BIT(7)
|
||||||
|
#define BIT_RTC_INTERRUPTS_REG_IT_ALARM_M BIT(3)
|
||||||
|
#define RTC_STATUS_MASK 0xFE
|
||||||
|
|
||||||
|
#define SECONDS_REG_MSK 0x7F
|
||||||
|
#define MINUTES_REG_MAK 0x7F
|
||||||
|
#define HOURS_REG_MSK 0x3F
|
||||||
|
#define DAYS_REG_MSK 0x3F
|
||||||
|
#define MONTHS_REG_MSK 0x1F
|
||||||
|
#define YEARS_REG_MSK 0xFF
|
||||||
|
#define WEEKS_REG_MSK 0x7
|
||||||
|
|
||||||
|
/* REG_SECONDS_REG through REG_YEARS_REG is how many registers? */
|
||||||
|
|
||||||
|
#define NUM_TIME_REGS (RK808_WEEKS_REG - RK808_SECONDS_REG + 1)
|
||||||
|
#define NUM_ALARM_REGS (RK808_ALARM_YEARS_REG - RK808_ALARM_SECONDS_REG + 1)
|
||||||
|
|
||||||
|
struct rk808_rtc {
|
||||||
|
struct rk808 *rk808;
|
||||||
|
struct rtc_device *rtc;
|
||||||
|
int irq;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Read current time and date in RTC */
|
||||||
|
static int rk808_rtc_readtime(struct device *dev, struct rtc_time *tm)
|
||||||
|
{
|
||||||
|
struct rk808_rtc *rk808_rtc = dev_get_drvdata(dev);
|
||||||
|
struct rk808 *rk808 = rk808_rtc->rk808;
|
||||||
|
u8 rtc_data[NUM_TIME_REGS];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Force an update of the shadowed registers right now */
|
||||||
|
ret = regmap_update_bits(rk808->regmap, RK808_RTC_CTRL_REG,
|
||||||
|
BIT_RTC_CTRL_REG_RTC_GET_TIME,
|
||||||
|
0);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "Failed to update bits rtc_ctrl: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = regmap_update_bits(rk808->regmap, RK808_RTC_CTRL_REG,
|
||||||
|
BIT_RTC_CTRL_REG_RTC_GET_TIME,
|
||||||
|
BIT_RTC_CTRL_REG_RTC_GET_TIME);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "Failed to update bits rtc_ctrl: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = regmap_bulk_read(rk808->regmap, RK808_SECONDS_REG,
|
||||||
|
rtc_data, NUM_TIME_REGS);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "Failed to bulk read rtc_data: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
tm->tm_sec = bcd2bin(rtc_data[0] & SECONDS_REG_MSK);
|
||||||
|
tm->tm_min = bcd2bin(rtc_data[1] & MINUTES_REG_MAK);
|
||||||
|
tm->tm_hour = bcd2bin(rtc_data[2] & HOURS_REG_MSK);
|
||||||
|
tm->tm_mday = bcd2bin(rtc_data[3] & DAYS_REG_MSK);
|
||||||
|
tm->tm_mon = (bcd2bin(rtc_data[4] & MONTHS_REG_MSK)) - 1;
|
||||||
|
tm->tm_year = (bcd2bin(rtc_data[5] & YEARS_REG_MSK)) + 100;
|
||||||
|
tm->tm_wday = bcd2bin(rtc_data[6] & WEEKS_REG_MSK);
|
||||||
|
dev_dbg(dev, "RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n",
|
||||||
|
1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
|
||||||
|
tm->tm_wday, tm->tm_hour , tm->tm_min, tm->tm_sec);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set current time and date in RTC */
|
||||||
|
static int rk808_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||||
|
{
|
||||||
|
struct rk808_rtc *rk808_rtc = dev_get_drvdata(dev);
|
||||||
|
struct rk808 *rk808 = rk808_rtc->rk808;
|
||||||
|
u8 rtc_data[NUM_TIME_REGS];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
rtc_data[0] = bin2bcd(tm->tm_sec);
|
||||||
|
rtc_data[1] = bin2bcd(tm->tm_min);
|
||||||
|
rtc_data[2] = bin2bcd(tm->tm_hour);
|
||||||
|
rtc_data[3] = bin2bcd(tm->tm_mday);
|
||||||
|
rtc_data[4] = bin2bcd(tm->tm_mon + 1);
|
||||||
|
rtc_data[5] = bin2bcd(tm->tm_year - 100);
|
||||||
|
rtc_data[6] = bin2bcd(tm->tm_wday);
|
||||||
|
dev_dbg(dev, "set RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n",
|
||||||
|
1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
|
||||||
|
tm->tm_wday, tm->tm_hour , tm->tm_min, tm->tm_sec);
|
||||||
|
|
||||||
|
/* Stop RTC while updating the RTC registers */
|
||||||
|
ret = regmap_update_bits(rk808->regmap, RK808_RTC_CTRL_REG,
|
||||||
|
BIT_RTC_CTRL_REG_STOP_RTC_M,
|
||||||
|
BIT_RTC_CTRL_REG_STOP_RTC_M);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "Failed to update RTC control: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = regmap_bulk_write(rk808->regmap, RK808_SECONDS_REG,
|
||||||
|
rtc_data, NUM_TIME_REGS);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "Failed to bull write rtc_data: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
/* Start RTC again */
|
||||||
|
ret = regmap_update_bits(rk808->regmap, RK808_RTC_CTRL_REG,
|
||||||
|
BIT_RTC_CTRL_REG_STOP_RTC_M, 0);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "Failed to update RTC control: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read alarm time and date in RTC */
|
||||||
|
static int rk808_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||||
|
{
|
||||||
|
struct rk808_rtc *rk808_rtc = dev_get_drvdata(dev);
|
||||||
|
struct rk808 *rk808 = rk808_rtc->rk808;
|
||||||
|
u8 alrm_data[NUM_ALARM_REGS];
|
||||||
|
uint32_t int_reg;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = regmap_bulk_read(rk808->regmap, RK808_ALARM_SECONDS_REG,
|
||||||
|
alrm_data, NUM_ALARM_REGS);
|
||||||
|
|
||||||
|
alrm->time.tm_sec = bcd2bin(alrm_data[0] & SECONDS_REG_MSK);
|
||||||
|
alrm->time.tm_min = bcd2bin(alrm_data[1] & MINUTES_REG_MAK);
|
||||||
|
alrm->time.tm_hour = bcd2bin(alrm_data[2] & HOURS_REG_MSK);
|
||||||
|
alrm->time.tm_mday = bcd2bin(alrm_data[3] & DAYS_REG_MSK);
|
||||||
|
alrm->time.tm_mon = (bcd2bin(alrm_data[4] & MONTHS_REG_MSK)) - 1;
|
||||||
|
alrm->time.tm_year = (bcd2bin(alrm_data[5] & YEARS_REG_MSK)) + 100;
|
||||||
|
|
||||||
|
ret = regmap_read(rk808->regmap, RK808_RTC_INT_REG, &int_reg);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "Failed to read RTC INT REG: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_dbg(dev, "alrm read RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n",
|
||||||
|
1900 + alrm->time.tm_year, alrm->time.tm_mon + 1,
|
||||||
|
alrm->time.tm_mday, alrm->time.tm_wday, alrm->time.tm_hour,
|
||||||
|
alrm->time.tm_min, alrm->time.tm_sec);
|
||||||
|
|
||||||
|
alrm->enabled = (int_reg & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M) ? 1 : 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rk808_rtc_stop_alarm(struct rk808_rtc *rk808_rtc)
|
||||||
|
{
|
||||||
|
struct rk808 *rk808 = rk808_rtc->rk808;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = regmap_update_bits(rk808->regmap, RK808_RTC_INT_REG,
|
||||||
|
BIT_RTC_INTERRUPTS_REG_IT_ALARM_M, 0);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rk808_rtc_start_alarm(struct rk808_rtc *rk808_rtc)
|
||||||
|
{
|
||||||
|
struct rk808 *rk808 = rk808_rtc->rk808;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = regmap_update_bits(rk808->regmap, RK808_RTC_INT_REG,
|
||||||
|
BIT_RTC_INTERRUPTS_REG_IT_ALARM_M,
|
||||||
|
BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rk808_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||||
|
{
|
||||||
|
struct rk808_rtc *rk808_rtc = dev_get_drvdata(dev);
|
||||||
|
struct rk808 *rk808 = rk808_rtc->rk808;
|
||||||
|
u8 alrm_data[NUM_ALARM_REGS];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = rk808_rtc_stop_alarm(rk808_rtc);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "Failed to stop alarm: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
dev_dbg(dev, "alrm set RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n",
|
||||||
|
1900 + alrm->time.tm_year, alrm->time.tm_mon + 1,
|
||||||
|
alrm->time.tm_mday, alrm->time.tm_wday, alrm->time.tm_hour,
|
||||||
|
alrm->time.tm_min, alrm->time.tm_sec);
|
||||||
|
|
||||||
|
alrm_data[0] = bin2bcd(alrm->time.tm_sec);
|
||||||
|
alrm_data[1] = bin2bcd(alrm->time.tm_min);
|
||||||
|
alrm_data[2] = bin2bcd(alrm->time.tm_hour);
|
||||||
|
alrm_data[3] = bin2bcd(alrm->time.tm_mday);
|
||||||
|
alrm_data[4] = bin2bcd(alrm->time.tm_mon + 1);
|
||||||
|
alrm_data[5] = bin2bcd(alrm->time.tm_year - 100);
|
||||||
|
|
||||||
|
ret = regmap_bulk_write(rk808->regmap, RK808_ALARM_SECONDS_REG,
|
||||||
|
alrm_data, NUM_ALARM_REGS);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "Failed to bulk write: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (alrm->enabled) {
|
||||||
|
ret = rk808_rtc_start_alarm(rk808_rtc);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "Failed to start alarm: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rk808_rtc_alarm_irq_enable(struct device *dev,
|
||||||
|
unsigned int enabled)
|
||||||
|
{
|
||||||
|
struct rk808_rtc *rk808_rtc = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
if (enabled)
|
||||||
|
return rk808_rtc_start_alarm(rk808_rtc);
|
||||||
|
|
||||||
|
return rk808_rtc_stop_alarm(rk808_rtc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We will just handle setting the frequency and make use the framework for
|
||||||
|
* reading the periodic interupts.
|
||||||
|
*
|
||||||
|
* @freq: Current periodic IRQ freq:
|
||||||
|
* bit 0: every second
|
||||||
|
* bit 1: every minute
|
||||||
|
* bit 2: every hour
|
||||||
|
* bit 3: every day
|
||||||
|
*/
|
||||||
|
static irqreturn_t rk808_alarm_irq(int irq, void *data)
|
||||||
|
{
|
||||||
|
struct rk808_rtc *rk808_rtc = data;
|
||||||
|
struct rk808 *rk808 = rk808_rtc->rk808;
|
||||||
|
struct i2c_client *client = rk808->i2c;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = regmap_write(rk808->regmap, RK808_RTC_STATUS_REG,
|
||||||
|
RTC_STATUS_MASK);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&client->dev,
|
||||||
|
"%s:Failed to update RTC status: %d\n", __func__, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
rtc_update_irq(rk808_rtc->rtc, 1, RTC_IRQF | RTC_AF);
|
||||||
|
dev_dbg(&client->dev,
|
||||||
|
"%s:irq=%d\n", __func__, irq);
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct rtc_class_ops rk808_rtc_ops = {
|
||||||
|
.read_time = rk808_rtc_readtime,
|
||||||
|
.set_time = rk808_rtc_set_time,
|
||||||
|
.read_alarm = rk808_rtc_readalarm,
|
||||||
|
.set_alarm = rk808_rtc_setalarm,
|
||||||
|
.alarm_irq_enable = rk808_rtc_alarm_irq_enable,
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM_SLEEP
|
||||||
|
/* Turn off the alarm if it should not be a wake source. */
|
||||||
|
static int rk808_rtc_suspend(struct device *dev)
|
||||||
|
{
|
||||||
|
struct platform_device *pdev = to_platform_device(dev);
|
||||||
|
struct rk808_rtc *rk808_rtc = dev_get_drvdata(&pdev->dev);
|
||||||
|
|
||||||
|
if (device_may_wakeup(dev))
|
||||||
|
enable_irq_wake(rk808_rtc->irq);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enable the alarm if it should be enabled (in case it was disabled to
|
||||||
|
* prevent use as a wake source).
|
||||||
|
*/
|
||||||
|
static int rk808_rtc_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
struct platform_device *pdev = to_platform_device(dev);
|
||||||
|
struct rk808_rtc *rk808_rtc = dev_get_drvdata(&pdev->dev);
|
||||||
|
|
||||||
|
if (device_may_wakeup(dev))
|
||||||
|
disable_irq_wake(rk808_rtc->irq);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static SIMPLE_DEV_PM_OPS(rk808_rtc_pm_ops,
|
||||||
|
rk808_rtc_suspend, rk808_rtc_resume);
|
||||||
|
|
||||||
|
static int rk808_rtc_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct rk808 *rk808 = dev_get_drvdata(pdev->dev.parent);
|
||||||
|
struct rk808_rtc *rk808_rtc;
|
||||||
|
struct rtc_time tm;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
rk808_rtc = devm_kzalloc(&pdev->dev, sizeof(*rk808_rtc), GFP_KERNEL);
|
||||||
|
if (rk808_rtc == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, rk808_rtc);
|
||||||
|
rk808_rtc->rk808 = rk808;
|
||||||
|
|
||||||
|
/* start rtc running by default, and use shadowed timer. */
|
||||||
|
ret = regmap_update_bits(rk808->regmap, RK808_RTC_CTRL_REG,
|
||||||
|
BIT_RTC_CTRL_REG_STOP_RTC_M |
|
||||||
|
BIT_RTC_CTRL_REG_RTC_READSEL_M,
|
||||||
|
BIT_RTC_CTRL_REG_RTC_READSEL_M);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&pdev->dev,
|
||||||
|
"Failed to update RTC control: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = regmap_write(rk808->regmap, RK808_RTC_STATUS_REG,
|
||||||
|
RTC_STATUS_MASK);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&pdev->dev,
|
||||||
|
"Failed to write RTC status: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set init time */
|
||||||
|
ret = rk808_rtc_readtime(&pdev->dev, &tm);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&pdev->dev, "Failed to read RTC time\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
ret = rtc_valid_tm(&tm);
|
||||||
|
if (ret)
|
||||||
|
dev_warn(&pdev->dev, "invalid date/time\n");
|
||||||
|
|
||||||
|
device_init_wakeup(&pdev->dev, 1);
|
||||||
|
|
||||||
|
rk808_rtc->rtc = devm_rtc_device_register(&pdev->dev, "rk808-rtc",
|
||||||
|
&rk808_rtc_ops, THIS_MODULE);
|
||||||
|
if (IS_ERR(rk808_rtc->rtc)) {
|
||||||
|
ret = PTR_ERR(rk808_rtc->rtc);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
rk808_rtc->irq = platform_get_irq(pdev, 0);
|
||||||
|
if (rk808_rtc->irq < 0) {
|
||||||
|
if (rk808_rtc->irq != -EPROBE_DEFER)
|
||||||
|
dev_err(&pdev->dev, "Wake up is not possible as irq = %d\n",
|
||||||
|
rk808_rtc->irq);
|
||||||
|
return rk808_rtc->irq;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* request alarm irq of rk808 */
|
||||||
|
ret = devm_request_threaded_irq(&pdev->dev, rk808_rtc->irq, NULL,
|
||||||
|
rk808_alarm_irq, 0,
|
||||||
|
"RTC alarm", rk808_rtc);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&pdev->dev, "Failed to request alarm IRQ %d: %d\n",
|
||||||
|
rk808_rtc->irq, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver rk808_rtc_driver = {
|
||||||
|
.probe = rk808_rtc_probe,
|
||||||
|
.driver = {
|
||||||
|
.name = "rk808-rtc",
|
||||||
|
.pm = &rk808_rtc_pm_ops,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module_platform_driver(rk808_rtc_driver);
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION("RTC driver for the rk808 series PMICs");
|
||||||
|
MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>");
|
||||||
|
MODULE_AUTHOR("Zhang Qing <zhangqing@rock-chips.com>");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_ALIAS("platform:rk808-rtc");
|
@ -142,12 +142,11 @@ static int rs5c_get_regs(struct rs5c372 *rs5c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
dev_dbg(&client->dev,
|
dev_dbg(&client->dev,
|
||||||
"%02x %02x %02x (%02x) %02x %02x %02x (%02x), "
|
"%3ph (%02x) %3ph (%02x), %3ph, %3ph; %02x %02x\n",
|
||||||
"%02x %02x %02x, %02x %02x %02x; %02x %02x\n",
|
rs5c->regs + 0, rs5c->regs[3],
|
||||||
rs5c->regs[0], rs5c->regs[1], rs5c->regs[2], rs5c->regs[3],
|
rs5c->regs + 4, rs5c->regs[7],
|
||||||
rs5c->regs[4], rs5c->regs[5], rs5c->regs[6], rs5c->regs[7],
|
rs5c->regs + 8, rs5c->regs + 11,
|
||||||
rs5c->regs[8], rs5c->regs[9], rs5c->regs[10], rs5c->regs[11],
|
rs5c->regs[14], rs5c->regs[15]);
|
||||||
rs5c->regs[12], rs5c->regs[13], rs5c->regs[14], rs5c->regs[15]);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -257,11 +257,11 @@ static ssize_t chp_status_write(struct device *dev,
|
|||||||
if (!num_args)
|
if (!num_args)
|
||||||
return count;
|
return count;
|
||||||
|
|
||||||
if (!strnicmp(cmd, "on", 2) || !strcmp(cmd, "1")) {
|
if (!strncasecmp(cmd, "on", 2) || !strcmp(cmd, "1")) {
|
||||||
mutex_lock(&cp->lock);
|
mutex_lock(&cp->lock);
|
||||||
error = s390_vary_chpid(cp->chpid, 1);
|
error = s390_vary_chpid(cp->chpid, 1);
|
||||||
mutex_unlock(&cp->lock);
|
mutex_unlock(&cp->lock);
|
||||||
} else if (!strnicmp(cmd, "off", 3) || !strcmp(cmd, "0")) {
|
} else if (!strncasecmp(cmd, "off", 3) || !strcmp(cmd, "0")) {
|
||||||
mutex_lock(&cp->lock);
|
mutex_lock(&cp->lock);
|
||||||
error = s390_vary_chpid(cp->chpid, 0);
|
error = s390_vary_chpid(cp->chpid, 0);
|
||||||
mutex_unlock(&cp->lock);
|
mutex_unlock(&cp->lock);
|
||||||
|
@ -528,7 +528,7 @@ ips_setup(char *ips_str)
|
|||||||
* Update the variables
|
* Update the variables
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < ARRAY_SIZE(options); i++) {
|
for (i = 0; i < ARRAY_SIZE(options); i++) {
|
||||||
if (strnicmp
|
if (strncasecmp
|
||||||
(key, options[i].option_name,
|
(key, options[i].option_name,
|
||||||
strlen(options[i].option_name)) == 0) {
|
strlen(options[i].option_name)) == 0) {
|
||||||
if (value)
|
if (value)
|
||||||
|
@ -3371,7 +3371,7 @@ static ssize_t opts_store(struct device_driver *ddp, const char *buf,
|
|||||||
char work[20];
|
char work[20];
|
||||||
|
|
||||||
if (1 == sscanf(buf, "%10s", work)) {
|
if (1 == sscanf(buf, "%10s", work)) {
|
||||||
if (0 == strnicmp(work,"0x", 2)) {
|
if (0 == strncasecmp(work,"0x", 2)) {
|
||||||
if (1 == sscanf(&work[2], "%x", &opts))
|
if (1 == sscanf(&work[2], "%x", &opts))
|
||||||
goto opts_done;
|
goto opts_done;
|
||||||
} else {
|
} else {
|
||||||
|
@ -79,7 +79,7 @@ int rtw_android_cmdstr_to_num(char *cmdstr)
|
|||||||
{
|
{
|
||||||
int cmd_num;
|
int cmd_num;
|
||||||
for (cmd_num = 0; cmd_num < ANDROID_WIFI_CMD_MAX; cmd_num++)
|
for (cmd_num = 0; cmd_num < ANDROID_WIFI_CMD_MAX; cmd_num++)
|
||||||
if (0 == strnicmp(cmdstr , android_wifi_cmd_str[cmd_num],
|
if (0 == strncasecmp(cmdstr , android_wifi_cmd_str[cmd_num],
|
||||||
strlen(android_wifi_cmd_str[cmd_num])))
|
strlen(android_wifi_cmd_str[cmd_num])))
|
||||||
break;
|
break;
|
||||||
return cmd_num;
|
return cmd_num;
|
||||||
|
@ -2957,25 +2957,13 @@ extern inline int rtllib_get_scans(struct rtllib_device *ieee)
|
|||||||
static inline const char *escape_essid(const char *essid, u8 essid_len)
|
static inline const char *escape_essid(const char *essid, u8 essid_len)
|
||||||
{
|
{
|
||||||
static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
|
static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
|
||||||
const char *s = essid;
|
|
||||||
char *d = escaped;
|
|
||||||
|
|
||||||
if (rtllib_is_empty_essid(essid, essid_len)) {
|
if (rtllib_is_empty_essid(essid, essid_len)) {
|
||||||
memcpy(escaped, "<hidden>", sizeof("<hidden>"));
|
memcpy(escaped, "<hidden>", sizeof("<hidden>"));
|
||||||
return escaped;
|
return escaped;
|
||||||
}
|
}
|
||||||
|
|
||||||
essid_len = min(essid_len, (u8)IW_ESSID_MAX_SIZE);
|
snprintf(escaped, sizeof(escaped), "%*pEn", essid_len, essid);
|
||||||
while (essid_len--) {
|
|
||||||
if (*s == '\0') {
|
|
||||||
*d++ = '\\';
|
|
||||||
*d++ = '0';
|
|
||||||
s++;
|
|
||||||
} else {
|
|
||||||
*d++ = *s++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*d = '\0';
|
|
||||||
return escaped;
|
return escaped;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2593,25 +2593,13 @@ static inline int ieee80211_get_scans(struct ieee80211_device *ieee)
|
|||||||
|
|
||||||
static inline const char *escape_essid(const char *essid, u8 essid_len) {
|
static inline const char *escape_essid(const char *essid, u8 essid_len) {
|
||||||
static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
|
static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
|
||||||
const char *s = essid;
|
|
||||||
char *d = escaped;
|
|
||||||
|
|
||||||
if (ieee80211_is_empty_essid(essid, essid_len)) {
|
if (ieee80211_is_empty_essid(essid, essid_len)) {
|
||||||
memcpy(escaped, "<hidden>", sizeof("<hidden>"));
|
memcpy(escaped, "<hidden>", sizeof("<hidden>"));
|
||||||
return escaped;
|
return escaped;
|
||||||
}
|
}
|
||||||
|
|
||||||
essid_len = min(essid_len, (u8)IW_ESSID_MAX_SIZE);
|
snprintf(escaped, sizeof(escaped), "%*pEn", essid_len, essid);
|
||||||
while (essid_len--) {
|
|
||||||
if (*s == '\0') {
|
|
||||||
*d++ = '\\';
|
|
||||||
*d++ = '0';
|
|
||||||
s++;
|
|
||||||
} else {
|
|
||||||
*d++ = *s++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*d = '\0';
|
|
||||||
return escaped;
|
return escaped;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +60,6 @@
|
|||||||
#include <linux/netdevice.h>
|
#include <linux/netdevice.h>
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
#include <linux/byteorder/generic.h>
|
#include <linux/byteorder/generic.h>
|
||||||
#include <linux/ctype.h>
|
|
||||||
|
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
@ -81,27 +80,6 @@
|
|||||||
#include "hfa384x.h"
|
#include "hfa384x.h"
|
||||||
#include "prism2mgmt.h"
|
#include "prism2mgmt.h"
|
||||||
|
|
||||||
/* Create a string of printable chars from something that might not be */
|
|
||||||
/* It's recommended that the str be 4*len + 1 bytes long */
|
|
||||||
#define wlan_mkprintstr(buf, buflen, str, strlen) \
|
|
||||||
{ \
|
|
||||||
int i = 0; \
|
|
||||||
int j = 0; \
|
|
||||||
memset(str, 0, (strlen)); \
|
|
||||||
for (i = 0; i < (buflen); i++) { \
|
|
||||||
if (isprint((buf)[i])) { \
|
|
||||||
(str)[j] = (buf)[i]; \
|
|
||||||
j++; \
|
|
||||||
} else { \
|
|
||||||
(str)[j] = '\\'; \
|
|
||||||
(str)[j+1] = 'x'; \
|
|
||||||
(str)[j+2] = hex_asc_hi((buf)[i]); \
|
|
||||||
(str)[j+3] = hex_asc_lo((buf)[i]); \
|
|
||||||
j += 4; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *dev_info = "prism2_usb";
|
static char *dev_info = "prism2_usb";
|
||||||
static wlandevice_t *create_wlan(void);
|
static wlandevice_t *create_wlan(void);
|
||||||
|
|
||||||
@ -607,7 +585,6 @@ static int prism2sta_getcardinfo(wlandevice_t *wlandev)
|
|||||||
hfa384x_t *hw = (hfa384x_t *) wlandev->priv;
|
hfa384x_t *hw = (hfa384x_t *) wlandev->priv;
|
||||||
u16 temp;
|
u16 temp;
|
||||||
u8 snum[HFA384x_RID_NICSERIALNUMBER_LEN];
|
u8 snum[HFA384x_RID_NICSERIALNUMBER_LEN];
|
||||||
char pstr[(HFA384x_RID_NICSERIALNUMBER_LEN * 4) + 1];
|
|
||||||
|
|
||||||
/* Collect version and compatibility info */
|
/* Collect version and compatibility info */
|
||||||
/* Some are critical, some are not */
|
/* Some are critical, some are not */
|
||||||
@ -862,9 +839,8 @@ static int prism2sta_getcardinfo(wlandevice_t *wlandev)
|
|||||||
result = hfa384x_drvr_getconfig(hw, HFA384x_RID_NICSERIALNUMBER,
|
result = hfa384x_drvr_getconfig(hw, HFA384x_RID_NICSERIALNUMBER,
|
||||||
snum, HFA384x_RID_NICSERIALNUMBER_LEN);
|
snum, HFA384x_RID_NICSERIALNUMBER_LEN);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
wlan_mkprintstr(snum, HFA384x_RID_NICSERIALNUMBER_LEN,
|
netdev_info(wlandev->netdev, "Prism2 card SN: %*pEhp\n",
|
||||||
pstr, sizeof(pstr));
|
HFA384x_RID_NICSERIALNUMBER_LEN, snum);
|
||||||
netdev_info(wlandev->netdev, "Prism2 card SN: %s\n", pstr);
|
|
||||||
} else {
|
} else {
|
||||||
netdev_err(wlandev->netdev, "Failed to retrieve Prism2 Card SN\n");
|
netdev_err(wlandev->netdev, "Failed to retrieve Prism2 Card SN\n");
|
||||||
goto failed;
|
goto failed;
|
||||||
|
@ -66,7 +66,7 @@ static struct thermal_governor *__find_governor(const char *name)
|
|||||||
return def_governor;
|
return def_governor;
|
||||||
|
|
||||||
list_for_each_entry(pos, &thermal_governor_list, governor_list)
|
list_for_each_entry(pos, &thermal_governor_list, governor_list)
|
||||||
if (!strnicmp(name, pos->name, THERMAL_NAME_LENGTH))
|
if (!strncasecmp(name, pos->name, THERMAL_NAME_LENGTH))
|
||||||
return pos;
|
return pos;
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -104,7 +104,7 @@ int thermal_register_governor(struct thermal_governor *governor)
|
|||||||
|
|
||||||
name = pos->tzp->governor_name;
|
name = pos->tzp->governor_name;
|
||||||
|
|
||||||
if (!strnicmp(name, governor->name, THERMAL_NAME_LENGTH))
|
if (!strncasecmp(name, governor->name, THERMAL_NAME_LENGTH))
|
||||||
pos->governor = governor;
|
pos->governor = governor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,7 +129,7 @@ void thermal_unregister_governor(struct thermal_governor *governor)
|
|||||||
mutex_lock(&thermal_list_lock);
|
mutex_lock(&thermal_list_lock);
|
||||||
|
|
||||||
list_for_each_entry(pos, &thermal_tz_list, node) {
|
list_for_each_entry(pos, &thermal_tz_list, node) {
|
||||||
if (!strnicmp(pos->governor->name, governor->name,
|
if (!strncasecmp(pos->governor->name, governor->name,
|
||||||
THERMAL_NAME_LENGTH))
|
THERMAL_NAME_LENGTH))
|
||||||
pos->governor = NULL;
|
pos->governor = NULL;
|
||||||
}
|
}
|
||||||
@ -1665,7 +1665,7 @@ struct thermal_zone_device *thermal_zone_get_zone_by_name(const char *name)
|
|||||||
|
|
||||||
mutex_lock(&thermal_list_lock);
|
mutex_lock(&thermal_list_lock);
|
||||||
list_for_each_entry(pos, &thermal_tz_list, node)
|
list_for_each_entry(pos, &thermal_tz_list, node)
|
||||||
if (!strnicmp(name, pos->type, THERMAL_NAME_LENGTH)) {
|
if (!strncasecmp(name, pos->type, THERMAL_NAME_LENGTH)) {
|
||||||
found++;
|
found++;
|
||||||
ref = pos;
|
ref = pos;
|
||||||
}
|
}
|
||||||
|
@ -1001,7 +1001,7 @@ static int pvr2_get_param(const struct pvr2_params *p, const char *s, int val,
|
|||||||
|
|
||||||
for (i = 0 ; i < size ; i++ ) {
|
for (i = 0 ; i < size ; i++ ) {
|
||||||
if (s != NULL) {
|
if (s != NULL) {
|
||||||
if (!strnicmp(p[i].name, s, strlen(s)))
|
if (!strncasecmp(p[i].name, s, strlen(s)))
|
||||||
return p[i].val;
|
return p[i].val;
|
||||||
} else {
|
} else {
|
||||||
if (p[i].val == val)
|
if (p[i].val == val)
|
||||||
|
@ -601,12 +601,12 @@ static int s3c2410fb_debug_store(struct device *dev,
|
|||||||
if (len < 1)
|
if (len < 1)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (strnicmp(buf, "on", 2) == 0 ||
|
if (strncasecmp(buf, "on", 2) == 0 ||
|
||||||
strnicmp(buf, "1", 1) == 0) {
|
strncasecmp(buf, "1", 1) == 0) {
|
||||||
debug = 1;
|
debug = 1;
|
||||||
dev_dbg(dev, "s3c2410fb: Debug On");
|
dev_dbg(dev, "s3c2410fb: Debug On");
|
||||||
} else if (strnicmp(buf, "off", 3) == 0 ||
|
} else if (strncasecmp(buf, "off", 3) == 0 ||
|
||||||
strnicmp(buf, "0", 1) == 0) {
|
strncasecmp(buf, "0", 1) == 0) {
|
||||||
debug = 0;
|
debug = 0;
|
||||||
dev_dbg(dev, "s3c2410fb: Debug Off");
|
dev_dbg(dev, "s3c2410fb: Debug Off");
|
||||||
} else {
|
} else {
|
||||||
|
@ -162,7 +162,7 @@ static void sisfb_search_mode(char *name, bool quiet)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
|
if(!strncasecmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
|
||||||
if(!quiet)
|
if(!quiet)
|
||||||
printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
|
printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
|
||||||
|
|
||||||
@ -201,7 +201,7 @@ static void sisfb_search_mode(char *name, bool quiet)
|
|||||||
|
|
||||||
i = 0; j = 0;
|
i = 0; j = 0;
|
||||||
while(sisbios_mode[i].mode_no[0] != 0) {
|
while(sisbios_mode[i].mode_no[0] != 0) {
|
||||||
if(!strnicmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
|
if(!strncasecmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
|
||||||
if(sisfb_fstn) {
|
if(sisfb_fstn) {
|
||||||
if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
|
if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
|
||||||
sisbios_mode[i-1].mode_no[1] == 0x56 ||
|
sisbios_mode[i-1].mode_no[1] == 0x56 ||
|
||||||
@ -262,7 +262,7 @@ sisfb_search_crt2type(const char *name)
|
|||||||
if(name == NULL) return;
|
if(name == NULL) return;
|
||||||
|
|
||||||
while(sis_crt2type[i].type_no != -1) {
|
while(sis_crt2type[i].type_no != -1) {
|
||||||
if(!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
|
if(!strncasecmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
|
||||||
sisfb_crt2type = sis_crt2type[i].type_no;
|
sisfb_crt2type = sis_crt2type[i].type_no;
|
||||||
sisfb_tvplug = sis_crt2type[i].tvplug_no;
|
sisfb_tvplug = sis_crt2type[i].tvplug_no;
|
||||||
sisfb_crt2flags = sis_crt2type[i].flags;
|
sisfb_crt2flags = sis_crt2type[i].flags;
|
||||||
@ -289,7 +289,7 @@ sisfb_search_tvstd(const char *name)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
while(sis_tvtype[i].type_no != -1) {
|
while(sis_tvtype[i].type_no != -1) {
|
||||||
if(!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
|
if(!strncasecmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
|
||||||
sisfb_tvstd = sis_tvtype[i].type_no;
|
sisfb_tvstd = sis_tvtype[i].type_no;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -308,12 +308,12 @@ sisfb_search_specialtiming(const char *name)
|
|||||||
if(name == NULL)
|
if(name == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(!strnicmp(name, "none", 4)) {
|
if(!strncasecmp(name, "none", 4)) {
|
||||||
sisfb_specialtiming = CUT_FORCENONE;
|
sisfb_specialtiming = CUT_FORCENONE;
|
||||||
printk(KERN_DEBUG "sisfb: Special timing disabled\n");
|
printk(KERN_DEBUG "sisfb: Special timing disabled\n");
|
||||||
} else {
|
} else {
|
||||||
while(mycustomttable[i].chipID != 0) {
|
while(mycustomttable[i].chipID != 0) {
|
||||||
if(!strnicmp(name,mycustomttable[i].optionName,
|
if(!strncasecmp(name,mycustomttable[i].optionName,
|
||||||
strlen(mycustomttable[i].optionName))) {
|
strlen(mycustomttable[i].optionName))) {
|
||||||
sisfb_specialtiming = mycustomttable[i].SpecialID;
|
sisfb_specialtiming = mycustomttable[i].SpecialID;
|
||||||
found = true;
|
found = true;
|
||||||
@ -3952,68 +3952,68 @@ static int __init sisfb_setup(char *options)
|
|||||||
|
|
||||||
if(!(*this_opt)) continue;
|
if(!(*this_opt)) continue;
|
||||||
|
|
||||||
if(!strnicmp(this_opt, "off", 3)) {
|
if(!strncasecmp(this_opt, "off", 3)) {
|
||||||
sisfb_off = 1;
|
sisfb_off = 1;
|
||||||
} else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
|
} else if(!strncasecmp(this_opt, "forcecrt2type:", 14)) {
|
||||||
/* Need to check crt2 type first for fstn/dstn */
|
/* Need to check crt2 type first for fstn/dstn */
|
||||||
sisfb_search_crt2type(this_opt + 14);
|
sisfb_search_crt2type(this_opt + 14);
|
||||||
} else if(!strnicmp(this_opt, "tvmode:",7)) {
|
} else if(!strncasecmp(this_opt, "tvmode:",7)) {
|
||||||
sisfb_search_tvstd(this_opt + 7);
|
sisfb_search_tvstd(this_opt + 7);
|
||||||
} else if(!strnicmp(this_opt, "tvstandard:",11)) {
|
} else if(!strncasecmp(this_opt, "tvstandard:",11)) {
|
||||||
sisfb_search_tvstd(this_opt + 11);
|
sisfb_search_tvstd(this_opt + 11);
|
||||||
} else if(!strnicmp(this_opt, "mode:", 5)) {
|
} else if(!strncasecmp(this_opt, "mode:", 5)) {
|
||||||
sisfb_search_mode(this_opt + 5, false);
|
sisfb_search_mode(this_opt + 5, false);
|
||||||
} else if(!strnicmp(this_opt, "vesa:", 5)) {
|
} else if(!strncasecmp(this_opt, "vesa:", 5)) {
|
||||||
sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), false);
|
sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), false);
|
||||||
} else if(!strnicmp(this_opt, "rate:", 5)) {
|
} else if(!strncasecmp(this_opt, "rate:", 5)) {
|
||||||
sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
|
sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
|
||||||
} else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
|
} else if(!strncasecmp(this_opt, "forcecrt1:", 10)) {
|
||||||
sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
|
sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
|
||||||
} else if(!strnicmp(this_opt, "mem:",4)) {
|
} else if(!strncasecmp(this_opt, "mem:",4)) {
|
||||||
sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
|
sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
|
||||||
} else if(!strnicmp(this_opt, "pdc:", 4)) {
|
} else if(!strncasecmp(this_opt, "pdc:", 4)) {
|
||||||
sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
|
sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
|
||||||
} else if(!strnicmp(this_opt, "pdc1:", 5)) {
|
} else if(!strncasecmp(this_opt, "pdc1:", 5)) {
|
||||||
sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
|
sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
|
||||||
} else if(!strnicmp(this_opt, "noaccel", 7)) {
|
} else if(!strncasecmp(this_opt, "noaccel", 7)) {
|
||||||
sisfb_accel = 0;
|
sisfb_accel = 0;
|
||||||
} else if(!strnicmp(this_opt, "accel", 5)) {
|
} else if(!strncasecmp(this_opt, "accel", 5)) {
|
||||||
sisfb_accel = -1;
|
sisfb_accel = -1;
|
||||||
} else if(!strnicmp(this_opt, "noypan", 6)) {
|
} else if(!strncasecmp(this_opt, "noypan", 6)) {
|
||||||
sisfb_ypan = 0;
|
sisfb_ypan = 0;
|
||||||
} else if(!strnicmp(this_opt, "ypan", 4)) {
|
} else if(!strncasecmp(this_opt, "ypan", 4)) {
|
||||||
sisfb_ypan = -1;
|
sisfb_ypan = -1;
|
||||||
} else if(!strnicmp(this_opt, "nomax", 5)) {
|
} else if(!strncasecmp(this_opt, "nomax", 5)) {
|
||||||
sisfb_max = 0;
|
sisfb_max = 0;
|
||||||
} else if(!strnicmp(this_opt, "max", 3)) {
|
} else if(!strncasecmp(this_opt, "max", 3)) {
|
||||||
sisfb_max = -1;
|
sisfb_max = -1;
|
||||||
} else if(!strnicmp(this_opt, "userom:", 7)) {
|
} else if(!strncasecmp(this_opt, "userom:", 7)) {
|
||||||
sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
|
sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
|
||||||
} else if(!strnicmp(this_opt, "useoem:", 7)) {
|
} else if(!strncasecmp(this_opt, "useoem:", 7)) {
|
||||||
sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
|
sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
|
||||||
} else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
|
} else if(!strncasecmp(this_opt, "nocrt2rate", 10)) {
|
||||||
sisfb_nocrt2rate = 1;
|
sisfb_nocrt2rate = 1;
|
||||||
} else if(!strnicmp(this_opt, "scalelcd:", 9)) {
|
} else if(!strncasecmp(this_opt, "scalelcd:", 9)) {
|
||||||
unsigned long temp = 2;
|
unsigned long temp = 2;
|
||||||
temp = simple_strtoul(this_opt + 9, NULL, 0);
|
temp = simple_strtoul(this_opt + 9, NULL, 0);
|
||||||
if((temp == 0) || (temp == 1)) {
|
if((temp == 0) || (temp == 1)) {
|
||||||
sisfb_scalelcd = temp ^ 1;
|
sisfb_scalelcd = temp ^ 1;
|
||||||
}
|
}
|
||||||
} else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
|
} else if(!strncasecmp(this_opt, "tvxposoffset:", 13)) {
|
||||||
int temp = 0;
|
int temp = 0;
|
||||||
temp = (int)simple_strtol(this_opt + 13, NULL, 0);
|
temp = (int)simple_strtol(this_opt + 13, NULL, 0);
|
||||||
if((temp >= -32) && (temp <= 32)) {
|
if((temp >= -32) && (temp <= 32)) {
|
||||||
sisfb_tvxposoffset = temp;
|
sisfb_tvxposoffset = temp;
|
||||||
}
|
}
|
||||||
} else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
|
} else if(!strncasecmp(this_opt, "tvyposoffset:", 13)) {
|
||||||
int temp = 0;
|
int temp = 0;
|
||||||
temp = (int)simple_strtol(this_opt + 13, NULL, 0);
|
temp = (int)simple_strtol(this_opt + 13, NULL, 0);
|
||||||
if((temp >= -32) && (temp <= 32)) {
|
if((temp >= -32) && (temp <= 32)) {
|
||||||
sisfb_tvyposoffset = temp;
|
sisfb_tvyposoffset = temp;
|
||||||
}
|
}
|
||||||
} else if(!strnicmp(this_opt, "specialtiming:", 14)) {
|
} else if(!strncasecmp(this_opt, "specialtiming:", 14)) {
|
||||||
sisfb_search_specialtiming(this_opt + 14);
|
sisfb_search_specialtiming(this_opt + 14);
|
||||||
} else if(!strnicmp(this_opt, "lvdshl:", 7)) {
|
} else if(!strncasecmp(this_opt, "lvdshl:", 7)) {
|
||||||
int temp = 4;
|
int temp = 4;
|
||||||
temp = simple_strtoul(this_opt + 7, NULL, 0);
|
temp = simple_strtoul(this_opt + 7, NULL, 0);
|
||||||
if((temp >= 0) && (temp <= 3)) {
|
if((temp >= 0) && (temp <= 3)) {
|
||||||
@ -4022,9 +4022,9 @@ static int __init sisfb_setup(char *options)
|
|||||||
} else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
|
} else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
|
||||||
sisfb_search_mode(this_opt, true);
|
sisfb_search_mode(this_opt, true);
|
||||||
#if !defined(__i386__) && !defined(__x86_64__)
|
#if !defined(__i386__) && !defined(__x86_64__)
|
||||||
} else if(!strnicmp(this_opt, "resetcard", 9)) {
|
} else if(!strncasecmp(this_opt, "resetcard", 9)) {
|
||||||
sisfb_resetcard = 1;
|
sisfb_resetcard = 1;
|
||||||
} else if(!strnicmp(this_opt, "videoram:", 9)) {
|
} else if(!strncasecmp(this_opt, "videoram:", 9)) {
|
||||||
sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
|
sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
|
@ -1187,9 +1187,9 @@ static ssize_t sm501fb_crtsrc_store(struct device *dev,
|
|||||||
if (len < 1)
|
if (len < 1)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (strnicmp(buf, "crt", 3) == 0)
|
if (strncasecmp(buf, "crt", 3) == 0)
|
||||||
head = HEAD_CRT;
|
head = HEAD_CRT;
|
||||||
else if (strnicmp(buf, "panel", 5) == 0)
|
else if (strncasecmp(buf, "panel", 5) == 0)
|
||||||
head = HEAD_PANEL;
|
head = HEAD_PANEL;
|
||||||
else
|
else
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -10,8 +10,6 @@
|
|||||||
|
|
||||||
#include "affs.h"
|
#include "affs.h"
|
||||||
|
|
||||||
extern struct timezone sys_tz;
|
|
||||||
|
|
||||||
static char ErrorBuffer[256];
|
static char ErrorBuffer[256];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -584,11 +584,14 @@ affs_extent_file_ofs(struct inode *inode, u32 newsize)
|
|||||||
bh->b_state &= ~(1UL << BH_New);
|
bh->b_state &= ~(1UL << BH_New);
|
||||||
mark_buffer_dirty_inode(bh, inode);
|
mark_buffer_dirty_inode(bh, inode);
|
||||||
if (prev_bh) {
|
if (prev_bh) {
|
||||||
u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
|
u32 tmp_next = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
|
||||||
if (tmp)
|
|
||||||
affs_warning(sb, "extent_file_ofs", "next block already set for %d (%d)", bidx, tmp);
|
if (tmp_next)
|
||||||
|
affs_warning(sb, "extent_file_ofs",
|
||||||
|
"next block already set for %d (%d)",
|
||||||
|
bidx, tmp_next);
|
||||||
AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);
|
AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);
|
||||||
affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp);
|
affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp_next);
|
||||||
mark_buffer_dirty_inode(prev_bh, inode);
|
mark_buffer_dirty_inode(prev_bh, inode);
|
||||||
affs_brelse(prev_bh);
|
affs_brelse(prev_bh);
|
||||||
}
|
}
|
||||||
@ -727,11 +730,14 @@ static int affs_write_end_ofs(struct file *file, struct address_space *mapping,
|
|||||||
AFFS_DATA_HEAD(bh)->next = 0;
|
AFFS_DATA_HEAD(bh)->next = 0;
|
||||||
bh->b_state &= ~(1UL << BH_New);
|
bh->b_state &= ~(1UL << BH_New);
|
||||||
if (prev_bh) {
|
if (prev_bh) {
|
||||||
u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
|
u32 tmp_next = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
|
||||||
if (tmp)
|
|
||||||
affs_warning(sb, "commit_write_ofs", "next block already set for %d (%d)", bidx, tmp);
|
if (tmp_next)
|
||||||
|
affs_warning(sb, "commit_write_ofs",
|
||||||
|
"next block already set for %d (%d)",
|
||||||
|
bidx, tmp_next);
|
||||||
AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);
|
AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);
|
||||||
affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp);
|
affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp_next);
|
||||||
mark_buffer_dirty_inode(prev_bh, inode);
|
mark_buffer_dirty_inode(prev_bh, inode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -758,11 +764,14 @@ static int affs_write_end_ofs(struct file *file, struct address_space *mapping,
|
|||||||
AFFS_DATA_HEAD(bh)->next = 0;
|
AFFS_DATA_HEAD(bh)->next = 0;
|
||||||
bh->b_state &= ~(1UL << BH_New);
|
bh->b_state &= ~(1UL << BH_New);
|
||||||
if (prev_bh) {
|
if (prev_bh) {
|
||||||
u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
|
u32 tmp_next = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
|
||||||
if (tmp)
|
|
||||||
affs_warning(sb, "commit_write_ofs", "next block already set for %d (%d)", bidx, tmp);
|
if (tmp_next)
|
||||||
|
affs_warning(sb, "commit_write_ofs",
|
||||||
|
"next block already set for %d (%d)",
|
||||||
|
bidx, tmp_next);
|
||||||
AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);
|
AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);
|
||||||
affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp);
|
affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp_next);
|
||||||
mark_buffer_dirty_inode(prev_bh, inode);
|
mark_buffer_dirty_inode(prev_bh, inode);
|
||||||
}
|
}
|
||||||
} else if (be32_to_cpu(AFFS_DATA_HEAD(bh)->size) < tmp)
|
} else if (be32_to_cpu(AFFS_DATA_HEAD(bh)->size) < tmp)
|
||||||
@ -842,12 +851,12 @@ affs_truncate(struct inode *inode)
|
|||||||
struct address_space *mapping = inode->i_mapping;
|
struct address_space *mapping = inode->i_mapping;
|
||||||
struct page *page;
|
struct page *page;
|
||||||
void *fsdata;
|
void *fsdata;
|
||||||
loff_t size = inode->i_size;
|
loff_t isize = inode->i_size;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
res = mapping->a_ops->write_begin(NULL, mapping, size, 0, 0, &page, &fsdata);
|
res = mapping->a_ops->write_begin(NULL, mapping, isize, 0, 0, &page, &fsdata);
|
||||||
if (!res)
|
if (!res)
|
||||||
res = mapping->a_ops->write_end(NULL, mapping, size, 0, 0, page, fsdata);
|
res = mapping->a_ops->write_end(NULL, mapping, isize, 0, 0, page, fsdata);
|
||||||
else
|
else
|
||||||
inode->i_size = AFFS_I(inode)->mmu_private;
|
inode->i_size = AFFS_I(inode)->mmu_private;
|
||||||
mark_inode_dirty(inode);
|
mark_inode_dirty(inode);
|
||||||
|
@ -14,13 +14,11 @@
|
|||||||
#include "affs.h"
|
#include "affs.h"
|
||||||
|
|
||||||
extern const struct inode_operations affs_symlink_inode_operations;
|
extern const struct inode_operations affs_symlink_inode_operations;
|
||||||
extern struct timezone sys_tz;
|
|
||||||
|
|
||||||
struct inode *affs_iget(struct super_block *sb, unsigned long ino)
|
struct inode *affs_iget(struct super_block *sb, unsigned long ino)
|
||||||
{
|
{
|
||||||
struct affs_sb_info *sbi = AFFS_SB(sb);
|
struct affs_sb_info *sbi = AFFS_SB(sb);
|
||||||
struct buffer_head *bh;
|
struct buffer_head *bh;
|
||||||
struct affs_head *head;
|
|
||||||
struct affs_tail *tail;
|
struct affs_tail *tail;
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
u32 block;
|
u32 block;
|
||||||
@ -49,7 +47,6 @@ struct inode *affs_iget(struct super_block *sb, unsigned long ino)
|
|||||||
goto bad_inode;
|
goto bad_inode;
|
||||||
}
|
}
|
||||||
|
|
||||||
head = AFFS_HEAD(bh);
|
|
||||||
tail = AFFS_TAIL(sb, bh);
|
tail = AFFS_TAIL(sb, bh);
|
||||||
prot = be32_to_cpu(tail->protect);
|
prot = be32_to_cpu(tail->protect);
|
||||||
|
|
||||||
|
@ -20,8 +20,6 @@
|
|||||||
#include <linux/writeback.h>
|
#include <linux/writeback.h>
|
||||||
#include "affs.h"
|
#include "affs.h"
|
||||||
|
|
||||||
extern struct timezone sys_tz;
|
|
||||||
|
|
||||||
static int affs_statfs(struct dentry *dentry, struct kstatfs *buf);
|
static int affs_statfs(struct dentry *dentry, struct kstatfs *buf);
|
||||||
static int affs_remount (struct super_block *sb, int *flags, char *data);
|
static int affs_remount (struct super_block *sb, int *flags, char *data);
|
||||||
|
|
||||||
@ -308,7 +306,6 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent)
|
|||||||
u32 chksum;
|
u32 chksum;
|
||||||
int num_bm;
|
int num_bm;
|
||||||
int i, j;
|
int i, j;
|
||||||
s32 key;
|
|
||||||
kuid_t uid;
|
kuid_t uid;
|
||||||
kgid_t gid;
|
kgid_t gid;
|
||||||
int reserved;
|
int reserved;
|
||||||
@ -367,7 +364,7 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent)
|
|||||||
i = j = blocksize;
|
i = j = blocksize;
|
||||||
size = size / (blocksize / 512);
|
size = size / (blocksize / 512);
|
||||||
}
|
}
|
||||||
for (blocksize = i, key = 0; blocksize <= j; blocksize <<= 1, size >>= 1) {
|
for (blocksize = i; blocksize <= j; blocksize <<= 1, size >>= 1) {
|
||||||
sbi->s_root_block = root_block;
|
sbi->s_root_block = root_block;
|
||||||
if (root_block < 0)
|
if (root_block < 0)
|
||||||
sbi->s_root_block = (reserved + size - 1) / 2;
|
sbi->s_root_block = (reserved + size - 1) / 2;
|
||||||
@ -399,7 +396,6 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent)
|
|||||||
be32_to_cpu(AFFS_ROOT_TAIL(sb, root_bh)->stype) == ST_ROOT) {
|
be32_to_cpu(AFFS_ROOT_TAIL(sb, root_bh)->stype) == ST_ROOT) {
|
||||||
sbi->s_hashsize = blocksize / 4 - 56;
|
sbi->s_hashsize = blocksize / 4 - 56;
|
||||||
sbi->s_root_block += num_bm;
|
sbi->s_root_block += num_bm;
|
||||||
key = 1;
|
|
||||||
goto got_root;
|
goto got_root;
|
||||||
}
|
}
|
||||||
affs_brelse(root_bh);
|
affs_brelse(root_bh);
|
||||||
|
@ -79,6 +79,10 @@ struct autofs_info {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#define AUTOFS_INF_EXPIRING (1<<0) /* dentry is in the process of expiring */
|
#define AUTOFS_INF_EXPIRING (1<<0) /* dentry is in the process of expiring */
|
||||||
|
#define AUTOFS_INF_NO_RCU (1<<1) /* the dentry is being considered
|
||||||
|
* for expiry, so RCU_walk is
|
||||||
|
* not permitted
|
||||||
|
*/
|
||||||
#define AUTOFS_INF_PENDING (1<<2) /* dentry pending mount */
|
#define AUTOFS_INF_PENDING (1<<2) /* dentry pending mount */
|
||||||
|
|
||||||
struct autofs_wait_queue {
|
struct autofs_wait_queue {
|
||||||
@ -148,7 +152,7 @@ void autofs4_free_ino(struct autofs_info *);
|
|||||||
|
|
||||||
/* Expiration */
|
/* Expiration */
|
||||||
int is_autofs4_dentry(struct dentry *);
|
int is_autofs4_dentry(struct dentry *);
|
||||||
int autofs4_expire_wait(struct dentry *dentry);
|
int autofs4_expire_wait(struct dentry *dentry, int rcu_walk);
|
||||||
int autofs4_expire_run(struct super_block *, struct vfsmount *,
|
int autofs4_expire_run(struct super_block *, struct vfsmount *,
|
||||||
struct autofs_sb_info *,
|
struct autofs_sb_info *,
|
||||||
struct autofs_packet_expire __user *);
|
struct autofs_packet_expire __user *);
|
||||||
|
@ -450,7 +450,7 @@ static int autofs_dev_ioctl_requester(struct file *fp,
|
|||||||
ino = autofs4_dentry_ino(path.dentry);
|
ino = autofs4_dentry_ino(path.dentry);
|
||||||
if (ino) {
|
if (ino) {
|
||||||
err = 0;
|
err = 0;
|
||||||
autofs4_expire_wait(path.dentry);
|
autofs4_expire_wait(path.dentry, 0);
|
||||||
spin_lock(&sbi->fs_lock);
|
spin_lock(&sbi->fs_lock);
|
||||||
param->requester.uid = from_kuid_munged(current_user_ns(), ino->uid);
|
param->requester.uid = from_kuid_munged(current_user_ns(), ino->uid);
|
||||||
param->requester.gid = from_kgid_munged(current_user_ns(), ino->gid);
|
param->requester.gid = from_kgid_munged(current_user_ns(), ino->gid);
|
||||||
|
@ -30,12 +30,6 @@ static inline int autofs4_can_expire(struct dentry *dentry,
|
|||||||
/* Too young to die */
|
/* Too young to die */
|
||||||
if (!timeout || time_after(ino->last_used + timeout, now))
|
if (!timeout || time_after(ino->last_used + timeout, now))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* update last_used here :-
|
|
||||||
- obviously makes sense if it is in use now
|
|
||||||
- less obviously, prevents rapid-fire expire
|
|
||||||
attempts if expire fails the first time */
|
|
||||||
ino->last_used = now;
|
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -327,10 +321,19 @@ struct dentry *autofs4_expire_direct(struct super_block *sb,
|
|||||||
if (ino->flags & AUTOFS_INF_PENDING)
|
if (ino->flags & AUTOFS_INF_PENDING)
|
||||||
goto out;
|
goto out;
|
||||||
if (!autofs4_direct_busy(mnt, root, timeout, do_now)) {
|
if (!autofs4_direct_busy(mnt, root, timeout, do_now)) {
|
||||||
ino->flags |= AUTOFS_INF_EXPIRING;
|
ino->flags |= AUTOFS_INF_NO_RCU;
|
||||||
init_completion(&ino->expire_complete);
|
|
||||||
spin_unlock(&sbi->fs_lock);
|
spin_unlock(&sbi->fs_lock);
|
||||||
return root;
|
synchronize_rcu();
|
||||||
|
spin_lock(&sbi->fs_lock);
|
||||||
|
if (!autofs4_direct_busy(mnt, root, timeout, do_now)) {
|
||||||
|
ino->flags |= AUTOFS_INF_EXPIRING;
|
||||||
|
smp_mb();
|
||||||
|
ino->flags &= ~AUTOFS_INF_NO_RCU;
|
||||||
|
init_completion(&ino->expire_complete);
|
||||||
|
spin_unlock(&sbi->fs_lock);
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
ino->flags &= ~AUTOFS_INF_NO_RCU;
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
spin_unlock(&sbi->fs_lock);
|
spin_unlock(&sbi->fs_lock);
|
||||||
@ -339,6 +342,89 @@ out:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check if 'dentry' should expire, or return a nearby
|
||||||
|
* dentry that is suitable.
|
||||||
|
* If returned dentry is different from arg dentry,
|
||||||
|
* then a dget() reference was taken, else not.
|
||||||
|
*/
|
||||||
|
static struct dentry *should_expire(struct dentry *dentry,
|
||||||
|
struct vfsmount *mnt,
|
||||||
|
unsigned long timeout,
|
||||||
|
int how)
|
||||||
|
{
|
||||||
|
int do_now = how & AUTOFS_EXP_IMMEDIATE;
|
||||||
|
int exp_leaves = how & AUTOFS_EXP_LEAVES;
|
||||||
|
struct autofs_info *ino = autofs4_dentry_ino(dentry);
|
||||||
|
unsigned int ino_count;
|
||||||
|
|
||||||
|
/* No point expiring a pending mount */
|
||||||
|
if (ino->flags & AUTOFS_INF_PENDING)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Case 1: (i) indirect mount or top level pseudo direct mount
|
||||||
|
* (autofs-4.1).
|
||||||
|
* (ii) indirect mount with offset mount, check the "/"
|
||||||
|
* offset (autofs-5.0+).
|
||||||
|
*/
|
||||||
|
if (d_mountpoint(dentry)) {
|
||||||
|
DPRINTK("checking mountpoint %p %.*s",
|
||||||
|
dentry, (int)dentry->d_name.len, dentry->d_name.name);
|
||||||
|
|
||||||
|
/* Can we umount this guy */
|
||||||
|
if (autofs4_mount_busy(mnt, dentry))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Can we expire this guy */
|
||||||
|
if (autofs4_can_expire(dentry, timeout, do_now))
|
||||||
|
return dentry;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dentry->d_inode && S_ISLNK(dentry->d_inode->i_mode)) {
|
||||||
|
DPRINTK("checking symlink %p %.*s",
|
||||||
|
dentry, (int)dentry->d_name.len, dentry->d_name.name);
|
||||||
|
/*
|
||||||
|
* A symlink can't be "busy" in the usual sense so
|
||||||
|
* just check last used for expire timeout.
|
||||||
|
*/
|
||||||
|
if (autofs4_can_expire(dentry, timeout, do_now))
|
||||||
|
return dentry;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (simple_empty(dentry))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Case 2: tree mount, expire iff entire tree is not busy */
|
||||||
|
if (!exp_leaves) {
|
||||||
|
/* Path walk currently on this dentry? */
|
||||||
|
ino_count = atomic_read(&ino->count) + 1;
|
||||||
|
if (d_count(dentry) > ino_count)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!autofs4_tree_busy(mnt, dentry, timeout, do_now))
|
||||||
|
return dentry;
|
||||||
|
/*
|
||||||
|
* Case 3: pseudo direct mount, expire individual leaves
|
||||||
|
* (autofs-4.1).
|
||||||
|
*/
|
||||||
|
} else {
|
||||||
|
/* Path walk currently on this dentry? */
|
||||||
|
struct dentry *expired;
|
||||||
|
ino_count = atomic_read(&ino->count) + 1;
|
||||||
|
if (d_count(dentry) > ino_count)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
expired = autofs4_check_leaves(mnt, dentry, timeout, do_now);
|
||||||
|
if (expired) {
|
||||||
|
if (expired == dentry)
|
||||||
|
dput(dentry);
|
||||||
|
return expired;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* Find an eligible tree to time-out
|
* Find an eligible tree to time-out
|
||||||
* A tree is eligible if :-
|
* A tree is eligible if :-
|
||||||
@ -353,11 +439,8 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb,
|
|||||||
unsigned long timeout;
|
unsigned long timeout;
|
||||||
struct dentry *root = sb->s_root;
|
struct dentry *root = sb->s_root;
|
||||||
struct dentry *dentry;
|
struct dentry *dentry;
|
||||||
struct dentry *expired = NULL;
|
struct dentry *expired;
|
||||||
int do_now = how & AUTOFS_EXP_IMMEDIATE;
|
|
||||||
int exp_leaves = how & AUTOFS_EXP_LEAVES;
|
|
||||||
struct autofs_info *ino;
|
struct autofs_info *ino;
|
||||||
unsigned int ino_count;
|
|
||||||
|
|
||||||
if (!root)
|
if (!root)
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -369,77 +452,28 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb,
|
|||||||
while ((dentry = get_next_positive_subdir(dentry, root))) {
|
while ((dentry = get_next_positive_subdir(dentry, root))) {
|
||||||
spin_lock(&sbi->fs_lock);
|
spin_lock(&sbi->fs_lock);
|
||||||
ino = autofs4_dentry_ino(dentry);
|
ino = autofs4_dentry_ino(dentry);
|
||||||
/* No point expiring a pending mount */
|
if (ino->flags & AUTOFS_INF_NO_RCU)
|
||||||
if (ino->flags & AUTOFS_INF_PENDING)
|
expired = NULL;
|
||||||
goto next;
|
else
|
||||||
|
expired = should_expire(dentry, mnt, timeout, how);
|
||||||
/*
|
if (!expired) {
|
||||||
* Case 1: (i) indirect mount or top level pseudo direct mount
|
spin_unlock(&sbi->fs_lock);
|
||||||
* (autofs-4.1).
|
continue;
|
||||||
* (ii) indirect mount with offset mount, check the "/"
|
|
||||||
* offset (autofs-5.0+).
|
|
||||||
*/
|
|
||||||
if (d_mountpoint(dentry)) {
|
|
||||||
DPRINTK("checking mountpoint %p %.*s",
|
|
||||||
dentry, (int)dentry->d_name.len, dentry->d_name.name);
|
|
||||||
|
|
||||||
/* Can we umount this guy */
|
|
||||||
if (autofs4_mount_busy(mnt, dentry))
|
|
||||||
goto next;
|
|
||||||
|
|
||||||
/* Can we expire this guy */
|
|
||||||
if (autofs4_can_expire(dentry, timeout, do_now)) {
|
|
||||||
expired = dentry;
|
|
||||||
goto found;
|
|
||||||
}
|
|
||||||
goto next;
|
|
||||||
}
|
}
|
||||||
|
ino = autofs4_dentry_ino(expired);
|
||||||
if (dentry->d_inode && S_ISLNK(dentry->d_inode->i_mode)) {
|
ino->flags |= AUTOFS_INF_NO_RCU;
|
||||||
DPRINTK("checking symlink %p %.*s",
|
spin_unlock(&sbi->fs_lock);
|
||||||
dentry, (int)dentry->d_name.len, dentry->d_name.name);
|
synchronize_rcu();
|
||||||
/*
|
spin_lock(&sbi->fs_lock);
|
||||||
* A symlink can't be "busy" in the usual sense so
|
if (should_expire(expired, mnt, timeout, how)) {
|
||||||
* just check last used for expire timeout.
|
if (expired != dentry)
|
||||||
*/
|
|
||||||
if (autofs4_can_expire(dentry, timeout, do_now)) {
|
|
||||||
expired = dentry;
|
|
||||||
goto found;
|
|
||||||
}
|
|
||||||
goto next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (simple_empty(dentry))
|
|
||||||
goto next;
|
|
||||||
|
|
||||||
/* Case 2: tree mount, expire iff entire tree is not busy */
|
|
||||||
if (!exp_leaves) {
|
|
||||||
/* Path walk currently on this dentry? */
|
|
||||||
ino_count = atomic_read(&ino->count) + 1;
|
|
||||||
if (d_count(dentry) > ino_count)
|
|
||||||
goto next;
|
|
||||||
|
|
||||||
if (!autofs4_tree_busy(mnt, dentry, timeout, do_now)) {
|
|
||||||
expired = dentry;
|
|
||||||
goto found;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Case 3: pseudo direct mount, expire individual leaves
|
|
||||||
* (autofs-4.1).
|
|
||||||
*/
|
|
||||||
} else {
|
|
||||||
/* Path walk currently on this dentry? */
|
|
||||||
ino_count = atomic_read(&ino->count) + 1;
|
|
||||||
if (d_count(dentry) > ino_count)
|
|
||||||
goto next;
|
|
||||||
|
|
||||||
expired = autofs4_check_leaves(mnt, dentry, timeout, do_now);
|
|
||||||
if (expired) {
|
|
||||||
dput(dentry);
|
dput(dentry);
|
||||||
goto found;
|
goto found;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
next:
|
|
||||||
|
ino->flags &= ~AUTOFS_INF_NO_RCU;
|
||||||
|
if (expired != dentry)
|
||||||
|
dput(expired);
|
||||||
spin_unlock(&sbi->fs_lock);
|
spin_unlock(&sbi->fs_lock);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -447,8 +481,9 @@ next:
|
|||||||
found:
|
found:
|
||||||
DPRINTK("returning %p %.*s",
|
DPRINTK("returning %p %.*s",
|
||||||
expired, (int)expired->d_name.len, expired->d_name.name);
|
expired, (int)expired->d_name.len, expired->d_name.name);
|
||||||
ino = autofs4_dentry_ino(expired);
|
|
||||||
ino->flags |= AUTOFS_INF_EXPIRING;
|
ino->flags |= AUTOFS_INF_EXPIRING;
|
||||||
|
smp_mb();
|
||||||
|
ino->flags &= ~AUTOFS_INF_NO_RCU;
|
||||||
init_completion(&ino->expire_complete);
|
init_completion(&ino->expire_complete);
|
||||||
spin_unlock(&sbi->fs_lock);
|
spin_unlock(&sbi->fs_lock);
|
||||||
spin_lock(&sbi->lookup_lock);
|
spin_lock(&sbi->lookup_lock);
|
||||||
@ -461,13 +496,18 @@ found:
|
|||||||
return expired;
|
return expired;
|
||||||
}
|
}
|
||||||
|
|
||||||
int autofs4_expire_wait(struct dentry *dentry)
|
int autofs4_expire_wait(struct dentry *dentry, int rcu_walk)
|
||||||
{
|
{
|
||||||
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
|
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
|
||||||
struct autofs_info *ino = autofs4_dentry_ino(dentry);
|
struct autofs_info *ino = autofs4_dentry_ino(dentry);
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
/* Block on any pending expire */
|
/* Block on any pending expire */
|
||||||
|
if (!(ino->flags & (AUTOFS_INF_EXPIRING | AUTOFS_INF_NO_RCU)))
|
||||||
|
return 0;
|
||||||
|
if (rcu_walk)
|
||||||
|
return -ECHILD;
|
||||||
|
|
||||||
spin_lock(&sbi->fs_lock);
|
spin_lock(&sbi->fs_lock);
|
||||||
if (ino->flags & AUTOFS_INF_EXPIRING) {
|
if (ino->flags & AUTOFS_INF_EXPIRING) {
|
||||||
spin_unlock(&sbi->fs_lock);
|
spin_unlock(&sbi->fs_lock);
|
||||||
@ -519,6 +559,8 @@ int autofs4_expire_run(struct super_block *sb,
|
|||||||
|
|
||||||
spin_lock(&sbi->fs_lock);
|
spin_lock(&sbi->fs_lock);
|
||||||
ino = autofs4_dentry_ino(dentry);
|
ino = autofs4_dentry_ino(dentry);
|
||||||
|
/* avoid rapid-fire expire attempts if expiry fails */
|
||||||
|
ino->last_used = now;
|
||||||
ino->flags &= ~AUTOFS_INF_EXPIRING;
|
ino->flags &= ~AUTOFS_INF_EXPIRING;
|
||||||
complete_all(&ino->expire_complete);
|
complete_all(&ino->expire_complete);
|
||||||
spin_unlock(&sbi->fs_lock);
|
spin_unlock(&sbi->fs_lock);
|
||||||
@ -545,6 +587,8 @@ int autofs4_do_expire_multi(struct super_block *sb, struct vfsmount *mnt,
|
|||||||
ret = autofs4_wait(sbi, dentry, NFY_EXPIRE);
|
ret = autofs4_wait(sbi, dentry, NFY_EXPIRE);
|
||||||
|
|
||||||
spin_lock(&sbi->fs_lock);
|
spin_lock(&sbi->fs_lock);
|
||||||
|
/* avoid rapid-fire expire attempts if expiry fails */
|
||||||
|
ino->last_used = now;
|
||||||
ino->flags &= ~AUTOFS_INF_EXPIRING;
|
ino->flags &= ~AUTOFS_INF_EXPIRING;
|
||||||
complete_all(&ino->expire_complete);
|
complete_all(&ino->expire_complete);
|
||||||
spin_unlock(&sbi->fs_lock);
|
spin_unlock(&sbi->fs_lock);
|
||||||
|
@ -210,7 +210,8 @@ next:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct dentry *autofs4_lookup_expiring(struct dentry *dentry)
|
static struct dentry *autofs4_lookup_expiring(struct dentry *dentry,
|
||||||
|
bool rcu_walk)
|
||||||
{
|
{
|
||||||
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
|
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
|
||||||
struct dentry *parent = dentry->d_parent;
|
struct dentry *parent = dentry->d_parent;
|
||||||
@ -229,6 +230,11 @@ static struct dentry *autofs4_lookup_expiring(struct dentry *dentry)
|
|||||||
struct dentry *expiring;
|
struct dentry *expiring;
|
||||||
struct qstr *qstr;
|
struct qstr *qstr;
|
||||||
|
|
||||||
|
if (rcu_walk) {
|
||||||
|
spin_unlock(&sbi->lookup_lock);
|
||||||
|
return ERR_PTR(-ECHILD);
|
||||||
|
}
|
||||||
|
|
||||||
ino = list_entry(p, struct autofs_info, expiring);
|
ino = list_entry(p, struct autofs_info, expiring);
|
||||||
expiring = ino->dentry;
|
expiring = ino->dentry;
|
||||||
|
|
||||||
@ -264,13 +270,15 @@ next:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int autofs4_mount_wait(struct dentry *dentry)
|
static int autofs4_mount_wait(struct dentry *dentry, bool rcu_walk)
|
||||||
{
|
{
|
||||||
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
|
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
|
||||||
struct autofs_info *ino = autofs4_dentry_ino(dentry);
|
struct autofs_info *ino = autofs4_dentry_ino(dentry);
|
||||||
int status = 0;
|
int status = 0;
|
||||||
|
|
||||||
if (ino->flags & AUTOFS_INF_PENDING) {
|
if (ino->flags & AUTOFS_INF_PENDING) {
|
||||||
|
if (rcu_walk)
|
||||||
|
return -ECHILD;
|
||||||
DPRINTK("waiting for mount name=%.*s",
|
DPRINTK("waiting for mount name=%.*s",
|
||||||
dentry->d_name.len, dentry->d_name.name);
|
dentry->d_name.len, dentry->d_name.name);
|
||||||
status = autofs4_wait(sbi, dentry, NFY_MOUNT);
|
status = autofs4_wait(sbi, dentry, NFY_MOUNT);
|
||||||
@ -280,20 +288,22 @@ static int autofs4_mount_wait(struct dentry *dentry)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_expire_wait(struct dentry *dentry)
|
static int do_expire_wait(struct dentry *dentry, bool rcu_walk)
|
||||||
{
|
{
|
||||||
struct dentry *expiring;
|
struct dentry *expiring;
|
||||||
|
|
||||||
expiring = autofs4_lookup_expiring(dentry);
|
expiring = autofs4_lookup_expiring(dentry, rcu_walk);
|
||||||
|
if (IS_ERR(expiring))
|
||||||
|
return PTR_ERR(expiring);
|
||||||
if (!expiring)
|
if (!expiring)
|
||||||
return autofs4_expire_wait(dentry);
|
return autofs4_expire_wait(dentry, rcu_walk);
|
||||||
else {
|
else {
|
||||||
/*
|
/*
|
||||||
* If we are racing with expire the request might not
|
* If we are racing with expire the request might not
|
||||||
* be quite complete, but the directory has been removed
|
* be quite complete, but the directory has been removed
|
||||||
* so it must have been successful, just wait for it.
|
* so it must have been successful, just wait for it.
|
||||||
*/
|
*/
|
||||||
autofs4_expire_wait(expiring);
|
autofs4_expire_wait(expiring, 0);
|
||||||
autofs4_del_expiring(expiring);
|
autofs4_del_expiring(expiring);
|
||||||
dput(expiring);
|
dput(expiring);
|
||||||
}
|
}
|
||||||
@ -345,7 +355,7 @@ static struct vfsmount *autofs4_d_automount(struct path *path)
|
|||||||
* and the directory was removed, so just go ahead and try
|
* and the directory was removed, so just go ahead and try
|
||||||
* the mount.
|
* the mount.
|
||||||
*/
|
*/
|
||||||
status = do_expire_wait(dentry);
|
status = do_expire_wait(dentry, 0);
|
||||||
if (status && status != -EAGAIN)
|
if (status && status != -EAGAIN)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@ -353,7 +363,7 @@ static struct vfsmount *autofs4_d_automount(struct path *path)
|
|||||||
spin_lock(&sbi->fs_lock);
|
spin_lock(&sbi->fs_lock);
|
||||||
if (ino->flags & AUTOFS_INF_PENDING) {
|
if (ino->flags & AUTOFS_INF_PENDING) {
|
||||||
spin_unlock(&sbi->fs_lock);
|
spin_unlock(&sbi->fs_lock);
|
||||||
status = autofs4_mount_wait(dentry);
|
status = autofs4_mount_wait(dentry, 0);
|
||||||
if (status)
|
if (status)
|
||||||
return ERR_PTR(status);
|
return ERR_PTR(status);
|
||||||
goto done;
|
goto done;
|
||||||
@ -394,7 +404,7 @@ static struct vfsmount *autofs4_d_automount(struct path *path)
|
|||||||
}
|
}
|
||||||
ino->flags |= AUTOFS_INF_PENDING;
|
ino->flags |= AUTOFS_INF_PENDING;
|
||||||
spin_unlock(&sbi->fs_lock);
|
spin_unlock(&sbi->fs_lock);
|
||||||
status = autofs4_mount_wait(dentry);
|
status = autofs4_mount_wait(dentry, 0);
|
||||||
spin_lock(&sbi->fs_lock);
|
spin_lock(&sbi->fs_lock);
|
||||||
ino->flags &= ~AUTOFS_INF_PENDING;
|
ino->flags &= ~AUTOFS_INF_PENDING;
|
||||||
if (status) {
|
if (status) {
|
||||||
@ -423,28 +433,46 @@ static int autofs4_d_manage(struct dentry *dentry, bool rcu_walk)
|
|||||||
|
|
||||||
/* The daemon never waits. */
|
/* The daemon never waits. */
|
||||||
if (autofs4_oz_mode(sbi)) {
|
if (autofs4_oz_mode(sbi)) {
|
||||||
if (rcu_walk)
|
|
||||||
return 0;
|
|
||||||
if (!d_mountpoint(dentry))
|
if (!d_mountpoint(dentry))
|
||||||
return -EISDIR;
|
return -EISDIR;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We need to sleep, so we need pathwalk to be in ref-mode */
|
|
||||||
if (rcu_walk)
|
|
||||||
return -ECHILD;
|
|
||||||
|
|
||||||
/* Wait for pending expires */
|
/* Wait for pending expires */
|
||||||
do_expire_wait(dentry);
|
if (do_expire_wait(dentry, rcu_walk) == -ECHILD)
|
||||||
|
return -ECHILD;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This dentry may be under construction so wait on mount
|
* This dentry may be under construction so wait on mount
|
||||||
* completion.
|
* completion.
|
||||||
*/
|
*/
|
||||||
status = autofs4_mount_wait(dentry);
|
status = autofs4_mount_wait(dentry, rcu_walk);
|
||||||
if (status)
|
if (status)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
|
if (rcu_walk) {
|
||||||
|
/* We don't need fs_lock in rcu_walk mode,
|
||||||
|
* just testing 'AUTOFS_INFO_NO_RCU' is enough.
|
||||||
|
* simple_empty() takes a spinlock, so leave it
|
||||||
|
* to last.
|
||||||
|
* We only return -EISDIR when certain this isn't
|
||||||
|
* a mount-trap.
|
||||||
|
*/
|
||||||
|
struct inode *inode;
|
||||||
|
if (ino->flags & (AUTOFS_INF_EXPIRING | AUTOFS_INF_NO_RCU))
|
||||||
|
return 0;
|
||||||
|
if (d_mountpoint(dentry))
|
||||||
|
return 0;
|
||||||
|
inode = ACCESS_ONCE(dentry->d_inode);
|
||||||
|
if (inode && S_ISLNK(inode->i_mode))
|
||||||
|
return -EISDIR;
|
||||||
|
if (list_empty(&dentry->d_subdirs))
|
||||||
|
return 0;
|
||||||
|
if (!simple_empty(dentry))
|
||||||
|
return -EISDIR;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
spin_lock(&sbi->fs_lock);
|
spin_lock(&sbi->fs_lock);
|
||||||
/*
|
/*
|
||||||
* If the dentry has been selected for expire while we slept
|
* If the dentry has been selected for expire while we slept
|
||||||
|
@ -78,11 +78,11 @@
|
|||||||
/*
|
/*
|
||||||
* In memory structure of each btree node
|
* In memory structure of each btree node
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
struct befs_btree_node {
|
||||||
befs_host_btree_nodehead head; /* head of node converted to cpu byteorder */
|
befs_host_btree_nodehead head; /* head of node converted to cpu byteorder */
|
||||||
struct buffer_head *bh;
|
struct buffer_head *bh;
|
||||||
befs_btree_nodehead *od_node; /* on disk node */
|
befs_btree_nodehead *od_node; /* on disk node */
|
||||||
} befs_btree_node;
|
};
|
||||||
|
|
||||||
/* local constants */
|
/* local constants */
|
||||||
static const befs_off_t befs_bt_inval = 0xffffffffffffffffULL;
|
static const befs_off_t befs_bt_inval = 0xffffffffffffffffULL;
|
||||||
@ -90,27 +90,30 @@ static const befs_off_t befs_bt_inval = 0xffffffffffffffffULL;
|
|||||||
/* local functions */
|
/* local functions */
|
||||||
static int befs_btree_seekleaf(struct super_block *sb, befs_data_stream * ds,
|
static int befs_btree_seekleaf(struct super_block *sb, befs_data_stream * ds,
|
||||||
befs_btree_super * bt_super,
|
befs_btree_super * bt_super,
|
||||||
befs_btree_node * this_node,
|
struct befs_btree_node *this_node,
|
||||||
befs_off_t * node_off);
|
befs_off_t * node_off);
|
||||||
|
|
||||||
static int befs_bt_read_super(struct super_block *sb, befs_data_stream * ds,
|
static int befs_bt_read_super(struct super_block *sb, befs_data_stream * ds,
|
||||||
befs_btree_super * sup);
|
befs_btree_super * sup);
|
||||||
|
|
||||||
static int befs_bt_read_node(struct super_block *sb, befs_data_stream * ds,
|
static int befs_bt_read_node(struct super_block *sb, befs_data_stream * ds,
|
||||||
befs_btree_node * node, befs_off_t node_off);
|
struct befs_btree_node *node,
|
||||||
|
befs_off_t node_off);
|
||||||
|
|
||||||
static int befs_leafnode(befs_btree_node * node);
|
static int befs_leafnode(struct befs_btree_node *node);
|
||||||
|
|
||||||
static fs16 *befs_bt_keylen_index(befs_btree_node * node);
|
static fs16 *befs_bt_keylen_index(struct befs_btree_node *node);
|
||||||
|
|
||||||
static fs64 *befs_bt_valarray(befs_btree_node * node);
|
static fs64 *befs_bt_valarray(struct befs_btree_node *node);
|
||||||
|
|
||||||
static char *befs_bt_keydata(befs_btree_node * node);
|
static char *befs_bt_keydata(struct befs_btree_node *node);
|
||||||
|
|
||||||
static int befs_find_key(struct super_block *sb, befs_btree_node * node,
|
static int befs_find_key(struct super_block *sb,
|
||||||
|
struct befs_btree_node *node,
|
||||||
const char *findkey, befs_off_t * value);
|
const char *findkey, befs_off_t * value);
|
||||||
|
|
||||||
static char *befs_bt_get_key(struct super_block *sb, befs_btree_node * node,
|
static char *befs_bt_get_key(struct super_block *sb,
|
||||||
|
struct befs_btree_node *node,
|
||||||
int index, u16 * keylen);
|
int index, u16 * keylen);
|
||||||
|
|
||||||
static int befs_compare_strings(const void *key1, int keylen1,
|
static int befs_compare_strings(const void *key1, int keylen1,
|
||||||
@ -191,7 +194,7 @@ befs_bt_read_super(struct super_block *sb, befs_data_stream * ds,
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
befs_bt_read_node(struct super_block *sb, befs_data_stream * ds,
|
befs_bt_read_node(struct super_block *sb, befs_data_stream * ds,
|
||||||
befs_btree_node * node, befs_off_t node_off)
|
struct befs_btree_node *node, befs_off_t node_off)
|
||||||
{
|
{
|
||||||
uint off = 0;
|
uint off = 0;
|
||||||
|
|
||||||
@ -247,7 +250,7 @@ int
|
|||||||
befs_btree_find(struct super_block *sb, befs_data_stream * ds,
|
befs_btree_find(struct super_block *sb, befs_data_stream * ds,
|
||||||
const char *key, befs_off_t * value)
|
const char *key, befs_off_t * value)
|
||||||
{
|
{
|
||||||
befs_btree_node *this_node = NULL;
|
struct befs_btree_node *this_node = NULL;
|
||||||
befs_btree_super bt_super;
|
befs_btree_super bt_super;
|
||||||
befs_off_t node_off;
|
befs_off_t node_off;
|
||||||
int res;
|
int res;
|
||||||
@ -260,11 +263,11 @@ befs_btree_find(struct super_block *sb, befs_data_stream * ds,
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
this_node = kmalloc(sizeof (befs_btree_node),
|
this_node = kmalloc(sizeof(struct befs_btree_node),
|
||||||
GFP_NOFS);
|
GFP_NOFS);
|
||||||
if (!this_node) {
|
if (!this_node) {
|
||||||
befs_error(sb, "befs_btree_find() failed to allocate %zu "
|
befs_error(sb, "befs_btree_find() failed to allocate %zu "
|
||||||
"bytes of memory", sizeof (befs_btree_node));
|
"bytes of memory", sizeof(struct befs_btree_node));
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,7 +336,7 @@ befs_btree_find(struct super_block *sb, befs_data_stream * ds,
|
|||||||
* Use binary search instead of a linear.
|
* Use binary search instead of a linear.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
befs_find_key(struct super_block *sb, befs_btree_node * node,
|
befs_find_key(struct super_block *sb, struct befs_btree_node *node,
|
||||||
const char *findkey, befs_off_t * value)
|
const char *findkey, befs_off_t * value)
|
||||||
{
|
{
|
||||||
int first, last, mid;
|
int first, last, mid;
|
||||||
@ -417,7 +420,7 @@ befs_btree_read(struct super_block *sb, befs_data_stream * ds,
|
|||||||
loff_t key_no, size_t bufsize, char *keybuf, size_t * keysize,
|
loff_t key_no, size_t bufsize, char *keybuf, size_t * keysize,
|
||||||
befs_off_t * value)
|
befs_off_t * value)
|
||||||
{
|
{
|
||||||
befs_btree_node *this_node;
|
struct befs_btree_node *this_node;
|
||||||
befs_btree_super bt_super;
|
befs_btree_super bt_super;
|
||||||
befs_off_t node_off = 0;
|
befs_off_t node_off = 0;
|
||||||
int cur_key;
|
int cur_key;
|
||||||
@ -436,9 +439,10 @@ befs_btree_read(struct super_block *sb, befs_data_stream * ds,
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((this_node = kmalloc(sizeof (befs_btree_node), GFP_NOFS)) == NULL) {
|
this_node = kmalloc(sizeof(struct befs_btree_node), GFP_NOFS);
|
||||||
|
if (this_node == NULL) {
|
||||||
befs_error(sb, "befs_btree_read() failed to allocate %zu "
|
befs_error(sb, "befs_btree_read() failed to allocate %zu "
|
||||||
"bytes of memory", sizeof (befs_btree_node));
|
"bytes of memory", sizeof(struct befs_btree_node));
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -545,7 +549,8 @@ befs_btree_read(struct super_block *sb, befs_data_stream * ds,
|
|||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
befs_btree_seekleaf(struct super_block *sb, befs_data_stream * ds,
|
befs_btree_seekleaf(struct super_block *sb, befs_data_stream * ds,
|
||||||
befs_btree_super * bt_super, befs_btree_node * this_node,
|
befs_btree_super *bt_super,
|
||||||
|
struct befs_btree_node *this_node,
|
||||||
befs_off_t * node_off)
|
befs_off_t * node_off)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -600,7 +605,7 @@ befs_btree_seekleaf(struct super_block *sb, befs_data_stream * ds,
|
|||||||
* Return 1 if leaf, 0 if interior
|
* Return 1 if leaf, 0 if interior
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
befs_leafnode(befs_btree_node * node)
|
befs_leafnode(struct befs_btree_node *node)
|
||||||
{
|
{
|
||||||
/* all interior nodes (and only interior nodes) have an overflow node */
|
/* all interior nodes (and only interior nodes) have an overflow node */
|
||||||
if (node->head.overflow == befs_bt_inval)
|
if (node->head.overflow == befs_bt_inval)
|
||||||
@ -623,7 +628,7 @@ befs_leafnode(befs_btree_node * node)
|
|||||||
* Except that rounding up to 8 works, and rounding up to 4 doesn't.
|
* Except that rounding up to 8 works, and rounding up to 4 doesn't.
|
||||||
*/
|
*/
|
||||||
static fs16 *
|
static fs16 *
|
||||||
befs_bt_keylen_index(befs_btree_node * node)
|
befs_bt_keylen_index(struct befs_btree_node *node)
|
||||||
{
|
{
|
||||||
const int keylen_align = 8;
|
const int keylen_align = 8;
|
||||||
unsigned long int off =
|
unsigned long int off =
|
||||||
@ -644,7 +649,7 @@ befs_bt_keylen_index(befs_btree_node * node)
|
|||||||
* of the node pointed to by the node header
|
* of the node pointed to by the node header
|
||||||
*/
|
*/
|
||||||
static fs64 *
|
static fs64 *
|
||||||
befs_bt_valarray(befs_btree_node * node)
|
befs_bt_valarray(struct befs_btree_node *node)
|
||||||
{
|
{
|
||||||
void *keylen_index_start = (void *) befs_bt_keylen_index(node);
|
void *keylen_index_start = (void *) befs_bt_keylen_index(node);
|
||||||
size_t keylen_index_size = node->head.all_key_count * sizeof (fs16);
|
size_t keylen_index_size = node->head.all_key_count * sizeof (fs16);
|
||||||
@ -660,7 +665,7 @@ befs_bt_valarray(befs_btree_node * node)
|
|||||||
* of the node pointed to by the node header
|
* of the node pointed to by the node header
|
||||||
*/
|
*/
|
||||||
static char *
|
static char *
|
||||||
befs_bt_keydata(befs_btree_node * node)
|
befs_bt_keydata(struct befs_btree_node *node)
|
||||||
{
|
{
|
||||||
return (char *) ((void *) node->od_node + sizeof (befs_btree_nodehead));
|
return (char *) ((void *) node->od_node + sizeof (befs_btree_nodehead));
|
||||||
}
|
}
|
||||||
@ -676,7 +681,7 @@ befs_bt_keydata(befs_btree_node * node)
|
|||||||
* Returns NULL on failure (bad input) and sets *@keylen = 0
|
* Returns NULL on failure (bad input) and sets *@keylen = 0
|
||||||
*/
|
*/
|
||||||
static char *
|
static char *
|
||||||
befs_bt_get_key(struct super_block *sb, befs_btree_node * node,
|
befs_bt_get_key(struct super_block *sb, struct befs_btree_node *node,
|
||||||
int index, u16 * keylen)
|
int index, u16 * keylen)
|
||||||
{
|
{
|
||||||
int prev_key_end;
|
int prev_key_end;
|
||||||
|
@ -62,7 +62,22 @@ static struct file_system_type bm_fs_type;
|
|||||||
static struct vfsmount *bm_mnt;
|
static struct vfsmount *bm_mnt;
|
||||||
static int entry_count;
|
static int entry_count;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
* Max length of the register string. Determined by:
|
||||||
|
* - 7 delimiters
|
||||||
|
* - name: ~50 bytes
|
||||||
|
* - type: 1 byte
|
||||||
|
* - offset: 3 bytes (has to be smaller than BINPRM_BUF_SIZE)
|
||||||
|
* - magic: 128 bytes (512 in escaped form)
|
||||||
|
* - mask: 128 bytes (512 in escaped form)
|
||||||
|
* - interp: ~50 bytes
|
||||||
|
* - flags: 5 bytes
|
||||||
|
* Round that up a bit, and then back off to hold the internal data
|
||||||
|
* (like struct Node).
|
||||||
|
*/
|
||||||
|
#define MAX_REGISTER_LENGTH 1920
|
||||||
|
|
||||||
|
/*
|
||||||
* Check if we support the binfmt
|
* Check if we support the binfmt
|
||||||
* if we do, return the node, else NULL
|
* if we do, return the node, else NULL
|
||||||
* locking is done in load_misc_binary
|
* locking is done in load_misc_binary
|
||||||
@ -279,7 +294,7 @@ static Node *create_entry(const char __user *buffer, size_t count)
|
|||||||
|
|
||||||
/* some sanity checks */
|
/* some sanity checks */
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
if ((count < 11) || (count > 256))
|
if ((count < 11) || (count > MAX_REGISTER_LENGTH))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
@ -396,12 +411,12 @@ static int parse_command(const char __user *buffer, size_t count)
|
|||||||
{
|
{
|
||||||
char s[4];
|
char s[4];
|
||||||
|
|
||||||
if (!count)
|
|
||||||
return 0;
|
|
||||||
if (count > 3)
|
if (count > 3)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (copy_from_user(s, buffer, count))
|
if (copy_from_user(s, buffer, count))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
if (!count)
|
||||||
|
return 0;
|
||||||
if (s[count-1] == '\n')
|
if (s[count-1] == '\n')
|
||||||
count--;
|
count--;
|
||||||
if (count == 1 && s[0] == '0')
|
if (count == 1 && s[0] == '0')
|
||||||
|
@ -1331,8 +1331,8 @@ lookup_bh_lru(struct block_device *bdev, sector_t block, unsigned size)
|
|||||||
for (i = 0; i < BH_LRU_SIZE; i++) {
|
for (i = 0; i < BH_LRU_SIZE; i++) {
|
||||||
struct buffer_head *bh = __this_cpu_read(bh_lrus.bhs[i]);
|
struct buffer_head *bh = __this_cpu_read(bh_lrus.bhs[i]);
|
||||||
|
|
||||||
if (bh && bh->b_bdev == bdev &&
|
if (bh && bh->b_blocknr == block && bh->b_bdev == bdev &&
|
||||||
bh->b_blocknr == block && bh->b_size == size) {
|
bh->b_size == size) {
|
||||||
if (i) {
|
if (i) {
|
||||||
while (i) {
|
while (i) {
|
||||||
__this_cpu_write(bh_lrus.bhs[i],
|
__this_cpu_write(bh_lrus.bhs[i],
|
||||||
|
@ -195,15 +195,15 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
|
|||||||
else
|
else
|
||||||
noff = tkn_e - (sb_mountdata + off) + 1;
|
noff = tkn_e - (sb_mountdata + off) + 1;
|
||||||
|
|
||||||
if (strnicmp(sb_mountdata + off, "unc=", 4) == 0) {
|
if (strncasecmp(sb_mountdata + off, "unc=", 4) == 0) {
|
||||||
off += noff;
|
off += noff;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (strnicmp(sb_mountdata + off, "ip=", 3) == 0) {
|
if (strncasecmp(sb_mountdata + off, "ip=", 3) == 0) {
|
||||||
off += noff;
|
off += noff;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (strnicmp(sb_mountdata + off, "prefixpath=", 11) == 0) {
|
if (strncasecmp(sb_mountdata + off, "prefixpath=", 11) == 0) {
|
||||||
off += noff;
|
off += noff;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1718,7 +1718,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
|
|||||||
goto cifs_parse_mount_err;
|
goto cifs_parse_mount_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strnicmp(string, "default", 7) != 0) {
|
if (strncasecmp(string, "default", 7) != 0) {
|
||||||
vol->iocharset = kstrdup(string,
|
vol->iocharset = kstrdup(string,
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!vol->iocharset) {
|
if (!vol->iocharset) {
|
||||||
@ -1790,7 +1790,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
|
|||||||
if (string == NULL)
|
if (string == NULL)
|
||||||
goto out_nomem;
|
goto out_nomem;
|
||||||
|
|
||||||
if (strnicmp(string, "1", 1) == 0) {
|
if (strncasecmp(string, "1", 1) == 0) {
|
||||||
/* This is the default */
|
/* This is the default */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -199,6 +199,14 @@ static int format_corename(struct core_name *cn, struct coredump_params *cprm)
|
|||||||
err = cn_printf(cn, "%d",
|
err = cn_printf(cn, "%d",
|
||||||
task_tgid_nr(current));
|
task_tgid_nr(current));
|
||||||
break;
|
break;
|
||||||
|
case 'i':
|
||||||
|
err = cn_printf(cn, "%d",
|
||||||
|
task_pid_vnr(current));
|
||||||
|
break;
|
||||||
|
case 'I':
|
||||||
|
err = cn_printf(cn, "%d",
|
||||||
|
task_pid_nr(current));
|
||||||
|
break;
|
||||||
/* uid */
|
/* uid */
|
||||||
case 'u':
|
case 'u':
|
||||||
err = cn_printf(cn, "%d", cred->uid);
|
err = cn_printf(cn, "%d", cred->uid);
|
||||||
|
@ -164,8 +164,6 @@ int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern struct timezone sys_tz;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The epoch of FAT timestamp is 1980.
|
* The epoch of FAT timestamp is 1980.
|
||||||
* : bits : value
|
* : bits : value
|
||||||
|
@ -242,8 +242,6 @@ extern int hfs_mac2asc(struct super_block *, char *, const struct hfs_name *);
|
|||||||
/* super.c */
|
/* super.c */
|
||||||
extern void hfs_mark_mdb_dirty(struct super_block *sb);
|
extern void hfs_mark_mdb_dirty(struct super_block *sb);
|
||||||
|
|
||||||
extern struct timezone sys_tz;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* There are two time systems. Both are based on seconds since
|
* There are two time systems. Both are based on seconds since
|
||||||
* a particular time/date.
|
* a particular time/date.
|
||||||
|
@ -247,7 +247,7 @@ static int isofs_dentry_cmp_common(
|
|||||||
}
|
}
|
||||||
if (alen == blen) {
|
if (alen == blen) {
|
||||||
if (ci) {
|
if (ci) {
|
||||||
if (strnicmp(name->name, str, alen) == 0)
|
if (strncasecmp(name->name, str, alen) == 0)
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
if (strncmp(name->name, str, alen) == 0)
|
if (strncmp(name->name, str, alen) == 0)
|
||||||
|
@ -1178,9 +1178,6 @@ static int day_n[] =
|
|||||||
{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0};
|
{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0};
|
||||||
/* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
|
/* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
|
||||||
|
|
||||||
|
|
||||||
extern struct timezone sys_tz;
|
|
||||||
|
|
||||||
static int utc2local(int time)
|
static int utc2local(int time)
|
||||||
{
|
{
|
||||||
return time - sys_tz.tz_minuteswest * 60;
|
return time - sys_tz.tz_minuteswest * 60;
|
||||||
|
@ -56,11 +56,9 @@ int nilfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
|
|||||||
mutex_unlock(&inode->i_mutex);
|
mutex_unlock(&inode->i_mutex);
|
||||||
|
|
||||||
nilfs = inode->i_sb->s_fs_info;
|
nilfs = inode->i_sb->s_fs_info;
|
||||||
if (!err && nilfs_test_opt(nilfs, BARRIER)) {
|
if (!err)
|
||||||
err = blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
|
err = nilfs_flush_device(nilfs);
|
||||||
if (err != -EIO)
|
|
||||||
err = 0;
|
|
||||||
}
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,7 +126,7 @@ int nilfs_get_block(struct inode *inode, sector_t blkoff,
|
|||||||
nilfs_transaction_abort(inode->i_sb);
|
nilfs_transaction_abort(inode->i_sb);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
nilfs_mark_inode_dirty(inode);
|
nilfs_mark_inode_dirty_sync(inode);
|
||||||
nilfs_transaction_commit(inode->i_sb); /* never fails */
|
nilfs_transaction_commit(inode->i_sb); /* never fails */
|
||||||
/* Error handling should be detailed */
|
/* Error handling should be detailed */
|
||||||
set_buffer_new(bh_result);
|
set_buffer_new(bh_result);
|
||||||
@ -672,7 +672,7 @@ void nilfs_write_inode_common(struct inode *inode,
|
|||||||
for substitutions of appended fields */
|
for substitutions of appended fields */
|
||||||
}
|
}
|
||||||
|
|
||||||
void nilfs_update_inode(struct inode *inode, struct buffer_head *ibh)
|
void nilfs_update_inode(struct inode *inode, struct buffer_head *ibh, int flags)
|
||||||
{
|
{
|
||||||
ino_t ino = inode->i_ino;
|
ino_t ino = inode->i_ino;
|
||||||
struct nilfs_inode_info *ii = NILFS_I(inode);
|
struct nilfs_inode_info *ii = NILFS_I(inode);
|
||||||
@ -683,7 +683,8 @@ void nilfs_update_inode(struct inode *inode, struct buffer_head *ibh)
|
|||||||
|
|
||||||
if (test_and_clear_bit(NILFS_I_NEW, &ii->i_state))
|
if (test_and_clear_bit(NILFS_I_NEW, &ii->i_state))
|
||||||
memset(raw_inode, 0, NILFS_MDT(ifile)->mi_entry_size);
|
memset(raw_inode, 0, NILFS_MDT(ifile)->mi_entry_size);
|
||||||
set_bit(NILFS_I_INODE_DIRTY, &ii->i_state);
|
if (flags & I_DIRTY_DATASYNC)
|
||||||
|
set_bit(NILFS_I_INODE_SYNC, &ii->i_state);
|
||||||
|
|
||||||
nilfs_write_inode_common(inode, raw_inode, 0);
|
nilfs_write_inode_common(inode, raw_inode, 0);
|
||||||
/* XXX: call with has_bmap = 0 is a workaround to avoid
|
/* XXX: call with has_bmap = 0 is a workaround to avoid
|
||||||
@ -939,7 +940,7 @@ int nilfs_set_file_dirty(struct inode *inode, unsigned nr_dirty)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int nilfs_mark_inode_dirty(struct inode *inode)
|
int __nilfs_mark_inode_dirty(struct inode *inode, int flags)
|
||||||
{
|
{
|
||||||
struct buffer_head *ibh;
|
struct buffer_head *ibh;
|
||||||
int err;
|
int err;
|
||||||
@ -950,7 +951,7 @@ int nilfs_mark_inode_dirty(struct inode *inode)
|
|||||||
"failed to reget inode block.\n");
|
"failed to reget inode block.\n");
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
nilfs_update_inode(inode, ibh);
|
nilfs_update_inode(inode, ibh, flags);
|
||||||
mark_buffer_dirty(ibh);
|
mark_buffer_dirty(ibh);
|
||||||
nilfs_mdt_mark_dirty(NILFS_I(inode)->i_root->ifile);
|
nilfs_mdt_mark_dirty(NILFS_I(inode)->i_root->ifile);
|
||||||
brelse(ibh);
|
brelse(ibh);
|
||||||
@ -983,7 +984,7 @@ void nilfs_dirty_inode(struct inode *inode, int flags)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
nilfs_transaction_begin(inode->i_sb, &ti, 0);
|
nilfs_transaction_begin(inode->i_sb, &ti, 0);
|
||||||
nilfs_mark_inode_dirty(inode);
|
__nilfs_mark_inode_dirty(inode, flags);
|
||||||
nilfs_transaction_commit(inode->i_sb); /* never fails */
|
nilfs_transaction_commit(inode->i_sb); /* never fails */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1022,11 +1022,9 @@ static int nilfs_ioctl_sync(struct inode *inode, struct file *filp,
|
|||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
nilfs = inode->i_sb->s_fs_info;
|
nilfs = inode->i_sb->s_fs_info;
|
||||||
if (nilfs_test_opt(nilfs, BARRIER)) {
|
ret = nilfs_flush_device(nilfs);
|
||||||
ret = blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
|
if (ret < 0)
|
||||||
if (ret == -EIO)
|
return ret;
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (argp != NULL) {
|
if (argp != NULL) {
|
||||||
down_read(&nilfs->ns_segctor_sem);
|
down_read(&nilfs->ns_segctor_sem);
|
||||||
|
@ -104,7 +104,7 @@ enum {
|
|||||||
constructor */
|
constructor */
|
||||||
NILFS_I_COLLECTED, /* All dirty blocks are collected */
|
NILFS_I_COLLECTED, /* All dirty blocks are collected */
|
||||||
NILFS_I_UPDATED, /* The file has been written back */
|
NILFS_I_UPDATED, /* The file has been written back */
|
||||||
NILFS_I_INODE_DIRTY, /* write_inode is requested */
|
NILFS_I_INODE_SYNC, /* dsync is not allowed for inode */
|
||||||
NILFS_I_BMAP, /* has bmap and btnode_cache */
|
NILFS_I_BMAP, /* has bmap and btnode_cache */
|
||||||
NILFS_I_GCINODE, /* inode for GC, on memory only */
|
NILFS_I_GCINODE, /* inode for GC, on memory only */
|
||||||
};
|
};
|
||||||
@ -273,7 +273,7 @@ struct inode *nilfs_iget(struct super_block *sb, struct nilfs_root *root,
|
|||||||
unsigned long ino);
|
unsigned long ino);
|
||||||
extern struct inode *nilfs_iget_for_gc(struct super_block *sb,
|
extern struct inode *nilfs_iget_for_gc(struct super_block *sb,
|
||||||
unsigned long ino, __u64 cno);
|
unsigned long ino, __u64 cno);
|
||||||
extern void nilfs_update_inode(struct inode *, struct buffer_head *);
|
extern void nilfs_update_inode(struct inode *, struct buffer_head *, int);
|
||||||
extern void nilfs_truncate(struct inode *);
|
extern void nilfs_truncate(struct inode *);
|
||||||
extern void nilfs_evict_inode(struct inode *);
|
extern void nilfs_evict_inode(struct inode *);
|
||||||
extern int nilfs_setattr(struct dentry *, struct iattr *);
|
extern int nilfs_setattr(struct dentry *, struct iattr *);
|
||||||
@ -282,10 +282,18 @@ int nilfs_permission(struct inode *inode, int mask);
|
|||||||
int nilfs_load_inode_block(struct inode *inode, struct buffer_head **pbh);
|
int nilfs_load_inode_block(struct inode *inode, struct buffer_head **pbh);
|
||||||
extern int nilfs_inode_dirty(struct inode *);
|
extern int nilfs_inode_dirty(struct inode *);
|
||||||
int nilfs_set_file_dirty(struct inode *inode, unsigned nr_dirty);
|
int nilfs_set_file_dirty(struct inode *inode, unsigned nr_dirty);
|
||||||
extern int nilfs_mark_inode_dirty(struct inode *);
|
extern int __nilfs_mark_inode_dirty(struct inode *, int);
|
||||||
extern void nilfs_dirty_inode(struct inode *, int flags);
|
extern void nilfs_dirty_inode(struct inode *, int flags);
|
||||||
int nilfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
int nilfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
||||||
__u64 start, __u64 len);
|
__u64 start, __u64 len);
|
||||||
|
static inline int nilfs_mark_inode_dirty(struct inode *inode)
|
||||||
|
{
|
||||||
|
return __nilfs_mark_inode_dirty(inode, I_DIRTY);
|
||||||
|
}
|
||||||
|
static inline int nilfs_mark_inode_dirty_sync(struct inode *inode)
|
||||||
|
{
|
||||||
|
return __nilfs_mark_inode_dirty(inode, I_DIRTY_SYNC);
|
||||||
|
}
|
||||||
|
|
||||||
/* super.c */
|
/* super.c */
|
||||||
extern struct inode *nilfs_alloc_inode(struct super_block *);
|
extern struct inode *nilfs_alloc_inode(struct super_block *);
|
||||||
|
@ -930,7 +930,7 @@ static void nilfs_drop_collected_inodes(struct list_head *head)
|
|||||||
if (!test_and_clear_bit(NILFS_I_COLLECTED, &ii->i_state))
|
if (!test_and_clear_bit(NILFS_I_COLLECTED, &ii->i_state))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
clear_bit(NILFS_I_INODE_DIRTY, &ii->i_state);
|
clear_bit(NILFS_I_INODE_SYNC, &ii->i_state);
|
||||||
set_bit(NILFS_I_UPDATED, &ii->i_state);
|
set_bit(NILFS_I_UPDATED, &ii->i_state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1833,6 +1833,7 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci)
|
|||||||
nilfs_set_next_segment(nilfs, segbuf);
|
nilfs_set_next_segment(nilfs, segbuf);
|
||||||
|
|
||||||
if (update_sr) {
|
if (update_sr) {
|
||||||
|
nilfs->ns_flushed_device = 0;
|
||||||
nilfs_set_last_segment(nilfs, segbuf->sb_pseg_start,
|
nilfs_set_last_segment(nilfs, segbuf->sb_pseg_start,
|
||||||
segbuf->sb_sum.seg_seq, nilfs->ns_cno++);
|
segbuf->sb_sum.seg_seq, nilfs->ns_cno++);
|
||||||
|
|
||||||
@ -2194,7 +2195,7 @@ int nilfs_construct_dsync_segment(struct super_block *sb, struct inode *inode,
|
|||||||
nilfs_transaction_lock(sb, &ti, 0);
|
nilfs_transaction_lock(sb, &ti, 0);
|
||||||
|
|
||||||
ii = NILFS_I(inode);
|
ii = NILFS_I(inode);
|
||||||
if (test_bit(NILFS_I_INODE_DIRTY, &ii->i_state) ||
|
if (test_bit(NILFS_I_INODE_SYNC, &ii->i_state) ||
|
||||||
nilfs_test_opt(nilfs, STRICT_ORDER) ||
|
nilfs_test_opt(nilfs, STRICT_ORDER) ||
|
||||||
test_bit(NILFS_SC_UNCLOSED, &sci->sc_flags) ||
|
test_bit(NILFS_SC_UNCLOSED, &sci->sc_flags) ||
|
||||||
nilfs_discontinued(nilfs)) {
|
nilfs_discontinued(nilfs)) {
|
||||||
@ -2216,6 +2217,8 @@ int nilfs_construct_dsync_segment(struct super_block *sb, struct inode *inode,
|
|||||||
sci->sc_dsync_end = end;
|
sci->sc_dsync_end = end;
|
||||||
|
|
||||||
err = nilfs_segctor_do_construct(sci, SC_LSEG_DSYNC);
|
err = nilfs_segctor_do_construct(sci, SC_LSEG_DSYNC);
|
||||||
|
if (!err)
|
||||||
|
nilfs->ns_flushed_device = 0;
|
||||||
|
|
||||||
nilfs_transaction_unlock(sb);
|
nilfs_transaction_unlock(sb);
|
||||||
return err;
|
return err;
|
||||||
|
@ -310,6 +310,9 @@ int nilfs_commit_super(struct super_block *sb, int flag)
|
|||||||
nilfs->ns_sbsize));
|
nilfs->ns_sbsize));
|
||||||
}
|
}
|
||||||
clear_nilfs_sb_dirty(nilfs);
|
clear_nilfs_sb_dirty(nilfs);
|
||||||
|
nilfs->ns_flushed_device = 1;
|
||||||
|
/* make sure store to ns_flushed_device cannot be reordered */
|
||||||
|
smp_wmb();
|
||||||
return nilfs_sync_super(sb, flag);
|
return nilfs_sync_super(sb, flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -514,6 +517,9 @@ static int nilfs_sync_fs(struct super_block *sb, int wait)
|
|||||||
}
|
}
|
||||||
up_write(&nilfs->ns_sem);
|
up_write(&nilfs->ns_sem);
|
||||||
|
|
||||||
|
if (!err)
|
||||||
|
err = nilfs_flush_device(nilfs);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,6 +46,7 @@ enum {
|
|||||||
/**
|
/**
|
||||||
* struct the_nilfs - struct to supervise multiple nilfs mount points
|
* struct the_nilfs - struct to supervise multiple nilfs mount points
|
||||||
* @ns_flags: flags
|
* @ns_flags: flags
|
||||||
|
* @ns_flushed_device: flag indicating if all volatile data was flushed
|
||||||
* @ns_bdev: block device
|
* @ns_bdev: block device
|
||||||
* @ns_sem: semaphore for shared states
|
* @ns_sem: semaphore for shared states
|
||||||
* @ns_snapshot_mount_mutex: mutex to protect snapshot mounts
|
* @ns_snapshot_mount_mutex: mutex to protect snapshot mounts
|
||||||
@ -103,6 +104,7 @@ enum {
|
|||||||
*/
|
*/
|
||||||
struct the_nilfs {
|
struct the_nilfs {
|
||||||
unsigned long ns_flags;
|
unsigned long ns_flags;
|
||||||
|
int ns_flushed_device;
|
||||||
|
|
||||||
struct block_device *ns_bdev;
|
struct block_device *ns_bdev;
|
||||||
struct rw_semaphore ns_sem;
|
struct rw_semaphore ns_sem;
|
||||||
@ -371,4 +373,24 @@ static inline int nilfs_segment_is_active(struct the_nilfs *nilfs, __u64 n)
|
|||||||
return n == nilfs->ns_segnum || n == nilfs->ns_nextnum;
|
return n == nilfs->ns_segnum || n == nilfs->ns_nextnum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int nilfs_flush_device(struct the_nilfs *nilfs)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!nilfs_test_opt(nilfs, BARRIER) || nilfs->ns_flushed_device)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
nilfs->ns_flushed_device = 1;
|
||||||
|
/*
|
||||||
|
* the store to ns_flushed_device must not be reordered after
|
||||||
|
* blkdev_issue_flush().
|
||||||
|
*/
|
||||||
|
smp_wmb();
|
||||||
|
|
||||||
|
err = blkdev_issue_flush(nilfs->ns_bdev, GFP_KERNEL, NULL);
|
||||||
|
if (err != -EIO)
|
||||||
|
err = 0;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* _THE_NILFS_H */
|
#endif /* _THE_NILFS_H */
|
||||||
|
@ -2244,7 +2244,7 @@ ssize_t o2hb_heartbeat_group_mode_store(struct o2hb_heartbeat_group *group,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
for (i = 0; i < O2HB_HEARTBEAT_NUM_MODES; ++i) {
|
for (i = 0; i < O2HB_HEARTBEAT_NUM_MODES; ++i) {
|
||||||
if (strnicmp(page, o2hb_heartbeat_mode_desc[i], len))
|
if (strncasecmp(page, o2hb_heartbeat_mode_desc[i], len))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ret = o2hb_global_heartbeat_mode_set(i);
|
ret = o2hb_global_heartbeat_mode_set(i);
|
||||||
|
@ -49,13 +49,13 @@ static ssize_t mlog_mask_show(u64 mask, char *buf)
|
|||||||
|
|
||||||
static ssize_t mlog_mask_store(u64 mask, const char *buf, size_t count)
|
static ssize_t mlog_mask_store(u64 mask, const char *buf, size_t count)
|
||||||
{
|
{
|
||||||
if (!strnicmp(buf, "allow", 5)) {
|
if (!strncasecmp(buf, "allow", 5)) {
|
||||||
__mlog_set_u64(mask, mlog_and_bits);
|
__mlog_set_u64(mask, mlog_and_bits);
|
||||||
__mlog_clear_u64(mask, mlog_not_bits);
|
__mlog_clear_u64(mask, mlog_not_bits);
|
||||||
} else if (!strnicmp(buf, "deny", 4)) {
|
} else if (!strncasecmp(buf, "deny", 4)) {
|
||||||
__mlog_set_u64(mask, mlog_not_bits);
|
__mlog_set_u64(mask, mlog_not_bits);
|
||||||
__mlog_clear_u64(mask, mlog_and_bits);
|
__mlog_clear_u64(mask, mlog_and_bits);
|
||||||
} else if (!strnicmp(buf, "off", 3)) {
|
} else if (!strncasecmp(buf, "off", 3)) {
|
||||||
__mlog_clear_u64(mask, mlog_not_bits);
|
__mlog_clear_u64(mask, mlog_not_bits);
|
||||||
__mlog_clear_u64(mask, mlog_and_bits);
|
__mlog_clear_u64(mask, mlog_and_bits);
|
||||||
} else
|
} else
|
||||||
|
@ -306,9 +306,7 @@ static const struct super_operations omfs_sops = {
|
|||||||
*/
|
*/
|
||||||
static int omfs_get_imap(struct super_block *sb)
|
static int omfs_get_imap(struct super_block *sb)
|
||||||
{
|
{
|
||||||
int bitmap_size;
|
unsigned int bitmap_size, count, array_size;
|
||||||
int array_size;
|
|
||||||
int count;
|
|
||||||
struct omfs_sb_info *sbi = OMFS_SB(sb);
|
struct omfs_sb_info *sbi = OMFS_SB(sb);
|
||||||
struct buffer_head *bh;
|
struct buffer_head *bh;
|
||||||
unsigned long **ptr;
|
unsigned long **ptr;
|
||||||
@ -473,6 +471,12 @@ static int omfs_fill_super(struct super_block *sb, void *data, int silent)
|
|||||||
sbi->s_sys_blocksize = be32_to_cpu(omfs_sb->s_sys_blocksize);
|
sbi->s_sys_blocksize = be32_to_cpu(omfs_sb->s_sys_blocksize);
|
||||||
mutex_init(&sbi->s_bitmap_lock);
|
mutex_init(&sbi->s_bitmap_lock);
|
||||||
|
|
||||||
|
if (sbi->s_num_blocks > OMFS_MAX_BLOCKS) {
|
||||||
|
printk(KERN_ERR "omfs: sysblock number (%llx) is out of range\n",
|
||||||
|
(unsigned long long)sbi->s_num_blocks);
|
||||||
|
goto out_brelse_bh;
|
||||||
|
}
|
||||||
|
|
||||||
if (sbi->s_sys_blocksize > PAGE_SIZE) {
|
if (sbi->s_sys_blocksize > PAGE_SIZE) {
|
||||||
printk(KERN_ERR "omfs: sysblock size (%d) is out of range\n",
|
printk(KERN_ERR "omfs: sysblock size (%d) is out of range\n",
|
||||||
sbi->s_sys_blocksize);
|
sbi->s_sys_blocksize);
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#define OMFS_XOR_COUNT 19
|
#define OMFS_XOR_COUNT 19
|
||||||
#define OMFS_MAX_BLOCK_SIZE 8192
|
#define OMFS_MAX_BLOCK_SIZE 8192
|
||||||
#define OMFS_MAX_CLUSTER_SIZE 8
|
#define OMFS_MAX_CLUSTER_SIZE 8
|
||||||
|
#define OMFS_MAX_BLOCKS (1ul << 31)
|
||||||
|
|
||||||
struct omfs_super_block {
|
struct omfs_super_block {
|
||||||
char s_fill1[256];
|
char s_fill1[256];
|
||||||
|
@ -827,8 +827,21 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf,
|
|||||||
.private = &cp,
|
.private = &cp,
|
||||||
};
|
};
|
||||||
down_read(&mm->mmap_sem);
|
down_read(&mm->mmap_sem);
|
||||||
if (type == CLEAR_REFS_SOFT_DIRTY)
|
if (type == CLEAR_REFS_SOFT_DIRTY) {
|
||||||
|
for (vma = mm->mmap; vma; vma = vma->vm_next) {
|
||||||
|
if (!(vma->vm_flags & VM_SOFTDIRTY))
|
||||||
|
continue;
|
||||||
|
up_read(&mm->mmap_sem);
|
||||||
|
down_write(&mm->mmap_sem);
|
||||||
|
for (vma = mm->mmap; vma; vma = vma->vm_next) {
|
||||||
|
vma->vm_flags &= ~VM_SOFTDIRTY;
|
||||||
|
vma_set_page_prot(vma);
|
||||||
|
}
|
||||||
|
downgrade_write(&mm->mmap_sem);
|
||||||
|
break;
|
||||||
|
}
|
||||||
mmu_notifier_invalidate_range_start(mm, 0, -1);
|
mmu_notifier_invalidate_range_start(mm, 0, -1);
|
||||||
|
}
|
||||||
for (vma = mm->mmap; vma; vma = vma->vm_next) {
|
for (vma = mm->mmap; vma; vma = vma->vm_next) {
|
||||||
cp.vma = vma;
|
cp.vma = vma;
|
||||||
if (is_vm_hugetlb_page(vma))
|
if (is_vm_hugetlb_page(vma))
|
||||||
@ -848,10 +861,6 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf,
|
|||||||
continue;
|
continue;
|
||||||
if (type == CLEAR_REFS_MAPPED && !vma->vm_file)
|
if (type == CLEAR_REFS_MAPPED && !vma->vm_file)
|
||||||
continue;
|
continue;
|
||||||
if (type == CLEAR_REFS_SOFT_DIRTY) {
|
|
||||||
if (vma->vm_flags & VM_SOFTDIRTY)
|
|
||||||
vma->vm_flags &= ~VM_SOFTDIRTY;
|
|
||||||
}
|
|
||||||
walk_page_range(vma->vm_start, vma->vm_end,
|
walk_page_range(vma->vm_start, vma->vm_end,
|
||||||
&clear_refs_walk);
|
&clear_refs_walk);
|
||||||
}
|
}
|
||||||
|
@ -699,11 +699,13 @@ static int add_to_chunk(struct buffer_chunk *chunk, struct buffer_head *bh,
|
|||||||
chunk->bh[chunk->nr++] = bh;
|
chunk->bh[chunk->nr++] = bh;
|
||||||
if (chunk->nr >= CHUNK_SIZE) {
|
if (chunk->nr >= CHUNK_SIZE) {
|
||||||
ret = 1;
|
ret = 1;
|
||||||
if (lock)
|
if (lock) {
|
||||||
spin_unlock(lock);
|
spin_unlock(lock);
|
||||||
fn(chunk);
|
fn(chunk);
|
||||||
if (lock)
|
|
||||||
spin_lock(lock);
|
spin_lock(lock);
|
||||||
|
} else {
|
||||||
|
fn(chunk);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -784,7 +784,6 @@ static u64 ufs_bitmap_search(struct super_block *sb,
|
|||||||
0x0, 0x2, 0x6, 0xe, 0x1e, 0x3e, 0x7e, 0xfe, 0x1fe
|
0x0, 0x2, 0x6, 0xe, 0x1e, 0x3e, 0x7e, 0xfe, 0x1fe
|
||||||
};
|
};
|
||||||
struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
|
struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
|
||||||
struct ufs_cylinder_group *ucg;
|
|
||||||
unsigned start, length, loc;
|
unsigned start, length, loc;
|
||||||
unsigned pos, want, blockmap, mask, end;
|
unsigned pos, want, blockmap, mask, end;
|
||||||
u64 result;
|
u64 result;
|
||||||
@ -792,8 +791,6 @@ static u64 ufs_bitmap_search(struct super_block *sb,
|
|||||||
UFSD("ENTER, cg %u, goal %llu, count %u\n", ucpi->c_cgx,
|
UFSD("ENTER, cg %u, goal %llu, count %u\n", ucpi->c_cgx,
|
||||||
(unsigned long long)goal, count);
|
(unsigned long long)goal, count);
|
||||||
|
|
||||||
ucg = ubh_get_ucg(UCPI_UBH(ucpi));
|
|
||||||
|
|
||||||
if (goal)
|
if (goal)
|
||||||
start = ufs_dtogd(uspi, goal) >> 3;
|
start = ufs_dtogd(uspi, goal) >> 3;
|
||||||
else
|
else
|
||||||
|
@ -253,6 +253,20 @@ static inline int pmd_same(pmd_t pmd_a, pmd_t pmd_b)
|
|||||||
#define pgprot_device pgprot_noncached
|
#define pgprot_device pgprot_noncached
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef pgprot_modify
|
||||||
|
#define pgprot_modify pgprot_modify
|
||||||
|
static inline pgprot_t pgprot_modify(pgprot_t oldprot, pgprot_t newprot)
|
||||||
|
{
|
||||||
|
if (pgprot_val(oldprot) == pgprot_val(pgprot_noncached(oldprot)))
|
||||||
|
newprot = pgprot_noncached(newprot);
|
||||||
|
if (pgprot_val(oldprot) == pgprot_val(pgprot_writecombine(oldprot)))
|
||||||
|
newprot = pgprot_writecombine(newprot);
|
||||||
|
if (pgprot_val(oldprot) == pgprot_val(pgprot_device(oldprot)))
|
||||||
|
newprot = pgprot_device(newprot);
|
||||||
|
return newprot;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When walking page tables, get the address of the next boundary,
|
* When walking page tables, get the address of the next boundary,
|
||||||
* or the end address of the range if that comes earlier. Although no
|
* or the end address of the range if that comes earlier. Although no
|
||||||
|
@ -22,6 +22,9 @@ extern int __init cma_declare_contiguous(phys_addr_t size,
|
|||||||
phys_addr_t base, phys_addr_t limit,
|
phys_addr_t base, phys_addr_t limit,
|
||||||
phys_addr_t alignment, unsigned int order_per_bit,
|
phys_addr_t alignment, unsigned int order_per_bit,
|
||||||
bool fixed, struct cma **res_cma);
|
bool fixed, struct cma **res_cma);
|
||||||
|
extern int cma_init_reserved_mem(phys_addr_t size,
|
||||||
|
phys_addr_t base, int order_per_bit,
|
||||||
|
struct cma **res_cma);
|
||||||
extern struct page *cma_alloc(struct cma *cma, int count, unsigned int align);
|
extern struct page *cma_alloc(struct cma *cma, int count, unsigned int align);
|
||||||
extern bool cma_release(struct cma *cma, struct page *pages, int count);
|
extern bool cma_release(struct cma *cma, struct page *pages, int count);
|
||||||
#endif
|
#endif
|
||||||
|
66
include/linux/compiler-gcc5.h
Normal file
66
include/linux/compiler-gcc5.h
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
#ifndef __LINUX_COMPILER_H
|
||||||
|
#error "Please don't include <linux/compiler-gcc5.h> directly, include <linux/compiler.h> instead."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define __used __attribute__((__used__))
|
||||||
|
#define __must_check __attribute__((warn_unused_result))
|
||||||
|
#define __compiler_offsetof(a, b) __builtin_offsetof(a, b)
|
||||||
|
|
||||||
|
/* Mark functions as cold. gcc will assume any path leading to a call
|
||||||
|
to them will be unlikely. This means a lot of manual unlikely()s
|
||||||
|
are unnecessary now for any paths leading to the usual suspects
|
||||||
|
like BUG(), printk(), panic() etc. [but let's keep them for now for
|
||||||
|
older compilers]
|
||||||
|
|
||||||
|
Early snapshots of gcc 4.3 don't support this and we can't detect this
|
||||||
|
in the preprocessor, but we can live with this because they're unreleased.
|
||||||
|
Maketime probing would be overkill here.
|
||||||
|
|
||||||
|
gcc also has a __attribute__((__hot__)) to move hot functions into
|
||||||
|
a special section, but I don't see any sense in this right now in
|
||||||
|
the kernel context */
|
||||||
|
#define __cold __attribute__((__cold__))
|
||||||
|
|
||||||
|
#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__)
|
||||||
|
|
||||||
|
#ifndef __CHECKER__
|
||||||
|
# define __compiletime_warning(message) __attribute__((warning(message)))
|
||||||
|
# define __compiletime_error(message) __attribute__((error(message)))
|
||||||
|
#endif /* __CHECKER__ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mark a position in code as unreachable. This can be used to
|
||||||
|
* suppress control flow warnings after asm blocks that transfer
|
||||||
|
* control elsewhere.
|
||||||
|
*
|
||||||
|
* Early snapshots of gcc 4.5 don't support this and we can't detect
|
||||||
|
* this in the preprocessor, but we can live with this because they're
|
||||||
|
* unreleased. Really, we need to have autoconf for the kernel.
|
||||||
|
*/
|
||||||
|
#define unreachable() __builtin_unreachable()
|
||||||
|
|
||||||
|
/* Mark a function definition as prohibited from being cloned. */
|
||||||
|
#define __noclone __attribute__((__noclone__))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tell the optimizer that something else uses this function or variable.
|
||||||
|
*/
|
||||||
|
#define __visible __attribute__((externally_visible))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GCC 'asm goto' miscompiles certain code sequences:
|
||||||
|
*
|
||||||
|
* http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58670
|
||||||
|
*
|
||||||
|
* Work it around via a compiler barrier quirk suggested by Jakub Jelinek.
|
||||||
|
* Fixed in GCC 4.8.2 and later versions.
|
||||||
|
*
|
||||||
|
* (asm goto is automatically volatile - the naming reflects this.)
|
||||||
|
*/
|
||||||
|
#define asm_volatile_goto(x...) do { asm goto(x); asm (""); } while (0)
|
||||||
|
|
||||||
|
#ifdef CONFIG_ARCH_USE_BUILTIN_BSWAP
|
||||||
|
#define __HAVE_BUILTIN_BSWAP32__
|
||||||
|
#define __HAVE_BUILTIN_BSWAP64__
|
||||||
|
#define __HAVE_BUILTIN_BSWAP16__
|
||||||
|
#endif /* CONFIG_ARCH_USE_BUILTIN_BSWAP */
|
@ -376,10 +376,6 @@ extern unsigned long simple_strtoul(const char *,char **,unsigned int);
|
|||||||
extern long simple_strtol(const char *,char **,unsigned int);
|
extern long simple_strtol(const char *,char **,unsigned int);
|
||||||
extern unsigned long long simple_strtoull(const char *,char **,unsigned int);
|
extern unsigned long long simple_strtoull(const char *,char **,unsigned int);
|
||||||
extern long long simple_strtoll(const char *,char **,unsigned int);
|
extern long long simple_strtoll(const char *,char **,unsigned int);
|
||||||
#define strict_strtoul kstrtoul
|
|
||||||
#define strict_strtol kstrtol
|
|
||||||
#define strict_strtoull kstrtoull
|
|
||||||
#define strict_strtoll kstrtoll
|
|
||||||
|
|
||||||
extern int num_to_str(char *buf, int size, unsigned long long num);
|
extern int num_to_str(char *buf, int size, unsigned long long num);
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user