diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index 9b1f6ca100d1de96e9071193f90a3cbf6d81e34c..0a08126d30942bad2f59d11e09c9c651c8f5e63b 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -6,7 +6,7 @@ # To add a new book the only step required is to add the book to the # list of DOCBOOKS. -DOCBOOKS := wanbook.xml z8530book.xml mcabook.xml \ +DOCBOOKS := z8530book.xml mcabook.xml \ kernel-hacking.xml kernel-locking.xml deviceiobook.xml \ procfs-guide.xml writing_usb_driver.xml networking.xml \ kernel-api.xml filesystems.xml lsm.xml usb.xml kgdb.xml \ diff --git a/Documentation/DocBook/networking.tmpl b/Documentation/DocBook/networking.tmpl index f24f9e85e4aeba788d7b4557bf19d93efaa7dc99..627707a3cb9d66406ba40a356cf000772de97701 100644 --- a/Documentation/DocBook/networking.tmpl +++ b/Documentation/DocBook/networking.tmpl @@ -98,9 +98,6 @@ X!Enet/core/wireless.c --> - Synchronous PPP -!Edrivers/net/wan/syncppp.c - diff --git a/Documentation/DocBook/wanbook.tmpl b/Documentation/DocBook/wanbook.tmpl deleted file mode 100644 index 8c93db122f049a13177b5d5f612d8da3f12aeaad..0000000000000000000000000000000000000000 --- a/Documentation/DocBook/wanbook.tmpl +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - Synchronous PPP and Cisco HDLC Programming Guide - - - - Alan - Cox - -
- alan@lxorguk.ukuu.org.uk -
-
-
-
- - - 2000 - Alan Cox - - - - - This documentation is free software; you can redistribute - it and/or modify it under the terms of the GNU General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later - version. - - - - This program is distributed in the hope that it will be - useful, but WITHOUT ANY WARRANTY; without even the implied - warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU General Public License for more details. - - - - You should have received a copy of the GNU General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, - MA 02111-1307 USA - - - - For more details see the file COPYING in the source - distribution of Linux. - - -
- - - - - Introduction - - The syncppp drivers in Linux provide a fairly complete - implementation of Cisco HDLC and a minimal implementation of - PPP. The longer term goal is to switch the PPP layer to the - generic PPP interface that is new in Linux 2.3.x. The API should - remain unchanged when this is done, but support will then be - available for IPX, compression and other PPP features - - - - Known Bugs And Assumptions - - - PPP is minimal - - - The current PPP implementation is very basic, although sufficient - for most wan usages. - - - - Cisco HDLC Quirks - - - Currently we do not end all packets with the correct Cisco multicast - or unicast flags. Nothing appears to mind too much but this should - be corrected. - - - - - - - - - Public Functions Provided -!Edrivers/net/wan/syncppp.c - - -
diff --git a/Documentation/RCU/rculist_nulls.txt b/Documentation/RCU/rculist_nulls.txt new file mode 100644 index 0000000000000000000000000000000000000000..239f542d48baa9425f29a54b6b43f00468d986c2 --- /dev/null +++ b/Documentation/RCU/rculist_nulls.txt @@ -0,0 +1,167 @@ +Using hlist_nulls to protect read-mostly linked lists and +objects using SLAB_DESTROY_BY_RCU allocations. + +Please read the basics in Documentation/RCU/listRCU.txt + +Using special makers (called 'nulls') is a convenient way +to solve following problem : + +A typical RCU linked list managing objects which are +allocated with SLAB_DESTROY_BY_RCU kmem_cache can +use following algos : + +1) Lookup algo +-------------- +rcu_read_lock() +begin: +obj = lockless_lookup(key); +if (obj) { + if (!try_get_ref(obj)) // might fail for free objects + goto begin; + /* + * Because a writer could delete object, and a writer could + * reuse these object before the RCU grace period, we + * must check key after geting the reference on object + */ + if (obj->key != key) { // not the object we expected + put_ref(obj); + goto begin; + } +} +rcu_read_unlock(); + +Beware that lockless_lookup(key) cannot use traditional hlist_for_each_entry_rcu() +but a version with an additional memory barrier (smp_rmb()) + +lockless_lookup(key) +{ + struct hlist_node *node, *next; + for (pos = rcu_dereference((head)->first); + pos && ({ next = pos->next; smp_rmb(); prefetch(next); 1; }) && + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; }); + pos = rcu_dereference(next)) + if (obj->key == key) + return obj; + return NULL; + +And note the traditional hlist_for_each_entry_rcu() misses this smp_rmb() : + + struct hlist_node *node; + for (pos = rcu_dereference((head)->first); + pos && ({ prefetch(pos->next); 1; }) && + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; }); + pos = rcu_dereference(pos->next)) + if (obj->key == key) + return obj; + return NULL; +} + +Quoting Corey Minyard : + +"If the object is moved from one list to another list in-between the + time the hash is calculated and the next field is accessed, and the + object has moved to the end of a new list, the traversal will not + complete properly on the list it should have, since the object will + be on the end of the new list and there's not a way to tell it's on a + new list and restart the list traversal. I think that this can be + solved by pre-fetching the "next" field (with proper barriers) before + checking the key." + +2) Insert algo : +---------------- + +We need to make sure a reader cannot read the new 'obj->obj_next' value +and previous value of 'obj->key'. Or else, an item could be deleted +from a chain, and inserted into another chain. If new chain was empty +before the move, 'next' pointer is NULL, and lockless reader can +not detect it missed following items in original chain. + +/* + * Please note that new inserts are done at the head of list, + * not in the middle or end. + */ +obj = kmem_cache_alloc(...); +lock_chain(); // typically a spin_lock() +obj->key = key; +atomic_inc(&obj->refcnt); +/* + * we need to make sure obj->key is updated before obj->next + */ +smp_wmb(); +hlist_add_head_rcu(&obj->obj_node, list); +unlock_chain(); // typically a spin_unlock() + + +3) Remove algo +-------------- +Nothing special here, we can use a standard RCU hlist deletion. +But thanks to SLAB_DESTROY_BY_RCU, beware a deleted object can be reused +very very fast (before the end of RCU grace period) + +if (put_last_reference_on(obj) { + lock_chain(); // typically a spin_lock() + hlist_del_init_rcu(&obj->obj_node); + unlock_chain(); // typically a spin_unlock() + kmem_cache_free(cachep, obj); +} + + + +-------------------------------------------------------------------------- +With hlist_nulls we can avoid extra smp_rmb() in lockless_lookup() +and extra smp_wmb() in insert function. + +For example, if we choose to store the slot number as the 'nulls' +end-of-list marker for each slot of the hash table, we can detect +a race (some writer did a delete and/or a move of an object +to another chain) checking the final 'nulls' value if +the lookup met the end of chain. If final 'nulls' value +is not the slot number, then we must restart the lookup at +the begining. If the object was moved to same chain, +then the reader doesnt care : It might eventually +scan the list again without harm. + + +1) lookup algo + + head = &table[slot]; + rcu_read_lock(); +begin: + hlist_nulls_for_each_entry_rcu(obj, node, head, member) { + if (obj->key == key) { + if (!try_get_ref(obj)) // might fail for free objects + goto begin; + if (obj->key != key) { // not the object we expected + put_ref(obj); + goto begin; + } + goto out; + } +/* + * if the nulls value we got at the end of this lookup is + * not the expected one, we must restart lookup. + * We probably met an item that was moved to another chain. + */ + if (get_nulls_value(node) != slot) + goto begin; + obj = NULL; + +out: + rcu_read_unlock(); + +2) Insert function : +-------------------- + +/* + * Please note that new inserts are done at the head of list, + * not in the middle or end. + */ +obj = kmem_cache_alloc(cachep); +lock_chain(); // typically a spin_lock() +obj->key = key; +atomic_set(&obj->refcnt, 1); +/* + * insert obj in RCU way (readers might be traversing chain) + */ +hlist_nulls_add_head_rcu(&obj->obj_node, list); +unlock_chain(); // typically a spin_unlock() diff --git a/Documentation/controllers/cpuacct.txt b/Documentation/controllers/cpuacct.txt new file mode 100644 index 0000000000000000000000000000000000000000..bb775fbe43d78f6f5083f03a7986d9edf9012a05 --- /dev/null +++ b/Documentation/controllers/cpuacct.txt @@ -0,0 +1,32 @@ +CPU Accounting Controller +------------------------- + +The CPU accounting controller is used to group tasks using cgroups and +account the CPU usage of these groups of tasks. + +The CPU accounting controller supports multi-hierarchy groups. An accounting +group accumulates the CPU usage of all of its child groups and the tasks +directly present in its group. + +Accounting groups can be created by first mounting the cgroup filesystem. + +# mkdir /cgroups +# mount -t cgroup -ocpuacct none /cgroups + +With the above step, the initial or the parent accounting group +becomes visible at /cgroups. At bootup, this group includes all the +tasks in the system. /cgroups/tasks lists the tasks in this cgroup. +/cgroups/cpuacct.usage gives the CPU time (in nanoseconds) obtained by +this group which is essentially the CPU time obtained by all the tasks +in the system. + +New accounting groups can be created under the parent group /cgroups. + +# cd /cgroups +# mkdir g1 +# echo $$ > g1 + +The above steps create a new group g1 and move the current shell +process (bash) into it. CPU time consumed by this bash and its children +can be obtained from g1/cpuacct.usage and the same is accumulated in +/cgroups/cpuacct.usage also. diff --git a/Documentation/cpu-freq/user-guide.txt b/Documentation/cpu-freq/user-guide.txt index 4f3f3840320e30eaa0650e9197725b7d6e811b4e..e3443ddcfb890028cc8f1a9576a029c35d200154 100644 --- a/Documentation/cpu-freq/user-guide.txt +++ b/Documentation/cpu-freq/user-guide.txt @@ -93,10 +93,8 @@ Several "PowerBook" and "iBook2" notebooks are supported. 1.5 SuperH ---------- -The following SuperH processors are supported by cpufreq: - -SH-3 -SH-4 +All SuperH processors supporting rate rounding through the clock +framework are supported by cpufreq. 1.6 Blackfin ------------ diff --git a/Documentation/credentials.txt b/Documentation/credentials.txt new file mode 100644 index 0000000000000000000000000000000000000000..df03169782ea1811cc46ac93a82fad09aaeec8c8 --- /dev/null +++ b/Documentation/credentials.txt @@ -0,0 +1,582 @@ + ==================== + CREDENTIALS IN LINUX + ==================== + +By: David Howells + +Contents: + + (*) Overview. + + (*) Types of credentials. + + (*) File markings. + + (*) Task credentials. + + - Immutable credentials. + - Accessing task credentials. + - Accessing another task's credentials. + - Altering credentials. + - Managing credentials. + + (*) Open file credentials. + + (*) Overriding the VFS's use of credentials. + + +======== +OVERVIEW +======== + +There are several parts to the security check performed by Linux when one +object acts upon another: + + (1) Objects. + + Objects are things in the system that may be acted upon directly by + userspace programs. Linux has a variety of actionable objects, including: + + - Tasks + - Files/inodes + - Sockets + - Message queues + - Shared memory segments + - Semaphores + - Keys + + As a part of the description of all these objects there is a set of + credentials. What's in the set depends on the type of object. + + (2) Object ownership. + + Amongst the credentials of most objects, there will be a subset that + indicates the ownership of that object. This is used for resource + accounting and limitation (disk quotas and task rlimits for example). + + In a standard UNIX filesystem, for instance, this will be defined by the + UID marked on the inode. + + (3) The objective context. + + Also amongst the credentials of those objects, there will be a subset that + indicates the 'objective context' of that object. This may or may not be + the same set as in (2) - in standard UNIX files, for instance, this is the + defined by the UID and the GID marked on the inode. + + The objective context is used as part of the security calculation that is + carried out when an object is acted upon. + + (4) Subjects. + + A subject is an object that is acting upon another object. + + Most of the objects in the system are inactive: they don't act on other + objects within the system. Processes/tasks are the obvious exception: + they do stuff; they access and manipulate things. + + Objects other than tasks may under some circumstances also be subjects. + For instance an open file may send SIGIO to a task using the UID and EUID + given to it by a task that called fcntl(F_SETOWN) upon it. In this case, + the file struct will have a subjective context too. + + (5) The subjective context. + + A subject has an additional interpretation of its credentials. A subset + of its credentials forms the 'subjective context'. The subjective context + is used as part of the security calculation that is carried out when a + subject acts. + + A Linux task, for example, has the FSUID, FSGID and the supplementary + group list for when it is acting upon a file - which are quite separate + from the real UID and GID that normally form the objective context of the + task. + + (6) Actions. + + Linux has a number of actions available that a subject may perform upon an + object. The set of actions available depends on the nature of the subject + and the object. + + Actions include reading, writing, creating and deleting files; forking or + signalling and tracing tasks. + + (7) Rules, access control lists and security calculations. + + When a subject acts upon an object, a security calculation is made. This + involves taking the subjective context, the objective context and the + action, and searching one or more sets of rules to see whether the subject + is granted or denied permission to act in the desired manner on the + object, given those contexts. + + There are two main sources of rules: + + (a) Discretionary access control (DAC): + + Sometimes the object will include sets of rules as part of its + description. This is an 'Access Control List' or 'ACL'. A Linux + file may supply more than one ACL. + + A traditional UNIX file, for example, includes a permissions mask that + is an abbreviated ACL with three fixed classes of subject ('user', + 'group' and 'other'), each of which may be granted certain privileges + ('read', 'write' and 'execute' - whatever those map to for the object + in question). UNIX file permissions do not allow the arbitrary + specification of subjects, however, and so are of limited use. + + A Linux file might also sport a POSIX ACL. This is a list of rules + that grants various permissions to arbitrary subjects. + + (b) Mandatory access control (MAC): + + The system as a whole may have one or more sets of rules that get + applied to all subjects and objects, regardless of their source. + SELinux and Smack are examples of this. + + In the case of SELinux and Smack, each object is given a label as part + of its credentials. When an action is requested, they take the + subject label, the object label and the action and look for a rule + that says that this action is either granted or denied. + + +==================== +TYPES OF CREDENTIALS +==================== + +The Linux kernel supports the following types of credentials: + + (1) Traditional UNIX credentials. + + Real User ID + Real Group ID + + The UID and GID are carried by most, if not all, Linux objects, even if in + some cases it has to be invented (FAT or CIFS files for example, which are + derived from Windows). These (mostly) define the objective context of + that object, with tasks being slightly different in some cases. + + Effective, Saved and FS User ID + Effective, Saved and FS Group ID + Supplementary groups + + These are additional credentials used by tasks only. Usually, an + EUID/EGID/GROUPS will be used as the subjective context, and real UID/GID + will be used as the objective. For tasks, it should be noted that this is + not always true. + + (2) Capabilities. + + Set of permitted capabilities + Set of inheritable capabilities + Set of effective capabilities + Capability bounding set + + These are only carried by tasks. They indicate superior capabilities + granted piecemeal to a task that an ordinary task wouldn't otherwise have. + These are manipulated implicitly by changes to the traditional UNIX + credentials, but can also be manipulated directly by the capset() system + call. + + The permitted capabilities are those caps that the process might grant + itself to its effective or permitted sets through capset(). This + inheritable set might also be so constrained. + + The effective capabilities are the ones that a task is actually allowed to + make use of itself. + + The inheritable capabilities are the ones that may get passed across + execve(). + + The bounding set limits the capabilities that may be inherited across + execve(), especially when a binary is executed that will execute as UID 0. + + (3) Secure management flags (securebits). + + These are only carried by tasks. These govern the way the above + credentials are manipulated and inherited over certain operations such as + execve(). They aren't used directly as objective or subjective + credentials. + + (4) Keys and keyrings. + + These are only carried by tasks. They carry and cache security tokens + that don't fit into the other standard UNIX credentials. They are for + making such things as network filesystem keys available to the file + accesses performed by processes, without the necessity of ordinary + programs having to know about security details involved. + + Keyrings are a special type of key. They carry sets of other keys and can + be searched for the desired key. Each process may subscribe to a number + of keyrings: + + Per-thread keying + Per-process keyring + Per-session keyring + + When a process accesses a key, if not already present, it will normally be + cached on one of these keyrings for future accesses to find. + + For more information on using keys, see Documentation/keys.txt. + + (5) LSM + + The Linux Security Module allows extra controls to be placed over the + operations that a task may do. Currently Linux supports two main + alternate LSM options: SELinux and Smack. + + Both work by labelling the objects in a system and then applying sets of + rules (policies) that say what operations a task with one label may do to + an object with another label. + + (6) AF_KEY + + This is a socket-based approach to credential management for networking + stacks [RFC 2367]. It isn't discussed by this document as it doesn't + interact directly with task and file credentials; rather it keeps system + level credentials. + + +When a file is opened, part of the opening task's subjective context is +recorded in the file struct created. This allows operations using that file +struct to use those credentials instead of the subjective context of the task +that issued the operation. An example of this would be a file opened on a +network filesystem where the credentials of the opened file should be presented +to the server, regardless of who is actually doing a read or a write upon it. + + +============= +FILE MARKINGS +============= + +Files on disk or obtained over the network may have annotations that form the +objective security context of that file. Depending on the type of filesystem, +this may include one or more of the following: + + (*) UNIX UID, GID, mode; + + (*) Windows user ID; + + (*) Access control list; + + (*) LSM security label; + + (*) UNIX exec privilege escalation bits (SUID/SGID); + + (*) File capabilities exec privilege escalation bits. + +These are compared to the task's subjective security context, and certain +operations allowed or disallowed as a result. In the case of execve(), the +privilege escalation bits come into play, and may allow the resulting process +extra privileges, based on the annotations on the executable file. + + +================ +TASK CREDENTIALS +================ + +In Linux, all of a task's credentials are held in (uid, gid) or through +(groups, keys, LSM security) a refcounted structure of type 'struct cred'. +Each task points to its credentials by a pointer called 'cred' in its +task_struct. + +Once a set of credentials has been prepared and committed, it may not be +changed, barring the following exceptions: + + (1) its reference count may be changed; + + (2) the reference count on the group_info struct it points to may be changed; + + (3) the reference count on the security data it points to may be changed; + + (4) the reference count on any keyrings it points to may be changed; + + (5) any keyrings it points to may be revoked, expired or have their security + attributes changed; and + + (6) the contents of any keyrings to which it points may be changed (the whole + point of keyrings being a shared set of credentials, modifiable by anyone + with appropriate access). + +To alter anything in the cred struct, the copy-and-replace principle must be +adhered to. First take a copy, then alter the copy and then use RCU to change +the task pointer to make it point to the new copy. There are wrappers to aid +with this (see below). + +A task may only alter its _own_ credentials; it is no longer permitted for a +task to alter another's credentials. This means the capset() system call is no +longer permitted to take any PID other than the one of the current process. +Also keyctl_instantiate() and keyctl_negate() functions no longer permit +attachment to process-specific keyrings in the requesting process as the +instantiating process may need to create them. + + +IMMUTABLE CREDENTIALS +--------------------- + +Once a set of credentials has been made public (by calling commit_creds() for +example), it must be considered immutable, barring two exceptions: + + (1) The reference count may be altered. + + (2) Whilst the keyring subscriptions of a set of credentials may not be + changed, the keyrings subscribed to may have their contents altered. + +To catch accidental credential alteration at compile time, struct task_struct +has _const_ pointers to its credential sets, as does struct file. Furthermore, +certain functions such as get_cred() and put_cred() operate on const pointers, +thus rendering casts unnecessary, but require to temporarily ditch the const +qualification to be able to alter the reference count. + + +ACCESSING TASK CREDENTIALS +-------------------------- + +A task being able to alter only its own credentials permits the current process +to read or replace its own credentials without the need for any form of locking +- which simplifies things greatly. It can just call: + + const struct cred *current_cred() + +to get a pointer to its credentials structure, and it doesn't have to release +it afterwards. + +There are convenience wrappers for retrieving specific aspects of a task's +credentials (the value is simply returned in each case): + + uid_t current_uid(void) Current's real UID + gid_t current_gid(void) Current's real GID + uid_t current_euid(void) Current's effective UID + gid_t current_egid(void) Current's effective GID + uid_t current_fsuid(void) Current's file access UID + gid_t current_fsgid(void) Current's file access GID + kernel_cap_t current_cap(void) Current's effective capabilities + void *current_security(void) Current's LSM security pointer + struct user_struct *current_user(void) Current's user account + +There are also convenience wrappers for retrieving specific associated pairs of +a task's credentials: + + void current_uid_gid(uid_t *, gid_t *); + void current_euid_egid(uid_t *, gid_t *); + void current_fsuid_fsgid(uid_t *, gid_t *); + +which return these pairs of values through their arguments after retrieving +them from the current task's credentials. + + +In addition, there is a function for obtaining a reference on the current +process's current set of credentials: + + const struct cred *get_current_cred(void); + +and functions for getting references to one of the credentials that don't +actually live in struct cred: + + struct user_struct *get_current_user(void); + struct group_info *get_current_groups(void); + +which get references to the current process's user accounting structure and +supplementary groups list respectively. + +Once a reference has been obtained, it must be released with put_cred(), +free_uid() or put_group_info() as appropriate. + + +ACCESSING ANOTHER TASK'S CREDENTIALS +------------------------------------ + +Whilst a task may access its own credentials without the need for locking, the +same is not true of a task wanting to access another task's credentials. It +must use the RCU read lock and rcu_dereference(). + +The rcu_dereference() is wrapped by: + + const struct cred *__task_cred(struct task_struct *task); + +This should be used inside the RCU read lock, as in the following example: + + void foo(struct task_struct *t, struct foo_data *f) + { + const struct cred *tcred; + ... + rcu_read_lock(); + tcred = __task_cred(t); + f->uid = tcred->uid; + f->gid = tcred->gid; + f->groups = get_group_info(tcred->groups); + rcu_read_unlock(); + ... + } + +A function need not get RCU read lock to use __task_cred() if it is holding a +spinlock at the time as this implicitly holds the RCU read lock. + +Should it be necessary to hold another task's credentials for a long period of +time, and possibly to sleep whilst doing so, then the caller should get a +reference on them using: + + const struct cred *get_task_cred(struct task_struct *task); + +This does all the RCU magic inside of it. The caller must call put_cred() on +the credentials so obtained when they're finished with. + +There are a couple of convenience functions to access bits of another task's +credentials, hiding the RCU magic from the caller: + + uid_t task_uid(task) Task's real UID + uid_t task_euid(task) Task's effective UID + +If the caller is holding a spinlock or the RCU read lock at the time anyway, +then: + + __task_cred(task)->uid + __task_cred(task)->euid + +should be used instead. Similarly, if multiple aspects of a task's credentials +need to be accessed, RCU read lock or a spinlock should be used, __task_cred() +called, the result stored in a temporary pointer and then the credential +aspects called from that before dropping the lock. This prevents the +potentially expensive RCU magic from being invoked multiple times. + +Should some other single aspect of another task's credentials need to be +accessed, then this can be used: + + task_cred_xxx(task, member) + +where 'member' is a non-pointer member of the cred struct. For instance: + + uid_t task_cred_xxx(task, suid); + +will retrieve 'struct cred::suid' from the task, doing the appropriate RCU +magic. This may not be used for pointer members as what they point to may +disappear the moment the RCU read lock is dropped. + + +ALTERING CREDENTIALS +-------------------- + +As previously mentioned, a task may only alter its own credentials, and may not +alter those of another task. This means that it doesn't need to use any +locking to alter its own credentials. + +To alter the current process's credentials, a function should first prepare a +new set of credentials by calling: + + struct cred *prepare_creds(void); + +this locks current->cred_replace_mutex and then allocates and constructs a +duplicate of the current process's credentials, returning with the mutex still +held if successful. It returns NULL if not successful (out of memory). + +The mutex prevents ptrace() from altering the ptrace state of a process whilst +security checks on credentials construction and changing is taking place as +the ptrace state may alter the outcome, particularly in the case of execve(). + +The new credentials set should be altered appropriately, and any security +checks and hooks done. Both the current and the proposed sets of credentials +are available for this purpose as current_cred() will return the current set +still at this point. + + +When the credential set is ready, it should be committed to the current process +by calling: + + int commit_creds(struct cred *new); + +This will alter various aspects of the credentials and the process, giving the +LSM a chance to do likewise, then it will use rcu_assign_pointer() to actually +commit the new credentials to current->cred, it will release +current->cred_replace_mutex to allow ptrace() to take place, and it will notify +the scheduler and others of the changes. + +This function is guaranteed to return 0, so that it can be tail-called at the +end of such functions as sys_setresuid(). + +Note that this function consumes the caller's reference to the new credentials. +The caller should _not_ call put_cred() on the new credentials afterwards. + +Furthermore, once this function has been called on a new set of credentials, +those credentials may _not_ be changed further. + + +Should the security checks fail or some other error occur after prepare_creds() +has been called, then the following function should be invoked: + + void abort_creds(struct cred *new); + +This releases the lock on current->cred_replace_mutex that prepare_creds() got +and then releases the new credentials. + + +A typical credentials alteration function would look something like this: + + int alter_suid(uid_t suid) + { + struct cred *new; + int ret; + + new = prepare_creds(); + if (!new) + return -ENOMEM; + + new->suid = suid; + ret = security_alter_suid(new); + if (ret < 0) { + abort_creds(new); + return ret; + } + + return commit_creds(new); + } + + +MANAGING CREDENTIALS +-------------------- + +There are some functions to help manage credentials: + + (*) void put_cred(const struct cred *cred); + + This releases a reference to the given set of credentials. If the + reference count reaches zero, the credentials will be scheduled for + destruction by the RCU system. + + (*) const struct cred *get_cred(const struct cred *cred); + + This gets a reference on a live set of credentials, returning a pointer to + that set of credentials. + + (*) struct cred *get_new_cred(struct cred *cred); + + This gets a reference on a set of credentials that is under construction + and is thus still mutable, returning a pointer to that set of credentials. + + +===================== +OPEN FILE CREDENTIALS +===================== + +When a new file is opened, a reference is obtained on the opening task's +credentials and this is attached to the file struct as 'f_cred' in place of +'f_uid' and 'f_gid'. Code that used to access file->f_uid and file->f_gid +should now access file->f_cred->fsuid and file->f_cred->fsgid. + +It is safe to access f_cred without the use of RCU or locking because the +pointer will not change over the lifetime of the file struct, and nor will the +contents of the cred struct pointed to, barring the exceptions listed above +(see the Task Credentials section). + + +======================================= +OVERRIDING THE VFS'S USE OF CREDENTIALS +======================================= + +Under some circumstances it is desirable to override the credentials used by +the VFS, and that can be done by calling into such as vfs_mkdir() with a +different set of credentials. This is done in the following places: + + (*) sys_faccessat(). + + (*) do_coredump(). + + (*) nfs4recover.c. diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index c28a2ac88f9d9ed1457ab0c04324e3cf20fe986f..dc7c681e532cacf9fbf9ec0f692e9fb2bd5740e7 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -120,13 +120,6 @@ Who: Christoph Hellwig --------------------------- -What: eepro100 network driver -When: January 2007 -Why: replaced by the e100 driver -Who: Adrian Bunk - ---------------------------- - What: Unused EXPORT_SYMBOL/EXPORT_SYMBOL_GPL exports (temporary transition config option provided until then) The transition config option will also be removed at the same time. @@ -244,18 +237,6 @@ Who: Michael Buesch --------------------------- -What: init_mm export -When: 2.6.26 -Why: Not used in-tree. The current out-of-tree users used it to - work around problems in the CPA code which should be resolved - by now. One usecase was described to provide verification code - of the CPA operation. That's a good idea in general, but such - code / infrastructure should be in the kernel and not in some - out-of-tree driver. -Who: Thomas Gleixner - ----------------------------- - What: usedac i386 kernel parameter When: 2.6.27 Why: replaced by allowdac and no dac combination diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index bb1b0dd3bfcbcc919bea2fbdf706607608f915c5..71df353e367c9e8c3f2833fe7114c875a6d49d3b 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt @@ -1339,10 +1339,13 @@ nmi_watchdog Enables/Disables the NMI watchdog on x86 systems. When the value is non-zero the NMI watchdog is enabled and will continuously test all online cpus to -determine whether or not they are still functioning properly. +determine whether or not they are still functioning properly. Currently, +passing "nmi_watchdog=" parameter at boot time is required for this function +to work. -Because the NMI watchdog shares registers with oprofile, by disabling the NMI -watchdog, oprofile may have more registers to utilize. +If LAPIC NMI watchdog method is in use (nmi_watchdog=2 kernel parameter), the +NMI watchdog shares registers with oprofile. By disabling the NMI watchdog, +oprofile may have more registers to utilize. msgmni ------ diff --git a/Documentation/ftrace.txt b/Documentation/ftrace.txt index 9cc4d685dde583464cbfbd9c7448358c2de90ef3..803b1318b13da11242a3558123d28293d3ee4378 100644 --- a/Documentation/ftrace.txt +++ b/Documentation/ftrace.txt @@ -82,7 +82,7 @@ of ftrace. Here is a list of some of the key files: tracer is not adding more data, they will display the same information every time they are read. - iter_ctrl: This file lets the user control the amount of data + trace_options: This file lets the user control the amount of data that is displayed in one of the above output files. @@ -94,10 +94,10 @@ of ftrace. Here is a list of some of the key files: only be recorded if the latency is greater than the value in this file. (in microseconds) - trace_entries: This sets or displays the number of bytes each CPU + buffer_size_kb: This sets or displays the number of kilobytes each CPU buffer can hold. The tracer buffers are the same size for each CPU. The displayed number is the size of the - CPU buffer and not total size of all buffers. The + CPU buffer and not total size of all buffers. The trace buffers are allocated in pages (blocks of memory that the kernel uses for allocation, usually 4 KB in size). If the last page allocated has room for more bytes @@ -127,6 +127,8 @@ of ftrace. Here is a list of some of the key files: be traced. If a function exists in both set_ftrace_filter and set_ftrace_notrace, the function will _not_ be traced. + set_ftrace_pid: Have the function tracer only trace a single thread. + available_filter_functions: This lists the functions that ftrace has processed and can trace. These are the function names that you can pass to "set_ftrace_filter" or @@ -316,23 +318,23 @@ The above is mostly meaningful for kernel developers. The rest is the same as the 'trace' file. -iter_ctrl ---------- +trace_options +------------- -The iter_ctrl file is used to control what gets printed in the trace +The trace_options file is used to control what gets printed in the trace output. To see what is available, simply cat the file: - cat /debug/tracing/iter_ctrl + cat /debug/tracing/trace_options print-parent nosym-offset nosym-addr noverbose noraw nohex nobin \ - noblock nostacktrace nosched-tree + noblock nostacktrace nosched-tree nouserstacktrace nosym-userobj To disable one of the options, echo in the option prepended with "no". - echo noprint-parent > /debug/tracing/iter_ctrl + echo noprint-parent > /debug/tracing/trace_options To enable an option, leave off the "no". - echo sym-offset > /debug/tracing/iter_ctrl + echo sym-offset > /debug/tracing/trace_options Here are the available options: @@ -378,6 +380,20 @@ Here are the available options: When a trace is recorded, so is the stack of functions. This allows for back traces of trace sites. + userstacktrace - This option changes the trace. + It records a stacktrace of the current userspace thread. + + sym-userobj - when user stacktrace are enabled, look up which object the + address belongs to, and print a relative address + This is especially useful when ASLR is on, otherwise you don't + get a chance to resolve the address to object/file/line after the app is no + longer running + + The lookup is performed when you read trace,trace_pipe,latency_trace. Example: + + a.out-1623 [000] 40874.465068: /root/a.out[+0x480] <-/root/a.out[+0 +x494] <- /root/a.out[+0x4a8] <- /lib/libc-2.7.so[+0x1e1a6] + sched-tree - TBD (any users??) @@ -1059,6 +1075,83 @@ For simple one time traces, the above is sufficent. For anything else, a search through /proc/mounts may be needed to find where the debugfs file-system is mounted. + +Single thread tracing +--------------------- + +By writing into /debug/tracing/set_ftrace_pid you can trace a +single thread. For example: + +# cat /debug/tracing/set_ftrace_pid +no pid +# echo 3111 > /debug/tracing/set_ftrace_pid +# cat /debug/tracing/set_ftrace_pid +3111 +# echo function > /debug/tracing/current_tracer +# cat /debug/tracing/trace | head + # tracer: function + # + # TASK-PID CPU# TIMESTAMP FUNCTION + # | | | | | + yum-updatesd-3111 [003] 1637.254676: finish_task_switch <-thread_return + yum-updatesd-3111 [003] 1637.254681: hrtimer_cancel <-schedule_hrtimeout_range + yum-updatesd-3111 [003] 1637.254682: hrtimer_try_to_cancel <-hrtimer_cancel + yum-updatesd-3111 [003] 1637.254683: lock_hrtimer_base <-hrtimer_try_to_cancel + yum-updatesd-3111 [003] 1637.254685: fget_light <-do_sys_poll + yum-updatesd-3111 [003] 1637.254686: pipe_poll <-do_sys_poll +# echo -1 > /debug/tracing/set_ftrace_pid +# cat /debug/tracing/trace |head + # tracer: function + # + # TASK-PID CPU# TIMESTAMP FUNCTION + # | | | | | + ##### CPU 3 buffer started #### + yum-updatesd-3111 [003] 1701.957688: free_poll_entry <-poll_freewait + yum-updatesd-3111 [003] 1701.957689: remove_wait_queue <-free_poll_entry + yum-updatesd-3111 [003] 1701.957691: fput <-free_poll_entry + yum-updatesd-3111 [003] 1701.957692: audit_syscall_exit <-sysret_audit + yum-updatesd-3111 [003] 1701.957693: path_put <-audit_syscall_exit + +If you want to trace a function when executing, you could use +something like this simple program: + +#include +#include +#include +#include +#include +#include + +int main (int argc, char **argv) +{ + if (argc < 1) + exit(-1); + + if (fork() > 0) { + int fd, ffd; + char line[64]; + int s; + + ffd = open("/debug/tracing/current_tracer", O_WRONLY); + if (ffd < 0) + exit(-1); + write(ffd, "nop", 3); + + fd = open("/debug/tracing/set_ftrace_pid", O_WRONLY); + s = sprintf(line, "%d\n", getpid()); + write(fd, line, s); + + write(ffd, "function", 8); + + close(fd); + close(ffd); + + execvp(argv[1], argv+1); + } + + return 0; +} + dynamic ftrace -------------- @@ -1158,7 +1251,11 @@ These are the only wild cards which are supported. * will not work. - # echo hrtimer_* > /debug/tracing/set_ftrace_filter +Note: It is better to use quotes to enclose the wild cards, otherwise + the shell may expand the parameters into names of files in the local + directory. + + # echo 'hrtimer_*' > /debug/tracing/set_ftrace_filter Produces: @@ -1213,7 +1310,7 @@ Again, now we want to append. # echo sys_nanosleep > /debug/tracing/set_ftrace_filter # cat /debug/tracing/set_ftrace_filter sys_nanosleep - # echo hrtimer_* >> /debug/tracing/set_ftrace_filter + # echo 'hrtimer_*' >> /debug/tracing/set_ftrace_filter # cat /debug/tracing/set_ftrace_filter hrtimer_run_queues hrtimer_run_pending @@ -1299,41 +1396,29 @@ trace entries ------------- Having too much or not enough data can be troublesome in diagnosing -an issue in the kernel. The file trace_entries is used to modify +an issue in the kernel. The file buffer_size_kb is used to modify the size of the internal trace buffers. The number listed is the number of entries that can be recorded per CPU. To know the full size, multiply the number of possible CPUS with the number of entries. - # cat /debug/tracing/trace_entries -65620 + # cat /debug/tracing/buffer_size_kb +1408 (units kilobytes) Note, to modify this, you must have tracing completely disabled. To do that, echo "nop" into the current_tracer. If the current_tracer is not set to "nop", an EINVAL error will be returned. # echo nop > /debug/tracing/current_tracer - # echo 100000 > /debug/tracing/trace_entries - # cat /debug/tracing/trace_entries -100045 - - -Notice that we echoed in 100,000 but the size is 100,045. The entries -are held in individual pages. It allocates the number of pages it takes -to fulfill the request. If more entries may fit on the last page -then they will be added. - - # echo 1 > /debug/tracing/trace_entries - # cat /debug/tracing/trace_entries -85 - -This shows us that 85 entries can fit in a single page. + # echo 10000 > /debug/tracing/buffer_size_kb + # cat /debug/tracing/buffer_size_kb +10000 (units kilobytes) The number of pages which will be allocated is limited to a percentage of available memory. Allocating too much will produce an error. - # echo 1000000000000 > /debug/tracing/trace_entries + # echo 1000000000000 > /debug/tracing/buffer_size_kb -bash: echo: write error: Cannot allocate memory - # cat /debug/tracing/trace_entries + # cat /debug/tracing/buffer_size_kb 85 diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt index 7a7753321a263f62c2a00c9d0e348716e701ac2c..51104f9194a54feb64058f4b8f35f3b4d7cbc88f 100644 --- a/Documentation/kbuild/makefiles.txt +++ b/Documentation/kbuild/makefiles.txt @@ -383,6 +383,20 @@ more details, with real examples. to prerequisites are referenced with $(src) (because they are not generated files). + $(kecho) + echoing information to user in a rule is often a good practice + but when execution "make -s" one does not expect to see any output + except for warnings/errors. + To support this kbuild define $(kecho) which will echo out the + text following $(kecho) to stdout except if "make -s" is used. + + Example: + #arch/blackfin/boot/Makefile + $(obj)/vmImage: $(obj)/vmlinux.gz + $(call if_changed,uimage) + @$(kecho) 'Kernel: $@ is ready' + + --- 3.11 $(CC) support functions The kernel may be built with several different versions of diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index e0f346d201edb70fae654c55f6be842c4465a5ff..a2d8805c03d5588f317a9677add758c94051e6a6 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -89,6 +89,7 @@ parameter is applicable: SPARC Sparc architecture is enabled. SWSUSP Software suspend (hibernation) is enabled. SUSPEND System suspend states are enabled. + FTRACE Function tracing enabled. TS Appropriate touchscreen support is enabled. USB USB support is enabled. USBHID USB Human Interface Device support is enabled. @@ -220,14 +221,17 @@ and is between 256 and 4096 characters. It is defined in the file Bits in debug_level correspond to a level in ACPI_DEBUG_PRINT statements, e.g., ACPI_DEBUG_PRINT((ACPI_DB_INFO, ... - See Documentation/acpi/debug.txt for more information - about debug layers and levels. + The debug_level mask defaults to "info". See + Documentation/acpi/debug.txt for more information about + debug layers and levels. + Enable processor driver info messages: + acpi.debug_layer=0x20000000 + Enable PCI/PCI interrupt routing info messages: + acpi.debug_layer=0x400000 Enable AML "Debug" output, i.e., stores to the Debug object while interpreting AML: acpi.debug_layer=0xffffffff acpi.debug_level=0x2 - Enable PCI/PCI interrupt routing info messages: - acpi.debug_layer=0x400000 acpi.debug_level=0x4 Enable all messages related to ACPI hardware: acpi.debug_layer=0x2 acpi.debug_level=0xffffffff @@ -750,6 +754,14 @@ and is between 256 and 4096 characters. It is defined in the file parameter will force ia64_sal_cache_flush to call ia64_pal_cache_flush instead of SAL_CACHE_FLUSH. + ftrace=[tracer] + [ftrace] will set and start the specified tracer + as early as possible in order to facilitate early + boot debugging. + + ftrace_dump_on_oops + [ftrace] will dump the trace buffers on oops. + gamecon.map[2|3]= [HW,JOY] Multisystem joystick and NES/SNES/PSX pad support via parallel port (up to 5 devices per port) @@ -811,6 +823,9 @@ and is between 256 and 4096 characters. It is defined in the file hlt [BUGS=ARM,SH] + hvc_iucv= [S390] Number of z/VM IUCV Hypervisor console (HVC) + back-ends. Valid parameters: 0..8 + i8042.debug [HW] Toggle i8042 debug mode i8042.direct [HW] Put keyboard port into non-translated mode i8042.dumbkbd [HW] Pretend that controller can only read data from @@ -1393,7 +1408,20 @@ and is between 256 and 4096 characters. It is defined in the file when a NMI is triggered. Format: [state][,regs][,debounce][,die] - nmi_watchdog= [KNL,BUGS=X86-32] Debugging features for SMP kernels + nmi_watchdog= [KNL,BUGS=X86-32,X86-64] Debugging features for SMP kernels + Format: [panic,][num] + Valid num: 0,1,2 + 0 - turn nmi_watchdog off + 1 - use the IO-APIC timer for the NMI watchdog + 2 - use the local APIC for the NMI watchdog using + a performance counter. Note: This will use one performance + counter and the local APIC's performance vector. + When panic is specified panic when an NMI watchdog timeout occurs. + This is useful when you use a panic=... timeout and need the box + quickly up again. + Instead of 1 and 2 it is possible to use the following + symbolic names: lapic and ioapic + Example: nmi_watchdog=2 or nmi_watchdog=panic,lapic no387 [BUGS=X86-32] Tells the kernel to use the 387 maths emulation library even if a 387 maths coprocessor @@ -1449,6 +1477,10 @@ and is between 256 and 4096 characters. It is defined in the file instruction doesn't work correctly and not to use it. + no_file_caps Tells the kernel not to honor file capabilities. The + only way then for a file to be executed with privilege + is to be setuid root or executed by root. + nohalt [IA-64] Tells the kernel not to use the power saving function PAL_HALT_LIGHT when idle. This increases power-consumption. On the positive side, it reduces @@ -1626,6 +1658,17 @@ and is between 256 and 4096 characters. It is defined in the file nomsi [MSI] If the PCI_MSI kernel config parameter is enabled, this kernel boot option can be used to disable the use of MSI interrupts system-wide. + noioapicquirk [APIC] Disable all boot interrupt quirks. + Safety option to keep boot IRQs enabled. This + should never be necessary. + ioapicreroute [APIC] Enable rerouting of boot IRQs to the + primary IO-APIC for bridges that cannot disable + boot IRQs. This fixes a source of spurious IRQs + when the system masks IRQs. + noioapicreroute [APIC] Disable workaround that uses the + boot IRQ equivalent of an IRQ that connects to + a chipset where boot IRQs cannot be disabled. + The opposite of ioapicreroute. biosirq [X86-32] Use PCI BIOS calls to get the interrupt routing table. These calls are known to be buggy on several machines and they hang the machine @@ -2165,6 +2208,9 @@ and is between 256 and 4096 characters. It is defined in the file st= [HW,SCSI] SCSI tape parameters (buffers, etc.) See Documentation/scsi/st.txt. + stacktrace [FTRACE] + Enabled the stack tracer on boot up. + sti= [PARISC,HW] Format: Set the STI (builtin display/keyboard on the HP-PARISC @@ -2249,12 +2295,27 @@ and is between 256 and 4096 characters. It is defined in the file See comment before function dc390_setup() in drivers/scsi/tmscsim.c. + topology= [S390] + Format: {off | on} + Specify if the kernel should make use of the cpu + topology informations if the hardware supports these. + The scheduler will make use of these informations and + e.g. base its process migration decisions on it. + Default is off. + tp720= [HW,PS2] trix= [HW,OSS] MediaTrix AudioTrix Pro Format: ,,,,,,,, + tsc= Disable clocksource-must-verify flag for TSC. + Format: + [x86] reliable: mark tsc clocksource as reliable, this + disables clocksource verification at runtime. + Used to enable high-resolution timer mode on older + hardware, and in virtualized environment. + turbografx.map[2|3]= [HW,JOY] TurboGraFX parallel port interface Format: diff --git a/Documentation/markers.txt b/Documentation/markers.txt index 089f6138fcd94249a6444ca3a932a50c263098e1..d2b3d0e91b26d21423d8202668ac8d512558e7dd 100644 --- a/Documentation/markers.txt +++ b/Documentation/markers.txt @@ -51,11 +51,16 @@ to call) for the specific marker through marker_probe_register() and can be activated by calling marker_arm(). Marker deactivation can be done by calling marker_disarm() as many times as marker_arm() has been called. Removing a probe is done through marker_probe_unregister(); it will disarm the probe. -marker_synchronize_unregister() must be called before the end of the module exit -function to make sure there is no caller left using the probe. This, and the -fact that preemption is disabled around the probe call, make sure that probe -removal and module unload are safe. See the "Probe example" section below for a -sample probe module. + +marker_synchronize_unregister() must be called between probe unregistration and +the first occurrence of +- the end of module exit function, + to make sure there is no caller left using the probe; +- the free of any resource used by the probes, + to make sure the probes wont be accessing invalid data. +This, and the fact that preemption is disabled around the probe call, make sure +that probe removal and module unload are safe. See the "Probe example" section +below for a sample probe module. The marker mechanism supports inserting multiple instances of the same marker. Markers can be put in inline functions, inlined static functions, and @@ -70,6 +75,20 @@ a printk warning which identifies the inconsistency: "Format mismatch for probe probe_name (format), marker (format)" +Another way to use markers is to simply define the marker without generating any +function call to actually call into the marker. This is useful in combination +with tracepoint probes in a scheme like this : + +void probe_tracepoint_name(unsigned int arg1, struct task_struct *tsk); + +DEFINE_MARKER_TP(marker_eventname, tracepoint_name, probe_tracepoint_name, + "arg1 %u pid %d"); + +notrace void probe_tracepoint_name(unsigned int arg1, struct task_struct *tsk) +{ + struct marker *marker = &GET_MARKER(kernel_irq_entry); + /* write data to trace buffers ... */ +} * Probe / marker example diff --git a/Documentation/networking/README.ipw2200 b/Documentation/networking/README.ipw2200 index 4f2a40f1dbc629837463a96695759e3848f41c68..80c728522c4c7a0482d1804689f87869d9c404c0 100644 --- a/Documentation/networking/README.ipw2200 +++ b/Documentation/networking/README.ipw2200 @@ -147,7 +147,7 @@ Where the supported parameter are: driver. If disabled, the driver will not attempt to scan for and associate to a network until it has been configured with one or more properties for the target network, for example configuring - the network SSID. Default is 1 (auto-associate) + the network SSID. Default is 0 (do not auto-associate) Example: % modprobe ipw2200 associate=0 diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt index 688dfe1e6b70f75a36d84f30dda2234c53664be0..5ede7473b4251e43e53c5053e144cf12f3d6032a 100644 --- a/Documentation/networking/bonding.txt +++ b/Documentation/networking/bonding.txt @@ -194,6 +194,48 @@ or, for backwards compatibility, the option value. E.g., The parameters are as follows: +ad_select + + Specifies the 802.3ad aggregation selection logic to use. The + possible values and their effects are: + + stable or 0 + + The active aggregator is chosen by largest aggregate + bandwidth. + + Reselection of the active aggregator occurs only when all + slaves of the active aggregator are down or the active + aggregator has no slaves. + + This is the default value. + + bandwidth or 1 + + The active aggregator is chosen by largest aggregate + bandwidth. Reselection occurs if: + + - A slave is added to or removed from the bond + + - Any slave's link state changes + + - Any slave's 802.3ad association state changes + + - The bond's adminstrative state changes to up + + count or 2 + + The active aggregator is chosen by the largest number of + ports (slaves). Reselection occurs as described under the + "bandwidth" setting, above. + + The bandwidth and count selection policies permit failover of + 802.3ad aggregations when partial failure of the active aggregator + occurs. This keeps the aggregator with the highest availability + (either in bandwidth or in number of ports) active at all times. + + This option was added in bonding version 3.4.0. + arp_interval Specifies the ARP link monitoring frequency in milliseconds. @@ -551,6 +593,16 @@ num_grat_arp affects only the active-backup mode. This option was added for bonding version 3.3.0. +num_unsol_na + + Specifies the number of unsolicited IPv6 Neighbor Advertisements + to be issued after a failover event. One unsolicited NA is issued + immediately after the failover. + + The valid range is 0 - 255; the default value is 1. This option + affects only the active-backup mode. This option was added for + bonding version 3.4.0. + primary A string (eth0, eth2, etc) specifying which slave is the @@ -922,17 +974,19 @@ USERCTL=no NETMASK, NETWORK and BROADCAST) to match your network configuration. For later versions of initscripts, such as that found with Fedora -7 and Red Hat Enterprise Linux version 5 (or later), it is possible, and, -indeed, preferable, to specify the bonding options in the ifcfg-bond0 +7 (or later) and Red Hat Enterprise Linux version 5 (or later), it is possible, +and, indeed, preferable, to specify the bonding options in the ifcfg-bond0 file, e.g. a line of the format: -BONDING_OPTS="mode=active-backup arp_interval=60 arp_ip_target=+192.168.1.254" +BONDING_OPTS="mode=active-backup arp_interval=60 arp_ip_target=192.168.1.254" will configure the bond with the specified options. The options specified in BONDING_OPTS are identical to the bonding module parameters -except for the arp_ip_target field. Each target should be included as a -separate option and should be preceded by a '+' to indicate it should be -added to the list of queried targets, e.g., +except for the arp_ip_target field when using versions of initscripts older +than and 8.57 (Fedora 8) and 8.45.19 (Red Hat Enterprise Linux 5.2). When +using older versions each target should be included as a separate option and +should be preceded by a '+' to indicate it should be added to the list of +queried targets, e.g., arp_ip_target=+192.168.1.1 arp_ip_target=+192.168.1.2 @@ -940,7 +994,7 @@ added to the list of queried targets, e.g., options via BONDING_OPTS, it is not necessary to edit /etc/modules.conf or /etc/modprobe.conf. - For older versions of initscripts that do not support + For even older versions of initscripts that do not support BONDING_OPTS, it is necessary to edit /etc/modules.conf (or /etc/modprobe.conf, depending upon your distro) to load the bonding module with your desired options when the bond0 interface is brought up. The diff --git a/Documentation/networking/dccp.txt b/Documentation/networking/dccp.txt index 39131a3c78f8826bb9949ddf25ff50e591904028..7a3bb1abb8304a1fe7222e354e43164a7a7635bb 100644 --- a/Documentation/networking/dccp.txt +++ b/Documentation/networking/dccp.txt @@ -57,6 +57,24 @@ can be set before calling bind(). DCCP_SOCKOPT_GET_CUR_MPS is read-only and retrieves the current maximum packet size (application payload size) in bytes, see RFC 4340, section 14. +DCCP_SOCKOPT_AVAILABLE_CCIDS is also read-only and returns the list of CCIDs +supported by the endpoint (see include/linux/dccp.h for symbolic constants). +The caller needs to provide a sufficiently large (> 2) array of type uint8_t. + +DCCP_SOCKOPT_CCID is write-only and sets both the TX and RX CCIDs at the same +time, combining the operation of the next two socket options. This option is +preferrable over the latter two, since often applications will use the same +type of CCID for both directions; and mixed use of CCIDs is not currently well +understood. This socket option takes as argument at least one uint8_t value, or +an array of uint8_t values, which must match available CCIDS (see above). CCIDs +must be registered on the socket before calling connect() or listen(). + +DCCP_SOCKOPT_TX_CCID is read/write. It returns the current CCID (if set) or sets +the preference list for the TX CCID, using the same format as DCCP_SOCKOPT_CCID. +Please note that the getsockopt argument type here is `int', not uint8_t. + +DCCP_SOCKOPT_RX_CCID is analogous to DCCP_SOCKOPT_TX_CCID, but for the RX CCID. + DCCP_SOCKOPT_SERVER_TIMEWAIT enables the server (listening socket) to hold timewait state when closing the connection (RFC 4340, 8.3). The usual case is that the closing server sends a CloseReq, whereupon the client holds timewait @@ -115,20 +133,12 @@ retries2 importance for retransmitted acknowledgments and feature negotiation, data packets are never retransmitted. Analogue of tcp_retries2. -send_ndp = 1 - Whether or not to send NDP count options (sec. 7.7.2). - -send_ackvec = 1 - Whether or not to send Ack Vector options (sec. 11.5). - -ack_ratio = 2 - The default Ack Ratio (sec. 11.3) to use. - tx_ccid = 2 - Default CCID for the sender-receiver half-connection. + Default CCID for the sender-receiver half-connection. Depending on the + choice of CCID, the Send Ack Vector feature is enabled automatically. rx_ccid = 2 - Default CCID for the receiver-sender half-connection. + Default CCID for the receiver-sender half-connection; see tx_ccid. seq_window = 100 The initial sequence window (sec. 7.5.2). diff --git a/Documentation/networking/driver.txt b/Documentation/networking/driver.txt index ea72d2e66ca81a62fa493b695ed0e5cf94fc92a4..03283daa64fef72360667fb979a256aa10a3bb91 100644 --- a/Documentation/networking/driver.txt +++ b/Documentation/networking/driver.txt @@ -13,7 +13,7 @@ Transmit path guidelines: static int drv_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct drv *dp = dev->priv; + struct drv *dp = netdev_priv(dev); lock_tx(dp); ... diff --git a/Documentation/networking/generic-hdlc.txt b/Documentation/networking/generic-hdlc.txt index 31bc8b759b755e03875426f3678e92e86a022b33..4eb3cc40b702e33d7fa6f059555a2d7876c7a981 100644 --- a/Documentation/networking/generic-hdlc.txt +++ b/Documentation/networking/generic-hdlc.txt @@ -3,15 +3,15 @@ Krzysztof Halasa Generic HDLC layer currently supports: -1. Frame Relay (ANSI, CCITT, Cisco and no LMI). +1. Frame Relay (ANSI, CCITT, Cisco and no LMI) - Normal (routed) and Ethernet-bridged (Ethernet device emulation) interfaces can share a single PVC. - ARP support (no InARP support in the kernel - there is an experimental InARP user-space daemon available on: http://www.kernel.org/pub/linux/utils/net/hdlc/). -2. raw HDLC - either IP (IPv4) interface or Ethernet device emulation. -3. Cisco HDLC. -4. PPP (uses syncppp.c). +2. raw HDLC - either IP (IPv4) interface or Ethernet device emulation +3. Cisco HDLC +4. PPP 5. X.25 (uses X.25 routines). Generic HDLC is a protocol driver only - it needs a low-level driver diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index d84932650fd3e926cc11d5fa0bcaee6cc8a8cd33..c7712787933c1734c98a0191db23d9cb2886d0f8 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -27,6 +27,12 @@ min_adv_mss - INTEGER The advertised MSS depends on the first hop route MTU, but will never be lower than this setting. +rt_cache_rebuild_count - INTEGER + The per net-namespace route cache emergency rebuild threshold. + Any net-namespace having its route cache rebuilt due to + a hash bucket chain being too long more than this many times + will have its route caching disabled + IP Fragmentation: ipfrag_high_thresh - INTEGER diff --git a/Documentation/networking/mac80211_hwsim/README b/Documentation/networking/mac80211_hwsim/README index 2ff8ccb8dc3715dd343c5229b8c6ded98dde7d03..24ac91d56698d626fb266556c5b0c3b9fd212fa9 100644 --- a/Documentation/networking/mac80211_hwsim/README +++ b/Documentation/networking/mac80211_hwsim/README @@ -50,10 +50,6 @@ associates with the AP. hostapd and wpa_supplicant are used to take care of WPA2-PSK authentication. In addition, hostapd is also processing access point side of association. -Please note that the current Linux kernel does not enable AP mode, so a -simple patch is needed to enable AP mode selection: -http://johannes.sipsolutions.net/patches/kernel/all/LATEST/006-allow-ap-vlan-modes.patch - # Build mac80211_hwsim as part of kernel configuration @@ -65,3 +61,8 @@ hostapd hostapd.conf # Run wpa_supplicant (station) for wlan1 wpa_supplicant -Dwext -iwlan1 -c wpa_supplicant.conf + + +More test cases are available in hostap.git: +git://w1.fi/srv/git/hostap.git and mac80211_hwsim/tests subdirectory +(http://w1.fi/gitweb/gitweb.cgi?p=hostap.git;a=tree;f=mac80211_hwsim/tests) diff --git a/Documentation/networking/netdevices.txt b/Documentation/networking/netdevices.txt index d0f71fc7f7829b1dfb9dfc689afe0978bec53c76..a2ab6a0b116d96ff8e6198154d5f455cac2fec5e 100644 --- a/Documentation/networking/netdevices.txt +++ b/Documentation/networking/netdevices.txt @@ -18,7 +18,7 @@ There are routines in net_init.c to handle the common cases of alloc_etherdev, alloc_netdev. These reserve extra space for driver private data which gets freed when the network device is freed. If separately allocated data is attached to the network device -(dev->priv) then it is up to the module exit handler to free that. +(netdev_priv(dev)) then it is up to the module exit handler to free that. MTU === diff --git a/Documentation/networking/regulatory.txt b/Documentation/networking/regulatory.txt index a96989a8ff351c0a409187819175461cfa44f456..dcf31648414ad8423e934851bea5ee38b0d09f2f 100644 --- a/Documentation/networking/regulatory.txt +++ b/Documentation/networking/regulatory.txt @@ -131,11 +131,13 @@ are expected to do this during initialization. r = zd_reg2alpha2(mac->regdomain, alpha2); if (!r) - regulatory_hint(hw->wiphy, alpha2, NULL); + regulatory_hint(hw->wiphy, alpha2); Example code - drivers providing a built in regulatory domain: -------------------------------------------------------------- +[NOTE: This API is not currently available, it can be added when required] + If you have regulatory information you can obtain from your driver and you *need* to use this we let you build a regulatory domain structure and pass it to the wireless core. To do this you should @@ -167,7 +169,6 @@ struct ieee80211_regdomain mydriver_jp_regdom = { Then in some part of your code after your wiphy has been registered: - int r; struct ieee80211_regdomain *rd; int size_of_regd; int num_rules = mydriver_jp_regdom.n_reg_rules; @@ -178,17 +179,12 @@ Then in some part of your code after your wiphy has been registered: rd = kzalloc(size_of_regd, GFP_KERNEL); if (!rd) - return -ENOMEM; + return -ENOMEM; memcpy(rd, &mydriver_jp_regdom, sizeof(struct ieee80211_regdomain)); - for (i=0; i < num_rules; i++) { - memcpy(&rd->reg_rules[i], &mydriver_jp_regdom.reg_rules[i], - sizeof(struct ieee80211_reg_rule)); - } - r = regulatory_hint(hw->wiphy, NULL, rd); - if (r) { - kfree(rd); - return r; - } - + for (i=0; i < num_rules; i++) + memcpy(&rd->reg_rules[i], + &mydriver_jp_regdom.reg_rules[i], + sizeof(struct ieee80211_reg_rule)); + regulatory_struct_hint(rd); diff --git a/Documentation/nmi_watchdog.txt b/Documentation/nmi_watchdog.txt index 90aa4531cb67343b03b396610aa0db77c1d1e0ba..bf9f80a982829ae06062e9cc118762335936ad4a 100644 --- a/Documentation/nmi_watchdog.txt +++ b/Documentation/nmi_watchdog.txt @@ -69,6 +69,11 @@ to the overall system performance. On x86 nmi_watchdog is disabled by default so you have to enable it with a boot time parameter. +It's possible to disable the NMI watchdog in run-time by writing "0" to +/proc/sys/kernel/nmi_watchdog. Writing "1" to the same file will re-enable +the NMI watchdog. Notice that you still need to use "nmi_watchdog=" parameter +at boot time. + NOTE: In kernels prior to 2.4.2-ac18 the NMI-oopser is enabled unconditionally on x86 SMP boxes. diff --git a/Documentation/powerpc/dts-bindings/fsl/tsec.txt b/Documentation/powerpc/dts-bindings/fsl/tsec.txt index cf55fa4112d2736de01e0989c5f11d417346326a..7fa4b27574b5f54aabb1c9839e61fcf9f053c0ad 100644 --- a/Documentation/powerpc/dts-bindings/fsl/tsec.txt +++ b/Documentation/powerpc/dts-bindings/fsl/tsec.txt @@ -2,8 +2,8 @@ The MDIO is a bus to which the PHY devices are connected. For each device that exists on this bus, a child node should be created. See -the definition of the PHY node below for an example of how to define -a PHY. +the definition of the PHY node in booting-without-of.txt for an example +of how to define a PHY. Required properties: - reg : Offset and length of the register set for the device @@ -21,6 +21,14 @@ Example: }; }; +* TBI Internal MDIO bus + +As of this writing, every tsec is associated with an internal TBI PHY. +This PHY is accessed through the local MDIO bus. These buses are defined +similarly to the mdio buses, except they are compatible with "fsl,gianfar-tbi". +The TBI PHYs underneath them are similar to normal PHYs, but the reg property +is considered instructive, rather than descriptive. The reg property should +be chosen so it doesn't interfere with other PHYs on the bus. * Gianfar-compatible ethernet nodes diff --git a/Documentation/rfkill.txt b/Documentation/rfkill.txt index b65f0799df485dfea9d0346a3d3ede5c7fc5afba..4d3ee317a4a3e84181047ab417a3e2a88c4995bc 100644 --- a/Documentation/rfkill.txt +++ b/Documentation/rfkill.txt @@ -191,12 +191,20 @@ Userspace input handlers (uevents) or kernel input handlers (rfkill-input): to tell the devices registered with the rfkill class to change their state (i.e. translates the input layer event into real action). + * rfkill-input implements EPO by handling EV_SW SW_RFKILL_ALL 0 (power off all transmitters) in a special way: it ignores any overrides and local state cache and forces all transmitters to the RFKILL_STATE_SOFT_BLOCKED state (including those which are already - supposed to be BLOCKED). Note that the opposite event (power on all - transmitters) is handled normally. + supposed to be BLOCKED). + * rfkill EPO will remain active until rfkill-input receives an + EV_SW SW_RFKILL_ALL 1 event. While the EPO is active, transmitters + are locked in the blocked state (rfkill will refuse to unblock them). + * rfkill-input implements different policies that the user can + select for handling EV_SW SW_RFKILL_ALL 1. It will unlock rfkill, + and either do nothing (leave transmitters blocked, but now unlocked), + restore the transmitters to their state before the EPO, or unblock + them all. Userspace uevent handler or kernel platform-specific drivers hooked to the rfkill notifier chain: @@ -331,11 +339,9 @@ class to get a sysfs interface :-) correct event for your switch/button. These events are emergency power-off events when they are trying to turn the transmitters off. An example of an input device which SHOULD generate *_RFKILL_ALL events is the wireless-kill -switch in a laptop which is NOT a hotkey, but a real switch that kills radios -in hardware, even if the O.S. has gone to lunch. An example of an input device -which SHOULD NOT generate *_RFKILL_ALL events by default, is any sort of hot -key that does nothing by itself, as well as any hot key that is type-specific -(e.g. the one for WLAN). +switch in a laptop which is NOT a hotkey, but a real sliding/rocker switch. +An example of an input device which SHOULD NOT generate *_RFKILL_ALL events by +default, is any sort of hot key that is type-specific (e.g. the one for WLAN). 3.1 Guidelines for wireless device drivers diff --git a/Documentation/scheduler/sched-arch.txt b/Documentation/scheduler/sched-arch.txt index 941615a9769b91ea0cee31723023c600645db67d..d43dbcbd163b4d45e3479614149c780b5e12778f 100644 --- a/Documentation/scheduler/sched-arch.txt +++ b/Documentation/scheduler/sched-arch.txt @@ -8,7 +8,7 @@ Context switch By default, the switch_to arch function is called with the runqueue locked. This is usually not a problem unless switch_to may need to take the runqueue lock. This is usually due to a wake up operation in -the context switch. See include/asm-ia64/system.h for an example. +the context switch. See arch/ia64/include/asm/system.h for an example. To request the scheduler call switch_to with the runqueue unlocked, you must `#define __ARCH_WANT_UNLOCKED_CTXSW` in a header file @@ -23,7 +23,7 @@ disabled. Interrupts may be enabled over the call if it is likely to introduce a significant interrupt latency by adding the line `#define __ARCH_WANT_INTERRUPTS_ON_CTXSW` in the same place as for unlocked context switches. This define also implies -`__ARCH_WANT_UNLOCKED_CTXSW`. See include/asm-arm/system.h for an +`__ARCH_WANT_UNLOCKED_CTXSW`. See arch/arm/include/asm/system.h for an example. diff --git a/Documentation/scheduler/sched-design-CFS.txt b/Documentation/scheduler/sched-design-CFS.txt index eb471c7a905eda60bc83cbf9eeb03e807356606b..8398ca4ff4ede1e4671f334bdb417e4787593aec 100644 --- a/Documentation/scheduler/sched-design-CFS.txt +++ b/Documentation/scheduler/sched-design-CFS.txt @@ -273,3 +273,24 @@ task groups and modify their CPU share using the "cgroups" pseudo filesystem. # #Launch gmplayer (or your favourite movie player) # echo > multimedia/tasks + +8. Implementation note: user namespaces + +User namespaces are intended to be hierarchical. But they are currently +only partially implemented. Each of those has ramifications for CFS. + +First, since user namespaces are hierarchical, the /sys/kernel/uids +presentation is inadequate. Eventually we will likely want to use sysfs +tagging to provide private views of /sys/kernel/uids within each user +namespace. + +Second, the hierarchical nature is intended to support completely +unprivileged use of user namespaces. So if using user groups, then +we want the users in a user namespace to be children of the user +who created it. + +That is currently unimplemented. So instead, every user in a new +user namespace will receive 1024 shares just like any user in the +initial user namespace. Note that at the moment creation of a new +user namespace requires each of CAP_SYS_ADMIN, CAP_SETUID, and +CAP_SETGID. diff --git a/Documentation/sh/kgdb.txt b/Documentation/sh/kgdb.txt deleted file mode 100644 index 05b4ba89d28ca27f4cde52797475d9f8e13caf7e..0000000000000000000000000000000000000000 --- a/Documentation/sh/kgdb.txt +++ /dev/null @@ -1,179 +0,0 @@ - -This file describes the configuration and behavior of KGDB for the SH -kernel. Based on a description from Henry Bell , it -has been modified to account for quirks in the current implementation. - -Version -======= - -This version of KGDB was written for 2.4.xx kernels for the SH architecture. -Further documentation is available from the linux-sh project website. - - -Debugging Setup: Host -====================== - -The two machines will be connected together via a serial line - this -should be a null modem cable i.e. with a twist. - -On your DEVELOPMENT machine, go to your kernel source directory and -build the kernel, enabling KGDB support in the "kernel hacking" section. -This includes the KGDB code, and also makes the kernel be compiled with -the "-g" option set -- necessary for debugging. - -To install this new kernel, use the following installation procedure. - -Decide on which tty port you want the machines to communicate, then -cable them up back-to-back using the null modem. On the DEVELOPMENT -machine, you may wish to create an initialization file called .gdbinit -(in the kernel source directory or in your home directory) to execute -commonly-used commands at startup. - -A minimal .gdbinit might look like this: - - file vmlinux - set remotebaud 115200 - target remote /dev/ttyS0 - -Change the "target" definition so that it specifies the tty port that -you intend to use. Change the "remotebaud" definition to match the -data rate that you are going to use for the com line (115200 is the -default). - -Debugging Setup: Target -======================== - -By default, the KGDB stub will communicate with the host GDB using -ttySC1 at 115200 baud, 8 databits, no parity; these defaults can be -changed in the kernel configuration. As the kernel starts up, KGDB will -initialize so that breakpoints, kernel segfaults, and so forth will -generally enter the debugger. - -This behavior can be modified by including the "kgdb" option in the -kernel command line; this option has the general form: - - kgdb=, - -The indicates the port to use, and can optionally specify -baud, parity and databits -- e.g. "ttySC0,9600N8" or "ttySC1,19200". - -The can be "halt" or "disabled". The "halt" action enters the -debugger via a breakpoint as soon as kgdb is initialized; the "disabled" -action causes kgdb to ignore kernel segfaults and such until explicitly -entered by a breakpoint in the code or by external action (sysrq or NMI). - -(Both and can appear alone, w/o the separating comma.) - -For example, if you wish to debug early in kernel startup code, you -might specify the halt option: - - kgdb=halt - -Boot the TARGET machine, which will appear to hang. - -On your DEVELOPMENT machine, cd to the source directory and run the gdb -program. (This is likely to be a cross GDB which runs on your host but -is built for an SH target.) If everything is working correctly you -should see gdb print out a few lines indicating that a breakpoint has -been taken. It will actually show a line of code in the target kernel -inside the gdbstub activation code. - -NOTE: BE SURE TO TERMINATE OR SUSPEND any other host application which -may be using the same serial port (for example, a terminal emulator you -have been using to connect to the target boot code.) Otherwise, data -from the target may not all get to GDB! - -You can now use whatever gdb commands you like to set breakpoints. -Enter "continue" to start your target machine executing again. At this -point the target system will run at full speed until it encounters -your breakpoint or gets a segment violation in the kernel, or whatever. - -Serial Ports: KGDB, Console -============================ - -This version of KGDB may not gracefully handle conflict with other -drivers in the kernel using the same port. If KGDB is configured on the -same port (and with the same parameters) as the kernel console, or if -CONFIG_SH_KGDB_CONSOLE is configured, things should be fine (though in -some cases console messages may appear twice through GDB). But if the -KGDB port is not the kernel console and used by another serial driver -which assumes different serial parameters (e.g. baud rate) KGDB may not -recover. - -Also, when KGDB is entered via sysrq-g (requires CONFIG_KGDB_SYSRQ) and -the kgdb port uses the same port as the console, detaching GDB will not -restore the console to working order without the port being re-opened. - -Another serious consequence of this is that GDB currently CANNOT break -into KGDB externally (e.g. via ^C or ); unless a breakpoint or -error is encountered, the only way to enter KGDB after the initial halt -(see above) is via NMI (CONFIG_KGDB_NMI) or sysrq-g (CONFIG_KGDB_SYSRQ). - -Code is included for the basic Hitachi Solution Engine boards to allow -the use of ttyS0 for KGDB if desired; this is less robust, but may be -useful in some cases. (This cannot be selected using the config file, -but only through the kernel command line, e.g. "kgdb=ttyS0", though the -configured defaults for baud rate etc. still apply if not overridden.) - -If gdbstub Does Not Work -======================== - -If it doesn't work, you will have to troubleshoot it. Do the easy -things first like double checking your cabling and data rates. You -might try some non-kernel based programs to see if the back-to-back -connection works properly. Just something simple like cat /etc/hosts -/dev/ttyS0 on one machine and cat /dev/ttyS0 on the other will tell you -if you can send data from one machine to the other. There is no point -in tearing out your hair in the kernel if the line doesn't work. - -If you need to debug the GDB/KGDB communication itself, the gdb commands -"set debug remote 1" and "set debug serial 1" may be useful, but be -warned: they produce a lot of output. - -Threads -======= - -Each process in a target machine is seen as a gdb thread. gdb thread related -commands (info threads, thread n) can be used. CONFIG_KGDB_THREAD must -be defined for this to work. - -In this version, kgdb reports PID_MAX (32768) as the process ID for the -idle process (pid 0), since GDB does not accept 0 as an ID. - -Detaching (exiting KGDB) -========================= - -There are two ways to resume full-speed target execution: "continue" and -"detach". With "continue", GDB inserts any specified breakpoints in the -target code and resumes execution; the target is still in "gdb mode". -If a breakpoint or other debug event (e.g. NMI) happens, the target -halts and communicates with GDB again, which is waiting for it. - -With "detach", GDB does *not* insert any breakpoints; target execution -is resumed and GDB stops communicating (does not wait for the target). -In this case, the target is no longer in "gdb mode" -- for example, -console messages no longer get sent separately to the KGDB port, or -encapsulated for GDB. If a debug event (e.g. NMI) occurs, the target -will re-enter "gdb mode" and will display this fact on the console; you -must give a new "target remote" command to gdb. - -NOTE: TO AVOID LOSSING CONSOLE MESSAGES IN CASE THE KERNEL CONSOLE AND -KGDB USING THE SAME PORT, THE TARGET WAITS FOR ANY INPUT CHARACTER ON -THE KGDB PORT AFTER A DETACH COMMAND. For example, after the detach you -could start a terminal emulator on the same host port and enter a ; -however, this program must then be terminated or suspended in order to -use GBD again if KGDB is re-entered. - - -Acknowledgements -================ - -This code was mostly generated by Henry Bell ; -largely from KGDB by Amit S. Kale - extracts from -code by Glenn Engel, Jim Kingdon, David Grothe , Tigran -Aivazian , William Gatliff , Ben -Lee, Steve Chamberlain and Benoit Miller are also -included. - -Jeremy Siegel - diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 394d7d378dc74daf6899621d2bca0c37cdd598cf..841a9365d5fdd67b5018c7551ff7bb2433056c8a 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -757,6 +757,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. model - force the model name position_fix - Fix DMA pointer (0 = auto, 1 = use LPIB, 2 = POSBUF) probe_mask - Bitmask to probe codecs (default = -1, meaning all slots) + probe_only - Only probing and no codec initialization (default=off); + Useful to check the initial codec status for debugging bdl_pos_adj - Specifies the DMA IRQ timing delay in samples. Passing -1 will make the driver to choose the appropriate value based on the controller chip. @@ -772,327 +774,23 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. This module supports multiple cards and autoprobe. + See Documentation/sound/alsa/HD-Audio.txt for more details about + HD-audio driver. + Each codec may have a model table for different configurations. If your machine isn't listed there, the default (usually minimal) configuration is set up. You can pass "model=" option to specify a certain model in such a case. There are different - models depending on the codec chip. - - Model name Description - ---------- ----------- - ALC880 - 3stack 3-jack in back and a headphone out - 3stack-digout 3-jack in back, a HP out and a SPDIF out - 5stack 5-jack in back, 2-jack in front - 5stack-digout 5-jack in back, 2-jack in front, a SPDIF out - 6stack 6-jack in back, 2-jack in front - 6stack-digout 6-jack with a SPDIF out - w810 3-jack - z71v 3-jack (HP shared SPDIF) - asus 3-jack (ASUS Mobo) - asus-w1v ASUS W1V - asus-dig ASUS with SPDIF out - asus-dig2 ASUS with SPDIF out (using GPIO2) - uniwill 3-jack - fujitsu Fujitsu Laptops (Pi1536) - F1734 2-jack - lg LG laptop (m1 express dual) - lg-lw LG LW20/LW25 laptop - tcl TCL S700 - clevo Clevo laptops (m520G, m665n) - medion Medion Rim 2150 - test for testing/debugging purpose, almost all controls can be - adjusted. Appearing only when compiled with - $CONFIG_SND_DEBUG=y - auto auto-config reading BIOS (default) - - ALC260 - hp HP machines - hp-3013 HP machines (3013-variant) - hp-dc7600 HP DC7600 - fujitsu Fujitsu S7020 - acer Acer TravelMate - will Will laptops (PB V7900) - replacer Replacer 672V - basic fixed pin assignment (old default model) - test for testing/debugging purpose, almost all controls can - adjusted. Appearing only when compiled with - $CONFIG_SND_DEBUG=y - auto auto-config reading BIOS (default) - - ALC262 - fujitsu Fujitsu Laptop - hp-bpc HP xw4400/6400/8400/9400 laptops - hp-bpc-d7000 HP BPC D7000 - hp-tc-t5735 HP Thin Client T5735 - hp-rp5700 HP RP5700 - benq Benq ED8 - benq-t31 Benq T31 - hippo Hippo (ATI) with jack detection, Sony UX-90s - hippo_1 Hippo (Benq) with jack detection - sony-assamd Sony ASSAMD - toshiba-s06 Toshiba S06 - toshiba-rx1 Toshiba RX1 - ultra Samsung Q1 Ultra Vista model - lenovo-3000 Lenovo 3000 y410 - nec NEC Versa S9100 - basic fixed pin assignment w/o SPDIF - auto auto-config reading BIOS (default) - - ALC267/268 - quanta-il1 Quanta IL1 mini-notebook - 3stack 3-stack model - toshiba Toshiba A205 - acer Acer laptops - acer-aspire Acer Aspire One - dell Dell OEM laptops (Vostro 1200) - zepto Zepto laptops - test for testing/debugging purpose, almost all controls can - adjusted. Appearing only when compiled with - $CONFIG_SND_DEBUG=y - auto auto-config reading BIOS (default) - - ALC269 - basic Basic preset - quanta Quanta FL1 - eeepc-p703 ASUS Eeepc P703 P900A - eeepc-p901 ASUS Eeepc P901 S101 - - ALC662/663 - 3stack-dig 3-stack (2-channel) with SPDIF - 3stack-6ch 3-stack (6-channel) - 3stack-6ch-dig 3-stack (6-channel) with SPDIF - 6stack-dig 6-stack with SPDIF - lenovo-101e Lenovo laptop - eeepc-p701 ASUS Eeepc P701 - eeepc-ep20 ASUS Eeepc EP20 - ecs ECS/Foxconn mobo - m51va ASUS M51VA - g71v ASUS G71V - h13 ASUS H13 - g50v ASUS G50V - asus-mode1 ASUS - asus-mode2 ASUS - asus-mode3 ASUS - asus-mode4 ASUS - asus-mode5 ASUS - asus-mode6 ASUS - auto auto-config reading BIOS (default) - - ALC882/885 - 3stack-dig 3-jack with SPDIF I/O - 6stack-dig 6-jack digital with SPDIF I/O - arima Arima W820Di1 - targa Targa T8, MSI-1049 T8 - asus-a7j ASUS A7J - asus-a7m ASUS A7M - macpro MacPro support - mbp3 Macbook Pro rev3 - imac24 iMac 24'' with jack detection - w2jc ASUS W2JC - auto auto-config reading BIOS (default) - - ALC883/888 - 3stack-dig 3-jack with SPDIF I/O - 6stack-dig 6-jack digital with SPDIF I/O - 3stack-6ch 3-jack 6-channel - 3stack-6ch-dig 3-jack 6-channel with SPDIF I/O - 6stack-dig-demo 6-jack digital for Intel demo board - acer Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc) - acer-aspire Acer Aspire 9810 - medion Medion Laptops - medion-md2 Medion MD2 - targa-dig Targa/MSI - targa-2ch-dig Targs/MSI with 2-channel - laptop-eapd 3-jack with SPDIF I/O and EAPD (Clevo M540JE, M550JE) - lenovo-101e Lenovo 101E - lenovo-nb0763 Lenovo NB0763 - lenovo-ms7195-dig Lenovo MS7195 - lenovo-sky Lenovo Sky - haier-w66 Haier W66 - 3stack-hp HP machines with 3stack (Lucknow, Samba boards) - 6stack-dell Dell machines with 6stack (Inspiron 530) - mitac Mitac 8252D - clevo-m720 Clevo M720 laptop series - fujitsu-pi2515 Fujitsu AMILO Pi2515 - 3stack-6ch-intel Intel DG33* boards - auto auto-config reading BIOS (default) - - ALC861/660 - 3stack 3-jack - 3stack-dig 3-jack with SPDIF I/O - 6stack-dig 6-jack with SPDIF I/O - 3stack-660 3-jack (for ALC660) - uniwill-m31 Uniwill M31 laptop - toshiba Toshiba laptop support - asus Asus laptop support - asus-laptop ASUS F2/F3 laptops - auto auto-config reading BIOS (default) - - ALC861VD/660VD - 3stack 3-jack - 3stack-dig 3-jack with SPDIF OUT - 6stack-dig 6-jack with SPDIF OUT - 3stack-660 3-jack (for ALC660VD) - 3stack-660-digout 3-jack with SPDIF OUT (for ALC660VD) - lenovo Lenovo 3000 C200 - dallas Dallas laptops - hp HP TX1000 - auto auto-config reading BIOS (default) - - CMI9880 - minimal 3-jack in back - min_fp 3-jack in back, 2-jack in front - full 6-jack in back, 2-jack in front - full_dig 6-jack in back, 2-jack in front, SPDIF I/O - allout 5-jack in back, 2-jack in front, SPDIF out - auto auto-config reading BIOS (default) - - AD1882 / AD1882A - 3stack 3-stack mode (default) - 6stack 6-stack mode - - AD1884A / AD1883 / AD1984A / AD1984B - desktop 3-stack desktop (default) - laptop laptop with HP jack sensing - mobile mobile devices with HP jack sensing - thinkpad Lenovo Thinkpad X300 - - AD1884 - N/A - - AD1981 - basic 3-jack (default) - hp HP nx6320 - thinkpad Lenovo Thinkpad T60/X60/Z60 - toshiba Toshiba U205 - - AD1983 - N/A - - AD1984 - basic default configuration - thinkpad Lenovo Thinkpad T61/X61 - dell Dell T3400 - - AD1986A - 6stack 6-jack, separate surrounds (default) - 3stack 3-stack, shared surrounds - laptop 2-channel only (FSC V2060, Samsung M50) - laptop-eapd 2-channel with EAPD (Samsung R65, ASUS A6J) - laptop-automute 2-channel with EAPD and HP-automute (Lenovo N100) - ultra 2-channel with EAPD (Samsung Ultra tablet PC) - - AD1988/AD1988B/AD1989A/AD1989B - 6stack 6-jack - 6stack-dig ditto with SPDIF - 3stack 3-jack - 3stack-dig ditto with SPDIF - laptop 3-jack with hp-jack automute - laptop-dig ditto with SPDIF - auto auto-config reading BIOS (default) - - Conexant 5045 - laptop-hpsense Laptop with HP sense (old model laptop) - laptop-micsense Laptop with Mic sense (old model fujitsu) - laptop-hpmicsense Laptop with HP and Mic senses - benq Benq R55E - test for testing/debugging purpose, almost all controls - can be adjusted. Appearing only when compiled with - $CONFIG_SND_DEBUG=y - - Conexant 5047 - laptop Basic Laptop config - laptop-hp Laptop config for some HP models (subdevice 30A5) - laptop-eapd Laptop config with EAPD support - test for testing/debugging purpose, almost all controls - can be adjusted. Appearing only when compiled with - $CONFIG_SND_DEBUG=y - - Conexant 5051 - laptop Basic Laptop config (default) - hp HP Spartan laptop - - STAC9200 - ref Reference board - dell-d21 Dell (unknown) - dell-d22 Dell (unknown) - dell-d23 Dell (unknown) - dell-m21 Dell Inspiron 630m, Dell Inspiron 640m - dell-m22 Dell Latitude D620, Dell Latitude D820 - dell-m23 Dell XPS M1710, Dell Precision M90 - dell-m24 Dell Latitude 120L - dell-m25 Dell Inspiron E1505n - dell-m26 Dell Inspiron 1501 - dell-m27 Dell Inspiron E1705/9400 - gateway Gateway laptops with EAPD control - panasonic Panasonic CF-74 - - STAC9205/9254 - ref Reference board - dell-m42 Dell (unknown) - dell-m43 Dell Precision - dell-m44 Dell Inspiron - - STAC9220/9221 - ref Reference board - 3stack D945 3stack - 5stack D945 5stack + SPDIF - intel-mac-v1 Intel Mac Type 1 - intel-mac-v2 Intel Mac Type 2 - intel-mac-v3 Intel Mac Type 3 - intel-mac-v4 Intel Mac Type 4 - intel-mac-v5 Intel Mac Type 5 - intel-mac-auto Intel Mac (detect type according to subsystem id) - macmini Intel Mac Mini (equivalent with type 3) - macbook Intel Mac Book (eq. type 5) - macbook-pro-v1 Intel Mac Book Pro 1st generation (eq. type 3) - macbook-pro Intel Mac Book Pro 2nd generation (eq. type 3) - imac-intel Intel iMac (eq. type 2) - imac-intel-20 Intel iMac (newer version) (eq. type 3) - dell-d81 Dell (unknown) - dell-d82 Dell (unknown) - dell-m81 Dell (unknown) - dell-m82 Dell XPS M1210 - - STAC9202/9250/9251 - ref Reference board, base config - m2-2 Some Gateway MX series laptops - m6 Some Gateway NX series laptops - pa6 Gateway NX860 series - - STAC9227/9228/9229/927x - ref Reference board - ref-no-jd Reference board without HP/Mic jack detection - 3stack D965 3stack - 5stack D965 5stack + SPDIF - dell-3stack Dell Dimension E520 - dell-bios Fixes with Dell BIOS setup - - STAC92HD71B* - ref Reference board - dell-m4-1 Dell desktops - dell-m4-2 Dell desktops - dell-m4-3 Dell desktops - - STAC92HD73* - ref Reference board - no-jd BIOS setup but without jack-detection - dell-m6-amic Dell desktops/laptops with analog mics - dell-m6-dmic Dell desktops/laptops with digital mics - dell-m6 Dell desktops/laptops with both type of mics - - STAC9872 - vaio Setup for VAIO FE550G/SZ110 - vaio-ar Setup for VAIO AR + models depending on the codec chip. The list of available models + is found in HD-Audio-Models.txt The model name "genric" is treated as a special case. When this model is given, the driver uses the generic codec parser without "codec-patch". It's sometimes good for testing and debugging. If the default configuration doesn't work and one of the above - matches with your device, report it together with the PCI - subsystem ID (output of "lspci -nv") to ALSA BTS or alsa-devel + matches with your device, report it together with alsa-info.sh + output (with --no-upload option) to kernel bugzilla or alsa-devel ML (see the section "Links and Addresses"). power_save and power_save_controller options are for power-saving @@ -1652,7 +1350,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. * AuzenTech X-Meridian * Bgears b-Enspirer * Club3D Theatron DTS - * HT-Omega Claro + * HT-Omega Claro (plus) + * HT-Omega Claro halo (XT) * Razer Barracuda AC-1 * Sondigo Inferno @@ -2409,8 +2108,11 @@ Links and Addresses ALSA project homepage http://www.alsa-project.org - ALSA Bug Tracking System - https://bugtrack.alsa-project.org/bugs/ + Kernel Bugzilla + http://bugzilla.kernel.org/ ALSA Developers ML mailto:alsa-devel@alsa-project.org + + alsa-info.sh script + http://www.alsa-project.org/alsa-info.sh diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt new file mode 100644 index 0000000000000000000000000000000000000000..4b7ac21ea9eb15eb3c6ef4a350e3b640d998b1e2 --- /dev/null +++ b/Documentation/sound/alsa/HD-Audio-Models.txt @@ -0,0 +1,348 @@ + Model name Description + ---------- ----------- +ALC880 +====== + 3stack 3-jack in back and a headphone out + 3stack-digout 3-jack in back, a HP out and a SPDIF out + 5stack 5-jack in back, 2-jack in front + 5stack-digout 5-jack in back, 2-jack in front, a SPDIF out + 6stack 6-jack in back, 2-jack in front + 6stack-digout 6-jack with a SPDIF out + w810 3-jack + z71v 3-jack (HP shared SPDIF) + asus 3-jack (ASUS Mobo) + asus-w1v ASUS W1V + asus-dig ASUS with SPDIF out + asus-dig2 ASUS with SPDIF out (using GPIO2) + uniwill 3-jack + fujitsu Fujitsu Laptops (Pi1536) + F1734 2-jack + lg LG laptop (m1 express dual) + lg-lw LG LW20/LW25 laptop + tcl TCL S700 + clevo Clevo laptops (m520G, m665n) + medion Medion Rim 2150 + test for testing/debugging purpose, almost all controls can be + adjusted. Appearing only when compiled with + $CONFIG_SND_DEBUG=y + auto auto-config reading BIOS (default) + +ALC260 +====== + hp HP machines + hp-3013 HP machines (3013-variant) + hp-dc7600 HP DC7600 + fujitsu Fujitsu S7020 + acer Acer TravelMate + will Will laptops (PB V7900) + replacer Replacer 672V + basic fixed pin assignment (old default model) + test for testing/debugging purpose, almost all controls can + adjusted. Appearing only when compiled with + $CONFIG_SND_DEBUG=y + auto auto-config reading BIOS (default) + +ALC262 +====== + fujitsu Fujitsu Laptop + hp-bpc HP xw4400/6400/8400/9400 laptops + hp-bpc-d7000 HP BPC D7000 + hp-tc-t5735 HP Thin Client T5735 + hp-rp5700 HP RP5700 + benq Benq ED8 + benq-t31 Benq T31 + hippo Hippo (ATI) with jack detection, Sony UX-90s + hippo_1 Hippo (Benq) with jack detection + sony-assamd Sony ASSAMD + toshiba-s06 Toshiba S06 + toshiba-rx1 Toshiba RX1 + ultra Samsung Q1 Ultra Vista model + lenovo-3000 Lenovo 3000 y410 + nec NEC Versa S9100 + basic fixed pin assignment w/o SPDIF + auto auto-config reading BIOS (default) + +ALC267/268 +========== + quanta-il1 Quanta IL1 mini-notebook + 3stack 3-stack model + toshiba Toshiba A205 + acer Acer laptops + acer-dmic Acer laptops with digital-mic + acer-aspire Acer Aspire One + dell Dell OEM laptops (Vostro 1200) + zepto Zepto laptops + test for testing/debugging purpose, almost all controls can + adjusted. Appearing only when compiled with + $CONFIG_SND_DEBUG=y + auto auto-config reading BIOS (default) + +ALC269 +====== + basic Basic preset + quanta Quanta FL1 + eeepc-p703 ASUS Eeepc P703 P900A + eeepc-p901 ASUS Eeepc P901 S101 + fujitsu FSC Amilo + auto auto-config reading BIOS (default) + +ALC662/663 +========== + 3stack-dig 3-stack (2-channel) with SPDIF + 3stack-6ch 3-stack (6-channel) + 3stack-6ch-dig 3-stack (6-channel) with SPDIF + 6stack-dig 6-stack with SPDIF + lenovo-101e Lenovo laptop + eeepc-p701 ASUS Eeepc P701 + eeepc-ep20 ASUS Eeepc EP20 + ecs ECS/Foxconn mobo + m51va ASUS M51VA + g71v ASUS G71V + h13 ASUS H13 + g50v ASUS G50V + asus-mode1 ASUS + asus-mode2 ASUS + asus-mode3 ASUS + asus-mode4 ASUS + asus-mode5 ASUS + asus-mode6 ASUS + auto auto-config reading BIOS (default) + +ALC882/885 +========== + 3stack-dig 3-jack with SPDIF I/O + 6stack-dig 6-jack digital with SPDIF I/O + arima Arima W820Di1 + targa Targa T8, MSI-1049 T8 + asus-a7j ASUS A7J + asus-a7m ASUS A7M + macpro MacPro support + mbp3 Macbook Pro rev3 + imac24 iMac 24'' with jack detection + w2jc ASUS W2JC + auto auto-config reading BIOS (default) + +ALC883/888 +========== + 3stack-dig 3-jack with SPDIF I/O + 6stack-dig 6-jack digital with SPDIF I/O + 3stack-6ch 3-jack 6-channel + 3stack-6ch-dig 3-jack 6-channel with SPDIF I/O + 6stack-dig-demo 6-jack digital for Intel demo board + acer Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc) + acer-aspire Acer Aspire 9810 + acer-aspire-4930g Acer Aspire 4930G + medion Medion Laptops + medion-md2 Medion MD2 + targa-dig Targa/MSI + targa-2ch-dig Targs/MSI with 2-channel + laptop-eapd 3-jack with SPDIF I/O and EAPD (Clevo M540JE, M550JE) + lenovo-101e Lenovo 101E + lenovo-nb0763 Lenovo NB0763 + lenovo-ms7195-dig Lenovo MS7195 + lenovo-sky Lenovo Sky + haier-w66 Haier W66 + 3stack-hp HP machines with 3stack (Lucknow, Samba boards) + 6stack-dell Dell machines with 6stack (Inspiron 530) + mitac Mitac 8252D + clevo-m720 Clevo M720 laptop series + fujitsu-pi2515 Fujitsu AMILO Pi2515 + fujitsu-xa3530 Fujitsu AMILO XA3530 + 3stack-6ch-intel Intel DG33* boards + auto auto-config reading BIOS (default) + +ALC861/660 +========== + 3stack 3-jack + 3stack-dig 3-jack with SPDIF I/O + 6stack-dig 6-jack with SPDIF I/O + 3stack-660 3-jack (for ALC660) + uniwill-m31 Uniwill M31 laptop + toshiba Toshiba laptop support + asus Asus laptop support + asus-laptop ASUS F2/F3 laptops + auto auto-config reading BIOS (default) + +ALC861VD/660VD +============== + 3stack 3-jack + 3stack-dig 3-jack with SPDIF OUT + 6stack-dig 6-jack with SPDIF OUT + 3stack-660 3-jack (for ALC660VD) + 3stack-660-digout 3-jack with SPDIF OUT (for ALC660VD) + lenovo Lenovo 3000 C200 + dallas Dallas laptops + hp HP TX1000 + asus-v1s ASUS V1Sn + auto auto-config reading BIOS (default) + +CMI9880 +======= + minimal 3-jack in back + min_fp 3-jack in back, 2-jack in front + full 6-jack in back, 2-jack in front + full_dig 6-jack in back, 2-jack in front, SPDIF I/O + allout 5-jack in back, 2-jack in front, SPDIF out + auto auto-config reading BIOS (default) + +AD1882 / AD1882A +================ + 3stack 3-stack mode (default) + 6stack 6-stack mode + +AD1884A / AD1883 / AD1984A / AD1984B +==================================== + desktop 3-stack desktop (default) + laptop laptop with HP jack sensing + mobile mobile devices with HP jack sensing + thinkpad Lenovo Thinkpad X300 + +AD1884 +====== + N/A + +AD1981 +====== + basic 3-jack (default) + hp HP nx6320 + thinkpad Lenovo Thinkpad T60/X60/Z60 + toshiba Toshiba U205 + +AD1983 +====== + N/A + +AD1984 +====== + basic default configuration + thinkpad Lenovo Thinkpad T61/X61 + dell Dell T3400 + +AD1986A +======= + 6stack 6-jack, separate surrounds (default) + 3stack 3-stack, shared surrounds + laptop 2-channel only (FSC V2060, Samsung M50) + laptop-eapd 2-channel with EAPD (ASUS A6J) + laptop-automute 2-channel with EAPD and HP-automute (Lenovo N100) + ultra 2-channel with EAPD (Samsung Ultra tablet PC) + samsung 2-channel with EAPD (Samsung R65) + +AD1988/AD1988B/AD1989A/AD1989B +============================== + 6stack 6-jack + 6stack-dig ditto with SPDIF + 3stack 3-jack + 3stack-dig ditto with SPDIF + laptop 3-jack with hp-jack automute + laptop-dig ditto with SPDIF + auto auto-config reading BIOS (default) + +Conexant 5045 +============= + laptop-hpsense Laptop with HP sense (old model laptop) + laptop-micsense Laptop with Mic sense (old model fujitsu) + laptop-hpmicsense Laptop with HP and Mic senses + benq Benq R55E + test for testing/debugging purpose, almost all controls + can be adjusted. Appearing only when compiled with + $CONFIG_SND_DEBUG=y + +Conexant 5047 +============= + laptop Basic Laptop config + laptop-hp Laptop config for some HP models (subdevice 30A5) + laptop-eapd Laptop config with EAPD support + test for testing/debugging purpose, almost all controls + can be adjusted. Appearing only when compiled with + $CONFIG_SND_DEBUG=y + +Conexant 5051 +============= + laptop Basic Laptop config (default) + hp HP Spartan laptop + +STAC9200 +======== + ref Reference board + dell-d21 Dell (unknown) + dell-d22 Dell (unknown) + dell-d23 Dell (unknown) + dell-m21 Dell Inspiron 630m, Dell Inspiron 640m + dell-m22 Dell Latitude D620, Dell Latitude D820 + dell-m23 Dell XPS M1710, Dell Precision M90 + dell-m24 Dell Latitude 120L + dell-m25 Dell Inspiron E1505n + dell-m26 Dell Inspiron 1501 + dell-m27 Dell Inspiron E1705/9400 + gateway Gateway laptops with EAPD control + panasonic Panasonic CF-74 + +STAC9205/9254 +============= + ref Reference board + dell-m42 Dell (unknown) + dell-m43 Dell Precision + dell-m44 Dell Inspiron + +STAC9220/9221 +============= + ref Reference board + 3stack D945 3stack + 5stack D945 5stack + SPDIF + intel-mac-v1 Intel Mac Type 1 + intel-mac-v2 Intel Mac Type 2 + intel-mac-v3 Intel Mac Type 3 + intel-mac-v4 Intel Mac Type 4 + intel-mac-v5 Intel Mac Type 5 + intel-mac-auto Intel Mac (detect type according to subsystem id) + macmini Intel Mac Mini (equivalent with type 3) + macbook Intel Mac Book (eq. type 5) + macbook-pro-v1 Intel Mac Book Pro 1st generation (eq. type 3) + macbook-pro Intel Mac Book Pro 2nd generation (eq. type 3) + imac-intel Intel iMac (eq. type 2) + imac-intel-20 Intel iMac (newer version) (eq. type 3) + dell-d81 Dell (unknown) + dell-d82 Dell (unknown) + dell-m81 Dell (unknown) + dell-m82 Dell XPS M1210 + +STAC9202/9250/9251 +================== + ref Reference board, base config + m2-2 Some Gateway MX series laptops + m6 Some Gateway NX series laptops + pa6 Gateway NX860 series + +STAC9227/9228/9229/927x +======================= + ref Reference board + ref-no-jd Reference board without HP/Mic jack detection + 3stack D965 3stack + 5stack D965 5stack + SPDIF + dell-3stack Dell Dimension E520 + dell-bios Fixes with Dell BIOS setup + +STAC92HD71B* +============ + ref Reference board + dell-m4-1 Dell desktops + dell-m4-2 Dell desktops + dell-m4-3 Dell desktops + +STAC92HD73* +=========== + ref Reference board + no-jd BIOS setup but without jack-detection + dell-m6-amic Dell desktops/laptops with analog mics + dell-m6-dmic Dell desktops/laptops with digital mics + dell-m6 Dell desktops/laptops with both type of mics + +STAC92HD83* +=========== + ref Reference board + +STAC9872 +======== + vaio Setup for VAIO FE550G/SZ110 + vaio-ar Setup for VAIO AR diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt new file mode 100644 index 0000000000000000000000000000000000000000..8d68fff7183945a6b2dba6386ff4cf7da7ea5753 --- /dev/null +++ b/Documentation/sound/alsa/HD-Audio.txt @@ -0,0 +1,577 @@ +MORE NOTES ON HD-AUDIO DRIVER +============================= + Takashi Iwai + + +GENERAL +------- + +HD-audio is the new standard on-board audio component on modern PCs +after AC97. Although Linux has been supporting HD-audio since long +time ago, there are often problems with new machines. A part of the +problem is broken BIOS, and the rest is the driver implementation. +This document explains the brief trouble-shooting and debugging +methods for the HD-audio hardware. + +The HD-audio component consists of two parts: the controller chip and +the codec chips on the HD-audio bus. Linux provides a single driver +for all controllers, snd-hda-intel. Although the driver name contains +a word of a well-known harware vendor, it's not specific to it but for +all controller chips by other companies. Since the HD-audio +controllers are supposed to be compatible, the single snd-hda-driver +should work in most cases. But, not surprisingly, there are known +bugs and issues specific to each controller type. The snd-hda-intel +driver has a bunch of workarounds for these as described below. + +A controller may have multiple codecs. Usually you have one audio +codec and optionally one modem codec. In theory, there might be +multiple audio codecs, e.g. for analog and digital outputs, and the +driver might not work properly because of conflict of mixer elements. +This should be fixed in future if such hardware really exists. + +The snd-hda-intel driver has several different codec parsers depending +on the codec. It has a generic parser as a fallback, but this +functionality is fairly limited until now. Instead of the generic +parser, usually the codec-specific parser (coded in patch_*.c) is used +for the codec-specific implementations. The details about the +codec-specific problems are explained in the later sections. + +If you are interested in the deep debugging of HD-audio, read the +HD-audio specification at first. The specification is found on +Intel's web page, for example: + +- http://www.intel.com/standards/hdaudio/ + + +HD-AUDIO CONTROLLER +------------------- + +DMA-Position Problem +~~~~~~~~~~~~~~~~~~~~ +The most common problem of the controller is the inaccurate DMA +pointer reporting. The DMA pointer for playback and capture can be +read in two ways, either via a LPIB register or via a position-buffer +map. As default the driver tries to read from the io-mapped +position-buffer, and falls back to LPIB if the position-buffer appears +dead. However, this detection isn't perfect on some devices. In such +a case, you can change the default method via `position_fix` option. + +`position_fix=1` means to use LPIB method explicitly. +`position_fix=2` means to use the position-buffer. 0 is the default +value, the automatic check and fallback to LPIB as described in the +above. If you get a problem of repeated sounds, this option might +help. + +In addition to that, every controller is known to be broken regarding +the wake-up timing. It wakes up a few samples before actually +processing the data on the buffer. This caused a lot of problems, for +example, with ALSA dmix or JACK. Since 2.6.27 kernel, the driver puts +an artificial delay to the wake up timing. This delay is controlled +via `bdl_pos_adj` option. + +When `bdl_pos_adj` is a negative value (as default), it's assigned to +an appropriate value depending on the controller chip. For Intel +chips, it'd be 1 while it'd be 32 for others. Usually this works. +Only in case it doesn't work and you get warning messages, you should +change this parameter to other values. + + +Codec-Probing Problem +~~~~~~~~~~~~~~~~~~~~~ +A less often but a more severe problem is the codec probing. When +BIOS reports the available codec slots wrongly, the driver gets +confused and tries to access the non-existing codec slot. This often +results in the total screw-up, and destructs the further communication +with the codec chips. The symptom appears usually as error messages +like: +------------------------------------------------------------------------ + hda_intel: azx_get_response timeout, switching to polling mode: + last cmd=0x12345678 + hda_intel: azx_get_response timeout, switching to single_cmd mode: + last cmd=0x12345678 +------------------------------------------------------------------------ + +The first line is a warning, and this is usually relatively harmless. +It means that the codec response isn't notified via an IRQ. The +driver uses explicit polling method to read the response. It gives +very slight CPU overhead, but you'd unlikely notice it. + +The second line is, however, a fatal error. If this happens, usually +it means that something is really wrong. Most likely you are +accessing a non-existing codec slot. + +Thus, if the second error message appears, try to narrow the probed +codec slots via `probe_mask` option. It's a bitmask, and each bit +corresponds to the codec slot. For example, to probe only the first +slot, pass `probe_mask=1`. For the first and the third slots, pass +`probe_mask=5` (where 5 = 1 | 4), and so on. + +Since 2.6.29 kernel, the driver has a more robust probing method, so +this error might happen rarely, though. + + +Interrupt Handling +~~~~~~~~~~~~~~~~~~ +In rare but some cases, the interrupt isn't properly handled as +default. You would notice this by the DMA transfer error reported by +ALSA PCM core, for example. Using MSI might help in such a case. +Pass `enable_msi=1` option for enabling MSI. + + +HD-AUDIO CODEC +-------------- + +Model Option +~~~~~~~~~~~~ +The most common problem regarding the HD-audio driver is the +unsupported codec features or the mismatched device configuration. +Most of codec-specific code has several preset models, either to +override the BIOS setup or to provide more comprehensive features. + +The driver checks PCI SSID and looks through the static configuration +table until any matching entry is found. If you have a new machine, +you may see a message like below: +------------------------------------------------------------------------ + hda_codec: Unknown model for ALC880, trying auto-probe from BIOS... +------------------------------------------------------------------------ +Even if you see such a message, DON'T PANIC. Take a deep breath and +keep your towel. First of all, it's an informational message, no +warning, no error. This means that the PCI SSID of your device isn't +listed in the known preset model (white-)list. But, this doesn't mean +that the driver is broken. Many codec-drivers provide the automatic +configuration mechanism based on the BIOS setup. + +The HD-audio codec has usually "pin" widgets, and BIOS sets the default +configuration of each pin, which indicates the location, the +connection type, the jack color, etc. The HD-audio driver can guess +the right connection judging from these default configuration values. +However -- some codec-support codes, such as patch_analog.c, don't +support the automatic probing (yet as of 2.6.28). And, BIOS is often, +yes, pretty often broken. It sets up wrong values and screws up the +driver. + +The preset model is provided basically to overcome such a situation. +When the matching preset model is found in the white-list, the driver +assumes the static configuration of that preset and builds the mixer +elements and PCM streams based on the static information. Thus, if +you have a newer machine with a slightly different PCI SSID from the +existing one, you may have a good chance to re-use the same model. +You can pass the `model` option to specify the preset model instead of +PCI SSID look-up. + +What `model` option values are available depends on the codec chip. +Check your codec chip from the codec proc file (see "Codec Proc-File" +section below). It will show the vendor/product name of your codec +chip. Then, see Documentation/sound/alsa/HD-Audio-Modelstxt file, +the section of HD-audio driver. You can find a list of codecs +and `model` options belonging to each codec. For example, for Realtek +ALC262 codec chip, pass `model=ultra` for devices that are compatible +with Samsung Q1 Ultra. + +Thus, the first thing you can do for any brand-new, unsupported and +non-working HD-audio hardware is to check HD-audio codec and several +different `model` option values. If you have a luck, some of them +might suit with your device well. + +Some codecs such as ALC880 have a special model option `model=test`. +This configures the driver to provide as many mixer controls as +possible for every single pin feature except for the unsolicited +events (and maybe some other specials). Adjust each mixer element and +try the I/O in the way of trial-and-error until figuring out the whole +I/O pin mappings. + +Note that `model=generic` has a special meaning. It means to use the +generic parser regardless of the codec. Usually the codec-specific +parser is much better than the generic parser (as now). Thus this +option is more about the debugging purpose. + + +Speaker and Headphone Output +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +One of the most frequent (and obvious) bugs with HD-audio is the +silent output from either or both of a built-in speaker and a +headphone jack. In general, you should try a headphone output at +first. A speaker output often requires more additional controls like +the external amplifier bits. Thus a headphone output has a slightly +better chance. + +Before making a bug report, double-check whether the mixer is set up +correctly. The recent version of snd-hda-intel driver provides mostly +"Master" volume control as well as "Front" volume (where Front +indicates the front-channels). In addition, there can be individual +"Headphone" and "Speaker" controls. + +Ditto for the speaker output. There can be "External Amplifier" +switch on some codecs. Turn on this if present. + +Another related problem is the automatic mute of speaker output by +headphone plugging. This feature is implemented in most cases, but +not on every preset model or codec-support code. + +In anyway, try a different model option if you have such a problem. +Some other models may match better and give you more matching +functionality. If none of the available models works, send a bug +report. See the bug report section for details. + +If you are masochistic enough to debug the driver problem, note the +following: + +- The speaker (and the headphone, too) output often requires the + external amplifier. This can be set usually via EAPD verb or a + certain GPIO. If the codec pin supports EAPD, you have a better + chance via SET_EAPD_BTL verb (0x70c). On others, GPIO pin (mostly + it's either GPIO0 or GPIO1) may turn on/off EAPD. +- Some Realtek codecs require special vendor-specific coefficients to + turn on the amplifier. See patch_realtek.c. +- IDT codecs may have extra power-enable/disable controls on each + analog pin. See patch_sigmatel.c. +- Very rare but some devices don't accept the pin-detection verb until + triggered. Issuing GET_PIN_SENSE verb (0xf09) may result in the + codec-communication stall. Some examples are found in + patch_realtek.c. + + +Capture Problems +~~~~~~~~~~~~~~~~ +The capture problems are often because of missing setups of mixers. +Thus, before submitting a bug report, make sure that you set up the +mixer correctly. For example, both "Capture Volume" and "Capture +Switch" have to be set properly in addition to the right "Capture +Source" or "Input Source" selection. Some devices have "Mic Boost" +volume or switch. + +When the PCM device is opened via "default" PCM (without pulse-audio +plugin), you'll likely have "Digital Capture Volume" control as well. +This is provided for the extra gain/attenuation of the signal in +software, especially for the inputs without the hardware volume +control such as digital microphones. Unless really needed, this +should be set to exactly 50%, corresponding to 0dB -- neither extra +gain nor attenuation. When you use "hw" PCM, i.e., a raw access PCM, +this control will have no influence, though. + +It's known that some codecs / devices have fairly bad analog circuits, +and the recorded sound contains a certain DC-offset. This is no bug +of the driver. + +Most of modern laptops have no analog CD-input connection. Thus, the +recording from CD input won't work in many cases although the driver +provides it as the capture source. Use CDDA instead. + +The automatic switching of the built-in and external mic per plugging +is implemented on some codec models but not on every model. Partly +because of my laziness but mostly lack of testers. Feel free to +submit the improvement patch to the author. + + +Direct Debugging +~~~~~~~~~~~~~~~~ +If no model option gives you a better result, and you are a tough guy +to fight against evil, try debugging via hitting the raw HD-audio +codec verbs to the device. Some tools are available: hda-emu and +hda-analyzer. The detailed description is found in the sections +below. You'd need to enable hwdep for using these tools. See "Kernel +Configuration" section. + + +OTHER ISSUES +------------ + +Kernel Configuration +~~~~~~~~~~~~~~~~~~~~ +In general, I recommend you to enable the sound debug option, +`CONFIG_SND_DEBUG=y`, no matter whether you are debugging or not. +This enables snd_printd() macro and others, and you'll get additional +kernel messages at probing. + +In addition, you can enable `CONFIG_SND_DEBUG_VERBOSE=y`. But this +will give you far more messages. Thus turn this on only when you are +sure to want it. + +Don't forget to turn on the appropriate `CONFIG_SND_HDA_CODEC_*` +options. Note that each of them corresponds to the codec chip, not +the controller chip. Thus, even if lspci shows the Nvidia controller, +you may need to choose the option for other vendors. If you are +unsure, just select all yes. + +`CONFIG_SND_HDA_HWDEP` is a useful option for debugging the driver. +When this is enabled, the driver creates hardware-dependent devices +(one per each codec), and you have a raw access to the device via +these device files. For example, `hwC0D2` will be created for the +codec slot #2 of the first card (#0). For debug-tools such as +hda-verb and hda-analyzer, the hwdep device has to be enabled. +Thus, it'd be better to turn this on always. + +`CONFIG_SND_HDA_RECONFIG` is a new option, and this depends on the +hwdep option above. When enabled, you'll have some sysfs files under +the corresponding hwdep directory. See "HD-audio reconfiguration" +section below. + +`CONFIG_SND_HDA_POWER_SAVE` option enables the power-saving feature. +See "Power-saving" section below. + + +Codec Proc-File +~~~~~~~~~~~~~~~ +The codec proc-file is a treasure-chest for debugging HD-audio. +It shows most of useful information of each codec widget. + +The proc file is located in /proc/asound/card*/codec#*, one file per +each codec slot. You can know the codec vendor, product id and +names, the type of each widget, capabilities and so on. +This file, however, doesn't show the jack sensing state, so far. This +is because the jack-sensing might be depending on the trigger state. + +This file will be picked up by the debug tools, and also it can be fed +to the emulator as the primary codec information. See the debug tools +section below. + +This proc file can be also used to check whether the generic parser is +used. When the generic parser is used, the vendor/product ID name +will appear as "Realtek ID 0262", instead of "Realtek ALC262". + + +HD-Audio Reconfiguration +~~~~~~~~~~~~~~~~~~~~~~~~ +This is an experimental feature to allow you re-configure the HD-audio +codec dynamically without reloading the driver. The following sysfs +files are available under each codec-hwdep device directory (e.g. +/sys/class/sound/hwC0D0): + +vendor_id:: + Shows the 32bit codec vendor-id hex number. You can change the + vendor-id value by writing to this file. +subsystem_id:: + Shows the 32bit codec subsystem-id hex number. You can change the + subsystem-id value by writing to this file. +revision_id:: + Shows the 32bit codec revision-id hex number. You can change the + revision-id value by writing to this file. +afg:: + Shows the AFG ID. This is read-only. +mfg:: + Shows the MFG ID. This is read-only. +name:: + Shows the codec name string. Can be changed by writing to this + file. +modelname:: + Shows the currently set `model` option. Can be changed by writing + to this file. +init_verbs:: + The extra verbs to execute at initialization. You can add a verb by + writing to this file. Pass tree numbers, nid, verb and parameter. +hints:: + Shows hint strings for codec parsers for any use. Right now it's + not used. +reconfig:: + Triggers the codec re-configuration. When any value is written to + this file, the driver re-initialize and parses the codec tree + again. All the changes done by the sysfs entries above are taken + into account. +clear:: + Resets the codec, removes the mixer elements and PCM stuff of the + specified codec, and clear all init verbs and hints. + + +Power-Saving +~~~~~~~~~~~~ +The power-saving is a kind of auto-suspend of the device. When the +device is inactive for a certain time, the device is automatically +turned off to save the power. The time to go down is specified via +`power_save` module option, and this option can be changed dynamically +via sysfs. + +The power-saving won't work when the analog loopback is enabled on +some codecs. Make sure that you mute all unneeded signal routes when +you want the power-saving. + +The power-saving feature might cause audible click noises at each +power-down/up depending on the device. Some of them might be +solvable, but some are hard, I'm afraid. Some distros such as +openSUSE enables the power-saving feature automatically when the power +cable is unplugged. Thus, if you hear noises, suspect first the +power-saving. See /sys/module/snd_hda_intel/parameters/power_save to +check the current value. If it's non-zero, the feature is turned on. + + +Development Tree +~~~~~~~~~~~~~~~~ +The latest development codes for HD-audio are found on sound git tree: + +- git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6.git + +The master branch or for-next branches can be used as the main +development branches in general while the HD-audio specific patches +are committed in topic/hda branch. + +If you are using the latest Linus tree, it'd be better to pull the +above GIT tree onto it. If you are using the older kernels, an easy +way to try the latest ALSA code is to build from the snapshot +tarball. There are daily tarballs and the latest snapshot tarball. +All can be built just like normal alsa-driver release packages, that +is, installed via the usual spells: configure, make and make +install(-modules). See INSTALL in the package. The snapshot tarballs +are found at: + +- ftp://ftp.kernel.org/pub/linux/kernel/people/tiwai/snapshot/ + + +Sending a Bug Report +~~~~~~~~~~~~~~~~~~~~ +If any model or module options don't work for your device, it's time +to send a bug report to the developers. Give the following in your +bug report: + +- Hardware vendor, product and model names +- Kernel version (and ALSA-driver version if you built externally) +- `alsa-info.sh` output; run with `--no-upload` option. See the + section below about alsa-info + +If it's a regression, at best, send alsa-info outputs of both working +and non-working kernels. This is really helpful because we can +compare the codec registers directly. + +Send a bug report either the followings: + +kernel-bugzilla:: + http://bugme.linux-foundation.org/ +alsa-devel ML:: + alsa-devel@alsa-project.org + + +DEBUG TOOLS +----------- + +This section describes some tools available for debugging HD-audio +problems. + +alsa-info +~~~~~~~~~ +The script `alsa-info.sh` is a very useful tool to gather the audio +device information. You can fetch the latest version from: + +- http://www.alsa-project.org/alsa-info.sh + +Run this script as root, and it will gather the important information +such as the module lists, module parameters, proc file contents +including the codec proc files, mixer outputs and the control +elements. As default, it will store the information onto a web server +on alsa-project.org. But, if you send a bug report, it'd be better to +run with `--no-upload` option, and attach the generated file. + +There are some other useful options. See `--help` option output for +details. + + +hda-verb +~~~~~~~~ +hda-verb is a tiny program that allows you to access the HD-audio +codec directly. You can execute a raw HD-audio codec verb with this. +This program accesses the hwdep device, thus you need to enable the +kernel config `CONFIG_SND_HDA_HWDEP=y` beforehand. + +The hda-verb program takes four arguments: the hwdep device file, the +widget NID, the verb and the parameter. When you access to the codec +on the slot 2 of the card 0, pass /dev/snd/hwC0D2 to the first +argument, typically. (However, the real path name depends on the +system.) + +The second parameter is the widget number-id to access. The third +parameter can be either a hex/digit number or a string corresponding +to a verb. Similarly, the last parameter is the value to write, or +can be a string for the parameter type. + +------------------------------------------------------------------------ + % hda-verb /dev/snd/hwC0D0 0x12 0x701 2 + nid = 0x12, verb = 0x701, param = 0x2 + value = 0x0 + + % hda-verb /dev/snd/hwC0D0 0x0 PARAMETERS VENDOR_ID + nid = 0x0, verb = 0xf00, param = 0x0 + value = 0x10ec0262 + + % hda-verb /dev/snd/hwC0D0 2 set_a 0xb080 + nid = 0x2, verb = 0x300, param = 0xb080 + value = 0x0 +------------------------------------------------------------------------ + +Although you can issue any verbs with this program, the driver state +won't be always updated. For example, the volume values are usually +cached in the driver, and thus changing the widget amp value directly +via hda-verb won't change the mixer value. + +The hda-verb program is found in the ftp directory: + +- ftp://ftp.kernel.org/pub/linux/kernel/people/tiwai/misc/ + +Also a git repository is available: + +- git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/hda-verb.git + +See README file in the tarball for more details about hda-verb +program. + + +hda-analyzer +~~~~~~~~~~~~ +hda-analyzer provides a graphical interface to access the raw HD-audio +control, based on pyGTK2 binding. It's a more powerful version of +hda-verb. The program gives you an easy-to-use GUI stuff for showing +the widget information and adjusting the amp values, as well as the +proc-compatible output. + +The hda-analyzer is a part of alsa.git repository in +alsa-project.org: + +- http://git.alsa-project.org/?p=alsa.git;a=tree;f=hda-analyzer + + +Codecgraph +~~~~~~~~~~ +Codecgraph is a utility program to generate a graph and visualizes the +codec-node connection of a codec chip. It's especially useful when +you analyze or debug a codec without a proper datasheet. The program +parses the given codec proc file and converts to SVG via graphiz +program. + +The tarball and GIT trees are found in the web page at: + +- http://helllabs.org/codecgraph/ + + +hda-emu +~~~~~~~ +hda-emu is an HD-audio emulator. The main purpose of this program is +to debug an HD-audio codec without the real hardware. Thus, it +doesn't emulate the behavior with the real audio I/O, but it just +dumps the codec register changes and the ALSA-driver internal changes +at probing and operating the HD-audio driver. + +The program requires a codec proc-file to simulate. Get a proc file +for the target codec beforehand, or pick up an example codec from the +codec proc collections in the tarball. Then, run the program with the +proc file, and the hda-emu program will start parsing the codec file +and simulates the HD-audio driver: + +------------------------------------------------------------------------ + % hda-emu codecs/stac9200-dell-d820-laptop + # Parsing.. + hda_codec: Unknown model for STAC9200, using BIOS defaults + hda_codec: pin nid 08 bios pin config 40c003fa + .... +------------------------------------------------------------------------ + +The program gives you only a very dumb command-line interface. You +can get a proc-file dump at the current state, get a list of control +(mixer) elements, set/get the control element value, simulate the PCM +operation, the jack plugging simulation, etc. + +The package is found in: + +- ftp://ftp.kernel.org/pub/linux/kernel/people/tiwai/misc/ + +A git repository is available: + +- git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/hda-emu.git + +See README file in the tarball for more details about hda-emu +program. diff --git a/Documentation/sound/alsa/Procfile.txt b/Documentation/sound/alsa/Procfile.txt index f738b296440a55a3a3cc86b0f0039bff1c2d2067..bba2dbb79d81c10d71bbc5b0879f6d3745d1543d 100644 --- a/Documentation/sound/alsa/Procfile.txt +++ b/Documentation/sound/alsa/Procfile.txt @@ -153,6 +153,16 @@ card*/codec#* Shows the general codec information and the attribute of each widget node. +card*/eld#* + Available for HDMI or DisplayPort interfaces. + Shows ELD(EDID Like Data) info retrieved from the attached HDMI sink, + and describes its audio capabilities and configurations. + + Some ELD fields may be modified by doing `echo name hex_value > eld#*`. + Only do this if you are sure the HDMI sink provided value is wrong. + And if that makes your HDMI audio work, please report to us so that we + can fix it in future kernel releases. + Sequencer Information --------------------- diff --git a/Documentation/sound/alsa/soc/machine.txt b/Documentation/sound/alsa/soc/machine.txt index f370e7db86af6a970de14433523af4b1ca71d390..bab7711ce96311470a3eddb9a9500772b02a777e 100644 --- a/Documentation/sound/alsa/soc/machine.txt +++ b/Documentation/sound/alsa/soc/machine.txt @@ -9,7 +9,7 @@ the audio subsystem with the kernel as a platform device and is represented by the following struct:- /* SoC machine */ -struct snd_soc_machine { +struct snd_soc_card { char *name; int (*probe)(struct platform_device *pdev); @@ -67,10 +67,10 @@ static struct snd_soc_dai_link corgi_dai = { .ops = &corgi_ops, }; -struct snd_soc_machine then sets up the machine with it's DAIs. e.g. +struct snd_soc_card then sets up the machine with it's DAIs. e.g. /* corgi audio machine driver */ -static struct snd_soc_machine snd_soc_machine_corgi = { +static struct snd_soc_card snd_soc_corgi = { .name = "Corgi", .dai_link = &corgi_dai, .num_links = 1, @@ -90,7 +90,7 @@ static struct wm8731_setup_data corgi_wm8731_setup = { /* corgi audio subsystem */ static struct snd_soc_device corgi_snd_devdata = { - .machine = &snd_soc_machine_corgi, + .machine = &snd_soc_corgi, .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm8731, .codec_data = &corgi_wm8731_setup, diff --git a/Documentation/tracepoints.txt b/Documentation/tracepoints.txt index 5d354e16749447c667934ecd4c8f4fe5ee3da36c..6f0a044f5b5e51e27f2bdae2cd6d68123eb98bd7 100644 --- a/Documentation/tracepoints.txt +++ b/Documentation/tracepoints.txt @@ -3,28 +3,30 @@ Mathieu Desnoyers -This document introduces Linux Kernel Tracepoints and their use. It provides -examples of how to insert tracepoints in the kernel and connect probe functions -to them and provides some examples of probe functions. +This document introduces Linux Kernel Tracepoints and their use. It +provides examples of how to insert tracepoints in the kernel and +connect probe functions to them and provides some examples of probe +functions. * Purpose of tracepoints -A tracepoint placed in code provides a hook to call a function (probe) that you -can provide at runtime. A tracepoint can be "on" (a probe is connected to it) or -"off" (no probe is attached). When a tracepoint is "off" it has no effect, -except for adding a tiny time penalty (checking a condition for a branch) and -space penalty (adding a few bytes for the function call at the end of the -instrumented function and adds a data structure in a separate section). When a -tracepoint is "on", the function you provide is called each time the tracepoint -is executed, in the execution context of the caller. When the function provided -ends its execution, it returns to the caller (continuing from the tracepoint -site). +A tracepoint placed in code provides a hook to call a function (probe) +that you can provide at runtime. A tracepoint can be "on" (a probe is +connected to it) or "off" (no probe is attached). When a tracepoint is +"off" it has no effect, except for adding a tiny time penalty +(checking a condition for a branch) and space penalty (adding a few +bytes for the function call at the end of the instrumented function +and adds a data structure in a separate section). When a tracepoint +is "on", the function you provide is called each time the tracepoint +is executed, in the execution context of the caller. When the function +provided ends its execution, it returns to the caller (continuing from +the tracepoint site). You can put tracepoints at important locations in the code. They are lightweight hooks that can pass an arbitrary number of parameters, -which prototypes are described in a tracepoint declaration placed in a header -file. +which prototypes are described in a tracepoint declaration placed in a +header file. They can be used for tracing and performance accounting. @@ -42,14 +44,16 @@ In include/trace/subsys.h : #include -DEFINE_TRACE(subsys_eventname, - TPPTOTO(int firstarg, struct task_struct *p), +DECLARE_TRACE(subsys_eventname, + TPPROTO(int firstarg, struct task_struct *p), TPARGS(firstarg, p)); In subsys/file.c (where the tracing statement must be added) : #include +DEFINE_TRACE(subsys_eventname); + void somefct(void) { ... @@ -61,31 +65,41 @@ Where : - subsys_eventname is an identifier unique to your event - subsys is the name of your subsystem. - eventname is the name of the event to trace. -- TPPTOTO(int firstarg, struct task_struct *p) is the prototype of the function - called by this tracepoint. -- TPARGS(firstarg, p) are the parameters names, same as found in the prototype. -Connecting a function (probe) to a tracepoint is done by providing a probe -(function to call) for the specific tracepoint through -register_trace_subsys_eventname(). Removing a probe is done through -unregister_trace_subsys_eventname(); it will remove the probe sure there is no -caller left using the probe when it returns. Probe removal is preempt-safe -because preemption is disabled around the probe call. See the "Probe example" -section below for a sample probe module. - -The tracepoint mechanism supports inserting multiple instances of the same -tracepoint, but a single definition must be made of a given tracepoint name over -all the kernel to make sure no type conflict will occur. Name mangling of the -tracepoints is done using the prototypes to make sure typing is correct. -Verification of probe type correctness is done at the registration site by the -compiler. Tracepoints can be put in inline functions, inlined static functions, -and unrolled loops as well as regular functions. - -The naming scheme "subsys_event" is suggested here as a convention intended -to limit collisions. Tracepoint names are global to the kernel: they are -considered as being the same whether they are in the core kernel image or in -modules. +- TPPROTO(int firstarg, struct task_struct *p) is the prototype of the + function called by this tracepoint. +- TPARGS(firstarg, p) are the parameters names, same as found in the + prototype. + +Connecting a function (probe) to a tracepoint is done by providing a +probe (function to call) for the specific tracepoint through +register_trace_subsys_eventname(). Removing a probe is done through +unregister_trace_subsys_eventname(); it will remove the probe. + +tracepoint_synchronize_unregister() must be called before the end of +the module exit function to make sure there is no caller left using +the probe. This, and the fact that preemption is disabled around the +probe call, make sure that probe removal and module unload are safe. +See the "Probe example" section below for a sample probe module. + +The tracepoint mechanism supports inserting multiple instances of the +same tracepoint, but a single definition must be made of a given +tracepoint name over all the kernel to make sure no type conflict will +occur. Name mangling of the tracepoints is done using the prototypes +to make sure typing is correct. Verification of probe type correctness +is done at the registration site by the compiler. Tracepoints can be +put in inline functions, inlined static functions, and unrolled loops +as well as regular functions. + +The naming scheme "subsys_event" is suggested here as a convention +intended to limit collisions. Tracepoint names are global to the +kernel: they are considered as being the same whether they are in the +core kernel image or in modules. + +If the tracepoint has to be used in kernel modules, an +EXPORT_TRACEPOINT_SYMBOL_GPL() or EXPORT_TRACEPOINT_SYMBOL() can be +used to export the defined tracepoints. * Probe / tracepoint example diff --git a/Documentation/x86/boot.txt b/Documentation/x86/boot.txt index 83c0033ee9e01d26866494b58115a1da9b2c429a..fcdc62b3c3d8d8d1b826c04ce70a3bf9ea0b2a9b 100644 --- a/Documentation/x86/boot.txt +++ b/Documentation/x86/boot.txt @@ -349,7 +349,7 @@ Protocol: 2.00+ 3 SYSLINUX 4 EtherBoot 5 ELILO - 7 GRuB + 7 GRUB 8 U-BOOT 9 Xen A Gujin @@ -537,8 +537,8 @@ Type: read Offset/size: 0x248/4 Protocol: 2.08+ - If non-zero then this field contains the offset from the end of the - real-mode code to the payload. + If non-zero then this field contains the offset from the beginning + of the protected-mode code to the payload. The payload may be compressed. The format of both the compressed and uncompressed data should be determined using the standard magic diff --git a/Documentation/x86/pat.txt b/Documentation/x86/pat.txt index c93ff5f4c0ddc0e979daa1ad0e950c8c1c6e31c1..cf08c9fff3cdaa62b2217f8e4526d9a7cc88fbec 100644 --- a/Documentation/x86/pat.txt +++ b/Documentation/x86/pat.txt @@ -80,6 +80,30 @@ pci proc | -- | -- | WC | | | | | ------------------------------------------------------------------- +Advanced APIs for drivers +------------------------- +A. Exporting pages to users with remap_pfn_range, io_remap_pfn_range, +vm_insert_pfn + +Drivers wanting to export some pages to userspace do it by using mmap +interface and a combination of +1) pgprot_noncached() +2) io_remap_pfn_range() or remap_pfn_range() or vm_insert_pfn() + +With PAT support, a new API pgprot_writecombine is being added. So, drivers can +continue to use the above sequence, with either pgprot_noncached() or +pgprot_writecombine() in step 1, followed by step 2. + +In addition, step 2 internally tracks the region as UC or WC in memtype +list in order to ensure no conflicting mapping. + +Note that this set of APIs only works with IO (non RAM) regions. If driver +wants to export a RAM region, it has to do set_memory_uc() or set_memory_wc() +as step 0 above and also track the usage of those pages and use set_memory_wb() +before the page is freed to free pool. + + + Notes: -- in the above table mean "Not suggested usage for the API". Some of the --'s diff --git a/Documentation/x86/x86_64/boot-options.txt b/Documentation/x86/x86_64/boot-options.txt index f6d561a1a9b2d3d022baf17bb05138485fb32130..34c13040a718f6febbccadc1f32bc24f4a060664 100644 --- a/Documentation/x86/x86_64/boot-options.txt +++ b/Documentation/x86/x86_64/boot-options.txt @@ -79,17 +79,6 @@ Timing Report when timer interrupts are lost because some code turned off interrupts for too long. - nmi_watchdog=NUMBER[,panic] - NUMBER can be: - 0 don't use an NMI watchdog - 1 use the IO-APIC timer for the NMI watchdog - 2 use the local APIC for the NMI watchdog using a performance counter. Note - This will use one performance counter and the local APIC's performance - vector. - When panic is specified panic when an NMI watchdog timeout occurs. - This is useful when you use a panic=... timeout and need the box - quickly up again. - nohpet Don't use the HPET timer. diff --git a/Documentation/x86/x86_64/mm.txt b/Documentation/x86/x86_64/mm.txt index efce7509736911434e299d0fe63e344c70d7b1e3..29b52b14d0b43950fa79f3948b1fbe4789396fbf 100644 --- a/Documentation/x86/x86_64/mm.txt +++ b/Documentation/x86/x86_64/mm.txt @@ -6,7 +6,7 @@ Virtual memory map with 4 level page tables: 0000000000000000 - 00007fffffffffff (=47 bits) user space, different per mm hole caused by [48:63] sign extension ffff800000000000 - ffff80ffffffffff (=40 bits) guard hole -ffff810000000000 - ffffc0ffffffffff (=46 bits) direct mapping of all phys. memory +ffff880000000000 - ffffc0ffffffffff (=57 TB) direct mapping of all phys. memory ffffc10000000000 - ffffc1ffffffffff (=40 bits) hole ffffc20000000000 - ffffe1ffffffffff (=45 bits) vmalloc/ioremap space ffffe20000000000 - ffffe2ffffffffff (=40 bits) virtual memory map (1TB) diff --git a/MAINTAINERS b/MAINTAINERS index c42a567e010c7db73ef761370179e346867aaf3e..08d0ab7fa1615b093864bf30444a4427109b6d00 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -742,7 +742,7 @@ M: jirislaby@gmail.com P: Nick Kossifidis M: mickflemm@gmail.com P: Luis R. Rodriguez -M: mcgrof@gmail.com +M: lrodriguez@atheros.com P: Bob Copeland M: me@bobcopeland.com L: linux-wireless@vger.kernel.org @@ -1607,11 +1607,6 @@ L: acpi4asus-user@lists.sourceforge.net W: http://sourceforge.net/projects/acpi4asus S: Maintained -EEPRO100 NETWORK DRIVER -P: Andrey V. Savochkin -M: saw@saw.sw.com.sg -S: Maintained - EFS FILESYSTEM W: http://aeschi.ch.eu.org/efs/ S: Orphan @@ -1849,7 +1844,7 @@ P: Haavard Skinnemoen M: hskinnemoen@atmel.com S: Supported -GENERIC HDLC DRIVER, N2, C101, PCI200SYN and WANXL DRIVERS +GENERIC HDLC (WAN) DRIVERS P: Krzysztof Halasa M: khc@pm.waw.pl W: http://www.kernel.org/pub/linux/utils/net/hdlc/ @@ -2248,6 +2243,11 @@ M: dan.j.williams@intel.com L: linux-kernel@vger.kernel.org S: Supported +INTEL IXP4XX QMGR, NPE, ETHERNET and HSS SUPPORT +P: Krzysztof Halasa +M: khc@pm.waw.pl +S: Maintained + INTEL IXP4XX RANDOM NUMBER GENERATOR SUPPORT P: Deepak Saxena M: dsaxena@plexity.net @@ -3614,16 +3614,26 @@ L: linux-hams@vger.kernel.org W: http://www.linux-ax25.org/ S: Maintained -RTL818X WIRELESS DRIVER -P: Michael Wu -M: flamingice@sourmilk.net -P: Andrea Merello -M: andreamrl@tiscali.it +RTL8180 WIRELESS DRIVER +P: John W. Linville +M: linville@tuxdriver.com L: linux-wireless@vger.kernel.org W: http://linuxwireless.org/ -T: git kernel.org:/pub/scm/linux/kernel/git/mwu/mac80211-drivers.git +T: git kernel.org:/pub/scm/linux/kernel/git/linville/wireless-testing.git S: Maintained +RTL8187 WIRELESS DRIVER +P: Herton Ronaldo Krzesinski +M: herton@mandriva.com.br +P: Hin-Tak Leung +M htl10@users.sourceforge.net +P: Larry Finger +M: Larry.Finger@lwfinger.net +L: linux-wireless@vger.kernel.org +W: http://linuxwireless.org/ +T: git kernel.org:/pub/scm/linux/kernel/git/linville/wireless-testing.git +S: Maintained + S3 SAVAGE FRAMEBUFFER DRIVER P: Antonino Daplas M: adaplas@gmail.com @@ -3913,6 +3923,18 @@ M: mhoffman@lightlink.com L: lm-sensors@lm-sensors.org S: Maintained +SMSC911x ETHERNET DRIVER +P: Steve Glendinning +M: steve.glendinning@smsc.com +L: netdev@vger.kernel.org +S: Supported + +SMSC9420 PCI ETHERNET DRIVER +P: Steve Glendinning +M: steve.glendinning@smsc.com +L: netdev@vger.kernel.org +S: Supported + SMX UIO Interface P: Ben Nizette M: bn@niasdigital.com @@ -3977,7 +3999,7 @@ M: tiwai@suse.de L: alsa-devel@alsa-project.org (subscribers-only) S: Maintained -SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT +SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT (ASoC) P: Liam Girdwood M: lrg@slimlogic.co.uk P: Mark Brown @@ -4529,7 +4551,7 @@ S: Maintained USB VIDEO CLASS P: Laurent Pinchart M: laurent.pinchart@skynet.be -L: linux-uvc-devel@lists.berlios.de +L: linux-uvc-devel@lists.berlios.de (subscribers-only) L: video4linux-list@redhat.com W: http://linux-uvc.berlios.de S: Maintained diff --git a/Makefile b/Makefile index 4c8d79710b84b9c6d58b36cd2269e3c5622765f0..09ff7d81809a79fe7ff04a4b29a66eb9cfe10648 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 28 -EXTRAVERSION = -rc9 +EXTRAVERSION = NAME = Erotic Pickled Herring # *DOCUMENTATION* @@ -336,7 +336,7 @@ LINUXINCLUDE := -Iinclude \ -I$(srctree)/arch/$(hdr-arch)/include \ -include include/linux/autoconf.h -KBUILD_CPPFLAGS := -D__KERNEL__ $(LINUXINCLUDE) +KBUILD_CPPFLAGS := -D__KERNEL__ KBUILD_CFLAGS := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \ -fno-strict-aliasing -fno-common \ @@ -439,7 +439,11 @@ ifeq ($(config-targets),1) include $(srctree)/arch/$(SRCARCH)/Makefile export KBUILD_DEFCONFIG KBUILD_KCONFIG -config %config: scripts_basic outputmakefile FORCE +config: scripts_basic outputmakefile FORCE + $(Q)mkdir -p include/linux include/config + $(Q)$(MAKE) $(build)=scripts/kconfig $@ + +%config: scripts_basic outputmakefile FORCE $(Q)mkdir -p include/linux include/config $(Q)$(MAKE) $(build)=scripts/kconfig $@ @@ -600,20 +604,25 @@ export INSTALL_PATH ?= /boot MODLIB = $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE) export MODLIB -# -# INSTALL_MOD_STRIP, if defined, will cause modules to be -# stripped after they are installed. If INSTALL_MOD_STRIP is '1', then -# the default option --strip-debug will be used. Otherwise, -# INSTALL_MOD_STRIP will used as the options to the strip command. +strip-symbols := $(srctree)/scripts/strip-symbols \ + $(wildcard $(srctree)/arch/$(ARCH)/scripts/strip-symbols) +# +# INSTALL_MOD_STRIP, if defined, will cause modules to be stripped while +# they get installed. If INSTALL_MOD_STRIP is '1', then the default +# options (see below) will be used. Otherwise, INSTALL_MOD_STRIP will +# be used as the option(s) to the objcopy command. ifdef INSTALL_MOD_STRIP ifeq ($(INSTALL_MOD_STRIP),1) -mod_strip_cmd = $(STRIP) --strip-debug +mod_strip_cmd = $(OBJCOPY) --strip-debug +ifeq ($(CONFIG_KALLSYMS_ALL),$(CONFIG_KALLSYMS_STRIP_GENERATED)) +mod_strip_cmd += --wildcard $(addprefix --strip-symbols ,$(strip-symbols)) +endif else -mod_strip_cmd = $(STRIP) $(INSTALL_MOD_STRIP) +mod_strip_cmd = $(OBJCOPY) $(INSTALL_MOD_STRIP) endif # INSTALL_MOD_STRIP=1 else -mod_strip_cmd = true +mod_strip_cmd = false endif # INSTALL_MOD_STRIP export mod_strip_cmd @@ -743,6 +752,7 @@ last_kallsyms := 2 endif kallsyms.o := .tmp_kallsyms$(last_kallsyms).o +kallsyms.h := $(wildcard include/config/kallsyms/*.h) $(wildcard include/config/kallsyms/*/*.h) define verify_kallsyms $(Q)$(if $($(quiet)cmd_sysmap), \ @@ -767,24 +777,41 @@ endef # Generate .S file with all kernel symbols quiet_cmd_kallsyms = KSYM $@ - cmd_kallsyms = $(NM) -n $< | $(KALLSYMS) \ - $(if $(CONFIG_KALLSYMS_ALL),--all-symbols) > $@ + cmd_kallsyms = { test $* -eq 0 || $(NM) -n $<; } \ + | $(KALLSYMS) $(if $(CONFIG_KALLSYMS_ALL),--all-symbols) >$@ -.tmp_kallsyms1.o .tmp_kallsyms2.o .tmp_kallsyms3.o: %.o: %.S scripts FORCE +quiet_cmd_kstrip = STRIP $@ + cmd_kstrip = $(OBJCOPY) --wildcard $(addprefix --strip$(if $(CONFIG_RELOCATABLE),-unneeded)-symbols ,$(filter %/scripts/strip-symbols,$^)) $< $@ + +$(foreach n,0 1 2 3,.tmp_kallsyms$(n).o): KBUILD_AFLAGS += -Wa,--strip-local-absolute +$(foreach n,0 1 2 3,.tmp_kallsyms$(n).o): %.o: %.S scripts FORCE $(call if_changed_dep,as_o_S) -.tmp_kallsyms%.S: .tmp_vmlinux% $(KALLSYMS) +ifeq ($(CONFIG_KALLSYMS_STRIP_GENERATED),y) +strip-ext := .stripped +endif + +.tmp_kallsyms%.S: .tmp_vmlinux%$(strip-ext) $(KALLSYMS) $(kallsyms.h) $(call cmd,kallsyms) +# make -jN seems to have problems with intermediate files, see bug #3330. +.SECONDARY: $(foreach n,1 2 3,.tmp_vmlinux$(n).stripped) +.tmp_vmlinux%.stripped: .tmp_vmlinux% $(strip-symbols) $(kallsyms.h) + $(call cmd,kstrip) + +ifneq ($(CONFIG_DEBUG_INFO),y) +.tmp_vmlinux%: LDFLAGS_vmlinux += -S +endif # .tmp_vmlinux1 must be complete except kallsyms, so update vmlinux version -.tmp_vmlinux1: $(vmlinux-lds) $(vmlinux-all) FORCE - $(call if_changed_rule,ksym_ld) +.tmp_vmlinux%: $(vmlinux-lds) $(vmlinux-all) FORCE + $(if $(filter 1,$*),$(call if_changed_rule,ksym_ld),$(call if_changed,vmlinux__)) -.tmp_vmlinux2: $(vmlinux-lds) $(vmlinux-all) .tmp_kallsyms1.o FORCE - $(call if_changed,vmlinux__) +.tmp_vmlinux0$(strip-ext): + $(Q)echo "placeholder" >$@ -.tmp_vmlinux3: $(vmlinux-lds) $(vmlinux-all) .tmp_kallsyms2.o FORCE - $(call if_changed,vmlinux__) +.tmp_vmlinux1: .tmp_kallsyms0.o +.tmp_vmlinux2: .tmp_kallsyms1.o +.tmp_vmlinux3: .tmp_kallsyms2.o # Needs to visit scripts/ before $(KALLSYMS) can be used. $(KALLSYMS): scripts ; @@ -926,7 +953,7 @@ PHONY += prepare archprepare prepare0 prepare1 prepare2 prepare3 # 2) Create the include2 directory, used for the second asm symlink prepare3: include/config/kernel.release ifneq ($(KBUILD_SRC),) - @echo ' Using $(srctree) as source for kernel' + @$(kecho) ' Using $(srctree) as source for kernel' $(Q)if [ -f $(srctree)/.config -o -d $(srctree)/include/config ]; then \ echo " $(srctree) is not clean, please run 'make mrproper'";\ echo " in the '$(srctree)' directory.";\ @@ -983,7 +1010,7 @@ endef # directory for generated filesas used by some architectures. define create-symlink if [ ! -L include/asm ]; then \ - echo ' SYMLINK $@ -> include/asm-$(SRCARCH)'; \ + $(kecho) ' SYMLINK $@ -> include/asm-$(SRCARCH)'; \ if [ ! -d include/asm-$(SRCARCH) ]; then \ mkdir -p include/asm-$(SRCARCH); \ fi; \ @@ -1022,6 +1049,10 @@ include/linux/version.h: $(srctree)/Makefile FORCE include/linux/utsrelease.h: include/config/kernel.release FORCE $(call filechk,utsrelease.h) +PHONY += headerdep +headerdep: + $(Q)find include/ -name '*.h' | xargs --max-args 1 scripts/headerdep.pl + # --------------------------------------------------------------------------- PHONY += depend dep @@ -1096,7 +1127,7 @@ all: modules PHONY += modules modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux) $(Q)$(AWK) '!x[$$0]++' $(vmlinux-dirs:%=$(objtree)/%/modules.order) > $(objtree)/modules.order - @echo ' Building modules, stage 2.'; + @$(kecho) ' Building modules, stage 2.'; $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.fwinst obj=firmware __fw_modbuild @@ -1270,7 +1301,8 @@ help: @echo ' versioncheck - Sanity check on version.h usage' @echo ' includecheck - Check for duplicate included header files' @echo ' export_report - List the usages of all exported symbols' - @echo ' headers_check - Sanity check on exported headers'; \ + @echo ' headers_check - Sanity check on exported headers' + @echo ' headerdep - Detect inclusion cycles in headers'; \ echo '' @echo 'Kernel packaging:' @$(MAKE) $(build)=$(package-dir) help @@ -1360,7 +1392,7 @@ $(module-dirs): crmodverdir $(objtree)/Module.symvers $(Q)$(MAKE) $(build)=$(patsubst _module_%,%,$@) modules: $(module-dirs) - @echo ' Building modules, stage 2.'; + @$(kecho) ' Building modules, stage 2.'; $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost PHONY += modules_install @@ -1409,123 +1441,12 @@ endif # KBUILD_EXTMOD # Generate tags for editors # --------------------------------------------------------------------------- +quiet_cmd_tags = GEN $@ + cmd_tags = $(CONFIG_SHELL) $(srctree)/scripts/tags.sh $@ -#We want __srctree to totally vanish out when KBUILD_OUTPUT is not set -#(which is the most common case IMHO) to avoid unneeded clutter in the big tags file. -#Adding $(srctree) adds about 20M on i386 to the size of the output file! - -ifeq ($(src),$(obj)) -__srctree = -else -__srctree = $(srctree)/ -endif - -ifeq ($(ALLSOURCE_ARCHS),) -ifeq ($(ARCH),um) -ALLINCLUDE_ARCHS := $(ARCH) $(SUBARCH) -else -ALLINCLUDE_ARCHS := $(SRCARCH) -endif -else -#Allow user to specify only ALLSOURCE_PATHS on the command line, keeping existing behaviour. -ALLINCLUDE_ARCHS := $(ALLSOURCE_ARCHS) -endif - -ALLSOURCE_ARCHS := $(SRCARCH) - -define find-sources - ( for arch in $(ALLSOURCE_ARCHS) ; do \ - find $(__srctree)arch/$${arch} $(RCS_FIND_IGNORE) \ - -wholename $(__srctree)arch/$${arch}/include/asm -type d -prune \ - -o -name $1 -print; \ - done ; \ - find $(__srctree)security/selinux/include $(RCS_FIND_IGNORE) \ - -name $1 -print; \ - find $(__srctree)include $(RCS_FIND_IGNORE) \ - \( -name config -o -name 'asm-*' \) -prune \ - -o -name $1 -print; \ - for arch in $(ALLINCLUDE_ARCHS) ; do \ - test -e $(__srctree)include/asm-$${arch} && \ - find $(__srctree)include/asm-$${arch} $(RCS_FIND_IGNORE) \ - -name $1 -print; \ - test -e $(__srctree)arch/$${arch}/include/asm && \ - find $(__srctree)arch/$${arch}/include/asm $(RCS_FIND_IGNORE) \ - -name $1 -print; \ - done ; \ - find $(__srctree)include/asm-generic $(RCS_FIND_IGNORE) \ - -name $1 -print; \ - find $(__srctree) $(RCS_FIND_IGNORE) \ - \( -name include -o -name arch -o -name '.tmp_*' \) -prune -o \ - -name $1 -print; \ - ) -endef - -define all-sources - $(call find-sources,'*.[chS]') -endef -define all-kconfigs - $(call find-sources,'Kconfig*') -endef -define all-defconfigs - $(call find-sources,'defconfig') -endef - -define xtags - if $1 --version 2>&1 | grep -iq exuberant; then \ - $(all-sources) | xargs $1 -a \ - -I __initdata,__exitdata,__acquires,__releases \ - -I __read_mostly,____cacheline_aligned,____cacheline_aligned_in_smp,____cacheline_internodealigned_in_smp \ - -I EXPORT_SYMBOL,EXPORT_SYMBOL_GPL \ - --extra=+f --c-kinds=+px \ - --regex-asm='/^ENTRY\(([^)]*)\).*/\1/'; \ - $(all-kconfigs) | xargs $1 -a \ - --langdef=kconfig \ - --language-force=kconfig \ - --regex-kconfig='/^[[:blank:]]*(menu|)config[[:blank:]]+([[:alnum:]_]+)/\2/'; \ - $(all-defconfigs) | xargs -r $1 -a \ - --langdef=dotconfig \ - --language-force=dotconfig \ - --regex-dotconfig='/^#?[[:blank:]]*(CONFIG_[[:alnum:]_]+)/\1/'; \ - elif $1 --version 2>&1 | grep -iq emacs; then \ - $(all-sources) | xargs $1 -a; \ - $(all-kconfigs) | xargs $1 -a \ - --regex='/^[ \t]*\(\(menu\)*config\)[ \t]+\([a-zA-Z0-9_]+\)/\3/'; \ - $(all-defconfigs) | xargs -r $1 -a \ - --regex='/^#?[ \t]?\(CONFIG_[a-zA-Z0-9_]+\)/\1/'; \ - else \ - $(all-sources) | xargs $1 -a; \ - fi -endef - -quiet_cmd_cscope-file = FILELST cscope.files - cmd_cscope-file = (echo \-k; echo \-q; $(all-sources)) > cscope.files - -quiet_cmd_cscope = MAKE cscope.out - cmd_cscope = cscope -b -f cscope.out - -cscope: FORCE - $(call cmd,cscope-file) - $(call cmd,cscope) - -quiet_cmd_TAGS = MAKE $@ -define cmd_TAGS - rm -f $@; \ - $(call xtags,etags) -endef - -TAGS: FORCE - $(call cmd,TAGS) - -quiet_cmd_tags = MAKE $@ -define cmd_tags - rm -f $@; \ - $(call xtags,ctags) -endef - -tags: FORCE +tags TAGS cscope: FORCE $(call cmd,tags) - # Scripts to check various things for consistency # --------------------------------------------------------------------------- @@ -1604,7 +1525,11 @@ endif $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) # Modules -/ %/: prepare scripts FORCE +/: prepare scripts FORCE + $(cmd_crmodverdir) + $(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) \ + $(build)=$(build-dir) +%/: prepare scripts FORCE $(cmd_crmodverdir) $(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) \ $(build)=$(build-dir) @@ -1638,7 +1563,7 @@ cmd_crmodverdir = $(Q)mkdir -p $(MODVERDIR) \ $(if $(KBUILD_MODULES),; rm -f $(MODVERDIR)/*) a_flags = -Wp,-MD,$(depfile) $(KBUILD_AFLAGS) $(AFLAGS_KERNEL) \ - $(NOSTDINC_FLAGS) $(KBUILD_CPPFLAGS) \ + $(NOSTDINC_FLAGS) $(LINUXINCLUDE) $(KBUILD_CPPFLAGS) \ $(modkern_aflags) $(EXTRA_AFLAGS) $(AFLAGS_$(basetarget).o) quiet_cmd_as_o_S = AS $@ diff --git a/arch/alpha/kernel/asm-offsets.c b/arch/alpha/kernel/asm-offsets.c index 4b18cd94d59d5060acfac02ad276101579ca481a..6ff8886e7e22b9c4af281abe417a99a88596a3d1 100644 --- a/arch/alpha/kernel/asm-offsets.c +++ b/arch/alpha/kernel/asm-offsets.c @@ -19,15 +19,18 @@ void foo(void) BLANK(); DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked)); - DEFINE(TASK_UID, offsetof(struct task_struct, uid)); - DEFINE(TASK_EUID, offsetof(struct task_struct, euid)); - DEFINE(TASK_GID, offsetof(struct task_struct, gid)); - DEFINE(TASK_EGID, offsetof(struct task_struct, egid)); + DEFINE(TASK_CRED, offsetof(struct task_struct, cred)); DEFINE(TASK_REAL_PARENT, offsetof(struct task_struct, real_parent)); DEFINE(TASK_GROUP_LEADER, offsetof(struct task_struct, group_leader)); DEFINE(TASK_TGID, offsetof(struct task_struct, tgid)); BLANK(); + DEFINE(CRED_UID, offsetof(struct cred, uid)); + DEFINE(CRED_EUID, offsetof(struct cred, euid)); + DEFINE(CRED_GID, offsetof(struct cred, gid)); + DEFINE(CRED_EGID, offsetof(struct cred, egid)); + BLANK(); + DEFINE(SIZEOF_PT_REGS, sizeof(struct pt_regs)); DEFINE(PT_PTRACED, PT_PTRACED); DEFINE(CLONE_VM, CLONE_VM); diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S index 5fc61e281ac77724cbcf0270b4269dd4559a686b..f77345bc66a975ff244c2e4b83be931fbc50a096 100644 --- a/arch/alpha/kernel/entry.S +++ b/arch/alpha/kernel/entry.S @@ -850,8 +850,9 @@ osf_getpriority: sys_getxuid: .prologue 0 ldq $2, TI_TASK($8) - ldl $0, TASK_UID($2) - ldl $1, TASK_EUID($2) + ldq $3, TASK_CRED($2) + ldl $0, CRED_UID($3) + ldl $1, CRED_EUID($3) stq $1, 80($sp) ret .end sys_getxuid @@ -862,8 +863,9 @@ sys_getxuid: sys_getxgid: .prologue 0 ldq $2, TI_TASK($8) - ldl $0, TASK_GID($2) - ldl $1, TASK_EGID($2) + ldq $3, TASK_CRED($2) + ldl $0, CRED_GID($3) + ldl $1, CRED_EGID($3) stq $1, 80($sp) ret .end sys_getxgid diff --git a/arch/arm/mach-ixp4xx/fsg-setup.c b/arch/arm/mach-ixp4xx/fsg-setup.c index e7c6386782ede189976cb4cb6b59fa2b7af97497..5add22fc98999ac57b0da0f688926b4f65c0dcfc 100644 --- a/arch/arm/mach-ixp4xx/fsg-setup.c +++ b/arch/arm/mach-ixp4xx/fsg-setup.c @@ -177,7 +177,6 @@ static irqreturn_t fsg_reset_handler(int irq, void *dev_id) static void __init fsg_init(void) { - DECLARE_MAC_BUF(mac_buf); uint8_t __iomem *f; ixp4xx_sys_init(); @@ -256,10 +255,10 @@ static void __init fsg_init(void) #endif iounmap(f); } - printk(KERN_INFO "FSG: Using MAC address %s for port 0\n", - print_mac(mac_buf, fsg_plat_eth[0].hwaddr)); - printk(KERN_INFO "FSG: Using MAC address %s for port 1\n", - print_mac(mac_buf, fsg_plat_eth[1].hwaddr)); + printk(KERN_INFO "FSG: Using MAC address %pM for port 0\n", + fsg_plat_eth[0].hwaddr); + printk(KERN_INFO "FSG: Using MAC address %pM for port 1\n", + fsg_plat_eth[1].hwaddr); } diff --git a/arch/arm/mach-ixp4xx/include/mach/qmgr.h b/arch/arm/mach-ixp4xx/include/mach/qmgr.h index 1e52b95cede5518db0b73630cf65d2bc46f82315..0cbe6ceb67c5a012837221f8e9a95509689dea94 100644 --- a/arch/arm/mach-ixp4xx/include/mach/qmgr.h +++ b/arch/arm/mach-ixp4xx/include/mach/qmgr.h @@ -12,6 +12,8 @@ #include #include +#define DEBUG_QMGR 0 + #define HALF_QUEUES 32 #define QUEUES 64 /* only 32 lower queues currently supported */ #define MAX_QUEUE_LENGTH 4 /* in dwords */ @@ -61,22 +63,51 @@ void qmgr_enable_irq(unsigned int queue); void qmgr_disable_irq(unsigned int queue); /* request_ and release_queue() must be called from non-IRQ context */ + +#if DEBUG_QMGR +extern char qmgr_queue_descs[QUEUES][32]; + int qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */, unsigned int nearly_empty_watermark, - unsigned int nearly_full_watermark); + unsigned int nearly_full_watermark, + const char *desc_format, const char* name); +#else +int __qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */, + unsigned int nearly_empty_watermark, + unsigned int nearly_full_watermark); +#define qmgr_request_queue(queue, len, nearly_empty_watermark, \ + nearly_full_watermark, desc_format, name) \ + __qmgr_request_queue(queue, len, nearly_empty_watermark, \ + nearly_full_watermark) +#endif + void qmgr_release_queue(unsigned int queue); static inline void qmgr_put_entry(unsigned int queue, u32 val) { extern struct qmgr_regs __iomem *qmgr_regs; +#if DEBUG_QMGR + BUG_ON(!qmgr_queue_descs[queue]); /* not yet requested */ + + printk(KERN_DEBUG "Queue %s(%i) put %X\n", + qmgr_queue_descs[queue], queue, val); +#endif __raw_writel(val, &qmgr_regs->acc[queue][0]); } static inline u32 qmgr_get_entry(unsigned int queue) { + u32 val; extern struct qmgr_regs __iomem *qmgr_regs; - return __raw_readl(&qmgr_regs->acc[queue][0]); + val = __raw_readl(&qmgr_regs->acc[queue][0]); +#if DEBUG_QMGR + BUG_ON(!qmgr_queue_descs[queue]); /* not yet requested */ + + printk(KERN_DEBUG "Queue %s(%i) get %X\n", + qmgr_queue_descs[queue], queue, val); +#endif + return val; } static inline int qmgr_get_stat1(unsigned int queue) diff --git a/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c b/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c index c6cb069a5a83cea283e94dfc906f1ae81558a320..bfddc73d0a200b358b80761891106e5237b22799 100644 --- a/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c +++ b/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c @@ -14,8 +14,6 @@ #include #include -#define DEBUG 0 - struct qmgr_regs __iomem *qmgr_regs; static struct resource *mem_res; static spinlock_t qmgr_lock; @@ -23,6 +21,10 @@ static u32 used_sram_bitmap[4]; /* 128 16-dword pages */ static void (*irq_handlers[HALF_QUEUES])(void *pdev); static void *irq_pdevs[HALF_QUEUES]; +#if DEBUG_QMGR +char qmgr_queue_descs[QUEUES][32]; +#endif + void qmgr_set_irq(unsigned int queue, int src, void (*handler)(void *pdev), void *pdev) { @@ -70,6 +72,7 @@ void qmgr_disable_irq(unsigned int queue) spin_lock_irqsave(&qmgr_lock, flags); __raw_writel(__raw_readl(&qmgr_regs->irqen[0]) & ~(1 << queue), &qmgr_regs->irqen[0]); + __raw_writel(1 << queue, &qmgr_regs->irqstat[0]); /* clear */ spin_unlock_irqrestore(&qmgr_lock, flags); } @@ -81,9 +84,16 @@ static inline void shift_mask(u32 *mask) mask[0] <<= 1; } +#if DEBUG_QMGR int qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */, unsigned int nearly_empty_watermark, - unsigned int nearly_full_watermark) + unsigned int nearly_full_watermark, + const char *desc_format, const char* name) +#else +int __qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */, + unsigned int nearly_empty_watermark, + unsigned int nearly_full_watermark) +#endif { u32 cfg, addr = 0, mask[4]; /* in 16-dwords */ int err; @@ -151,12 +161,13 @@ int qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */, used_sram_bitmap[2] |= mask[2]; used_sram_bitmap[3] |= mask[3]; __raw_writel(cfg | (addr << 14), &qmgr_regs->sram[queue]); - spin_unlock_irq(&qmgr_lock); - -#if DEBUG - printk(KERN_DEBUG "qmgr: requested queue %i, addr = 0x%02X\n", - queue, addr); +#if DEBUG_QMGR + snprintf(qmgr_queue_descs[queue], sizeof(qmgr_queue_descs[0]), + desc_format, name); + printk(KERN_DEBUG "qmgr: requested queue %s(%i) addr = 0x%02X\n", + qmgr_queue_descs[queue], queue, addr); #endif + spin_unlock_irq(&qmgr_lock); return 0; err: @@ -189,6 +200,11 @@ void qmgr_release_queue(unsigned int queue) while (addr--) shift_mask(mask); +#if DEBUG_QMGR + printk(KERN_DEBUG "qmgr: releasing queue %s(%i)\n", + qmgr_queue_descs[queue], queue); + qmgr_queue_descs[queue][0] = '\x0'; +#endif __raw_writel(0, &qmgr_regs->sram[queue]); used_sram_bitmap[0] &= ~mask[0]; @@ -199,9 +215,10 @@ void qmgr_release_queue(unsigned int queue) spin_unlock_irq(&qmgr_lock); module_put(THIS_MODULE); -#if DEBUG - printk(KERN_DEBUG "qmgr: released queue %i\n", queue); -#endif + + while ((addr = qmgr_get_entry(queue))) + printk(KERN_ERR "qmgr: released queue %i not empty: 0x%08X\n", + queue, addr); } static int qmgr_init(void) @@ -272,5 +289,10 @@ EXPORT_SYMBOL(qmgr_regs); EXPORT_SYMBOL(qmgr_set_irq); EXPORT_SYMBOL(qmgr_enable_irq); EXPORT_SYMBOL(qmgr_disable_irq); +#if DEBUG_QMGR +EXPORT_SYMBOL(qmgr_queue_descs); EXPORT_SYMBOL(qmgr_request_queue); +#else +EXPORT_SYMBOL(__qmgr_request_queue); +#endif EXPORT_SYMBOL(qmgr_release_queue); diff --git a/arch/arm/mach-ixp4xx/nas100d-setup.c b/arch/arm/mach-ixp4xx/nas100d-setup.c index 0acd95ecf27ef39e716a2c27cf470e30c666c640..921c947b5b6b33f170f279525cf8e87dfc0697a4 100644 --- a/arch/arm/mach-ixp4xx/nas100d-setup.c +++ b/arch/arm/mach-ixp4xx/nas100d-setup.c @@ -231,7 +231,6 @@ static irqreturn_t nas100d_reset_handler(int irq, void *dev_id) static void __init nas100d_init(void) { - DECLARE_MAC_BUF(mac_buf); uint8_t __iomem *f; int i; @@ -294,8 +293,8 @@ static void __init nas100d_init(void) #endif iounmap(f); } - printk(KERN_INFO "NAS100D: Using MAC address %s for port 0\n", - print_mac(mac_buf, nas100d_plat_eth[0].hwaddr)); + printk(KERN_INFO "NAS100D: Using MAC address %pM for port 0\n", + nas100d_plat_eth[0].hwaddr); } diff --git a/arch/arm/mach-ixp4xx/nslu2-setup.c b/arch/arm/mach-ixp4xx/nslu2-setup.c index bc9d920ae54f0f28a58597682abcc0e9c0c99c5e..ff6a08d02cc42e8b050c3c91eced3b490ec92877 100644 --- a/arch/arm/mach-ixp4xx/nslu2-setup.c +++ b/arch/arm/mach-ixp4xx/nslu2-setup.c @@ -220,7 +220,6 @@ static struct sys_timer nslu2_timer = { static void __init nslu2_init(void) { - DECLARE_MAC_BUF(mac_buf); uint8_t __iomem *f; int i; @@ -275,8 +274,8 @@ static void __init nslu2_init(void) #endif iounmap(f); } - printk(KERN_INFO "NSLU2: Using MAC address %s for port 0\n", - print_mac(mac_buf, nslu2_plat_eth[0].hwaddr)); + printk(KERN_INFO "NSLU2: Using MAC address %pM for port 0\n", + nslu2_plat_eth[0].hwaddr); } diff --git a/arch/arm/mach-pxa/include/mach/palmasoc.h b/arch/arm/mach-pxa/include/mach/palmasoc.h new file mode 100644 index 0000000000000000000000000000000000000000..6c4b1f7de20aa1f7e84bedc127e820e18f50ad21 --- /dev/null +++ b/arch/arm/mach-pxa/include/mach/palmasoc.h @@ -0,0 +1,13 @@ +#ifndef _INCLUDE_PALMASOC_H_ +#define _INCLUDE_PALMASOC_H_ +struct palm27x_asoc_info { + int jack_gpio; +}; + +#ifdef CONFIG_SND_PXA2XX_SOC_PALM27X +void __init palm27x_asoc_set_pdata(struct palm27x_asoc_info *data); +#else +static inline void palm27x_asoc_set_pdata(struct palm27x_asoc_info *data) {} +#endif + +#endif diff --git a/arch/blackfin/boot/Makefile b/arch/blackfin/boot/Makefile index 522f3c12406041128bdfedc6639bcfbfa7893f05..e028d13481a93660c9843cde769517500c8046f5 100644 --- a/arch/blackfin/boot/Makefile +++ b/arch/blackfin/boot/Makefile @@ -25,7 +25,7 @@ $(obj)/vmlinux.gz: $(obj)/vmlinux.bin FORCE $(obj)/vmImage: $(obj)/vmlinux.gz $(call if_changed,uimage) - @echo 'Kernel: $@ is ready' + @$(kecho) 'Kernel: $@ is ready' install: sh $(srctree)/$(src)/install.sh $(KERNELRELEASE) $(BOOTIMAGE) System.map "$(INSTALL_PATH)" diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index 6bd91ed7cd03a8366d35745a499ea89c9daf93a6..7fa8f615ba6e7edaec647959f8d4623fcab4bad5 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig @@ -99,7 +99,7 @@ config GENERIC_IOMAP bool default y -config SCHED_NO_NO_OMIT_FRAME_POINTER +config SCHED_OMIT_FRAME_POINTER bool default y diff --git a/arch/ia64/hp/sim/simeth.c b/arch/ia64/hp/sim/simeth.c index 3d47839a0c488c5625bb6903b68e74d31b0489e8..e4d8fde68103b84a18492b1a0d1a9a47c8fd9011 100644 --- a/arch/ia64/hp/sim/simeth.c +++ b/arch/ia64/hp/sim/simeth.c @@ -167,6 +167,15 @@ netdev_read(int fd, unsigned char *buf, unsigned int len) return ia64_ssc(fd, __pa(buf), len, 0, SSC_NETDEV_RECV); } +static const struct net_device_ops simeth_netdev_ops = { + .ndo_open = simeth_open, + .ndo_stop = simeth_close, + .ndo_start_xmit = simeth_tx, + .ndo_get_stats = simeth_get_stats, + .ndo_set_multicast_list = set_multicast_list, /* not yet used */ + +}; + /* * Function shared with module code, so cannot be in init section * @@ -206,14 +215,10 @@ simeth_probe1(void) memcpy(dev->dev_addr, mac_addr, sizeof(mac_addr)); - local = dev->priv; + local = netdev_priv(dev); local->simfd = fd; /* keep track of underlying file descriptor */ - dev->open = simeth_open; - dev->stop = simeth_close; - dev->hard_start_xmit = simeth_tx; - dev->get_stats = simeth_get_stats; - dev->set_multicast_list = set_multicast_list; /* no yet used */ + dev->netdev_ops = &simeth_netdev_ops; err = register_netdev(dev); if (err) { @@ -325,7 +330,7 @@ simeth_device_event(struct notifier_block *this,unsigned long event, void *ptr) * we get DOWN then UP. */ - local = dev->priv; + local = netdev_priv(dev); /* now do it for real */ r = event == NETDEV_UP ? netdev_attach(local->simfd, dev->irq, ntohl(ifa->ifa_local)): @@ -380,7 +385,7 @@ frame_print(unsigned char *from, unsigned char *frame, int len) static int simeth_tx(struct sk_buff *skb, struct net_device *dev) { - struct simeth_local *local = dev->priv; + struct simeth_local *local = netdev_priv(dev); #if 0 /* ensure we have at least ETH_ZLEN bytes (min frame size) */ @@ -443,7 +448,7 @@ simeth_rx(struct net_device *dev) int len; int rcv_count = SIMETH_RECV_MAX; - local = dev->priv; + local = netdev_priv(dev); /* * the loop concept has been borrowed from other drivers * looks to me like it's a throttling thing to avoid pushing to many @@ -507,7 +512,7 @@ simeth_interrupt(int irq, void *dev_id) static struct net_device_stats * simeth_get_stats(struct net_device *dev) { - struct simeth_local *local = dev->priv; + struct simeth_local *local = netdev_priv(dev); return &local->stats; } diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c index 5e92ae00bdbba8403ee69ddd12d33ca44ce34699..16ef61a91d95810de82668fa23eefbd2d993a25c 100644 --- a/arch/ia64/ia32/sys_ia32.c +++ b/arch/ia64/ia32/sys_ia32.c @@ -1767,25 +1767,24 @@ groups16_from_user(struct group_info *group_info, short __user *grouplist) asmlinkage long sys32_getgroups16 (int gidsetsize, short __user *grouplist) { + const struct cred *cred = current_cred(); int i; if (gidsetsize < 0) return -EINVAL; - get_group_info(current->group_info); - i = current->group_info->ngroups; + i = cred->group_info->ngroups; if (gidsetsize) { if (i > gidsetsize) { i = -EINVAL; goto out; } - if (groups16_to_user(grouplist, current->group_info)) { + if (groups16_to_user(grouplist, cred->group_info)) { i = -EFAULT; goto out; } } out: - put_group_info(current->group_info); return i; } diff --git a/arch/ia64/kernel/mca_drv.c b/arch/ia64/kernel/mca_drv.c index fab1d21a4f2c1cfe4443aa8812518d4a6bfeaeb6..f94aaa86933fd81f0b347466907e16bdfcf10781 100644 --- a/arch/ia64/kernel/mca_drv.c +++ b/arch/ia64/kernel/mca_drv.c @@ -158,7 +158,7 @@ mca_handler_bh(unsigned long paddr, void *iip, unsigned long ipsr) ia64_mlogbuf_dump(); printk(KERN_ERR "OS_MCA: process [cpu %d, pid: %d, uid: %d, " "iip: %p, psr: 0x%lx,paddr: 0x%lx](%s) encounters MCA.\n", - raw_smp_processor_id(), current->pid, current->uid, + raw_smp_processor_id(), current->pid, current_uid(), iip, ipsr, paddr, current->comm); spin_lock(&mca_bh_lock); diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c index 6543a5547c84669434e5d4dbc3d962400a714f57..0e499757309bfbdab35d1233126e4259d9f42bdd 100644 --- a/arch/ia64/kernel/perfmon.c +++ b/arch/ia64/kernel/perfmon.c @@ -2220,8 +2220,8 @@ pfm_alloc_file(pfm_context_t *ctx) DPRINT(("new inode ino=%ld @%p\n", inode->i_ino, inode)); inode->i_mode = S_IFCHR|S_IRUGO; - inode->i_uid = current->fsuid; - inode->i_gid = current->fsgid; + inode->i_uid = current_fsuid(); + inode->i_gid = current_fsgid(); sprintf(name, "[%lu]", inode->i_ino); this.name = name; @@ -2399,22 +2399,33 @@ pfm_smpl_buffer_alloc(struct task_struct *task, struct file *filp, pfm_context_t static int pfm_bad_permissions(struct task_struct *task) { + const struct cred *tcred; + uid_t uid = current_uid(); + gid_t gid = current_gid(); + int ret; + + rcu_read_lock(); + tcred = __task_cred(task); + /* inspired by ptrace_attach() */ DPRINT(("cur: uid=%d gid=%d task: euid=%d suid=%d uid=%d egid=%d sgid=%d\n", - current->uid, - current->gid, - task->euid, - task->suid, - task->uid, - task->egid, - task->sgid)); - - return ((current->uid != task->euid) - || (current->uid != task->suid) - || (current->uid != task->uid) - || (current->gid != task->egid) - || (current->gid != task->sgid) - || (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE); + uid, + gid, + tcred->euid, + tcred->suid, + tcred->uid, + tcred->egid, + tcred->sgid)); + + ret = ((uid != tcred->euid) + || (uid != tcred->suid) + || (uid != tcred->uid) + || (gid != tcred->egid) + || (gid != tcred->sgid) + || (gid != tcred->gid)) && !capable(CAP_SYS_PTRACE); + + rcu_read_unlock(); + return ret; } static int diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c index e12500a9c44390b025feeb0b670baac1c1ffd523..e1821ca4c7dfddea3827102e2bd63a016e1162f3 100644 --- a/arch/ia64/kernel/signal.c +++ b/arch/ia64/kernel/signal.c @@ -229,7 +229,7 @@ ia64_rt_sigreturn (struct sigscratch *scr) si.si_errno = 0; si.si_code = SI_KERNEL; si.si_pid = task_pid_vnr(current); - si.si_uid = current->uid; + si.si_uid = current_uid(); si.si_addr = sc; force_sig_info(SIGSEGV, &si, current); return retval; @@ -326,7 +326,7 @@ force_sigsegv_info (int sig, void __user *addr) si.si_errno = 0; si.si_code = SI_KERNEL; si.si_pid = task_pid_vnr(current); - si.si_uid = current->uid; + si.si_uid = current_uid(); si.si_addr = addr; force_sig_info(SIGSEGV, &si, current); return 0; diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig index dbaed4a638153bc43c5fa4d6e138039bb5cca8df..29047d5c259aa9a2f9622bf15f9baa1e3d21dfcc 100644 --- a/arch/m32r/Kconfig +++ b/arch/m32r/Kconfig @@ -273,7 +273,7 @@ config GENERIC_CALIBRATE_DELAY bool default y -config SCHED_NO_NO_OMIT_FRAME_POINTER +config SCHED_OMIT_FRAME_POINTER bool default y diff --git a/arch/m68k/fpsp040/setox.S b/arch/m68k/fpsp040/setox.S index 145af5447581f1f3719549dd9cf7494c02dc44be..f1acf7e36d6b826c77c167efdefaa5729b140977 100644 --- a/arch/m68k/fpsp040/setox.S +++ b/arch/m68k/fpsp040/setox.S @@ -36,9 +36,9 @@ | depending on their values, the program may run faster or slower -- | but no worse than 10% slower even in the extreme cases. | -| The program setoxm1 takes approximately ???/??? cycles for input +| The program setoxm1 takes approximately ??? / ??? cycles for input | argument X, 0.25 <= |X| < 70log2. For |X| < 0.25, it takes -| approximately ???/??? cycles. For the less common arguments, +| approximately ??? / ??? cycles. For the less common arguments, | depending on their values, the program may run faster or slower -- | but no worse than 10% slower even in the extreme cases. | diff --git a/arch/m68k/mac/baboon.c b/arch/m68k/mac/baboon.c index c7b25b0aacffab1a7f6212cf9e83103d2dd8198c..245d16d078ad817c93bacf94fc15f72803e8e337 100644 --- a/arch/m68k/mac/baboon.c +++ b/arch/m68k/mac/baboon.c @@ -18,11 +18,14 @@ #include #include -/* #define DEBUG_BABOON */ /* #define DEBUG_IRQS */ +extern void mac_enable_irq(unsigned int); +extern void mac_disable_irq(unsigned int); + int baboon_present; static volatile struct baboon *baboon; +static unsigned char baboon_disabled; #if 0 extern int macide_ack_intr(struct ata_channel *); @@ -88,34 +91,51 @@ static irqreturn_t baboon_irq(int irq, void *dev_id) void __init baboon_register_interrupts(void) { - request_irq(IRQ_NUBUS_C, baboon_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, - "baboon", (void *) baboon); + baboon_disabled = 0; + request_irq(IRQ_NUBUS_C, baboon_irq, 0, "baboon", (void *)baboon); } -void baboon_irq_enable(int irq) { +/* + * The means for masking individual baboon interrupts remains a mystery, so + * enable the umbrella interrupt only when no baboon interrupt is disabled. + */ + +void baboon_irq_enable(int irq) +{ + int irq_idx = IRQ_IDX(irq); + #ifdef DEBUG_IRQUSE printk("baboon_irq_enable(%d)\n", irq); #endif - /* FIXME: figure out how to mask and unmask baboon interrupt sources */ - enable_irq(IRQ_NUBUS_C); + + baboon_disabled &= ~(1 << irq_idx); + if (!baboon_disabled) + mac_enable_irq(IRQ_NUBUS_C); } -void baboon_irq_disable(int irq) { +void baboon_irq_disable(int irq) +{ + int irq_idx = IRQ_IDX(irq); + #ifdef DEBUG_IRQUSE printk("baboon_irq_disable(%d)\n", irq); #endif - disable_irq(IRQ_NUBUS_C); + + baboon_disabled |= 1 << irq_idx; + if (baboon_disabled) + mac_disable_irq(IRQ_NUBUS_C); } -void baboon_irq_clear(int irq) { - int irq_idx = IRQ_IDX(irq); +void baboon_irq_clear(int irq) +{ + int irq_idx = IRQ_IDX(irq); baboon->mb_ifr &= ~(1 << irq_idx); } int baboon_irq_pending(int irq) { - int irq_idx = IRQ_IDX(irq); + int irq_idx = IRQ_IDX(irq); return baboon->mb_ifr & (1 << irq_idx); } diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c index c45e18449f321b820f08dc12409dfadc0083cf60..8819b97be32401b096587de6dcdda41e504a1749 100644 --- a/arch/m68k/mac/config.c +++ b/arch/m68k/mac/config.c @@ -162,10 +162,7 @@ void __init config_mac(void) mach_init_IRQ = mac_init_IRQ; mach_get_model = mac_get_model; mach_gettimeoffset = mac_gettimeoffset; -#warning move to adb/via init -#if 0 mach_hwclk = mac_hwclk; -#endif mach_set_clock_mmss = mac_set_clock_mmss; mach_reset = mac_reset; mach_halt = mac_poweroff; diff --git a/arch/m68k/mac/debug.c b/arch/m68k/mac/debug.c index 2165740786a551f2cb975d0fd359a79366ff08ad..65dd77a742a341c493a64982b16a0ec5de60d445 100644 --- a/arch/m68k/mac/debug.c +++ b/arch/m68k/mac/debug.c @@ -24,7 +24,6 @@ #define BOOTINFO_COMPAT_1_0 #include #include -#include #include extern unsigned long mac_videobase; diff --git a/arch/m68k/mac/macints.c b/arch/m68k/mac/macints.c index ecddac4a02b95abc11f80dbff860d2bdaea32fbd..82e560c076ce31e1cf82968ac3622f7c58c9a135 100644 --- a/arch/m68k/mac/macints.c +++ b/arch/m68k/mac/macints.c @@ -127,7 +127,6 @@ #include #include #include -#include #include #include #include @@ -215,8 +214,8 @@ irqreturn_t mac_debug_handler(int, void *); /* #define DEBUG_MACINTS */ -static void mac_enable_irq(unsigned int irq); -static void mac_disable_irq(unsigned int irq); +void mac_enable_irq(unsigned int irq); +void mac_disable_irq(unsigned int irq); static struct irq_controller mac_irq_controller = { .name = "mac", @@ -275,7 +274,7 @@ void __init mac_init_IRQ(void) * These routines are just dispatchers to the VIA/OSS/PSC routines. */ -static void mac_enable_irq(unsigned int irq) +void mac_enable_irq(unsigned int irq) { int irq_src = IRQ_SRC(irq); @@ -308,7 +307,7 @@ static void mac_enable_irq(unsigned int irq) } } -static void mac_disable_irq(unsigned int irq) +void mac_disable_irq(unsigned int irq) { int irq_src = IRQ_SRC(irq); diff --git a/arch/m68k/mac/misc.c b/arch/m68k/mac/misc.c index 56d1f5676ade43628f578c8786dd1e3bf7d1f818..a44c7086ab39a3b9352f2b3c5f0202b9e57bd471 100644 --- a/arch/m68k/mac/misc.c +++ b/arch/m68k/mac/misc.c @@ -93,7 +93,7 @@ static void cuda_write_pram(int offset, __u8 data) #define cuda_write_pram NULL #endif -#ifdef CONFIG_ADB_PMU68K +#if 0 /* def CONFIG_ADB_PMU68K */ static long pmu_read_time(void) { struct adb_request req; @@ -148,7 +148,7 @@ static void pmu_write_pram(int offset, __u8 data) #define pmu_write_pram NULL #endif -#ifdef CONFIG_ADB_MACIISI +#if 0 /* def CONFIG_ADB_MACIISI */ extern int maciisi_request(struct adb_request *req, void (*done)(struct adb_request *), int nbytes, ...); @@ -717,13 +717,18 @@ int mac_hwclk(int op, struct rtc_time *t) unmktime(now, 0, &t->tm_year, &t->tm_mon, &t->tm_mday, &t->tm_hour, &t->tm_min, &t->tm_sec); +#if 0 printk("mac_hwclk: read %04d-%02d-%-2d %02d:%02d:%02d\n", - t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); + t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, + t->tm_hour, t->tm_min, t->tm_sec); +#endif } else { /* write */ +#if 0 printk("mac_hwclk: tried to write %04d-%02d-%-2d %02d:%02d:%02d\n", - t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); + t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, + t->tm_hour, t->tm_min, t->tm_sec); +#endif -#if 0 /* it trashes my rtc */ now = mktime(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); @@ -742,7 +747,6 @@ int mac_hwclk(int op, struct rtc_time *t) case MAC_ADB_IISI: maciisi_write_time(now); } -#endif } return 0; } diff --git a/arch/m68k/mac/oss.c b/arch/m68k/mac/oss.c index 43d83e054b8e455888671e3b30b1f4240de501a7..8426501119ca82bf641b3098c4a726d696cc26bb 100644 --- a/arch/m68k/mac/oss.c +++ b/arch/m68k/mac/oss.c @@ -21,7 +21,6 @@ #include #include -#include #include #include #include diff --git a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c index 1bdb03c73c0f4d2c70d9e4251eb6b3280ed8ae9f..f01d418e64fed5c1fa6c67f9566577d774ec2785 100644 --- a/arch/m68k/mac/via.c +++ b/arch/m68k/mac/via.c @@ -32,15 +32,10 @@ #include #include #include -#include #include #include volatile __u8 *via1, *via2; -#if 0 -/* See note in mac_via.h about how this is possibly not useful */ -volatile long *via_memory_bogon=(long *)&via_memory_bogon; -#endif int rbv_present; int via_alt_mapping; EXPORT_SYMBOL(via_alt_mapping); @@ -66,7 +61,7 @@ static int gIER,gIFR,gBufA,gBufB; #define MAC_CLOCK_LOW (MAC_CLOCK_TICK&0xFF) #define MAC_CLOCK_HIGH (MAC_CLOCK_TICK>>8) -/* To disable a NuBus slot on Quadras we make the slot IRQ lines outputs, set +/* To disable a NuBus slot on Quadras we make that slot IRQ line an output set * high. On RBV we just use the slot interrupt enable register. On Macs with * genuine VIA chips we must use nubus_disabled to keep track of disabled slot * interrupts. When any slot IRQ is disabled we mask the (edge triggered) CA1 @@ -180,7 +175,7 @@ void __init via_init(void) via1[vT1CH] = 0; via1[vT2CL] = 0; via1[vT2CH] = 0; - via1[vACR] &= 0x3F; + via1[vACR] &= ~0xC0; /* setup T1 timer with no PB7 output */ via1[vACR] &= ~0x03; /* disable port A & B latches */ /* @@ -203,40 +198,41 @@ void __init via_init(void) /* Everything below this point is VIA2/RBV only... */ - if (oss_present) return; + if (oss_present) + return; -#if 1 /* Some machines support an alternate IRQ mapping that spreads */ /* Ethernet and Sound out to their own autolevel IRQs and moves */ /* VIA1 to level 6. A/UX uses this mapping and we do too. Note */ /* that the IIfx emulates this alternate mapping using the OSS. */ - switch(macintosh_config->ident) { - case MAC_MODEL_P475: - case MAC_MODEL_P475F: - case MAC_MODEL_P575: - case MAC_MODEL_Q605: - case MAC_MODEL_Q605_ACC: - case MAC_MODEL_C610: - case MAC_MODEL_Q610: - case MAC_MODEL_Q630: - case MAC_MODEL_C650: - case MAC_MODEL_Q650: - case MAC_MODEL_Q700: - case MAC_MODEL_Q800: - case MAC_MODEL_Q900: - case MAC_MODEL_Q950: + via_alt_mapping = 0; + if (macintosh_config->via_type == MAC_VIA_QUADRA) + switch (macintosh_config->ident) { + case MAC_MODEL_C660: + case MAC_MODEL_Q840: + /* not applicable */ + break; + case MAC_MODEL_P588: + case MAC_MODEL_TV: + case MAC_MODEL_PB140: + case MAC_MODEL_PB145: + case MAC_MODEL_PB160: + case MAC_MODEL_PB165: + case MAC_MODEL_PB165C: + case MAC_MODEL_PB170: + case MAC_MODEL_PB180: + case MAC_MODEL_PB180C: + case MAC_MODEL_PB190: + case MAC_MODEL_PB520: + /* not yet tested */ + break; + default: via_alt_mapping = 1; via1[vDirB] |= 0x40; via1[vBufB] &= ~0x40; break; - default: - via_alt_mapping = 0; - break; - } -#else - via_alt_mapping = 0; -#endif + } /* * Now initialize VIA2. For RBV we just kill all interrupts; @@ -252,14 +248,17 @@ void __init via_init(void) via2[vT1CH] = 0; via2[vT2CL] = 0; via2[vT2CH] = 0; - via2[vACR] &= 0x3F; + via2[vACR] &= ~0xC0; /* setup T1 timer with no PB7 output */ via2[vACR] &= ~0x03; /* disable port A & B latches */ } /* - * Set vPCR for SCSI interrupts (but not on RBV) + * Set vPCR for control line interrupts (but not on RBV) */ if (!rbv_present) { + /* For all VIA types, CA1 (SLOTS IRQ) and CB1 (ASC IRQ) + * are made negative edge triggered here. + */ if (macintosh_config->scsi_type == MAC_SCSI_OLD) { /* CB2 (IRQ) indep. input, positive edge */ /* CA2 (DRQ) indep. input, positive edge */ @@ -466,21 +465,6 @@ irqreturn_t via1_irq(int irq, void *dev_id) ++irq_num; irq_bit <<= 1; } while (events >= irq_bit); - -#if 0 /* freakin' pmu is doing weird stuff */ - if (!oss_present) { - /* This (still) seems to be necessary to get IDE - working. However, if you enable VBL interrupts, - you're screwed... */ - /* FIXME: should we check the SLOTIRQ bit before - pulling this stunt? */ - /* No, it won't be set. that's why we're doing this. */ - via_irq_disable(IRQ_MAC_NUBUS); - via_irq_clear(IRQ_MAC_NUBUS); - m68k_handle_int(IRQ_MAC_NUBUS); - via_irq_enable(IRQ_MAC_NUBUS); - } -#endif return IRQ_HANDLED; } diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index f4af967a6b3081173b9183d8e735d133382072c5..a5255e7c79e004001a8f55c82e33d964198b403f 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -653,7 +653,7 @@ config GENERIC_CMOS_UPDATE bool default y -config SCHED_NO_NO_OMIT_FRAME_POINTER +config SCHED_OMIT_FRAME_POINTER bool default y diff --git a/arch/mips/include/asm/byteorder.h b/arch/mips/include/asm/byteorder.h index 2988d29a0867f4c0ce187040e710e3c87344030d..33790b9e0cc0d46ee41f0ec8d3f3dbf181c8a9fc 100644 --- a/arch/mips/include/asm/byteorder.h +++ b/arch/mips/include/asm/byteorder.h @@ -50,9 +50,8 @@ static inline __attribute_const__ __u32 __arch_swab32(__u32 x) static inline __attribute_const__ __u64 __arch_swab64(__u64 x) { __asm__( - " dsbh %0, %1 \n" - " dshd %0, %0 \n" - " drotr %0, %0, 32 \n" + " dsbh %0, %1\n" + " dshd %0, %0" : "=r" (x) : "r" (x)); diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h index a8eac1697b3ddcf05dccc71d42267c549cc40904..d58f128aa747be974ac10ffd5fb1749d3292f505 100644 --- a/arch/mips/include/asm/elf.h +++ b/arch/mips/include/asm/elf.h @@ -232,7 +232,7 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; */ #ifdef __MIPSEB__ #define ELF_DATA ELFDATA2MSB -#elif __MIPSEL__ +#elif defined(__MIPSEL__) #define ELF_DATA ELFDATA2LSB #endif #define ELF_ARCH EM_MIPS diff --git a/arch/mips/kernel/kspd.c b/arch/mips/kernel/kspd.c index b0591ae0ce566456ed7c88eaa955d191a17bcaaa..fd6e512240347aac0a17b848cd9e1b42657badaf 100644 --- a/arch/mips/kernel/kspd.c +++ b/arch/mips/kernel/kspd.c @@ -174,8 +174,8 @@ static unsigned int translate_open_flags(int flags) static void sp_setfsuidgid( uid_t uid, gid_t gid) { - current->fsuid = uid; - current->fsgid = gid; + current->cred->fsuid = uid; + current->cred->fsgid = gid; key_fsuid_changed(current); key_fsgid_changed(current); diff --git a/arch/mips/kernel/mips-mt-fpaff.c b/arch/mips/kernel/mips-mt-fpaff.c index dc9eb72ed9de956164f557b0757496dae6638c2e..5e77a3a21f98e7926cc789915ad65bbe64911a1a 100644 --- a/arch/mips/kernel/mips-mt-fpaff.c +++ b/arch/mips/kernel/mips-mt-fpaff.c @@ -51,6 +51,7 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len, int retval; struct task_struct *p; struct thread_info *ti; + uid_t euid; if (len < sizeof(new_mask)) return -EINVAL; @@ -76,9 +77,9 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len, */ get_task_struct(p); + euid = current_euid(); retval = -EPERM; - if ((current->euid != p->euid) && (current->euid != p->uid) && - !capable(CAP_SYS_NICE)) { + if (euid != p->euid && euid != p->uid && !capable(CAP_SYS_NICE)) { read_unlock(&tasklist_lock); goto out_unlock; } diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c index a1b3da6bad5cb17c577712ac4bf83f439b5d7292..010b27e01f7bf9c03dd1b55c64fe15ca69c14100 100644 --- a/arch/mips/kernel/vpe.c +++ b/arch/mips/kernel/vpe.c @@ -1085,8 +1085,8 @@ static int vpe_open(struct inode *inode, struct file *filp) v->load_addr = NULL; v->len = 0; - v->uid = filp->f_uid; - v->gid = filp->f_gid; + v->uid = filp->f_cred->fsuid; + v->gid = filp->f_cred->fsgid; #ifdef CONFIG_MIPS_APSP_KSPD /* get kspd to tell us when a syscall_exit happens */ diff --git a/arch/parisc/include/asm/tlbflush.h b/arch/parisc/include/asm/tlbflush.h index b72ec66db699e56f0985ebd6d88d82a7ceb14411..1f6fd4fc05b91b518f4f574b3ada13ddd24b285a 100644 --- a/arch/parisc/include/asm/tlbflush.h +++ b/arch/parisc/include/asm/tlbflush.h @@ -44,9 +44,12 @@ static inline void flush_tlb_mm(struct mm_struct *mm) { BUG_ON(mm == &init_mm); /* Should never happen */ -#ifdef CONFIG_SMP +#if 1 || defined(CONFIG_SMP) flush_tlb_all(); #else + /* FIXME: currently broken, causing space id and protection ids + * to go out of sync, resulting in faults on userspace accesses. + */ if (mm) { if (mm->context != 0) free_sid(mm->context); diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index 06213d1d6d958f54d8a3139f9443aab13a5bbaed..f82544225e8e8b43b8ca76664101a849d1e8a7f7 100644 --- a/arch/parisc/kernel/signal.c +++ b/arch/parisc/kernel/signal.c @@ -182,7 +182,7 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall) si.si_errno = 0; si.si_code = SI_KERNEL; si.si_pid = task_pid_vnr(current); - si.si_uid = current->uid; + si.si_uid = current_uid(); si.si_addr = &frame->uc; force_sig_info(SIGSEGV, &si, current); return; diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 525c13a4de93ede9cd9451569d41cd20760b3636..79f25cef32dfe72b0d230ce6642ce95c747f080d 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -141,7 +141,7 @@ config GENERIC_NVRAM bool default y if PPC32 -config SCHED_NO_NO_OMIT_FRAME_POINTER +config SCHED_OMIT_FRAME_POINTER bool default y @@ -285,6 +285,10 @@ config IOMMU_VMERGE config IOMMU_HELPER def_bool PPC64 +config PPC_NEED_DMA_SYNC_OPS + def_bool y + depends on NOT_COHERENT_CACHE + config HOTPLUG_CPU bool "Support for enabling/disabling CPUs" depends on SMP && HOTPLUG && EXPERIMENTAL && (PPC_PSERIES || PPC_PMAC) @@ -322,7 +326,7 @@ config KEXEC config CRASH_DUMP bool "Build a kdump crash kernel" - depends on PPC_MULTIPLATFORM && PPC64 && RELOCATABLE + depends on (PPC64 && RELOCATABLE) || 6xx help Build a kernel suitable for use as a kdump capture kernel. The same kernel binary can be used as production kernel and dump @@ -401,23 +405,53 @@ config PPC_HAS_HASH_64K depends on PPC64 default n -config PPC_64K_PAGES - bool "64k page size" - depends on PPC64 - select PPC_HAS_HASH_64K +choice + prompt "Page size" + default PPC_4K_PAGES help - This option changes the kernel logical page size to 64k. On machines - without processor support for 64k pages, the kernel will simulate - them by loading each individual 4k page on demand transparently, - while on hardware with such support, it will be used to map - normal application pages. + Select the kernel logical page size. Increasing the page size + will reduce software overhead at each page boundary, allow + hardware prefetch mechanisms to be more effective, and allow + larger dma transfers increasing IO efficiency and reducing + overhead. However the utilization of memory will increase. + For example, each cached file will using a multiple of the + page size to hold its contents and the difference between the + end of file and the end of page is wasted. + + Some dedicated systems, such as software raid serving with + accelerated calculations, have shown significant increases. + + If you configure a 64 bit kernel for 64k pages but the + processor does not support them, then the kernel will simulate + them with 4k pages, loading them on demand, but with the + reduced software overhead and larger internal fragmentation. + For the 32 bit kernel, a large page option will not be offered + unless it is supported by the configured processor. + + If unsure, choose 4K_PAGES. + +config PPC_4K_PAGES + bool "4k page size" + +config PPC_16K_PAGES + bool "16k page size" if 44x + +config PPC_64K_PAGES + bool "64k page size" if 44x || PPC_STD_MMU_64 + select PPC_HAS_HASH_64K if PPC_STD_MMU_64 + +endchoice config FORCE_MAX_ZONEORDER int "Maximum zone order" - range 9 64 if PPC_64K_PAGES - default "9" if PPC_64K_PAGES - range 13 64 if PPC64 && !PPC_64K_PAGES - default "13" if PPC64 && !PPC_64K_PAGES + range 9 64 if PPC_STD_MMU_64 && PPC_64K_PAGES + default "9" if PPC_STD_MMU_64 && PPC_64K_PAGES + range 13 64 if PPC_STD_MMU_64 && !PPC_64K_PAGES + default "13" if PPC_STD_MMU_64 && !PPC_64K_PAGES + range 9 64 if PPC_STD_MMU_32 && PPC_16K_PAGES + default "9" if PPC_STD_MMU_32 && PPC_16K_PAGES + range 7 64 if PPC_STD_MMU_32 && PPC_64K_PAGES + default "7" if PPC_STD_MMU_32 && PPC_64K_PAGES range 11 64 default "11" help @@ -437,7 +471,7 @@ config FORCE_MAX_ZONEORDER config PPC_SUBPAGE_PROT bool "Support setting protections for 4k subpages" - depends on PPC_64K_PAGES + depends on PPC_STD_MMU_64 && PPC_64K_PAGES help This option adds support for a system call to allow user programs to set access permissions (read/write, readonly, or no access) diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug index 15eb27861fc713c1b02995fd030bc139652b24d2..08f7cc0a1953a2c3bae6c88e165f44e50379c23d 100644 --- a/arch/powerpc/Kconfig.debug +++ b/arch/powerpc/Kconfig.debug @@ -2,6 +2,15 @@ menu "Kernel hacking" source "lib/Kconfig.debug" +config PRINT_STACK_DEPTH + int "Stack depth to print" if DEBUG_KERNEL + default 64 + help + This option allows you to set the stack depth that the kernel + prints in stack traces. This can be useful if your display is + too small and stack traces cause important information to + scroll off the screen. + config DEBUG_STACKOVERFLOW bool "Check for stack overflows" depends on DEBUG_KERNEL diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 1f06670699404aafb55cb990b148bd4ba4a14f41..72d17f50e54fa7befc6b920fb781d393dd04a98a 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -107,7 +107,6 @@ KBUILD_CFLAGS += $(call cc-option,-mno-altivec) # (We use all available options to help semi-broken compilers) KBUILD_CFLAGS += $(call cc-option,-mno-spe) KBUILD_CFLAGS += $(call cc-option,-mspe=no) -KBUILD_CFLAGS += $(call cc-option,-mabi=no-spe) # Enable unit-at-a-time mode when possible. It shrinks the # kernel considerably. diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index 3d3daa674299038072e3d8e7f2d36f3181b5cb1f..f32829937aad4a8a60ed5aa521d94537cfd10510 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -194,6 +194,7 @@ image-$(CONFIG_PPC_MAPLE) += zImage.pseries image-$(CONFIG_PPC_IBM_CELL_BLADE) += zImage.pseries image-$(CONFIG_PPC_PS3) += dtbImage.ps3 image-$(CONFIG_PPC_CELLEB) += zImage.pseries +image-$(CONFIG_PPC_CELL_QPACE) += zImage.pseries image-$(CONFIG_PPC_CHRP) += zImage.chrp image-$(CONFIG_PPC_EFIKA) += zImage.chrp image-$(CONFIG_PPC_PMAC) += zImage.pmac diff --git a/arch/powerpc/boot/devtree.c b/arch/powerpc/boot/devtree.c index 5d12336dc3609d9d0cb9df0089f273ffc7fabe77..a7e21a35c03af6a7bd584cccf6b140f85157d7cf 100644 --- a/arch/powerpc/boot/devtree.c +++ b/arch/powerpc/boot/devtree.c @@ -213,7 +213,7 @@ static int find_range(u32 *reg, u32 *ranges, int nregaddr, u32 range_addr[MAX_ADDR_CELLS]; u32 range_size[MAX_ADDR_CELLS]; - copy_val(range_addr, ranges + i, naddr); + copy_val(range_addr, ranges + i, nregaddr); copy_val(range_size, ranges + i + nregaddr + naddr, nsize); if (compare_reg(reg, range_addr, range_size)) diff --git a/arch/powerpc/boot/dts/asp834x-redboot.dts b/arch/powerpc/boot/dts/asp834x-redboot.dts index 6235fca445de43ec0418cc2beb8c0bf91919bff3..524af7ef9f26742e388aa7b6f21adbe75df2b8e5 100644 --- a/arch/powerpc/boot/dts/asp834x-redboot.dts +++ b/arch/powerpc/boot/dts/asp834x-redboot.dts @@ -199,8 +199,26 @@ reg = <0x2>; device_type = "ethernet-phy"; }; + + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + enet0: ethernet@24000 { cell-index = <0>; device_type = "network"; @@ -210,6 +228,7 @@ local-mac-address = [ 00 08 e5 11 32 33 ]; interrupts = <32 0x8 33 0x8 34 0x8>; interrupt-parent = <&ipic>; + tbi-handle = <&tbi0>; phy-handle = <&phy0>; linux,network-index = <0>; }; @@ -223,6 +242,7 @@ local-mac-address = [ 00 08 e5 11 32 34 ]; interrupts = <35 0x8 36 0x8 37 0x8>; interrupt-parent = <&ipic>; + tbi-handle = <&tbi1>; phy-handle = <&phy1>; linux,network-index = <1>; }; diff --git a/arch/powerpc/boot/dts/bamboo.dts b/arch/powerpc/boot/dts/bamboo.dts index 6ce0cc2c0208e311e7924903d511f1c998a9ce4c..aa68911f6560a21449d19c283d0c0388016c5429 100644 --- a/arch/powerpc/boot/dts/bamboo.dts +++ b/arch/powerpc/boot/dts/bamboo.dts @@ -269,7 +269,8 @@ * later cannot be changed. Chip supports a second * IO range but we don't use it for now */ - ranges = <0x02000000 0x00000000 0xa0000000 0x00000000 0xa0000000 0x00000000 0x20000000 + ranges = <0x02000000 0x00000000 0xa0000000 0x00000000 0xa0000000 0x00000000 0x40000000 + 0x02000000 0x00000000 0x00000000 0x00000000 0xe0000000 0x00000000 0x00100000 0x01000000 0x00000000 0x00000000 0x00000000 0xe8000000 0x00000000 0x00010000>; /* Inbound 2GB range starting at 0 */ diff --git a/arch/powerpc/boot/dts/canyonlands.dts b/arch/powerpc/boot/dts/canyonlands.dts index 79fe412c11c9c0d0dfcf14b737492095129c4197..8b5ba8261a36ad54d80863881da214d3bc273d71 100644 --- a/arch/powerpc/boot/dts/canyonlands.dts +++ b/arch/powerpc/boot/dts/canyonlands.dts @@ -40,6 +40,7 @@ d-cache-size = <32768>; dcr-controller; dcr-access-method = "native"; + next-level-cache = <&L2C0>; }; }; @@ -104,6 +105,16 @@ dcr-reg = <0x00c 0x002>; }; + L2C0: l2c { + compatible = "ibm,l2-cache-460ex", "ibm,l2-cache"; + dcr-reg = <0x020 0x008 /* Internal SRAM DCR's */ + 0x030 0x008>; /* L2 cache DCR's */ + cache-line-size = <32>; /* 32 bytes */ + cache-size = <262144>; /* L2, 256K */ + interrupt-parent = <&UIC1>; + interrupts = <11 1>; + }; + plb { compatible = "ibm,plb-460ex", "ibm,plb4"; #address-cells = <2>; @@ -343,6 +354,7 @@ * later cannot be changed */ ranges = <0x02000000 0x00000000 0x80000000 0x0000000d 0x80000000 0x00000000 0x80000000 + 0x02000000 0x00000000 0x00000000 0x0000000c 0x0ee00000 0x00000000 0x00100000 0x01000000 0x00000000 0x00000000 0x0000000c 0x08000000 0x00000000 0x00010000>; /* Inbound 2GB range starting at 0 */ @@ -373,6 +385,7 @@ * later cannot be changed */ ranges = <0x02000000 0x00000000 0x80000000 0x0000000e 0x00000000 0x00000000 0x80000000 + 0x02000000 0x00000000 0x00000000 0x0000000f 0x00000000 0x00000000 0x00100000 0x01000000 0x00000000 0x00000000 0x0000000f 0x80000000 0x00000000 0x00010000>; /* Inbound 2GB range starting at 0 */ @@ -414,6 +427,7 @@ * later cannot be changed */ ranges = <0x02000000 0x00000000 0x80000000 0x0000000e 0x80000000 0x00000000 0x80000000 + 0x02000000 0x00000000 0x00000000 0x0000000f 0x00100000 0x00000000 0x00100000 0x01000000 0x00000000 0x00000000 0x0000000f 0x80010000 0x00000000 0x00010000>; /* Inbound 2GB range starting at 0 */ diff --git a/arch/powerpc/boot/dts/gef_sbc610.dts b/arch/powerpc/boot/dts/gef_sbc610.dts index e48cfa740c8aebaa35cb1cc7453bf0e607ea64a9..9708b3423bbdc11615a481f572af7792e38d0bbe 100644 --- a/arch/powerpc/boot/dts/gef_sbc610.dts +++ b/arch/powerpc/boot/dts/gef_sbc610.dts @@ -98,6 +98,12 @@ interrupt-parent = <&mpic>; }; + gef_gpio: gpio@7,14000 { + #gpio-cells = <2>; + compatible = "gef,sbc610-gpio"; + reg = <0x7 0x14000 0x24>; + gpio-controller; + }; }; soc@fef00000 { @@ -119,6 +125,11 @@ interrupt-parent = <&mpic>; dfsrr; + rtc@51 { + compatible = "epson,rx8581"; + reg = <0x00000051>; + }; + eti@6b { compatible = "dallas,ds1682"; reg = <0x6b>; diff --git a/arch/powerpc/boot/dts/ksi8560.dts b/arch/powerpc/boot/dts/ksi8560.dts index 49737589ffc81f65778a2dbf4a8476427ab49e09..3bfff47418db434c1520637b557d7812ad62b9ae 100644 --- a/arch/powerpc/boot/dts/ksi8560.dts +++ b/arch/powerpc/boot/dts/ksi8560.dts @@ -141,8 +141,26 @@ reg = <0x2>; device_type = "ethernet-phy"; }; + + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + enet0: ethernet@24000 { device_type = "network"; model = "TSEC"; @@ -152,6 +170,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <0x1d 0x2 0x1e 0x2 0x22 0x2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&PHY1>; }; @@ -164,6 +183,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <0x23 0x2 0x24 0x2 0x28 0x2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&PHY2>; }; diff --git a/arch/powerpc/boot/dts/kuroboxHD.dts b/arch/powerpc/boot/dts/kuroboxHD.dts index 2e5a1a1812b6343fa2e82f806a3b99527c9354b7..8d725d10882f3959e82c6271640d8fc4cf32b60d 100644 --- a/arch/powerpc/boot/dts/kuroboxHD.dts +++ b/arch/powerpc/boot/dts/kuroboxHD.dts @@ -76,7 +76,6 @@ XXXX add flash parts, rtc, ?? interrupt-parent = <&mpic>; rtc@32 { - device_type = "rtc"; compatible = "ricoh,rs5c372a"; reg = <0x32>; }; diff --git a/arch/powerpc/boot/dts/kuroboxHG.dts b/arch/powerpc/boot/dts/kuroboxHG.dts index e4916e69ad31fc33d9768875d679252a996144b1..b13a11eb81b01883769451405aca54a0cfe730b6 100644 --- a/arch/powerpc/boot/dts/kuroboxHG.dts +++ b/arch/powerpc/boot/dts/kuroboxHG.dts @@ -76,7 +76,6 @@ XXXX add flash parts, rtc, ?? interrupt-parent = <&mpic>; rtc@32 { - device_type = "rtc"; compatible = "ricoh,rs5c372a"; reg = <0x32>; }; diff --git a/arch/powerpc/boot/dts/lite5200.dts b/arch/powerpc/boot/dts/lite5200.dts index 2cf9a8768f4482218fe71eb1c2f368aeb3f9220f..3f7a5dce8de0bc397bde3177927cd65667118f1f 100644 --- a/arch/powerpc/boot/dts/lite5200.dts +++ b/arch/powerpc/boot/dts/lite5200.dts @@ -130,7 +130,6 @@ rtc@800 { // Real time clock compatible = "fsl,mpc5200-rtc"; - device_type = "rtc"; reg = <0x800 0x100>; interrupts = <1 5 0 1 6 0>; interrupt-parent = <&mpc5200_pic>; diff --git a/arch/powerpc/boot/dts/lite5200b.dts b/arch/powerpc/boot/dts/lite5200b.dts index 7bd5b9c399b8fe2933c171cb7c7790b1f0cb54a3..63e3bb48e843980953aa844b64862e7910f4a3f6 100644 --- a/arch/powerpc/boot/dts/lite5200b.dts +++ b/arch/powerpc/boot/dts/lite5200b.dts @@ -130,7 +130,6 @@ rtc@800 { // Real time clock compatible = "fsl,mpc5200b-rtc","fsl,mpc5200-rtc"; - device_type = "rtc"; reg = <0x800 0x100>; interrupts = <1 5 0 1 6 0>; interrupt-parent = <&mpc5200_pic>; diff --git a/arch/powerpc/boot/dts/motionpro.dts b/arch/powerpc/boot/dts/motionpro.dts index 9e3c921be16473b79934384b6145c97b17a3e186..52ba6f98b27311d351c114118cc4333a06474396 100644 --- a/arch/powerpc/boot/dts/motionpro.dts +++ b/arch/powerpc/boot/dts/motionpro.dts @@ -248,7 +248,6 @@ fsl5200-clocking; rtc@68 { - device_type = "rtc"; compatible = "dallas,ds1339"; reg = <0x68>; }; diff --git a/arch/powerpc/boot/dts/mpc8313erdb.dts b/arch/powerpc/boot/dts/mpc8313erdb.dts index 503031766825362e63a2691e0d98df1cd4611405..d4df8b6857a447c790a2f0f3e508bae22ca3e5ae 100644 --- a/arch/powerpc/boot/dts/mpc8313erdb.dts +++ b/arch/powerpc/boot/dts/mpc8313erdb.dts @@ -190,6 +190,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <37 0x8 36 0x8 35 0x8>; interrupt-parent = <&ipic>; + tbi-handle = < &tbi0 >; phy-handle = < &phy1 >; fsl,magic-packet; @@ -210,6 +211,10 @@ reg = <0x4>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; }; @@ -222,9 +227,24 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <34 0x8 33 0x8 32 0x8>; interrupt-parent = <&ipic>; + tbi-handle = < &tbi1 >; phy-handle = < &phy4 >; sleep = <&pmc 0x10000000>; fsl,magic-packet; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + }; serial0: serial@4500 { diff --git a/arch/powerpc/boot/dts/mpc8315erdb.dts b/arch/powerpc/boot/dts/mpc8315erdb.dts index 6b850670de1df9da01b043dac83dea9c3afa550d..072c9b0f8c8e837845e8bb9af1b5a433186e675d 100644 --- a/arch/powerpc/boot/dts/mpc8315erdb.dts +++ b/arch/powerpc/boot/dts/mpc8315erdb.dts @@ -117,7 +117,6 @@ interrupt-parent = <&ipic>; dfsrr; rtc@68 { - device_type = "rtc"; compatible = "dallas,ds1339"; reg = <0x68>; }; @@ -206,8 +205,25 @@ reg = <0x1>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; + enet0: ethernet@24000 { cell-index = <0>; device_type = "network"; @@ -217,6 +233,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <32 0x8 33 0x8 34 0x8>; interrupt-parent = <&ipic>; + tbi-handle = <&tbi0>; phy-handle = < &phy0 >; }; @@ -229,6 +246,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 0x8 36 0x8 37 0x8>; interrupt-parent = <&ipic>; + tbi-handle = <&tbi1>; phy-handle = < &phy1 >; }; diff --git a/arch/powerpc/boot/dts/mpc8349emitx.dts b/arch/powerpc/boot/dts/mpc8349emitx.dts index 4bdbaf4993a185c176000890f1c999108f6b2f11..b5eda94a8e2aa3afb1b108b138de1ff68cb5ed6f 100644 --- a/arch/powerpc/boot/dts/mpc8349emitx.dts +++ b/arch/powerpc/boot/dts/mpc8349emitx.dts @@ -85,7 +85,6 @@ dfsrr; rtc@68 { - device_type = "rtc"; compatible = "dallas,ds1339"; reg = <0x68>; interrupts = <18 0x8>; @@ -184,6 +183,22 @@ reg = <0x1c>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -195,6 +210,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <32 0x8 33 0x8 34 0x8>; interrupt-parent = <&ipic>; + tbi-handle = <&tbi0>; phy-handle = <&phy1c>; linux,network-index = <0>; }; @@ -211,6 +227,7 @@ /* Vitesse 7385 isn't on the MDIO bus */ fixed-link = <1 1 1000 0 0>; linux,network-index = <1>; + tbi-handle = <&tbi1>; }; serial0: serial@4500 { diff --git a/arch/powerpc/boot/dts/mpc8349emitxgp.dts b/arch/powerpc/boot/dts/mpc8349emitxgp.dts index fa40647ee62e9bb74ef363ff6c2c9962b8a6dac2..c87a6015e165a9ac5aaf4f57fef1f76900e8ede8 100644 --- a/arch/powerpc/boot/dts/mpc8349emitxgp.dts +++ b/arch/powerpc/boot/dts/mpc8349emitxgp.dts @@ -83,7 +83,6 @@ dfsrr; rtc@68 { - device_type = "rtc"; compatible = "dallas,ds1339"; reg = <0x68>; interrupts = <18 0x8>; @@ -163,6 +162,10 @@ reg = <0x1c>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -174,6 +177,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <32 0x8 33 0x8 34 0x8>; interrupt-parent = <&ipic>; + tbi-handle = <&tbi0>; phy-handle = <&phy1c>; linux,network-index = <0>; }; diff --git a/arch/powerpc/boot/dts/mpc834x_mds.dts b/arch/powerpc/boot/dts/mpc834x_mds.dts index c986c541e9bba8b9d013ede8db8e2017dc9ee6ee..d9adba01c09c7564898dca8bd5a2f3fd9e1e9c26 100644 --- a/arch/powerpc/boot/dts/mpc834x_mds.dts +++ b/arch/powerpc/boot/dts/mpc834x_mds.dts @@ -185,8 +185,25 @@ reg = <0x1>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; + enet0: ethernet@24000 { cell-index = <0>; device_type = "network"; @@ -196,6 +213,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <32 0x8 33 0x8 34 0x8>; interrupt-parent = <&ipic>; + tbi-handle = <&tbi0>; phy-handle = <&phy0>; linux,network-index = <0>; }; @@ -209,6 +227,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 0x8 36 0x8 37 0x8>; interrupt-parent = <&ipic>; + tbi-handle = <&tbi1>; phy-handle = <&phy1>; linux,network-index = <1>; }; diff --git a/arch/powerpc/boot/dts/mpc8377_mds.dts b/arch/powerpc/boot/dts/mpc8377_mds.dts index 0484561bd2c022aab258f40a2ea523144c663339..1d14d7052e6d534711ae067fe3dee07b89f6ed84 100644 --- a/arch/powerpc/boot/dts/mpc8377_mds.dts +++ b/arch/powerpc/boot/dts/mpc8377_mds.dts @@ -193,8 +193,25 @@ reg = <0x3>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; + enet0: ethernet@24000 { cell-index = <0>; device_type = "network"; @@ -205,6 +222,7 @@ interrupts = <32 0x8 33 0x8 34 0x8>; phy-connection-type = "mii"; interrupt-parent = <&ipic>; + tbi-handle = <&tbi0>; phy-handle = <&phy2>; }; @@ -218,6 +236,7 @@ interrupts = <35 0x8 36 0x8 37 0x8>; phy-connection-type = "mii"; interrupt-parent = <&ipic>; + tbi-handle = <&tbi1>; phy-handle = <&phy3>; }; diff --git a/arch/powerpc/boot/dts/mpc8377_rdb.dts b/arch/powerpc/boot/dts/mpc8377_rdb.dts index 435ef3dd022d0f3614f85e7bbcffced5c0102cd7..9413af3b99259c14fa1ea9127896d89f20dd5dcb 100644 --- a/arch/powerpc/boot/dts/mpc8377_rdb.dts +++ b/arch/powerpc/boot/dts/mpc8377_rdb.dts @@ -117,7 +117,6 @@ interrupt-parent = <&ipic>; dfsrr; rtc@68 { - device_type = "rtc"; compatible = "dallas,ds1339"; reg = <0x68>; }; @@ -211,8 +210,25 @@ reg = <0x2>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; + enet0: ethernet@24000 { cell-index = <0>; device_type = "network"; @@ -223,6 +239,7 @@ interrupts = <32 0x8 33 0x8 34 0x8>; phy-connection-type = "mii"; interrupt-parent = <&ipic>; + tbi-handle = <&tbi0>; phy-handle = <&phy2>; }; @@ -237,6 +254,7 @@ phy-connection-type = "mii"; interrupt-parent = <&ipic>; fixed-link = <1 1 1000 0 0>; + tbi-handle = <&tbi1>; }; serial0: serial@4500 { diff --git a/arch/powerpc/boot/dts/mpc8378_mds.dts b/arch/powerpc/boot/dts/mpc8378_mds.dts index 67a08d2e2ff254fff684ecfc550cd73e680f0318..b85fc02682d250991d3af01c3966dcd859704901 100644 --- a/arch/powerpc/boot/dts/mpc8378_mds.dts +++ b/arch/powerpc/boot/dts/mpc8378_mds.dts @@ -232,8 +232,25 @@ reg = <0x3>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; + enet0: ethernet@24000 { cell-index = <0>; device_type = "network"; @@ -244,6 +261,7 @@ interrupts = <32 0x8 33 0x8 34 0x8>; phy-connection-type = "mii"; interrupt-parent = <&ipic>; + tbi-handle = <&tbi0>; phy-handle = <&phy2>; }; @@ -257,6 +275,7 @@ interrupts = <35 0x8 36 0x8 37 0x8>; phy-connection-type = "mii"; interrupt-parent = <&ipic>; + tbi-handle = <&tbi1>; phy-handle = <&phy3>; }; diff --git a/arch/powerpc/boot/dts/mpc8378_rdb.dts b/arch/powerpc/boot/dts/mpc8378_rdb.dts index b11e68f56a0612d302ce61bee6d2c56f03f01f3b..23c10ce22c2cd6b95597e52a975eed284d54ddea 100644 --- a/arch/powerpc/boot/dts/mpc8378_rdb.dts +++ b/arch/powerpc/boot/dts/mpc8378_rdb.dts @@ -117,7 +117,6 @@ interrupt-parent = <&ipic>; dfsrr; rtc@68 { - device_type = "rtc"; compatible = "dallas,ds1339"; reg = <0x68>; }; @@ -211,8 +210,25 @@ reg = <0x2>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; + enet0: ethernet@24000 { cell-index = <0>; device_type = "network"; diff --git a/arch/powerpc/boot/dts/mpc8379_mds.dts b/arch/powerpc/boot/dts/mpc8379_mds.dts index 323370a2b5ff6fa38266e593b66110f8230fc33c..acf06c438dbf60bc5beb736a373ec7b24ce5a0af 100644 --- a/arch/powerpc/boot/dts/mpc8379_mds.dts +++ b/arch/powerpc/boot/dts/mpc8379_mds.dts @@ -232,6 +232,22 @@ reg = <0x3>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -244,6 +260,7 @@ interrupts = <32 0x8 33 0x8 34 0x8>; phy-connection-type = "mii"; interrupt-parent = <&ipic>; + tbi-handle = <&tbi0>; phy-handle = <&phy2>; }; @@ -257,6 +274,7 @@ interrupts = <35 0x8 36 0x8 37 0x8>; phy-connection-type = "mii"; interrupt-parent = <&ipic>; + tbi-handle = <&tbi1>; phy-handle = <&phy3>; }; diff --git a/arch/powerpc/boot/dts/mpc8379_rdb.dts b/arch/powerpc/boot/dts/mpc8379_rdb.dts index 337af6ea26d3817247543fa94ddddba9ee135ee9..72cdc3c4c7e36190e2c7c144c414e53d855165b4 100644 --- a/arch/powerpc/boot/dts/mpc8379_rdb.dts +++ b/arch/powerpc/boot/dts/mpc8379_rdb.dts @@ -117,7 +117,6 @@ interrupt-parent = <&ipic>; dfsrr; rtc@68 { - device_type = "rtc"; compatible = "dallas,ds1339"; reg = <0x68>; }; @@ -211,6 +210,22 @@ reg = <0x2>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -223,6 +238,7 @@ interrupts = <32 0x8 33 0x8 34 0x8>; phy-connection-type = "mii"; interrupt-parent = <&ipic>; + tbi-handle = <&tbi0>; phy-handle = <&phy2>; }; @@ -237,6 +253,7 @@ phy-connection-type = "mii"; interrupt-parent = <&ipic>; fixed-link = <1 1 1000 0 0>; + tbi-handle = <&tbi1>; }; serial0: serial@4500 { diff --git a/arch/powerpc/boot/dts/mpc8536ds.dts b/arch/powerpc/boot/dts/mpc8536ds.dts index 35db1e5440c7631928562337ac2f043f82e6f55a..3c905df1812ca1d50844e50f857d974505f12618 100644 --- a/arch/powerpc/boot/dts/mpc8536ds.dts +++ b/arch/powerpc/boot/dts/mpc8536ds.dts @@ -155,6 +155,22 @@ reg = <1>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@26520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x26520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; usb@22000 { @@ -186,6 +202,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <29 2 30 2 34 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&phy1>; phy-connection-type = "rgmii-id"; }; @@ -199,6 +216,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <31 2 32 2 33 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&phy0>; phy-connection-type = "rgmii-id"; }; diff --git a/arch/powerpc/boot/dts/mpc8540ads.dts b/arch/powerpc/boot/dts/mpc8540ads.dts index 9568bfaff8f74aab49f18c3526edbfa5655b9a13..79570ffe41b9e46179779044b8df213ed195cc34 100644 --- a/arch/powerpc/boot/dts/mpc8540ads.dts +++ b/arch/powerpc/boot/dts/mpc8540ads.dts @@ -150,6 +150,34 @@ reg = <0x3>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@26520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x26520 0x20>; + + tbi2: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -161,6 +189,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <29 2 30 2 34 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&phy0>; }; @@ -173,6 +202,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 2 36 2 40 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&phy1>; }; @@ -185,6 +215,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <41 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi2>; phy-handle = <&phy3>; }; diff --git a/arch/powerpc/boot/dts/mpc8541cds.dts b/arch/powerpc/boot/dts/mpc8541cds.dts index 6480f4fd96e09f3d7f7a7cab0a5b0daa0c68c6b5..221036a8ce236ca1a808274a0a9c874ba8cfb703 100644 --- a/arch/powerpc/boot/dts/mpc8541cds.dts +++ b/arch/powerpc/boot/dts/mpc8541cds.dts @@ -144,6 +144,22 @@ reg = <0x1>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -155,6 +171,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <29 2 30 2 34 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&phy0>; }; @@ -167,6 +184,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 2 36 2 40 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&phy1>; }; diff --git a/arch/powerpc/boot/dts/mpc8544ds.dts b/arch/powerpc/boot/dts/mpc8544ds.dts index f1fb20737e3ef35db6bfb247e7953cce2dbb6ca2..b9da42105066d37bd7a9432d530127a1d8aa100b 100644 --- a/arch/powerpc/boot/dts/mpc8544ds.dts +++ b/arch/powerpc/boot/dts/mpc8544ds.dts @@ -116,8 +116,26 @@ reg = <0x1>; device_type = "ethernet-phy"; }; + + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; + mdio@26520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x26520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + dma@21300 { #address-cells = <1>; #size-cells = <1>; @@ -169,6 +187,7 @@ interrupts = <29 2 30 2 34 2>; interrupt-parent = <&mpic>; phy-handle = <&phy0>; + tbi-handle = <&tbi0>; phy-connection-type = "rgmii-id"; }; @@ -182,6 +201,7 @@ interrupts = <31 2 32 2 33 2>; interrupt-parent = <&mpic>; phy-handle = <&phy1>; + tbi-handle = <&tbi1>; phy-connection-type = "rgmii-id"; }; diff --git a/arch/powerpc/boot/dts/mpc8548cds.dts b/arch/powerpc/boot/dts/mpc8548cds.dts index 431b496270dc47359e323f79e6e36e1049e9599f..df774a7088ffd409d8f3e3e921bbdab2d8287ee3 100644 --- a/arch/powerpc/boot/dts/mpc8548cds.dts +++ b/arch/powerpc/boot/dts/mpc8548cds.dts @@ -172,6 +172,46 @@ reg = <0x3>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@26520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x26520 0x20>; + + tbi2: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@27520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x27520 0x20>; + + tbi3: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -183,6 +223,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <29 2 30 2 34 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&phy0>; }; @@ -195,6 +236,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 2 36 2 40 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&phy1>; }; @@ -208,6 +250,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <31 2 32 2 33 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi2>; phy-handle = <&phy2>; }; @@ -220,6 +263,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <37 2 38 2 39 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi3>; phy-handle = <&phy3>; }; */ diff --git a/arch/powerpc/boot/dts/mpc8555cds.dts b/arch/powerpc/boot/dts/mpc8555cds.dts index d833a5c4f4766508988d716b6426eff4677c8049..053b01e1c93bf4d5603098a1d61098b1c225322c 100644 --- a/arch/powerpc/boot/dts/mpc8555cds.dts +++ b/arch/powerpc/boot/dts/mpc8555cds.dts @@ -144,6 +144,22 @@ reg = <0x1>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -155,6 +171,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <29 2 30 2 34 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&phy0>; }; @@ -167,6 +184,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 2 36 2 40 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&phy1>; }; diff --git a/arch/powerpc/boot/dts/mpc8560ads.dts b/arch/powerpc/boot/dts/mpc8560ads.dts index 4d1f2f28409439d118a552f97103bb861bc55946..11b1bcbe14cedaf47e297265bde1230fbcb84a1c 100644 --- a/arch/powerpc/boot/dts/mpc8560ads.dts +++ b/arch/powerpc/boot/dts/mpc8560ads.dts @@ -145,6 +145,22 @@ reg = <0x3>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -156,6 +172,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <29 2 30 2 34 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&phy0>; }; @@ -168,6 +185,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 2 36 2 40 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&phy1>; }; diff --git a/arch/powerpc/boot/dts/mpc8568mds.dts b/arch/powerpc/boot/dts/mpc8568mds.dts index c80158f7741db22f93c3f969492c10c706e18bb1..1955bd9e113d9d605d7264f790f669197a715074 100644 --- a/arch/powerpc/boot/dts/mpc8568mds.dts +++ b/arch/powerpc/boot/dts/mpc8568mds.dts @@ -179,6 +179,22 @@ reg = <0x3>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -190,6 +206,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <29 2 30 2 34 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&phy2>; }; @@ -202,6 +219,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 2 36 2 40 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&phy3>; }; diff --git a/arch/powerpc/boot/dts/mpc8572ds.dts b/arch/powerpc/boot/dts/mpc8572ds.dts index 5c69b2fafd32c588e64b0bb1ec1f257010477b18..21459e161d02ee0513a6db3c44e928eb884d401f 100644 --- a/arch/powerpc/boot/dts/mpc8572ds.dts +++ b/arch/powerpc/boot/dts/mpc8572ds.dts @@ -63,6 +63,119 @@ device_type = "memory"; }; + localbus@ffe05000 { + #address-cells = <2>; + #size-cells = <1>; + compatible = "fsl,mpc8572-elbc", "fsl,elbc", "simple-bus"; + reg = <0 0xffe05000 0 0x1000>; + interrupts = <19 2>; + interrupt-parent = <&mpic>; + + ranges = <0x0 0x0 0x0 0xe8000000 0x08000000 + 0x1 0x0 0x0 0xe0000000 0x08000000 + 0x2 0x0 0x0 0xffa00000 0x00040000 + 0x3 0x0 0x0 0xffdf0000 0x00008000 + 0x4 0x0 0x0 0xffa40000 0x00040000 + 0x5 0x0 0x0 0xffa80000 0x00040000 + 0x6 0x0 0x0 0xffac0000 0x00040000>; + + nor@0,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "cfi-flash"; + reg = <0x0 0x0 0x8000000>; + bank-width = <2>; + device-width = <1>; + + ramdisk@0 { + reg = <0x0 0x03000000>; + readl-only; + }; + + diagnostic@3000000 { + reg = <0x03000000 0x00e00000>; + read-only; + }; + + dink@3e00000 { + reg = <0x03e00000 0x00200000>; + read-only; + }; + + kernel@4000000 { + reg = <0x04000000 0x00400000>; + read-only; + }; + + jffs2@4400000 { + reg = <0x04400000 0x03b00000>; + }; + + dtb@7f00000 { + reg = <0x07f00000 0x00080000>; + read-only; + }; + + u-boot@7f80000 { + reg = <0x07f80000 0x00080000>; + read-only; + }; + }; + + nand@2,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,mpc8572-fcm-nand", + "fsl,elbc-fcm-nand"; + reg = <0x2 0x0 0x40000>; + + u-boot@0 { + reg = <0x0 0x02000000>; + read-only; + }; + + jffs2@2000000 { + reg = <0x02000000 0x10000000>; + }; + + ramdisk@12000000 { + reg = <0x12000000 0x08000000>; + read-only; + }; + + kernel@1a000000 { + reg = <0x1a000000 0x04000000>; + }; + + dtb@1e000000 { + reg = <0x1e000000 0x01000000>; + read-only; + }; + + empty@1f000000 { + reg = <0x1f000000 0x21000000>; + }; + }; + + nand@4,0 { + compatible = "fsl,mpc8572-fcm-nand", + "fsl,elbc-fcm-nand"; + reg = <0x4 0x0 0x40000>; + }; + + nand@5,0 { + compatible = "fsl,mpc8572-fcm-nand", + "fsl,elbc-fcm-nand"; + reg = <0x5 0x0 0x40000>; + }; + + nand@6,0 { + compatible = "fsl,mpc8572-fcm-nand", + "fsl,elbc-fcm-nand"; + reg = <0x6 0x0 0x40000>; + }; + }; + soc8572@ffe00000 { #address-cells = <1>; #size-cells = <1>; @@ -225,6 +338,47 @@ interrupts = <10 1>; reg = <0x3>; }; + + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@26520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x26520 0x20>; + + tbi2: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@27520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x27520 0x20>; + + tbi3: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -236,6 +390,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <29 2 30 2 34 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&phy0>; phy-connection-type = "rgmii-id"; }; @@ -249,6 +404,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 2 36 2 40 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&phy1>; phy-connection-type = "rgmii-id"; }; @@ -262,6 +418,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <31 2 32 2 33 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi2>; phy-handle = <&phy2>; phy-connection-type = "rgmii-id"; }; @@ -275,6 +432,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <37 2 38 2 39 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi3>; phy-handle = <&phy3>; phy-connection-type = "rgmii-id"; }; diff --git a/arch/powerpc/boot/dts/mpc8572ds_camp_core0.dts b/arch/powerpc/boot/dts/mpc8572ds_camp_core0.dts new file mode 100644 index 0000000000000000000000000000000000000000..c114c4ee99313755602e53f8dac45799b6974008 --- /dev/null +++ b/arch/powerpc/boot/dts/mpc8572ds_camp_core0.dts @@ -0,0 +1,483 @@ +/* + * MPC8572 DS Core0 Device Tree Source in CAMP mode. + * + * In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache + * can be shared, all the other devices must be assigned to one core only. + * This dts file allows core0 to have memory, l2, i2c, dma1, global-util, eth0, + * eth1, crypto, pci0, pci1. + * + * Copyright 2007, 2008 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +/dts-v1/; +/ { + model = "fsl,MPC8572DS"; + compatible = "fsl,MPC8572DS", "fsl,MPC8572DS-CAMP"; + #address-cells = <1>; + #size-cells = <1>; + + aliases { + ethernet0 = &enet0; + ethernet1 = &enet1; + serial0 = &serial0; + pci0 = &pci0; + pci1 = &pci1; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + PowerPC,8572@0 { + device_type = "cpu"; + reg = <0x0>; + d-cache-line-size = <32>; // 32 bytes + i-cache-line-size = <32>; // 32 bytes + d-cache-size = <0x8000>; // L1, 32K + i-cache-size = <0x8000>; // L1, 32K + timebase-frequency = <0>; + bus-frequency = <0>; + clock-frequency = <0>; + next-level-cache = <&L2>; + }; + + }; + + memory { + device_type = "memory"; + reg = <0x0 0x0>; // Filled by U-Boot + }; + + soc8572@ffe00000 { + #address-cells = <1>; + #size-cells = <1>; + device_type = "soc"; + compatible = "simple-bus"; + ranges = <0x0 0xffe00000 0x100000>; + reg = <0xffe00000 0x1000>; // CCSRBAR & soc regs, remove once parse code for immrbase fixed + bus-frequency = <0>; // Filled out by uboot. + + memory-controller@2000 { + compatible = "fsl,mpc8572-memory-controller"; + reg = <0x2000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <18 2>; + }; + + memory-controller@6000 { + compatible = "fsl,mpc8572-memory-controller"; + reg = <0x6000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <18 2>; + }; + + L2: l2-cache-controller@20000 { + compatible = "fsl,mpc8572-l2-cache-controller"; + reg = <0x20000 0x1000>; + cache-line-size = <32>; // 32 bytes + cache-size = <0x80000>; // L2, 512K + interrupt-parent = <&mpic>; + interrupts = <16 2>; + }; + + i2c@3000 { + #address-cells = <1>; + #size-cells = <0>; + cell-index = <0>; + compatible = "fsl-i2c"; + reg = <0x3000 0x100>; + interrupts = <43 2>; + interrupt-parent = <&mpic>; + dfsrr; + }; + + i2c@3100 { + #address-cells = <1>; + #size-cells = <0>; + cell-index = <1>; + compatible = "fsl-i2c"; + reg = <0x3100 0x100>; + interrupts = <43 2>; + interrupt-parent = <&mpic>; + dfsrr; + }; + + dma@21300 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,mpc8572-dma", "fsl,eloplus-dma"; + reg = <0x21300 0x4>; + ranges = <0x0 0x21100 0x200>; + cell-index = <0>; + dma-channel@0 { + compatible = "fsl,mpc8572-dma-channel", + "fsl,eloplus-dma-channel"; + reg = <0x0 0x80>; + cell-index = <0>; + interrupt-parent = <&mpic>; + interrupts = <20 2>; + }; + dma-channel@80 { + compatible = "fsl,mpc8572-dma-channel", + "fsl,eloplus-dma-channel"; + reg = <0x80 0x80>; + cell-index = <1>; + interrupt-parent = <&mpic>; + interrupts = <21 2>; + }; + dma-channel@100 { + compatible = "fsl,mpc8572-dma-channel", + "fsl,eloplus-dma-channel"; + reg = <0x100 0x80>; + cell-index = <2>; + interrupt-parent = <&mpic>; + interrupts = <22 2>; + }; + dma-channel@180 { + compatible = "fsl,mpc8572-dma-channel", + "fsl,eloplus-dma-channel"; + reg = <0x180 0x80>; + cell-index = <3>; + interrupt-parent = <&mpic>; + interrupts = <23 2>; + }; + }; + + mdio@24520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-mdio"; + reg = <0x24520 0x20>; + + phy0: ethernet-phy@0 { + interrupt-parent = <&mpic>; + interrupts = <10 1>; + reg = <0x0>; + }; + phy1: ethernet-phy@1 { + interrupt-parent = <&mpic>; + interrupts = <10 1>; + reg = <0x1>; + }; + }; + + enet0: ethernet@24000 { + cell-index = <0>; + device_type = "network"; + model = "eTSEC"; + compatible = "gianfar"; + reg = <0x24000 0x1000>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupts = <29 2 30 2 34 2>; + interrupt-parent = <&mpic>; + phy-handle = <&phy0>; + phy-connection-type = "rgmii-id"; + }; + + enet1: ethernet@25000 { + cell-index = <1>; + device_type = "network"; + model = "eTSEC"; + compatible = "gianfar"; + reg = <0x25000 0x1000>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupts = <35 2 36 2 40 2>; + interrupt-parent = <&mpic>; + phy-handle = <&phy1>; + phy-connection-type = "rgmii-id"; + }; + + serial0: serial@4500 { + cell-index = <0>; + device_type = "serial"; + compatible = "ns16550"; + reg = <0x4500 0x100>; + clock-frequency = <0>; + }; + + global-utilities@e0000 { //global utilities block + compatible = "fsl,mpc8572-guts"; + reg = <0xe0000 0x1000>; + fsl,has-rstcr; + }; + + crypto@30000 { + compatible = "fsl,sec3.0", "fsl,sec2.4", "fsl,sec2.2", + "fsl,sec2.1", "fsl,sec2.0"; + reg = <0x30000 0x10000>; + interrupts = <45 2 58 2>; + interrupt-parent = <&mpic>; + fsl,num-channels = <4>; + fsl,channel-fifo-len = <24>; + fsl,exec-units-mask = <0x9fe>; + fsl,descriptor-types-mask = <0x3ab0ebf>; + }; + + mpic: pic@40000 { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <2>; + reg = <0x40000 0x40000>; + compatible = "chrp,open-pic"; + device_type = "open-pic"; + protected-sources = < + 31 32 33 37 38 39 /* enet2 enet3 */ + 76 77 78 79 27 42 /* dma2 pci2 serial*/ + 0xe0 0xe1 0xe2 0xe3 /* msi */ + 0xe4 0xe5 0xe6 0xe7 + >; + }; + }; + + pci0: pcie@ffe08000 { + cell-index = <0>; + compatible = "fsl,mpc8548-pcie"; + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = <0xffe08000 0x1000>; + bus-range = <0 255>; + ranges = <0x2000000 0x0 0x80000000 0x80000000 0x0 0x20000000 + 0x1000000 0x0 0x0 0xffc00000 0x0 0x10000>; + clock-frequency = <33333333>; + interrupt-parent = <&mpic>; + interrupts = <24 2>; + interrupt-map-mask = <0xff00 0x0 0x0 0x7>; + interrupt-map = < + /* IDSEL 0x11 func 0 - PCI slot 1 */ + 0x8800 0x0 0x0 0x1 &mpic 0x2 0x1 + 0x8800 0x0 0x0 0x2 &mpic 0x3 0x1 + 0x8800 0x0 0x0 0x3 &mpic 0x4 0x1 + 0x8800 0x0 0x0 0x4 &mpic 0x1 0x1 + + /* IDSEL 0x11 func 1 - PCI slot 1 */ + 0x8900 0x0 0x0 0x1 &mpic 0x2 0x1 + 0x8900 0x0 0x0 0x2 &mpic 0x3 0x1 + 0x8900 0x0 0x0 0x3 &mpic 0x4 0x1 + 0x8900 0x0 0x0 0x4 &mpic 0x1 0x1 + + /* IDSEL 0x11 func 2 - PCI slot 1 */ + 0x8a00 0x0 0x0 0x1 &mpic 0x2 0x1 + 0x8a00 0x0 0x0 0x2 &mpic 0x3 0x1 + 0x8a00 0x0 0x0 0x3 &mpic 0x4 0x1 + 0x8a00 0x0 0x0 0x4 &mpic 0x1 0x1 + + /* IDSEL 0x11 func 3 - PCI slot 1 */ + 0x8b00 0x0 0x0 0x1 &mpic 0x2 0x1 + 0x8b00 0x0 0x0 0x2 &mpic 0x3 0x1 + 0x8b00 0x0 0x0 0x3 &mpic 0x4 0x1 + 0x8b00 0x0 0x0 0x4 &mpic 0x1 0x1 + + /* IDSEL 0x11 func 4 - PCI slot 1 */ + 0x8c00 0x0 0x0 0x1 &mpic 0x2 0x1 + 0x8c00 0x0 0x0 0x2 &mpic 0x3 0x1 + 0x8c00 0x0 0x0 0x3 &mpic 0x4 0x1 + 0x8c00 0x0 0x0 0x4 &mpic 0x1 0x1 + + /* IDSEL 0x11 func 5 - PCI slot 1 */ + 0x8d00 0x0 0x0 0x1 &mpic 0x2 0x1 + 0x8d00 0x0 0x0 0x2 &mpic 0x3 0x1 + 0x8d00 0x0 0x0 0x3 &mpic 0x4 0x1 + 0x8d00 0x0 0x0 0x4 &mpic 0x1 0x1 + + /* IDSEL 0x11 func 6 - PCI slot 1 */ + 0x8e00 0x0 0x0 0x1 &mpic 0x2 0x1 + 0x8e00 0x0 0x0 0x2 &mpic 0x3 0x1 + 0x8e00 0x0 0x0 0x3 &mpic 0x4 0x1 + 0x8e00 0x0 0x0 0x4 &mpic 0x1 0x1 + + /* IDSEL 0x11 func 7 - PCI slot 1 */ + 0x8f00 0x0 0x0 0x1 &mpic 0x2 0x1 + 0x8f00 0x0 0x0 0x2 &mpic 0x3 0x1 + 0x8f00 0x0 0x0 0x3 &mpic 0x4 0x1 + 0x8f00 0x0 0x0 0x4 &mpic 0x1 0x1 + + /* IDSEL 0x12 func 0 - PCI slot 2 */ + 0x9000 0x0 0x0 0x1 &mpic 0x3 0x1 + 0x9000 0x0 0x0 0x2 &mpic 0x4 0x1 + 0x9000 0x0 0x0 0x3 &mpic 0x1 0x1 + 0x9000 0x0 0x0 0x4 &mpic 0x2 0x1 + + /* IDSEL 0x12 func 1 - PCI slot 2 */ + 0x9100 0x0 0x0 0x1 &mpic 0x3 0x1 + 0x9100 0x0 0x0 0x2 &mpic 0x4 0x1 + 0x9100 0x0 0x0 0x3 &mpic 0x1 0x1 + 0x9100 0x0 0x0 0x4 &mpic 0x2 0x1 + + /* IDSEL 0x12 func 2 - PCI slot 2 */ + 0x9200 0x0 0x0 0x1 &mpic 0x3 0x1 + 0x9200 0x0 0x0 0x2 &mpic 0x4 0x1 + 0x9200 0x0 0x0 0x3 &mpic 0x1 0x1 + 0x9200 0x0 0x0 0x4 &mpic 0x2 0x1 + + /* IDSEL 0x12 func 3 - PCI slot 2 */ + 0x9300 0x0 0x0 0x1 &mpic 0x3 0x1 + 0x9300 0x0 0x0 0x2 &mpic 0x4 0x1 + 0x9300 0x0 0x0 0x3 &mpic 0x1 0x1 + 0x9300 0x0 0x0 0x4 &mpic 0x2 0x1 + + /* IDSEL 0x12 func 4 - PCI slot 2 */ + 0x9400 0x0 0x0 0x1 &mpic 0x3 0x1 + 0x9400 0x0 0x0 0x2 &mpic 0x4 0x1 + 0x9400 0x0 0x0 0x3 &mpic 0x1 0x1 + 0x9400 0x0 0x0 0x4 &mpic 0x2 0x1 + + /* IDSEL 0x12 func 5 - PCI slot 2 */ + 0x9500 0x0 0x0 0x1 &mpic 0x3 0x1 + 0x9500 0x0 0x0 0x2 &mpic 0x4 0x1 + 0x9500 0x0 0x0 0x3 &mpic 0x1 0x1 + 0x9500 0x0 0x0 0x4 &mpic 0x2 0x1 + + /* IDSEL 0x12 func 6 - PCI slot 2 */ + 0x9600 0x0 0x0 0x1 &mpic 0x3 0x1 + 0x9600 0x0 0x0 0x2 &mpic 0x4 0x1 + 0x9600 0x0 0x0 0x3 &mpic 0x1 0x1 + 0x9600 0x0 0x0 0x4 &mpic 0x2 0x1 + + /* IDSEL 0x12 func 7 - PCI slot 2 */ + 0x9700 0x0 0x0 0x1 &mpic 0x3 0x1 + 0x9700 0x0 0x0 0x2 &mpic 0x4 0x1 + 0x9700 0x0 0x0 0x3 &mpic 0x1 0x1 + 0x9700 0x0 0x0 0x4 &mpic 0x2 0x1 + + // IDSEL 0x1c USB + 0xe000 0x0 0x0 0x1 &i8259 0xc 0x2 + 0xe100 0x0 0x0 0x2 &i8259 0x9 0x2 + 0xe200 0x0 0x0 0x3 &i8259 0xa 0x2 + 0xe300 0x0 0x0 0x4 &i8259 0xb 0x2 + + // IDSEL 0x1d Audio + 0xe800 0x0 0x0 0x1 &i8259 0x6 0x2 + + // IDSEL 0x1e Legacy + 0xf000 0x0 0x0 0x1 &i8259 0x7 0x2 + 0xf100 0x0 0x0 0x1 &i8259 0x7 0x2 + + // IDSEL 0x1f IDE/SATA + 0xf800 0x0 0x0 0x1 &i8259 0xe 0x2 + 0xf900 0x0 0x0 0x1 &i8259 0x5 0x2 + + >; + + pcie@0 { + reg = <0x0 0x0 0x0 0x0 0x0>; + #size-cells = <2>; + #address-cells = <3>; + device_type = "pci"; + ranges = <0x2000000 0x0 0x80000000 + 0x2000000 0x0 0x80000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + uli1575@0 { + reg = <0x0 0x0 0x0 0x0 0x0>; + #size-cells = <2>; + #address-cells = <3>; + ranges = <0x2000000 0x0 0x80000000 + 0x2000000 0x0 0x80000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + isa@1e { + device_type = "isa"; + #interrupt-cells = <2>; + #size-cells = <1>; + #address-cells = <2>; + reg = <0xf000 0x0 0x0 0x0 0x0>; + ranges = <0x1 0x0 0x1000000 0x0 0x0 + 0x1000>; + interrupt-parent = <&i8259>; + + i8259: interrupt-controller@20 { + reg = <0x1 0x20 0x2 + 0x1 0xa0 0x2 + 0x1 0x4d0 0x2>; + interrupt-controller; + device_type = "interrupt-controller"; + #address-cells = <0>; + #interrupt-cells = <2>; + compatible = "chrp,iic"; + interrupts = <9 2>; + interrupt-parent = <&mpic>; + }; + + i8042@60 { + #size-cells = <0>; + #address-cells = <1>; + reg = <0x1 0x60 0x1 0x1 0x64 0x1>; + interrupts = <1 3 12 3>; + interrupt-parent = + <&i8259>; + + keyboard@0 { + reg = <0x0>; + compatible = "pnpPNP,303"; + }; + + mouse@1 { + reg = <0x1>; + compatible = "pnpPNP,f03"; + }; + }; + + rtc@70 { + compatible = "pnpPNP,b00"; + reg = <0x1 0x70 0x2>; + }; + + gpio@400 { + reg = <0x1 0x400 0x80>; + }; + }; + }; + }; + + }; + + pci1: pcie@ffe09000 { + cell-index = <1>; + compatible = "fsl,mpc8548-pcie"; + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = <0xffe09000 0x1000>; + bus-range = <0 255>; + ranges = <0x2000000 0x0 0xa0000000 0xa0000000 0x0 0x20000000 + 0x1000000 0x0 0x0 0xffc10000 0x0 0x10000>; + clock-frequency = <33333333>; + interrupt-parent = <&mpic>; + interrupts = <26 2>; + interrupt-map-mask = <0xf800 0x0 0x0 0x7>; + interrupt-map = < + /* IDSEL 0x0 */ + 0000 0x0 0x0 0x1 &mpic 0x4 0x1 + 0000 0x0 0x0 0x2 &mpic 0x5 0x1 + 0000 0x0 0x0 0x3 &mpic 0x6 0x1 + 0000 0x0 0x0 0x4 &mpic 0x7 0x1 + >; + pcie@0 { + reg = <0x0 0x0 0x0 0x0 0x0>; + #size-cells = <2>; + #address-cells = <3>; + device_type = "pci"; + ranges = <0x2000000 0x0 0xa0000000 + 0x2000000 0x0 0xa0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; +}; diff --git a/arch/powerpc/boot/dts/mpc8572ds_camp_core1.dts b/arch/powerpc/boot/dts/mpc8572ds_camp_core1.dts new file mode 100644 index 0000000000000000000000000000000000000000..04ecda18d2066cd18861fafd099c980ad17bd15b --- /dev/null +++ b/arch/powerpc/boot/dts/mpc8572ds_camp_core1.dts @@ -0,0 +1,234 @@ +/* + * MPC8572 DS Core1 Device Tree Source in CAMP mode. + * + * In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache + * can be shared, all the other devices must be assigned to one core only. + * This dts allows core1 to have l2, dma2, eth2, eth3, pci2, msi. + * + * Please note to add "-b 1" for core1's dts compiling. + * + * Copyright 2007, 2008 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +/dts-v1/; +/ { + model = "fsl,MPC8572DS"; + compatible = "fsl,MPC8572DS", "fsl,MPC8572DS-CAMP"; + #address-cells = <1>; + #size-cells = <1>; + + aliases { + ethernet2 = &enet2; + ethernet3 = &enet3; + serial0 = &serial0; + pci2 = &pci2; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + PowerPC,8572@1 { + device_type = "cpu"; + reg = <0x1>; + d-cache-line-size = <32>; // 32 bytes + i-cache-line-size = <32>; // 32 bytes + d-cache-size = <0x8000>; // L1, 32K + i-cache-size = <0x8000>; // L1, 32K + timebase-frequency = <0>; + bus-frequency = <0>; + clock-frequency = <0>; + next-level-cache = <&L2>; + }; + }; + + memory { + device_type = "memory"; + reg = <0x0 0x0>; // Filled by U-Boot + }; + + soc8572@ffe00000 { + #address-cells = <1>; + #size-cells = <1>; + device_type = "soc"; + compatible = "simple-bus"; + ranges = <0x0 0xffe00000 0x100000>; + reg = <0xffe00000 0x1000>; // CCSRBAR & soc regs, remove once parse code for immrbase fixed + bus-frequency = <0>; // Filled out by uboot. + + L2: l2-cache-controller@20000 { + compatible = "fsl,mpc8572-l2-cache-controller"; + reg = <0x20000 0x1000>; + cache-line-size = <32>; // 32 bytes + cache-size = <0x80000>; // L2, 512K + interrupt-parent = <&mpic>; + }; + + dma@c300 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,mpc8572-dma", "fsl,eloplus-dma"; + reg = <0xc300 0x4>; + ranges = <0x0 0xc100 0x200>; + cell-index = <0>; + dma-channel@0 { + compatible = "fsl,mpc8572-dma-channel", + "fsl,eloplus-dma-channel"; + reg = <0x0 0x80>; + cell-index = <0>; + interrupt-parent = <&mpic>; + interrupts = <76 2>; + }; + dma-channel@80 { + compatible = "fsl,mpc8572-dma-channel", + "fsl,eloplus-dma-channel"; + reg = <0x80 0x80>; + cell-index = <1>; + interrupt-parent = <&mpic>; + interrupts = <77 2>; + }; + dma-channel@100 { + compatible = "fsl,mpc8572-dma-channel", + "fsl,eloplus-dma-channel"; + reg = <0x100 0x80>; + cell-index = <2>; + interrupt-parent = <&mpic>; + interrupts = <78 2>; + }; + dma-channel@180 { + compatible = "fsl,mpc8572-dma-channel", + "fsl,eloplus-dma-channel"; + reg = <0x180 0x80>; + cell-index = <3>; + interrupt-parent = <&mpic>; + interrupts = <79 2>; + }; + }; + + mdio@24520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-mdio"; + reg = <0x24520 0x20>; + + phy2: ethernet-phy@2 { + interrupt-parent = <&mpic>; + reg = <0x2>; + }; + phy3: ethernet-phy@3 { + interrupt-parent = <&mpic>; + reg = <0x3>; + }; + }; + + enet2: ethernet@26000 { + cell-index = <2>; + device_type = "network"; + model = "eTSEC"; + compatible = "gianfar"; + reg = <0x26000 0x1000>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupts = <31 2 32 2 33 2>; + interrupt-parent = <&mpic>; + phy-handle = <&phy2>; + phy-connection-type = "rgmii-id"; + }; + + enet3: ethernet@27000 { + cell-index = <3>; + device_type = "network"; + model = "eTSEC"; + compatible = "gianfar"; + reg = <0x27000 0x1000>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupts = <37 2 38 2 39 2>; + interrupt-parent = <&mpic>; + phy-handle = <&phy3>; + phy-connection-type = "rgmii-id"; + }; + + msi@41600 { + compatible = "fsl,mpc8572-msi", "fsl,mpic-msi"; + reg = <0x41600 0x80>; + msi-available-ranges = <0 0x100>; + interrupts = < + 0xe0 0 + 0xe1 0 + 0xe2 0 + 0xe3 0 + 0xe4 0 + 0xe5 0 + 0xe6 0 + 0xe7 0>; + interrupt-parent = <&mpic>; + }; + + serial0: serial@4600 { + cell-index = <1>; + device_type = "serial"; + compatible = "ns16550"; + reg = <0x4600 0x100>; + clock-frequency = <0>; + }; + + mpic: pic@40000 { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <2>; + reg = <0x40000 0x40000>; + compatible = "chrp,open-pic"; + device_type = "open-pic"; + protected-sources = < + 18 16 10 42 45 58 /* MEM L2 mdio serial crypto */ + 29 30 34 35 36 40 /* enet0 enet1 */ + 24 26 20 21 22 23 /* pcie0 pcie1 dma1 */ + 43 /* i2c */ + 0x1 0x2 0x3 0x4 /* pci slot */ + 0x9 0xa 0xb 0xc /* usb */ + 0x6 0x7 0xe 0x5 /* Audio elgacy SATA */ + >; + }; + }; + + pci2: pcie@ffe0a000 { + cell-index = <2>; + compatible = "fsl,mpc8548-pcie"; + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = <0xffe0a000 0x1000>; + bus-range = <0 255>; + ranges = <0x2000000 0x0 0xc0000000 0xc0000000 0x0 0x20000000 + 0x1000000 0x0 0x0 0xffc20000 0x0 0x10000>; + clock-frequency = <33333333>; + interrupt-parent = <&mpic>; + interrupts = <27 2>; + interrupt-map-mask = <0xf800 0x0 0x0 0x7>; + interrupt-map = < + /* IDSEL 0x0 */ + 0000 0x0 0x0 0x1 &mpic 0x0 0x1 + 0000 0x0 0x0 0x2 &mpic 0x1 0x1 + 0000 0x0 0x0 0x3 &mpic 0x2 0x1 + 0000 0x0 0x0 0x4 &mpic 0x3 0x1 + >; + pcie@0 { + reg = <0x0 0x0 0x0 0x0 0x0>; + #size-cells = <2>; + #address-cells = <3>; + device_type = "pci"; + ranges = <0x2000000 0x0 0xc0000000 + 0x2000000 0x0 0xc0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; +}; diff --git a/arch/powerpc/boot/dts/mpc8641_hpcn.dts b/arch/powerpc/boot/dts/mpc8641_hpcn.dts index d665e767822a8cfcd2d8371721f5c320c6325034..35d5e248ccd7939768ce2bd14e8a54cc5101353f 100644 --- a/arch/powerpc/boot/dts/mpc8641_hpcn.dts +++ b/arch/powerpc/boot/dts/mpc8641_hpcn.dts @@ -205,8 +205,49 @@ reg = <3>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@26520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x26520 0x20>; + + tbi2: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@27520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x27520 0x20>; + + tbi3: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; + enet0: ethernet@24000 { cell-index = <0>; device_type = "network"; @@ -216,6 +257,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <29 2 30 2 34 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&phy0>; phy-connection-type = "rgmii-id"; }; @@ -229,6 +271,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 2 36 2 40 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&phy1>; phy-connection-type = "rgmii-id"; }; @@ -242,6 +285,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <31 2 32 2 33 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi2>; phy-handle = <&phy2>; phy-connection-type = "rgmii-id"; }; @@ -255,6 +299,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <37 2 38 2 39 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi3>; phy-handle = <&phy3>; phy-connection-type = "rgmii-id"; }; diff --git a/arch/powerpc/boot/dts/pcm030.dts b/arch/powerpc/boot/dts/pcm030.dts index 7c1bb952360cf8af82c6593c8b0cbf7bcd6694f0..be2c11ca05944de59a21a936ee4d08f8439a771b 100644 --- a/arch/powerpc/boot/dts/pcm030.dts +++ b/arch/powerpc/boot/dts/pcm030.dts @@ -143,7 +143,6 @@ rtc@800 { // Real time clock compatible = "fsl,mpc5200b-rtc","fsl,mpc5200-rtc"; - device_type = "rtc"; reg = <0x800 0x100>; interrupts = <0x1 0x5 0x0 0x1 0x6 0x0>; interrupt-parent = <&mpc5200_pic>; @@ -301,7 +300,6 @@ interrupt-parent = <&mpc5200_pic>; fsl5200-clocking; rtc@51 { - device_type = "rtc"; compatible = "nxp,pcf8563"; reg = <0x51>; }; diff --git a/arch/powerpc/boot/dts/sbc8349.dts b/arch/powerpc/boot/dts/sbc8349.dts index 0f941f310e444ae2d209f8195b7f71525cb07ad4..8d365a57ebc122bbc4aefce181a30c1ae638daa7 100644 --- a/arch/powerpc/boot/dts/sbc8349.dts +++ b/arch/powerpc/boot/dts/sbc8349.dts @@ -177,6 +177,22 @@ reg = <0x1a>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -188,6 +204,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <32 0x8 33 0x8 34 0x8>; interrupt-parent = <&ipic>; + tbi-handle = <&tbi0>; phy-handle = <&phy0>; linux,network-index = <0>; }; @@ -201,6 +218,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 0x8 36 0x8 37 0x8>; interrupt-parent = <&ipic>; + tbi-handle = <&tbi1>; phy-handle = <&phy1>; linux,network-index = <1>; }; diff --git a/arch/powerpc/boot/dts/sbc8548.dts b/arch/powerpc/boot/dts/sbc8548.dts index 333552b4e90dd1d417ebe31cbf3c5ef0d248aab2..2baf4a51f224a9c7a63792182a0d837d6fad4624 100644 --- a/arch/powerpc/boot/dts/sbc8548.dts +++ b/arch/powerpc/boot/dts/sbc8548.dts @@ -252,6 +252,22 @@ reg = <0x1a>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -263,6 +279,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <0x1d 0x2 0x1e 0x2 0x22 0x2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&phy0>; }; @@ -275,6 +292,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <0x23 0x2 0x24 0x2 0x28 0x2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&phy1>; }; diff --git a/arch/powerpc/boot/dts/sbc8560.dts b/arch/powerpc/boot/dts/sbc8560.dts index db3632ef9888f3270a4885ba647f88bceb9c8ac8..01542f7062abf7d6cb428ac9eadefbd8e117adab 100644 --- a/arch/powerpc/boot/dts/sbc8560.dts +++ b/arch/powerpc/boot/dts/sbc8560.dts @@ -168,6 +168,22 @@ reg = <0x1c>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -179,6 +195,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <0x1d 0x2 0x1e 0x2 0x22 0x2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&phy0>; }; @@ -191,6 +208,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <0x23 0x2 0x24 0x2 0x28 0x2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&phy1>; }; diff --git a/arch/powerpc/boot/dts/sbc8641d.dts b/arch/powerpc/boot/dts/sbc8641d.dts index 9652456158fbac84db0da31f7e7825e61bcabd9f..36db981548e4754768ecbc4c69f780d4a7b46381 100644 --- a/arch/powerpc/boot/dts/sbc8641d.dts +++ b/arch/powerpc/boot/dts/sbc8641d.dts @@ -222,6 +222,46 @@ reg = <2>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@26520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x26520 0x20>; + + tbi2: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@27520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x27520 0x20>; + + tbi3: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -233,6 +273,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <29 2 30 2 34 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&phy0>; phy-connection-type = "rgmii-id"; }; @@ -246,6 +287,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 2 36 2 40 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&phy1>; phy-connection-type = "rgmii-id"; }; @@ -259,6 +301,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <31 2 32 2 33 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi2>; phy-handle = <&phy2>; phy-connection-type = "rgmii-id"; }; @@ -272,6 +315,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <37 2 38 2 39 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi3>; phy-handle = <&phy3>; phy-connection-type = "rgmii-id"; }; diff --git a/arch/powerpc/boot/dts/stx_gp3_8560.dts b/arch/powerpc/boot/dts/stx_gp3_8560.dts index fcd1db6ca0a8e10ea0860c349e75882ac9c473fb..fff33fe6efc61211449673e24f9fc85f4a21d7b8 100644 --- a/arch/powerpc/boot/dts/stx_gp3_8560.dts +++ b/arch/powerpc/boot/dts/stx_gp3_8560.dts @@ -142,6 +142,22 @@ reg = <4>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -153,6 +169,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <29 2 30 2 34 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&phy2>; }; @@ -165,6 +182,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 2 36 2 40 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&phy4>; }; diff --git a/arch/powerpc/boot/dts/tqm5200.dts b/arch/powerpc/boot/dts/tqm5200.dts index 3008bf8830c1a1579115d8d4d362c4d7c7a2ff3a..906302e26a6225f5f0ff1ca5b731adf68368f8e0 100644 --- a/arch/powerpc/boot/dts/tqm5200.dts +++ b/arch/powerpc/boot/dts/tqm5200.dts @@ -181,7 +181,6 @@ fsl5200-clocking; rtc@68 { - device_type = "rtc"; compatible = "dallas,ds1307"; reg = <0x68>; }; diff --git a/arch/powerpc/boot/dts/tqm8540.dts b/arch/powerpc/boot/dts/tqm8540.dts index e1d260b9085eeaaf8a3b3e0620a2a6408d5a145f..a693f01c21aa6874f0688437425da6622094522b 100644 --- a/arch/powerpc/boot/dts/tqm8540.dts +++ b/arch/powerpc/boot/dts/tqm8540.dts @@ -155,6 +155,34 @@ reg = <3>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@26520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x26520 0x20>; + + tbi2: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { diff --git a/arch/powerpc/boot/dts/tqm8541.dts b/arch/powerpc/boot/dts/tqm8541.dts index d76441ec5dc72f1599ced341d2356062538da9b5..9e3f5f0dde2002049b531600c52a48f61a53f4a9 100644 --- a/arch/powerpc/boot/dts/tqm8541.dts +++ b/arch/powerpc/boot/dts/tqm8541.dts @@ -154,6 +154,22 @@ reg = <3>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -165,6 +181,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <29 2 30 2 34 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&phy2>; }; @@ -177,6 +194,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 2 36 2 40 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&phy1>; }; diff --git a/arch/powerpc/boot/dts/tqm8548-bigflash.dts b/arch/powerpc/boot/dts/tqm8548-bigflash.dts index 4199e89b4e50cdf871ca2ff51f74f3e7be7ba541..15086eb65c507cf039c920ee91d84117b189bb75 100644 --- a/arch/powerpc/boot/dts/tqm8548-bigflash.dts +++ b/arch/powerpc/boot/dts/tqm8548-bigflash.dts @@ -179,6 +179,46 @@ reg = <5>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@26520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x26520 0x20>; + + tbi2: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@27520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x27520 0x20>; + + tbi3: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -190,6 +230,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <29 2 30 2 34 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&phy2>; }; @@ -202,6 +243,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 2 36 2 40 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&phy1>; }; @@ -214,6 +256,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <31 2 32 2 33 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi2>; phy-handle = <&phy3>; }; @@ -226,6 +269,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <37 2 38 2 39 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi3>; phy-handle = <&phy4>; }; diff --git a/arch/powerpc/boot/dts/tqm8548.dts b/arch/powerpc/boot/dts/tqm8548.dts index 58ee4185454b233f32f3bca4195303d7ddd5e20f..b7b65f5e79b654a024c1b1cff191b28d01c65bfb 100644 --- a/arch/powerpc/boot/dts/tqm8548.dts +++ b/arch/powerpc/boot/dts/tqm8548.dts @@ -179,6 +179,46 @@ reg = <5>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@26520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x26520 0x20>; + + tbi2: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@27520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x27520 0x20>; + + tbi3: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -190,6 +230,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <29 2 30 2 34 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&phy2>; }; @@ -202,6 +243,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 2 36 2 40 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&phy1>; }; @@ -214,6 +256,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <31 2 32 2 33 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi2>; phy-handle = <&phy3>; }; @@ -226,6 +269,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <37 2 38 2 39 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi3>; phy-handle = <&phy4>; }; diff --git a/arch/powerpc/boot/dts/tqm8555.dts b/arch/powerpc/boot/dts/tqm8555.dts index 6f7ea59c4846e05c783b4076349cc29cb6c09185..cf92b4e7945e3d6fa61b57907929692ac48b29d0 100644 --- a/arch/powerpc/boot/dts/tqm8555.dts +++ b/arch/powerpc/boot/dts/tqm8555.dts @@ -154,6 +154,22 @@ reg = <3>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -165,6 +181,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <29 2 30 2 34 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&phy2>; }; @@ -177,6 +194,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 2 36 2 40 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&phy1>; }; diff --git a/arch/powerpc/boot/dts/tqm8560.dts b/arch/powerpc/boot/dts/tqm8560.dts index 3fe35208907b9cfe317d64642223fba9ed8467b5..9e1ab2d2f669b003d7b676a312aac96a0b8bfbe3 100644 --- a/arch/powerpc/boot/dts/tqm8560.dts +++ b/arch/powerpc/boot/dts/tqm8560.dts @@ -156,6 +156,22 @@ reg = <3>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -167,6 +183,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <29 2 30 2 34 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&phy2>; }; @@ -179,6 +196,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 2 36 2 40 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&phy1>; }; diff --git a/arch/powerpc/boot/libfdt-wrapper.c b/arch/powerpc/boot/libfdt-wrapper.c index 9276327bc2bb1995343dabf417f2c3927386cd95..bb8b9b3505eecd5ce694371f0ababf41f4cf65b1 100644 --- a/arch/powerpc/boot/libfdt-wrapper.c +++ b/arch/powerpc/boot/libfdt-wrapper.c @@ -185,7 +185,7 @@ void fdt_init(void *blob) /* Make sure the dt blob is the right version and so forth */ fdt = blob; - bufsize = fdt_totalsize(fdt) + 4; + bufsize = fdt_totalsize(fdt) + EXPAND_GRANULARITY; buf = malloc(bufsize); if(!buf) fatal("malloc failed. can't relocate the device tree\n\r"); diff --git a/arch/powerpc/configs/86xx/gef_sbc610_defconfig b/arch/powerpc/configs/86xx/gef_sbc610_defconfig index 07ccaf89f3793bf53006c0f8e2a011671e47766f..cd1ffa44932779daa077f8cd229243f3ad8e2a3d 100644 --- a/arch/powerpc/configs/86xx/gef_sbc610_defconfig +++ b/arch/powerpc/configs/86xx/gef_sbc610_defconfig @@ -1397,8 +1397,11 @@ CONFIG_USB_STORAGE=y # CONFIG_ACCESSIBILITY is not set # CONFIG_INFINIBAND is not set # CONFIG_EDAC is not set -CONFIG_RTC_LIB=m -CONFIG_RTC_CLASS=m +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set # # RTC interfaces @@ -1424,6 +1427,7 @@ CONFIG_RTC_INTF_DEV=y # CONFIG_RTC_DRV_M41T80 is not set # CONFIG_RTC_DRV_S35390A is not set # CONFIG_RTC_DRV_FM3130 is not set +CONFIG_RTC_DRV_RX8581=y # # SPI RTC drivers diff --git a/arch/powerpc/configs/ppc44x_defconfig b/arch/powerpc/configs/ppc44x_defconfig index cfc94cfcf4cb3ec27803eac80aa669fddc686064..034a1fbdc8878c22892a9d62c47b845a50ea74be 100644 --- a/arch/powerpc/configs/ppc44x_defconfig +++ b/arch/powerpc/configs/ppc44x_defconfig @@ -267,7 +267,7 @@ CONFIG_PCI_SYSCALL=y # CONFIG_PCIEPORTBUS is not set CONFIG_ARCH_SUPPORTS_MSI=y # CONFIG_PCI_MSI is not set -CONFIG_PCI_LEGACY=y +# CONFIG_PCI_LEGACY is not set # CONFIG_PCI_DEBUG is not set # CONFIG_PCCARD is not set # CONFIG_HOTPLUG_PCI is not set @@ -354,7 +354,7 @@ CONFIG_IPV6_NDISC_NODETYPE=y # CONFIG_IP_SCTP is not set # CONFIG_TIPC is not set # CONFIG_ATM is not set -# CONFIG_BRIDGE is not set +CONFIG_BRIDGE=m # CONFIG_NET_DSA is not set # CONFIG_VLAN_8021Q is not set # CONFIG_DECNET is not set @@ -579,7 +579,7 @@ CONFIG_NETDEVICES=y # CONFIG_BONDING is not set # CONFIG_MACVLAN is not set # CONFIG_EQUALIZER is not set -# CONFIG_TUN is not set +CONFIG_TUN=m # CONFIG_VETH is not set # CONFIG_ARCNET is not set # CONFIG_PHYLIB is not set @@ -1001,11 +1001,11 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y # CONFIG_USB_TMC is not set # -# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed; # # -# may also be needed; see USB_STORAGE Help for more information +# see USB_STORAGE Help for more information # CONFIG_USB_STORAGE=m # CONFIG_USB_STORAGE_DEBUG is not set @@ -1418,6 +1418,6 @@ CONFIG_CRYPTO_LZO=m # CONFIG_PPC_CLOCK is not set CONFIG_VIRTUALIZATION=y CONFIG_KVM=y -CONFIG_KVM_BOOKE_HOST=y +CONFIG_KVM_440=y # CONFIG_VIRTIO_PCI is not set # CONFIG_VIRTIO_BALLOON is not set diff --git a/arch/powerpc/include/asm/atomic.h b/arch/powerpc/include/asm/atomic.h index f3fc733758f5ccfeb27e1e3e51df7d4039608cbb..499be5bdd6fae52bd0f8894fa62e1553eb237912 100644 --- a/arch/powerpc/include/asm/atomic.h +++ b/arch/powerpc/include/asm/atomic.h @@ -111,7 +111,7 @@ static __inline__ void atomic_inc(atomic_t *v) bne- 1b" : "=&r" (t), "+m" (v->counter) : "r" (&v->counter) - : "cc"); + : "cc", "xer"); } static __inline__ int atomic_inc_return(atomic_t *v) @@ -128,7 +128,7 @@ static __inline__ int atomic_inc_return(atomic_t *v) ISYNC_ON_SMP : "=&r" (t) : "r" (&v->counter) - : "cc", "memory"); + : "cc", "xer", "memory"); return t; } @@ -155,7 +155,7 @@ static __inline__ void atomic_dec(atomic_t *v) bne- 1b" : "=&r" (t), "+m" (v->counter) : "r" (&v->counter) - : "cc"); + : "cc", "xer"); } static __inline__ int atomic_dec_return(atomic_t *v) @@ -172,7 +172,7 @@ static __inline__ int atomic_dec_return(atomic_t *v) ISYNC_ON_SMP : "=&r" (t) : "r" (&v->counter) - : "cc", "memory"); + : "cc", "xer", "memory"); return t; } @@ -346,7 +346,7 @@ static __inline__ void atomic64_inc(atomic64_t *v) bne- 1b" : "=&r" (t), "+m" (v->counter) : "r" (&v->counter) - : "cc"); + : "cc", "xer"); } static __inline__ long atomic64_inc_return(atomic64_t *v) @@ -362,7 +362,7 @@ static __inline__ long atomic64_inc_return(atomic64_t *v) ISYNC_ON_SMP : "=&r" (t) : "r" (&v->counter) - : "cc", "memory"); + : "cc", "xer", "memory"); return t; } @@ -388,7 +388,7 @@ static __inline__ void atomic64_dec(atomic64_t *v) bne- 1b" : "=&r" (t), "+m" (v->counter) : "r" (&v->counter) - : "cc"); + : "cc", "xer"); } static __inline__ long atomic64_dec_return(atomic64_t *v) @@ -404,7 +404,7 @@ static __inline__ long atomic64_dec_return(atomic64_t *v) ISYNC_ON_SMP : "=&r" (t) : "r" (&v->counter) - : "cc", "memory"); + : "cc", "xer", "memory"); return t; } @@ -431,7 +431,7 @@ static __inline__ long atomic64_dec_if_positive(atomic64_t *v) "\n\ 2:" : "=&r" (t) : "r" (&v->counter) - : "cc", "memory"); + : "cc", "xer", "memory"); return t; } diff --git a/arch/powerpc/include/asm/bug.h b/arch/powerpc/include/asm/bug.h index e55d1f66b86fca4646f702355e15beaea10f6b65..64e1fdca233e065a0b3208517917a4e6103e6a21 100644 --- a/arch/powerpc/include/asm/bug.h +++ b/arch/powerpc/include/asm/bug.h @@ -3,6 +3,7 @@ #ifdef __KERNEL__ #include + /* * Define an illegal instr to trap on the bug. * We don't use 0 because that marks the end of a function @@ -14,6 +15,7 @@ #ifdef CONFIG_BUG #ifdef __ASSEMBLY__ +#include #ifdef CONFIG_DEBUG_BUGVERBOSE .macro EMIT_BUG_ENTRY addr,file,line,flags .section __bug_table,"a" @@ -26,7 +28,7 @@ .previous .endm #else - .macro EMIT_BUG_ENTRY addr,file,line,flags +.macro EMIT_BUG_ENTRY addr,file,line,flags .section __bug_table,"a" 5001: PPC_LONG \addr .short \flags @@ -113,6 +115,13 @@ #define HAVE_ARCH_BUG_ON #define HAVE_ARCH_WARN_ON #endif /* __ASSEMBLY __ */ +#else +#ifdef __ASSEMBLY__ +.macro EMIT_BUG_ENTRY addr,file,line,flags +.endm +#else /* !__ASSEMBLY__ */ +#define _EMIT_BUG_ENTRY +#endif #endif /* CONFIG_BUG */ #include diff --git a/arch/powerpc/include/asm/byteorder.h b/arch/powerpc/include/asm/byteorder.h index b37752214a16a7316756ab975ab4b1ef154f7529..d5de325472e9f4ae9aa3cbc06b66b4cb40978e0d 100644 --- a/arch/powerpc/include/asm/byteorder.h +++ b/arch/powerpc/include/asm/byteorder.h @@ -11,6 +11,8 @@ #include #include +#define __BIG_ENDIAN + #ifdef __GNUC__ #ifdef __KERNEL__ @@ -21,12 +23,19 @@ static __inline__ __u16 ld_le16(const volatile __u16 *addr) __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (addr), "m" (*addr)); return val; } +#define __arch_swab16p ld_le16 static __inline__ void st_le16(volatile __u16 *addr, const __u16 val) { __asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*addr) : "r" (val), "r" (addr)); } +static inline void __arch_swab16s(__u16 *addr) +{ + st_le16(addr, *addr); +} +#define __arch_swab16s __arch_swab16s + static __inline__ __u32 ld_le32(const volatile __u32 *addr) { __u32 val; @@ -34,13 +43,20 @@ static __inline__ __u32 ld_le32(const volatile __u32 *addr) __asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (addr), "m" (*addr)); return val; } +#define __arch_swab32p ld_le32 static __inline__ void st_le32(volatile __u32 *addr, const __u32 val) { __asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*addr) : "r" (val), "r" (addr)); } -static __inline__ __attribute_const__ __u16 ___arch__swab16(__u16 value) +static inline void __arch_swab32s(__u32 *addr) +{ + st_le32(addr, *addr); +} +#define __arch_swab32s __arch_swab32s + +static inline __attribute_const__ __u16 __arch_swab16(__u16 value) { __u16 result; @@ -49,8 +65,9 @@ static __inline__ __attribute_const__ __u16 ___arch__swab16(__u16 value) : "r" (value), "0" (value >> 8)); return result; } +#define __arch_swab16 __arch_swab16 -static __inline__ __attribute_const__ __u32 ___arch__swab32(__u32 value) +static inline __attribute_const__ __u32 __arch_swab32(__u32 value) { __u32 result; @@ -61,29 +78,16 @@ static __inline__ __attribute_const__ __u32 ___arch__swab32(__u32 value) : "r" (value), "0" (value >> 24)); return result; } - -#define __arch__swab16(x) ___arch__swab16(x) -#define __arch__swab32(x) ___arch__swab32(x) - -/* The same, but returns converted value from the location pointer by addr. */ -#define __arch__swab16p(addr) ld_le16(addr) -#define __arch__swab32p(addr) ld_le32(addr) - -/* The same, but do the conversion in situ, ie. put the value back to addr. */ -#define __arch__swab16s(addr) st_le16(addr,*addr) -#define __arch__swab32s(addr) st_le32(addr,*addr) +#define __arch_swab32 __arch_swab32 #endif /* __KERNEL__ */ -#ifndef __STRICT_ANSI__ -#define __BYTEORDER_HAS_U64__ #ifndef __powerpc64__ #define __SWAB_64_THRU_32__ #endif /* __powerpc64__ */ -#endif /* __STRICT_ANSI__ */ #endif /* __GNUC__ */ -#include +#include #endif /* _ASM_POWERPC_BYTEORDER_H */ diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index 1e94b07a020ed6907be0fd1d35a2ec58b4d5b852..4911104791c319b0a6731676c4db599b5530aab9 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h @@ -82,6 +82,7 @@ struct cpu_spec { char *cpu_name; unsigned long cpu_features; /* Kernel features */ unsigned int cpu_user_features; /* Userland features */ + unsigned int mmu_features; /* MMU features */ /* cache line sizes */ unsigned int icache_bsize; @@ -144,17 +145,14 @@ extern const char *powerpc_base_platform; #define CPU_FTR_USE_TB ASM_CONST(0x0000000000000040) #define CPU_FTR_L2CSR ASM_CONST(0x0000000000000080) #define CPU_FTR_601 ASM_CONST(0x0000000000000100) -#define CPU_FTR_HPTE_TABLE ASM_CONST(0x0000000000000200) #define CPU_FTR_CAN_NAP ASM_CONST(0x0000000000000400) #define CPU_FTR_L3CR ASM_CONST(0x0000000000000800) #define CPU_FTR_L3_DISABLE_NAP ASM_CONST(0x0000000000001000) #define CPU_FTR_NAP_DISABLE_L2_PR ASM_CONST(0x0000000000002000) #define CPU_FTR_DUAL_PLL_750FX ASM_CONST(0x0000000000004000) #define CPU_FTR_NO_DPM ASM_CONST(0x0000000000008000) -#define CPU_FTR_HAS_HIGH_BATS ASM_CONST(0x0000000000010000) #define CPU_FTR_NEED_COHERENT ASM_CONST(0x0000000000020000) #define CPU_FTR_NO_BTIC ASM_CONST(0x0000000000040000) -#define CPU_FTR_BIG_PHYS ASM_CONST(0x0000000000080000) #define CPU_FTR_NODSISRALIGN ASM_CONST(0x0000000000100000) #define CPU_FTR_PPC_LE ASM_CONST(0x0000000000200000) #define CPU_FTR_REAL_LE ASM_CONST(0x0000000000400000) @@ -163,6 +161,8 @@ extern const char *powerpc_base_platform; #define CPU_FTR_SPE ASM_CONST(0x0000000002000000) #define CPU_FTR_NEED_PAIRED_STWCX ASM_CONST(0x0000000004000000) #define CPU_FTR_LWSYNC ASM_CONST(0x0000000008000000) +#define CPU_FTR_NOEXECUTE ASM_CONST(0x0000000010000000) +#define CPU_FTR_INDEXED_DCR ASM_CONST(0x0000000020000000) /* * Add the 64-bit processor unique features in the top half of the word; @@ -177,7 +177,6 @@ extern const char *powerpc_base_platform; #define CPU_FTR_SLB LONG_ASM_CONST(0x0000000100000000) #define CPU_FTR_16M_PAGE LONG_ASM_CONST(0x0000000200000000) #define CPU_FTR_TLBIEL LONG_ASM_CONST(0x0000000400000000) -#define CPU_FTR_NOEXECUTE LONG_ASM_CONST(0x0000000800000000) #define CPU_FTR_IABR LONG_ASM_CONST(0x0000002000000000) #define CPU_FTR_MMCRA LONG_ASM_CONST(0x0000004000000000) #define CPU_FTR_CTRL LONG_ASM_CONST(0x0000008000000000) @@ -194,6 +193,7 @@ extern const char *powerpc_base_platform; #define CPU_FTR_VSX LONG_ASM_CONST(0x0010000000000000) #define CPU_FTR_SAO LONG_ASM_CONST(0x0020000000000000) #define CPU_FTR_CP_USE_DCBTZ LONG_ASM_CONST(0x0040000000000000) +#define CPU_FTR_UNALIGNED_LD_STD LONG_ASM_CONST(0x0080000000000000) #ifndef __ASSEMBLY__ @@ -264,164 +264,159 @@ extern const char *powerpc_base_platform; !defined(CONFIG_POWER3) && !defined(CONFIG_POWER4) && \ !defined(CONFIG_BOOKE)) -#define CPU_FTRS_PPC601 (CPU_FTR_COMMON | CPU_FTR_601 | CPU_FTR_HPTE_TABLE | \ +#define CPU_FTRS_PPC601 (CPU_FTR_COMMON | CPU_FTR_601 | \ CPU_FTR_COHERENT_ICACHE | CPU_FTR_UNIFIED_ID_CACHE) #define CPU_FTRS_603 (CPU_FTR_COMMON | \ CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | \ CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_PPC_LE) #define CPU_FTRS_604 (CPU_FTR_COMMON | \ - CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_PPC_LE) + CPU_FTR_USE_TB | CPU_FTR_PPC_LE) #define CPU_FTRS_740_NOTAU (CPU_FTR_COMMON | \ CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \ - CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_PPC_LE) + CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_PPC_LE) #define CPU_FTRS_740 (CPU_FTR_COMMON | \ CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \ - CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \ + CPU_FTR_TAU | CPU_FTR_MAYBE_CAN_NAP | \ CPU_FTR_PPC_LE) #define CPU_FTRS_750 (CPU_FTR_COMMON | \ CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \ - CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \ + CPU_FTR_TAU | CPU_FTR_MAYBE_CAN_NAP | \ CPU_FTR_PPC_LE) -#define CPU_FTRS_750CL (CPU_FTRS_750 | CPU_FTR_HAS_HIGH_BATS) +#define CPU_FTRS_750CL (CPU_FTRS_750) #define CPU_FTRS_750FX1 (CPU_FTRS_750 | CPU_FTR_DUAL_PLL_750FX | CPU_FTR_NO_DPM) #define CPU_FTRS_750FX2 (CPU_FTRS_750 | CPU_FTR_NO_DPM) -#define CPU_FTRS_750FX (CPU_FTRS_750 | CPU_FTR_DUAL_PLL_750FX | \ - CPU_FTR_HAS_HIGH_BATS) +#define CPU_FTRS_750FX (CPU_FTRS_750 | CPU_FTR_DUAL_PLL_750FX) #define CPU_FTRS_750GX (CPU_FTRS_750FX) #define CPU_FTRS_7400_NOTAU (CPU_FTR_COMMON | \ CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \ - CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE | \ + CPU_FTR_ALTIVEC_COMP | \ CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_PPC_LE) #define CPU_FTRS_7400 (CPU_FTR_COMMON | \ CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \ - CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE | \ + CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | \ CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_PPC_LE) #define CPU_FTRS_7450_20 (CPU_FTR_COMMON | \ CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \ - CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \ + CPU_FTR_L3CR | CPU_FTR_SPEC7450 | \ CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE | CPU_FTR_NEED_PAIRED_STWCX) #define CPU_FTRS_7450_21 (CPU_FTR_COMMON | \ CPU_FTR_USE_TB | \ CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \ - CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \ + CPU_FTR_L3CR | CPU_FTR_SPEC7450 | \ CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_L3_DISABLE_NAP | \ CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE | CPU_FTR_NEED_PAIRED_STWCX) #define CPU_FTRS_7450_23 (CPU_FTR_COMMON | \ CPU_FTR_USE_TB | CPU_FTR_NEED_PAIRED_STWCX | \ CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \ - CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \ + CPU_FTR_L3CR | CPU_FTR_SPEC7450 | \ CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE) #define CPU_FTRS_7455_1 (CPU_FTR_COMMON | \ CPU_FTR_USE_TB | CPU_FTR_NEED_PAIRED_STWCX | \ CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR | \ - CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_HAS_HIGH_BATS | \ - CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE) + CPU_FTR_SPEC7450 | CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE) #define CPU_FTRS_7455_20 (CPU_FTR_COMMON | \ CPU_FTR_USE_TB | CPU_FTR_NEED_PAIRED_STWCX | \ CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \ - CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \ + CPU_FTR_L3CR | CPU_FTR_SPEC7450 | \ CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_L3_DISABLE_NAP | \ - CPU_FTR_NEED_COHERENT | CPU_FTR_HAS_HIGH_BATS | CPU_FTR_PPC_LE) + CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE) #define CPU_FTRS_7455 (CPU_FTR_COMMON | \ CPU_FTR_USE_TB | \ CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \ - CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \ - CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS | \ + CPU_FTR_L3CR | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR | \ CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE | CPU_FTR_NEED_PAIRED_STWCX) #define CPU_FTRS_7447_10 (CPU_FTR_COMMON | \ CPU_FTR_USE_TB | \ CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \ - CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \ - CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS | \ + CPU_FTR_L3CR | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR | \ CPU_FTR_NEED_COHERENT | CPU_FTR_NO_BTIC | CPU_FTR_PPC_LE | \ CPU_FTR_NEED_PAIRED_STWCX) #define CPU_FTRS_7447 (CPU_FTR_COMMON | \ CPU_FTR_USE_TB | \ CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \ - CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \ - CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS | \ + CPU_FTR_L3CR | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR | \ CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE | CPU_FTR_NEED_PAIRED_STWCX) #define CPU_FTRS_7447A (CPU_FTR_COMMON | \ CPU_FTR_USE_TB | \ CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \ - CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \ - CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS | \ + CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR | \ CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE | CPU_FTR_NEED_PAIRED_STWCX) #define CPU_FTRS_7448 (CPU_FTR_COMMON | \ CPU_FTR_USE_TB | \ CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \ - CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \ - CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS | \ + CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR | \ CPU_FTR_PPC_LE | CPU_FTR_NEED_PAIRED_STWCX) #define CPU_FTRS_82XX (CPU_FTR_COMMON | \ CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB) #define CPU_FTRS_G2_LE (CPU_FTR_COMMON | CPU_FTR_MAYBE_CAN_DOZE | \ - CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_HAS_HIGH_BATS) + CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP) #define CPU_FTRS_E300 (CPU_FTR_MAYBE_CAN_DOZE | \ - CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_HAS_HIGH_BATS | \ + CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | \ CPU_FTR_COMMON) #define CPU_FTRS_E300C2 (CPU_FTR_MAYBE_CAN_DOZE | \ - CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_HAS_HIGH_BATS | \ + CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | \ CPU_FTR_COMMON | CPU_FTR_FPU_UNAVAILABLE) -#define CPU_FTRS_CLASSIC32 (CPU_FTR_COMMON | \ - CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE) +#define CPU_FTRS_CLASSIC32 (CPU_FTR_COMMON | CPU_FTR_USE_TB) #define CPU_FTRS_8XX (CPU_FTR_USE_TB) -#define CPU_FTRS_40X (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN) -#define CPU_FTRS_44X (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN) +#define CPU_FTRS_40X (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | CPU_FTR_NOEXECUTE) +#define CPU_FTRS_44X (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | CPU_FTR_NOEXECUTE) +#define CPU_FTRS_440x6 (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | CPU_FTR_NOEXECUTE | \ + CPU_FTR_INDEXED_DCR) #define CPU_FTRS_E200 (CPU_FTR_USE_TB | CPU_FTR_SPE_COMP | \ CPU_FTR_NODSISRALIGN | CPU_FTR_COHERENT_ICACHE | \ - CPU_FTR_UNIFIED_ID_CACHE) + CPU_FTR_UNIFIED_ID_CACHE | CPU_FTR_NOEXECUTE) #define CPU_FTRS_E500 (CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | \ - CPU_FTR_SPE_COMP | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_NODSISRALIGN) + CPU_FTR_SPE_COMP | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_NODSISRALIGN | \ + CPU_FTR_NOEXECUTE) #define CPU_FTRS_E500_2 (CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | \ - CPU_FTR_SPE_COMP | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_BIG_PHYS | \ - CPU_FTR_NODSISRALIGN) + CPU_FTR_SPE_COMP | CPU_FTR_MAYBE_CAN_NAP | \ + CPU_FTR_NODSISRALIGN | CPU_FTR_NOEXECUTE) #define CPU_FTRS_E500MC (CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | \ - CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_BIG_PHYS | CPU_FTR_NODSISRALIGN | \ - CPU_FTR_L2CSR | CPU_FTR_LWSYNC) + CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_NODSISRALIGN | \ + CPU_FTR_L2CSR | CPU_FTR_LWSYNC | CPU_FTR_NOEXECUTE) #define CPU_FTRS_GENERIC_32 (CPU_FTR_COMMON | CPU_FTR_NODSISRALIGN) /* 64-bit CPUs */ #define CPU_FTRS_POWER3 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \ - CPU_FTR_HPTE_TABLE | CPU_FTR_IABR | CPU_FTR_PPC_LE) + CPU_FTR_IABR | CPU_FTR_PPC_LE) #define CPU_FTRS_RS64 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \ - CPU_FTR_HPTE_TABLE | CPU_FTR_IABR | \ + CPU_FTR_IABR | \ CPU_FTR_MMCRA | CPU_FTR_CTRL) #define CPU_FTRS_POWER4 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \ - CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \ + CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \ CPU_FTR_MMCRA | CPU_FTR_CP_USE_DCBTZ) #define CPU_FTRS_PPC970 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \ - CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \ + CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \ CPU_FTR_ALTIVEC_COMP | CPU_FTR_CAN_NAP | CPU_FTR_MMCRA | \ CPU_FTR_CP_USE_DCBTZ) #define CPU_FTRS_POWER5 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \ - CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \ + CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \ CPU_FTR_MMCRA | CPU_FTR_SMT | \ CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \ CPU_FTR_PURR) #define CPU_FTRS_POWER6 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \ - CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \ + CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \ CPU_FTR_MMCRA | CPU_FTR_SMT | \ CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \ CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \ - CPU_FTR_DSCR) + CPU_FTR_DSCR | CPU_FTR_UNALIGNED_LD_STD) #define CPU_FTRS_POWER7 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \ - CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \ + CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \ CPU_FTR_MMCRA | CPU_FTR_SMT | \ CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \ CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \ CPU_FTR_DSCR | CPU_FTR_SAO) #define CPU_FTRS_CELL (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \ - CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \ + CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \ CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \ CPU_FTR_PAUSE_ZERO | CPU_FTR_CI_LARGE_PAGE | \ - CPU_FTR_CELL_TB_BUG | CPU_FTR_CP_USE_DCBTZ) + CPU_FTR_CELL_TB_BUG | CPU_FTR_CP_USE_DCBTZ | \ + CPU_FTR_UNALIGNED_LD_STD) #define CPU_FTRS_PA6T (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \ - CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | \ + CPU_FTR_PPCAS_ARCH_V2 | \ CPU_FTR_ALTIVEC_COMP | CPU_FTR_CI_LARGE_PAGE | \ CPU_FTR_PURR | CPU_FTR_REAL_LE | CPU_FTR_NO_SLBIE_B) -#define CPU_FTRS_COMPATIBLE (CPU_FTR_USE_TB | \ - CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2) +#define CPU_FTRS_COMPATIBLE (CPU_FTR_USE_TB | CPU_FTR_PPCAS_ARCH_V2) #ifdef __powerpc64__ #define CPU_FTRS_POSSIBLE \ @@ -452,7 +447,7 @@ enum { CPU_FTRS_40X | #endif #ifdef CONFIG_44x - CPU_FTRS_44X | + CPU_FTRS_44X | CPU_FTRS_440x6 | #endif #ifdef CONFIG_E200 CPU_FTRS_E200 | @@ -492,7 +487,7 @@ enum { CPU_FTRS_40X & #endif #ifdef CONFIG_44x - CPU_FTRS_44X & + CPU_FTRS_44X & CPU_FTRS_440x6 & #endif #ifdef CONFIG_E200 CPU_FTRS_E200 & diff --git a/arch/powerpc/include/asm/dcr-native.h b/arch/powerpc/include/asm/dcr-native.h index 72d2b72c739007c447f25272bc0f30515cd08f76..7d2e6235726d14a94190436891ca157c2457d0c1 100644 --- a/arch/powerpc/include/asm/dcr-native.h +++ b/arch/powerpc/include/asm/dcr-native.h @@ -23,6 +23,7 @@ #ifndef __ASSEMBLY__ #include +#include typedef struct { unsigned int base; @@ -39,23 +40,45 @@ static inline bool dcr_map_ok_native(dcr_host_native_t host) #define dcr_read_native(host, dcr_n) mfdcr(dcr_n + host.base) #define dcr_write_native(host, dcr_n, value) mtdcr(dcr_n + host.base, value) -/* Device Control Registers */ -void __mtdcr(int reg, unsigned int val); -unsigned int __mfdcr(int reg); +/* Table based DCR accessors */ +extern void __mtdcr(unsigned int reg, unsigned int val); +extern unsigned int __mfdcr(unsigned int reg); + +/* mfdcrx/mtdcrx instruction based accessors. We hand code + * the opcodes in order not to depend on newer binutils + */ +static inline unsigned int mfdcrx(unsigned int reg) +{ + unsigned int ret; + asm volatile(".long 0x7c000206 | (%0 << 21) | (%1 << 16)" + : "=r" (ret) : "r" (reg)); + return ret; +} + +static inline void mtdcrx(unsigned int reg, unsigned int val) +{ + asm volatile(".long 0x7c000306 | (%0 << 21) | (%1 << 16)" + : : "r" (val), "r" (reg)); +} + #define mfdcr(rn) \ ({unsigned int rval; \ - if (__builtin_constant_p(rn)) \ + if (__builtin_constant_p(rn) && rn < 1024) \ asm volatile("mfdcr %0," __stringify(rn) \ : "=r" (rval)); \ + else if (likely(cpu_has_feature(CPU_FTR_INDEXED_DCR))) \ + rval = mfdcrx(rn); \ else \ rval = __mfdcr(rn); \ rval;}) #define mtdcr(rn, v) \ do { \ - if (__builtin_constant_p(rn)) \ + if (__builtin_constant_p(rn) && rn < 1024) \ asm volatile("mtdcr " __stringify(rn) ",%0" \ : : "r" (v)); \ + else if (likely(cpu_has_feature(CPU_FTR_INDEXED_DCR))) \ + mtdcrx(rn, v); \ else \ __mtdcr(rn, v); \ } while (0) @@ -69,8 +92,13 @@ static inline unsigned __mfdcri(int base_addr, int base_data, int reg) unsigned int val; spin_lock_irqsave(&dcr_ind_lock, flags); - __mtdcr(base_addr, reg); - val = __mfdcr(base_data); + if (cpu_has_feature(CPU_FTR_INDEXED_DCR)) { + mtdcrx(base_addr, reg); + val = mfdcrx(base_data); + } else { + __mtdcr(base_addr, reg); + val = __mfdcr(base_data); + } spin_unlock_irqrestore(&dcr_ind_lock, flags); return val; } @@ -81,8 +109,13 @@ static inline void __mtdcri(int base_addr, int base_data, int reg, unsigned long flags; spin_lock_irqsave(&dcr_ind_lock, flags); - __mtdcr(base_addr, reg); - __mtdcr(base_data, val); + if (cpu_has_feature(CPU_FTR_INDEXED_DCR)) { + mtdcrx(base_addr, reg); + mtdcrx(base_data, val); + } else { + __mtdcr(base_addr, reg); + __mtdcr(base_data, val); + } spin_unlock_irqrestore(&dcr_ind_lock, flags); } @@ -93,9 +126,15 @@ static inline void __dcri_clrset(int base_addr, int base_data, int reg, unsigned int val; spin_lock_irqsave(&dcr_ind_lock, flags); - __mtdcr(base_addr, reg); - val = (__mfdcr(base_data) & ~clr) | set; - __mtdcr(base_data, val); + if (cpu_has_feature(CPU_FTR_INDEXED_DCR)) { + mtdcrx(base_addr, reg); + val = (mfdcrx(base_data) & ~clr) | set; + mtdcrx(base_data, val); + } else { + __mtdcr(base_addr, reg); + val = (__mfdcr(base_data) & ~clr) | set; + __mtdcr(base_data, val); + } spin_unlock_irqrestore(&dcr_ind_lock, flags); } diff --git a/arch/powerpc/include/asm/dcr.h b/arch/powerpc/include/asm/dcr.h index d13fb68bb5c0e3daf5a965635b548f18bc00a648..9d6851cfb84149ee0d042acb7b17408c77ab080a 100644 --- a/arch/powerpc/include/asm/dcr.h +++ b/arch/powerpc/include/asm/dcr.h @@ -68,9 +68,9 @@ typedef dcr_host_mmio_t dcr_host_t; * additional helpers to read the DCR * base from the device-tree */ struct device_node; -extern unsigned int dcr_resource_start(struct device_node *np, +extern unsigned int dcr_resource_start(const struct device_node *np, unsigned int index); -extern unsigned int dcr_resource_len(struct device_node *np, +extern unsigned int dcr_resource_len(const struct device_node *np, unsigned int index); #endif /* CONFIG_PPC_DCR */ #endif /* __ASSEMBLY__ */ diff --git a/arch/powerpc/include/asm/device.h b/arch/powerpc/include/asm/device.h index dfd504caccc1c711216adc077b351eb5710f32ca..7d2277cef09a8502b22bdea95185f132a479f7db 100644 --- a/arch/powerpc/include/asm/device.h +++ b/arch/powerpc/include/asm/device.h @@ -18,4 +18,16 @@ struct dev_archdata { void *dma_data; }; +static inline void dev_archdata_set_node(struct dev_archdata *ad, + struct device_node *np) +{ + ad->of_node = np; +} + +static inline struct device_node * +dev_archdata_get_node(const struct dev_archdata *ad) +{ + return ad->of_node; +} + #endif /* _ASM_POWERPC_DEVICE_H */ diff --git a/arch/powerpc/include/asm/dma-mapping.h b/arch/powerpc/include/asm/dma-mapping.h index fddb229bd74f270231c570726d7e15bef0a201f5..86cef7ddc8d5f251b07c6c838bf7dcba9d8d579d 100644 --- a/arch/powerpc/include/asm/dma-mapping.h +++ b/arch/powerpc/include/asm/dma-mapping.h @@ -60,12 +60,6 @@ struct dma_mapping_ops { dma_addr_t *dma_handle, gfp_t flag); void (*free_coherent)(struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle); - dma_addr_t (*map_single)(struct device *dev, void *ptr, - size_t size, enum dma_data_direction direction, - struct dma_attrs *attrs); - void (*unmap_single)(struct device *dev, dma_addr_t dma_addr, - size_t size, enum dma_data_direction direction, - struct dma_attrs *attrs); int (*map_sg)(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction direction, struct dma_attrs *attrs); @@ -82,6 +76,22 @@ struct dma_mapping_ops { dma_addr_t dma_address, size_t size, enum dma_data_direction direction, struct dma_attrs *attrs); +#ifdef CONFIG_PPC_NEED_DMA_SYNC_OPS + void (*sync_single_range_for_cpu)(struct device *hwdev, + dma_addr_t dma_handle, unsigned long offset, + size_t size, + enum dma_data_direction direction); + void (*sync_single_range_for_device)(struct device *hwdev, + dma_addr_t dma_handle, unsigned long offset, + size_t size, + enum dma_data_direction direction); + void (*sync_sg_for_cpu)(struct device *hwdev, + struct scatterlist *sg, int nelems, + enum dma_data_direction direction); + void (*sync_sg_for_device)(struct device *hwdev, + struct scatterlist *sg, int nelems, + enum dma_data_direction direction); +#endif }; /* @@ -149,10 +159,9 @@ static inline int dma_set_mask(struct device *dev, u64 dma_mask) } /* - * TODO: map_/unmap_single will ideally go away, to be completely - * replaced by map/unmap_page. Until then, we allow dma_ops to have - * one or the other, or both by checking to see if the specific - * function requested exists; and if not, falling back on the other set. + * map_/unmap_single actually call through to map/unmap_page now that all the + * dma_mapping_ops have been converted over. We just have to get the page and + * offset to pass through to map_page */ static inline dma_addr_t dma_map_single_attrs(struct device *dev, void *cpu_addr, @@ -164,10 +173,6 @@ static inline dma_addr_t dma_map_single_attrs(struct device *dev, BUG_ON(!dma_ops); - if (dma_ops->map_single) - return dma_ops->map_single(dev, cpu_addr, size, direction, - attrs); - return dma_ops->map_page(dev, virt_to_page(cpu_addr), (unsigned long)cpu_addr % PAGE_SIZE, size, direction, attrs); @@ -183,11 +188,6 @@ static inline void dma_unmap_single_attrs(struct device *dev, BUG_ON(!dma_ops); - if (dma_ops->unmap_single) { - dma_ops->unmap_single(dev, dma_addr, size, direction, attrs); - return; - } - dma_ops->unmap_page(dev, dma_addr, size, direction, attrs); } @@ -201,12 +201,7 @@ static inline dma_addr_t dma_map_page_attrs(struct device *dev, BUG_ON(!dma_ops); - if (dma_ops->map_page) - return dma_ops->map_page(dev, page, offset, size, direction, - attrs); - - return dma_ops->map_single(dev, page_address(page) + offset, size, - direction, attrs); + return dma_ops->map_page(dev, page, offset, size, direction, attrs); } static inline void dma_unmap_page_attrs(struct device *dev, @@ -219,12 +214,7 @@ static inline void dma_unmap_page_attrs(struct device *dev, BUG_ON(!dma_ops); - if (dma_ops->unmap_page) { - dma_ops->unmap_page(dev, dma_address, size, direction, attrs); - return; - } - - dma_ops->unmap_single(dev, dma_address, size, direction, attrs); + dma_ops->unmap_page(dev, dma_address, size, direction, attrs); } static inline int dma_map_sg_attrs(struct device *dev, struct scatterlist *sg, @@ -308,47 +298,107 @@ static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg, dma_unmap_sg_attrs(dev, sg, nhwentries, direction, NULL); } +#ifdef CONFIG_PPC_NEED_DMA_SYNC_OPS static inline void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, enum dma_data_direction direction) { - BUG_ON(direction == DMA_NONE); - __dma_sync(bus_to_virt(dma_handle), size, direction); + struct dma_mapping_ops *dma_ops = get_dma_ops(dev); + + BUG_ON(!dma_ops); + dma_ops->sync_single_range_for_cpu(dev, dma_handle, 0, + size, direction); } static inline void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size, enum dma_data_direction direction) { - BUG_ON(direction == DMA_NONE); - __dma_sync(bus_to_virt(dma_handle), size, direction); + struct dma_mapping_ops *dma_ops = get_dma_ops(dev); + + BUG_ON(!dma_ops); + dma_ops->sync_single_range_for_device(dev, dma_handle, + 0, size, direction); } static inline void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sgl, int nents, enum dma_data_direction direction) { - struct scatterlist *sg; - int i; + struct dma_mapping_ops *dma_ops = get_dma_ops(dev); - BUG_ON(direction == DMA_NONE); + BUG_ON(!dma_ops); + dma_ops->sync_sg_for_cpu(dev, sgl, nents, direction); +} + +static inline void dma_sync_sg_for_device(struct device *dev, + struct scatterlist *sgl, int nents, + enum dma_data_direction direction) +{ + struct dma_mapping_ops *dma_ops = get_dma_ops(dev); + + BUG_ON(!dma_ops); + dma_ops->sync_sg_for_device(dev, sgl, nents, direction); +} + +static inline void dma_sync_single_range_for_cpu(struct device *dev, + dma_addr_t dma_handle, unsigned long offset, size_t size, + enum dma_data_direction direction) +{ + struct dma_mapping_ops *dma_ops = get_dma_ops(dev); - for_each_sg(sgl, sg, nents, i) - __dma_sync_page(sg_page(sg), sg->offset, sg->length, direction); + BUG_ON(!dma_ops); + dma_ops->sync_single_range_for_cpu(dev, dma_handle, + offset, size, direction); +} + +static inline void dma_sync_single_range_for_device(struct device *dev, + dma_addr_t dma_handle, unsigned long offset, size_t size, + enum dma_data_direction direction) +{ + struct dma_mapping_ops *dma_ops = get_dma_ops(dev); + + BUG_ON(!dma_ops); + dma_ops->sync_single_range_for_device(dev, dma_handle, offset, + size, direction); +} +#else /* CONFIG_PPC_NEED_DMA_SYNC_OPS */ +static inline void dma_sync_single_for_cpu(struct device *dev, + dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction) +{ +} + +static inline void dma_sync_single_for_device(struct device *dev, + dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction) +{ +} + +static inline void dma_sync_sg_for_cpu(struct device *dev, + struct scatterlist *sgl, int nents, + enum dma_data_direction direction) +{ } static inline void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sgl, int nents, enum dma_data_direction direction) { - struct scatterlist *sg; - int i; +} - BUG_ON(direction == DMA_NONE); +static inline void dma_sync_single_range_for_cpu(struct device *dev, + dma_addr_t dma_handle, unsigned long offset, size_t size, + enum dma_data_direction direction) +{ +} - for_each_sg(sgl, sg, nents, i) - __dma_sync_page(sg_page(sg), sg->offset, sg->length, direction); +static inline void dma_sync_single_range_for_device(struct device *dev, + dma_addr_t dma_handle, unsigned long offset, size_t size, + enum dma_data_direction direction) +{ } +#endif static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { @@ -382,22 +432,6 @@ static inline int dma_get_cache_alignment(void) #endif } -static inline void dma_sync_single_range_for_cpu(struct device *dev, - dma_addr_t dma_handle, unsigned long offset, size_t size, - enum dma_data_direction direction) -{ - /* just sync everything for now */ - dma_sync_single_for_cpu(dev, dma_handle, offset + size, direction); -} - -static inline void dma_sync_single_range_for_device(struct device *dev, - dma_addr_t dma_handle, unsigned long offset, size_t size, - enum dma_data_direction direction) -{ - /* just sync everything for now */ - dma_sync_single_for_device(dev, dma_handle, offset + size, direction); -} - static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction direction) { diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h index b886bec67016795582d1922b3ccc2c0913c8f878..66ea9b8b95c58f44c2ca464758d754f5378ac2ca 100644 --- a/arch/powerpc/include/asm/eeh.h +++ b/arch/powerpc/include/asm/eeh.h @@ -17,8 +17,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _PPC64_EEH_H -#define _PPC64_EEH_H +#ifndef _POWERPC_EEH_H +#define _POWERPC_EEH_H #ifdef __KERNEL__ #include @@ -110,6 +110,7 @@ static inline void eeh_remove_bus_device(struct pci_dev *dev) { } #define EEH_IO_ERROR_VALUE(size) (-1UL) #endif /* CONFIG_EEH */ +#ifdef CONFIG_PPC64 /* * MMIO read/write operations with EEH support. */ @@ -207,5 +208,6 @@ static inline void eeh_readsl(const volatile void __iomem *addr, void * buf, eeh_check_failure(addr, *(u32*)buf); } +#endif /* CONFIG_PPC64 */ #endif /* __KERNEL__ */ -#endif /* _PPC64_EEH_H */ +#endif /* _POWERPC_EEH_H */ diff --git a/arch/powerpc/include/asm/elf.h b/arch/powerpc/include/asm/elf.h index d812929390e45e602b0a2e02506c7e4e4ac1474c..cd46f023ec6d298dd4571249881ed54a12649eb0 100644 --- a/arch/powerpc/include/asm/elf.h +++ b/arch/powerpc/include/asm/elf.h @@ -267,7 +267,7 @@ extern int ucache_bsize; #define ARCH_HAS_SETUP_ADDITIONAL_PAGES struct linux_binprm; extern int arch_setup_additional_pages(struct linux_binprm *bprm, - int executable_stack); + int uses_interp); #define VDSO_AUX_ENT(a,b) NEW_AUX_ENT(a,b); #endif /* __KERNEL__ */ diff --git a/arch/powerpc/include/asm/feature-fixups.h b/arch/powerpc/include/asm/feature-fixups.h index a1029967620be29003550a84fd12d3e78a13c4b7..e4094a5cb05b6f7de223dd6c15eaf888289d5240 100644 --- a/arch/powerpc/include/asm/feature-fixups.h +++ b/arch/powerpc/include/asm/feature-fixups.h @@ -81,6 +81,36 @@ label##5: \ #define ALT_FTR_SECTION_END_IFCLR(msk) \ ALT_FTR_SECTION_END_NESTED_IFCLR(msk, 97) +/* MMU feature dependent sections */ +#define BEGIN_MMU_FTR_SECTION_NESTED(label) START_FTR_SECTION(label) +#define BEGIN_MMU_FTR_SECTION START_FTR_SECTION(97) + +#define END_MMU_FTR_SECTION_NESTED(msk, val, label) \ + FTR_SECTION_ELSE_NESTED(label) \ + MAKE_FTR_SECTION_ENTRY(msk, val, label, __mmu_ftr_fixup) + +#define END_MMU_FTR_SECTION(msk, val) \ + END_MMU_FTR_SECTION_NESTED(msk, val, 97) + +#define END_MMU_FTR_SECTION_IFSET(msk) END_MMU_FTR_SECTION((msk), (msk)) +#define END_MMU_FTR_SECTION_IFCLR(msk) END_MMU_FTR_SECTION((msk), 0) + +/* MMU feature sections with alternatives, use BEGIN_FTR_SECTION to start */ +#define MMU_FTR_SECTION_ELSE_NESTED(label) FTR_SECTION_ELSE_NESTED(label) +#define MMU_FTR_SECTION_ELSE MMU_FTR_SECTION_ELSE_NESTED(97) +#define ALT_MMU_FTR_SECTION_END_NESTED(msk, val, label) \ + MAKE_FTR_SECTION_ENTRY(msk, val, label, __mmu_ftr_fixup) +#define ALT_MMU_FTR_SECTION_END_NESTED_IFSET(msk, label) \ + ALT_MMU_FTR_SECTION_END_NESTED(msk, msk, label) +#define ALT_MMU_FTR_SECTION_END_NESTED_IFCLR(msk, label) \ + ALT_MMU_FTR_SECTION_END_NESTED(msk, 0, label) +#define ALT_MMU_FTR_SECTION_END(msk, val) \ + ALT_MMU_FTR_SECTION_END_NESTED(msk, val, 97) +#define ALT_MMU_FTR_SECTION_END_IFSET(msk) \ + ALT_MMU_FTR_SECTION_END_NESTED_IFSET(msk, 97) +#define ALT_MMU_FTR_SECTION_END_IFCLR(msk) \ + ALT_MMU_FTR_SECTION_END_NESTED_IFCLR(msk, 97) + /* Firmware feature dependent sections */ #define BEGIN_FW_FTR_SECTION_NESTED(label) START_FTR_SECTION(label) #define BEGIN_FW_FTR_SECTION START_FTR_SECTION(97) diff --git a/arch/powerpc/include/asm/ftrace.h b/arch/powerpc/include/asm/ftrace.h index b298f7a631e6cd9620094c72da4c82832afcdb43..e5f2ae8362f7ea8e15fcaca975fefa6e3662010b 100644 --- a/arch/powerpc/include/asm/ftrace.h +++ b/arch/powerpc/include/asm/ftrace.h @@ -7,7 +7,19 @@ #ifndef __ASSEMBLY__ extern void _mcount(void); -#endif + +#ifdef CONFIG_DYNAMIC_FTRACE +static inline unsigned long ftrace_call_adjust(unsigned long addr) +{ + /* reloction of mcount call site is the same as the address */ + return addr; +} + +struct dyn_arch_ftrace { + struct module *mod; +}; +#endif /* CONFIG_DYNAMIC_FTRACE */ +#endif /* __ASSEMBLY__ */ #endif diff --git a/arch/powerpc/include/asm/highmem.h b/arch/powerpc/include/asm/highmem.h index 91c589520c0aa65256f954c0fce003e37a527b5d..04e4a620952eaefead81d476e95e03fb9dab9e3e 100644 --- a/arch/powerpc/include/asm/highmem.h +++ b/arch/powerpc/include/asm/highmem.h @@ -38,9 +38,24 @@ extern pte_t *pkmap_page_table; * easily, subsequent pte tables have to be allocated in one physical * chunk of RAM. */ -#define LAST_PKMAP (1 << PTE_SHIFT) -#define LAST_PKMAP_MASK (LAST_PKMAP-1) +/* + * We use one full pte table with 4K pages. And with 16K/64K pages pte + * table covers enough memory (32MB and 512MB resp.) that both FIXMAP + * and PKMAP can be placed in single pte table. We use 1024 pages for + * PKMAP in case of 16K/64K pages. + */ +#ifdef CONFIG_PPC_4K_PAGES +#define PKMAP_ORDER PTE_SHIFT +#else +#define PKMAP_ORDER 10 +#endif +#define LAST_PKMAP (1 << PKMAP_ORDER) +#ifndef CONFIG_PPC_4K_PAGES +#define PKMAP_BASE (FIXADDR_START - PAGE_SIZE*(LAST_PKMAP + 1)) +#else #define PKMAP_BASE ((FIXADDR_START - PAGE_SIZE*(LAST_PKMAP + 1)) & PMD_MASK) +#endif +#define LAST_PKMAP_MASK (LAST_PKMAP-1) #define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT) #define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) @@ -85,7 +100,7 @@ static inline void *kmap_atomic_prot(struct page *page, enum km_type type, pgpro BUG_ON(!pte_none(*(kmap_pte-idx))); #endif __set_pte_at(&init_mm, vaddr, kmap_pte-idx, mk_pte(page, prot)); - flush_tlb_page(NULL, vaddr); + local_flush_tlb_page(NULL, vaddr); return (void*) vaddr; } @@ -113,7 +128,7 @@ static inline void kunmap_atomic(void *kvaddr, enum km_type type) * this pte without first remap it */ pte_clear(&init_mm, vaddr, kmap_pte-idx); - flush_tlb_page(NULL, vaddr); + local_flush_tlb_page(NULL, vaddr); #endif pagefault_enable(); } diff --git a/arch/powerpc/include/asm/io.h b/arch/powerpc/include/asm/io.h index 08266d2728b315f78d4b48231d5ac2db7bce2eb4..494cd8b0a278a8b8299f149cd765505513c6b3bb 100644 --- a/arch/powerpc/include/asm/io.h +++ b/arch/powerpc/include/asm/io.h @@ -713,13 +713,6 @@ static inline void * phys_to_virt(unsigned long address) */ #define page_to_phys(page) ((phys_addr_t)page_to_pfn(page) << PAGE_SHIFT) -/* We do NOT want virtual merging, it would put too much pressure on - * our iommu allocator. Instead, we want drivers to be smart enough - * to coalesce sglists that happen to have been mapped in a contiguous - * way by the iommu - */ -#define BIO_VMERGE_BOUNDARY 0 - /* * 32 bits still uses virt_to_bus() for it's implementation of DMA * mappings se we have to keep it defined here. We also have some old diff --git a/arch/powerpc/include/asm/kdump.h b/arch/powerpc/include/asm/kdump.h index b07ebb9784d365b61d4216969fe24fa5c697e269..5ebfe5d3c61ff23c8dd411f8ed8816d0e5286c01 100644 --- a/arch/powerpc/include/asm/kdump.h +++ b/arch/powerpc/include/asm/kdump.h @@ -1,6 +1,8 @@ #ifndef _PPC64_KDUMP_H #define _PPC64_KDUMP_H +#include + /* Kdump kernel runs at 32 MB, change at your peril. */ #define KDUMP_KERNELBASE 0x2000000 @@ -11,8 +13,19 @@ #ifdef CONFIG_CRASH_DUMP +/* + * On PPC64 translation is disabled during trampoline setup, so we use + * physical addresses. Though on PPC32 translation is already enabled, + * so we can't do the same. Luckily create_trampoline() creates relative + * branches, so we can just add the PAGE_OFFSET and don't worry about it. + */ +#ifdef __powerpc64__ #define KDUMP_TRAMPOLINE_START 0x0100 #define KDUMP_TRAMPOLINE_END 0x3000 +#else +#define KDUMP_TRAMPOLINE_START (0x0100 + PAGE_OFFSET) +#define KDUMP_TRAMPOLINE_END (0x3000 + PAGE_OFFSET) +#endif /* __powerpc64__ */ #define KDUMP_MIN_TCE_ENTRIES 2048 diff --git a/arch/powerpc/include/asm/kexec.h b/arch/powerpc/include/asm/kexec.h index 3736d9b332896bb83ba0b9c5c7358e4510766386..6dbffc9817024d684420ea7144d68e66f477d119 100644 --- a/arch/powerpc/include/asm/kexec.h +++ b/arch/powerpc/include/asm/kexec.h @@ -33,12 +33,12 @@ #ifndef __ASSEMBLY__ #include +#include typedef void (*crash_shutdown_t)(void); #ifdef CONFIG_KEXEC -#ifdef __powerpc64__ /* * This function is responsible for capturing register states if coming * via panic or invoking dump using sysrq-trigger. @@ -48,6 +48,7 @@ static inline void crash_setup_regs(struct pt_regs *newregs, { if (oldregs) memcpy(newregs, oldregs, sizeof(*newregs)); +#ifdef __powerpc64__ else { /* FIXME Merge this with xmon_save_regs ?? */ unsigned long tmp1, tmp2; @@ -100,15 +101,11 @@ static inline void crash_setup_regs(struct pt_regs *newregs, : "b" (newregs) : "memory"); } -} #else -/* - * Provide a dummy definition to avoid build failures. Will remain - * empty till crash dump support is enabled. - */ -static inline void crash_setup_regs(struct pt_regs *newregs, - struct pt_regs *oldregs) { } -#endif /* !__powerpc64 __ */ + else + ppc_save_regs(newregs); +#endif /* __powerpc64__ */ +} extern void kexec_smp_wait(void); /* get and clear naca physid, wait for master to copy new code to 0 */ diff --git a/arch/powerpc/include/asm/local.h b/arch/powerpc/include/asm/local.h index 612d8327665351c43b39dcd41e5323178ecc6f60..84b457a3c1bcda476a0c475d2bddf594a134e9bc 100644 --- a/arch/powerpc/include/asm/local.h +++ b/arch/powerpc/include/asm/local.h @@ -67,7 +67,7 @@ static __inline__ long local_inc_return(local_t *l) bne- 1b" : "=&r" (t) : "r" (&(l->a.counter)) - : "cc", "memory"); + : "cc", "xer", "memory"); return t; } @@ -94,7 +94,7 @@ static __inline__ long local_dec_return(local_t *l) bne- 1b" : "=&r" (t) : "r" (&(l->a.counter)) - : "cc", "memory"); + : "cc", "xer", "memory"); return t; } diff --git a/arch/powerpc/include/asm/lppaca.h b/arch/powerpc/include/asm/lppaca.h index 2fe268b10333433ad6b2e40bcf2d90c392c45798..25aaa97facd821954a2a85a53fafe67497082e50 100644 --- a/arch/powerpc/include/asm/lppaca.h +++ b/arch/powerpc/include/asm/lppaca.h @@ -133,7 +133,8 @@ struct lppaca { //============================================================================= // CACHE_LINE_4-5 0x0180 - 0x027F Contains PMC interrupt data //============================================================================= - u8 pmc_save_area[256]; // PMC interrupt Area x00-xFF + u32 page_ins; // CMO Hint - # page ins by OS x00-x04 + u8 pmc_save_area[252]; // PMC interrupt Area x04-xFF } __attribute__((__aligned__(0x400))); extern struct lppaca lppaca[]; diff --git a/arch/powerpc/include/asm/mmu-40x.h b/arch/powerpc/include/asm/mmu-40x.h index 3d108676584c8ef6cf0c4ac7e3cb813939a358a8..776f415a36aa36da64c4d78084514730a16d2c61 100644 --- a/arch/powerpc/include/asm/mmu-40x.h +++ b/arch/powerpc/include/asm/mmu-40x.h @@ -54,8 +54,9 @@ #ifndef __ASSEMBLY__ typedef struct { - unsigned long id; - unsigned long vdso_base; + unsigned int id; + unsigned int active; + unsigned long vdso_base; } mm_context_t; #endif /* !__ASSEMBLY__ */ diff --git a/arch/powerpc/include/asm/mmu-44x.h b/arch/powerpc/include/asm/mmu-44x.h index a825524c981a3965bda27107e53e83b62e7b4c13..8a97cfb08b7e9eaad3a6149ce3285e6ad9507234 100644 --- a/arch/powerpc/include/asm/mmu-44x.h +++ b/arch/powerpc/include/asm/mmu-44x.h @@ -4,6 +4,8 @@ * PPC440 support */ +#include + #define PPC44x_MMUCR_TID 0x000000ff #define PPC44x_MMUCR_STS 0x00010000 @@ -56,8 +58,9 @@ extern unsigned int tlb_44x_hwater; typedef struct { - unsigned long id; - unsigned long vdso_base; + unsigned int id; + unsigned int active; + unsigned long vdso_base; } mm_context_t; #endif /* !__ASSEMBLY__ */ @@ -73,4 +76,19 @@ typedef struct { /* Size of the TLBs used for pinning in lowmem */ #define PPC_PIN_SIZE (1 << 28) /* 256M */ +#if (PAGE_SHIFT == 12) +#define PPC44x_TLBE_SIZE PPC44x_TLB_4K +#elif (PAGE_SHIFT == 14) +#define PPC44x_TLBE_SIZE PPC44x_TLB_16K +#elif (PAGE_SHIFT == 16) +#define PPC44x_TLBE_SIZE PPC44x_TLB_64K +#else +#error "Unsupported PAGE_SIZE" +#endif + +#define PPC44x_PGD_OFF_SHIFT (32 - PGDIR_SHIFT + PGD_T_LOG2) +#define PPC44x_PGD_OFF_MASK_BIT (PGDIR_SHIFT - PGD_T_LOG2) +#define PPC44x_PTE_ADD_SHIFT (32 - PGDIR_SHIFT + PTE_SHIFT + PTE_T_LOG2) +#define PPC44x_PTE_ADD_MASK_BIT (32 - PTE_T_LOG2 - PTE_SHIFT) + #endif /* _ASM_POWERPC_MMU_44X_H_ */ diff --git a/arch/powerpc/include/asm/mmu-8xx.h b/arch/powerpc/include/asm/mmu-8xx.h index 9db877eb88db4f28d1eefce0321add39ce85ca82..07865a357848e66f204f7e9a94da1191eec72cac 100644 --- a/arch/powerpc/include/asm/mmu-8xx.h +++ b/arch/powerpc/include/asm/mmu-8xx.h @@ -137,7 +137,8 @@ #ifndef __ASSEMBLY__ typedef struct { - unsigned long id; + unsigned int id; + unsigned int active; unsigned long vdso_base; } mm_context_t; #endif /* !__ASSEMBLY__ */ diff --git a/arch/powerpc/include/asm/mmu-fsl-booke.h b/arch/powerpc/include/asm/mmu-fsl-booke.h index 925d93cf64d8596f5b376a6b7740cc7193b25a95..3f941c0f7e8eb504dd921e2a89b3f93087fb66ca 100644 --- a/arch/powerpc/include/asm/mmu-fsl-booke.h +++ b/arch/powerpc/include/asm/mmu-fsl-booke.h @@ -40,6 +40,8 @@ #define MAS2_M 0x00000004 #define MAS2_G 0x00000002 #define MAS2_E 0x00000001 +#define MAS2_EPN_MASK(size) (~0 << (2*(size) + 10)) +#define MAS2_VAL(addr, size, flags) ((addr) & MAS2_EPN_MASK(size) | (flags)) #define MAS3_RPN 0xFFFFF000 #define MAS3_U0 0x00000200 @@ -74,8 +76,9 @@ #ifndef __ASSEMBLY__ typedef struct { - unsigned long id; - unsigned long vdso_base; + unsigned int id; + unsigned int active; + unsigned long vdso_base; } mm_context_t; #endif /* !__ASSEMBLY__ */ diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h index 4c0e1b4f975c369e2655b29c8bf660d9b05ac8a6..6e76399113189baaf849676a188127efb46e4e5a 100644 --- a/arch/powerpc/include/asm/mmu.h +++ b/arch/powerpc/include/asm/mmu.h @@ -2,6 +2,63 @@ #define _ASM_POWERPC_MMU_H_ #ifdef __KERNEL__ +#include +#include + +/* + * MMU features bit definitions + */ + +/* + * First half is MMU families + */ +#define MMU_FTR_HPTE_TABLE ASM_CONST(0x00000001) +#define MMU_FTR_TYPE_8xx ASM_CONST(0x00000002) +#define MMU_FTR_TYPE_40x ASM_CONST(0x00000004) +#define MMU_FTR_TYPE_44x ASM_CONST(0x00000008) +#define MMU_FTR_TYPE_FSL_E ASM_CONST(0x00000010) + +/* + * This is individual features + */ + +/* Enable use of high BAT registers */ +#define MMU_FTR_USE_HIGH_BATS ASM_CONST(0x00010000) + +/* Enable >32-bit physical addresses on 32-bit processor, only used + * by CONFIG_6xx currently as BookE supports that from day 1 + */ +#define MMU_FTR_BIG_PHYS ASM_CONST(0x00020000) + +/* Enable use of broadcast TLB invalidations. We don't always set it + * on processors that support it due to other constraints with the + * use of such invalidations + */ +#define MMU_FTR_USE_TLBIVAX_BCAST ASM_CONST(0x00040000) + +/* Enable use of tlbilx invalidate-by-PID variant. + */ +#define MMU_FTR_USE_TLBILX_PID ASM_CONST(0x00080000) + +/* This indicates that the processor cannot handle multiple outstanding + * broadcast tlbivax or tlbsync. This makes the code use a spinlock + * around such invalidate forms. + */ +#define MMU_FTR_LOCK_BCAST_INVAL ASM_CONST(0x00100000) + +#ifndef __ASSEMBLY__ +#include + +static inline int mmu_has_feature(unsigned long feature) +{ + return (cur_cpu_spec->mmu_features & feature); +} + +extern unsigned int __start___mmu_ftr_fixup, __stop___mmu_ftr_fixup; + +#endif /* !__ASSEMBLY__ */ + + #ifdef CONFIG_PPC64 /* 64-bit classic hash table MMU */ # include diff --git a/arch/powerpc/include/asm/mmu_context.h b/arch/powerpc/include/asm/mmu_context.h index 6b993ef452ff8010c6c539f34145621fa6b3c4dd..ab4f19263c4286b199a084ea5dff32259d50820b 100644 --- a/arch/powerpc/include/asm/mmu_context.h +++ b/arch/powerpc/include/asm/mmu_context.h @@ -2,237 +2,26 @@ #define __ASM_POWERPC_MMU_CONTEXT_H #ifdef __KERNEL__ +#include +#include +#include +#include #include #include #include - -#ifndef CONFIG_PPC64 -#include -#include - -/* - * On 32-bit PowerPC 6xx/7xx/7xxx CPUs, we use a set of 16 VSIDs - * (virtual segment identifiers) for each context. Although the - * hardware supports 24-bit VSIDs, and thus >1 million contexts, - * we only use 32,768 of them. That is ample, since there can be - * at most around 30,000 tasks in the system anyway, and it means - * that we can use a bitmap to indicate which contexts are in use. - * Using a bitmap means that we entirely avoid all of the problems - * that we used to have when the context number overflowed, - * particularly on SMP systems. - * -- paulus. - */ - -/* - * This function defines the mapping from contexts to VSIDs (virtual - * segment IDs). We use a skew on both the context and the high 4 bits - * of the 32-bit virtual address (the "effective segment ID") in order - * to spread out the entries in the MMU hash table. Note, if this - * function is changed then arch/ppc/mm/hashtable.S will have to be - * changed to correspond. - */ -#define CTX_TO_VSID(ctx, va) (((ctx) * (897 * 16) + ((va) >> 28) * 0x111) \ - & 0xffffff) - -/* - The MPC8xx has only 16 contexts. We rotate through them on each - task switch. A better way would be to keep track of tasks that - own contexts, and implement an LRU usage. That way very active - tasks don't always have to pay the TLB reload overhead. The - kernel pages are mapped shared, so the kernel can run on behalf - of any task that makes a kernel entry. Shared does not mean they - are not protected, just that the ASID comparison is not performed. - -- Dan - - The IBM4xx has 256 contexts, so we can just rotate through these - as a way of "switching" contexts. If the TID of the TLB is zero, - the PID/TID comparison is disabled, so we can use a TID of zero - to represent all kernel pages as shared among all contexts. - -- Dan - */ - -static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) -{ -} - -#ifdef CONFIG_8xx -#define NO_CONTEXT 16 -#define LAST_CONTEXT 15 -#define FIRST_CONTEXT 0 - -#elif defined(CONFIG_4xx) -#define NO_CONTEXT 256 -#define LAST_CONTEXT 255 -#define FIRST_CONTEXT 1 - -#elif defined(CONFIG_E200) || defined(CONFIG_E500) -#define NO_CONTEXT 256 -#define LAST_CONTEXT 255 -#define FIRST_CONTEXT 1 - -#else - -/* PPC 6xx, 7xx CPUs */ -#define NO_CONTEXT ((unsigned long) -1) -#define LAST_CONTEXT 32767 -#define FIRST_CONTEXT 1 -#endif - -/* - * Set the current MMU context. - * On 32-bit PowerPCs (other than the 8xx embedded chips), this is done by - * loading up the segment registers for the user part of the address space. - * - * Since the PGD is immediately available, it is much faster to simply - * pass this along as a second parameter, which is required for 8xx and - * can be used for debugging on all processors (if you happen to have - * an Abatron). - */ -extern void set_context(unsigned long contextid, pgd_t *pgd); - -/* - * Bitmap of contexts in use. - * The size of this bitmap is LAST_CONTEXT + 1 bits. - */ -extern unsigned long context_map[]; - -/* - * This caches the next context number that we expect to be free. - * Its use is an optimization only, we can't rely on this context - * number to be free, but it usually will be. - */ -extern unsigned long next_mmu_context; - -/* - * If we don't have sufficient contexts to give one to every task - * that could be in the system, we need to be able to steal contexts. - * These variables support that. - */ -#if LAST_CONTEXT < 30000 -#define FEW_CONTEXTS 1 -extern atomic_t nr_free_contexts; -extern struct mm_struct *context_mm[LAST_CONTEXT+1]; -extern void steal_context(void); -#endif - -/* - * Get a new mmu context for the address space described by `mm'. - */ -static inline void get_mmu_context(struct mm_struct *mm) -{ - unsigned long ctx; - - if (mm->context.id != NO_CONTEXT) - return; -#ifdef FEW_CONTEXTS - while (atomic_dec_if_positive(&nr_free_contexts) < 0) - steal_context(); -#endif - ctx = next_mmu_context; - while (test_and_set_bit(ctx, context_map)) { - ctx = find_next_zero_bit(context_map, LAST_CONTEXT+1, ctx); - if (ctx > LAST_CONTEXT) - ctx = 0; - } - next_mmu_context = (ctx + 1) & LAST_CONTEXT; - mm->context.id = ctx; -#ifdef FEW_CONTEXTS - context_mm[ctx] = mm; -#endif -} - -/* - * Set up the context for a new address space. - */ -static inline int init_new_context(struct task_struct *t, struct mm_struct *mm) -{ - mm->context.id = NO_CONTEXT; - return 0; -} - -/* - * We're finished using the context for an address space. - */ -static inline void destroy_context(struct mm_struct *mm) -{ - preempt_disable(); - if (mm->context.id != NO_CONTEXT) { - clear_bit(mm->context.id, context_map); - mm->context.id = NO_CONTEXT; -#ifdef FEW_CONTEXTS - atomic_inc(&nr_free_contexts); -#endif - } - preempt_enable(); -} - -static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, - struct task_struct *tsk) -{ -#ifdef CONFIG_ALTIVEC - if (cpu_has_feature(CPU_FTR_ALTIVEC)) - asm volatile ("dssall;\n" -#ifndef CONFIG_POWER4 - "sync;\n" /* G4 needs a sync here, G5 apparently not */ -#endif - : : ); -#endif /* CONFIG_ALTIVEC */ - - tsk->thread.pgdir = next->pgd; - - /* No need to flush userspace segments if the mm doesnt change */ - if (prev == next) - return; - - /* Setup new userspace context */ - get_mmu_context(next); - set_context(next->context.id, next->pgd); -} - -#define deactivate_mm(tsk,mm) do { } while (0) +#include /* - * After we have set current->mm to a new value, this activates - * the context for the new mm so we see the new mappings. + * Most if the context management is out of line */ -#define activate_mm(active_mm, mm) switch_mm(active_mm, mm, current) - extern void mmu_context_init(void); - - -#else - -#include -#include -#include - -/* - * Copyright (C) 2001 PPC 64 Team, IBM Corp - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -static inline void enter_lazy_tlb(struct mm_struct *mm, - struct task_struct *tsk) -{ -} - -/* - * The proto-VSID space has 2^35 - 1 segments available for user mappings. - * Each segment contains 2^28 bytes. Each context maps 2^44 bytes, - * so we can support 2^19-1 contexts (19 == 35 + 28 - 44). - */ -#define NO_CONTEXT 0 -#define MAX_CONTEXT ((1UL << 19) - 1) - extern int init_new_context(struct task_struct *tsk, struct mm_struct *mm); extern void destroy_context(struct mm_struct *mm); +extern void switch_mmu_context(struct mm_struct *prev, struct mm_struct *next); extern void switch_stab(struct task_struct *tsk, struct mm_struct *mm); extern void switch_slb(struct task_struct *tsk, struct mm_struct *mm); +extern void set_context(unsigned long id, pgd_t *pgd); /* * switch_mm is the entry point called from the architecture independent @@ -241,22 +30,39 @@ extern void switch_slb(struct task_struct *tsk, struct mm_struct *mm); static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk) { - if (!cpu_isset(smp_processor_id(), next->cpu_vm_mask)) - cpu_set(smp_processor_id(), next->cpu_vm_mask); + /* Mark this context has been used on the new CPU */ + cpu_set(smp_processor_id(), next->cpu_vm_mask); + + /* 32-bit keeps track of the current PGDIR in the thread struct */ +#ifdef CONFIG_PPC32 + tsk->thread.pgdir = next->pgd; +#endif /* CONFIG_PPC32 */ - /* No need to flush userspace segments if the mm doesnt change */ + /* Nothing else to do if we aren't actually switching */ if (prev == next) return; + /* We must stop all altivec streams before changing the HW + * context + */ #ifdef CONFIG_ALTIVEC if (cpu_has_feature(CPU_FTR_ALTIVEC)) asm volatile ("dssall"); #endif /* CONFIG_ALTIVEC */ + /* The actual HW switching method differs between the various + * sub architectures. + */ +#ifdef CONFIG_PPC_STD_MMU_64 if (cpu_has_feature(CPU_FTR_SLB)) switch_slb(tsk, next); else switch_stab(tsk, next); +#else + /* Out of line for now */ + switch_mmu_context(prev, next); +#endif + } #define deactivate_mm(tsk,mm) do { } while (0) @@ -274,6 +80,11 @@ static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next) local_irq_restore(flags); } -#endif /* CONFIG_PPC64 */ +/* We don't currently use enter_lazy_tlb() for anything */ +static inline void enter_lazy_tlb(struct mm_struct *mm, + struct task_struct *tsk) +{ +} + #endif /* __KERNEL__ */ #endif /* __ASM_POWERPC_MMU_CONTEXT_H */ diff --git a/arch/powerpc/include/asm/module.h b/arch/powerpc/include/asm/module.h index e5f14b13ccf0ff2c11ef8392b6697750608ca919..08454880a2c047258da91b4968f080f4e38fc4af 100644 --- a/arch/powerpc/include/asm/module.h +++ b/arch/powerpc/include/asm/module.h @@ -34,11 +34,19 @@ struct mod_arch_specific { #ifdef __powerpc64__ unsigned int stubs_section; /* Index of stubs section in module */ unsigned int toc_section; /* What section is the TOC? */ -#else +#ifdef CONFIG_DYNAMIC_FTRACE + unsigned long toc; + unsigned long tramp; +#endif + +#else /* powerpc64 */ /* Indices of PLT sections within module. */ unsigned int core_plt_section; unsigned int init_plt_section; +#ifdef CONFIG_DYNAMIC_FTRACE + unsigned long tramp; #endif +#endif /* powerpc64 */ /* List of BUG addresses, source line numbers and filenames */ struct list_head bug_list; @@ -68,6 +76,12 @@ struct mod_arch_specific { # endif /* MODULE */ #endif +#ifdef CONFIG_DYNAMIC_FTRACE +# ifdef MODULE + asm(".section .ftrace.tramp,\"ax\",@nobits; .align 3; .previous"); +# endif /* MODULE */ +#endif + struct exception_table_entry; void sort_ex_table(struct exception_table_entry *start, diff --git a/arch/powerpc/include/asm/mpc52xx.h b/arch/powerpc/include/asm/mpc52xx.h index 81ef10b6b672455e2ed65d9a05e2a3556d989eef..81a23932a160c7e47aaa4ceb359e591ee7ee5c6f 100644 --- a/arch/powerpc/include/asm/mpc52xx.h +++ b/arch/powerpc/include/asm/mpc52xx.h @@ -239,6 +239,25 @@ struct mpc52xx_cdm { u16 mclken_div_psc6; /* CDM + 0x36 reg13 byte2,3 */ }; +/* Interrupt controller Register set */ +struct mpc52xx_intr { + u32 per_mask; /* INTR + 0x00 */ + u32 per_pri1; /* INTR + 0x04 */ + u32 per_pri2; /* INTR + 0x08 */ + u32 per_pri3; /* INTR + 0x0c */ + u32 ctrl; /* INTR + 0x10 */ + u32 main_mask; /* INTR + 0x14 */ + u32 main_pri1; /* INTR + 0x18 */ + u32 main_pri2; /* INTR + 0x1c */ + u32 reserved1; /* INTR + 0x20 */ + u32 enc_status; /* INTR + 0x24 */ + u32 crit_status; /* INTR + 0x28 */ + u32 main_status; /* INTR + 0x2c */ + u32 per_status; /* INTR + 0x30 */ + u32 reserved2; /* INTR + 0x34 */ + u32 per_error; /* INTR + 0x38 */ +}; + #endif /* __ASSEMBLY__ */ diff --git a/arch/powerpc/include/asm/mpc52xx_psc.h b/arch/powerpc/include/asm/mpc52xx_psc.h index 8917ed63056593377498abaf721e3f33ecaa3b1e..a218da6bec7c5ea69091196d363b9cb7c51158b0 100644 --- a/arch/powerpc/include/asm/mpc52xx_psc.h +++ b/arch/powerpc/include/asm/mpc52xx_psc.h @@ -68,12 +68,20 @@ #define MPC52xx_PSC_IMR_ORERR 0x1000 #define MPC52xx_PSC_IMR_IPC 0x8000 -/* PSC input port change bit */ +/* PSC input port change bits */ #define MPC52xx_PSC_CTS 0x01 #define MPC52xx_PSC_DCD 0x02 #define MPC52xx_PSC_D_CTS 0x10 #define MPC52xx_PSC_D_DCD 0x20 +/* PSC acr bits */ +#define MPC52xx_PSC_IEC_CTS 0x01 +#define MPC52xx_PSC_IEC_DCD 0x02 + +/* PSC output port bits */ +#define MPC52xx_PSC_OP_RTS 0x01 +#define MPC52xx_PSC_OP_RES 0x02 + /* PSC mode fields */ #define MPC52xx_PSC_MODE_5_BITS 0x00 #define MPC52xx_PSC_MODE_6_BITS 0x01 @@ -91,6 +99,7 @@ #define MPC52xx_PSC_MODE_ONE_STOP_5_BITS 0x00 #define MPC52xx_PSC_MODE_ONE_STOP 0x07 #define MPC52xx_PSC_MODE_TWO_STOP 0x0f +#define MPC52xx_PSC_MODE_TXCTS 0x10 #define MPC52xx_PSC_RFNUM_MASK 0x01ff diff --git a/arch/powerpc/include/asm/mutex.h b/arch/powerpc/include/asm/mutex.h index 458c1f7fbc1808d48982aa0c5fe89bfe3df2098c..dabc01c727b86efb4b35c1d8f30e58e0ce95ede4 100644 --- a/arch/powerpc/include/asm/mutex.h +++ b/arch/powerpc/include/asm/mutex.h @@ -1,9 +1,134 @@ /* - * Pull in the generic implementation for the mutex fastpath. + * Optimised mutex implementation of include/asm-generic/mutex-dec.h algorithm + */ +#ifndef _ASM_POWERPC_MUTEX_H +#define _ASM_POWERPC_MUTEX_H + +static inline int __mutex_cmpxchg_lock(atomic_t *v, int old, int new) +{ + int t; + + __asm__ __volatile__ ( +"1: lwarx %0,0,%1 # mutex trylock\n\ + cmpw 0,%0,%2\n\ + bne- 2f\n" + PPC405_ERR77(0,%1) +" stwcx. %3,0,%1\n\ + bne- 1b" + ISYNC_ON_SMP + "\n\ +2:" + : "=&r" (t) + : "r" (&v->counter), "r" (old), "r" (new) + : "cc", "memory"); + + return t; +} + +static inline int __mutex_dec_return_lock(atomic_t *v) +{ + int t; + + __asm__ __volatile__( +"1: lwarx %0,0,%1 # mutex lock\n\ + addic %0,%0,-1\n" + PPC405_ERR77(0,%1) +" stwcx. %0,0,%1\n\ + bne- 1b" + ISYNC_ON_SMP + : "=&r" (t) + : "r" (&v->counter) + : "cc", "memory"); + + return t; +} + +static inline int __mutex_inc_return_unlock(atomic_t *v) +{ + int t; + + __asm__ __volatile__( + LWSYNC_ON_SMP +"1: lwarx %0,0,%1 # mutex unlock\n\ + addic %0,%0,1\n" + PPC405_ERR77(0,%1) +" stwcx. %0,0,%1 \n\ + bne- 1b" + : "=&r" (t) + : "r" (&v->counter) + : "cc", "memory"); + + return t; +} + +/** + * __mutex_fastpath_lock - try to take the lock by moving the count + * from 1 to a 0 value + * @count: pointer of type atomic_t + * @fail_fn: function to call if the original value was not 1 + * + * Change the count from 1 to a value lower than 1, and call if + * it wasn't 1 originally. This function MUST leave the value lower than + * 1 even when the "1" assertion wasn't true. + */ +static inline void +__mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *)) +{ + if (unlikely(__mutex_dec_return_lock(count) < 0)) + fail_fn(count); +} + +/** + * __mutex_fastpath_lock_retval - try to take the lock by moving the count + * from 1 to a 0 value + * @count: pointer of type atomic_t + * @fail_fn: function to call if the original value was not 1 + * + * Change the count from 1 to a value lower than 1, and call if + * it wasn't 1 originally. This function returns 0 if the fastpath succeeds, + * or anything the slow path function returns. + */ +static inline int +__mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *)) +{ + if (unlikely(__mutex_dec_return_lock(count) < 0)) + return fail_fn(count); + return 0; +} + +/** + * __mutex_fastpath_unlock - try to promote the count from 0 to 1 + * @count: pointer of type atomic_t + * @fail_fn: function to call if the original value was not 0 + * + * Try to promote the count from 0 to 1. If it wasn't 0, call . + * In the failure case, this function is allowed to either set the value to + * 1, or to set it to a value lower than 1. + */ +static inline void +__mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *)) +{ + if (unlikely(__mutex_inc_return_unlock(count) <= 0)) + fail_fn(count); +} + +#define __mutex_slowpath_needs_to_unlock() 1 + +/** + * __mutex_fastpath_trylock - try to acquire the mutex, without waiting + * + * @count: pointer of type atomic_t + * @fail_fn: fallback function * - * TODO: implement optimized primitives instead, or leave the generic - * implementation in place, or pick the atomic_xchg() based generic - * implementation. (see asm-generic/mutex-xchg.h for details) + * Change the count from 1 to 0, and return 1 (success), or if the count + * was not 1, then return 0 (failure). */ +static inline int +__mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *)) +{ + if (likely(__mutex_cmpxchg_lock(count, 1, 0) == 1)) + return 1; + return 0; +} -#include +#endif diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h index c0b8d4a29a91cd34c7e10bb45608d7e9fe83fee0..197d569f5bd3c44a1f3718f0714e165b72a453de 100644 --- a/arch/powerpc/include/asm/page.h +++ b/arch/powerpc/include/asm/page.h @@ -19,12 +19,15 @@ #include /* - * On PPC32 page size is 4K. For PPC64 we support either 4K or 64K software + * On regular PPC32 page size is 4K (but we support 4K/16K/64K pages + * on PPC44x). For PPC64 we support either 4K or 64K software * page size. When using 64K pages however, whether we are really supporting * 64K pages in HW or not is irrelevant to those definitions. */ -#ifdef CONFIG_PPC_64K_PAGES +#if defined(CONFIG_PPC_64K_PAGES) #define PAGE_SHIFT 16 +#elif defined(CONFIG_PPC_16K_PAGES) +#define PAGE_SHIFT 14 #else #define PAGE_SHIFT 12 #endif @@ -151,7 +154,7 @@ typedef struct { pte_basic_t pte; } pte_t; /* 64k pages additionally define a bigger "real PTE" type that gathers * the "second half" part of the PTE for pseudo 64k pages */ -#ifdef CONFIG_PPC_64K_PAGES +#if defined(CONFIG_PPC_64K_PAGES) && defined(CONFIG_PPC_STD_MMU_64) typedef struct { pte_t pte; unsigned long hidx; } real_pte_t; #else typedef struct { pte_t pte; } real_pte_t; @@ -191,10 +194,10 @@ typedef pte_basic_t pte_t; #define pte_val(x) (x) #define __pte(x) (x) -#ifdef CONFIG_PPC_64K_PAGES +#if defined(CONFIG_PPC_64K_PAGES) && defined(CONFIG_PPC_STD_MMU_64) typedef struct { pte_t pte; unsigned long hidx; } real_pte_t; #else -typedef unsigned long real_pte_t; +typedef pte_t real_pte_t; #endif diff --git a/arch/powerpc/include/asm/page_32.h b/arch/powerpc/include/asm/page_32.h index d77072a32cc68b2553b1e329542b1f4925656c57..1458d95003814dbc591d6e0d5b124485488218c9 100644 --- a/arch/powerpc/include/asm/page_32.h +++ b/arch/powerpc/include/asm/page_32.h @@ -19,6 +19,8 @@ #define PTE_FLAGS_OFFSET 0 #endif +#define PTE_SHIFT (PAGE_SHIFT - PTE_T_LOG2) /* full page */ + #ifndef __ASSEMBLY__ /* * The basic type of a PTE - 64 bits for those CPUs with > 32 bit @@ -26,10 +28,8 @@ */ #ifdef CONFIG_PTE_64BIT typedef unsigned long long pte_basic_t; -#define PTE_SHIFT (PAGE_SHIFT - 3) /* 512 ptes per page */ #else typedef unsigned long pte_basic_t; -#define PTE_SHIFT (PAGE_SHIFT - 2) /* 1024 ptes per page */ #endif struct page; @@ -39,6 +39,9 @@ extern void copy_page(void *to, void *from); #include +#define PGD_T_LOG2 (__builtin_ffs(sizeof(pgd_t)) - 1) +#define PTE_T_LOG2 (__builtin_ffs(sizeof(pte_t)) - 1) + #endif /* __ASSEMBLY__ */ #endif /* _ASM_POWERPC_PAGE_32_H */ diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h index 9047af7baa697afad42e89b19f2cfdd893ad7430..84007afabdb52a307d0f0a34fb7c8877091eb79a 100644 --- a/arch/powerpc/include/asm/pci-bridge.h +++ b/arch/powerpc/include/asm/pci-bridge.h @@ -13,7 +13,6 @@ struct device_node; -extern unsigned int ppc_pci_flags; enum { /* Force re-assigning all resources (ignore firmware * setup completely) @@ -36,6 +35,31 @@ enum { /* ... except for domain 0 */ PPC_PCI_COMPAT_DOMAIN_0 = 0x00000020, }; +#ifdef CONFIG_PCI +extern unsigned int ppc_pci_flags; + +static inline void ppc_pci_set_flags(int flags) +{ + ppc_pci_flags = flags; +} + +static inline void ppc_pci_add_flags(int flags) +{ + ppc_pci_flags |= flags; +} + +static inline int ppc_pci_has_flag(int flag) +{ + return (ppc_pci_flags & flag); +} +#else +static inline void ppc_pci_set_flags(int flags) { } +static inline void ppc_pci_add_flags(int flags) { } +static inline int ppc_pci_has_flag(int flag) +{ + return 0; +} +#endif /* @@ -241,9 +265,6 @@ extern void pcibios_remove_pci_devices(struct pci_bus *bus); /** Discover new pci devices under this bus, and add them */ extern void pcibios_add_pci_devices(struct pci_bus *bus); -extern void pcibios_fixup_new_pci_devices(struct pci_bus *bus); - -extern int pcibios_remove_root_bus(struct pci_controller *phb); static inline struct pci_controller *pci_bus_to_host(const struct pci_bus *bus) { @@ -290,6 +311,7 @@ extern void pci_process_bridge_OF_ranges(struct pci_controller *hose, /* Allocate & free a PCI host bridge structure */ extern struct pci_controller *pcibios_alloc_controller(struct device_node *dev); extern void pcibios_free_controller(struct pci_controller *phb); +extern void pcibios_setup_phb_resources(struct pci_controller *hose); #ifdef CONFIG_PCI extern unsigned long pci_address_to_pio(phys_addr_t address); diff --git a/arch/powerpc/include/asm/pci.h b/arch/powerpc/include/asm/pci.h index 57a2a494886befada20215df66518bfe37ec6e17..3548159a1beb98b55ef6c7e39985da655f85920d 100644 --- a/arch/powerpc/include/asm/pci.h +++ b/arch/powerpc/include/asm/pci.h @@ -38,8 +38,8 @@ struct pci_dev; * Set this to 1 if you want the kernel to re-assign all PCI * bus numbers (don't do that on ppc64 yet !) */ -#define pcibios_assign_all_busses() (ppc_pci_flags & \ - PPC_PCI_REASSIGN_ALL_BUS) +#define pcibios_assign_all_busses() \ + (ppc_pci_has_flag(PPC_PCI_REASSIGN_ALL_BUS)) #define pcibios_scan_all_fns(a, b) 0 static inline void pcibios_set_master(struct pci_dev *dev) @@ -204,15 +204,14 @@ static inline struct resource *pcibios_select_root(struct pci_dev *pdev, return root; } -extern void pcibios_setup_new_device(struct pci_dev *dev); - extern void pcibios_claim_one_bus(struct pci_bus *b); -extern void pcibios_allocate_bus_resources(struct pci_bus *bus); +extern void pcibios_finish_adding_to_bus(struct pci_bus *bus); extern void pcibios_resource_survey(void); extern struct pci_controller *init_phb_dynamic(struct device_node *dn); +extern int remove_phb_dynamic(struct pci_controller *phb); extern struct pci_dev *of_create_pci_dev(struct device_node *node, struct pci_bus *bus, int devfn); @@ -221,6 +220,7 @@ extern void of_scan_pci_bridge(struct device_node *node, struct pci_dev *dev); extern void of_scan_bus(struct device_node *node, struct pci_bus *bus); +extern void of_rescan_bus(struct device_node *node, struct pci_bus *bus); extern int pci_read_irq_line(struct pci_dev *dev); @@ -235,9 +235,8 @@ extern void pci_resource_to_user(const struct pci_dev *dev, int bar, const struct resource *rsrc, resource_size_t *start, resource_size_t *end); -extern void pcibios_do_bus_setup(struct pci_bus *bus); -extern void pcibios_fixup_of_probed_bus(struct pci_bus *bus); - +extern void pcibios_setup_bus_devices(struct pci_bus *bus); +extern void pcibios_setup_bus_self(struct pci_bus *bus); #endif /* __KERNEL__ */ #endif /* __ASM_POWERPC_PCI_H */ diff --git a/arch/powerpc/include/asm/pgalloc-32.h b/arch/powerpc/include/asm/pgalloc-32.h index 58c07147b3ea445c17851c8cb5ab8489a6432805..0815eb40acae214b8947a4da26d565bfaf4fb8a7 100644 --- a/arch/powerpc/include/asm/pgalloc-32.h +++ b/arch/powerpc/include/asm/pgalloc-32.h @@ -3,6 +3,8 @@ #include +#define PTE_NONCACHE_NUM 0 /* dummy for now to share code w/ppc64 */ + extern void __bad_pte(pmd_t *pmd); extern pgd_t *pgd_alloc(struct mm_struct *mm); @@ -33,10 +35,13 @@ extern void pgd_free(struct mm_struct *mm, pgd_t *pgd); extern pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr); extern pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long addr); -extern void pte_free_kernel(struct mm_struct *mm, pte_t *pte); -extern void pte_free(struct mm_struct *mm, pgtable_t pte); -#define __pte_free_tlb(tlb, pte) pte_free((tlb)->mm, (pte)) +static inline void pgtable_free(pgtable_free_t pgf) +{ + void *p = (void *)(pgf.val & ~PGF_CACHENUM_MASK); + + free_page((unsigned long)p); +} #define check_pgt_cache() do { } while (0) diff --git a/arch/powerpc/include/asm/pgalloc-64.h b/arch/powerpc/include/asm/pgalloc-64.h index 812a1d8f35cbc58f21d9096b3ef00c8678d930f9..afda2bdd860f8bc8eb20dbb915701fface743ce6 100644 --- a/arch/powerpc/include/asm/pgalloc-64.h +++ b/arch/powerpc/include/asm/pgalloc-64.h @@ -7,7 +7,6 @@ * 2 of the License, or (at your option) any later version. */ -#include #include #include #include @@ -108,31 +107,6 @@ static inline pgtable_t pte_alloc_one(struct mm_struct *mm, return page; } -static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte) -{ - free_page((unsigned long)pte); -} - -static inline void pte_free(struct mm_struct *mm, pgtable_t ptepage) -{ - pgtable_page_dtor(ptepage); - __free_page(ptepage); -} - -#define PGF_CACHENUM_MASK 0x7 - -typedef struct pgtable_free { - unsigned long val; -} pgtable_free_t; - -static inline pgtable_free_t pgtable_free_cache(void *p, int cachenum, - unsigned long mask) -{ - BUG_ON(cachenum > PGF_CACHENUM_MASK); - - return (pgtable_free_t){.val = ((unsigned long) p & ~mask) | cachenum}; -} - static inline void pgtable_free(pgtable_free_t pgf) { void *p = (void *)(pgf.val & ~PGF_CACHENUM_MASK); @@ -144,14 +118,6 @@ static inline void pgtable_free(pgtable_free_t pgf) kmem_cache_free(pgtable_cache[cachenum], p); } -extern void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf); - -#define __pte_free_tlb(tlb,ptepage) \ -do { \ - pgtable_page_dtor(ptepage); \ - pgtable_free_tlb(tlb, pgtable_free_cache(page_address(ptepage), \ - PTE_NONCACHE_NUM, PTE_TABLE_SIZE-1)); \ -} while (0) #define __pmd_free_tlb(tlb, pmd) \ pgtable_free_tlb(tlb, pgtable_free_cache(pmd, \ PMD_CACHE_NUM, PMD_TABLE_SIZE-1)) diff --git a/arch/powerpc/include/asm/pgalloc.h b/arch/powerpc/include/asm/pgalloc.h index b4505ed0f0f26843c6432a25cec991f16ecd0130..5d8480265a77561bfa48cb2b82eb2fca9b4a4fd2 100644 --- a/arch/powerpc/include/asm/pgalloc.h +++ b/arch/powerpc/include/asm/pgalloc.h @@ -2,11 +2,52 @@ #define _ASM_POWERPC_PGALLOC_H #ifdef __KERNEL__ +#include + +static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte) +{ + free_page((unsigned long)pte); +} + +static inline void pte_free(struct mm_struct *mm, pgtable_t ptepage) +{ + pgtable_page_dtor(ptepage); + __free_page(ptepage); +} + +typedef struct pgtable_free { + unsigned long val; +} pgtable_free_t; + +#define PGF_CACHENUM_MASK 0x7 + +static inline pgtable_free_t pgtable_free_cache(void *p, int cachenum, + unsigned long mask) +{ + BUG_ON(cachenum > PGF_CACHENUM_MASK); + + return (pgtable_free_t){.val = ((unsigned long) p & ~mask) | cachenum}; +} + #ifdef CONFIG_PPC64 #include #else #include #endif +extern void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf); + +#ifdef CONFIG_SMP +#define __pte_free_tlb(tlb,ptepage) \ +do { \ + pgtable_page_dtor(ptepage); \ + pgtable_free_tlb(tlb, pgtable_free_cache(page_address(ptepage), \ + PTE_NONCACHE_NUM, PTE_TABLE_SIZE-1)); \ +} while (0) +#else +#define __pte_free_tlb(tlb, pte) pte_free((tlb)->mm, (pte)) +#endif + + #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_PGALLOC_H */ diff --git a/arch/powerpc/include/asm/pgtable-ppc32.h b/arch/powerpc/include/asm/pgtable-ppc32.h index 6ab7c67cb5ab6355ba453e4832ad55bcdb03ec85..f69a4d97772904ea5c42beda4748a8d4cc085202 100644 --- a/arch/powerpc/include/asm/pgtable-ppc32.h +++ b/arch/powerpc/include/asm/pgtable-ppc32.h @@ -228,9 +228,10 @@ extern int icache_44x_need_flush; * - FILE *must* be in the bottom three bits because swap cache * entries use the top 29 bits for TLB2. * - * - CACHE COHERENT bit (M) has no effect on PPC440 core, because it - * doesn't support SMP. So we can use this as software bit, like - * DIRTY. + * - CACHE COHERENT bit (M) has no effect on original PPC440 cores, + * because it doesn't support SMP. However, some later 460 variants + * have -some- form of SMP support and so I keep the bit there for + * future use * * With the PPC 44x Linux implementation, the 0-11th LSBs of the PTE are used * for memory protection related functions (see PTE structure in @@ -436,20 +437,23 @@ extern int icache_44x_need_flush; _PAGE_USER | _PAGE_ACCESSED | \ _PAGE_RW | _PAGE_HWWRITE | _PAGE_DIRTY | \ _PAGE_EXEC | _PAGE_HWEXEC) + /* - * Note: the _PAGE_COHERENT bit automatically gets set in the hardware - * PTE if CONFIG_SMP is defined (hash_page does this); there is no need - * to have it in the Linux PTE, and in fact the bit could be reused for - * another purpose. -- paulus. + * We define 2 sets of base prot bits, one for basic pages (ie, + * cacheable kernel and user pages) and one for non cacheable + * pages. We always set _PAGE_COHERENT when SMP is enabled or + * the processor might need it for DMA coherency. */ - -#ifdef CONFIG_44x -#define _PAGE_BASE (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_GUARDED) +#if defined(CONFIG_SMP) || defined(CONFIG_PPC_STD_MMU) +#define _PAGE_BASE (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_COHERENT) #else #define _PAGE_BASE (_PAGE_PRESENT | _PAGE_ACCESSED) #endif +#define _PAGE_BASE_NC (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_NO_CACHE) + #define _PAGE_WRENABLE (_PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE) #define _PAGE_KERNEL (_PAGE_BASE | _PAGE_SHARED | _PAGE_WRENABLE) +#define _PAGE_KERNEL_NC (_PAGE_BASE_NC | _PAGE_SHARED | _PAGE_WRENABLE) #ifdef CONFIG_PPC_STD_MMU /* On standard PPC MMU, no user access implies kernel read/write access, @@ -459,7 +463,7 @@ extern int icache_44x_need_flush; #define _PAGE_KERNEL_RO (_PAGE_BASE | _PAGE_SHARED) #endif -#define _PAGE_IO (_PAGE_KERNEL | _PAGE_NO_CACHE | _PAGE_GUARDED) +#define _PAGE_IO (_PAGE_KERNEL_NC | _PAGE_GUARDED) #define _PAGE_RAM (_PAGE_KERNEL | _PAGE_HWEXEC) #if defined(CONFIG_KGDB) || defined(CONFIG_XMON) || defined(CONFIG_BDI_SWITCH) ||\ @@ -552,9 +556,6 @@ static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; } static inline int pte_special(pte_t pte) { return pte_val(pte) & _PAGE_SPECIAL; } -static inline void pte_uncache(pte_t pte) { pte_val(pte) |= _PAGE_NO_CACHE; } -static inline void pte_cache(pte_t pte) { pte_val(pte) &= ~_PAGE_NO_CACHE; } - static inline pte_t pte_wrprotect(pte_t pte) { pte_val(pte) &= ~(_PAGE_RW | _PAGE_HWWRITE); return pte; } static inline pte_t pte_mkclean(pte_t pte) { @@ -693,10 +694,11 @@ static inline void __set_pte_at(struct mm_struct *mm, unsigned long addr, #endif } + static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte) { -#if defined(CONFIG_PTE_64BIT) && defined(CONFIG_SMP) +#if defined(CONFIG_PTE_64BIT) && defined(CONFIG_SMP) && defined(CONFIG_DEBUG_VM) WARN_ON(pte_present(*ptep)); #endif __set_pte_at(mm, addr, ptep, pte); @@ -760,16 +762,6 @@ static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry, int dirty) __changed; \ }) -/* - * Macro to mark a page protection value as "uncacheable". - */ -#define pgprot_noncached(prot) (__pgprot(pgprot_val(prot) | _PAGE_NO_CACHE | _PAGE_GUARDED)) - -struct file; -extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, - unsigned long size, pgprot_t vma_prot); -#define __HAVE_PHYS_MEM_ACCESS_PROT - #define __HAVE_ARCH_PTE_SAME #define pte_same(A,B) (((pte_val(A) ^ pte_val(B)) & ~_PAGE_HASHPTE) == 0) diff --git a/arch/powerpc/include/asm/pgtable-ppc64.h b/arch/powerpc/include/asm/pgtable-ppc64.h index 4c0a8c62859d0f6d1560c2b575ecc85cfc219831..b0f18be81d9fbde440a17ccf52e785cfb3b7a408 100644 --- a/arch/powerpc/include/asm/pgtable-ppc64.h +++ b/arch/powerpc/include/asm/pgtable-ppc64.h @@ -100,7 +100,7 @@ #define _PAGE_WRENABLE (_PAGE_RW | _PAGE_DIRTY) -/* __pgprot defined in arch/powerpc/incliude/asm/page.h */ +/* __pgprot defined in arch/powerpc/include/asm/page.h */ #define PAGE_NONE __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED) #define PAGE_SHARED __pgprot(_PAGE_BASE | _PAGE_RW | _PAGE_USER) @@ -245,9 +245,6 @@ static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED;} static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE;} static inline int pte_special(pte_t pte) { return pte_val(pte) & _PAGE_SPECIAL; } -static inline void pte_uncache(pte_t pte) { pte_val(pte) |= _PAGE_NO_CACHE; } -static inline void pte_cache(pte_t pte) { pte_val(pte) &= ~_PAGE_NO_CACHE; } - static inline pte_t pte_wrprotect(pte_t pte) { pte_val(pte) &= ~(_PAGE_RW); return pte; } static inline pte_t pte_mkclean(pte_t pte) { @@ -405,16 +402,6 @@ static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry, int dirty) __changed; \ }) -/* - * Macro to mark a page protection value as "uncacheable". - */ -#define pgprot_noncached(prot) (__pgprot(pgprot_val(prot) | _PAGE_NO_CACHE | _PAGE_GUARDED)) - -struct file; -extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, - unsigned long size, pgprot_t vma_prot); -#define __HAVE_PHYS_MEM_ACCESS_PROT - #define __HAVE_ARCH_PTE_SAME #define pte_same(A,B) (((pte_val(A) ^ pte_val(B)) & ~_PAGE_HPTEFLAGS) == 0) diff --git a/arch/powerpc/include/asm/pgtable.h b/arch/powerpc/include/asm/pgtable.h index dbb8ca172e445461a8c61bcad3a994bf62276f96..07f55e6016962c4af3c9acc34fd9b54f04f44a8b 100644 --- a/arch/powerpc/include/asm/pgtable.h +++ b/arch/powerpc/include/asm/pgtable.h @@ -16,6 +16,32 @@ struct mm_struct; #endif #ifndef __ASSEMBLY__ + +/* + * Macro to mark a page protection value as "uncacheable". + */ + +#define _PAGE_CACHE_CTL (_PAGE_COHERENT | _PAGE_GUARDED | _PAGE_NO_CACHE | \ + _PAGE_WRITETHRU) + +#define pgprot_noncached(prot) (__pgprot((pgprot_val(prot) & ~_PAGE_CACHE_CTL) | \ + _PAGE_NO_CACHE | _PAGE_GUARDED)) + +#define pgprot_noncached_wc(prot) (__pgprot((pgprot_val(prot) & ~_PAGE_CACHE_CTL) | \ + _PAGE_NO_CACHE)) + +#define pgprot_cached(prot) (__pgprot((pgprot_val(prot) & ~_PAGE_CACHE_CTL) | \ + _PAGE_COHERENT)) + +#define pgprot_cached_wthru(prot) (__pgprot((pgprot_val(prot) & ~_PAGE_CACHE_CTL) | \ + _PAGE_COHERENT | _PAGE_WRITETHRU)) + + +struct file; +extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, + unsigned long size, pgprot_t vma_prot); +#define __HAVE_PHYS_MEM_ACCESS_PROT + /* * ZERO_PAGE is a global shared page that is always zero: used * for zero-mapped memory areas etc.. diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h index c4a029ccb4d31d5273cc6e43fc381e23ff6f9c08..1a0d628eb114bc0f1a6a930ee1a171c91c1eae06 100644 --- a/arch/powerpc/include/asm/ppc_asm.h +++ b/arch/powerpc/include/asm/ppc_asm.h @@ -425,14 +425,14 @@ END_FTR_SECTION_IFCLR(CPU_FTR_601) #define fromreal(rd) tovirt(rd,rd) #define tophys(rd,rs) \ -0: addis rd,rs,-KERNELBASE@h; \ +0: addis rd,rs,-PAGE_OFFSET@h; \ .section ".vtop_fixup","aw"; \ .align 1; \ .long 0b; \ .previous #define tovirt(rd,rs) \ -0: addis rd,rs,KERNELBASE@h; \ +0: addis rd,rs,PAGE_OFFSET@h; \ .section ".ptov_fixup","aw"; \ .align 1; \ .long 0b; \ diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h index 101ed87f7d844d832a7d37a41d91739ed8f0aeb1..d3466490104a557de496a0c531430948384e6264 100644 --- a/arch/powerpc/include/asm/processor.h +++ b/arch/powerpc/include/asm/processor.h @@ -69,8 +69,6 @@ extern int _prep_type; #ifdef __KERNEL__ -extern int have_of; - struct task_struct; void start_thread(struct pt_regs *regs, unsigned long fdptr, unsigned long sp); void release_thread(struct task_struct *); @@ -207,6 +205,11 @@ struct thread_struct { #define INIT_SP_LIMIT \ (_ALIGN_UP(sizeof(init_thread_info), 16) + (unsigned long) &init_stack) +#ifdef CONFIG_SPE +#define SPEFSCR_INIT .spefscr = SPEFSCR_FINVE | SPEFSCR_FDBZE | SPEFSCR_FUNFE | SPEFSCR_FOVFE, +#else +#define SPEFSCR_INIT +#endif #ifdef CONFIG_PPC32 #define INIT_THREAD { \ @@ -215,6 +218,7 @@ struct thread_struct { .fs = KERNEL_DS, \ .pgdir = swapper_pg_dir, \ .fpexc_mode = MSR_FE0 | MSR_FE1, \ + SPEFSCR_INIT \ } #else #define INIT_THREAD { \ diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h index eb3bd2e1c7f6a6491fda0583b55befd012298eab..6ff04185d2aad679e52d4449fafd0271a101595b 100644 --- a/arch/powerpc/include/asm/prom.h +++ b/arch/powerpc/include/asm/prom.h @@ -253,6 +253,9 @@ extern void kdump_move_device_tree(void); /* CPU OF node matching */ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread); +/* cache lookup */ +struct device_node *of_find_next_cache_node(struct device_node *np); + /* Get the MAC address */ extern const void *of_get_mac_address(struct device_node *np); diff --git a/arch/powerpc/include/asm/ps3.h b/arch/powerpc/include/asm/ps3.h index f9e34c493cbbcb3764a7f584296ca5809cfa60a9..cff30c0ef1fffa12d29c1497cefa4150eabe3894 100644 --- a/arch/powerpc/include/asm/ps3.h +++ b/arch/powerpc/include/asm/ps3.h @@ -305,30 +305,34 @@ static inline const char* ps3_result(int result) /* system bus routines */ enum ps3_match_id { - PS3_MATCH_ID_EHCI = 1, - PS3_MATCH_ID_OHCI = 2, - PS3_MATCH_ID_GELIC = 3, - PS3_MATCH_ID_AV_SETTINGS = 4, - PS3_MATCH_ID_SYSTEM_MANAGER = 5, - PS3_MATCH_ID_STOR_DISK = 6, - PS3_MATCH_ID_STOR_ROM = 7, - PS3_MATCH_ID_STOR_FLASH = 8, - PS3_MATCH_ID_SOUND = 9, - PS3_MATCH_ID_GRAPHICS = 10, - PS3_MATCH_ID_LPM = 11, + PS3_MATCH_ID_EHCI = 1, + PS3_MATCH_ID_OHCI = 2, + PS3_MATCH_ID_GELIC = 3, + PS3_MATCH_ID_AV_SETTINGS = 4, + PS3_MATCH_ID_SYSTEM_MANAGER = 5, + PS3_MATCH_ID_STOR_DISK = 6, + PS3_MATCH_ID_STOR_ROM = 7, + PS3_MATCH_ID_STOR_FLASH = 8, + PS3_MATCH_ID_SOUND = 9, + PS3_MATCH_ID_GPU = 10, + PS3_MATCH_ID_LPM = 11, }; -#define PS3_MODULE_ALIAS_EHCI "ps3:1" -#define PS3_MODULE_ALIAS_OHCI "ps3:2" -#define PS3_MODULE_ALIAS_GELIC "ps3:3" -#define PS3_MODULE_ALIAS_AV_SETTINGS "ps3:4" -#define PS3_MODULE_ALIAS_SYSTEM_MANAGER "ps3:5" -#define PS3_MODULE_ALIAS_STOR_DISK "ps3:6" -#define PS3_MODULE_ALIAS_STOR_ROM "ps3:7" -#define PS3_MODULE_ALIAS_STOR_FLASH "ps3:8" -#define PS3_MODULE_ALIAS_SOUND "ps3:9" -#define PS3_MODULE_ALIAS_GRAPHICS "ps3:10" -#define PS3_MODULE_ALIAS_LPM "ps3:11" +enum ps3_match_sub_id { + PS3_MATCH_SUB_ID_GPU_FB = 1, +}; + +#define PS3_MODULE_ALIAS_EHCI "ps3:1:0" +#define PS3_MODULE_ALIAS_OHCI "ps3:2:0" +#define PS3_MODULE_ALIAS_GELIC "ps3:3:0" +#define PS3_MODULE_ALIAS_AV_SETTINGS "ps3:4:0" +#define PS3_MODULE_ALIAS_SYSTEM_MANAGER "ps3:5:0" +#define PS3_MODULE_ALIAS_STOR_DISK "ps3:6:0" +#define PS3_MODULE_ALIAS_STOR_ROM "ps3:7:0" +#define PS3_MODULE_ALIAS_STOR_FLASH "ps3:8:0" +#define PS3_MODULE_ALIAS_SOUND "ps3:9:0" +#define PS3_MODULE_ALIAS_GPU_FB "ps3:10:1" +#define PS3_MODULE_ALIAS_LPM "ps3:11:0" enum ps3_system_bus_device_type { PS3_DEVICE_TYPE_IOC0 = 1, @@ -337,11 +341,6 @@ enum ps3_system_bus_device_type { PS3_DEVICE_TYPE_LPM, }; -enum ps3_match_sub_id { - /* for PS3_MATCH_ID_GRAPHICS */ - PS3_MATCH_SUB_ID_FB = 1, -}; - /** * struct ps3_system_bus_device - a device on the system bus */ @@ -516,4 +515,7 @@ void ps3_sync_irq(int node); u32 ps3_get_hw_thread_id(int cpu); u64 ps3_get_spe_id(void *arg); +/* mutex synchronizing GPU accesses and video mode changes */ +extern struct mutex ps3_gpu_mutex; + #endif diff --git a/arch/powerpc/include/asm/ps3av.h b/arch/powerpc/include/asm/ps3av.h index 5aa22cffdbd658d02c616ba822e3071ac642e3ac..cd24ac16660a2d595f7679694a7e800c92c2a7f3 100644 --- a/arch/powerpc/include/asm/ps3av.h +++ b/arch/powerpc/include/asm/ps3av.h @@ -740,8 +740,4 @@ extern int ps3av_audio_mute(int); extern int ps3av_audio_mute_analog(int); extern int ps3av_dev_open(void); extern int ps3av_dev_close(void); -extern void ps3av_register_flip_ctl(void (*flip_ctl)(int on, void *data), - void *flip_data); -extern void ps3av_flip_ctl(int on); - #endif /* _ASM_POWERPC_PS3AV_H_ */ diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index c6d1ab650778fa440d6eb79fa25a1b0a3cc779aa..f484a343efba4b8f1372f2c6a8c92af1335d6b69 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -783,6 +783,10 @@ extern void scom970_write(unsigned int address, unsigned long value); #define __get_SP() ({unsigned long sp; \ asm volatile("mr %0,1": "=r" (sp)); sp;}) +struct pt_regs; + +extern void ppc_save_regs(struct pt_regs *regs); + #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_REG_H */ diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h index 8eaa7b28d9d07d59ad6d2f0a6cb83187380ec8b3..e0175beb446291d0d92f92d5f65897fb200a4472 100644 --- a/arch/powerpc/include/asm/rtas.h +++ b/arch/powerpc/include/asm/rtas.h @@ -168,6 +168,7 @@ extern void rtas_os_term(char *str); extern int rtas_get_sensor(int sensor, int index, int *state); extern int rtas_get_power_level(int powerdomain, int *level); extern int rtas_set_power_level(int powerdomain, int level, int *setlevel); +extern bool rtas_indicator_present(int token, int *maxindex); extern int rtas_set_indicator(int indicator, int index, int new_value); extern int rtas_set_indicator_fast(int indicator, int index, int new_value); extern void rtas_progress(char *s, unsigned short hex); diff --git a/arch/powerpc/include/asm/sfp-machine.h b/arch/powerpc/include/asm/sfp-machine.h index ced34f1dc8f814ce0a79a691ef67297220510f40..3d9f831c3c55749829e76abf8e912cbf47af7991 100644 --- a/arch/powerpc/include/asm/sfp-machine.h +++ b/arch/powerpc/include/asm/sfp-machine.h @@ -82,7 +82,7 @@ #define _FP_MUL_MEAT_S(R,X,Y) _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_S,R,X,Y,umul_ppmm) #define _FP_MUL_MEAT_D(R,X,Y) _FP_MUL_MEAT_2_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm) -#define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_udiv(S,R,X,Y) +#define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_udiv_norm(S,R,X,Y) #define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_2_udiv(D,R,X,Y) /* These macros define what NaN looks like. They're supposed to expand to @@ -97,6 +97,20 @@ #define _FP_KEEPNANFRACP 1 +#ifdef FP_EX_BOOKE_E500_SPE +#define FP_EX_INEXACT (1 << 21) +#define FP_EX_INVALID (1 << 20) +#define FP_EX_DIVZERO (1 << 19) +#define FP_EX_UNDERFLOW (1 << 18) +#define FP_EX_OVERFLOW (1 << 17) +#define FP_INHIBIT_RESULTS 0 + +#define __FPU_FPSCR (current->thread.spefscr) +#define __FPU_ENABLED_EXC \ +({ \ + (__FPU_FPSCR >> 2) & 0x1f; \ +}) +#else /* Exception flags. We use the bit positions of the appropriate bits in the FPSCR, which also correspond to the FE_* bits. This makes everything easier ;-). */ @@ -111,22 +125,6 @@ #define FP_EX_DIVZERO (1 << (31 - 5)) #define FP_EX_INEXACT (1 << (31 - 6)) -/* This macro appears to be called when both X and Y are NaNs, and - * has to choose one and copy it to R. i386 goes for the larger of the - * two, sparc64 just picks Y. I don't understand this at all so I'll - * go with sparc64 because it's shorter :-> -- PMM - */ -#define _FP_CHOOSENAN(fs, wc, R, X, Y, OP) \ - do { \ - R##_s = Y##_s; \ - _FP_FRAC_COPY_##wc(R,Y); \ - R##_c = FP_CLS_NAN; \ - } while (0) - - -#include -#include - #define __FPU_FPSCR (current->thread.fpscr.val) /* We only actually write to the destination register @@ -137,6 +135,32 @@ (__FPU_FPSCR >> 3) & 0x1f; \ }) +#endif + +/* + * If one NaN is signaling and the other is not, + * we choose that one, otherwise we choose X. + */ +#define _FP_CHOOSENAN(fs, wc, R, X, Y, OP) \ + do { \ + if ((_FP_FRAC_HIGH_RAW_##fs(Y) & _FP_QNANBIT_##fs) \ + && !(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs)) \ + { \ + R##_s = X##_s; \ + _FP_FRAC_COPY_##wc(R,X); \ + } \ + else \ + { \ + R##_s = Y##_s; \ + _FP_FRAC_COPY_##wc(R,Y); \ + } \ + R##_c = FP_CLS_NAN; \ + } while (0) + + +#include +#include + #define __FPU_TRAP_P(bits) \ ((__FPU_ENABLED_EXC & (bits)) != 0) diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h index 1866cec4f9677b5fc995e754cea3ed6936d7ec57..c25f73d1d84203e0393d26d5da07e390c79417e5 100644 --- a/arch/powerpc/include/asm/smp.h +++ b/arch/powerpc/include/asm/smp.h @@ -81,6 +81,13 @@ extern int cpu_to_core_id(int cpu); #define PPC_MSG_CALL_FUNC_SINGLE 2 #define PPC_MSG_DEBUGGER_BREAK 3 +/* + * irq controllers that have dedicated ipis per message and don't + * need additional code in the action handler may use this + */ +extern int smp_request_message_ipi(int virq, int message); +extern const char *smp_ipi_name[]; + void smp_init_iSeries(void); void smp_init_pSeries(void); void smp_init_cell(void); diff --git a/arch/powerpc/include/asm/spinlock.h b/arch/powerpc/include/asm/spinlock.h index f56a843f47058fa238ec86f844786d3b4cbe9499..36864364e601cb22b6221fb824929973a2b2e688 100644 --- a/arch/powerpc/include/asm/spinlock.h +++ b/arch/powerpc/include/asm/spinlock.h @@ -277,7 +277,7 @@ static inline void __raw_read_unlock(raw_rwlock_t *rw) bne- 1b" : "=&r"(tmp) : "r"(&rw->lock) - : "cr0", "memory"); + : "cr0", "xer", "memory"); } static inline void __raw_write_unlock(raw_rwlock_t *rw) diff --git a/arch/powerpc/include/asm/synch.h b/arch/powerpc/include/asm/synch.h index 45963e80f557d2b1108781a6d381e2ab37f6ec31..28f6ddbff4cf31d6e9fa8d420563dc8228e1db5a 100644 --- a/arch/powerpc/include/asm/synch.h +++ b/arch/powerpc/include/asm/synch.h @@ -5,6 +5,10 @@ #include #include +#if defined(__powerpc64__) || defined(CONFIG_PPC_E500MC) +#define __SUBARCH_HAS_LWSYNC +#endif + #ifndef __ASSEMBLY__ extern unsigned int __start___lwsync_fixup, __stop___lwsync_fixup; extern void do_lwsync_fixups(unsigned long value, void *fixup_start, diff --git a/arch/powerpc/include/asm/system.h b/arch/powerpc/include/asm/system.h index d6648c1433221972a6730392236dc8c3c63fe614..2a4be19a92c43275343fb5ed808667c92117bb92 100644 --- a/arch/powerpc/include/asm/system.h +++ b/arch/powerpc/include/asm/system.h @@ -23,15 +23,17 @@ * read_barrier_depends() prevents data-dependent loads being reordered * across this point (nop on PPC). * - * We have to use the sync instructions for mb(), since lwsync doesn't - * order loads with respect to previous stores. Lwsync is fine for - * rmb(), though. Note that rmb() actually uses a sync on 32-bit - * architectures. + * *mb() variants without smp_ prefix must order all types of memory + * operations with one another. sync is the only instruction sufficient + * to do this. * - * For wmb(), we use sync since wmb is used in drivers to order - * stores to system memory with respect to writes to the device. - * However, smp_wmb() can be a lighter-weight lwsync or eieio barrier - * on SMP since it is only used to order updates to system memory. + * For the smp_ barriers, ordering is for cacheable memory operations + * only. We have to use the sync instruction for smp_mb(), since lwsync + * doesn't order loads with respect to previous stores. Lwsync can be + * used for smp_rmb() and smp_wmb(). + * + * However, on CPUs that don't support lwsync, lwsync actually maps to a + * heavy-weight sync, so smp_wmb() can be a lighter-weight eieio. */ #define mb() __asm__ __volatile__ ("sync" : : : "memory") #define rmb() __asm__ __volatile__ ("sync" : : : "memory") @@ -45,14 +47,14 @@ #ifdef CONFIG_SMP #ifdef __SUBARCH_HAS_LWSYNC -# define SMPWMB lwsync +# define SMPWMB LWSYNC #else # define SMPWMB eieio #endif #define smp_mb() mb() -#define smp_rmb() rmb() -#define smp_wmb() __asm__ __volatile__ (__stringify(SMPWMB) : : :"memory") +#define smp_rmb() __asm__ __volatile__ (stringify_in_c(LWSYNC) : : :"memory") +#define smp_wmb() __asm__ __volatile__ (stringify_in_c(SMPWMB) : : :"memory") #define smp_read_barrier_depends() read_barrier_depends() #else #define smp_mb() barrier() diff --git a/arch/powerpc/include/asm/time.h b/arch/powerpc/include/asm/time.h index febd581ec9b047a01b1ff67425fef02375e34b50..27ccb764fdaba84518d5e7eadaa50ae4ed06513b 100644 --- a/arch/powerpc/include/asm/time.h +++ b/arch/powerpc/include/asm/time.h @@ -48,26 +48,6 @@ extern unsigned long ppc_proc_freq; extern unsigned long ppc_tb_freq; #define DEFAULT_TB_FREQ 125000000UL -/* - * By putting all of this stuff into a single struct we - * reduce the number of cache lines touched by do_gettimeofday. - * Both by collecting all of the data in one cache line and - * by touching only one TOC entry on ppc64. - */ -struct gettimeofday_vars { - u64 tb_to_xs; - u64 stamp_xsec; - u64 tb_orig_stamp; -}; - -struct gettimeofday_struct { - unsigned long tb_ticks_per_sec; - struct gettimeofday_vars vars[2]; - struct gettimeofday_vars * volatile varp; - unsigned var_idx; - unsigned tb_to_us; -}; - struct div_result { u64 result_high; u64 result_low; diff --git a/arch/powerpc/include/asm/tlbflush.h b/arch/powerpc/include/asm/tlbflush.h index a2c6bfd85fb7a38ab6d002373c24afbf8648399a..abbe3419d1dd244e57d543a58f4a25bb55502da4 100644 --- a/arch/powerpc/include/asm/tlbflush.h +++ b/arch/powerpc/include/asm/tlbflush.h @@ -6,6 +6,9 @@ * * - flush_tlb_mm(mm) flushes the specified mm context TLB's * - flush_tlb_page(vma, vmaddr) flushes one page + * - local_flush_tlb_mm(mm) flushes the specified mm context on + * the local processor + * - local_flush_tlb_page(vma, vmaddr) flushes one page on the local processor * - flush_tlb_page_nohash(vma, vmaddr) flushes one page if SW loaded TLB * - flush_tlb_range(vma, start, end) flushes a range of pages * - flush_tlb_kernel_range(start, end) flushes a range of kernel pages @@ -17,7 +20,7 @@ */ #ifdef __KERNEL__ -#if defined(CONFIG_4xx) || defined(CONFIG_8xx) || defined(CONFIG_FSL_BOOKE) +#ifdef CONFIG_PPC_MMU_NOHASH /* * TLB flushing for software loaded TLB chips * @@ -28,63 +31,49 @@ #include -extern void _tlbie(unsigned long address, unsigned int pid); -extern void _tlbil_all(void); -extern void _tlbil_pid(unsigned int pid); -extern void _tlbil_va(unsigned long address, unsigned int pid); +#define MMU_NO_CONTEXT ((unsigned int)-1) -#if defined(CONFIG_40x) || defined(CONFIG_8xx) -#define _tlbia() asm volatile ("tlbia; sync" : : : "memory") -#else /* CONFIG_44x || CONFIG_FSL_BOOKE */ -extern void _tlbia(void); -#endif - -static inline void flush_tlb_mm(struct mm_struct *mm) -{ - _tlbil_pid(mm->context.id); -} - -static inline void flush_tlb_page(struct vm_area_struct *vma, - unsigned long vmaddr) -{ - _tlbil_va(vmaddr, vma ? vma->vm_mm->context.id : 0); -} +extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end); +extern void flush_tlb_kernel_range(unsigned long start, unsigned long end); -static inline void flush_tlb_page_nohash(struct vm_area_struct *vma, - unsigned long vmaddr) -{ - flush_tlb_page(vma, vmaddr); -} +extern void local_flush_tlb_mm(struct mm_struct *mm); +extern void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr); -static inline void flush_tlb_range(struct vm_area_struct *vma, - unsigned long start, unsigned long end) -{ - _tlbil_pid(vma->vm_mm->context.id); -} +#ifdef CONFIG_SMP +extern void flush_tlb_mm(struct mm_struct *mm); +extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr); +#else +#define flush_tlb_mm(mm) local_flush_tlb_mm(mm) +#define flush_tlb_page(vma,addr) local_flush_tlb_page(vma,addr) +#endif +#define flush_tlb_page_nohash(vma,addr) flush_tlb_page(vma,addr) -static inline void flush_tlb_kernel_range(unsigned long start, - unsigned long end) -{ - _tlbil_pid(0); -} +#elif defined(CONFIG_PPC_STD_MMU_32) -#elif defined(CONFIG_PPC32) /* - * TLB flushing for "classic" hash-MMMU 32-bit CPUs, 6xx, 7xx, 7xxx + * TLB flushing for "classic" hash-MMU 32-bit CPUs, 6xx, 7xx, 7xxx */ -extern void _tlbie(unsigned long address); -extern void _tlbia(void); - extern void flush_tlb_mm(struct mm_struct *mm); extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr); extern void flush_tlb_page_nohash(struct vm_area_struct *vma, unsigned long addr); extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end); extern void flush_tlb_kernel_range(unsigned long start, unsigned long end); +static inline void local_flush_tlb_page(struct vm_area_struct *vma, + unsigned long vmaddr) +{ + flush_tlb_page(vma, vmaddr); +} +static inline void local_flush_tlb_mm(struct mm_struct *mm) +{ + flush_tlb_mm(mm); +} + +#elif defined(CONFIG_PPC_STD_MMU_64) -#else /* - * TLB flushing for 64-bit has-MMU CPUs + * TLB flushing for 64-bit hash-MMU CPUs */ #include @@ -134,10 +123,19 @@ extern void flush_hash_page(unsigned long va, real_pte_t pte, int psize, extern void flush_hash_range(unsigned long number, int local); +static inline void local_flush_tlb_mm(struct mm_struct *mm) +{ +} + static inline void flush_tlb_mm(struct mm_struct *mm) { } +static inline void local_flush_tlb_page(struct vm_area_struct *vma, + unsigned long vmaddr) +{ +} + static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr) { @@ -162,7 +160,8 @@ static inline void flush_tlb_kernel_range(unsigned long start, extern void __flush_hash_table_range(struct mm_struct *mm, unsigned long start, unsigned long end); - +#else +#error Unsupported MMU type #endif #endif /*__KERNEL__ */ diff --git a/arch/powerpc/include/asm/vdso_datapage.h b/arch/powerpc/include/asm/vdso_datapage.h index f01393224b52dfe66ad88ef3bedad00f49a7fca4..13c2c283e17828dee6839885cf1d89e837eed2da 100644 --- a/arch/powerpc/include/asm/vdso_datapage.h +++ b/arch/powerpc/include/asm/vdso_datapage.h @@ -39,6 +39,7 @@ #ifndef __ASSEMBLY__ #include +#include #define SYSCALL_MAP_SIZE ((__NR_syscalls + 31) / 32) @@ -83,6 +84,7 @@ struct vdso_data { __u32 icache_log_block_size; /* L1 i-cache log block size */ __s32 wtom_clock_sec; /* Wall to monotonic clock */ __s32 wtom_clock_nsec; + struct timespec stamp_xtime; /* xtime as at tb_orig_stamp */ __u32 syscall_map_64[SYSCALL_MAP_SIZE]; /* map of syscalls */ __u32 syscall_map_32[SYSCALL_MAP_SIZE]; /* map of syscalls */ }; @@ -102,6 +104,7 @@ struct vdso_data { __u32 tz_dsttime; /* Type of dst correction 0x5C */ __s32 wtom_clock_sec; /* Wall to monotonic clock */ __s32 wtom_clock_nsec; + struct timespec stamp_xtime; /* xtime as at tb_orig_stamp */ __u32 syscall_map_32[SYSCALL_MAP_SIZE]; /* map of syscalls */ __u32 dcache_block_size; /* L1 d-cache block size */ __u32 icache_block_size; /* L1 i-cache block size */ diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 92673b43858d067d6ccfab7a1cc083018d4a5c4f..1308a86e9070814a1680d5f40e3ec00fe2b5c637 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -17,6 +17,7 @@ ifdef CONFIG_FUNCTION_TRACER CFLAGS_REMOVE_cputable.o = -pg -mno-sched-epilog CFLAGS_REMOVE_prom_init.o = -pg -mno-sched-epilog CFLAGS_REMOVE_btext.o = -pg -mno-sched-epilog +CFLAGS_REMOVE_prom.o = -pg -mno-sched-epilog ifdef CONFIG_DYNAMIC_FTRACE # dynamic ftrace setup. @@ -102,6 +103,10 @@ endif obj-$(CONFIG_PPC64) += $(obj64-y) +ifneq ($(CONFIG_XMON)$(CONFIG_KEXEC),) +obj-y += ppc_save_regs.o +endif + extra-$(CONFIG_PPC_FPU) += fpu.o extra-$(CONFIG_PPC64) += entry_64.o diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 75c5dd0138fd327a96d22d0fe46b9bac899cb610..661d07d2146bcbead9cb44e2a43aff1b5151e562 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -60,6 +60,7 @@ int main(void) { DEFINE(THREAD, offsetof(struct task_struct, thread)); DEFINE(MM, offsetof(struct task_struct, mm)); + DEFINE(MMCONTEXTID, offsetof(struct mm_struct, context.id)); #ifdef CONFIG_PPC64 DEFINE(AUDITCONTEXT, offsetof(struct task_struct, audit_context)); #else @@ -306,6 +307,7 @@ int main(void) DEFINE(CFG_SYSCALL_MAP32, offsetof(struct vdso_data, syscall_map_32)); DEFINE(WTOM_CLOCK_SEC, offsetof(struct vdso_data, wtom_clock_sec)); DEFINE(WTOM_CLOCK_NSEC, offsetof(struct vdso_data, wtom_clock_nsec)); + DEFINE(STAMP_XTIME, offsetof(struct vdso_data, stamp_xtime)); DEFINE(CFG_ICACHE_BLOCKSZ, offsetof(struct vdso_data, icache_block_size)); DEFINE(CFG_DCACHE_BLOCKSZ, offsetof(struct vdso_data, dcache_block_size)); DEFINE(CFG_ICACHE_LOGBLOCKSZ, offsetof(struct vdso_data, icache_log_block_size)); @@ -378,6 +380,10 @@ int main(void) DEFINE(VCPU_FAULT_DEAR, offsetof(struct kvm_vcpu, arch.fault_dear)); DEFINE(VCPU_FAULT_ESR, offsetof(struct kvm_vcpu, arch.fault_esr)); #endif +#ifdef CONFIG_44x + DEFINE(PGD_T_LOG2, PGD_T_LOG2); + DEFINE(PTE_T_LOG2, PTE_T_LOG2); +#endif return 0; } diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 7e8719504f39d65bf50e822289c602470f569713..923f87aff20a4522f44d1e01f487938b598604ff 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -19,6 +19,7 @@ #include #include #include /* for PTRRELOC on ARCH=ppc */ +#include struct cpu_spec* cur_cpu_spec = NULL; EXPORT_SYMBOL(cur_cpu_spec); @@ -94,6 +95,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "POWER3 (630)", .cpu_features = CPU_FTRS_POWER3, .cpu_user_features = COMMON_USER_PPC64|PPC_FEATURE_PPC_LE, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, @@ -109,6 +111,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "POWER3 (630+)", .cpu_features = CPU_FTRS_POWER3, .cpu_user_features = COMMON_USER_PPC64|PPC_FEATURE_PPC_LE, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, @@ -124,6 +127,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "RS64-II (northstar)", .cpu_features = CPU_FTRS_RS64, .cpu_user_features = COMMON_USER_PPC64, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, @@ -139,6 +143,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "RS64-III (pulsar)", .cpu_features = CPU_FTRS_RS64, .cpu_user_features = COMMON_USER_PPC64, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, @@ -154,6 +159,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "RS64-III (icestar)", .cpu_features = CPU_FTRS_RS64, .cpu_user_features = COMMON_USER_PPC64, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, @@ -169,6 +175,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "RS64-IV (sstar)", .cpu_features = CPU_FTRS_RS64, .cpu_user_features = COMMON_USER_PPC64, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, @@ -184,6 +191,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "POWER4 (gp)", .cpu_features = CPU_FTRS_POWER4, .cpu_user_features = COMMON_USER_POWER4, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, @@ -199,6 +207,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "POWER4+ (gq)", .cpu_features = CPU_FTRS_POWER4, .cpu_user_features = COMMON_USER_POWER4, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, @@ -215,6 +224,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_PPC970, .cpu_user_features = COMMON_USER_POWER4 | PPC_FEATURE_HAS_ALTIVEC_COMP, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, @@ -233,6 +243,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_PPC970, .cpu_user_features = COMMON_USER_POWER4 | PPC_FEATURE_HAS_ALTIVEC_COMP, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, @@ -251,6 +262,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_PPC970, .cpu_user_features = COMMON_USER_POWER4 | PPC_FEATURE_HAS_ALTIVEC_COMP, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, @@ -269,6 +281,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_PPC970, .cpu_user_features = COMMON_USER_POWER4 | PPC_FEATURE_HAS_ALTIVEC_COMP, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, @@ -287,6 +300,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_PPC970, .cpu_user_features = COMMON_USER_POWER4 | PPC_FEATURE_HAS_ALTIVEC_COMP, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, @@ -303,6 +317,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "POWER5 (gr)", .cpu_features = CPU_FTRS_POWER5, .cpu_user_features = COMMON_USER_POWER5, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 6, @@ -323,6 +338,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "POWER5+ (gs)", .cpu_features = CPU_FTRS_POWER5, .cpu_user_features = COMMON_USER_POWER5_PLUS, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 6, @@ -339,6 +355,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "POWER5+ (gs)", .cpu_features = CPU_FTRS_POWER5, .cpu_user_features = COMMON_USER_POWER5_PLUS, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 6, @@ -356,6 +373,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "POWER5+", .cpu_features = CPU_FTRS_POWER5, .cpu_user_features = COMMON_USER_POWER5_PLUS, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 128, .dcache_bsize = 128, .machine_check = machine_check_generic, @@ -369,6 +387,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_POWER6, .cpu_user_features = COMMON_USER_POWER6 | PPC_FEATURE_POWER6_EXT, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 6, @@ -388,6 +407,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "POWER6 (architected)", .cpu_features = CPU_FTRS_POWER6, .cpu_user_features = COMMON_USER_POWER6, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 128, .dcache_bsize = 128, .machine_check = machine_check_generic, @@ -400,6 +420,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "POWER7 (architected)", .cpu_features = CPU_FTRS_POWER7, .cpu_user_features = COMMON_USER_POWER7, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 128, .dcache_bsize = 128, .machine_check = machine_check_generic, @@ -412,6 +433,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "POWER7 (raw)", .cpu_features = CPU_FTRS_POWER7, .cpu_user_features = COMMON_USER_POWER7, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 6, @@ -434,6 +456,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_user_features = COMMON_USER_PPC64 | PPC_FEATURE_CELL | PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_SMT, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 4, @@ -449,6 +472,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "PA6T", .cpu_features = CPU_FTRS_PA6T, .cpu_user_features = COMMON_USER_PA6T, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 64, .dcache_bsize = 64, .num_pmcs = 6, @@ -466,6 +490,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "POWER4 (compatible)", .cpu_features = CPU_FTRS_COMPATIBLE, .cpu_user_features = COMMON_USER_PPC64, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 6, @@ -483,6 +508,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_PPC601, .cpu_user_features = COMMON_USER | PPC_FEATURE_601_INSTR | PPC_FEATURE_UNIFIED_CACHE | PPC_FEATURE_NO_TB, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 32, .dcache_bsize = 32, .machine_check = machine_check_generic, @@ -494,6 +520,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "603", .cpu_features = CPU_FTRS_603, .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, + .mmu_features = 0, .icache_bsize = 32, .dcache_bsize = 32, .cpu_setup = __setup_cpu_603, @@ -506,6 +533,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "603e", .cpu_features = CPU_FTRS_603, .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, + .mmu_features = 0, .icache_bsize = 32, .dcache_bsize = 32, .cpu_setup = __setup_cpu_603, @@ -518,6 +546,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "603ev", .cpu_features = CPU_FTRS_603, .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, + .mmu_features = 0, .icache_bsize = 32, .dcache_bsize = 32, .cpu_setup = __setup_cpu_603, @@ -530,6 +559,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "604", .cpu_features = CPU_FTRS_604, .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 2, @@ -543,6 +573,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "604e", .cpu_features = CPU_FTRS_604, .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -556,6 +587,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "604r", .cpu_features = CPU_FTRS_604, .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -569,6 +601,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "604ev", .cpu_features = CPU_FTRS_604, .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -582,6 +615,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "740/750", .cpu_features = CPU_FTRS_740_NOTAU, .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -595,6 +629,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "750CX", .cpu_features = CPU_FTRS_750, .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -608,6 +643,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "750CX", .cpu_features = CPU_FTRS_750, .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -622,6 +658,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "750CXe", .cpu_features = CPU_FTRS_750, .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -636,6 +673,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "750CXe", .cpu_features = CPU_FTRS_750, .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -650,6 +688,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "750CL", .cpu_features = CPU_FTRS_750CL, .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, + .mmu_features = MMU_FTR_HPTE_TABLE | MMU_FTR_USE_HIGH_BATS, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -664,6 +703,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "745/755", .cpu_features = CPU_FTRS_750, .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -678,6 +718,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "750FX", .cpu_features = CPU_FTRS_750FX1, .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -692,6 +733,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "750FX", .cpu_features = CPU_FTRS_750FX2, .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -706,6 +748,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "750FX", .cpu_features = CPU_FTRS_750FX, .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, + .mmu_features = MMU_FTR_HPTE_TABLE | MMU_FTR_USE_HIGH_BATS, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -720,6 +763,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "750GX", .cpu_features = CPU_FTRS_750GX, .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, + .mmu_features = MMU_FTR_HPTE_TABLE | MMU_FTR_USE_HIGH_BATS, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -734,6 +778,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "740/750", .cpu_features = CPU_FTRS_740, .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -749,6 +794,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_7400_NOTAU, .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -764,6 +810,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_7400, .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -779,6 +826,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_7400, .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -794,6 +842,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_7450_20, .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -811,6 +860,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_7450_21, .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -828,6 +878,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_7450_23, .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -845,6 +896,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_7455_1, .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE, + .mmu_features = MMU_FTR_HPTE_TABLE | MMU_FTR_USE_HIGH_BATS, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -862,6 +914,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_7455_20, .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE, + .mmu_features = MMU_FTR_HPTE_TABLE | MMU_FTR_USE_HIGH_BATS, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -879,6 +932,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_7455, .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE, + .mmu_features = MMU_FTR_HPTE_TABLE | MMU_FTR_USE_HIGH_BATS, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -896,6 +950,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_7447_10, .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE, + .mmu_features = MMU_FTR_HPTE_TABLE | MMU_FTR_USE_HIGH_BATS, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -913,6 +968,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_7447_10, .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE, + .mmu_features = MMU_FTR_HPTE_TABLE | MMU_FTR_USE_HIGH_BATS, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -929,6 +985,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "7447/7457", .cpu_features = CPU_FTRS_7447, .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE, + .mmu_features = MMU_FTR_HPTE_TABLE | MMU_FTR_USE_HIGH_BATS, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -946,6 +1003,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_7447A, .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE, + .mmu_features = MMU_FTR_HPTE_TABLE | MMU_FTR_USE_HIGH_BATS, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -963,6 +1021,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_7448, .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE, + .mmu_features = MMU_FTR_HPTE_TABLE | MMU_FTR_USE_HIGH_BATS, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -979,6 +1038,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "82xx", .cpu_features = CPU_FTRS_82XX, .cpu_user_features = COMMON_USER, + .mmu_features = 0, .icache_bsize = 32, .dcache_bsize = 32, .cpu_setup = __setup_cpu_603, @@ -991,6 +1051,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "G2_LE", .cpu_features = CPU_FTRS_G2_LE, .cpu_user_features = COMMON_USER, + .mmu_features = MMU_FTR_USE_HIGH_BATS, .icache_bsize = 32, .dcache_bsize = 32, .cpu_setup = __setup_cpu_603, @@ -1003,6 +1064,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "e300c1", .cpu_features = CPU_FTRS_E300, .cpu_user_features = COMMON_USER, + .mmu_features = MMU_FTR_USE_HIGH_BATS, .icache_bsize = 32, .dcache_bsize = 32, .cpu_setup = __setup_cpu_603, @@ -1015,6 +1077,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "e300c2", .cpu_features = CPU_FTRS_E300C2, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU, + .mmu_features = MMU_FTR_USE_HIGH_BATS, .icache_bsize = 32, .dcache_bsize = 32, .cpu_setup = __setup_cpu_603, @@ -1027,6 +1090,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "e300c3", .cpu_features = CPU_FTRS_E300, .cpu_user_features = COMMON_USER, + .mmu_features = MMU_FTR_USE_HIGH_BATS, .icache_bsize = 32, .dcache_bsize = 32, .cpu_setup = __setup_cpu_603, @@ -1041,6 +1105,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "e300c4", .cpu_features = CPU_FTRS_E300, .cpu_user_features = COMMON_USER, + .mmu_features = MMU_FTR_USE_HIGH_BATS, .icache_bsize = 32, .dcache_bsize = 32, .cpu_setup = __setup_cpu_603, @@ -1056,6 +1121,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "(generic PPC)", .cpu_features = CPU_FTRS_CLASSIC32, .cpu_user_features = COMMON_USER, + .mmu_features = MMU_FTR_HPTE_TABLE, .icache_bsize = 32, .dcache_bsize = 32, .machine_check = machine_check_generic, @@ -1071,6 +1137,7 @@ static struct cpu_spec __initdata cpu_specs[] = { * if the 8xx code is there.... */ .cpu_features = CPU_FTRS_8XX, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU, + .mmu_features = MMU_FTR_TYPE_8xx, .icache_bsize = 16, .dcache_bsize = 16, .platform = "ppc823", @@ -1083,6 +1150,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "403GC", .cpu_features = CPU_FTRS_40X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU, + .mmu_features = MMU_FTR_TYPE_40x, .icache_bsize = 16, .dcache_bsize = 16, .machine_check = machine_check_4xx, @@ -1095,6 +1163,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_40X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_NO_TB, + .mmu_features = MMU_FTR_TYPE_40x, .icache_bsize = 16, .dcache_bsize = 16, .machine_check = machine_check_4xx, @@ -1106,6 +1175,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "403G ??", .cpu_features = CPU_FTRS_40X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU, + .mmu_features = MMU_FTR_TYPE_40x, .icache_bsize = 16, .dcache_bsize = 16, .machine_check = machine_check_4xx, @@ -1118,6 +1188,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_40X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, + .mmu_features = MMU_FTR_TYPE_40x, .icache_bsize = 32, .dcache_bsize = 32, .machine_check = machine_check_4xx, @@ -1130,6 +1201,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_40X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, + .mmu_features = MMU_FTR_TYPE_40x, .icache_bsize = 32, .dcache_bsize = 32, .machine_check = machine_check_4xx, @@ -1142,6 +1214,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_40X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, + .mmu_features = MMU_FTR_TYPE_40x, .icache_bsize = 32, .dcache_bsize = 32, .machine_check = machine_check_4xx, @@ -1154,6 +1227,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_40X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, + .mmu_features = MMU_FTR_TYPE_40x, .icache_bsize = 32, .dcache_bsize = 32, .machine_check = machine_check_4xx, @@ -1166,6 +1240,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_40X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, + .mmu_features = MMU_FTR_TYPE_40x, .icache_bsize = 32, .dcache_bsize = 32, .machine_check = machine_check_4xx, @@ -1178,6 +1253,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_40X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, + .mmu_features = MMU_FTR_TYPE_40x, .icache_bsize = 32, .dcache_bsize = 32, .machine_check = machine_check_4xx, @@ -1190,6 +1266,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_40X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, + .mmu_features = MMU_FTR_TYPE_40x, .icache_bsize = 32, .dcache_bsize = 32, .machine_check = machine_check_4xx, @@ -1202,6 +1279,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_40X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, + .mmu_features = MMU_FTR_TYPE_40x, .icache_bsize = 32, .dcache_bsize = 32, .machine_check = machine_check_4xx, @@ -1213,6 +1291,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "405LP", .cpu_features = CPU_FTRS_40X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU, + .mmu_features = MMU_FTR_TYPE_40x, .icache_bsize = 32, .dcache_bsize = 32, .machine_check = machine_check_4xx, @@ -1225,6 +1304,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_40X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, + .mmu_features = MMU_FTR_TYPE_40x, .icache_bsize = 32, .dcache_bsize = 32, .machine_check = machine_check_4xx, @@ -1237,6 +1317,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_40X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, + .mmu_features = MMU_FTR_TYPE_40x, .icache_bsize = 32, .dcache_bsize = 32, .machine_check = machine_check_4xx, @@ -1249,6 +1330,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_40X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, + .mmu_features = MMU_FTR_TYPE_40x, .icache_bsize = 32, .dcache_bsize = 32, .machine_check = machine_check_4xx, @@ -1261,6 +1343,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_40X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, + .mmu_features = MMU_FTR_TYPE_40x, .icache_bsize = 32, .dcache_bsize = 32, .machine_check = machine_check_4xx, @@ -1273,6 +1356,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_40X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, + .mmu_features = MMU_FTR_TYPE_40x, .icache_bsize = 32, .dcache_bsize = 32, .machine_check = machine_check_4xx, @@ -1286,6 +1370,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_40X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, + .mmu_features = MMU_FTR_TYPE_40x, .icache_bsize = 32, .dcache_bsize = 32, .machine_check = machine_check_4xx, @@ -1298,6 +1383,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_40X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, + .mmu_features = MMU_FTR_TYPE_40x, .icache_bsize = 32, .dcache_bsize = 32, .machine_check = machine_check_4xx, @@ -1312,6 +1398,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "440GR Rev. A", .cpu_features = CPU_FTRS_44X, .cpu_user_features = COMMON_USER_BOOKE, + .mmu_features = MMU_FTR_TYPE_44x, .icache_bsize = 32, .dcache_bsize = 32, .machine_check = machine_check_4xx, @@ -1323,6 +1410,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "440EP Rev. A", .cpu_features = CPU_FTRS_44X, .cpu_user_features = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU, + .mmu_features = MMU_FTR_TYPE_44x, .icache_bsize = 32, .dcache_bsize = 32, .cpu_setup = __setup_cpu_440ep, @@ -1335,6 +1423,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "440GR Rev. B", .cpu_features = CPU_FTRS_44X, .cpu_user_features = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU, + .mmu_features = MMU_FTR_TYPE_44x, .icache_bsize = 32, .dcache_bsize = 32, .machine_check = machine_check_4xx, @@ -1346,6 +1435,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "440EP Rev. C", .cpu_features = CPU_FTRS_44X, .cpu_user_features = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU, + .mmu_features = MMU_FTR_TYPE_44x, .icache_bsize = 32, .dcache_bsize = 32, .cpu_setup = __setup_cpu_440ep, @@ -1358,6 +1448,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "440EP Rev. B", .cpu_features = CPU_FTRS_44X, .cpu_user_features = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU, + .mmu_features = MMU_FTR_TYPE_44x, .icache_bsize = 32, .dcache_bsize = 32, .cpu_setup = __setup_cpu_440ep, @@ -1370,6 +1461,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "440GRX", .cpu_features = CPU_FTRS_44X, .cpu_user_features = COMMON_USER_BOOKE, + .mmu_features = MMU_FTR_TYPE_44x, .icache_bsize = 32, .dcache_bsize = 32, .cpu_setup = __setup_cpu_440grx, @@ -1382,6 +1474,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "440EPX", .cpu_features = CPU_FTRS_44X, .cpu_user_features = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU, + .mmu_features = MMU_FTR_TYPE_44x, .icache_bsize = 32, .dcache_bsize = 32, .cpu_setup = __setup_cpu_440epx, @@ -1394,6 +1487,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "440GP Rev. B", .cpu_features = CPU_FTRS_44X, .cpu_user_features = COMMON_USER_BOOKE, + .mmu_features = MMU_FTR_TYPE_44x, .icache_bsize = 32, .dcache_bsize = 32, .machine_check = machine_check_4xx, @@ -1405,6 +1499,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "440GP Rev. C", .cpu_features = CPU_FTRS_44X, .cpu_user_features = COMMON_USER_BOOKE, + .mmu_features = MMU_FTR_TYPE_44x, .icache_bsize = 32, .dcache_bsize = 32, .machine_check = machine_check_4xx, @@ -1416,6 +1511,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "440GX Rev. A", .cpu_features = CPU_FTRS_44X, .cpu_user_features = COMMON_USER_BOOKE, + .mmu_features = MMU_FTR_TYPE_44x, .icache_bsize = 32, .dcache_bsize = 32, .cpu_setup = __setup_cpu_440gx, @@ -1428,6 +1524,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "440GX Rev. B", .cpu_features = CPU_FTRS_44X, .cpu_user_features = COMMON_USER_BOOKE, + .mmu_features = MMU_FTR_TYPE_44x, .icache_bsize = 32, .dcache_bsize = 32, .cpu_setup = __setup_cpu_440gx, @@ -1440,6 +1537,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "440GX Rev. C", .cpu_features = CPU_FTRS_44X, .cpu_user_features = COMMON_USER_BOOKE, + .mmu_features = MMU_FTR_TYPE_44x, .icache_bsize = 32, .dcache_bsize = 32, .cpu_setup = __setup_cpu_440gx, @@ -1452,6 +1550,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "440GX Rev. F", .cpu_features = CPU_FTRS_44X, .cpu_user_features = COMMON_USER_BOOKE, + .mmu_features = MMU_FTR_TYPE_44x, .icache_bsize = 32, .dcache_bsize = 32, .cpu_setup = __setup_cpu_440gx, @@ -1464,6 +1563,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "440SP Rev. A", .cpu_features = CPU_FTRS_44X, .cpu_user_features = COMMON_USER_BOOKE, + .mmu_features = MMU_FTR_TYPE_44x, .icache_bsize = 32, .dcache_bsize = 32, .machine_check = machine_check_4xx, @@ -1475,6 +1575,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "440SPe Rev. A", .cpu_features = CPU_FTRS_44X, .cpu_user_features = COMMON_USER_BOOKE, + .mmu_features = MMU_FTR_TYPE_44x, .icache_bsize = 32, .dcache_bsize = 32, .cpu_setup = __setup_cpu_440spe, @@ -1487,6 +1588,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "440SPe Rev. B", .cpu_features = CPU_FTRS_44X, .cpu_user_features = COMMON_USER_BOOKE, + .mmu_features = MMU_FTR_TYPE_44x, .icache_bsize = 32, .dcache_bsize = 32, .cpu_setup = __setup_cpu_440spe, @@ -1499,6 +1601,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "440 in Virtex-5 FXT", .cpu_features = CPU_FTRS_44X, .cpu_user_features = COMMON_USER_BOOKE, + .mmu_features = MMU_FTR_TYPE_44x, .icache_bsize = 32, .dcache_bsize = 32, .cpu_setup = __setup_cpu_440x5, @@ -1509,8 +1612,9 @@ static struct cpu_spec __initdata cpu_specs[] = { .pvr_mask = 0xffff0002, .pvr_value = 0x13020002, .cpu_name = "460EX", - .cpu_features = CPU_FTRS_44X, + .cpu_features = CPU_FTRS_440x6, .cpu_user_features = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU, + .mmu_features = MMU_FTR_TYPE_44x, .icache_bsize = 32, .dcache_bsize = 32, .cpu_setup = __setup_cpu_460ex, @@ -1521,8 +1625,9 @@ static struct cpu_spec __initdata cpu_specs[] = { .pvr_mask = 0xffff0002, .pvr_value = 0x13020000, .cpu_name = "460GT", - .cpu_features = CPU_FTRS_44X, + .cpu_features = CPU_FTRS_440x6, .cpu_user_features = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU, + .mmu_features = MMU_FTR_TYPE_44x, .icache_bsize = 32, .dcache_bsize = 32, .cpu_setup = __setup_cpu_460gt, @@ -1535,6 +1640,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "(generic 44x PPC)", .cpu_features = CPU_FTRS_44X, .cpu_user_features = COMMON_USER_BOOKE, + .mmu_features = MMU_FTR_TYPE_44x, .icache_bsize = 32, .dcache_bsize = 32, .machine_check = machine_check_4xx, @@ -1551,6 +1657,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_user_features = COMMON_USER_BOOKE | PPC_FEATURE_HAS_EFP_SINGLE | PPC_FEATURE_UNIFIED_CACHE, + .mmu_features = MMU_FTR_TYPE_FSL_E, .dcache_bsize = 32, .machine_check = machine_check_e200, .platform = "ppc5554", @@ -1565,6 +1672,7 @@ static struct cpu_spec __initdata cpu_specs[] = { PPC_FEATURE_HAS_SPE_COMP | PPC_FEATURE_HAS_EFP_SINGLE_COMP | PPC_FEATURE_UNIFIED_CACHE, + .mmu_features = MMU_FTR_TYPE_FSL_E, .dcache_bsize = 32, .machine_check = machine_check_e200, .platform = "ppc5554", @@ -1577,6 +1685,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_user_features = COMMON_USER_BOOKE | PPC_FEATURE_HAS_EFP_SINGLE | PPC_FEATURE_UNIFIED_CACHE, + .mmu_features = MMU_FTR_TYPE_FSL_E, .dcache_bsize = 32, .machine_check = machine_check_e200, .platform = "ppc5554", @@ -1591,6 +1700,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_user_features = COMMON_USER_BOOKE | PPC_FEATURE_HAS_SPE_COMP | PPC_FEATURE_HAS_EFP_SINGLE_COMP, + .mmu_features = MMU_FTR_TYPE_FSL_E, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -1608,6 +1718,7 @@ static struct cpu_spec __initdata cpu_specs[] = { PPC_FEATURE_HAS_SPE_COMP | PPC_FEATURE_HAS_EFP_SINGLE_COMP | PPC_FEATURE_HAS_EFP_DOUBLE_COMP, + .mmu_features = MMU_FTR_TYPE_FSL_E | MMU_FTR_BIG_PHYS, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -1622,6 +1733,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "e500mc", .cpu_features = CPU_FTRS_E500MC, .cpu_user_features = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU, + .mmu_features = MMU_FTR_TYPE_FSL_E | MMU_FTR_BIG_PHYS, .icache_bsize = 64, .dcache_bsize = 64, .num_pmcs = 4, @@ -1638,6 +1750,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_user_features = COMMON_USER_BOOKE | PPC_FEATURE_HAS_SPE_COMP | PPC_FEATURE_HAS_EFP_SINGLE_COMP, + .mmu_features = MMU_FTR_TYPE_FSL_E, .icache_bsize = 32, .dcache_bsize = 32, .machine_check = machine_check_e500, diff --git a/arch/powerpc/kernel/dma.c b/arch/powerpc/kernel/dma.c index 3a6eaa876ee1169026837a52fcb119a95def9bd3..1c5c8a6fc129ff825bd1b4cb4da985e15ba85707 100644 --- a/arch/powerpc/kernel/dma.c +++ b/arch/powerpc/kernel/dma.c @@ -120,6 +120,26 @@ static inline void dma_direct_unmap_page(struct device *dev, { } +#ifdef CONFIG_NOT_COHERENT_CACHE +static inline void dma_direct_sync_sg(struct device *dev, + struct scatterlist *sgl, int nents, + enum dma_data_direction direction) +{ + struct scatterlist *sg; + int i; + + for_each_sg(sgl, sg, nents, i) + __dma_sync_page(sg_page(sg), sg->offset, sg->length, direction); +} + +static inline void dma_direct_sync_single_range(struct device *dev, + dma_addr_t dma_handle, unsigned long offset, size_t size, + enum dma_data_direction direction) +{ + __dma_sync(bus_to_virt(dma_handle+offset), size, direction); +} +#endif + struct dma_mapping_ops dma_direct_ops = { .alloc_coherent = dma_direct_alloc_coherent, .free_coherent = dma_direct_free_coherent, @@ -128,5 +148,11 @@ struct dma_mapping_ops dma_direct_ops = { .dma_supported = dma_direct_dma_supported, .map_page = dma_direct_map_page, .unmap_page = dma_direct_unmap_page, +#ifdef CONFIG_NOT_COHERENT_CACHE + .sync_single_range_for_cpu = dma_direct_sync_single_range, + .sync_single_range_for_device = dma_direct_sync_single_range, + .sync_sg_for_cpu = dma_direct_sync_sg, + .sync_sg_for_device = dma_direct_sync_sg, +#endif }; EXPORT_SYMBOL(dma_direct_ops); diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index 7ecc0d1855c3342d341a8b00ea9cdbd9f51d1b42..6f7eb7e00c79eb3df9c6eba5ad61087e36427015 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S @@ -1162,39 +1162,17 @@ machine_check_in_rtas: #ifdef CONFIG_DYNAMIC_FTRACE _GLOBAL(mcount) _GLOBAL(_mcount) - stwu r1,-48(r1) - stw r3, 12(r1) - stw r4, 16(r1) - stw r5, 20(r1) - stw r6, 24(r1) - mflr r3 - stw r7, 28(r1) - mfcr r5 - stw r8, 32(r1) - stw r9, 36(r1) - stw r10,40(r1) - stw r3, 44(r1) - stw r5, 8(r1) - subi r3, r3, MCOUNT_INSN_SIZE - .globl mcount_call -mcount_call: - bl ftrace_stub - nop - lwz r6, 8(r1) - lwz r0, 44(r1) - lwz r3, 12(r1) + /* + * It is required that _mcount on PPC32 must preserve the + * link register. But we have r0 to play with. We use r0 + * to push the return address back to the caller of mcount + * into the ctr register, restore the link register and + * then jump back using the ctr register. + */ + mflr r0 mtctr r0 - lwz r4, 16(r1) - mtcr r6 - lwz r5, 20(r1) - lwz r6, 24(r1) - lwz r0, 52(r1) - lwz r7, 28(r1) - lwz r8, 32(r1) + lwz r0, 4(r1) mtlr r0 - lwz r9, 36(r1) - lwz r10,40(r1) - addi r1, r1, 48 bctr _GLOBAL(ftrace_caller) diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index e0bcf93542867d79e20c1d5951397813535545a2..383ed6eb00850d2a7ab89b3b54b4677a3b9b1478 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -894,18 +894,6 @@ _GLOBAL(enter_prom) #ifdef CONFIG_DYNAMIC_FTRACE _GLOBAL(mcount) _GLOBAL(_mcount) - /* Taken from output of objdump from lib64/glibc */ - mflr r3 - stdu r1, -112(r1) - std r3, 128(r1) - subi r3, r3, MCOUNT_INSN_SIZE - .globl mcount_call -mcount_call: - bl ftrace_stub - nop - ld r0, 128(r1) - mtlr r0 - addi r1, r1, 112 blr _GLOBAL(ftrace_caller) diff --git a/arch/powerpc/kernel/ftrace.c b/arch/powerpc/kernel/ftrace.c index f4b006ed0ab1ef183a0b0593520be182f4144c1f..5355244c99ff934abde18ce75336fe9a37689bcb 100644 --- a/arch/powerpc/kernel/ftrace.c +++ b/arch/powerpc/kernel/ftrace.c @@ -9,22 +9,30 @@ #include #include +#include +#include #include #include #include #include #include +#include #include +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(fmt , ...) do { } while (0) +#endif -static unsigned int ftrace_nop = 0x60000000; +static unsigned int ftrace_nop = PPC_NOP_INSTR; #ifdef CONFIG_PPC32 # define GET_ADDR(addr) addr #else /* PowerPC64's functions are data that points to the functions */ -# define GET_ADDR(addr) *(unsigned long *)addr +# define GET_ADDR(addr) (*(unsigned long *)addr) #endif @@ -33,12 +41,12 @@ static unsigned int ftrace_calc_offset(long ip, long addr) return (int)(addr - ip); } -unsigned char *ftrace_nop_replace(void) +static unsigned char *ftrace_nop_replace(void) { return (char *)&ftrace_nop; } -unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) +static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) { static unsigned int op; @@ -68,49 +76,422 @@ unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) # define _ASM_PTR " .long " #endif -int +static int ftrace_modify_code(unsigned long ip, unsigned char *old_code, unsigned char *new_code) { - unsigned replaced; - unsigned old = *(unsigned *)old_code; - unsigned new = *(unsigned *)new_code; - int faulted = 0; + unsigned char replaced[MCOUNT_INSN_SIZE]; /* * Note: Due to modules and __init, code can * disappear and change, we need to protect against faulting - * as well as code changing. + * as well as code changing. We do this by using the + * probe_kernel_* functions. * * No real locking needed, this code is run through - * kstop_machine. + * kstop_machine, or before SMP starts. */ - asm volatile ( - "1: lwz %1, 0(%2)\n" - " cmpw %1, %5\n" - " bne 2f\n" - " stwu %3, 0(%2)\n" - "2:\n" - ".section .fixup, \"ax\"\n" - "3: li %0, 1\n" - " b 2b\n" - ".previous\n" - ".section __ex_table,\"a\"\n" - _ASM_ALIGN "\n" - _ASM_PTR "1b, 3b\n" - ".previous" - : "=r"(faulted), "=r"(replaced) - : "r"(ip), "r"(new), - "0"(faulted), "r"(old) - : "memory"); - - if (replaced != old && replaced != new) - faulted = 2; - - if (!faulted) - flush_icache_range(ip, ip + 8); - - return faulted; + + /* read the text we want to modify */ + if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE)) + return -EFAULT; + + /* Make sure it is what we expect it to be */ + if (memcmp(replaced, old_code, MCOUNT_INSN_SIZE) != 0) + return -EINVAL; + + /* replace the text with the new text */ + if (probe_kernel_write((void *)ip, new_code, MCOUNT_INSN_SIZE)) + return -EPERM; + + flush_icache_range(ip, ip + 8); + + return 0; +} + +/* + * Helper functions that are the same for both PPC64 and PPC32. + */ +static int test_24bit_addr(unsigned long ip, unsigned long addr) +{ + + /* use the create_branch to verify that this offset can be branched */ + return create_branch((unsigned int *)ip, addr, 0); +} + +static int is_bl_op(unsigned int op) +{ + return (op & 0xfc000003) == 0x48000001; +} + +static unsigned long find_bl_target(unsigned long ip, unsigned int op) +{ + static int offset; + + offset = (op & 0x03fffffc); + /* make it signed */ + if (offset & 0x02000000) + offset |= 0xfe000000; + + return ip + (long)offset; +} + +#ifdef CONFIG_PPC64 +static int +__ftrace_make_nop(struct module *mod, + struct dyn_ftrace *rec, unsigned long addr) +{ + unsigned int op; + unsigned int jmp[5]; + unsigned long ptr; + unsigned long ip = rec->ip; + unsigned long tramp; + int offset; + + /* read where this goes */ + if (probe_kernel_read(&op, (void *)ip, sizeof(int))) + return -EFAULT; + + /* Make sure that that this is still a 24bit jump */ + if (!is_bl_op(op)) { + printk(KERN_ERR "Not expected bl: opcode is %x\n", op); + return -EINVAL; + } + + /* lets find where the pointer goes */ + tramp = find_bl_target(ip, op); + + /* + * On PPC64 the trampoline looks like: + * 0x3d, 0x82, 0x00, 0x00, addis r12,r2, + * 0x39, 0x8c, 0x00, 0x00, addi r12,r12, + * Where the bytes 2,3,6 and 7 make up the 32bit offset + * to the TOC that holds the pointer. + * to jump to. + * 0xf8, 0x41, 0x00, 0x28, std r2,40(r1) + * 0xe9, 0x6c, 0x00, 0x20, ld r11,32(r12) + * The actually address is 32 bytes from the offset + * into the TOC. + * 0xe8, 0x4c, 0x00, 0x28, ld r2,40(r12) + */ + + DEBUGP("ip:%lx jumps to %lx r2: %lx", ip, tramp, mod->arch.toc); + + /* Find where the trampoline jumps to */ + if (probe_kernel_read(jmp, (void *)tramp, sizeof(jmp))) { + printk(KERN_ERR "Failed to read %lx\n", tramp); + return -EFAULT; + } + + DEBUGP(" %08x %08x", jmp[0], jmp[1]); + + /* verify that this is what we expect it to be */ + if (((jmp[0] & 0xffff0000) != 0x3d820000) || + ((jmp[1] & 0xffff0000) != 0x398c0000) || + (jmp[2] != 0xf8410028) || + (jmp[3] != 0xe96c0020) || + (jmp[4] != 0xe84c0028)) { + printk(KERN_ERR "Not a trampoline\n"); + return -EINVAL; + } + + offset = (unsigned)((unsigned short)jmp[0]) << 16 | + (unsigned)((unsigned short)jmp[1]); + + DEBUGP(" %x ", offset); + + /* get the address this jumps too */ + tramp = mod->arch.toc + offset + 32; + DEBUGP("toc: %lx", tramp); + + if (probe_kernel_read(jmp, (void *)tramp, 8)) { + printk(KERN_ERR "Failed to read %lx\n", tramp); + return -EFAULT; + } + + DEBUGP(" %08x %08x\n", jmp[0], jmp[1]); + + ptr = ((unsigned long)jmp[0] << 32) + jmp[1]; + + /* This should match what was called */ + if (ptr != GET_ADDR(addr)) { + printk(KERN_ERR "addr does not match %lx\n", ptr); + return -EINVAL; + } + + /* + * We want to nop the line, but the next line is + * 0xe8, 0x41, 0x00, 0x28 ld r2,40(r1) + * This needs to be turned to a nop too. + */ + if (probe_kernel_read(&op, (void *)(ip+4), MCOUNT_INSN_SIZE)) + return -EFAULT; + + if (op != 0xe8410028) { + printk(KERN_ERR "Next line is not ld! (%08x)\n", op); + return -EINVAL; + } + + /* + * Milton Miller pointed out that we can not blindly do nops. + * If a task was preempted when calling a trace function, + * the nops will remove the way to restore the TOC in r2 + * and the r2 TOC will get corrupted. + */ + + /* + * Replace: + * bl <==== will be replaced with "b 1f" + * ld r2,40(r1) + * 1: + */ + op = 0x48000008; /* b +8 */ + + if (probe_kernel_write((void *)ip, &op, MCOUNT_INSN_SIZE)) + return -EPERM; + + + flush_icache_range(ip, ip + 8); + + return 0; +} + +#else /* !PPC64 */ +static int +__ftrace_make_nop(struct module *mod, + struct dyn_ftrace *rec, unsigned long addr) +{ + unsigned int op; + unsigned int jmp[4]; + unsigned long ip = rec->ip; + unsigned long tramp; + + if (probe_kernel_read(&op, (void *)ip, MCOUNT_INSN_SIZE)) + return -EFAULT; + + /* Make sure that that this is still a 24bit jump */ + if (!is_bl_op(op)) { + printk(KERN_ERR "Not expected bl: opcode is %x\n", op); + return -EINVAL; + } + + /* lets find where the pointer goes */ + tramp = find_bl_target(ip, op); + + /* + * On PPC32 the trampoline looks like: + * 0x3d, 0x60, 0x00, 0x00 lis r11,sym@ha + * 0x39, 0x6b, 0x00, 0x00 addi r11,r11,sym@l + * 0x7d, 0x69, 0x03, 0xa6 mtctr r11 + * 0x4e, 0x80, 0x04, 0x20 bctr + */ + + DEBUGP("ip:%lx jumps to %lx", ip, tramp); + + /* Find where the trampoline jumps to */ + if (probe_kernel_read(jmp, (void *)tramp, sizeof(jmp))) { + printk(KERN_ERR "Failed to read %lx\n", tramp); + return -EFAULT; + } + + DEBUGP(" %08x %08x ", jmp[0], jmp[1]); + + /* verify that this is what we expect it to be */ + if (((jmp[0] & 0xffff0000) != 0x3d600000) || + ((jmp[1] & 0xffff0000) != 0x396b0000) || + (jmp[2] != 0x7d6903a6) || + (jmp[3] != 0x4e800420)) { + printk(KERN_ERR "Not a trampoline\n"); + return -EINVAL; + } + + tramp = (jmp[1] & 0xffff) | + ((jmp[0] & 0xffff) << 16); + if (tramp & 0x8000) + tramp -= 0x10000; + + DEBUGP(" %x ", tramp); + + if (tramp != addr) { + printk(KERN_ERR + "Trampoline location %08lx does not match addr\n", + tramp); + return -EINVAL; + } + + op = PPC_NOP_INSTR; + + if (probe_kernel_write((void *)ip, &op, MCOUNT_INSN_SIZE)) + return -EPERM; + + flush_icache_range(ip, ip + 8); + + return 0; +} +#endif /* PPC64 */ + +int ftrace_make_nop(struct module *mod, + struct dyn_ftrace *rec, unsigned long addr) +{ + unsigned char *old, *new; + unsigned long ip = rec->ip; + + /* + * If the calling address is more that 24 bits away, + * then we had to use a trampoline to make the call. + * Otherwise just update the call site. + */ + if (test_24bit_addr(ip, addr)) { + /* within range */ + old = ftrace_call_replace(ip, addr); + new = ftrace_nop_replace(); + return ftrace_modify_code(ip, old, new); + } + + /* + * Out of range jumps are called from modules. + * We should either already have a pointer to the module + * or it has been passed in. + */ + if (!rec->arch.mod) { + if (!mod) { + printk(KERN_ERR "No module loaded addr=%lx\n", + addr); + return -EFAULT; + } + rec->arch.mod = mod; + } else if (mod) { + if (mod != rec->arch.mod) { + printk(KERN_ERR + "Record mod %p not equal to passed in mod %p\n", + rec->arch.mod, mod); + return -EINVAL; + } + /* nothing to do if mod == rec->arch.mod */ + } else + mod = rec->arch.mod; + + return __ftrace_make_nop(mod, rec, addr); + +} + +#ifdef CONFIG_PPC64 +static int +__ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) +{ + unsigned int op[2]; + unsigned long ip = rec->ip; + + /* read where this goes */ + if (probe_kernel_read(op, (void *)ip, MCOUNT_INSN_SIZE * 2)) + return -EFAULT; + + /* + * It should be pointing to two nops or + * b +8; ld r2,40(r1) + */ + if (((op[0] != 0x48000008) || (op[1] != 0xe8410028)) && + ((op[0] != PPC_NOP_INSTR) || (op[1] != PPC_NOP_INSTR))) { + printk(KERN_ERR "Expected NOPs but have %x %x\n", op[0], op[1]); + return -EINVAL; + } + + /* If we never set up a trampoline to ftrace_caller, then bail */ + if (!rec->arch.mod->arch.tramp) { + printk(KERN_ERR "No ftrace trampoline\n"); + return -EINVAL; + } + + /* create the branch to the trampoline */ + op[0] = create_branch((unsigned int *)ip, + rec->arch.mod->arch.tramp, BRANCH_SET_LINK); + if (!op[0]) { + printk(KERN_ERR "REL24 out of range!\n"); + return -EINVAL; + } + + /* ld r2,40(r1) */ + op[1] = 0xe8410028; + + DEBUGP("write to %lx\n", rec->ip); + + if (probe_kernel_write((void *)ip, op, MCOUNT_INSN_SIZE * 2)) + return -EPERM; + + flush_icache_range(ip, ip + 8); + + return 0; +} +#else +static int +__ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) +{ + unsigned int op; + unsigned long ip = rec->ip; + + /* read where this goes */ + if (probe_kernel_read(&op, (void *)ip, MCOUNT_INSN_SIZE)) + return -EFAULT; + + /* It should be pointing to a nop */ + if (op != PPC_NOP_INSTR) { + printk(KERN_ERR "Expected NOP but have %x\n", op); + return -EINVAL; + } + + /* If we never set up a trampoline to ftrace_caller, then bail */ + if (!rec->arch.mod->arch.tramp) { + printk(KERN_ERR "No ftrace trampoline\n"); + return -EINVAL; + } + + /* create the branch to the trampoline */ + op = create_branch((unsigned int *)ip, + rec->arch.mod->arch.tramp, BRANCH_SET_LINK); + if (!op) { + printk(KERN_ERR "REL24 out of range!\n"); + return -EINVAL; + } + + DEBUGP("write to %lx\n", rec->ip); + + if (probe_kernel_write((void *)ip, &op, MCOUNT_INSN_SIZE)) + return -EPERM; + + flush_icache_range(ip, ip + 8); + + return 0; +} +#endif /* CONFIG_PPC64 */ + +int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) +{ + unsigned char *old, *new; + unsigned long ip = rec->ip; + + /* + * If the calling address is more that 24 bits away, + * then we had to use a trampoline to make the call. + * Otherwise just update the call site. + */ + if (test_24bit_addr(ip, addr)) { + /* within range */ + old = ftrace_nop_replace(); + new = ftrace_call_replace(ip, addr); + return ftrace_modify_code(ip, old, new); + } + + /* + * Out of range jumps are called from modules. + * Being that we are converting from nop, it had better + * already have a module defined. + */ + if (!rec->arch.mod) { + printk(KERN_ERR "No module loaded\n"); + return -EINVAL; + } + + return __ftrace_make_call(rec, addr); } int ftrace_update_ftrace_func(ftrace_func_t func) @@ -128,10 +509,10 @@ int ftrace_update_ftrace_func(ftrace_func_t func) int __init ftrace_dyn_arch_init(void *data) { - /* This is running in kstop_machine */ + /* caller expects data to be zero */ + unsigned long *p = data; - ftrace_mcount_set(data); + *p = 0; return 0; } - diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S index 0c326823c6d4caf088663efd2c68804c6696d983..a1c4cfd25dedb0fee8e01cdddd8ba66f76f0dc88 100644 --- a/arch/powerpc/kernel/head_32.S +++ b/arch/powerpc/kernel/head_32.S @@ -31,6 +31,7 @@ #include #include #include +#include /* 601 only have IBAT; cr0.eq is set on 601 when using this macro */ #define LOAD_BAT(n, reg, RA, RB) \ @@ -182,7 +183,8 @@ __after_mmu_off: bl reloc_offset mr r26,r3 addis r4,r3,KERNELBASE@h /* current address of _start */ - cmpwi 0,r4,0 /* are we already running at 0? */ + lis r5,PHYSICAL_START@h + cmplw 0,r4,r5 /* already running at PHYSICAL_START? */ bne relocate_kernel /* * we now have the 1st 16M of ram mapped with the bats. @@ -810,13 +812,13 @@ giveup_altivec: /* * This code is jumped to from the startup code to copy - * the kernel image to physical address 0. + * the kernel image to physical address PHYSICAL_START. */ relocate_kernel: addis r9,r26,klimit@ha /* fetch klimit */ lwz r25,klimit@l(r9) addis r25,r25,-KERNELBASE@h - li r3,0 /* Destination base address */ + lis r3,PHYSICAL_START@h /* Destination base address */ li r6,0 /* Destination offset */ li r5,0x4000 /* # bytes of memory to copy */ bl copy_and_flush /* copy the first 0x4000 bytes */ @@ -989,12 +991,12 @@ load_up_mmu: LOAD_BAT(1,r3,r4,r5) LOAD_BAT(2,r3,r4,r5) LOAD_BAT(3,r3,r4,r5) -BEGIN_FTR_SECTION +BEGIN_MMU_FTR_SECTION LOAD_BAT(4,r3,r4,r5) LOAD_BAT(5,r3,r4,r5) LOAD_BAT(6,r3,r4,r5) LOAD_BAT(7,r3,r4,r5) -END_FTR_SECTION_IFSET(CPU_FTR_HAS_HIGH_BATS) +END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS) blr /* @@ -1070,9 +1072,14 @@ start_here: RFI /* + * void switch_mmu_context(struct mm_struct *prev, struct mm_struct *next); + * * Set up the segment registers for a new context. */ -_ENTRY(set_context) +_ENTRY(switch_mmu_context) + lwz r3,MMCONTEXTID(r4) + cmpwi cr0,r3,0 + blt- 4f mulli r3,r3,897 /* multiply context by skew factor */ rlwinm r3,r3,4,8,27 /* VSID = (context & 0xfffff) << 4 */ addis r3,r3,0x6000 /* Set Ks, Ku bits */ @@ -1083,6 +1090,7 @@ _ENTRY(set_context) /* Context switch the PTE pointer for the Abatron BDI2000. * The PGDIR is passed as second argument. */ + lwz r4,MM_PGD(r4) lis r5, KERNELBASE@h lwz r5, 0xf0(r5) stw r4, 0x4(r5) @@ -1098,6 +1106,9 @@ _ENTRY(set_context) sync isync blr +4: trap + EMIT_BUG_ENTRY 4b,__FILE__,__LINE__,0 + blr /* * An undocumented "feature" of 604e requires that the v bit @@ -1131,7 +1142,7 @@ clear_bats: mtspr SPRN_IBAT2L,r10 mtspr SPRN_IBAT3U,r10 mtspr SPRN_IBAT3L,r10 -BEGIN_FTR_SECTION +BEGIN_MMU_FTR_SECTION /* Here's a tweak: at this point, CPU setup have * not been called yet, so HIGH_BAT_EN may not be * set in HID0 for the 745x processors. However, it @@ -1154,7 +1165,7 @@ BEGIN_FTR_SECTION mtspr SPRN_IBAT6L,r10 mtspr SPRN_IBAT7U,r10 mtspr SPRN_IBAT7L,r10 -END_FTR_SECTION_IFSET(CPU_FTR_HAS_HIGH_BATS) +END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS) blr flush_tlbs: @@ -1178,11 +1189,11 @@ mmu_off: /* * Use the first pair of BAT registers to map the 1st 16MB - * of RAM to KERNELBASE. From this point on we can't safely + * of RAM to PAGE_OFFSET. From this point on we can't safely * call OF any more. */ initial_bats: - lis r11,KERNELBASE@h + lis r11,PAGE_OFFSET@h mfspr r9,SPRN_PVR rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ cmpwi 0,r9,1 diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S index f3a1ea9d7fe44d8e45371d3f9b91863277fa4756..b56fecc93a16c68f2f9b40ed18304d996c9e343e 100644 --- a/arch/powerpc/kernel/head_44x.S +++ b/arch/powerpc/kernel/head_44x.S @@ -68,6 +68,17 @@ _ENTRY(_start); mr r27,r7 li r24,0 /* CPU number */ +/* + * In case the firmware didn't do it, we apply some workarounds + * that are good for all 440 core variants here + */ + mfspr r3,SPRN_CCR0 + rlwinm r3,r3,0,0,27 /* disable icache prefetch */ + isync + mtspr SPRN_CCR0,r3 + isync + sync + /* * Set up the initial MMU state * @@ -391,12 +402,14 @@ interrupt_base: rlwimi r13,r12,10,30,30 /* Load the PTE */ - rlwinm r12, r10, 13, 19, 29 /* Compute pgdir/pmd offset */ + /* Compute pgdir/pmd offset */ + rlwinm r12, r10, PPC44x_PGD_OFF_SHIFT, PPC44x_PGD_OFF_MASK_BIT, 29 lwzx r11, r12, r11 /* Get pgd/pmd entry */ rlwinm. r12, r11, 0, 0, 20 /* Extract pt base address */ beq 2f /* Bail if no table */ - rlwimi r12, r10, 23, 20, 28 /* Compute pte address */ + /* Compute pte address */ + rlwimi r12, r10, PPC44x_PTE_ADD_SHIFT, PPC44x_PTE_ADD_MASK_BIT, 28 lwz r11, 0(r12) /* Get high word of pte entry */ lwz r12, 4(r12) /* Get low word of pte entry */ @@ -485,12 +498,14 @@ tlb_44x_patch_hwater_D: /* Make up the required permissions */ li r13,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_HWEXEC - rlwinm r12, r10, 13, 19, 29 /* Compute pgdir/pmd offset */ + /* Compute pgdir/pmd offset */ + rlwinm r12, r10, PPC44x_PGD_OFF_SHIFT, PPC44x_PGD_OFF_MASK_BIT, 29 lwzx r11, r12, r11 /* Get pgd/pmd entry */ rlwinm. r12, r11, 0, 0, 20 /* Extract pt base address */ beq 2f /* Bail if no table */ - rlwimi r12, r10, 23, 20, 28 /* Compute pte address */ + /* Compute pte address */ + rlwimi r12, r10, PPC44x_PTE_ADD_SHIFT, PPC44x_PTE_ADD_MASK_BIT, 28 lwz r11, 0(r12) /* Get high word of pte entry */ lwz r12, 4(r12) /* Get low word of pte entry */ @@ -554,15 +569,16 @@ tlb_44x_patch_hwater_I: */ finish_tlb_load: /* Combine RPN & ERPN an write WS 0 */ - rlwimi r11,r12,0,0,19 + rlwimi r11,r12,0,0,31-PAGE_SHIFT tlbwe r11,r13,PPC44x_TLB_XLAT /* * Create WS1. This is the faulting address (EPN), * page size, and valid flag. */ - li r11,PPC44x_TLB_VALID | PPC44x_TLB_4K - rlwimi r10,r11,0,20,31 /* Insert valid and page size*/ + li r11,PPC44x_TLB_VALID | PPC44x_TLBE_SIZE + /* Insert valid and page size */ + rlwimi r10,r11,0,PPC44x_PTE_ADD_MASK_BIT,31 tlbwe r10,r13,PPC44x_TLB_PAGEID /* Write PAGEID */ /* And WS 2 */ @@ -634,12 +650,12 @@ _GLOBAL(set_context) * goes at the beginning of the data segment, which is page-aligned. */ .data - .align 12 + .align PAGE_SHIFT .globl sdata sdata: .globl empty_zero_page empty_zero_page: - .space 4096 + .space PAGE_SIZE /* * To support >32-bit physical addresses, we use an 8KB pgdir. diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S index 590304c24dad37ea5d49f06c6176eb9ae1aab2ac..11b549acc0340909d3f5b253e73d12ec7fa3e589 100644 --- a/arch/powerpc/kernel/head_fsl_booke.S +++ b/arch/powerpc/kernel/head_fsl_booke.S @@ -92,6 +92,7 @@ _ENTRY(_start); * if needed */ +_ENTRY(__early_start) /* 1. Find the index of the entry we're executing in */ bl invstr /* Find our address */ invstr: mflr r6 /* Make it accessible */ @@ -235,36 +236,40 @@ skpinv: addi r6,r6,1 /* Increment */ tlbivax 0,r9 TLBSYNC +/* The mapping only needs to be cache-coherent on SMP */ +#ifdef CONFIG_SMP +#define M_IF_SMP MAS2_M +#else +#define M_IF_SMP 0 +#endif + /* 6. Setup KERNELBASE mapping in TLB1[0] */ lis r6,0x1000 /* Set MAS0(TLBSEL) = TLB1(1), ESEL = 0 */ mtspr SPRN_MAS0,r6 lis r6,(MAS1_VALID|MAS1_IPROT)@h ori r6,r6,(MAS1_TSIZE(BOOKE_PAGESZ_64M))@l mtspr SPRN_MAS1,r6 - li r7,0 - lis r6,PAGE_OFFSET@h - ori r6,r6,PAGE_OFFSET@l - rlwimi r6,r7,0,20,31 + lis r6,MAS2_VAL(PAGE_OFFSET, BOOKE_PAGESZ_64M, M_IF_SMP)@h + ori r6,r6,MAS2_VAL(PAGE_OFFSET, BOOKE_PAGESZ_64M, M_IF_SMP)@l mtspr SPRN_MAS2,r6 mtspr SPRN_MAS3,r8 tlbwe /* 7. Jump to KERNELBASE mapping */ - lis r6,KERNELBASE@h - ori r6,r6,KERNELBASE@l - rlwimi r6,r7,0,20,31 + lis r6,(KERNELBASE & ~0xfff)@h + ori r6,r6,(KERNELBASE & ~0xfff)@l lis r7,MSR_KERNEL@h ori r7,r7,MSR_KERNEL@l bl 1f /* Find our address */ 1: mflr r9 rlwimi r6,r9,0,20,31 - addi r6,r6,24 + addi r6,r6,(2f - 1b) mtspr SPRN_SRR0,r6 mtspr SPRN_SRR1,r7 rfi /* start execution out of TLB1[0] entry */ /* 8. Clear out the temp mapping */ - lis r7,0x1000 /* Set MAS0(TLBSEL) = 1 */ +2: lis r7,0x1000 /* Set MAS0(TLBSEL) = 1 */ rlwimi r7,r5,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r5) */ mtspr SPRN_MAS0,r7 tlbre @@ -344,6 +349,15 @@ skpinv: addi r6,r6,1 /* Increment */ mtspr SPRN_DBSR,r2 #endif +#ifdef CONFIG_SMP + /* Check to see if we're the second processor, and jump + * to the secondary_start code if so + */ + mfspr r24,SPRN_PIR + cmpwi r24,0 + bne __secondary_start +#endif + /* * This is where the main kernel code starts. */ @@ -685,12 +699,13 @@ interrupt_base: /* SPE Floating Point Data */ #ifdef CONFIG_SPE EXCEPTION(0x2030, SPEFloatingPointData, SPEFloatingPointException, EXC_XFER_EE); -#else - EXCEPTION(0x2040, SPEFloatingPointData, unknown_exception, EXC_XFER_EE) -#endif /* CONFIG_SPE */ /* SPE Floating Point Round */ + EXCEPTION(0x2050, SPEFloatingPointRound, SPEFloatingPointRoundException, EXC_XFER_EE) +#else + EXCEPTION(0x2040, SPEFloatingPointData, unknown_exception, EXC_XFER_EE) EXCEPTION(0x2050, SPEFloatingPointRound, unknown_exception, EXC_XFER_EE) +#endif /* CONFIG_SPE */ /* Performance Monitor */ EXCEPTION(0x2060, PerformanceMonitor, performance_monitor_exception, EXC_XFER_STD) @@ -734,6 +749,9 @@ finish_tlb_load: rlwimi r12, r11, 26, 24, 31 /* extract ...WIMGE from pte */ #else rlwimi r12, r11, 26, 27, 31 /* extract WIMGE from pte */ +#endif +#ifdef CONFIG_SMP + ori r12, r12, MAS2_M #endif mtspr SPRN_MAS2, r12 @@ -746,15 +764,15 @@ finish_tlb_load: iseleq r12, r12, r10 #ifdef CONFIG_PTE_64BIT -2: rlwimi r12, r13, 24, 0, 7 /* grab RPN[32:39] */ + rlwimi r12, r13, 24, 0, 7 /* grab RPN[32:39] */ rlwimi r12, r11, 24, 8, 19 /* grab RPN[40:51] */ mtspr SPRN_MAS3, r12 -BEGIN_FTR_SECTION +BEGIN_MMU_FTR_SECTION srwi r10, r13, 8 /* grab RPN[8:31] */ mtspr SPRN_MAS7, r10 -END_FTR_SECTION_IFSET(CPU_FTR_BIG_PHYS) +END_MMU_FTR_SECTION_IFSET(MMU_FTR_BIG_PHYS) #else -2: rlwimi r11, r12, 0, 20, 31 /* Extract RPN from PTE and merge with perms */ + rlwimi r11, r12, 0, 20, 31 /* Extract RPN from PTE and merge with perms */ mtspr SPRN_MAS3, r11 #endif #ifdef CONFIG_E200 @@ -1037,6 +1055,63 @@ _GLOBAL(flush_dcache_L1) blr +#ifdef CONFIG_SMP +/* When we get here, r24 needs to hold the CPU # */ + .globl __secondary_start +__secondary_start: + lis r3,__secondary_hold_acknowledge@h + ori r3,r3,__secondary_hold_acknowledge@l + stw r24,0(r3) + + li r3,0 + mr r4,r24 /* Why? */ + bl call_setup_cpu + + lis r3,tlbcam_index@ha + lwz r3,tlbcam_index@l(r3) + mtctr r3 + li r26,0 /* r26 safe? */ + + /* Load each CAM entry */ +1: mr r3,r26 + bl loadcam_entry + addi r26,r26,1 + bdnz 1b + + /* get current_thread_info and current */ + lis r1,secondary_ti@ha + lwz r1,secondary_ti@l(r1) + lwz r2,TI_TASK(r1) + + /* stack */ + addi r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD + li r0,0 + stw r0,0(r1) + + /* ptr to current thread */ + addi r4,r2,THREAD /* address of our thread_struct */ + mtspr SPRN_SPRG3,r4 + + /* Setup the defaults for TLB entries */ + li r4,(MAS4_TSIZED(BOOKE_PAGESZ_4K))@l + mtspr SPRN_MAS4,r4 + + /* Jump to start_secondary */ + lis r4,MSR_KERNEL@h + ori r4,r4,MSR_KERNEL@l + lis r3,start_secondary@h + ori r3,r3,start_secondary@l + mtspr SPRN_SRR0,r3 + mtspr SPRN_SRR1,r4 + sync + rfi + sync + + .globl __secondary_hold_acknowledge +__secondary_hold_acknowledge: + .long -1 +#endif + /* * We put a few things here that have to be page-aligned. This stuff * goes at the beginning of the data segment, which is page-aligned. diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c index 64299d28f36485d3441e0b59604228e141712cb1..6e3f62493659abc79e68f6795f14dd3d52d8cab1 100644 --- a/arch/powerpc/kernel/ibmebus.c +++ b/arch/powerpc/kernel/ibmebus.c @@ -47,7 +47,7 @@ #include static struct device ibmebus_bus_device = { /* fake "parent" device */ - .bus_id = "ibmebus", + .init_name = "ibmebus", }; struct bus_type ibmebus_bus_type; @@ -231,6 +231,7 @@ void ibmebus_free_irq(u32 ist, void *dev_id) unsigned int irq = irq_find_mapping(NULL, ist); free_irq(irq, dev_id); + irq_dispose_mapping(irq); } EXPORT_SYMBOL(ibmebus_free_irq); diff --git a/arch/powerpc/kernel/idle.c b/arch/powerpc/kernel/idle.c index 31982d05d81a8814d73dfc8b5a562cd90b66e5d3..88d9c1d5e5fb0aea1e74757ae9ac1133e9f352ef 100644 --- a/arch/powerpc/kernel/idle.c +++ b/arch/powerpc/kernel/idle.c @@ -69,10 +69,15 @@ void cpu_idle(void) smp_mb(); local_irq_disable(); + /* Don't trace irqs off for idle */ + stop_critical_timings(); + /* check again after disabling irqs */ if (!need_resched() && !cpu_should_die()) ppc_md.power_save(); + start_critical_timings(); + local_irq_enable(); set_thread_flag(TIF_POLLING_NRFLAG); diff --git a/arch/powerpc/kernel/machine_kexec.c b/arch/powerpc/kernel/machine_kexec.c index ac2a21f45c757a41f8ab639abca5a449d6576207..b3abebb7ee64641420fd81fd796b5c13282dccbf 100644 --- a/arch/powerpc/kernel/machine_kexec.c +++ b/arch/powerpc/kernel/machine_kexec.c @@ -13,13 +13,17 @@ #include #include #include +#include #include #include +#include void machine_crash_shutdown(struct pt_regs *regs) { if (ppc_md.machine_crash_shutdown) ppc_md.machine_crash_shutdown(regs); + else + default_machine_crash_shutdown(regs); } /* @@ -31,11 +35,8 @@ int machine_kexec_prepare(struct kimage *image) { if (ppc_md.machine_kexec_prepare) return ppc_md.machine_kexec_prepare(image); - /* - * Fail if platform doesn't provide its own machine_kexec_prepare - * implementation. - */ - return -ENOSYS; + else + return default_machine_kexec_prepare(image); } void machine_kexec_cleanup(struct kimage *image) @@ -52,13 +53,11 @@ void machine_kexec(struct kimage *image) { if (ppc_md.machine_kexec) ppc_md.machine_kexec(image); - else { - /* - * Fall back to normal restart if platform doesn't provide - * its own kexec function, and user insist to kexec... - */ - machine_restart(NULL); - } + else + default_machine_kexec(image); + + /* Fall back to normal restart if we're still alive. */ + machine_restart(NULL); for(;;); } @@ -118,3 +117,71 @@ int overlaps_crashkernel(unsigned long start, unsigned long size) { return (start + size) > crashk_res.start && start <= crashk_res.end; } + +/* Values we need to export to the second kernel via the device tree. */ +static unsigned long kernel_end; +static unsigned long crashk_size; + +static struct property kernel_end_prop = { + .name = "linux,kernel-end", + .length = sizeof(unsigned long), + .value = &kernel_end, +}; + +static struct property crashk_base_prop = { + .name = "linux,crashkernel-base", + .length = sizeof(unsigned long), + .value = &crashk_res.start, +}; + +static struct property crashk_size_prop = { + .name = "linux,crashkernel-size", + .length = sizeof(unsigned long), + .value = &crashk_size, +}; + +static void __init export_crashk_values(struct device_node *node) +{ + struct property *prop; + + /* There might be existing crash kernel properties, but we can't + * be sure what's in them, so remove them. */ + prop = of_find_property(node, "linux,crashkernel-base", NULL); + if (prop) + prom_remove_property(node, prop); + + prop = of_find_property(node, "linux,crashkernel-size", NULL); + if (prop) + prom_remove_property(node, prop); + + if (crashk_res.start != 0) { + prom_add_property(node, &crashk_base_prop); + crashk_size = crashk_res.end - crashk_res.start + 1; + prom_add_property(node, &crashk_size_prop); + } +} + +static int __init kexec_setup(void) +{ + struct device_node *node; + struct property *prop; + + node = of_find_node_by_path("/chosen"); + if (!node) + return -ENOENT; + + /* remove any stale properties so ours can be found */ + prop = of_find_property(node, kernel_end_prop.name, NULL); + if (prop) + prom_remove_property(node, prop); + + /* information needed by userspace when using default_machine_kexec */ + kernel_end = __pa(_end); + prom_add_property(node, &kernel_end_prop); + + export_crashk_values(node); + + of_node_put(node); + return 0; +} +late_initcall(kexec_setup); diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c index 3c4ca046e854c9e88ab587c1672eae97b2c69c4a..49e705fcee6df804545dd790b6cd0dc7fb6d7ada 100644 --- a/arch/powerpc/kernel/machine_kexec_64.c +++ b/arch/powerpc/kernel/machine_kexec_64.c @@ -289,7 +289,7 @@ void default_machine_kexec(struct kimage *image) } /* Values we need to export to the second kernel via the device tree. */ -static unsigned long htab_base, kernel_end; +static unsigned long htab_base; static struct property htab_base_prop = { .name = "linux,htab-base", @@ -303,25 +303,20 @@ static struct property htab_size_prop = { .value = &htab_size_bytes, }; -static struct property kernel_end_prop = { - .name = "linux,kernel-end", - .length = sizeof(unsigned long), - .value = &kernel_end, -}; - -static void __init export_htab_values(void) +static int __init export_htab_values(void) { struct device_node *node; struct property *prop; + /* On machines with no htab htab_address is NULL */ + if (!htab_address) + return -ENODEV; + node = of_find_node_by_path("/chosen"); if (!node) - return; + return -ENODEV; /* remove any stale propertys so ours can be found */ - prop = of_find_property(node, kernel_end_prop.name, NULL); - if (prop) - prom_remove_property(node, prop); prop = of_find_property(node, htab_base_prop.name, NULL); if (prop) prom_remove_property(node, prop); @@ -329,68 +324,11 @@ static void __init export_htab_values(void) if (prop) prom_remove_property(node, prop); - /* information needed by userspace when using default_machine_kexec */ - kernel_end = __pa(_end); - prom_add_property(node, &kernel_end_prop); - - /* On machines with no htab htab_address is NULL */ - if (NULL == htab_address) - goto out; - htab_base = __pa(htab_address); prom_add_property(node, &htab_base_prop); prom_add_property(node, &htab_size_prop); - out: - of_node_put(node); -} - -static struct property crashk_base_prop = { - .name = "linux,crashkernel-base", - .length = sizeof(unsigned long), - .value = &crashk_res.start, -}; - -static unsigned long crashk_size; - -static struct property crashk_size_prop = { - .name = "linux,crashkernel-size", - .length = sizeof(unsigned long), - .value = &crashk_size, -}; - -static void __init export_crashk_values(void) -{ - struct device_node *node; - struct property *prop; - - node = of_find_node_by_path("/chosen"); - if (!node) - return; - - /* There might be existing crash kernel properties, but we can't - * be sure what's in them, so remove them. */ - prop = of_find_property(node, "linux,crashkernel-base", NULL); - if (prop) - prom_remove_property(node, prop); - - prop = of_find_property(node, "linux,crashkernel-size", NULL); - if (prop) - prom_remove_property(node, prop); - - if (crashk_res.start != 0) { - prom_add_property(node, &crashk_base_prop); - crashk_size = crashk_res.end - crashk_res.start + 1; - prom_add_property(node, &crashk_size_prop); - } - of_node_put(node); -} - -static int __init kexec_setup(void) -{ - export_htab_values(); - export_crashk_values(); return 0; } -__initcall(kexec_setup); +late_initcall(export_htab_values); diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S index 5c33bc14bd9fe161a75d7c12bc6809e77cba5a93..15f28e0de78dae1919c3cf55f6ec77f15f71d9b5 100644 --- a/arch/powerpc/kernel/misc_32.S +++ b/arch/powerpc/kernel/misc_32.S @@ -29,6 +29,7 @@ #include #include #include +#include .text @@ -271,231 +272,6 @@ _GLOBAL(real_writeb) #endif /* CONFIG_40x */ -/* - * Flush MMU TLB - */ -#ifndef CONFIG_FSL_BOOKE -_GLOBAL(_tlbil_all) -_GLOBAL(_tlbil_pid) -#endif -_GLOBAL(_tlbia) -#if defined(CONFIG_40x) - sync /* Flush to memory before changing mapping */ - tlbia - isync /* Flush shadow TLB */ -#elif defined(CONFIG_44x) - li r3,0 - sync - - /* Load high watermark */ - lis r4,tlb_44x_hwater@ha - lwz r5,tlb_44x_hwater@l(r4) - -1: tlbwe r3,r3,PPC44x_TLB_PAGEID - addi r3,r3,1 - cmpw 0,r3,r5 - ble 1b - - isync -#elif defined(CONFIG_FSL_BOOKE) - /* Invalidate all entries in TLB0 */ - li r3, 0x04 - tlbivax 0,3 - /* Invalidate all entries in TLB1 */ - li r3, 0x0c - tlbivax 0,3 - msync -#ifdef CONFIG_SMP - tlbsync -#endif /* CONFIG_SMP */ -#else /* !(CONFIG_40x || CONFIG_44x || CONFIG_FSL_BOOKE) */ -#if defined(CONFIG_SMP) - rlwinm r8,r1,0,0,(31-THREAD_SHIFT) - lwz r8,TI_CPU(r8) - oris r8,r8,10 - mfmsr r10 - SYNC - rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */ - rlwinm r0,r0,0,28,26 /* clear DR */ - mtmsr r0 - SYNC_601 - isync - lis r9,mmu_hash_lock@h - ori r9,r9,mmu_hash_lock@l - tophys(r9,r9) -10: lwarx r7,0,r9 - cmpwi 0,r7,0 - bne- 10b - stwcx. r8,0,r9 - bne- 10b - sync - tlbia - sync - TLBSYNC - li r0,0 - stw r0,0(r9) /* clear mmu_hash_lock */ - mtmsr r10 - SYNC_601 - isync -#else /* CONFIG_SMP */ - sync - tlbia - sync -#endif /* CONFIG_SMP */ -#endif /* ! defined(CONFIG_40x) */ - blr - -/* - * Flush MMU TLB for a particular address - */ -#ifndef CONFIG_FSL_BOOKE -_GLOBAL(_tlbil_va) -#endif -_GLOBAL(_tlbie) -#if defined(CONFIG_40x) - /* We run the search with interrupts disabled because we have to change - * the PID and I don't want to preempt when that happens. - */ - mfmsr r5 - mfspr r6,SPRN_PID - wrteei 0 - mtspr SPRN_PID,r4 - tlbsx. r3, 0, r3 - mtspr SPRN_PID,r6 - wrtee r5 - bne 10f - sync - /* There are only 64 TLB entries, so r3 < 64, which means bit 25 is clear. - * Since 25 is the V bit in the TLB_TAG, loading this value will invalidate - * the TLB entry. */ - tlbwe r3, r3, TLB_TAG - isync -10: - -#elif defined(CONFIG_44x) - mfspr r5,SPRN_MMUCR - rlwimi r5,r4,0,24,31 /* Set TID */ - - /* We have to run the search with interrupts disabled, even critical - * and debug interrupts (in fact the only critical exceptions we have - * are debug and machine check). Otherwise an interrupt which causes - * a TLB miss can clobber the MMUCR between the mtspr and the tlbsx. */ - mfmsr r4 - lis r6,(MSR_EE|MSR_CE|MSR_ME|MSR_DE)@ha - addi r6,r6,(MSR_EE|MSR_CE|MSR_ME|MSR_DE)@l - andc r6,r4,r6 - mtmsr r6 - mtspr SPRN_MMUCR,r5 - tlbsx. r3, 0, r3 - mtmsr r4 - bne 10f - sync - /* There are only 64 TLB entries, so r3 < 64, - * which means bit 22, is clear. Since 22 is - * the V bit in the TLB_PAGEID, loading this - * value will invalidate the TLB entry. - */ - tlbwe r3, r3, PPC44x_TLB_PAGEID - isync -10: -#elif defined(CONFIG_FSL_BOOKE) - rlwinm r4, r3, 0, 0, 19 - ori r5, r4, 0x08 /* TLBSEL = 1 */ - tlbivax 0, r4 - tlbivax 0, r5 - msync -#if defined(CONFIG_SMP) - tlbsync -#endif /* CONFIG_SMP */ -#else /* !(CONFIG_40x || CONFIG_44x || CONFIG_FSL_BOOKE) */ -#if defined(CONFIG_SMP) - rlwinm r8,r1,0,0,(31-THREAD_SHIFT) - lwz r8,TI_CPU(r8) - oris r8,r8,11 - mfmsr r10 - SYNC - rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */ - rlwinm r0,r0,0,28,26 /* clear DR */ - mtmsr r0 - SYNC_601 - isync - lis r9,mmu_hash_lock@h - ori r9,r9,mmu_hash_lock@l - tophys(r9,r9) -10: lwarx r7,0,r9 - cmpwi 0,r7,0 - bne- 10b - stwcx. r8,0,r9 - bne- 10b - eieio - tlbie r3 - sync - TLBSYNC - li r0,0 - stw r0,0(r9) /* clear mmu_hash_lock */ - mtmsr r10 - SYNC_601 - isync -#else /* CONFIG_SMP */ - tlbie r3 - sync -#endif /* CONFIG_SMP */ -#endif /* ! CONFIG_40x */ - blr - -#if defined(CONFIG_FSL_BOOKE) -/* - * Flush MMU TLB, but only on the local processor (no broadcast) - */ -_GLOBAL(_tlbil_all) -#define MMUCSR0_TLBFI (MMUCSR0_TLB0FI | MMUCSR0_TLB1FI | \ - MMUCSR0_TLB2FI | MMUCSR0_TLB3FI) - li r3,(MMUCSR0_TLBFI)@l - mtspr SPRN_MMUCSR0, r3 -1: - mfspr r3,SPRN_MMUCSR0 - andi. r3,r3,MMUCSR0_TLBFI@l - bne 1b - blr - -/* - * Flush MMU TLB for a particular process id, but only on the local processor - * (no broadcast) - */ -_GLOBAL(_tlbil_pid) -/* we currently do an invalidate all since we don't have per pid invalidate */ - li r3,(MMUCSR0_TLBFI)@l - mtspr SPRN_MMUCSR0, r3 -1: - mfspr r3,SPRN_MMUCSR0 - andi. r3,r3,MMUCSR0_TLBFI@l - bne 1b - msync - isync - blr - -/* - * Flush MMU TLB for a particular address, but only on the local processor - * (no broadcast) - */ -_GLOBAL(_tlbil_va) - mfmsr r10 - wrteei 0 - slwi r4,r4,16 - mtspr SPRN_MAS6,r4 /* assume AS=0 for now */ - tlbsx 0,r3 - mfspr r4,SPRN_MAS1 /* check valid */ - andis. r3,r4,MAS1_VALID@h - beq 1f - rlwinm r4,r4,0,1,31 - mtspr SPRN_MAS1,r4 - tlbwe - msync - isync -1: wrtee r10 - blr -#endif /* CONFIG_FSL_BOOKE */ - /* * Flush instruction cache. @@ -650,8 +426,8 @@ _GLOBAL(__flush_dcache_icache) BEGIN_FTR_SECTION blr END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) - rlwinm r3,r3,0,0,19 /* Get page base address */ - li r4,4096/L1_CACHE_BYTES /* Number of lines in a page */ + rlwinm r3,r3,0,0,31-PAGE_SHIFT /* Get page base address */ + li r4,PAGE_SIZE/L1_CACHE_BYTES /* Number of lines in a page */ mtctr r4 mr r6,r3 0: dcbst 0,r3 /* Write line to ram */ @@ -691,8 +467,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) rlwinm r0,r10,0,28,26 /* clear DR */ mtmsr r0 isync - rlwinm r3,r3,0,0,19 /* Get page base address */ - li r4,4096/L1_CACHE_BYTES /* Number of lines in a page */ + rlwinm r3,r3,0,0,31-PAGE_SHIFT /* Get page base address */ + li r4,PAGE_SIZE/L1_CACHE_BYTES /* Number of lines in a page */ mtctr r4 mr r6,r3 0: dcbst 0,r3 /* Write line to ram */ @@ -716,7 +492,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) * void clear_pages(void *page, int order) ; */ _GLOBAL(clear_pages) - li r0,4096/L1_CACHE_BYTES + li r0,PAGE_SIZE/L1_CACHE_BYTES slw r0,r0,r4 mtctr r0 #ifdef CONFIG_8xx @@ -774,7 +550,7 @@ _GLOBAL(copy_page) dcbt r5,r4 li r11,L1_CACHE_BYTES+4 #endif /* MAX_COPY_PREFETCH */ - li r0,4096/L1_CACHE_BYTES - MAX_COPY_PREFETCH + li r0,PAGE_SIZE/L1_CACHE_BYTES - MAX_COPY_PREFETCH crclr 4*cr0+eq 2: mtctr r0 diff --git a/arch/powerpc/kernel/module.c b/arch/powerpc/kernel/module.c index 7ff292475269f10fb1e1e4ad85270587c4756d15..43e7e3a7f130220bdd56122c1560d42484a6db80 100644 --- a/arch/powerpc/kernel/module.c +++ b/arch/powerpc/kernel/module.c @@ -78,6 +78,12 @@ int module_finalize(const Elf_Ehdr *hdr, (void *)sect->sh_addr, (void *)sect->sh_addr + sect->sh_size); + sect = find_section(hdr, sechdrs, "__mmu_ftr_fixup"); + if (sect != NULL) + do_feature_fixups(cur_cpu_spec->mmu_features, + (void *)sect->sh_addr, + (void *)sect->sh_addr + sect->sh_size); + #ifdef CONFIG_PPC64 sect = find_section(hdr, sechdrs, "__fw_ftr_fixup"); if (sect != NULL) diff --git a/arch/powerpc/kernel/module_32.c b/arch/powerpc/kernel/module_32.c index 2df91a03462a26109d49b9fc82b852df76c14b34..f832773fc28e940f82ed0dcecc6104d5e6e71939 100644 --- a/arch/powerpc/kernel/module_32.c +++ b/arch/powerpc/kernel/module_32.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -53,6 +54,9 @@ static unsigned int count_relocs(const Elf32_Rela *rela, unsigned int num) r_addend = rela[i].r_addend; } +#ifdef CONFIG_DYNAMIC_FTRACE + _count_relocs++; /* add one for ftrace_caller */ +#endif return _count_relocs; } @@ -306,5 +310,11 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, return -ENOEXEC; } } +#ifdef CONFIG_DYNAMIC_FTRACE + module->arch.tramp = + do_plt_call(module->module_core, + (unsigned long)ftrace_caller, + sechdrs, module); +#endif return 0; } diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c index 1af2377e49929dc367d49b4588fd2ba6d23d7e91..8992b031a7b6a6cc54433453b6b991d1610cb5d6 100644 --- a/arch/powerpc/kernel/module_64.c +++ b/arch/powerpc/kernel/module_64.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -163,6 +164,11 @@ static unsigned long get_stubs_size(const Elf64_Ehdr *hdr, } } +#ifdef CONFIG_DYNAMIC_FTRACE + /* make the trampoline to the ftrace_caller */ + relocs++; +#endif + DEBUGP("Looks like a total of %lu stubs, max\n", relocs); return relocs * sizeof(struct ppc64_stub_entry); } @@ -441,5 +447,12 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, } } +#ifdef CONFIG_DYNAMIC_FTRACE + me->arch.toc = my_r2(sechdrs, me); + me->arch.tramp = stub_for_addr(sechdrs, + (unsigned long)ftrace_caller, + me); +#endif + return 0; } diff --git a/arch/powerpc/kernel/of_device.c b/arch/powerpc/kernel/of_device.c index f3c9cae01dd5d76389b1c2ce8779c14cb8e6f086..fa983a59c4ce1084d939da4ea6fce17d91036f2a 100644 --- a/arch/powerpc/kernel/of_device.c +++ b/arch/powerpc/kernel/of_device.c @@ -14,7 +14,6 @@ static void of_device_make_bus_id(struct of_device *dev) { static atomic_t bus_no_reg_magic; struct device_node *node = dev->node; - char *name = dev->dev.bus_id; const u32 *reg; u64 addr; int magic; @@ -27,14 +26,12 @@ static void of_device_make_bus_id(struct of_device *dev) reg = of_get_property(node, "dcr-reg", NULL); if (reg) { #ifdef CONFIG_PPC_DCR_NATIVE - snprintf(name, BUS_ID_SIZE, "d%x.%s", - *reg, node->name); + dev_set_name(&dev->dev, "d%x.%s", *reg, node->name); #else /* CONFIG_PPC_DCR_NATIVE */ addr = of_translate_dcr_address(node, *reg, NULL); if (addr != OF_BAD_ADDR) { - snprintf(name, BUS_ID_SIZE, - "D%llx.%s", (unsigned long long)addr, - node->name); + dev_set_name(&dev->dev, "D%llx.%s", + (unsigned long long)addr, node->name); return; } #endif /* !CONFIG_PPC_DCR_NATIVE */ @@ -48,9 +45,8 @@ static void of_device_make_bus_id(struct of_device *dev) if (reg) { addr = of_translate_address(node, reg); if (addr != OF_BAD_ADDR) { - snprintf(name, BUS_ID_SIZE, - "%llx.%s", (unsigned long long)addr, - node->name); + dev_set_name(&dev->dev, "%llx.%s", + (unsigned long long)addr, node->name); return; } } @@ -60,7 +56,7 @@ static void of_device_make_bus_id(struct of_device *dev) * counter (and pray...) */ magic = atomic_add_return(1, &bus_no_reg_magic); - snprintf(name, BUS_ID_SIZE, "%s.%d", node->name, magic - 1); + dev_set_name(&dev->dev, "%s.%d", node->name, magic - 1); } struct of_device *of_device_alloc(struct device_node *np, @@ -80,7 +76,7 @@ struct of_device *of_device_alloc(struct device_node *np, dev->dev.archdata.of_node = np; if (bus_id) - strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE); + dev_set_name(&dev->dev, bus_id); else of_device_make_bus_id(dev); diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c index 48a347133f41607c84a05e4b26647f17e4b6829c..c744b327bcabc866230198eda4dce37169ad0151 100644 --- a/arch/powerpc/kernel/paca.c +++ b/arch/powerpc/kernel/paca.c @@ -37,6 +37,7 @@ struct lppaca lppaca[] = { .end_of_quantum = 0xfffffffffffffffful, .slb_count = 64, .vmxregs_in_use = 0, + .page_ins = 0, }, }; diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index f36936d9fda32f903880c3362c2fa051e42f08f1..2538030954d85102c3ac929b076ad3979d98a4c1 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -37,13 +37,7 @@ #include #include #include - -#ifdef DEBUG -#include -#define DBG(fmt...) printk(fmt) -#else -#define DBG(fmt...) -#endif +#include static DEFINE_SPINLOCK(hose_spinlock); @@ -53,8 +47,9 @@ static int global_phb_number; /* Global phb counter */ /* ISA Memory physical address */ resource_size_t isa_mem_base; -/* Default PCI flags is 0 */ -unsigned int ppc_pci_flags; +/* Default PCI flags is 0 on ppc32, modified at boot on ppc64 */ +unsigned int ppc_pci_flags = 0; + static struct dma_mapping_ops *pci_dma_ops; @@ -165,8 +160,6 @@ EXPORT_SYMBOL(pci_domain_nr); */ struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node) { - if (!have_of) - return NULL; while(node) { struct pci_controller *hose, *tmp; list_for_each_entry_safe(hose, tmp, &hose_list, list_node) @@ -208,26 +201,6 @@ char __devinit *pcibios_setup(char *str) return str; } -void __devinit pcibios_setup_new_device(struct pci_dev *dev) -{ - struct dev_archdata *sd = &dev->dev.archdata; - - sd->of_node = pci_device_to_OF_node(dev); - - DBG("PCI: device %s OF node: %s\n", pci_name(dev), - sd->of_node ? sd->of_node->full_name : ""); - - sd->dma_ops = pci_dma_ops; -#ifdef CONFIG_PPC32 - sd->dma_data = (void *)PCI_DRAM_OFFSET; -#endif - set_dev_node(&dev->dev, pcibus_to_node(dev->bus)); - - if (ppc_md.pci_dma_dev_setup) - ppc_md.pci_dma_dev_setup(dev); -} -EXPORT_SYMBOL(pcibios_setup_new_device); - /* * Reads the interrupt pin to determine if interrupt is use by card. * If the interrupt is used, then gets the interrupt line from the @@ -252,7 +225,7 @@ int pci_read_irq_line(struct pci_dev *pci_dev) return -1; #endif - DBG("Try to map irq for %s...\n", pci_name(pci_dev)); + pr_debug("PCI: Try to map irq for %s...\n", pci_name(pci_dev)); #ifdef DEBUG memset(&oirq, 0xff, sizeof(oirq)); @@ -276,26 +249,26 @@ int pci_read_irq_line(struct pci_dev *pci_dev) line == 0xff || line == 0) { return -1; } - DBG(" -> no map ! Using line %d (pin %d) from PCI config\n", - line, pin); + pr_debug(" No map ! Using line %d (pin %d) from PCI config\n", + line, pin); virq = irq_create_mapping(NULL, line); if (virq != NO_IRQ) set_irq_type(virq, IRQ_TYPE_LEVEL_LOW); } else { - DBG(" -> got one, spec %d cells (0x%08x 0x%08x...) on %s\n", - oirq.size, oirq.specifier[0], oirq.specifier[1], + pr_debug(" Got one, spec %d cells (0x%08x 0x%08x...) on %s\n", + oirq.size, oirq.specifier[0], oirq.specifier[1], oirq.controller->full_name); virq = irq_create_of_mapping(oirq.controller, oirq.specifier, oirq.size); } if(virq == NO_IRQ) { - DBG(" -> failed to map !\n"); + pr_debug(" Failed to map !\n"); return -1; } - DBG(" -> mapped to linux irq %d\n", virq); + pr_debug(" Mapped to linux irq %d\n", virq); pci_dev->irq = virq; @@ -397,13 +370,10 @@ static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp, } /* XXX would be nice to have a way to ask for write-through */ - prot |= _PAGE_NO_CACHE; if (write_combine) - prot &= ~_PAGE_GUARDED; + return pgprot_noncached_wc(prot); else - prot |= _PAGE_GUARDED; - - return __pgprot(prot); + return pgprot_noncached(prot); } /* @@ -414,19 +384,17 @@ static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp, pgprot_t pci_phys_mem_access_prot(struct file *file, unsigned long pfn, unsigned long size, - pgprot_t protection) + pgprot_t prot) { struct pci_dev *pdev = NULL; struct resource *found = NULL; - unsigned long prot = pgprot_val(protection); resource_size_t offset = ((resource_size_t)pfn) << PAGE_SHIFT; int i; if (page_is_ram(pfn)) - return __pgprot(prot); - - prot |= _PAGE_NO_CACHE | _PAGE_GUARDED; + return prot; + prot = pgprot_noncached(prot); for_each_pci_dev(pdev) { for (i = 0; i <= PCI_ROM_RESOURCE; i++) { struct resource *rp = &pdev->resource[i]; @@ -447,14 +415,14 @@ pgprot_t pci_phys_mem_access_prot(struct file *file, } if (found) { if (found->flags & IORESOURCE_PREFETCH) - prot &= ~_PAGE_GUARDED; + prot = pgprot_noncached_wc(prot); pci_dev_put(pdev); } - DBG("non-PCI map for %llx, prot: %lx\n", - (unsigned long long)offset, prot); + pr_debug("PCI: Non-PCI map for %llx, prot: %lx\n", + (unsigned long long)offset, pgprot_val(prot)); - return __pgprot(prot); + return prot; } @@ -610,8 +578,7 @@ int pci_mmap_legacy_page_range(struct pci_bus *bus, pr_debug(" -> mapping phys %llx\n", (unsigned long long)offset); vma->vm_pgoff = offset >> PAGE_SHIFT; - vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) - | _PAGE_NO_CACHE | _PAGE_GUARDED); + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, vma->vm_end - vma->vm_start, vma->vm_page_prot); @@ -853,15 +820,12 @@ void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose, int pci_proc_domain(struct pci_bus *bus) { struct pci_controller *hose = pci_bus_to_host(bus); -#ifdef CONFIG_PPC64 - return hose->buid != 0; -#else + if (!(ppc_pci_flags & PPC_PCI_ENABLE_PROC_DOMAINS)) return 0; if (ppc_pci_flags & PPC_PCI_COMPAT_DOMAIN_0) return hose->global_number != 0; return 1; -#endif } void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, @@ -1083,27 +1047,50 @@ static void __devinit pcibios_fixup_bridge(struct pci_bus *bus) } } -static void __devinit __pcibios_fixup_bus(struct pci_bus *bus) +void __devinit pcibios_setup_bus_self(struct pci_bus *bus) { - struct pci_dev *dev = bus->self; - - pr_debug("PCI: Fixup bus %d (%s)\n", bus->number, dev ? pci_name(dev) : "PHB"); - - /* Fixup PCI<->PCI bridges. Host bridges are handled separately, for - * now differently between 32 and 64 bits. - */ - if (dev != NULL) + /* Fix up the bus resources for P2P bridges */ + if (bus->self != NULL) pcibios_fixup_bridge(bus); - /* Additional setup that is different between 32 and 64 bits for now */ - pcibios_do_bus_setup(bus); - - /* Platform specific bus fixups */ + /* Platform specific bus fixups. This is currently only used + * by fsl_pci and I'm hoping to get rid of it at some point + */ if (ppc_md.pcibios_fixup_bus) ppc_md.pcibios_fixup_bus(bus); - /* Read default IRQs and fixup if necessary */ + /* Setup bus DMA mappings */ + if (ppc_md.pci_dma_bus_setup) + ppc_md.pci_dma_bus_setup(bus); +} + +void __devinit pcibios_setup_bus_devices(struct pci_bus *bus) +{ + struct pci_dev *dev; + + pr_debug("PCI: Fixup bus devices %d (%s)\n", + bus->number, bus->self ? pci_name(bus->self) : "PHB"); + list_for_each_entry(dev, &bus->devices, bus_list) { + struct dev_archdata *sd = &dev->dev.archdata; + + /* Setup OF node pointer in archdata */ + sd->of_node = pci_device_to_OF_node(dev); + + /* Fixup NUMA node as it may not be setup yet by the generic + * code and is needed by the DMA init + */ + set_dev_node(&dev->dev, pcibus_to_node(dev->bus)); + + /* Hook up default DMA ops */ + sd->dma_ops = pci_dma_ops; + sd->dma_data = (void *)PCI_DRAM_OFFSET; + + /* Additional platform DMA/iommu setup */ + if (ppc_md.pci_dma_dev_setup) + ppc_md.pci_dma_dev_setup(dev); + + /* Read default IRQs and fixup if necessary */ pci_read_irq_line(dev); if (ppc_md.pci_irq_fixup) ppc_md.pci_irq_fixup(dev); @@ -1113,22 +1100,19 @@ static void __devinit __pcibios_fixup_bus(struct pci_bus *bus) void __devinit pcibios_fixup_bus(struct pci_bus *bus) { /* When called from the generic PCI probe, read PCI<->PCI bridge - * bases before proceeding + * bases. This is -not- called when generating the PCI tree from + * the OF device-tree. */ if (bus->self != NULL) pci_read_bridge_bases(bus); - __pcibios_fixup_bus(bus); -} -EXPORT_SYMBOL(pcibios_fixup_bus); -/* When building a bus from the OF tree rather than probing, we need a - * slightly different version of the fixup which doesn't read the - * bridge bases using config space accesses - */ -void __devinit pcibios_fixup_of_probed_bus(struct pci_bus *bus) -{ - __pcibios_fixup_bus(bus); + /* Now fixup the bus bus */ + pcibios_setup_bus_self(bus); + + /* Now fixup devices on that bus */ + pcibios_setup_bus_devices(bus); } +EXPORT_SYMBOL(pcibios_fixup_bus); static int skip_isa_ioresource_align(struct pci_dev *dev) { @@ -1198,10 +1182,10 @@ static int __init reparent_resources(struct resource *parent, *pp = NULL; for (p = res->child; p != NULL; p = p->sibling) { p->parent = res; - DBG(KERN_INFO "PCI: reparented %s [%llx..%llx] under %s\n", - p->name, - (unsigned long long)p->start, - (unsigned long long)p->end, res->name); + pr_debug("PCI: Reparented %s [%llx..%llx] under %s\n", + p->name, + (unsigned long long)p->start, + (unsigned long long)p->end, res->name); } return 0; } @@ -1245,9 +1229,12 @@ void pcibios_allocate_bus_resources(struct pci_bus *bus) int i; struct resource *res, *pr; + pr_debug("PCI: Allocating bus resources for %04x:%02x...\n", + pci_domain_nr(bus), bus->number); + for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) { if ((res = bus->resource[i]) == NULL || !res->flags - || res->start > res->end) + || res->start > res->end || res->parent) continue; if (bus->parent == NULL) pr = (res->flags & IORESOURCE_IO) ? @@ -1271,14 +1258,14 @@ void pcibios_allocate_bus_resources(struct pci_bus *bus) } } - DBG("PCI: %s (bus %d) bridge rsrc %d: %016llx-%016llx " - "[0x%x], parent %p (%s)\n", - bus->self ? pci_name(bus->self) : "PHB", - bus->number, i, - (unsigned long long)res->start, - (unsigned long long)res->end, - (unsigned int)res->flags, - pr, (pr && pr->name) ? pr->name : "nil"); + pr_debug("PCI: %s (bus %d) bridge rsrc %d: %016llx-%016llx " + "[0x%x], parent %p (%s)\n", + bus->self ? pci_name(bus->self) : "PHB", + bus->number, i, + (unsigned long long)res->start, + (unsigned long long)res->end, + (unsigned int)res->flags, + pr, (pr && pr->name) ? pr->name : "nil"); if (pr && !(pr->flags & IORESOURCE_UNSET)) { if (request_resource(pr, res) == 0) @@ -1305,11 +1292,11 @@ static inline void __devinit alloc_resource(struct pci_dev *dev, int idx) { struct resource *pr, *r = &dev->resource[idx]; - DBG("PCI: Allocating %s: Resource %d: %016llx..%016llx [%x]\n", - pci_name(dev), idx, - (unsigned long long)r->start, - (unsigned long long)r->end, - (unsigned int)r->flags); + pr_debug("PCI: Allocating %s: Resource %d: %016llx..%016llx [%x]\n", + pci_name(dev), idx, + (unsigned long long)r->start, + (unsigned long long)r->end, + (unsigned int)r->flags); pr = pci_find_parent_resource(dev, r); if (!pr || (pr->flags & IORESOURCE_UNSET) || @@ -1317,10 +1304,11 @@ static inline void __devinit alloc_resource(struct pci_dev *dev, int idx) printk(KERN_WARNING "PCI: Cannot allocate resource region %d" " of device %s, will remap\n", idx, pci_name(dev)); if (pr) - DBG("PCI: parent is %p: %016llx-%016llx [%x]\n", pr, - (unsigned long long)pr->start, - (unsigned long long)pr->end, - (unsigned int)pr->flags); + pr_debug("PCI: parent is %p: %016llx-%016llx [%x]\n", + pr, + (unsigned long long)pr->start, + (unsigned long long)pr->end, + (unsigned int)pr->flags); /* We'll assign a new address later */ r->flags |= IORESOURCE_UNSET; r->end -= r->start; @@ -1358,7 +1346,8 @@ static void __init pcibios_allocate_resources(int pass) * but keep it unregistered. */ u32 reg; - DBG("PCI: Switching off ROM of %s\n", pci_name(dev)); + pr_debug("PCI: Switching off ROM of %s\n", + pci_name(dev)); r->flags &= ~IORESOURCE_ROM_ENABLE; pci_read_config_dword(dev, dev->rom_base_reg, ®); pci_write_config_dword(dev, dev->rom_base_reg, @@ -1383,7 +1372,7 @@ void __init pcibios_resource_survey(void) } if (!(ppc_pci_flags & PPC_PCI_PROBE_ONLY)) { - DBG("PCI: Assigning unassigned resouces...\n"); + pr_debug("PCI: Assigning unassigned resouces...\n"); pci_assign_unassigned_resources(); } @@ -1393,9 +1382,11 @@ void __init pcibios_resource_survey(void) } #ifdef CONFIG_HOTPLUG -/* This is used by the pSeries hotplug driver to allocate resource + +/* This is used by the PCI hotplug driver to allocate resource * of newly plugged busses. We can try to consolidate with the - * rest of the code later, for now, keep it as-is + * rest of the code later, for now, keep it as-is as our main + * resource allocation function doesn't deal with sub-trees yet. */ void __devinit pcibios_claim_one_bus(struct pci_bus *bus) { @@ -1410,6 +1401,14 @@ void __devinit pcibios_claim_one_bus(struct pci_bus *bus) if (r->parent || !r->start || !r->flags) continue; + + pr_debug("PCI: Claiming %s: " + "Resource %d: %016llx..%016llx [%x]\n", + pci_name(dev), i, + (unsigned long long)r->start, + (unsigned long long)r->end, + (unsigned int)r->flags); + pci_claim_resource(dev, i); } } @@ -1418,6 +1417,31 @@ void __devinit pcibios_claim_one_bus(struct pci_bus *bus) pcibios_claim_one_bus(child_bus); } EXPORT_SYMBOL_GPL(pcibios_claim_one_bus); + + +/* pcibios_finish_adding_to_bus + * + * This is to be called by the hotplug code after devices have been + * added to a bus, this include calling it for a PHB that is just + * being added + */ +void pcibios_finish_adding_to_bus(struct pci_bus *bus) +{ + pr_debug("PCI: Finishing adding to hotplug bus %04x:%02x\n", + pci_domain_nr(bus), bus->number); + + /* Allocate bus and devices resources */ + pcibios_allocate_bus_resources(bus); + pcibios_claim_one_bus(bus); + + /* Add new devices to global lists. Register in proc, sysfs. */ + pci_bus_add_devices(bus); + + /* Fixup EEH */ + eeh_add_device_tree_late(bus); +} +EXPORT_SYMBOL_GPL(pcibios_finish_adding_to_bus); + #endif /* CONFIG_HOTPLUG */ int pcibios_enable_device(struct pci_dev *dev, int mask) @@ -1428,3 +1452,61 @@ int pcibios_enable_device(struct pci_dev *dev, int mask) return pci_enable_resources(dev, mask); } + +void __devinit pcibios_setup_phb_resources(struct pci_controller *hose) +{ + struct pci_bus *bus = hose->bus; + struct resource *res; + int i; + + /* Hookup PHB IO resource */ + bus->resource[0] = res = &hose->io_resource; + + if (!res->flags) { + printk(KERN_WARNING "PCI: I/O resource not set for host" + " bridge %s (domain %d)\n", + hose->dn->full_name, hose->global_number); +#ifdef CONFIG_PPC32 + /* Workaround for lack of IO resource only on 32-bit */ + res->start = (unsigned long)hose->io_base_virt - isa_io_base; + res->end = res->start + IO_SPACE_LIMIT; + res->flags = IORESOURCE_IO; +#endif /* CONFIG_PPC32 */ + } + + pr_debug("PCI: PHB IO resource = %016llx-%016llx [%lx]\n", + (unsigned long long)res->start, + (unsigned long long)res->end, + (unsigned long)res->flags); + + /* Hookup PHB Memory resources */ + for (i = 0; i < 3; ++i) { + res = &hose->mem_resources[i]; + if (!res->flags) { + if (i > 0) + continue; + printk(KERN_ERR "PCI: Memory resource 0 not set for " + "host bridge %s (domain %d)\n", + hose->dn->full_name, hose->global_number); +#ifdef CONFIG_PPC32 + /* Workaround for lack of MEM resource only on 32-bit */ + res->start = hose->pci_mem_offset; + res->end = (resource_size_t)-1LL; + res->flags = IORESOURCE_MEM; +#endif /* CONFIG_PPC32 */ + } + bus->resource[i+1] = res; + + pr_debug("PCI: PHB MEM resource %d = %016llx-%016llx [%lx]\n", i, + (unsigned long long)res->start, + (unsigned long long)res->end, + (unsigned long)res->flags); + } + + pr_debug("PCI: PHB MEM offset = %016llx\n", + (unsigned long long)hose->pci_mem_offset); + pr_debug("PCI: PHB IO offset = %08lx\n", + (unsigned long)hose->io_base_virt - _IO_BASE); + +} + diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c index 131b1dfa68c6993ff32006ae1cf22a7f0386211f..132cd80afa21575fe1ee52db1a4afb68083afe99 100644 --- a/arch/powerpc/kernel/pci_32.c +++ b/arch/powerpc/kernel/pci_32.c @@ -26,12 +26,6 @@ #undef DEBUG -#ifdef DEBUG -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif - unsigned long isa_io_base = 0; unsigned long pci_dram_offset = 0; int pcibios_assign_bus_offset = 1; @@ -272,17 +266,14 @@ pci_busdev_to_OF_node(struct pci_bus *bus, int devfn) { struct device_node *parent, *np; - if (!have_of) - return NULL; - - DBG("pci_busdev_to_OF_node(%d,0x%x)\n", bus->number, devfn); + pr_debug("pci_busdev_to_OF_node(%d,0x%x)\n", bus->number, devfn); parent = scan_OF_for_pci_bus(bus); if (parent == NULL) return NULL; - DBG(" parent is %s\n", parent ? parent->full_name : ""); + pr_debug(" parent is %s\n", parent ? parent->full_name : ""); np = scan_OF_for_pci_dev(parent, devfn); of_node_put(parent); - DBG(" result is %s\n", np ? np->full_name : ""); + pr_debug(" result is %s\n", np ? np->full_name : ""); /* XXX most callers don't release the returned node * mostly because ppc64 doesn't increase the refcount, @@ -315,8 +306,6 @@ pci_device_from_OF_node(struct device_node* node, u8* bus, u8* devfn) struct pci_controller* hose; struct pci_dev* dev = NULL; - if (!have_of) - return -ENODEV; /* Make sure it's really a PCI device */ hose = pci_find_hose_for_OF_device(node); if (!hose || !hose->dn) @@ -379,10 +368,41 @@ void pcibios_make_OF_bus_map(void) } #endif /* CONFIG_PPC_OF */ +static void __devinit pcibios_scan_phb(struct pci_controller *hose) +{ + struct pci_bus *bus; + struct device_node *node = hose->dn; + unsigned long io_offset; + struct resource *res = &hose->io_resource; + + pr_debug("PCI: Scanning PHB %s\n", + node ? node->full_name : ""); + + /* Create an empty bus for the toplevel */ + bus = pci_create_bus(hose->parent, hose->first_busno, hose->ops, hose); + if (bus == NULL) { + printk(KERN_ERR "Failed to create bus for PCI domain %04x\n", + hose->global_number); + return; + } + bus->secondary = hose->first_busno; + hose->bus = bus; + + /* Fixup IO space offset */ + io_offset = (unsigned long)hose->io_base_virt - isa_io_base; + res->start = (res->start + io_offset) & 0xffffffffu; + res->end = (res->end + io_offset) & 0xffffffffu; + + /* Wire up PHB bus resources */ + pcibios_setup_phb_resources(hose); + + /* Scan children */ + hose->last_busno = bus->subordinate = pci_scan_child_bus(bus); +} + static int __init pcibios_init(void) { struct pci_controller *hose, *tmp; - struct pci_bus *bus; int next_busno = 0; printk(KERN_INFO "PCI: Probing PCI hardware\n"); @@ -395,12 +415,8 @@ static int __init pcibios_init(void) if (pci_assign_all_buses) hose->first_busno = next_busno; hose->last_busno = 0xff; - bus = pci_scan_bus_parented(hose->parent, hose->first_busno, - hose->ops, hose); - if (bus) { - pci_bus_add_devices(bus); - hose->last_busno = bus->subordinate; - } + pcibios_scan_phb(hose); + pci_bus_add_devices(hose->bus); if (pci_assign_all_buses || next_busno <= hose->last_busno) next_busno = hose->last_busno + pcibios_assign_bus_offset; } @@ -410,7 +426,7 @@ static int __init pcibios_init(void) * numbers vs. kernel bus numbers since we may have to * remap them. */ - if (pci_assign_all_buses && have_of) + if (pci_assign_all_buses) pcibios_make_OF_bus_map(); /* Call common code to handle resource allocation */ @@ -425,54 +441,6 @@ static int __init pcibios_init(void) subsys_initcall(pcibios_init); -void __devinit pcibios_do_bus_setup(struct pci_bus *bus) -{ - struct pci_controller *hose = (struct pci_controller *) bus->sysdata; - unsigned long io_offset; - struct resource *res; - int i; - struct pci_dev *dev; - - /* Hookup PHB resources */ - io_offset = (unsigned long)hose->io_base_virt - isa_io_base; - if (bus->parent == NULL) { - /* This is a host bridge - fill in its resources */ - hose->bus = bus; - - bus->resource[0] = res = &hose->io_resource; - if (!res->flags) { - if (io_offset) - printk(KERN_ERR "I/O resource not set for host" - " bridge %d\n", hose->global_number); - res->start = 0; - res->end = IO_SPACE_LIMIT; - res->flags = IORESOURCE_IO; - } - res->start = (res->start + io_offset) & 0xffffffffu; - res->end = (res->end + io_offset) & 0xffffffffu; - - for (i = 0; i < 3; ++i) { - res = &hose->mem_resources[i]; - if (!res->flags) { - if (i > 0) - continue; - printk(KERN_ERR "Memory resource not set for " - "host bridge %d\n", hose->global_number); - res->start = hose->pci_mem_offset; - res->end = ~0U; - res->flags = IORESOURCE_MEM; - } - bus->resource[i+1] = res; - } - } - - if (ppc_md.pci_dma_bus_setup) - ppc_md.pci_dma_bus_setup(bus); - - list_for_each_entry(dev, &bus->devices, bus_list) - pcibios_setup_new_device(dev); -} - /* the next one is stolen from the alpha port... */ void __init pcibios_update_irq(struct pci_dev *dev, int irq) diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index 3502b9101e6baa7e924806ef6bb284a1aca604c5..39fadc6e149219771985bfc1d697a47afe27f885 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c @@ -32,13 +32,6 @@ #include #include -#ifdef DEBUG -#include -#define DBG(fmt...) printk(fmt) -#else -#define DBG(fmt...) -#endif - unsigned long pci_probe_only = 1; /* pci_io_base -- the base address from which io bars are offsets. @@ -102,7 +95,7 @@ static void pci_parse_of_addrs(struct device_node *node, struct pci_dev *dev) addrs = of_get_property(node, "assigned-addresses", &proplen); if (!addrs) return; - DBG(" parse addresses (%d bytes) @ %p\n", proplen, addrs); + pr_debug(" parse addresses (%d bytes) @ %p\n", proplen, addrs); for (; proplen >= 20; proplen -= 20, addrs += 5) { flags = pci_parse_of_flags(addrs[0]); if (!flags) @@ -112,8 +105,9 @@ static void pci_parse_of_addrs(struct device_node *node, struct pci_dev *dev) if (!size) continue; i = addrs[0] & 0xff; - DBG(" base: %llx, size: %llx, i: %x\n", - (unsigned long long)base, (unsigned long long)size, i); + pr_debug(" base: %llx, size: %llx, i: %x\n", + (unsigned long long)base, + (unsigned long long)size, i); if (PCI_BASE_ADDRESS_0 <= i && i <= PCI_BASE_ADDRESS_5) { res = &dev->resource[(i - PCI_BASE_ADDRESS_0) >> 2]; @@ -144,7 +138,7 @@ struct pci_dev *of_create_pci_dev(struct device_node *node, if (type == NULL) type = ""; - DBG(" create device, devfn: %x, type: %s\n", devfn, type); + pr_debug(" create device, devfn: %x, type: %s\n", devfn, type); dev->bus = bus; dev->sysdata = node; @@ -165,8 +159,8 @@ struct pci_dev *of_create_pci_dev(struct device_node *node, dev->class = get_int_prop(node, "class-code", 0); dev->revision = get_int_prop(node, "revision-id", 0); - DBG(" class: 0x%x\n", dev->class); - DBG(" revision: 0x%x\n", dev->revision); + pr_debug(" class: 0x%x\n", dev->class); + pr_debug(" revision: 0x%x\n", dev->revision); dev->current_state = 4; /* unknown power state */ dev->error_state = pci_channel_io_normal; @@ -187,7 +181,7 @@ struct pci_dev *of_create_pci_dev(struct device_node *node, pci_parse_of_addrs(node, dev); - DBG(" adding to system ...\n"); + pr_debug(" adding to system ...\n"); pci_device_add(dev, bus); @@ -195,19 +189,20 @@ struct pci_dev *of_create_pci_dev(struct device_node *node, } EXPORT_SYMBOL(of_create_pci_dev); -void __devinit of_scan_bus(struct device_node *node, - struct pci_bus *bus) +static void __devinit __of_scan_bus(struct device_node *node, + struct pci_bus *bus, int rescan_existing) { struct device_node *child; const u32 *reg; int reglen, devfn; struct pci_dev *dev; - DBG("of_scan_bus(%s) bus no %d... \n", node->full_name, bus->number); + pr_debug("of_scan_bus(%s) bus no %d... \n", + node->full_name, bus->number); /* Scan direct children */ for_each_child_of_node(node, child) { - DBG(" * %s\n", child->full_name); + pr_debug(" * %s\n", child->full_name); reg = of_get_property(child, "reg", ®len); if (reg == NULL || reglen < 20) continue; @@ -217,11 +212,15 @@ void __devinit of_scan_bus(struct device_node *node, dev = of_create_pci_dev(child, bus, devfn); if (!dev) continue; - DBG(" dev header type: %x\n", dev->hdr_type); + pr_debug(" dev header type: %x\n", dev->hdr_type); } - /* Ally all fixups */ - pcibios_fixup_of_probed_bus(bus); + /* Apply all fixups necessary. We don't fixup the bus "self" + * for an existing bridge that is being rescanned + */ + if (!rescan_existing) + pcibios_setup_bus_self(bus); + pcibios_setup_bus_devices(bus); /* Now scan child busses */ list_for_each_entry(dev, &bus->devices, bus_list) { @@ -233,7 +232,20 @@ void __devinit of_scan_bus(struct device_node *node, } } } -EXPORT_SYMBOL(of_scan_bus); + +void __devinit of_scan_bus(struct device_node *node, + struct pci_bus *bus) +{ + __of_scan_bus(node, bus, 0); +} +EXPORT_SYMBOL_GPL(of_scan_bus); + +void __devinit of_rescan_bus(struct device_node *node, + struct pci_bus *bus) +{ + __of_scan_bus(node, bus, 1); +} +EXPORT_SYMBOL_GPL(of_rescan_bus); void __devinit of_scan_pci_bridge(struct device_node *node, struct pci_dev *dev) @@ -245,7 +257,7 @@ void __devinit of_scan_pci_bridge(struct device_node *node, unsigned int flags; u64 size; - DBG("of_scan_pci_bridge(%s)\n", node->full_name); + pr_debug("of_scan_pci_bridge(%s)\n", node->full_name); /* parse bus-range property */ busrange = of_get_property(node, "bus-range", &len); @@ -309,12 +321,12 @@ void __devinit of_scan_pci_bridge(struct device_node *node, } sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus), bus->number); - DBG(" bus name: %s\n", bus->name); + pr_debug(" bus name: %s\n", bus->name); mode = PCI_PROBE_NORMAL; if (ppc_md.pci_probe_mode) mode = ppc_md.pci_probe_mode(bus); - DBG(" probe mode: %d\n", mode); + pr_debug(" probe mode: %d\n", mode); if (mode == PCI_PROBE_DEVTREE) of_scan_bus(node, bus); @@ -327,9 +339,10 @@ void __devinit scan_phb(struct pci_controller *hose) { struct pci_bus *bus; struct device_node *node = hose->dn; - int i, mode; + int mode; - DBG("PCI: Scanning PHB %s\n", node ? node->full_name : ""); + pr_debug("PCI: Scanning PHB %s\n", + node ? node->full_name : ""); /* Create an empty bus for the toplevel */ bus = pci_create_bus(hose->parent, hose->first_busno, hose->ops, node); @@ -345,26 +358,13 @@ void __devinit scan_phb(struct pci_controller *hose) pcibios_map_io_space(bus); /* Wire up PHB bus resources */ - DBG("PCI: PHB IO resource = %016lx-%016lx [%lx]\n", - hose->io_resource.start, hose->io_resource.end, - hose->io_resource.flags); - bus->resource[0] = &hose->io_resource; - for (i = 0; i < 3; ++i) { - DBG("PCI: PHB MEM resource %d = %016lx-%016lx [%lx]\n", i, - hose->mem_resources[i].start, - hose->mem_resources[i].end, - hose->mem_resources[i].flags); - bus->resource[i+1] = &hose->mem_resources[i]; - } - DBG("PCI: PHB MEM offset = %016lx\n", hose->pci_mem_offset); - DBG("PCI: PHB IO offset = %08lx\n", - (unsigned long)hose->io_base_virt - _IO_BASE); + pcibios_setup_phb_resources(hose); /* Get probe mode and perform scan */ mode = PCI_PROBE_NORMAL; if (node && ppc_md.pci_probe_mode) mode = ppc_md.pci_probe_mode(bus); - DBG(" probe mode: %d\n", mode); + pr_debug(" probe mode: %d\n", mode); if (mode == PCI_PROBE_DEVTREE) { bus->subordinate = hose->last_busno; of_scan_bus(node, bus); @@ -380,7 +380,7 @@ static int __init pcibios_init(void) printk(KERN_INFO "PCI: Probing PCI hardware\n"); - /* For now, override phys_mem_access_prot. If we need it, + /* For now, override phys_mem_access_prot. If we need it,g * later, we may move that initialization to each ppc_md */ ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot; @@ -388,6 +388,11 @@ static int __init pcibios_init(void) if (pci_probe_only) ppc_pci_flags |= PPC_PCI_PROBE_ONLY; + /* On ppc64, we always enable PCI domains and we keep domain 0 + * backward compatible in /proc for video cards + */ + ppc_pci_flags |= PPC_PCI_ENABLE_PROC_DOMAINS | PPC_PCI_COMPAT_DOMAIN_0; + /* Scan all of the recorded PCI controllers. */ list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { scan_phb(hose); @@ -422,8 +427,8 @@ int pcibios_unmap_io_space(struct pci_bus *bus) if (bus->self) { struct resource *res = bus->resource[0]; - DBG("IO unmapping for PCI-PCI bridge %s\n", - pci_name(bus->self)); + pr_debug("IO unmapping for PCI-PCI bridge %s\n", + pci_name(bus->self)); __flush_hash_table_range(&init_mm, res->start + _IO_BASE, res->end + _IO_BASE + 1); @@ -437,8 +442,8 @@ int pcibios_unmap_io_space(struct pci_bus *bus) if (hose->io_base_alloc == 0) return 0; - DBG("IO unmapping for PHB %s\n", hose->dn->full_name); - DBG(" alloc=0x%p\n", hose->io_base_alloc); + pr_debug("IO unmapping for PHB %s\n", hose->dn->full_name); + pr_debug(" alloc=0x%p\n", hose->io_base_alloc); /* This is a PHB, we fully unmap the IO area */ vunmap(hose->io_base_alloc); @@ -463,11 +468,11 @@ int __devinit pcibios_map_io_space(struct pci_bus *bus) * thus HPTEs will be faulted in when needed */ if (bus->self) { - DBG("IO mapping for PCI-PCI bridge %s\n", - pci_name(bus->self)); - DBG(" virt=0x%016lx...0x%016lx\n", - bus->resource[0]->start + _IO_BASE, - bus->resource[0]->end + _IO_BASE); + pr_debug("IO mapping for PCI-PCI bridge %s\n", + pci_name(bus->self)); + pr_debug(" virt=0x%016lx...0x%016lx\n", + bus->resource[0]->start + _IO_BASE, + bus->resource[0]->end + _IO_BASE); return 0; } @@ -496,11 +501,11 @@ int __devinit pcibios_map_io_space(struct pci_bus *bus) hose->io_base_virt = (void __iomem *)(area->addr + hose->io_base_phys - phys_page); - DBG("IO mapping for PHB %s\n", hose->dn->full_name); - DBG(" phys=0x%016lx, virt=0x%p (alloc=0x%p)\n", - hose->io_base_phys, hose->io_base_virt, hose->io_base_alloc); - DBG(" size=0x%016lx (alloc=0x%016lx)\n", - hose->pci_io_size, size_page); + pr_debug("IO mapping for PHB %s\n", hose->dn->full_name); + pr_debug(" phys=0x%016lx, virt=0x%p (alloc=0x%p)\n", + hose->io_base_phys, hose->io_base_virt, hose->io_base_alloc); + pr_debug(" size=0x%016lx (alloc=0x%016lx)\n", + hose->pci_io_size, size_page); /* Establish the mapping */ if (__ioremap_at(phys_page, area->addr, size_page, @@ -512,24 +517,13 @@ int __devinit pcibios_map_io_space(struct pci_bus *bus) hose->io_resource.start += io_virt_offset; hose->io_resource.end += io_virt_offset; - DBG(" hose->io_resource=0x%016lx...0x%016lx\n", - hose->io_resource.start, hose->io_resource.end); + pr_debug(" hose->io_resource=0x%016lx...0x%016lx\n", + hose->io_resource.start, hose->io_resource.end); return 0; } EXPORT_SYMBOL_GPL(pcibios_map_io_space); -void __devinit pcibios_do_bus_setup(struct pci_bus *bus) -{ - struct pci_dev *dev; - - if (ppc_md.pci_dma_bus_setup) - ppc_md.pci_dma_bus_setup(bus); - - list_for_each_entry(dev, &bus->devices, bus_list) - pcibios_setup_new_device(dev); -} - unsigned long pci_address_to_pio(phys_addr_t address) { struct pci_controller *hose, *tmp; diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c index 260089dccfb0524aa30fd8a126af60cbd80f41ac..dcec1325d3404adf5f06df1a4b440ca07838a5d9 100644 --- a/arch/powerpc/kernel/ppc_ksyms.c +++ b/arch/powerpc/kernel/ppc_ksyms.c @@ -116,12 +116,6 @@ EXPORT_SYMBOL(giveup_spe); #ifndef CONFIG_PPC64 EXPORT_SYMBOL(flush_instruction_cache); -EXPORT_SYMBOL(flush_tlb_kernel_range); -EXPORT_SYMBOL(flush_tlb_page); -EXPORT_SYMBOL(_tlbie); -#if defined(CONFIG_4xx) || defined(CONFIG_8xx) || defined(CONFIG_FSL_BOOKE) -EXPORT_SYMBOL(_tlbil_va); -#endif #endif EXPORT_SYMBOL(__flush_icache_range); EXPORT_SYMBOL(flush_dcache_range); @@ -174,8 +168,7 @@ EXPORT_SYMBOL(cacheable_memcpy); #endif #ifdef CONFIG_PPC32 -EXPORT_SYMBOL(next_mmu_context); -EXPORT_SYMBOL(set_context); +EXPORT_SYMBOL(switch_mmu_context); #endif #ifdef CONFIG_PPC_STD_MMU_32 diff --git a/arch/powerpc/xmon/setjmp.S b/arch/powerpc/kernel/ppc_save_regs.S similarity index 98% rename from arch/powerpc/xmon/setjmp.S rename to arch/powerpc/kernel/ppc_save_regs.S index 04c0b305ad4ad65ba5722c7c0813be912ef0fdb6..5113bd2285e14d546b0e1d16779f5c24d9287bfe 100644 --- a/arch/powerpc/xmon/setjmp.S +++ b/arch/powerpc/kernel/ppc_save_regs.S @@ -22,7 +22,7 @@ * that will be different for 32-bit and 64-bit, because of the * different ABIs, though). */ -_GLOBAL(xmon_save_regs) +_GLOBAL(ppc_save_regs) PPC_STL r0,0*SZL(r3) PPC_STL r2,2*SZL(r3) PPC_STL r3,3*SZL(r3) diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 957bded0020d5d8921e11f6db8fc4517565207a8..51b201ddf9a160002d10ff3c61cd9bb2e40119a5 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -467,6 +467,8 @@ static struct regbit { {MSR_VEC, "VEC"}, {MSR_VSX, "VSX"}, {MSR_ME, "ME"}, + {MSR_CE, "CE"}, + {MSR_DE, "DE"}, {MSR_IR, "IR"}, {MSR_DR, "DR"}, {0, NULL} @@ -998,7 +1000,7 @@ unsigned long get_wchan(struct task_struct *p) return 0; } -static int kstack_depth_to_print = 64; +static int kstack_depth_to_print = CONFIG_PRINT_STACK_DEPTH; void show_stack(struct task_struct *tsk, unsigned long *stack) { diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 3a2dc7e6586a392292ccf3ccbfacb39151a3f675..6f73c739f1e2f443d988f3bb440dec4c648b44d9 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -1160,6 +1160,8 @@ static inline void __init phyp_dump_reserve_mem(void) {} void __init early_init_devtree(void *params) { + unsigned long limit; + DBG(" -> early_init_devtree(%p)\n", params); /* Setup flat device-tree pointer */ @@ -1200,7 +1202,19 @@ void __init early_init_devtree(void *params) early_reserve_mem(); phyp_dump_reserve_mem(); - lmb_enforce_memory_limit(memory_limit); + limit = memory_limit; + if (! limit) { + unsigned long memsize; + + /* Ensure that total memory size is page-aligned, because + * otherwise mark_bootmem() gets upset. */ + lmb_analyze(); + memsize = lmb_phys_mem_size(); + if ((memsize & PAGE_MASK) != memsize) + limit = memsize & PAGE_MASK; + } + lmb_enforce_memory_limit(limit); + lmb_analyze(); DBG("Phys. mem: %lx\n", lmb_phys_mem_size()); @@ -1270,6 +1284,37 @@ struct device_node *of_find_node_by_phandle(phandle handle) } EXPORT_SYMBOL(of_find_node_by_phandle); +/** + * of_find_next_cache_node - Find a node's subsidiary cache + * @np: node of type "cpu" or "cache" + * + * Returns a node pointer with refcount incremented, use + * of_node_put() on it when done. Caller should hold a reference + * to np. + */ +struct device_node *of_find_next_cache_node(struct device_node *np) +{ + struct device_node *child; + const phandle *handle; + + handle = of_get_property(np, "l2-cache", NULL); + if (!handle) + handle = of_get_property(np, "next-level-cache", NULL); + + if (handle) + return of_find_node_by_phandle(*handle); + + /* OF on pmac has nodes instead of properties named "l2-cache" + * beneath CPU nodes. + */ + if (!strcmp(np->type, "cpu")) + for_each_child_of_node(np, child) + if (!strcmp(child->type, "cache")) + return child; + + return NULL; +} + /** * of_find_all_nodes - Get next node in global list * @prev: Previous node or NULL to start iteration diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c index a11d68976dc840fdf545120f94cda1c746a362c8..8c133556608914b0e61a1768a326d49b89c6d5d1 100644 --- a/arch/powerpc/kernel/prom_parse.c +++ b/arch/powerpc/kernel/prom_parse.c @@ -734,10 +734,7 @@ void of_irq_map_init(unsigned int flags) if (flags & OF_IMAP_NO_PHANDLE) { struct device_node *np; - for(np = NULL; (np = of_find_all_nodes(np)) != NULL;) { - if (of_get_property(np, "interrupt-controller", NULL) - == NULL) - continue; + for_each_node_with_property(np, "interrupt-controller") { /* Skip /chosen/interrupt-controller */ if (strcmp(np->name, "chosen") == 0) continue; diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index 1f8505c235482c5fea77a9f3fd1ec175a526a202..fdfe14c4bdefc735640745625cb559fc4908a2fa 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c @@ -566,6 +566,32 @@ int rtas_get_sensor(int sensor, int index, int *state) } EXPORT_SYMBOL(rtas_get_sensor); +bool rtas_indicator_present(int token, int *maxindex) +{ + int proplen, count, i; + const struct indicator_elem { + u32 token; + u32 maxindex; + } *indicators; + + indicators = of_get_property(rtas.dev, "rtas-indicators", &proplen); + if (!indicators) + return false; + + count = proplen / sizeof(struct indicator_elem); + + for (i = 0; i < count; i++) { + if (indicators[i].token != token) + continue; + if (maxindex) + *maxindex = indicators[i].maxindex; + return true; + } + + return false; +} +EXPORT_SYMBOL(rtas_indicator_present); + int rtas_set_indicator(int indicator, int index, int new_value) { int token = rtas_token("set-indicator"); diff --git a/arch/powerpc/kernel/rtas_pci.c b/arch/powerpc/kernel/rtas_pci.c index 589a2797eac2006075af50ee60e6bff836f3882c..8869001ab5d7691baae77296e6ca4bdd7aec010d 100644 --- a/arch/powerpc/kernel/rtas_pci.c +++ b/arch/powerpc/kernel/rtas_pci.c @@ -301,51 +301,3 @@ void __init find_and_init_phbs(void) #endif /* CONFIG_PPC32 */ } } - -/* RPA-specific bits for removing PHBs */ -int pcibios_remove_root_bus(struct pci_controller *phb) -{ - struct pci_bus *b = phb->bus; - struct resource *res; - int rc, i; - - res = b->resource[0]; - if (!res->flags) { - printk(KERN_ERR "%s: no IO resource for PHB %s\n", __func__, - b->name); - return 1; - } - - rc = pcibios_unmap_io_space(b); - if (rc) { - printk(KERN_ERR "%s: failed to unmap IO on bus %s\n", - __func__, b->name); - return 1; - } - - if (release_resource(res)) { - printk(KERN_ERR "%s: failed to release IO on bus %s\n", - __func__, b->name); - return 1; - } - - for (i = 1; i < 3; ++i) { - res = b->resource[i]; - if (!res->flags && i == 0) { - printk(KERN_ERR "%s: no MEM resource for PHB %s\n", - __func__, b->name); - return 1; - } - if (res->flags && release_resource(res)) { - printk(KERN_ERR - "%s: failed to release IO %d on bus %s\n", - __func__, i, b->name); - return 1; - } - } - - pcibios_free_controller(phb); - - return 0; -} -EXPORT_SYMBOL(pcibios_remove_root_bus); diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index c1a27626a940d1b49c990bbcc3f3f2c5f538b097..9e1ca745d8f059afc2809353eaae248155b9c282 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -38,6 +38,7 @@ #include #include #include +#include #include "setup.h" @@ -49,12 +50,12 @@ int boot_cpuid; EXPORT_SYMBOL_GPL(boot_cpuid); int boot_cpuid_phys; +int smp_hw_index[NR_CPUS]; + unsigned long ISA_DMA_THRESHOLD; unsigned int DMA_MODE_READ; unsigned int DMA_MODE_WRITE; -int have_of = 1; - #ifdef CONFIG_VGA_CONSOLE unsigned long vgacon_remap_base; EXPORT_SYMBOL(vgacon_remap_base); @@ -97,6 +98,10 @@ notrace unsigned long __init early_init(unsigned long dt_ptr) PTRRELOC(&__start___ftr_fixup), PTRRELOC(&__stop___ftr_fixup)); + do_feature_fixups(spec->mmu_features, + PTRRELOC(&__start___mmu_ftr_fixup), + PTRRELOC(&__stop___mmu_ftr_fixup)); + do_lwsync_fixups(spec->cpu_features, PTRRELOC(&__start___lwsync_fixup), PTRRELOC(&__stop___lwsync_fixup)); @@ -121,6 +126,8 @@ notrace void __init machine_init(unsigned long dt_ptr) probe_machine(); + setup_kdump_trampoline(); + #ifdef CONFIG_6xx if (cpu_has_feature(CPU_FTR_CAN_DOZE) || cpu_has_feature(CPU_FTR_CAN_NAP)) @@ -326,4 +333,8 @@ void __init setup_arch(char **cmdline_p) if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab); paging_init(); + + /* Initialize the MMU context management stuff */ + mmu_context_init(); + } diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 169d74cef157d84e347afb489f3cce3d805f9a8a..d8bd2161e7388c55afcb53f77d2c03504cf073ff 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -70,7 +70,6 @@ #define DBG(fmt...) #endif -int have_of = 1; int boot_cpuid = 0; u64 ppc64_pft_size; @@ -362,6 +361,8 @@ void __init setup_system(void) */ do_feature_fixups(cur_cpu_spec->cpu_features, &__start___ftr_fixup, &__stop___ftr_fixup); + do_feature_fixups(cur_cpu_spec->mmu_features, + &__start___mmu_ftr_fixup, &__stop___mmu_ftr_fixup); do_feature_fixups(powerpc_firmware_features, &__start___fw_ftr_fixup, &__stop___fw_ftr_fixup); do_lwsync_fixups(cur_cpu_spec->cpu_features, @@ -606,8 +607,6 @@ void __init setup_per_cpu_areas(void) for_each_possible_cpu(i) { ptr = alloc_bootmem_pages_node(NODE_DATA(cpu_to_node(i)), size); - if (!ptr) - panic("Cannot allocate cpu data for CPU %d\n", i); paca[i].data_offset = ptr - __per_cpu_start; memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start); diff --git a/arch/powerpc/kernel/smp-tbsync.c b/arch/powerpc/kernel/smp-tbsync.c index bc892e69b4f732cd11c46a5ccb79be51eaf34fae..a5e54526403df182f074ee3bd90c715d6f54b444 100644 --- a/arch/powerpc/kernel/smp-tbsync.c +++ b/arch/powerpc/kernel/smp-tbsync.c @@ -113,7 +113,7 @@ void __devinit smp_generic_give_timebase(void) { int i, score, score2, old, min=0, max=5000, offset=1000; - printk("Synchronizing timebase\n"); + pr_debug("Software timebase sync\n"); /* if this fails then this kernel won't work anyway... */ tbsync = kzalloc( sizeof(*tbsync), GFP_KERNEL ); @@ -123,13 +123,13 @@ void __devinit smp_generic_give_timebase(void) while (!tbsync->ack) barrier(); - printk("Got ack\n"); + pr_debug("Got ack\n"); /* binary search */ for (old = -1; old != offset ; offset = (min+max) / 2) { score = start_contest(kSetAndTest, offset, NUM_ITER); - printk("score %d, offset %d\n", score, offset ); + pr_debug("score %d, offset %d\n", score, offset ); if( score > 0 ) max = offset; @@ -140,8 +140,8 @@ void __devinit smp_generic_give_timebase(void) score = start_contest(kSetAndTest, min, NUM_ITER); score2 = start_contest(kSetAndTest, max, NUM_ITER); - printk("Min %d (score %d), Max %d (score %d)\n", - min, score, max, score2); + pr_debug("Min %d (score %d), Max %d (score %d)\n", + min, score, max, score2); score = abs(score); score2 = abs(score2); offset = (score < score2) ? min : max; @@ -155,7 +155,7 @@ void __devinit smp_generic_give_timebase(void) if (score2 <= score || score2 < 20) break; } - printk("Final offset: %d (%d/%d)\n", offset, score2, NUM_ITER ); + pr_debug("Final offset: %d (%d/%d)\n", offset, score2, NUM_ITER ); /* exiting */ tbsync->cmd = kExit; diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index ff9f7010097d1568943329a15d8c04458beddc4c..8ac3f721d2359e20b09476fbe85aafc7c161f97d 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -57,7 +57,6 @@ #define DBG(fmt...) #endif -int smp_hw_index[NR_CPUS]; struct thread_info *secondary_ti; cpumask_t cpu_possible_map = CPU_MASK_NONE; @@ -123,6 +122,65 @@ void smp_message_recv(int msg) } } +static irqreturn_t call_function_action(int irq, void *data) +{ + generic_smp_call_function_interrupt(); + return IRQ_HANDLED; +} + +static irqreturn_t reschedule_action(int irq, void *data) +{ + /* we just need the return path side effect of checking need_resched */ + return IRQ_HANDLED; +} + +static irqreturn_t call_function_single_action(int irq, void *data) +{ + generic_smp_call_function_single_interrupt(); + return IRQ_HANDLED; +} + +static irqreturn_t debug_ipi_action(int irq, void *data) +{ + smp_message_recv(PPC_MSG_DEBUGGER_BREAK); + return IRQ_HANDLED; +} + +static irq_handler_t smp_ipi_action[] = { + [PPC_MSG_CALL_FUNCTION] = call_function_action, + [PPC_MSG_RESCHEDULE] = reschedule_action, + [PPC_MSG_CALL_FUNC_SINGLE] = call_function_single_action, + [PPC_MSG_DEBUGGER_BREAK] = debug_ipi_action, +}; + +const char *smp_ipi_name[] = { + [PPC_MSG_CALL_FUNCTION] = "ipi call function", + [PPC_MSG_RESCHEDULE] = "ipi reschedule", + [PPC_MSG_CALL_FUNC_SINGLE] = "ipi call function single", + [PPC_MSG_DEBUGGER_BREAK] = "ipi debugger", +}; + +/* optional function to request ipi, for controllers with >= 4 ipis */ +int smp_request_message_ipi(int virq, int msg) +{ + int err; + + if (msg < 0 || msg > PPC_MSG_DEBUGGER_BREAK) { + return -EINVAL; + } +#if !defined(CONFIG_DEBUGGER) && !defined(CONFIG_KEXEC) + if (msg == PPC_MSG_DEBUGGER_BREAK) { + return 1; + } +#endif + err = request_irq(virq, smp_ipi_action[msg], IRQF_DISABLED|IRQF_PERCPU, + smp_ipi_name[msg], 0); + WARN(err < 0, "unable to request_irq %d for %s (rc %d)\n", + virq, smp_ipi_name[msg], err); + + return err; +} + void smp_send_reschedule(int cpu) { if (likely(smp_ops)) @@ -408,8 +466,7 @@ int cpu_to_core_id(int cpu) static struct device_node *cpu_to_l2cache(int cpu) { struct device_node *np; - const phandle *php; - phandle ph; + struct device_node *cache; if (!cpu_present(cpu)) return NULL; @@ -418,13 +475,11 @@ static struct device_node *cpu_to_l2cache(int cpu) if (np == NULL) return NULL; - php = of_get_property(np, "l2-cache", NULL); - if (php == NULL) - return NULL; - ph = *php; + cache = of_find_next_cache_node(np); + of_node_put(np); - return of_find_node_by_phandle(ph); + return cache; } /* Activate a secondary processor. */ diff --git a/arch/powerpc/kernel/swsusp.c b/arch/powerpc/kernel/swsusp.c index 77b7b34b5955f0d6453e829b75454f0df145da9c..560c961195015d39b0f62296f48413f27f394f0f 100644 --- a/arch/powerpc/kernel/swsusp.c +++ b/arch/powerpc/kernel/swsusp.c @@ -34,6 +34,6 @@ void save_processor_state(void) void restore_processor_state(void) { #ifdef CONFIG_PPC32 - set_context(current->active_mm->context.id, current->active_mm->pgd); + switch_mmu_context(NULL, current->active_mm); #endif } diff --git a/arch/powerpc/kernel/swsusp_32.S b/arch/powerpc/kernel/swsusp_32.S index 77fc76607ab2080d41667f3171fcdef9ee44dfd1..b47d8ceffb5232e21e8990b86ea29d18f2f16024 100644 --- a/arch/powerpc/kernel/swsusp_32.S +++ b/arch/powerpc/kernel/swsusp_32.S @@ -5,7 +5,7 @@ #include #include #include - +#include /* * Structure for storing CPU registers on the save area. @@ -279,7 +279,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) mtibatl 3,r4 #endif -BEGIN_FTR_SECTION +BEGIN_MMU_FTR_SECTION li r4,0 mtspr SPRN_DBAT4U,r4 mtspr SPRN_DBAT4L,r4 @@ -297,7 +297,7 @@ BEGIN_FTR_SECTION mtspr SPRN_IBAT6L,r4 mtspr SPRN_IBAT7U,r4 mtspr SPRN_IBAT7L,r4 -END_FTR_SECTION_IFSET(CPU_FTR_HAS_HIGH_BATS) +END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS) /* Flush all TLBs */ lis r4,0x1000 diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index 20885a38237aa0ab5f028aa67537b365b340aad0..0c64f10087b9833b871ac62b55e177a48f2f5af3 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c @@ -566,7 +566,6 @@ static bool cache_is_unified(struct device_node *np) static struct cache_desc * __cpuinit create_cache_index_info(struct device_node *np, struct kobject *parent, int index, int level) { - const phandle *next_cache_phandle; struct device_node *next_cache; struct cache_desc *new, **end; @@ -591,11 +590,7 @@ static struct cache_desc * __cpuinit create_cache_index_info(struct device_node while (*end) end = &(*end)->next; - next_cache_phandle = of_get_property(np, "l2-cache", NULL); - if (!next_cache_phandle) - goto out; - - next_cache = of_find_node_by_phandle(*next_cache_phandle); + next_cache = of_find_next_cache_node(np); if (!next_cache) goto out; diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index e2ee66b5831d9f86cf41704784863cd74bbc3c91..e1f3a51404292ee3c422295e47292da9b7c22256 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -164,8 +164,6 @@ static u64 tb_to_ns_scale __read_mostly; static unsigned tb_to_ns_shift __read_mostly; static unsigned long boot_tb __read_mostly; -static struct gettimeofday_struct do_gtod; - extern struct timezone sys_tz; static long timezone_offset; @@ -415,31 +413,9 @@ void udelay(unsigned long usecs) } EXPORT_SYMBOL(udelay); - -/* - * There are two copies of tb_to_xs and stamp_xsec so that no - * lock is needed to access and use these values in - * do_gettimeofday. We alternate the copies and as long as a - * reasonable time elapses between changes, there will never - * be inconsistent values. ntpd has a minimum of one minute - * between updates. - */ static inline void update_gtod(u64 new_tb_stamp, u64 new_stamp_xsec, u64 new_tb_to_xs) { - unsigned temp_idx; - struct gettimeofday_vars *temp_varp; - - temp_idx = (do_gtod.var_idx == 0); - temp_varp = &do_gtod.vars[temp_idx]; - - temp_varp->tb_to_xs = new_tb_to_xs; - temp_varp->tb_orig_stamp = new_tb_stamp; - temp_varp->stamp_xsec = new_stamp_xsec; - smp_mb(); - do_gtod.varp = temp_varp; - do_gtod.var_idx = temp_idx; - /* * tb_update_count is used to allow the userspace gettimeofday code * to assure itself that it sees a consistent view of the tb_to_xs and @@ -456,6 +432,7 @@ static inline void update_gtod(u64 new_tb_stamp, u64 new_stamp_xsec, vdso_data->tb_to_xs = new_tb_to_xs; vdso_data->wtom_clock_sec = wall_to_monotonic.tv_sec; vdso_data->wtom_clock_nsec = wall_to_monotonic.tv_nsec; + vdso_data->stamp_xtime = xtime; smp_wmb(); ++(vdso_data->tb_update_count); } @@ -514,9 +491,7 @@ static int __init iSeries_tb_recal(void) tb_ticks_per_sec = new_tb_ticks_per_sec; calc_cputime_factors(); div128_by_32( XSEC_PER_SEC, 0, tb_ticks_per_sec, &divres ); - do_gtod.tb_ticks_per_sec = tb_ticks_per_sec; tb_to_xs = divres.result_low; - do_gtod.varp->tb_to_xs = tb_to_xs; vdso_data->tb_ticks_per_sec = tb_ticks_per_sec; vdso_data->tb_to_xs = tb_to_xs; } @@ -988,15 +963,6 @@ void __init time_init(void) sys_tz.tz_dsttime = 0; } - do_gtod.varp = &do_gtod.vars[0]; - do_gtod.var_idx = 0; - do_gtod.varp->tb_orig_stamp = tb_last_jiffy; - __get_cpu_var(last_jiffy) = tb_last_jiffy; - do_gtod.varp->stamp_xsec = (u64) xtime.tv_sec * XSEC_PER_SEC; - do_gtod.tb_ticks_per_sec = tb_ticks_per_sec; - do_gtod.varp->tb_to_xs = tb_to_xs; - do_gtod.tb_to_us = tb_to_us; - vdso_data->tb_orig_stamp = tb_last_jiffy; vdso_data->tb_update_count = 0; vdso_data->tb_ticks_per_sec = tb_ticks_per_sec; diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index f5def6cf5cd61b0114458c74a5171fe724683267..5457e9575685291a5a84dcad525cd89b009c9e1e 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -1160,37 +1160,85 @@ void CacheLockingException(struct pt_regs *regs, unsigned long address, #ifdef CONFIG_SPE void SPEFloatingPointException(struct pt_regs *regs) { + extern int do_spe_mathemu(struct pt_regs *regs); unsigned long spefscr; int fpexc_mode; int code = 0; + int err; + + preempt_disable(); + if (regs->msr & MSR_SPE) + giveup_spe(current); + preempt_enable(); spefscr = current->thread.spefscr; fpexc_mode = current->thread.fpexc_mode; - /* Hardware does not neccessarily set sticky - * underflow/overflow/invalid flags */ if ((spefscr & SPEFSCR_FOVF) && (fpexc_mode & PR_FP_EXC_OVF)) { code = FPE_FLTOVF; - spefscr |= SPEFSCR_FOVFS; } else if ((spefscr & SPEFSCR_FUNF) && (fpexc_mode & PR_FP_EXC_UND)) { code = FPE_FLTUND; - spefscr |= SPEFSCR_FUNFS; } else if ((spefscr & SPEFSCR_FDBZ) && (fpexc_mode & PR_FP_EXC_DIV)) code = FPE_FLTDIV; else if ((spefscr & SPEFSCR_FINV) && (fpexc_mode & PR_FP_EXC_INV)) { code = FPE_FLTINV; - spefscr |= SPEFSCR_FINVS; } else if ((spefscr & (SPEFSCR_FG | SPEFSCR_FX)) && (fpexc_mode & PR_FP_EXC_RES)) code = FPE_FLTRES; - current->thread.spefscr = spefscr; + err = do_spe_mathemu(regs); + if (err == 0) { + regs->nip += 4; /* skip emulated instruction */ + emulate_single_step(regs); + return; + } + + if (err == -EFAULT) { + /* got an error reading the instruction */ + _exception(SIGSEGV, regs, SEGV_ACCERR, regs->nip); + } else if (err == -EINVAL) { + /* didn't recognize the instruction */ + printk(KERN_ERR "unrecognized spe instruction " + "in %s at %lx\n", current->comm, regs->nip); + } else { + _exception(SIGFPE, regs, code, regs->nip); + } - _exception(SIGFPE, regs, code, regs->nip); return; } + +void SPEFloatingPointRoundException(struct pt_regs *regs) +{ + extern int speround_handler(struct pt_regs *regs); + int err; + + preempt_disable(); + if (regs->msr & MSR_SPE) + giveup_spe(current); + preempt_enable(); + + regs->nip -= 4; + err = speround_handler(regs); + if (err == 0) { + regs->nip += 4; /* skip emulated instruction */ + emulate_single_step(regs); + return; + } + + if (err == -EFAULT) { + /* got an error reading the instruction */ + _exception(SIGSEGV, regs, SEGV_ACCERR, regs->nip); + } else if (err == -EINVAL) { + /* didn't recognize the instruction */ + printk(KERN_ERR "unrecognized spe instruction " + "in %s at %lx\n", current->comm, regs->nip); + } else { + _exception(SIGFPE, regs, 0, regs->nip); + return; + } +} #endif /* diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c index 65639a43e644888577d4bf92328f54c95aef99fb..ad06d5c75b15ddb4ac6c92e00cfde45f3174d452 100644 --- a/arch/powerpc/kernel/vdso.c +++ b/arch/powerpc/kernel/vdso.c @@ -184,8 +184,7 @@ static void dump_vdso_pages(struct vm_area_struct * vma) * This is called from binfmt_elf, we create the special vma for the * vDSO and insert it into the mm struct tree */ -int arch_setup_additional_pages(struct linux_binprm *bprm, - int executable_stack) +int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) { struct mm_struct *mm = current->mm; struct page **vdso_pagelist; @@ -567,6 +566,11 @@ static __init int vdso_fixup_features(struct lib32_elfinfo *v32, do_feature_fixups(cur_cpu_spec->cpu_features, start64, start64 + size64); + start64 = find_section64(v64->hdr, "__mmu_ftr_fixup", &size64); + if (start64) + do_feature_fixups(cur_cpu_spec->mmu_features, + start64, start64 + size64); + start64 = find_section64(v64->hdr, "__fw_ftr_fixup", &size64); if (start64) do_feature_fixups(powerpc_firmware_features, @@ -583,6 +587,11 @@ static __init int vdso_fixup_features(struct lib32_elfinfo *v32, do_feature_fixups(cur_cpu_spec->cpu_features, start32, start32 + size32); + start32 = find_section32(v32->hdr, "__mmu_ftr_fixup", &size32); + if (start32) + do_feature_fixups(cur_cpu_spec->mmu_features, + start32, start32 + size32); + #ifdef CONFIG_PPC64 start32 = find_section32(v32->hdr, "__fw_ftr_fixup", &size32); if (start32) diff --git a/arch/powerpc/kernel/vdso32/gettimeofday.S b/arch/powerpc/kernel/vdso32/gettimeofday.S index 72ca26df457e567d75225aaad333eeebf0e783a2..ee038d4bf252f7e423aaaf442f6a71c9245e5bed 100644 --- a/arch/powerpc/kernel/vdso32/gettimeofday.S +++ b/arch/powerpc/kernel/vdso32/gettimeofday.S @@ -16,6 +16,13 @@ #include #include +/* Offset for the low 32-bit part of a field of long type */ +#ifdef CONFIG_PPC64 +#define LOPART 4 +#else +#define LOPART 0 +#endif + .text /* * Exact prototype of gettimeofday @@ -90,101 +97,53 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime) mflr r12 /* r12 saves lr */ .cfi_register lr,r12 - mr r10,r3 /* r10 saves id */ mr r11,r4 /* r11 saves tp */ bl __get_datapage@local /* get data page */ mr r9,r3 /* datapage ptr in r9 */ - beq cr1,50f /* if monotonic -> jump there */ - - /* - * CLOCK_REALTIME - */ - - bl __do_get_xsec@local /* get xsec from tb & kernel */ - bne- 98f /* out of line -> do syscall */ - - /* seconds are xsec >> 20 */ - rlwinm r5,r4,12,20,31 - rlwimi r5,r3,12,0,19 - stw r5,TSPC32_TV_SEC(r11) - /* get remaining xsec and convert to nsec. we scale - * up remaining xsec by 12 bits and get the top 32 bits - * of the multiplication, then we multiply by 1000 - */ - rlwinm r5,r4,12,0,19 - lis r6,1000000@h - ori r6,r6,1000000@l - mulhwu r5,r5,r6 - mulli r5,r5,1000 - stw r5,TSPC32_TV_NSEC(r11) - mtlr r12 - crclr cr0*4+so - li r3,0 - blr +50: bl __do_get_tspec@local /* get sec/nsec from tb & kernel */ + bne cr1,80f /* not monotonic -> all done */ /* * CLOCK_MONOTONIC */ -50: bl __do_get_xsec@local /* get xsec from tb & kernel */ - bne- 98f /* out of line -> do syscall */ - - /* seconds are xsec >> 20 */ - rlwinm r6,r4,12,20,31 - rlwimi r6,r3,12,0,19 - - /* get remaining xsec and convert to nsec. we scale - * up remaining xsec by 12 bits and get the top 32 bits - * of the multiplication, then we multiply by 1000 - */ - rlwinm r7,r4,12,0,19 - lis r5,1000000@h - ori r5,r5,1000000@l - mulhwu r7,r7,r5 - mulli r7,r7,1000 - /* now we must fixup using wall to monotonic. We need to snapshot * that value and do the counter trick again. Fortunately, we still * have the counter value in r8 that was returned by __do_get_xsec. - * At this point, r6,r7 contain our sec/nsec values, r3,r4 and r5 - * can be used + * At this point, r3,r4 contain our sec/nsec values, r5 and r6 + * can be used, r7 contains NSEC_PER_SEC. */ - lwz r3,WTOM_CLOCK_SEC(r9) - lwz r4,WTOM_CLOCK_NSEC(r9) + lwz r5,WTOM_CLOCK_SEC(r9) + lwz r6,WTOM_CLOCK_NSEC(r9) - /* We now have our result in r3,r4. We create a fake dependency - * on that result and re-check the counter + /* We now have our offset in r5,r6. We create a fake dependency + * on that value and re-check the counter */ - or r5,r4,r3 - xor r0,r5,r5 + or r0,r6,r5 + xor r0,r0,r0 add r9,r9,r0 -#ifdef CONFIG_PPC64 - lwz r0,(CFG_TB_UPDATE_COUNT+4)(r9) -#else - lwz r0,(CFG_TB_UPDATE_COUNT)(r9) -#endif + lwz r0,(CFG_TB_UPDATE_COUNT+LOPART)(r9) cmpl cr0,r8,r0 /* check if updated */ bne- 50b - /* Calculate and store result. Note that this mimmics the C code, + /* Calculate and store result. Note that this mimics the C code, * which may cause funny results if nsec goes negative... is that * possible at all ? */ - add r3,r3,r6 - add r4,r4,r7 - lis r5,NSEC_PER_SEC@h - ori r5,r5,NSEC_PER_SEC@l - cmpl cr0,r4,r5 - cmpli cr1,r4,0 + add r3,r3,r5 + add r4,r4,r6 + cmpw cr0,r4,r7 + cmpwi cr1,r4,0 blt 1f - subf r4,r5,r4 + subf r4,r7,r4 addi r3,r3,1 -1: bge cr1,1f +1: bge cr1,80f addi r3,r3,-1 - add r4,r4,r5 -1: stw r3,TSPC32_TV_SEC(r11) + add r4,r4,r7 + +80: stw r3,TSPC32_TV_SEC(r11) stw r4,TSPC32_TV_NSEC(r11) mtlr r12 @@ -195,10 +154,6 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime) /* * syscall fallback */ -98: - mtlr r12 - mr r3,r10 - mr r4,r11 99: li r0,__NR_clock_gettime sc @@ -254,11 +209,7 @@ __do_get_xsec: /* Check for update count & load values. We use the low * order 32 bits of the update count */ -#ifdef CONFIG_PPC64 -1: lwz r8,(CFG_TB_UPDATE_COUNT+4)(r9) -#else -1: lwz r8,(CFG_TB_UPDATE_COUNT)(r9) -#endif +1: lwz r8,(CFG_TB_UPDATE_COUNT+LOPART)(r9) andi. r0,r8,1 /* pending update ? loop */ bne- 1b xor r0,r8,r8 /* create dependency */ @@ -305,11 +256,7 @@ __do_get_xsec: or r6,r4,r3 xor r0,r6,r6 add r9,r9,r0 -#ifdef CONFIG_PPC64 - lwz r0,(CFG_TB_UPDATE_COUNT+4)(r9) -#else - lwz r0,(CFG_TB_UPDATE_COUNT)(r9) -#endif + lwz r0,(CFG_TB_UPDATE_COUNT+LOPART)(r9) cmpl cr0,r8,r0 /* check if updated */ bne- 1b @@ -322,3 +269,98 @@ __do_get_xsec: */ 3: blr .cfi_endproc + +/* + * This is the core of clock_gettime(), it returns the current + * time in seconds and nanoseconds in r3 and r4. + * It expects the datapage ptr in r9 and doesn't clobber it. + * It clobbers r0, r5, r6, r10 and returns NSEC_PER_SEC in r7. + * On return, r8 contains the counter value that can be reused. + * This clobbers cr0 but not any other cr field. + */ +__do_get_tspec: + .cfi_startproc + /* Check for update count & load values. We use the low + * order 32 bits of the update count + */ +1: lwz r8,(CFG_TB_UPDATE_COUNT+LOPART)(r9) + andi. r0,r8,1 /* pending update ? loop */ + bne- 1b + xor r0,r8,r8 /* create dependency */ + add r9,r9,r0 + + /* Load orig stamp (offset to TB) */ + lwz r5,CFG_TB_ORIG_STAMP(r9) + lwz r6,(CFG_TB_ORIG_STAMP+4)(r9) + + /* Get a stable TB value */ +2: mftbu r3 + mftbl r4 + mftbu r0 + cmpl cr0,r3,r0 + bne- 2b + + /* Subtract tb orig stamp and shift left 12 bits. + */ + subfc r7,r6,r4 + subfe r0,r5,r3 + slwi r0,r0,12 + rlwimi. r0,r7,12,20,31 + slwi r7,r7,12 + + /* Load scale factor & do multiplication */ + lwz r5,CFG_TB_TO_XS(r9) /* load values */ + lwz r6,(CFG_TB_TO_XS+4)(r9) + mulhwu r3,r7,r6 + mullw r10,r7,r5 + mulhwu r4,r7,r5 + addc r10,r3,r10 + li r3,0 + + beq+ 4f /* skip high part computation if 0 */ + mulhwu r3,r0,r5 + mullw r7,r0,r5 + mulhwu r5,r0,r6 + mullw r6,r0,r6 + adde r4,r4,r7 + addze r3,r3 + addc r4,r4,r5 + addze r3,r3 + addc r10,r10,r6 + +4: addze r4,r4 /* add in carry */ + lis r7,NSEC_PER_SEC@h + ori r7,r7,NSEC_PER_SEC@l + mulhwu r4,r4,r7 /* convert to nanoseconds */ + + /* At this point, we have seconds & nanoseconds since the xtime + * stamp in r3+CA and r4. Load & add the xtime stamp. + */ +#ifdef CONFIG_PPC64 + lwz r5,STAMP_XTIME+TSPC64_TV_SEC+LOPART(r9) + lwz r6,STAMP_XTIME+TSPC64_TV_NSEC+LOPART(r9) +#else + lwz r5,STAMP_XTIME+TSPC32_TV_SEC(r9) + lwz r6,STAMP_XTIME+TSPC32_TV_NSEC(r9) +#endif + add r4,r4,r6 + adde r3,r3,r5 + + /* We now have our result in r3,r4. We create a fake dependency + * on that result and re-check the counter + */ + or r6,r4,r3 + xor r0,r6,r6 + add r9,r9,r0 + lwz r0,(CFG_TB_UPDATE_COUNT+LOPART)(r9) + cmpl cr0,r8,r0 /* check if updated */ + bne- 1b + + /* check for nanosecond overflow and adjust if necessary */ + cmpw r4,r7 + bltlr /* all done if no overflow */ + subf r4,r7,r4 /* adjust if overflow */ + addi r3,r3,1 + + blr + .cfi_endproc diff --git a/arch/powerpc/kernel/vdso32/vdso32.lds.S b/arch/powerpc/kernel/vdso32/vdso32.lds.S index be3b6a41dc09f7c78402405182502eff3f360dd4..904ef1360dd7bca3ee4cbffead2e4dfefcce57f2 100644 --- a/arch/powerpc/kernel/vdso32/vdso32.lds.S +++ b/arch/powerpc/kernel/vdso32/vdso32.lds.S @@ -33,6 +33,9 @@ SECTIONS . = ALIGN(8); __ftr_fixup : { *(__ftr_fixup) } + . = ALIGN(8); + __mmu_ftr_fixup : { *(__mmu_ftr_fixup) } + . = ALIGN(8); __lwsync_fixup : { *(__lwsync_fixup) } diff --git a/arch/powerpc/kernel/vdso64/gettimeofday.S b/arch/powerpc/kernel/vdso64/gettimeofday.S index c6401f9e37f1fd2427cc6fa9373a3bff335949c8..262cd5857a56dff9b53657e2a0872b7c769cc63e 100644 --- a/arch/powerpc/kernel/vdso64/gettimeofday.S +++ b/arch/powerpc/kernel/vdso64/gettimeofday.S @@ -75,90 +75,49 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime) mflr r12 /* r12 saves lr */ .cfi_register lr,r12 - mr r10,r3 /* r10 saves id */ mr r11,r4 /* r11 saves tp */ bl V_LOCAL_FUNC(__get_datapage) /* get data page */ - beq cr1,50f /* if monotonic -> jump there */ - - /* - * CLOCK_REALTIME - */ - - bl V_LOCAL_FUNC(__do_get_xsec) /* get xsec from tb & kernel */ - - lis r7,15 /* r7 = 1000000 = USEC_PER_SEC */ - ori r7,r7,16960 - rldicl r5,r4,44,20 /* r5 = sec = xsec / XSEC_PER_SEC */ - rldicr r6,r5,20,43 /* r6 = sec * XSEC_PER_SEC */ - std r5,TSPC64_TV_SEC(r11) /* store sec in tv */ - subf r0,r6,r4 /* r0 = xsec = (xsec - r6) */ - mulld r0,r0,r7 /* usec = (xsec * USEC_PER_SEC) / - * XSEC_PER_SEC - */ - rldicl r0,r0,44,20 - mulli r0,r0,1000 /* nsec = usec * 1000 */ - std r0,TSPC64_TV_NSEC(r11) /* store nsec in tp */ - - mtlr r12 - crclr cr0*4+so - li r3,0 - blr +50: bl V_LOCAL_FUNC(__do_get_tspec) /* get time from tb & kernel */ + bne cr1,80f /* if not monotonic, all done */ /* * CLOCK_MONOTONIC */ -50: bl V_LOCAL_FUNC(__do_get_xsec) /* get xsec from tb & kernel */ - - lis r7,15 /* r7 = 1000000 = USEC_PER_SEC */ - ori r7,r7,16960 - rldicl r5,r4,44,20 /* r5 = sec = xsec / XSEC_PER_SEC */ - rldicr r6,r5,20,43 /* r6 = sec * XSEC_PER_SEC */ - subf r0,r6,r4 /* r0 = xsec = (xsec - r6) */ - mulld r0,r0,r7 /* usec = (xsec * USEC_PER_SEC) / - * XSEC_PER_SEC - */ - rldicl r6,r0,44,20 - mulli r6,r6,1000 /* nsec = usec * 1000 */ - /* now we must fixup using wall to monotonic. We need to snapshot * that value and do the counter trick again. Fortunately, we still - * have the counter value in r8 that was returned by __do_get_xsec. - * At this point, r5,r6 contain our sec/nsec values. - * can be used + * have the counter value in r8 that was returned by __do_get_tspec. + * At this point, r4,r5 contain our sec/nsec values. */ - lwa r4,WTOM_CLOCK_SEC(r3) - lwa r7,WTOM_CLOCK_NSEC(r3) + lwa r6,WTOM_CLOCK_SEC(r3) + lwa r9,WTOM_CLOCK_NSEC(r3) - /* We now have our result in r4,r7. We create a fake dependency + /* We now have our result in r6,r9. We create a fake dependency * on that result and re-check the counter */ - or r9,r4,r7 - xor r0,r9,r9 + or r0,r6,r9 + xor r0,r0,r0 add r3,r3,r0 ld r0,CFG_TB_UPDATE_COUNT(r3) cmpld cr0,r0,r8 /* check if updated */ bne- 50b - /* Calculate and store result. Note that this mimmics the C code, - * which may cause funny results if nsec goes negative... is that - * possible at all ? + /* Add wall->monotonic offset and check for overflow or underflow. */ - add r4,r4,r5 - add r7,r7,r6 - lis r9,NSEC_PER_SEC@h - ori r9,r9,NSEC_PER_SEC@l - cmpl cr0,r7,r9 - cmpli cr1,r7,0 + add r4,r4,r6 + add r5,r5,r9 + cmpd cr0,r5,r7 + cmpdi cr1,r5,0 blt 1f - subf r7,r9,r7 + subf r5,r7,r5 addi r4,r4,1 -1: bge cr1,1f +1: bge cr1,80f addi r4,r4,-1 - add r7,r7,r9 -1: std r4,TSPC64_TV_SEC(r11) - std r7,TSPC64_TV_NSEC(r11) + add r5,r5,r7 + +80: std r4,TSPC64_TV_SEC(r11) + std r5,TSPC64_TV_NSEC(r11) mtlr r12 crclr cr0*4+so @@ -168,10 +127,6 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime) /* * syscall fallback */ -98: - mtlr r12 - mr r3,r10 - mr r4,r11 99: li r0,__NR_clock_gettime sc @@ -253,3 +208,59 @@ V_FUNCTION_BEGIN(__do_get_xsec) blr .cfi_endproc V_FUNCTION_END(__do_get_xsec) + +/* + * This is the core of clock_gettime(), it returns the current + * time in seconds and nanoseconds in r4 and r5. + * It expects the datapage ptr in r3 and doesn't clobber it. + * It clobbers r0 and r6 and returns NSEC_PER_SEC in r7. + * On return, r8 contains the counter value that can be reused. + * This clobbers cr0 but not any other cr field. + */ +V_FUNCTION_BEGIN(__do_get_tspec) + .cfi_startproc + /* check for update count & load values */ +1: ld r8,CFG_TB_UPDATE_COUNT(r3) + andi. r0,r8,1 /* pending update ? loop */ + bne- 1b + xor r0,r8,r8 /* create dependency */ + add r3,r3,r0 + + /* Get TB & offset it. We use the MFTB macro which will generate + * workaround code for Cell. + */ + MFTB(r7) + ld r9,CFG_TB_ORIG_STAMP(r3) + subf r7,r9,r7 + + /* Scale result */ + ld r5,CFG_TB_TO_XS(r3) + sldi r7,r7,12 /* compute time since stamp_xtime */ + mulhdu r6,r7,r5 /* in units of 2^-32 seconds */ + + /* Add stamp since epoch */ + ld r4,STAMP_XTIME+TSPC64_TV_SEC(r3) + ld r5,STAMP_XTIME+TSPC64_TV_NSEC(r3) + or r0,r4,r5 + or r0,r0,r6 + xor r0,r0,r0 + add r3,r3,r0 + ld r0,CFG_TB_UPDATE_COUNT(r3) + cmpld r0,r8 /* check if updated */ + bne- 1b /* reload if so */ + + /* convert to seconds & nanoseconds and add to stamp */ + lis r7,NSEC_PER_SEC@h + ori r7,r7,NSEC_PER_SEC@l + mulhwu r0,r6,r7 /* compute nanoseconds and */ + srdi r6,r6,32 /* seconds since stamp_xtime */ + clrldi r0,r0,32 + add r5,r5,r0 /* add nanoseconds together */ + cmpd r5,r7 /* overflow? */ + add r4,r4,r6 + bltlr /* all done if no overflow */ + subf r5,r7,r5 /* if overflow, adjust */ + addi r4,r4,1 + blr + .cfi_endproc +V_FUNCTION_END(__do_get_tspec) diff --git a/arch/powerpc/kernel/vdso64/vdso64.lds.S b/arch/powerpc/kernel/vdso64/vdso64.lds.S index d0b2526dd38d05e0dda9870d4dd1eea529845bea..0e615404e247353cd9a696bb086d03486013403e 100644 --- a/arch/powerpc/kernel/vdso64/vdso64.lds.S +++ b/arch/powerpc/kernel/vdso64/vdso64.lds.S @@ -34,6 +34,9 @@ SECTIONS . = ALIGN(8); __ftr_fixup : { *(__ftr_fixup) } + . = ALIGN(8); + __mmu_ftr_fixup : { *(__mmu_ftr_fixup) } + . = ALIGN(8); __lwsync_fixup : { *(__lwsync_fixup) } diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index a11e6bc59b307e9d9ac7e6892e95a4eef34f6ca1..94aa7b011b276528d2ec7677e2e01abac612fc7e 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -41,9 +41,9 @@ static struct bus_type vio_bus_type; static struct vio_dev vio_bus_device = { /* fake "parent" device */ - .name = vio_bus_device.dev.bus_id, + .name = "vio", .type = "", - .dev.bus_id = "vio", + .dev.init_name = "vio", .dev.bus = &vio_bus_type, }; @@ -1216,7 +1216,7 @@ struct vio_dev *vio_register_device_node(struct device_node *of_node) viodev->irq = irq_of_parse_and_map(of_node, 0); - snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%x", *unit_address); + dev_set_name(&viodev->dev, "%x", *unit_address); viodev->name = of_node->name; viodev->type = of_node->type; viodev->unit_address = *unit_address; @@ -1243,7 +1243,7 @@ struct vio_dev *vio_register_device_node(struct device_node *of_node) /* register with generic device framework */ if (device_register(&viodev->dev)) { printk(KERN_ERR "%s: failed to register device %s\n", - __func__, viodev->dev.bus_id); + __func__, dev_name(&viodev->dev)); /* XXX free TCE table */ kfree(viodev); return NULL; @@ -1400,13 +1400,13 @@ static struct vio_dev *vio_find_name(const char *name) struct vio_dev *vio_find_node(struct device_node *vnode) { const uint32_t *unit_address; - char kobj_name[BUS_ID_SIZE]; + char kobj_name[20]; /* construct the kobject name from the device node */ unit_address = of_get_property(vnode, "reg", NULL); if (!unit_address) return NULL; - snprintf(kobj_name, BUS_ID_SIZE, "%x", *unit_address); + snprintf(kobj_name, sizeof(kobj_name), "%x", *unit_address); return vio_find_name(kobj_name); } diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index 2412c056baa45bcf81d5716786ccc6edfd9118a3..47bf15cd2c9eb62be6d00d12f2f1e8130976ce93 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -152,6 +152,12 @@ SECTIONS __stop___ftr_fixup = .; } . = ALIGN(8); + __mmu_ftr_fixup : AT(ADDR(__mmu_ftr_fixup) - LOAD_OFFSET) { + __start___mmu_ftr_fixup = .; + *(__mmu_ftr_fixup) + __stop___mmu_ftr_fixup = .; + } + . = ALIGN(8); __lwsync_fixup : AT(ADDR(__lwsync_fixup) - LOAD_OFFSET) { __start___lwsync_fixup = .; *(__lwsync_fixup) diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index fda9baada132b1c5348dfec8b84ba99d8bc24dc1..8bef0efcdfe19ba11b1f5d8d9f3561213f6a2a45 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -28,6 +28,7 @@ #include #include #include +#include "../mm/mmu_decl.h" gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn) @@ -330,7 +331,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) /* XXX It would be nice to differentiate between heavyweight exit and * sched_out here, since we could avoid the TLB flush for heavyweight * exits. */ - _tlbia(); + _tlbil_all(); } int kvm_arch_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu, diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index d69912c07ce732c937412dac1286ba0223ded96c..8db35278a4b43643c2cf42b280b79ad9d33be7bc 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile @@ -6,6 +6,9 @@ ifeq ($(CONFIG_PPC64),y) EXTRA_CFLAGS += -mno-minimal-toc endif +CFLAGS_REMOVE_code-patching.o = -pg +CFLAGS_REMOVE_feature-fixups.o = -pg + obj-y := string.o alloc.o \ checksum_$(CONFIG_WORD_SIZE).o obj-$(CONFIG_PPC32) += div64.o copy_32.o crtsavres.o diff --git a/arch/powerpc/lib/copyuser_64.S b/arch/powerpc/lib/copyuser_64.S index 25ec5378afa454232704d48c604e968efdd33cc0..70693a5c12a113d36d55a0dd1800a255589e73a0 100644 --- a/arch/powerpc/lib/copyuser_64.S +++ b/arch/powerpc/lib/copyuser_64.S @@ -26,11 +26,24 @@ _GLOBAL(__copy_tofrom_user) andi. r6,r6,7 PPC_MTOCRF 0x01,r5 blt cr1,.Lshort_copy +/* Below we want to nop out the bne if we're on a CPU that has the + * CPU_FTR_UNALIGNED_LD_STD bit set and the CPU_FTR_CP_USE_DCBTZ bit + * cleared. + * At the time of writing the only CPU that has this combination of bits + * set is Power6. + */ +BEGIN_FTR_SECTION + nop +FTR_SECTION_ELSE bne .Ldst_unaligned +ALT_FTR_SECTION_END(CPU_FTR_UNALIGNED_LD_STD | CPU_FTR_CP_USE_DCBTZ, \ + CPU_FTR_UNALIGNED_LD_STD) .Ldst_aligned: - andi. r0,r4,7 addi r3,r3,-16 +BEGIN_FTR_SECTION + andi. r0,r4,7 bne .Lsrc_unaligned +END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD) srdi r7,r5,4 20: ld r9,0(r4) addi r4,r4,-8 @@ -138,7 +151,7 @@ _GLOBAL(__copy_tofrom_user) PPC_MTOCRF 0x01,r6 /* put #bytes to 8B bdry into cr7 */ subf r5,r6,r5 li r7,0 - cmpldi r1,r5,16 + cmpldi cr1,r5,16 bf cr7*4+3,1f 35: lbz r0,0(r4) 81: stb r0,0(r3) diff --git a/arch/powerpc/lib/dma-noncoherent.c b/arch/powerpc/lib/dma-noncoherent.c index 31734c0969cd28014b226f300f0b1932186ea4e1..b7dc4c19f58211641d2bb1db44dea62315a3d641 100644 --- a/arch/powerpc/lib/dma-noncoherent.c +++ b/arch/powerpc/lib/dma-noncoherent.c @@ -77,26 +77,26 @@ static DEFINE_SPINLOCK(consistent_lock); * the amount of RAM found at boot time.) I would imagine that get_vm_area() * would have to initialise this each time prior to calling vm_region_alloc(). */ -struct vm_region { +struct ppc_vm_region { struct list_head vm_list; unsigned long vm_start; unsigned long vm_end; }; -static struct vm_region consistent_head = { +static struct ppc_vm_region consistent_head = { .vm_list = LIST_HEAD_INIT(consistent_head.vm_list), .vm_start = CONSISTENT_BASE, .vm_end = CONSISTENT_END, }; -static struct vm_region * -vm_region_alloc(struct vm_region *head, size_t size, gfp_t gfp) +static struct ppc_vm_region * +ppc_vm_region_alloc(struct ppc_vm_region *head, size_t size, gfp_t gfp) { unsigned long addr = head->vm_start, end = head->vm_end - size; unsigned long flags; - struct vm_region *c, *new; + struct ppc_vm_region *c, *new; - new = kmalloc(sizeof(struct vm_region), gfp); + new = kmalloc(sizeof(struct ppc_vm_region), gfp); if (!new) goto out; @@ -130,9 +130,9 @@ vm_region_alloc(struct vm_region *head, size_t size, gfp_t gfp) return NULL; } -static struct vm_region *vm_region_find(struct vm_region *head, unsigned long addr) +static struct ppc_vm_region *ppc_vm_region_find(struct ppc_vm_region *head, unsigned long addr) { - struct vm_region *c; + struct ppc_vm_region *c; list_for_each_entry(c, &head->vm_list, vm_list) { if (c->vm_start == addr) @@ -151,7 +151,7 @@ void * __dma_alloc_coherent(size_t size, dma_addr_t *handle, gfp_t gfp) { struct page *page; - struct vm_region *c; + struct ppc_vm_region *c; unsigned long order; u64 mask = 0x00ffffff, limit; /* ISA default */ @@ -191,7 +191,7 @@ __dma_alloc_coherent(size_t size, dma_addr_t *handle, gfp_t gfp) /* * Allocate a virtual address in the consistent mapping region. */ - c = vm_region_alloc(&consistent_head, size, + c = ppc_vm_region_alloc(&consistent_head, size, gfp & ~(__GFP_DMA | __GFP_HIGHMEM)); if (c) { unsigned long vaddr = c->vm_start; @@ -239,7 +239,7 @@ EXPORT_SYMBOL(__dma_alloc_coherent); */ void __dma_free_coherent(size_t size, void *vaddr) { - struct vm_region *c; + struct ppc_vm_region *c; unsigned long flags, addr; pte_t *ptep; @@ -247,7 +247,7 @@ void __dma_free_coherent(size_t size, void *vaddr) spin_lock_irqsave(&consistent_lock, flags); - c = vm_region_find(&consistent_head, (unsigned long)vaddr); + c = ppc_vm_region_find(&consistent_head, (unsigned long)vaddr); if (!c) goto no_area; @@ -320,7 +320,6 @@ static int __init dma_alloc_init(void) ret = -ENOMEM; break; } - WARN_ON(!pmd_none(*pmd)); pte = pte_alloc_kernel(pmd, CONSISTENT_BASE); if (!pte) { diff --git a/arch/powerpc/lib/memcpy_64.S b/arch/powerpc/lib/memcpy_64.S index 3f131129d1c1a496607637f39eb1f563596768d0..fe2d34e5332d8250dd778ca77489631e2a4e9266 100644 --- a/arch/powerpc/lib/memcpy_64.S +++ b/arch/powerpc/lib/memcpy_64.S @@ -18,11 +18,23 @@ _GLOBAL(memcpy) andi. r6,r6,7 dcbt 0,r4 blt cr1,.Lshort_copy +/* Below we want to nop out the bne if we're on a CPU that has the + CPU_FTR_UNALIGNED_LD_STD bit set and the CPU_FTR_CP_USE_DCBTZ bit + cleared. + At the time of writing the only CPU that has this combination of bits + set is Power6. */ +BEGIN_FTR_SECTION + nop +FTR_SECTION_ELSE bne .Ldst_unaligned +ALT_FTR_SECTION_END(CPU_FTR_UNALIGNED_LD_STD | CPU_FTR_CP_USE_DCBTZ, \ + CPU_FTR_UNALIGNED_LD_STD) .Ldst_aligned: - andi. r0,r4,7 addi r3,r3,-16 +BEGIN_FTR_SECTION + andi. r0,r4,7 bne .Lsrc_unaligned +END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD) srdi r7,r5,4 ld r9,0(r4) addi r4,r4,-8 @@ -131,7 +143,7 @@ _GLOBAL(memcpy) PPC_MTOCRF 0x01,r6 # put #bytes to 8B bdry into cr7 subf r5,r6,r5 li r7,0 - cmpldi r1,r5,16 + cmpldi cr1,r5,16 bf cr7*4+3,1f lbz r0,0(r4) stb r0,0(r3) diff --git a/arch/powerpc/math-emu/Makefile b/arch/powerpc/math-emu/Makefile index 03aa98dd9f0a5c0b1a6f564bd9a658d2260620cc..f9e506a735ae2e0d833bb0d0197b7d323679a67c 100644 --- a/arch/powerpc/math-emu/Makefile +++ b/arch/powerpc/math-emu/Makefile @@ -11,6 +11,8 @@ obj-$(CONFIG_MATH_EMULATION) += fabs.o fadd.o fadds.o fcmpo.o fcmpu.o \ mcrfs.o mffs.o mtfsb0.o mtfsb1.o \ mtfsf.o mtfsfi.o stfiwx.o stfs.o +obj-$(CONFIG_SPE) += math_efp.o + CFLAGS_fabs.o = -fno-builtin-fabs CFLAGS_math.o = -fno-builtin-fabs diff --git a/arch/powerpc/math-emu/fadd.c b/arch/powerpc/math-emu/fadd.c index 04d3b4aa32cedb9ab75801aaa6b21a5019118a98..0158a16e2b826b7597563dd56c7a12c63c5c4ee7 100644 --- a/arch/powerpc/math-emu/fadd.c +++ b/arch/powerpc/math-emu/fadd.c @@ -13,7 +13,6 @@ fadd(void *frD, void *frA, void *frB) FP_DECL_D(B); FP_DECL_D(R); FP_DECL_EX; - int ret = 0; #ifdef DEBUG printk("%s: %p %p %p\n", __func__, frD, frA, frB); diff --git a/arch/powerpc/math-emu/fcmpo.c b/arch/powerpc/math-emu/fcmpo.c index b5dc4498cd71023dfdc237f79415b1043901f36b..5bce011c2aece41137e83ca30611cbdc7f5db7f1 100644 --- a/arch/powerpc/math-emu/fcmpo.c +++ b/arch/powerpc/math-emu/fcmpo.c @@ -14,7 +14,6 @@ fcmpo(u32 *ccr, int crfD, void *frA, void *frB) FP_DECL_EX; int code[4] = { (1 << 3), (1 << 1), (1 << 2), (1 << 0) }; long cmp; - int ret = 0; #ifdef DEBUG printk("%s: %p (%08x) %d %p %p\n", __func__, ccr, *ccr, crfD, frA, frB); @@ -29,7 +28,7 @@ fcmpo(u32 *ccr, int crfD, void *frA, void *frB) #endif if (A_c == FP_CLS_NAN || B_c == FP_CLS_NAN) - ret |= EFLAG_VXVC; + FP_SET_EXCEPTION(EFLAG_VXVC); FP_CMP_D(cmp, A, B, 2); cmp = code[(cmp + 1) & 3]; @@ -44,5 +43,5 @@ fcmpo(u32 *ccr, int crfD, void *frA, void *frB) printk("CR: %08x\n", *ccr); #endif - return ret; + return FP_CUR_EXCEPTIONS; } diff --git a/arch/powerpc/math-emu/fdiv.c b/arch/powerpc/math-emu/fdiv.c index 2db15097d98e9ba65ad049023561bdf397d26054..a29239c05e3eecb13b47b193b9e54e4aa04696d2 100644 --- a/arch/powerpc/math-emu/fdiv.c +++ b/arch/powerpc/math-emu/fdiv.c @@ -13,7 +13,6 @@ fdiv(void *frD, void *frA, void *frB) FP_DECL_D(B); FP_DECL_D(R); FP_DECL_EX; - int ret = 0; #ifdef DEBUG printk("%s: %p %p %p\n", __func__, frD, frA, frB); @@ -28,22 +27,22 @@ fdiv(void *frD, void *frA, void *frB) #endif if (A_c == FP_CLS_ZERO && B_c == FP_CLS_ZERO) { - ret |= EFLAG_VXZDZ; + FP_SET_EXCEPTION(EFLAG_VXZDZ); #ifdef DEBUG printk("%s: FPSCR_VXZDZ raised\n", __func__); #endif } if (A_c == FP_CLS_INF && B_c == FP_CLS_INF) { - ret |= EFLAG_VXIDI; + FP_SET_EXCEPTION(EFLAG_VXIDI); #ifdef DEBUG printk("%s: FPSCR_VXIDI raised\n", __func__); #endif } if (B_c == FP_CLS_ZERO && A_c != FP_CLS_ZERO) { - ret |= EFLAG_DIVZERO; + FP_SET_EXCEPTION(EFLAG_DIVZERO); if (__FPU_TRAP_P(EFLAG_DIVZERO)) - return ret; + return FP_CUR_EXCEPTIONS; } FP_DIV_D(R, A, B); diff --git a/arch/powerpc/math-emu/fdivs.c b/arch/powerpc/math-emu/fdivs.c index 797f6a9a20b53f405687828c556ca526235ef201..526bc261275f81178320637a82f467c30131cbe5 100644 --- a/arch/powerpc/math-emu/fdivs.c +++ b/arch/powerpc/math-emu/fdivs.c @@ -14,7 +14,6 @@ fdivs(void *frD, void *frA, void *frB) FP_DECL_D(B); FP_DECL_D(R); FP_DECL_EX; - int ret = 0; #ifdef DEBUG printk("%s: %p %p %p\n", __func__, frD, frA, frB); @@ -29,22 +28,22 @@ fdivs(void *frD, void *frA, void *frB) #endif if (A_c == FP_CLS_ZERO && B_c == FP_CLS_ZERO) { - ret |= EFLAG_VXZDZ; + FP_SET_EXCEPTION(EFLAG_VXZDZ); #ifdef DEBUG printk("%s: FPSCR_VXZDZ raised\n", __func__); #endif } if (A_c == FP_CLS_INF && B_c == FP_CLS_INF) { - ret |= EFLAG_VXIDI; + FP_SET_EXCEPTION(EFLAG_VXIDI); #ifdef DEBUG printk("%s: FPSCR_VXIDI raised\n", __func__); #endif } if (B_c == FP_CLS_ZERO && A_c != FP_CLS_ZERO) { - ret |= EFLAG_DIVZERO; + FP_SET_EXCEPTION(EFLAG_DIVZERO); if (__FPU_TRAP_P(EFLAG_DIVZERO)) - return ret; + return FP_CUR_EXCEPTIONS; } FP_DIV_D(R, A, B); diff --git a/arch/powerpc/math-emu/fmadd.c b/arch/powerpc/math-emu/fmadd.c index 925313aa6f82b38b73307d0bfea6936d3021917e..8c3f20aa5a95359e354986f429720d3c2c0d9f73 100644 --- a/arch/powerpc/math-emu/fmadd.c +++ b/arch/powerpc/math-emu/fmadd.c @@ -15,7 +15,6 @@ fmadd(void *frD, void *frA, void *frB, void *frC) FP_DECL_D(C); FP_DECL_D(T); FP_DECL_EX; - int ret = 0; #ifdef DEBUG printk("%s: %p %p %p %p\n", __func__, frD, frA, frB, frC); @@ -33,12 +32,12 @@ fmadd(void *frD, void *frA, void *frB, void *frC) if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) || (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF)) - ret |= EFLAG_VXIMZ; + FP_SET_EXCEPTION(EFLAG_VXIMZ); FP_MUL_D(T, A, C); if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF) - ret |= EFLAG_VXISI; + FP_SET_EXCEPTION(EFLAG_VXISI); FP_ADD_D(R, T, B); diff --git a/arch/powerpc/math-emu/fmadds.c b/arch/powerpc/math-emu/fmadds.c index aea80ef79399d3630d5574a534a49e64d978810a..794fb31e59d17c878b44c7927c7dd5431cc3ac9c 100644 --- a/arch/powerpc/math-emu/fmadds.c +++ b/arch/powerpc/math-emu/fmadds.c @@ -16,7 +16,6 @@ fmadds(void *frD, void *frA, void *frB, void *frC) FP_DECL_D(C); FP_DECL_D(T); FP_DECL_EX; - int ret = 0; #ifdef DEBUG printk("%s: %p %p %p %p\n", __func__, frD, frA, frB, frC); @@ -34,12 +33,12 @@ fmadds(void *frD, void *frA, void *frB, void *frC) if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) || (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF)) - ret |= EFLAG_VXIMZ; + FP_SET_EXCEPTION(EFLAG_VXIMZ); FP_MUL_D(T, A, C); if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF) - ret |= EFLAG_VXISI; + FP_SET_EXCEPTION(EFLAG_VXISI); FP_ADD_D(R, T, B); diff --git a/arch/powerpc/math-emu/fmsub.c b/arch/powerpc/math-emu/fmsub.c index a644d525fca66442f0c2322b52fe0d9c6d1d4f5c..626f6fed84ac5c06541013dcd7df5c5c4a2f8104 100644 --- a/arch/powerpc/math-emu/fmsub.c +++ b/arch/powerpc/math-emu/fmsub.c @@ -15,7 +15,6 @@ fmsub(void *frD, void *frA, void *frB, void *frC) FP_DECL_D(C); FP_DECL_D(T); FP_DECL_EX; - int ret = 0; #ifdef DEBUG printk("%s: %p %p %p %p\n", __func__, frD, frA, frB, frC); @@ -33,7 +32,7 @@ fmsub(void *frD, void *frA, void *frB, void *frC) if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) || (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF)) - ret |= EFLAG_VXIMZ; + FP_SET_EXCEPTION(EFLAG_VXIMZ); FP_MUL_D(T, A, C); @@ -41,7 +40,7 @@ fmsub(void *frD, void *frA, void *frB, void *frC) B_s ^= 1; if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF) - ret |= EFLAG_VXISI; + FP_SET_EXCEPTION(EFLAG_VXISI); FP_ADD_D(R, T, B); diff --git a/arch/powerpc/math-emu/fmsubs.c b/arch/powerpc/math-emu/fmsubs.c index 2fdeeb9bb569690b5c5e67adca34f2f3d51f68da..3425bc899760483012920dcd3bcbf74fb03057a5 100644 --- a/arch/powerpc/math-emu/fmsubs.c +++ b/arch/powerpc/math-emu/fmsubs.c @@ -16,7 +16,6 @@ fmsubs(void *frD, void *frA, void *frB, void *frC) FP_DECL_D(C); FP_DECL_D(T); FP_DECL_EX; - int ret = 0; #ifdef DEBUG printk("%s: %p %p %p %p\n", __func__, frD, frA, frB, frC); @@ -34,7 +33,7 @@ fmsubs(void *frD, void *frA, void *frB, void *frC) if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) || (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF)) - ret |= EFLAG_VXIMZ; + FP_SET_EXCEPTION(EFLAG_VXIMZ); FP_MUL_D(T, A, C); @@ -42,7 +41,7 @@ fmsubs(void *frD, void *frA, void *frB, void *frC) B_s ^= 1; if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF) - ret |= EFLAG_VXISI; + FP_SET_EXCEPTION(EFLAG_VXISI); FP_ADD_D(R, T, B); diff --git a/arch/powerpc/math-emu/fmul.c b/arch/powerpc/math-emu/fmul.c index 391fd17d3440fd85c1637480857ffc386c219e6c..2c1929779892b6e29f228467c0625a46cff830ee 100644 --- a/arch/powerpc/math-emu/fmul.c +++ b/arch/powerpc/math-emu/fmul.c @@ -13,7 +13,6 @@ fmul(void *frD, void *frA, void *frB) FP_DECL_D(B); FP_DECL_D(R); FP_DECL_EX; - int ret = 0; #ifdef DEBUG printk("%s: %p %p %p\n", __func__, frD, frA, frB); @@ -31,7 +30,7 @@ fmul(void *frD, void *frA, void *frB) if ((A_c == FP_CLS_INF && B_c == FP_CLS_ZERO) || (A_c == FP_CLS_ZERO && B_c == FP_CLS_INF)) - ret |= EFLAG_VXIMZ; + FP_SET_EXCEPTION(EFLAG_VXIMZ); FP_MUL_D(R, A, B); diff --git a/arch/powerpc/math-emu/fmuls.c b/arch/powerpc/math-emu/fmuls.c index 2d3ec5f7da20f4c20a255e4eca8b804f2a47a913..f5ad5c9c77d001b3ed9bacbff92dcaea66a88e75 100644 --- a/arch/powerpc/math-emu/fmuls.c +++ b/arch/powerpc/math-emu/fmuls.c @@ -14,7 +14,6 @@ fmuls(void *frD, void *frA, void *frB) FP_DECL_D(B); FP_DECL_D(R); FP_DECL_EX; - int ret = 0; #ifdef DEBUG printk("%s: %p %p %p\n", __func__, frD, frA, frB); @@ -32,7 +31,7 @@ fmuls(void *frD, void *frA, void *frB) if ((A_c == FP_CLS_INF && B_c == FP_CLS_ZERO) || (A_c == FP_CLS_ZERO && B_c == FP_CLS_INF)) - ret |= EFLAG_VXIMZ; + FP_SET_EXCEPTION(EFLAG_VXIMZ); FP_MUL_D(R, A, B); diff --git a/arch/powerpc/math-emu/fnmadd.c b/arch/powerpc/math-emu/fnmadd.c index 2497b86494e5425ac64fe8355b91a0c2827afb4a..e817bc5453efc4597d8ebd79df40924fb2e44cda 100644 --- a/arch/powerpc/math-emu/fnmadd.c +++ b/arch/powerpc/math-emu/fnmadd.c @@ -15,7 +15,6 @@ fnmadd(void *frD, void *frA, void *frB, void *frC) FP_DECL_D(C); FP_DECL_D(T); FP_DECL_EX; - int ret = 0; #ifdef DEBUG printk("%s: %p %p %p %p\n", __func__, frD, frA, frB, frC); @@ -33,12 +32,12 @@ fnmadd(void *frD, void *frA, void *frB, void *frC) if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) || (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF)) - ret |= EFLAG_VXIMZ; + FP_SET_EXCEPTION(EFLAG_VXIMZ); FP_MUL_D(T, A, C); if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF) - ret |= EFLAG_VXISI; + FP_SET_EXCEPTION(EFLAG_VXISI); FP_ADD_D(R, T, B); diff --git a/arch/powerpc/math-emu/fnmadds.c b/arch/powerpc/math-emu/fnmadds.c index ee9d71e0b376f7578a9ebd25c0b8ef12746d4e72..4db4b7d9ba8d3d7157cd999ec4dcb042e799054f 100644 --- a/arch/powerpc/math-emu/fnmadds.c +++ b/arch/powerpc/math-emu/fnmadds.c @@ -16,7 +16,6 @@ fnmadds(void *frD, void *frA, void *frB, void *frC) FP_DECL_D(C); FP_DECL_D(T); FP_DECL_EX; - int ret = 0; #ifdef DEBUG printk("%s: %p %p %p %p\n", __func__, frD, frA, frB, frC); @@ -34,12 +33,12 @@ fnmadds(void *frD, void *frA, void *frB, void *frC) if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) || (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF)) - ret |= EFLAG_VXIMZ; + FP_SET_EXCEPTION(EFLAG_VXIMZ); FP_MUL_D(T, A, C); if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF) - ret |= EFLAG_VXISI; + FP_SET_EXCEPTION(EFLAG_VXISI); FP_ADD_D(R, T, B); diff --git a/arch/powerpc/math-emu/fnmsub.c b/arch/powerpc/math-emu/fnmsub.c index 3885a77acc9324919f89ee5aef1d6c842d4c1b17..f65979fa770eac810e07762874c2c206f38cd602 100644 --- a/arch/powerpc/math-emu/fnmsub.c +++ b/arch/powerpc/math-emu/fnmsub.c @@ -15,7 +15,6 @@ fnmsub(void *frD, void *frA, void *frB, void *frC) FP_DECL_D(C); FP_DECL_D(T); FP_DECL_EX; - int ret = 0; #ifdef DEBUG printk("%s: %p %p %p %p\n", __func__, frD, frA, frB, frC); @@ -33,7 +32,7 @@ fnmsub(void *frD, void *frA, void *frB, void *frC) if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) || (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF)) - ret |= EFLAG_VXIMZ; + FP_SET_EXCEPTION(EFLAG_VXIMZ); FP_MUL_D(T, A, C); @@ -41,7 +40,7 @@ fnmsub(void *frD, void *frA, void *frB, void *frC) B_s ^= 1; if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF) - ret |= EFLAG_VXISI; + FP_SET_EXCEPTION(EFLAG_VXISI); FP_ADD_D(R, T, B); diff --git a/arch/powerpc/math-emu/fnmsubs.c b/arch/powerpc/math-emu/fnmsubs.c index f835dfeb0fd1f3b8e8cdafec9d8cf581f6025b4b..9021dacc03b8b2f1d5326cc03c75ff97eb19d3c8 100644 --- a/arch/powerpc/math-emu/fnmsubs.c +++ b/arch/powerpc/math-emu/fnmsubs.c @@ -16,7 +16,6 @@ fnmsubs(void *frD, void *frA, void *frB, void *frC) FP_DECL_D(C); FP_DECL_D(T); FP_DECL_EX; - int ret = 0; #ifdef DEBUG printk("%s: %p %p %p %p\n", __func__, frD, frA, frB, frC); @@ -34,7 +33,7 @@ fnmsubs(void *frD, void *frA, void *frB, void *frC) if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) || (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF)) - ret |= EFLAG_VXIMZ; + FP_SET_EXCEPTION(EFLAG_VXIMZ); FP_MUL_D(T, A, C); @@ -42,7 +41,7 @@ fnmsubs(void *frD, void *frA, void *frB, void *frC) B_s ^= 1; if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF) - ret |= EFLAG_VXISI; + FP_SET_EXCEPTION(EFLAG_VXISI); FP_ADD_D(R, T, B); diff --git a/arch/powerpc/math-emu/fsqrt.c b/arch/powerpc/math-emu/fsqrt.c index 3e90072693a0befdd1661000bfe629f1074ae9d0..a55fc7d49983fe331eecf5f931a4790af6d6de63 100644 --- a/arch/powerpc/math-emu/fsqrt.c +++ b/arch/powerpc/math-emu/fsqrt.c @@ -12,7 +12,6 @@ fsqrt(void *frD, void *frB) FP_DECL_D(B); FP_DECL_D(R); FP_DECL_EX; - int ret = 0; #ifdef DEBUG printk("%s: %p %p %p %p\n", __func__, frD, frB); @@ -25,9 +24,9 @@ fsqrt(void *frD, void *frB) #endif if (B_s && B_c != FP_CLS_ZERO) - ret |= EFLAG_VXSQRT; + FP_SET_EXCEPTION(EFLAG_VXSQRT); if (B_c == FP_CLS_NAN) - ret |= EFLAG_VXSNAN; + FP_SET_EXCEPTION(EFLAG_VXSNAN); FP_SQRT_D(R, B); diff --git a/arch/powerpc/math-emu/fsqrts.c b/arch/powerpc/math-emu/fsqrts.c index 2843be986e2e97aa1a09f2ad8e5e7eb46cdd9852..31dccbfc39ff8073a66849e3ca2617b40b1bc34c 100644 --- a/arch/powerpc/math-emu/fsqrts.c +++ b/arch/powerpc/math-emu/fsqrts.c @@ -13,7 +13,6 @@ fsqrts(void *frD, void *frB) FP_DECL_D(B); FP_DECL_D(R); FP_DECL_EX; - int ret = 0; #ifdef DEBUG printk("%s: %p %p %p %p\n", __func__, frD, frB); @@ -26,9 +25,9 @@ fsqrts(void *frD, void *frB) #endif if (B_s && B_c != FP_CLS_ZERO) - ret |= EFLAG_VXSQRT; + FP_SET_EXCEPTION(EFLAG_VXSQRT); if (B_c == FP_CLS_NAN) - ret |= EFLAG_VXSNAN; + FP_SET_EXCEPTION(EFLAG_VXSNAN); FP_SQRT_D(R, B); diff --git a/arch/powerpc/math-emu/fsub.c b/arch/powerpc/math-emu/fsub.c index 78b09446a0e14f61e5288aba797df5ca87c523de..02c5dff458baa2afac1648a7ccdc997eef31f5e3 100644 --- a/arch/powerpc/math-emu/fsub.c +++ b/arch/powerpc/math-emu/fsub.c @@ -13,7 +13,6 @@ fsub(void *frD, void *frA, void *frB) FP_DECL_D(B); FP_DECL_D(R); FP_DECL_EX; - int ret = 0; #ifdef DEBUG printk("%s: %p %p %p\n", __func__, frD, frA, frB); @@ -31,7 +30,7 @@ fsub(void *frD, void *frA, void *frB) B_s ^= 1; if (A_s != B_s && A_c == FP_CLS_INF && B_c == FP_CLS_INF) - ret |= EFLAG_VXISI; + FP_SET_EXCEPTION(EFLAG_VXISI); FP_ADD_D(R, A, B); diff --git a/arch/powerpc/math-emu/fsubs.c b/arch/powerpc/math-emu/fsubs.c index d3bf90863cf29ba0abec9285c0c386785b4b20c6..5d9b18c35e074aeb8997b0f9dc1a78059ea0a79a 100644 --- a/arch/powerpc/math-emu/fsubs.c +++ b/arch/powerpc/math-emu/fsubs.c @@ -14,7 +14,6 @@ fsubs(void *frD, void *frA, void *frB) FP_DECL_D(B); FP_DECL_D(R); FP_DECL_EX; - int ret = 0; #ifdef DEBUG printk("%s: %p %p %p\n", __func__, frD, frA, frB); @@ -32,7 +31,7 @@ fsubs(void *frD, void *frA, void *frB) B_s ^= 1; if (A_s != B_s && A_c == FP_CLS_INF && B_c == FP_CLS_INF) - ret |= EFLAG_VXISI; + FP_SET_EXCEPTION(EFLAG_VXISI); FP_ADD_D(R, A, B); diff --git a/arch/powerpc/math-emu/math_efp.c b/arch/powerpc/math-emu/math_efp.c new file mode 100644 index 0000000000000000000000000000000000000000..41f4ef30e480e6deb7584627d42a91f5d3f4f674 --- /dev/null +++ b/arch/powerpc/math-emu/math_efp.c @@ -0,0 +1,720 @@ +/* + * arch/powerpc/math-emu/math_efp.c + * + * Copyright (C) 2006-2008 Freescale Semiconductor, Inc. All rights reserved. + * + * Author: Ebony Zhu, + * Yu Liu, + * + * Derived from arch/alpha/math-emu/math.c + * arch/powerpc/math-emu/math.c + * + * Description: + * This file is the exception handler to make E500 SPE instructions + * fully comply with IEEE-754 floating point standard. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include + +#include +#include + +#define FP_EX_BOOKE_E500_SPE +#include + +#include +#include +#include + +#define EFAPU 0x4 + +#define VCT 0x4 +#define SPFP 0x6 +#define DPFP 0x7 + +#define EFSADD 0x2c0 +#define EFSSUB 0x2c1 +#define EFSABS 0x2c4 +#define EFSNABS 0x2c5 +#define EFSNEG 0x2c6 +#define EFSMUL 0x2c8 +#define EFSDIV 0x2c9 +#define EFSCMPGT 0x2cc +#define EFSCMPLT 0x2cd +#define EFSCMPEQ 0x2ce +#define EFSCFD 0x2cf +#define EFSCFSI 0x2d1 +#define EFSCTUI 0x2d4 +#define EFSCTSI 0x2d5 +#define EFSCTUF 0x2d6 +#define EFSCTSF 0x2d7 +#define EFSCTUIZ 0x2d8 +#define EFSCTSIZ 0x2da + +#define EVFSADD 0x280 +#define EVFSSUB 0x281 +#define EVFSABS 0x284 +#define EVFSNABS 0x285 +#define EVFSNEG 0x286 +#define EVFSMUL 0x288 +#define EVFSDIV 0x289 +#define EVFSCMPGT 0x28c +#define EVFSCMPLT 0x28d +#define EVFSCMPEQ 0x28e +#define EVFSCTUI 0x294 +#define EVFSCTSI 0x295 +#define EVFSCTUF 0x296 +#define EVFSCTSF 0x297 +#define EVFSCTUIZ 0x298 +#define EVFSCTSIZ 0x29a + +#define EFDADD 0x2e0 +#define EFDSUB 0x2e1 +#define EFDABS 0x2e4 +#define EFDNABS 0x2e5 +#define EFDNEG 0x2e6 +#define EFDMUL 0x2e8 +#define EFDDIV 0x2e9 +#define EFDCTUIDZ 0x2ea +#define EFDCTSIDZ 0x2eb +#define EFDCMPGT 0x2ec +#define EFDCMPLT 0x2ed +#define EFDCMPEQ 0x2ee +#define EFDCFS 0x2ef +#define EFDCTUI 0x2f4 +#define EFDCTSI 0x2f5 +#define EFDCTUF 0x2f6 +#define EFDCTSF 0x2f7 +#define EFDCTUIZ 0x2f8 +#define EFDCTSIZ 0x2fa + +#define AB 2 +#define XA 3 +#define XB 4 +#define XCR 5 +#define NOTYPE 0 + +#define SIGN_BIT_S (1UL << 31) +#define SIGN_BIT_D (1ULL << 63) +#define FP_EX_MASK (FP_EX_INEXACT | FP_EX_INVALID | FP_EX_DIVZERO | \ + FP_EX_UNDERFLOW | FP_EX_OVERFLOW) + +union dw_union { + u64 dp[1]; + u32 wp[2]; +}; + +static unsigned long insn_type(unsigned long speinsn) +{ + unsigned long ret = NOTYPE; + + switch (speinsn & 0x7ff) { + case EFSABS: ret = XA; break; + case EFSADD: ret = AB; break; + case EFSCFD: ret = XB; break; + case EFSCMPEQ: ret = XCR; break; + case EFSCMPGT: ret = XCR; break; + case EFSCMPLT: ret = XCR; break; + case EFSCTSF: ret = XB; break; + case EFSCTSI: ret = XB; break; + case EFSCTSIZ: ret = XB; break; + case EFSCTUF: ret = XB; break; + case EFSCTUI: ret = XB; break; + case EFSCTUIZ: ret = XB; break; + case EFSDIV: ret = AB; break; + case EFSMUL: ret = AB; break; + case EFSNABS: ret = XA; break; + case EFSNEG: ret = XA; break; + case EFSSUB: ret = AB; break; + case EFSCFSI: ret = XB; break; + + case EVFSABS: ret = XA; break; + case EVFSADD: ret = AB; break; + case EVFSCMPEQ: ret = XCR; break; + case EVFSCMPGT: ret = XCR; break; + case EVFSCMPLT: ret = XCR; break; + case EVFSCTSF: ret = XB; break; + case EVFSCTSI: ret = XB; break; + case EVFSCTSIZ: ret = XB; break; + case EVFSCTUF: ret = XB; break; + case EVFSCTUI: ret = XB; break; + case EVFSCTUIZ: ret = XB; break; + case EVFSDIV: ret = AB; break; + case EVFSMUL: ret = AB; break; + case EVFSNABS: ret = XA; break; + case EVFSNEG: ret = XA; break; + case EVFSSUB: ret = AB; break; + + case EFDABS: ret = XA; break; + case EFDADD: ret = AB; break; + case EFDCFS: ret = XB; break; + case EFDCMPEQ: ret = XCR; break; + case EFDCMPGT: ret = XCR; break; + case EFDCMPLT: ret = XCR; break; + case EFDCTSF: ret = XB; break; + case EFDCTSI: ret = XB; break; + case EFDCTSIDZ: ret = XB; break; + case EFDCTSIZ: ret = XB; break; + case EFDCTUF: ret = XB; break; + case EFDCTUI: ret = XB; break; + case EFDCTUIDZ: ret = XB; break; + case EFDCTUIZ: ret = XB; break; + case EFDDIV: ret = AB; break; + case EFDMUL: ret = AB; break; + case EFDNABS: ret = XA; break; + case EFDNEG: ret = XA; break; + case EFDSUB: ret = AB; break; + + default: + printk(KERN_ERR "\nOoops! SPE instruction no type found."); + printk(KERN_ERR "\ninst code: %08lx\n", speinsn); + } + + return ret; +} + +int do_spe_mathemu(struct pt_regs *regs) +{ + FP_DECL_EX; + int IR, cmp; + + unsigned long type, func, fc, fa, fb, src, speinsn; + union dw_union vc, va, vb; + + if (get_user(speinsn, (unsigned int __user *) regs->nip)) + return -EFAULT; + if ((speinsn >> 26) != EFAPU) + return -EINVAL; /* not an spe instruction */ + + type = insn_type(speinsn); + if (type == NOTYPE) + return -ENOSYS; + + func = speinsn & 0x7ff; + fc = (speinsn >> 21) & 0x1f; + fa = (speinsn >> 16) & 0x1f; + fb = (speinsn >> 11) & 0x1f; + src = (speinsn >> 5) & 0x7; + + vc.wp[0] = current->thread.evr[fc]; + vc.wp[1] = regs->gpr[fc]; + va.wp[0] = current->thread.evr[fa]; + va.wp[1] = regs->gpr[fa]; + vb.wp[0] = current->thread.evr[fb]; + vb.wp[1] = regs->gpr[fb]; + + __FPU_FPSCR = mfspr(SPRN_SPEFSCR); + +#ifdef DEBUG + printk("speinsn:%08lx spefscr:%08lx\n", speinsn, __FPU_FPSCR); + printk("vc: %08x %08x\n", vc.wp[0], vc.wp[1]); + printk("va: %08x %08x\n", va.wp[0], va.wp[1]); + printk("vb: %08x %08x\n", vb.wp[0], vb.wp[1]); +#endif + + switch (src) { + case SPFP: { + FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); + + switch (type) { + case AB: + case XCR: + FP_UNPACK_SP(SA, va.wp + 1); + case XB: + FP_UNPACK_SP(SB, vb.wp + 1); + break; + case XA: + FP_UNPACK_SP(SA, va.wp + 1); + break; + } + +#ifdef DEBUG + printk("SA: %ld %08lx %ld (%ld)\n", SA_s, SA_f, SA_e, SA_c); + printk("SB: %ld %08lx %ld (%ld)\n", SB_s, SB_f, SB_e, SB_c); +#endif + + switch (func) { + case EFSABS: + vc.wp[1] = va.wp[1] & ~SIGN_BIT_S; + goto update_regs; + + case EFSNABS: + vc.wp[1] = va.wp[1] | SIGN_BIT_S; + goto update_regs; + + case EFSNEG: + vc.wp[1] = va.wp[1] ^ SIGN_BIT_S; + goto update_regs; + + case EFSADD: + FP_ADD_S(SR, SA, SB); + goto pack_s; + + case EFSSUB: + FP_SUB_S(SR, SA, SB); + goto pack_s; + + case EFSMUL: + FP_MUL_S(SR, SA, SB); + goto pack_s; + + case EFSDIV: + FP_DIV_S(SR, SA, SB); + goto pack_s; + + case EFSCMPEQ: + cmp = 0; + goto cmp_s; + + case EFSCMPGT: + cmp = 1; + goto cmp_s; + + case EFSCMPLT: + cmp = -1; + goto cmp_s; + + case EFSCTSF: + case EFSCTUF: + if (!((vb.wp[1] >> 23) == 0xff && ((vb.wp[1] & 0x7fffff) > 0))) { + /* NaN */ + if (((vb.wp[1] >> 23) & 0xff) == 0) { + /* denorm */ + vc.wp[1] = 0x0; + } else if ((vb.wp[1] >> 31) == 0) { + /* positive normal */ + vc.wp[1] = (func == EFSCTSF) ? + 0x7fffffff : 0xffffffff; + } else { /* negative normal */ + vc.wp[1] = (func == EFSCTSF) ? + 0x80000000 : 0x0; + } + } else { /* rB is NaN */ + vc.wp[1] = 0x0; + } + goto update_regs; + + case EFSCFD: { + FP_DECL_D(DB); + FP_CLEAR_EXCEPTIONS; + FP_UNPACK_DP(DB, vb.dp); +#ifdef DEBUG + printk("DB: %ld %08lx %08lx %ld (%ld)\n", + DB_s, DB_f1, DB_f0, DB_e, DB_c); +#endif + FP_CONV(S, D, 1, 2, SR, DB); + goto pack_s; + } + + case EFSCTSI: + case EFSCTSIZ: + case EFSCTUI: + case EFSCTUIZ: + if (func & 0x4) { + _FP_ROUND(1, SB); + } else { + _FP_ROUND_ZERO(1, SB); + } + FP_TO_INT_S(vc.wp[1], SB, 32, ((func & 0x3) != 0)); + goto update_regs; + + default: + goto illegal; + } + break; + +pack_s: +#ifdef DEBUG + printk("SR: %ld %08lx %ld (%ld)\n", SR_s, SR_f, SR_e, SR_c); +#endif + FP_PACK_SP(vc.wp + 1, SR); + goto update_regs; + +cmp_s: + FP_CMP_S(IR, SA, SB, 3); + if (IR == 3 && (FP_ISSIGNAN_S(SA) || FP_ISSIGNAN_S(SB))) + FP_SET_EXCEPTION(FP_EX_INVALID); + if (IR == cmp) { + IR = 0x4; + } else { + IR = 0; + } + goto update_ccr; + } + + case DPFP: { + FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR); + + switch (type) { + case AB: + case XCR: + FP_UNPACK_DP(DA, va.dp); + case XB: + FP_UNPACK_DP(DB, vb.dp); + break; + case XA: + FP_UNPACK_DP(DA, va.dp); + break; + } + +#ifdef DEBUG + printk("DA: %ld %08lx %08lx %ld (%ld)\n", + DA_s, DA_f1, DA_f0, DA_e, DA_c); + printk("DB: %ld %08lx %08lx %ld (%ld)\n", + DB_s, DB_f1, DB_f0, DB_e, DB_c); +#endif + + switch (func) { + case EFDABS: + vc.dp[0] = va.dp[0] & ~SIGN_BIT_D; + goto update_regs; + + case EFDNABS: + vc.dp[0] = va.dp[0] | SIGN_BIT_D; + goto update_regs; + + case EFDNEG: + vc.dp[0] = va.dp[0] ^ SIGN_BIT_D; + goto update_regs; + + case EFDADD: + FP_ADD_D(DR, DA, DB); + goto pack_d; + + case EFDSUB: + FP_SUB_D(DR, DA, DB); + goto pack_d; + + case EFDMUL: + FP_MUL_D(DR, DA, DB); + goto pack_d; + + case EFDDIV: + FP_DIV_D(DR, DA, DB); + goto pack_d; + + case EFDCMPEQ: + cmp = 0; + goto cmp_d; + + case EFDCMPGT: + cmp = 1; + goto cmp_d; + + case EFDCMPLT: + cmp = -1; + goto cmp_d; + + case EFDCTSF: + case EFDCTUF: + if (!((vb.wp[0] >> 20) == 0x7ff && + ((vb.wp[0] & 0xfffff) > 0 || (vb.wp[1] > 0)))) { + /* not a NaN */ + if (((vb.wp[0] >> 20) & 0x7ff) == 0) { + /* denorm */ + vc.wp[1] = 0x0; + } else if ((vb.wp[0] >> 31) == 0) { + /* positive normal */ + vc.wp[1] = (func == EFDCTSF) ? + 0x7fffffff : 0xffffffff; + } else { /* negative normal */ + vc.wp[1] = (func == EFDCTSF) ? + 0x80000000 : 0x0; + } + } else { /* NaN */ + vc.wp[1] = 0x0; + } + goto update_regs; + + case EFDCFS: { + FP_DECL_S(SB); + FP_CLEAR_EXCEPTIONS; + FP_UNPACK_SP(SB, vb.wp + 1); +#ifdef DEBUG + printk("SB: %ld %08lx %ld (%ld)\n", + SB_s, SB_f, SB_e, SB_c); +#endif + FP_CONV(D, S, 2, 1, DR, SB); + goto pack_d; + } + + case EFDCTUIDZ: + case EFDCTSIDZ: + _FP_ROUND_ZERO(2, DB); + FP_TO_INT_D(vc.dp[0], DB, 64, ((func & 0x1) == 0)); + goto update_regs; + + case EFDCTUI: + case EFDCTSI: + case EFDCTUIZ: + case EFDCTSIZ: + if (func & 0x4) { + _FP_ROUND(2, DB); + } else { + _FP_ROUND_ZERO(2, DB); + } + FP_TO_INT_D(vc.wp[1], DB, 32, ((func & 0x3) != 0)); + goto update_regs; + + default: + goto illegal; + } + break; + +pack_d: +#ifdef DEBUG + printk("DR: %ld %08lx %08lx %ld (%ld)\n", + DR_s, DR_f1, DR_f0, DR_e, DR_c); +#endif + FP_PACK_DP(vc.dp, DR); + goto update_regs; + +cmp_d: + FP_CMP_D(IR, DA, DB, 3); + if (IR == 3 && (FP_ISSIGNAN_D(DA) || FP_ISSIGNAN_D(DB))) + FP_SET_EXCEPTION(FP_EX_INVALID); + if (IR == cmp) { + IR = 0x4; + } else { + IR = 0; + } + goto update_ccr; + + } + + case VCT: { + FP_DECL_S(SA0); FP_DECL_S(SB0); FP_DECL_S(SR0); + FP_DECL_S(SA1); FP_DECL_S(SB1); FP_DECL_S(SR1); + int IR0, IR1; + + switch (type) { + case AB: + case XCR: + FP_UNPACK_SP(SA0, va.wp); + FP_UNPACK_SP(SA1, va.wp + 1); + case XB: + FP_UNPACK_SP(SB0, vb.wp); + FP_UNPACK_SP(SB1, vb.wp + 1); + break; + case XA: + FP_UNPACK_SP(SA0, va.wp); + FP_UNPACK_SP(SA1, va.wp + 1); + break; + } + +#ifdef DEBUG + printk("SA0: %ld %08lx %ld (%ld)\n", SA0_s, SA0_f, SA0_e, SA0_c); + printk("SA1: %ld %08lx %ld (%ld)\n", SA1_s, SA1_f, SA1_e, SA1_c); + printk("SB0: %ld %08lx %ld (%ld)\n", SB0_s, SB0_f, SB0_e, SB0_c); + printk("SB1: %ld %08lx %ld (%ld)\n", SB1_s, SB1_f, SB1_e, SB1_c); +#endif + + switch (func) { + case EVFSABS: + vc.wp[0] = va.wp[0] & ~SIGN_BIT_S; + vc.wp[1] = va.wp[1] & ~SIGN_BIT_S; + goto update_regs; + + case EVFSNABS: + vc.wp[0] = va.wp[0] | SIGN_BIT_S; + vc.wp[1] = va.wp[1] | SIGN_BIT_S; + goto update_regs; + + case EVFSNEG: + vc.wp[0] = va.wp[0] ^ SIGN_BIT_S; + vc.wp[1] = va.wp[1] ^ SIGN_BIT_S; + goto update_regs; + + case EVFSADD: + FP_ADD_S(SR0, SA0, SB0); + FP_ADD_S(SR1, SA1, SB1); + goto pack_vs; + + case EVFSSUB: + FP_SUB_S(SR0, SA0, SB0); + FP_SUB_S(SR1, SA1, SB1); + goto pack_vs; + + case EVFSMUL: + FP_MUL_S(SR0, SA0, SB0); + FP_MUL_S(SR1, SA1, SB1); + goto pack_vs; + + case EVFSDIV: + FP_DIV_S(SR0, SA0, SB0); + FP_DIV_S(SR1, SA1, SB1); + goto pack_vs; + + case EVFSCMPEQ: + cmp = 0; + goto cmp_vs; + + case EVFSCMPGT: + cmp = 1; + goto cmp_vs; + + case EVFSCMPLT: + cmp = -1; + goto cmp_vs; + + case EVFSCTSF: + __asm__ __volatile__ ("mtspr 512, %4\n" + "efsctsf %0, %2\n" + "efsctsf %1, %3\n" + : "=r" (vc.wp[0]), "=r" (vc.wp[1]) + : "r" (vb.wp[0]), "r" (vb.wp[1]), "r" (0)); + goto update_regs; + + case EVFSCTUF: + __asm__ __volatile__ ("mtspr 512, %4\n" + "efsctuf %0, %2\n" + "efsctuf %1, %3\n" + : "=r" (vc.wp[0]), "=r" (vc.wp[1]) + : "r" (vb.wp[0]), "r" (vb.wp[1]), "r" (0)); + goto update_regs; + + case EVFSCTUI: + case EVFSCTSI: + case EVFSCTUIZ: + case EVFSCTSIZ: + if (func & 0x4) { + _FP_ROUND(1, SB0); + _FP_ROUND(1, SB1); + } else { + _FP_ROUND_ZERO(1, SB0); + _FP_ROUND_ZERO(1, SB1); + } + FP_TO_INT_S(vc.wp[0], SB0, 32, ((func & 0x3) != 0)); + FP_TO_INT_S(vc.wp[1], SB1, 32, ((func & 0x3) != 0)); + goto update_regs; + + default: + goto illegal; + } + break; + +pack_vs: +#ifdef DEBUG + printk("SR0: %ld %08lx %ld (%ld)\n", SR0_s, SR0_f, SR0_e, SR0_c); + printk("SR1: %ld %08lx %ld (%ld)\n", SR1_s, SR1_f, SR1_e, SR1_c); +#endif + FP_PACK_SP(vc.wp, SR0); + FP_PACK_SP(vc.wp + 1, SR1); + goto update_regs; + +cmp_vs: + { + int ch, cl; + + FP_CMP_S(IR0, SA0, SB0, 3); + FP_CMP_S(IR1, SA1, SB1, 3); + if (IR0 == 3 && (FP_ISSIGNAN_S(SA0) || FP_ISSIGNAN_S(SB0))) + FP_SET_EXCEPTION(FP_EX_INVALID); + if (IR1 == 3 && (FP_ISSIGNAN_S(SA1) || FP_ISSIGNAN_S(SB1))) + FP_SET_EXCEPTION(FP_EX_INVALID); + ch = (IR0 == cmp) ? 1 : 0; + cl = (IR1 == cmp) ? 1 : 0; + IR = (ch << 3) | (cl << 2) | ((ch | cl) << 1) | + ((ch & cl) << 0); + goto update_ccr; + } + } + default: + return -EINVAL; + } + +update_ccr: + regs->ccr &= ~(15 << ((7 - ((speinsn >> 23) & 0x7)) << 2)); + regs->ccr |= (IR << ((7 - ((speinsn >> 23) & 0x7)) << 2)); + +update_regs: + __FPU_FPSCR &= ~FP_EX_MASK; + __FPU_FPSCR |= (FP_CUR_EXCEPTIONS & FP_EX_MASK); + mtspr(SPRN_SPEFSCR, __FPU_FPSCR); + + current->thread.evr[fc] = vc.wp[0]; + regs->gpr[fc] = vc.wp[1]; + +#ifdef DEBUG + printk("ccr = %08lx\n", regs->ccr); + printk("cur exceptions = %08x spefscr = %08lx\n", + FP_CUR_EXCEPTIONS, __FPU_FPSCR); + printk("vc: %08x %08x\n", vc.wp[0], vc.wp[1]); + printk("va: %08x %08x\n", va.wp[0], va.wp[1]); + printk("vb: %08x %08x\n", vb.wp[0], vb.wp[1]); +#endif + + return 0; + +illegal: + printk(KERN_ERR "\nOoops! IEEE-754 compliance handler encountered un-supported instruction.\ninst code: %08lx\n", speinsn); + return -ENOSYS; +} + +int speround_handler(struct pt_regs *regs) +{ + union dw_union fgpr; + int s_lo, s_hi; + unsigned long speinsn, type, fc; + + if (get_user(speinsn, (unsigned int __user *) regs->nip)) + return -EFAULT; + if ((speinsn >> 26) != 4) + return -EINVAL; /* not an spe instruction */ + + type = insn_type(speinsn & 0x7ff); + if (type == XCR) return -ENOSYS; + + fc = (speinsn >> 21) & 0x1f; + s_lo = regs->gpr[fc] & SIGN_BIT_S; + s_hi = current->thread.evr[fc] & SIGN_BIT_S; + fgpr.wp[0] = current->thread.evr[fc]; + fgpr.wp[1] = regs->gpr[fc]; + + __FPU_FPSCR = mfspr(SPRN_SPEFSCR); + + switch ((speinsn >> 5) & 0x7) { + /* Since SPE instructions on E500 core can handle round to nearest + * and round toward zero with IEEE-754 complied, we just need + * to handle round toward +Inf and round toward -Inf by software. + */ + case SPFP: + if ((FP_ROUNDMODE) == FP_RND_PINF) { + if (!s_lo) fgpr.wp[1]++; /* Z > 0, choose Z1 */ + } else { /* round to -Inf */ + if (s_lo) fgpr.wp[1]++; /* Z < 0, choose Z2 */ + } + break; + + case DPFP: + if (FP_ROUNDMODE == FP_RND_PINF) { + if (!s_hi) fgpr.dp[0]++; /* Z > 0, choose Z1 */ + } else { /* round to -Inf */ + if (s_hi) fgpr.dp[0]++; /* Z < 0, choose Z2 */ + } + break; + + case VCT: + if (FP_ROUNDMODE == FP_RND_PINF) { + if (!s_lo) fgpr.wp[1]++; /* Z_low > 0, choose Z1 */ + if (!s_hi) fgpr.wp[0]++; /* Z_high word > 0, choose Z1 */ + } else { /* round to -Inf */ + if (s_lo) fgpr.wp[1]++; /* Z_low < 0, choose Z2 */ + if (s_hi) fgpr.wp[0]++; /* Z_high < 0, choose Z2 */ + } + break; + + default: + return -EINVAL; + } + + current->thread.evr[fc] = fgpr.wp[0]; + regs->gpr[fc] = fgpr.wp[1]; + + return 0; +} diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile index e7392b45a5ef6ae82ad68727188e257990d407ea..953cc4a1cde56061bccdc347ff0e347930eb052b 100644 --- a/arch/powerpc/mm/Makefile +++ b/arch/powerpc/mm/Makefile @@ -6,17 +6,19 @@ ifeq ($(CONFIG_PPC64),y) EXTRA_CFLAGS += -mno-minimal-toc endif -obj-y := fault.o mem.o \ +obj-y := fault.o mem.o pgtable.o \ init_$(CONFIG_WORD_SIZE).o \ - pgtable_$(CONFIG_WORD_SIZE).o \ - mmu_context_$(CONFIG_WORD_SIZE).o + pgtable_$(CONFIG_WORD_SIZE).o +obj-$(CONFIG_PPC_MMU_NOHASH) += mmu_context_nohash.o tlb_nohash.o \ + tlb_nohash_low.o hash-$(CONFIG_PPC_NATIVE) := hash_native_64.o obj-$(CONFIG_PPC64) += hash_utils_64.o \ slb_low.o slb.o stab.o \ gup.o mmap.o $(hash-y) obj-$(CONFIG_PPC_STD_MMU_32) += ppc_mmu_32.o obj-$(CONFIG_PPC_STD_MMU) += hash_low_$(CONFIG_WORD_SIZE).o \ - tlb_$(CONFIG_WORD_SIZE).o + tlb_hash$(CONFIG_WORD_SIZE).o \ + mmu_context_hash$(CONFIG_WORD_SIZE).o obj-$(CONFIG_40x) += 40x_mmu.o obj-$(CONFIG_44x) += 44x_mmu.o obj-$(CONFIG_FSL_BOOKE) += fsl_booke_mmu.o diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index 565b7a237c847929e885eb5597fe4cdb14746cf3..91c7b8636b8a751ba160a7791df929be25d32543 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -283,7 +284,7 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, } pte_update(ptep, 0, _PAGE_HWEXEC | _PAGE_ACCESSED); - _tlbie(address, mm->context.id); + local_flush_tlb_page(vma, address); pte_unmap_unlock(ptep, ptl); up_read(&mm->mmap_sem); return 0; @@ -318,9 +319,16 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, goto do_sigbus; BUG(); } - if (ret & VM_FAULT_MAJOR) + if (ret & VM_FAULT_MAJOR) { current->maj_flt++; - else +#ifdef CONFIG_PPC_SMLPAR + if (firmware_has_feature(FW_FEATURE_CMO)) { + preempt_disable(); + get_lppaca()->page_ins += (1 << PAGE_FACTOR); + preempt_enable(); + } +#endif + } else current->min_flt++; up_read(&mm->mmap_sem); return 0; @@ -339,7 +347,7 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, && printk_ratelimit()) printk(KERN_CRIT "kernel tried to execute NX-protected" " page (%lx) - exploit attempt? (uid: %d)\n", - address, current->uid); + address, current_uid()); return SIGSEGV; diff --git a/arch/powerpc/mm/hash_low_32.S b/arch/powerpc/mm/hash_low_32.S index 7bffb70b9fe25cd71750428578ba961561412ee6..67850ec9feb36e04ae26ddb6acef20709ff6db16 100644 --- a/arch/powerpc/mm/hash_low_32.S +++ b/arch/powerpc/mm/hash_low_32.S @@ -35,36 +35,6 @@ mmu_hash_lock: .space 4 #endif /* CONFIG_SMP */ -/* - * Sync CPUs with hash_page taking & releasing the hash - * table lock - */ -#ifdef CONFIG_SMP - .text -_GLOBAL(hash_page_sync) - mfmsr r10 - rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */ - mtmsr r0 - lis r8,mmu_hash_lock@h - ori r8,r8,mmu_hash_lock@l - lis r0,0x0fff - b 10f -11: lwz r6,0(r8) - cmpwi 0,r6,0 - bne 11b -10: lwarx r6,0,r8 - cmpwi 0,r6,0 - bne- 11b - stwcx. r0,0,r8 - bne- 10b - isync - eieio - li r0,0 - stw r0,0(r8) - mtmsr r10 - blr -#endif /* CONFIG_SMP */ - /* * Load a PTE into the hash table, if possible. * The address is in r4, and r3 contains an access flag: @@ -353,8 +323,8 @@ _GLOBAL(create_hpte) ori r8,r8,0xe14 /* clear out reserved bits and M */ andc r8,r5,r8 /* PP = user? (rw&dirty? 2: 3): 0 */ BEGIN_FTR_SECTION - ori r8,r8,_PAGE_COHERENT /* set M (coherence required) */ -END_FTR_SECTION_IFSET(CPU_FTR_NEED_COHERENT) + rlwinm r8,r8,0,~_PAGE_COHERENT /* clear M (coherence not required) */ +END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT) #ifdef CONFIG_PTE_64BIT /* Put the XPN bits into the PTE */ rlwimi r8,r10,8,20,22 @@ -663,3 +633,80 @@ _GLOBAL(flush_hash_patch_B) SYNC_601 isync blr + +/* + * Flush an entry from the TLB + */ +_GLOBAL(_tlbie) +#ifdef CONFIG_SMP + rlwinm r8,r1,0,0,(31-THREAD_SHIFT) + lwz r8,TI_CPU(r8) + oris r8,r8,11 + mfmsr r10 + SYNC + rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */ + rlwinm r0,r0,0,28,26 /* clear DR */ + mtmsr r0 + SYNC_601 + isync + lis r9,mmu_hash_lock@h + ori r9,r9,mmu_hash_lock@l + tophys(r9,r9) +10: lwarx r7,0,r9 + cmpwi 0,r7,0 + bne- 10b + stwcx. r8,0,r9 + bne- 10b + eieio + tlbie r3 + sync + TLBSYNC + li r0,0 + stw r0,0(r9) /* clear mmu_hash_lock */ + mtmsr r10 + SYNC_601 + isync +#else /* CONFIG_SMP */ + tlbie r3 + sync +#endif /* CONFIG_SMP */ + blr + +/* + * Flush the entire TLB. 603/603e only + */ +_GLOBAL(_tlbia) +#if defined(CONFIG_SMP) + rlwinm r8,r1,0,0,(31-THREAD_SHIFT) + lwz r8,TI_CPU(r8) + oris r8,r8,10 + mfmsr r10 + SYNC + rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */ + rlwinm r0,r0,0,28,26 /* clear DR */ + mtmsr r0 + SYNC_601 + isync + lis r9,mmu_hash_lock@h + ori r9,r9,mmu_hash_lock@l + tophys(r9,r9) +10: lwarx r7,0,r9 + cmpwi 0,r7,0 + bne- 10b + stwcx. r8,0,r9 + bne- 10b + sync + tlbia + sync + TLBSYNC + li r0,0 + stw r0,0(r9) /* clear mmu_hash_lock */ + mtmsr r10 + SYNC_601 + isync +#else /* CONFIG_SMP */ + sync + tlbia + sync +#endif /* CONFIG_SMP */ + blr diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index f0c3b88d50fa5a5f98847bd1914be1881885af9d..201c7a5486cb3f815e89ec8e54966b5f29f6feb0 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -53,8 +53,7 @@ unsigned int mmu_huge_psizes[MMU_PAGE_COUNT] = { }; /* initialize all to 0 */ /* Subtract one from array size because we don't need a cache for 4K since * is not a huge page size */ -#define huge_pgtable_cache(psize) (pgtable_cache[HUGEPTE_CACHE_NUM \ - + psize-1]) +#define HUGE_PGTABLE_INDEX(psize) (HUGEPTE_CACHE_NUM + psize - 1) #define HUGEPTE_CACHE_NAME(psize) (huge_pgtable_cache_name[psize]) static const char *huge_pgtable_cache_name[MMU_PAGE_COUNT] = { @@ -113,7 +112,7 @@ static inline pte_t *hugepte_offset(hugepd_t *hpdp, unsigned long addr, static int __hugepte_alloc(struct mm_struct *mm, hugepd_t *hpdp, unsigned long address, unsigned int psize) { - pte_t *new = kmem_cache_zalloc(huge_pgtable_cache(psize), + pte_t *new = kmem_cache_zalloc(pgtable_cache[HUGE_PGTABLE_INDEX(psize)], GFP_KERNEL|__GFP_REPEAT); if (! new) @@ -121,7 +120,7 @@ static int __hugepte_alloc(struct mm_struct *mm, hugepd_t *hpdp, spin_lock(&mm->page_table_lock); if (!hugepd_none(*hpdp)) - kmem_cache_free(huge_pgtable_cache(psize), new); + kmem_cache_free(pgtable_cache[HUGE_PGTABLE_INDEX(psize)], new); else hpdp->pd = (unsigned long)new | HUGEPD_OK; spin_unlock(&mm->page_table_lock); @@ -763,13 +762,14 @@ static int __init hugetlbpage_init(void) for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) { if (mmu_huge_psizes[psize]) { - huge_pgtable_cache(psize) = kmem_cache_create( - HUGEPTE_CACHE_NAME(psize), - HUGEPTE_TABLE_SIZE(psize), - HUGEPTE_TABLE_SIZE(psize), - 0, - NULL); - if (!huge_pgtable_cache(psize)) + pgtable_cache[HUGE_PGTABLE_INDEX(psize)] = + kmem_cache_create( + HUGEPTE_CACHE_NAME(psize), + HUGEPTE_TABLE_SIZE(psize), + HUGEPTE_TABLE_SIZE(psize), + 0, + NULL); + if (!pgtable_cache[HUGE_PGTABLE_INDEX(psize)]) panic("hugetlbpage_init(): could not create %s"\ "\n", HUGEPTE_CACHE_NAME(psize)); } diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c index 388ceda632f346fa5314c4254512807b414802b3..666a5e8a5be1d582685d20b23ce5ec045f83cd4d 100644 --- a/arch/powerpc/mm/init_32.c +++ b/arch/powerpc/mm/init_32.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include @@ -49,7 +48,7 @@ #if defined(CONFIG_KERNEL_START_BOOL) || defined(CONFIG_LOWMEM_SIZE_BOOL) /* The ammount of lowmem must be within 0xF0000000 - KERNELBASE. */ -#if (CONFIG_LOWMEM_SIZE > (0xF0000000 - KERNELBASE)) +#if (CONFIG_LOWMEM_SIZE > (0xF0000000 - PAGE_OFFSET)) #error "You must adjust CONFIG_LOWMEM_SIZE or CONFIG_START_KERNEL" #endif #endif @@ -180,9 +179,6 @@ void __init MMU_init(void) if (ppc_md.progress) ppc_md.progress("MMU:setio", 0x302); - /* Initialize the context management stuff */ - mmu_context_init(); - if (ppc_md.progress) ppc_md.progress("MMU:exit", 0x211); diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index b9e1a1da6e52a35f2276c798b71e717bb224ec88..53b06ebb3f2f7cad0a9dd690f30d0582184e8042 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -102,8 +102,8 @@ pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, return ppc_md.phys_mem_access_prot(file, pfn, size, vma_prot); if (!page_is_ram(pfn)) - vma_prot = __pgprot(pgprot_val(vma_prot) - | _PAGE_GUARDED | _PAGE_NO_CACHE); + vma_prot = pgprot_noncached(vma_prot); + return vma_prot; } EXPORT_SYMBOL(phys_mem_access_prot); @@ -488,7 +488,7 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, * we invalidate the TLB here, thus avoiding dcbst * misbehaviour. */ - _tlbie(address, 0 /* 8xx doesn't care about PID */); + _tlbil_va(address, 0 /* 8xx doesn't care about PID */); #endif /* The _PAGE_USER test should really be _PAGE_EXEC, but * older glibc versions execute some code from no-exec diff --git a/arch/powerpc/mm/mmu_context_32.c b/arch/powerpc/mm/mmu_context_32.c deleted file mode 100644 index cc32ba41d9003f7340b3d31b08c42096f7fa65c1..0000000000000000000000000000000000000000 --- a/arch/powerpc/mm/mmu_context_32.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * This file contains the routines for handling the MMU on those - * PowerPC implementations where the MMU substantially follows the - * architecture specification. This includes the 6xx, 7xx, 7xxx, - * 8260, and POWER3 implementations but excludes the 8xx and 4xx. - * -- paulus - * - * Derived from arch/ppc/mm/init.c: - * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) - * - * Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au) - * and Cort Dougan (PReP) (cort@cs.nmt.edu) - * Copyright (C) 1996 Paul Mackerras - * - * Derived from "arch/i386/mm/init.c" - * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ - -#include -#include - -#include -#include - -unsigned long next_mmu_context; -unsigned long context_map[LAST_CONTEXT / BITS_PER_LONG + 1]; -#ifdef FEW_CONTEXTS -atomic_t nr_free_contexts; -struct mm_struct *context_mm[LAST_CONTEXT+1]; -void steal_context(void); -#endif /* FEW_CONTEXTS */ - -/* - * Initialize the context management stuff. - */ -void __init -mmu_context_init(void) -{ - /* - * Some processors have too few contexts to reserve one for - * init_mm, and require using context 0 for a normal task. - * Other processors reserve the use of context zero for the kernel. - * This code assumes FIRST_CONTEXT < 32. - */ - context_map[0] = (1 << FIRST_CONTEXT) - 1; - next_mmu_context = FIRST_CONTEXT; -#ifdef FEW_CONTEXTS - atomic_set(&nr_free_contexts, LAST_CONTEXT - FIRST_CONTEXT + 1); -#endif /* FEW_CONTEXTS */ -} - -#ifdef FEW_CONTEXTS -/* - * Steal a context from a task that has one at the moment. - * This is only used on 8xx and 4xx and we presently assume that - * they don't do SMP. If they do then this will have to check - * whether the MM we steal is in use. - * We also assume that this is only used on systems that don't - * use an MMU hash table - this is true for 8xx and 4xx. - * This isn't an LRU system, it just frees up each context in - * turn (sort-of pseudo-random replacement :). This would be the - * place to implement an LRU scheme if anyone was motivated to do it. - * -- paulus - */ -void -steal_context(void) -{ - struct mm_struct *mm; - - /* free up context `next_mmu_context' */ - /* if we shouldn't free context 0, don't... */ - if (next_mmu_context < FIRST_CONTEXT) - next_mmu_context = FIRST_CONTEXT; - mm = context_mm[next_mmu_context]; - flush_tlb_mm(mm); - destroy_context(mm); -} -#endif /* FEW_CONTEXTS */ diff --git a/arch/powerpc/mm/mmu_context_hash32.c b/arch/powerpc/mm/mmu_context_hash32.c new file mode 100644 index 0000000000000000000000000000000000000000..0dfba2bf7f3189e0fd93c3168ad769a4968a6522 --- /dev/null +++ b/arch/powerpc/mm/mmu_context_hash32.c @@ -0,0 +1,103 @@ +/* + * This file contains the routines for handling the MMU on those + * PowerPC implementations where the MMU substantially follows the + * architecture specification. This includes the 6xx, 7xx, 7xxx, + * 8260, and POWER3 implementations but excludes the 8xx and 4xx. + * -- paulus + * + * Derived from arch/ppc/mm/init.c: + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au) + * and Cort Dougan (PReP) (cort@cs.nmt.edu) + * Copyright (C) 1996 Paul Mackerras + * + * Derived from "arch/i386/mm/init.c" + * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include + +#include +#include + +/* + * On 32-bit PowerPC 6xx/7xx/7xxx CPUs, we use a set of 16 VSIDs + * (virtual segment identifiers) for each context. Although the + * hardware supports 24-bit VSIDs, and thus >1 million contexts, + * we only use 32,768 of them. That is ample, since there can be + * at most around 30,000 tasks in the system anyway, and it means + * that we can use a bitmap to indicate which contexts are in use. + * Using a bitmap means that we entirely avoid all of the problems + * that we used to have when the context number overflowed, + * particularly on SMP systems. + * -- paulus. + */ +#define NO_CONTEXT ((unsigned long) -1) +#define LAST_CONTEXT 32767 +#define FIRST_CONTEXT 1 + +/* + * This function defines the mapping from contexts to VSIDs (virtual + * segment IDs). We use a skew on both the context and the high 4 bits + * of the 32-bit virtual address (the "effective segment ID") in order + * to spread out the entries in the MMU hash table. Note, if this + * function is changed then arch/ppc/mm/hashtable.S will have to be + * changed to correspond. + * + * + * CTX_TO_VSID(ctx, va) (((ctx) * (897 * 16) + ((va) >> 28) * 0x111) \ + * & 0xffffff) + */ + +static unsigned long next_mmu_context; +static unsigned long context_map[LAST_CONTEXT / BITS_PER_LONG + 1]; + + +/* + * Set up the context for a new address space. + */ +int init_new_context(struct task_struct *t, struct mm_struct *mm) +{ + unsigned long ctx = next_mmu_context; + + while (test_and_set_bit(ctx, context_map)) { + ctx = find_next_zero_bit(context_map, LAST_CONTEXT+1, ctx); + if (ctx > LAST_CONTEXT) + ctx = 0; + } + next_mmu_context = (ctx + 1) & LAST_CONTEXT; + mm->context.id = ctx; + + return 0; +} + +/* + * We're finished using the context for an address space. + */ +void destroy_context(struct mm_struct *mm) +{ + preempt_disable(); + if (mm->context.id != NO_CONTEXT) { + clear_bit(mm->context.id, context_map); + mm->context.id = NO_CONTEXT; + } + preempt_enable(); +} + +/* + * Initialize the context management stuff. + */ +void __init mmu_context_init(void) +{ + /* Reserve context 0 for kernel use */ + context_map[0] = (1 << FIRST_CONTEXT) - 1; + next_mmu_context = FIRST_CONTEXT; +} diff --git a/arch/powerpc/mm/mmu_context_64.c b/arch/powerpc/mm/mmu_context_hash64.c similarity index 86% rename from arch/powerpc/mm/mmu_context_64.c rename to arch/powerpc/mm/mmu_context_hash64.c index 1db38ba1f544e003a40c48a9b5652834bfa4bf27..dbeb86ac90cd79f01396eecbd72b98bc172253dc 100644 --- a/arch/powerpc/mm/mmu_context_64.c +++ b/arch/powerpc/mm/mmu_context_hash64.c @@ -24,6 +24,14 @@ static DEFINE_SPINLOCK(mmu_context_lock); static DEFINE_IDR(mmu_context_idr); +/* + * The proto-VSID space has 2^35 - 1 segments available for user mappings. + * Each segment contains 2^28 bytes. Each context maps 2^44 bytes, + * so we can support 2^19-1 contexts (19 == 35 + 28 - 44). + */ +#define NO_CONTEXT 0 +#define MAX_CONTEXT ((1UL << 19) - 1) + int init_new_context(struct task_struct *tsk, struct mm_struct *mm) { int index; diff --git a/arch/powerpc/mm/mmu_context_nohash.c b/arch/powerpc/mm/mmu_context_nohash.c new file mode 100644 index 0000000000000000000000000000000000000000..52a0cfc38b6488eecd50374d56271f1fc3a83553 --- /dev/null +++ b/arch/powerpc/mm/mmu_context_nohash.c @@ -0,0 +1,397 @@ +/* + * This file contains the routines for handling the MMU on those + * PowerPC implementations where the MMU is not using the hash + * table, such as 8xx, 4xx, BookE's etc... + * + * Copyright 2008 Ben Herrenschmidt + * IBM Corp. + * + * Derived from previous arch/powerpc/mm/mmu_context.c + * and arch/powerpc/include/asm/mmu_context.h + * + * 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. + * + * TODO: + * + * - The global context lock will not scale very well + * - The maps should be dynamically allocated to allow for processors + * that support more PID bits at runtime + * - Implement flush_tlb_mm() by making the context stale and picking + * a new one + * - More aggressively clear stale map bits and maybe find some way to + * also clear mm->cpu_vm_mask bits when processes are migrated + */ + +#undef DEBUG +#define DEBUG_STEAL_ONLY +#undef DEBUG_MAP_CONSISTENCY +/*#define DEBUG_CLAMP_LAST_CONTEXT 15 */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static unsigned int first_context, last_context; +static unsigned int next_context, nr_free_contexts; +static unsigned long *context_map; +static unsigned long *stale_map[NR_CPUS]; +static struct mm_struct **context_mm; +static spinlock_t context_lock = SPIN_LOCK_UNLOCKED; + +#define CTX_MAP_SIZE \ + (sizeof(unsigned long) * (last_context / BITS_PER_LONG + 1)) + + +/* Steal a context from a task that has one at the moment. + * + * This is used when we are running out of available PID numbers + * on the processors. + * + * This isn't an LRU system, it just frees up each context in + * turn (sort-of pseudo-random replacement :). This would be the + * place to implement an LRU scheme if anyone was motivated to do it. + * -- paulus + * + * For context stealing, we use a slightly different approach for + * SMP and UP. Basically, the UP one is simpler and doesn't use + * the stale map as we can just flush the local CPU + * -- benh + */ +#ifdef CONFIG_SMP +static unsigned int steal_context_smp(unsigned int id) +{ + struct mm_struct *mm; + unsigned int cpu, max; + + again: + max = last_context - first_context; + + /* Attempt to free next_context first and then loop until we manage */ + while (max--) { + /* Pick up the victim mm */ + mm = context_mm[id]; + + /* We have a candidate victim, check if it's active, on SMP + * we cannot steal active contexts + */ + if (mm->context.active) { + id++; + if (id > last_context) + id = first_context; + continue; + } + pr_debug("[%d] steal context %d from mm @%p\n", + smp_processor_id(), id, mm); + + /* Mark this mm has having no context anymore */ + mm->context.id = MMU_NO_CONTEXT; + + /* Mark it stale on all CPUs that used this mm */ + for_each_cpu_mask_nr(cpu, mm->cpu_vm_mask) + __set_bit(id, stale_map[cpu]); + return id; + } + + /* This will happen if you have more CPUs than available contexts, + * all we can do here is wait a bit and try again + */ + spin_unlock(&context_lock); + cpu_relax(); + spin_lock(&context_lock); + goto again; +} +#endif /* CONFIG_SMP */ + +/* Note that this will also be called on SMP if all other CPUs are + * offlined, which means that it may be called for cpu != 0. For + * this to work, we somewhat assume that CPUs that are onlined + * come up with a fully clean TLB (or are cleaned when offlined) + */ +static unsigned int steal_context_up(unsigned int id) +{ + struct mm_struct *mm; + int cpu = smp_processor_id(); + + /* Pick up the victim mm */ + mm = context_mm[id]; + + pr_debug("[%d] steal context %d from mm @%p\n", cpu, id, mm); + + /* Mark this mm has having no context anymore */ + mm->context.id = MMU_NO_CONTEXT; + + /* Flush the TLB for that context */ + local_flush_tlb_mm(mm); + + /* XXX This clear should ultimately be part of local_flush_tlb_mm */ + __clear_bit(id, stale_map[cpu]); + + return id; +} + +#ifdef DEBUG_MAP_CONSISTENCY +static void context_check_map(void) +{ + unsigned int id, nrf, nact; + + nrf = nact = 0; + for (id = first_context; id <= last_context; id++) { + int used = test_bit(id, context_map); + if (!used) + nrf++; + if (used != (context_mm[id] != NULL)) + pr_err("MMU: Context %d is %s and MM is %p !\n", + id, used ? "used" : "free", context_mm[id]); + if (context_mm[id] != NULL) + nact += context_mm[id]->context.active; + } + if (nrf != nr_free_contexts) { + pr_err("MMU: Free context count out of sync ! (%d vs %d)\n", + nr_free_contexts, nrf); + nr_free_contexts = nrf; + } + if (nact > num_online_cpus()) + pr_err("MMU: More active contexts than CPUs ! (%d vs %d)\n", + nact, num_online_cpus()); + if (first_context > 0 && !test_bit(0, context_map)) + pr_err("MMU: Context 0 has been freed !!!\n"); +} +#else +static void context_check_map(void) { } +#endif + +void switch_mmu_context(struct mm_struct *prev, struct mm_struct *next) +{ + unsigned int id, cpu = smp_processor_id(); + unsigned long *map; + + /* No lockless fast path .. yet */ + spin_lock(&context_lock); + +#ifndef DEBUG_STEAL_ONLY + pr_debug("[%d] activating context for mm @%p, active=%d, id=%d\n", + cpu, next, next->context.active, next->context.id); +#endif + +#ifdef CONFIG_SMP + /* Mark us active and the previous one not anymore */ + next->context.active++; + if (prev) { +#ifndef DEBUG_STEAL_ONLY + pr_debug(" old context %p active was: %d\n", + prev, prev->context.active); +#endif + WARN_ON(prev->context.active < 1); + prev->context.active--; + } +#endif /* CONFIG_SMP */ + + /* If we already have a valid assigned context, skip all that */ + id = next->context.id; + if (likely(id != MMU_NO_CONTEXT)) + goto ctxt_ok; + + /* We really don't have a context, let's try to acquire one */ + id = next_context; + if (id > last_context) + id = first_context; + map = context_map; + + /* No more free contexts, let's try to steal one */ + if (nr_free_contexts == 0) { +#ifdef CONFIG_SMP + if (num_online_cpus() > 1) { + id = steal_context_smp(id); + goto stolen; + } +#endif /* CONFIG_SMP */ + id = steal_context_up(id); + goto stolen; + } + nr_free_contexts--; + + /* We know there's at least one free context, try to find it */ + while (__test_and_set_bit(id, map)) { + id = find_next_zero_bit(map, last_context+1, id); + if (id > last_context) + id = first_context; + } + stolen: + next_context = id + 1; + context_mm[id] = next; + next->context.id = id; + +#ifndef DEBUG_STEAL_ONLY + pr_debug("[%d] picked up new id %d, nrf is now %d\n", + cpu, id, nr_free_contexts); +#endif + + context_check_map(); + ctxt_ok: + + /* If that context got marked stale on this CPU, then flush the + * local TLB for it and unmark it before we use it + */ + if (test_bit(id, stale_map[cpu])) { + pr_debug("[%d] flushing stale context %d for mm @%p !\n", + cpu, id, next); + local_flush_tlb_mm(next); + + /* XXX This clear should ultimately be part of local_flush_tlb_mm */ + __clear_bit(id, stale_map[cpu]); + } + + /* Flick the MMU and release lock */ + set_context(id, next->pgd); + spin_unlock(&context_lock); +} + +/* + * Set up the context for a new address space. + */ +int init_new_context(struct task_struct *t, struct mm_struct *mm) +{ + mm->context.id = MMU_NO_CONTEXT; + mm->context.active = 0; + + return 0; +} + +/* + * We're finished using the context for an address space. + */ +void destroy_context(struct mm_struct *mm) +{ + unsigned int id; + + if (mm->context.id == MMU_NO_CONTEXT) + return; + + WARN_ON(mm->context.active != 0); + + spin_lock(&context_lock); + id = mm->context.id; + if (id != MMU_NO_CONTEXT) { + __clear_bit(id, context_map); + mm->context.id = MMU_NO_CONTEXT; +#ifdef DEBUG_MAP_CONSISTENCY + mm->context.active = 0; + context_mm[id] = NULL; +#endif + nr_free_contexts++; + } + spin_unlock(&context_lock); +} + +#ifdef CONFIG_SMP + +static int __cpuinit mmu_context_cpu_notify(struct notifier_block *self, + unsigned long action, void *hcpu) +{ + unsigned int cpu = (unsigned int)(long)hcpu; + + /* We don't touch CPU 0 map, it's allocated at aboot and kept + * around forever + */ + if (cpu == 0) + return NOTIFY_OK; + + switch (action) { + case CPU_ONLINE: + case CPU_ONLINE_FROZEN: + pr_debug("MMU: Allocating stale context map for CPU %d\n", cpu); + stale_map[cpu] = kzalloc(CTX_MAP_SIZE, GFP_KERNEL); + break; +#ifdef CONFIG_HOTPLUG_CPU + case CPU_DEAD: + case CPU_DEAD_FROZEN: + pr_debug("MMU: Freeing stale context map for CPU %d\n", cpu); + kfree(stale_map[cpu]); + stale_map[cpu] = NULL; + break; +#endif + } + return NOTIFY_OK; +} + +static struct notifier_block __cpuinitdata mmu_context_cpu_nb = { + .notifier_call = mmu_context_cpu_notify, +}; + +#endif /* CONFIG_SMP */ + +/* + * Initialize the context management stuff. + */ +void __init mmu_context_init(void) +{ + /* Mark init_mm as being active on all possible CPUs since + * we'll get called with prev == init_mm the first time + * we schedule on a given CPU + */ + init_mm.context.active = NR_CPUS; + + /* + * The MPC8xx has only 16 contexts. We rotate through them on each + * task switch. A better way would be to keep track of tasks that + * own contexts, and implement an LRU usage. That way very active + * tasks don't always have to pay the TLB reload overhead. The + * kernel pages are mapped shared, so the kernel can run on behalf + * of any task that makes a kernel entry. Shared does not mean they + * are not protected, just that the ASID comparison is not performed. + * -- Dan + * + * The IBM4xx has 256 contexts, so we can just rotate through these + * as a way of "switching" contexts. If the TID of the TLB is zero, + * the PID/TID comparison is disabled, so we can use a TID of zero + * to represent all kernel pages as shared among all contexts. + * -- Dan + */ + if (mmu_has_feature(MMU_FTR_TYPE_8xx)) { + first_context = 0; + last_context = 15; + } else { + first_context = 1; + last_context = 255; + } + +#ifdef DEBUG_CLAMP_LAST_CONTEXT + last_context = DEBUG_CLAMP_LAST_CONTEXT; +#endif + /* + * Allocate the maps used by context management + */ + context_map = alloc_bootmem(CTX_MAP_SIZE); + context_mm = alloc_bootmem(sizeof(void *) * (last_context + 1)); + stale_map[0] = alloc_bootmem(CTX_MAP_SIZE); + +#ifdef CONFIG_SMP + register_cpu_notifier(&mmu_context_cpu_nb); +#endif + + printk(KERN_INFO + "MMU: Allocated %d bytes of context maps for %d contexts\n", + 2 * CTX_MAP_SIZE + (sizeof(void *) * (last_context + 1)), + last_context - first_context + 1); + + /* + * Some processors have too few contexts to reserve one for + * init_mm, and require using context 0 for a normal task. + * Other processors reserve the use of context zero for the kernel. + * This code assumes first_context < 32. + */ + context_map[0] = (1 << first_context) - 1; + next_context = first_context; + nr_free_contexts = last_context - first_context + 1; +} + diff --git a/arch/powerpc/mm/mmu_decl.h b/arch/powerpc/mm/mmu_decl.h index fab3cfad40992d45dcae4113b862497dfea42632..4314b39b6faf6c5c83f517c4bed95d00b5191123 100644 --- a/arch/powerpc/mm/mmu_decl.h +++ b/arch/powerpc/mm/mmu_decl.h @@ -22,10 +22,58 @@ #include #include +#ifdef CONFIG_PPC_MMU_NOHASH + +/* + * On 40x and 8xx, we directly inline tlbia and tlbivax + */ +#if defined(CONFIG_40x) || defined(CONFIG_8xx) +static inline void _tlbil_all(void) +{ + asm volatile ("sync; tlbia; isync" : : : "memory") +} +static inline void _tlbil_pid(unsigned int pid) +{ + asm volatile ("sync; tlbia; isync" : : : "memory") +} +#else /* CONFIG_40x || CONFIG_8xx */ +extern void _tlbil_all(void); +extern void _tlbil_pid(unsigned int pid); +#endif /* !(CONFIG_40x || CONFIG_8xx) */ + +/* + * On 8xx, we directly inline tlbie, on others, it's extern + */ +#ifdef CONFIG_8xx +static inline void _tlbil_va(unsigned long address, unsigned int pid) +{ + asm volatile ("tlbie %0; sync" : : "r" (address) : "memory") +} +#else /* CONFIG_8xx */ +extern void _tlbil_va(unsigned long address, unsigned int pid); +#endif /* CONIFG_8xx */ + +/* + * As of today, we don't support tlbivax broadcast on any + * implementation. When that becomes the case, this will be + * an extern. + */ +static inline void _tlbivax_bcast(unsigned long address, unsigned int pid) +{ + BUG(); +} + +#else /* CONFIG_PPC_MMU_NOHASH */ + extern void hash_preload(struct mm_struct *mm, unsigned long ea, unsigned long access, unsigned long trap); +extern void _tlbie(unsigned long address); +extern void _tlbia(void); + +#endif /* CONFIG_PPC_MMU_NOHASH */ + #ifdef CONFIG_PPC32 extern void mapin_ram(void); extern int map_page(unsigned long va, phys_addr_t pa, int flags); @@ -58,17 +106,14 @@ extern phys_addr_t lowmem_end_addr; * architectures. -- Dan */ #if defined(CONFIG_8xx) -#define flush_HPTE(X, va, pg) _tlbie(va, 0 /* 8xx doesn't care about PID */) #define MMU_init_hw() do { } while(0) #define mmu_mapin_ram() (0UL) #elif defined(CONFIG_4xx) -#define flush_HPTE(pid, va, pg) _tlbie(va, pid) extern void MMU_init_hw(void); extern unsigned long mmu_mapin_ram(void); #elif defined(CONFIG_FSL_BOOKE) -#define flush_HPTE(pid, va, pg) _tlbie(va, pid) extern void MMU_init_hw(void); extern unsigned long mmu_mapin_ram(void); extern void adjust_total_lowmem(void); @@ -77,18 +122,4 @@ extern void adjust_total_lowmem(void); /* anything 32-bit except 4xx or 8xx */ extern void MMU_init_hw(void); extern unsigned long mmu_mapin_ram(void); - -/* Be careful....this needs to be updated if we ever encounter 603 SMPs, - * which includes all new 82xx processors. We need tlbie/tlbsync here - * in that case (I think). -- Dan. - */ -static inline void flush_HPTE(unsigned context, unsigned long va, - unsigned long pdval) -{ - if ((Hash != 0) && - cpu_has_feature(CPU_FTR_HPTE_TABLE)) - flush_hash_pages(0, va, pdval, 1); - else - _tlbie(va); -} #endif diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c new file mode 100644 index 0000000000000000000000000000000000000000..6d94116fdea171b6683fc938e7639dfe92ba1caf --- /dev/null +++ b/arch/powerpc/mm/pgtable.c @@ -0,0 +1,117 @@ +/* + * This file contains common routines for dealing with free of page tables + * + * Derived from arch/powerpc/mm/tlb_64.c: + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au) + * and Cort Dougan (PReP) (cort@cs.nmt.edu) + * Copyright (C) 1996 Paul Mackerras + * + * Derived from "arch/i386/mm/init.c" + * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds + * + * Dave Engebretsen + * Rework for PPC64 port. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static DEFINE_PER_CPU(struct pte_freelist_batch *, pte_freelist_cur); +static unsigned long pte_freelist_forced_free; + +struct pte_freelist_batch +{ + struct rcu_head rcu; + unsigned int index; + pgtable_free_t tables[0]; +}; + +#define PTE_FREELIST_SIZE \ + ((PAGE_SIZE - sizeof(struct pte_freelist_batch)) \ + / sizeof(pgtable_free_t)) + +static void pte_free_smp_sync(void *arg) +{ + /* Do nothing, just ensure we sync with all CPUs */ +} + +/* This is only called when we are critically out of memory + * (and fail to get a page in pte_free_tlb). + */ +static void pgtable_free_now(pgtable_free_t pgf) +{ + pte_freelist_forced_free++; + + smp_call_function(pte_free_smp_sync, NULL, 1); + + pgtable_free(pgf); +} + +static void pte_free_rcu_callback(struct rcu_head *head) +{ + struct pte_freelist_batch *batch = + container_of(head, struct pte_freelist_batch, rcu); + unsigned int i; + + for (i = 0; i < batch->index; i++) + pgtable_free(batch->tables[i]); + + free_page((unsigned long)batch); +} + +static void pte_free_submit(struct pte_freelist_batch *batch) +{ + INIT_RCU_HEAD(&batch->rcu); + call_rcu(&batch->rcu, pte_free_rcu_callback); +} + +void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf) +{ + /* This is safe since tlb_gather_mmu has disabled preemption */ + cpumask_t local_cpumask = cpumask_of_cpu(smp_processor_id()); + struct pte_freelist_batch **batchp = &__get_cpu_var(pte_freelist_cur); + + if (atomic_read(&tlb->mm->mm_users) < 2 || + cpus_equal(tlb->mm->cpu_vm_mask, local_cpumask)) { + pgtable_free(pgf); + return; + } + + if (*batchp == NULL) { + *batchp = (struct pte_freelist_batch *)__get_free_page(GFP_ATOMIC); + if (*batchp == NULL) { + pgtable_free_now(pgf); + return; + } + (*batchp)->index = 0; + } + (*batchp)->tables[(*batchp)->index++] = pgf; + if ((*batchp)->index == PTE_FREELIST_SIZE) { + pte_free_submit(*batchp); + *batchp = NULL; + } +} + +void pte_free_finish(void) +{ + /* This is safe since tlb_gather_mmu has disabled preemption */ + struct pte_freelist_batch **batchp = &__get_cpu_var(pte_freelist_cur); + + if (*batchp == NULL) + return; + pte_free_submit(*batchp); + *batchp = NULL; +} diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c index c31d6d26f0b57c50b5b38bdc042f7221a93adf82..38ff35f2142a5faa37aeb7947fb6f33ce34e9df5 100644 --- a/arch/powerpc/mm/pgtable_32.c +++ b/arch/powerpc/mm/pgtable_32.c @@ -48,10 +48,6 @@ EXPORT_SYMBOL(ioremap_bot); /* aka VMALLOC_END */ extern char etext[], _stext[]; -#ifdef CONFIG_SMP -extern void hash_page_sync(void); -#endif - #ifdef HAVE_BATS extern phys_addr_t v_mapped_by_bats(unsigned long va); extern unsigned long p_mapped_by_bats(phys_addr_t pa); @@ -72,24 +68,29 @@ extern unsigned long p_mapped_by_tlbcam(unsigned long pa); #define p_mapped_by_tlbcam(x) (0UL) #endif /* HAVE_TLBCAM */ -#ifdef CONFIG_PTE_64BIT -/* Some processors use an 8kB pgdir because they have 8-byte Linux PTEs. */ -#define PGDIR_ORDER 1 -#else -#define PGDIR_ORDER 0 -#endif +#define PGDIR_ORDER (32 + PGD_T_LOG2 - PGDIR_SHIFT) pgd_t *pgd_alloc(struct mm_struct *mm) { pgd_t *ret; - ret = (pgd_t *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, PGDIR_ORDER); + /* pgdir take page or two with 4K pages and a page fraction otherwise */ +#ifndef CONFIG_PPC_4K_PAGES + ret = (pgd_t *)kzalloc(1 << PGDIR_ORDER, GFP_KERNEL); +#else + ret = (pgd_t *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, + PGDIR_ORDER - PAGE_SHIFT); +#endif return ret; } void pgd_free(struct mm_struct *mm, pgd_t *pgd) { - free_pages((unsigned long)pgd, PGDIR_ORDER); +#ifndef CONFIG_PPC_4K_PAGES + kfree((void *)pgd); +#else + free_pages((unsigned long)pgd, PGDIR_ORDER - PAGE_SHIFT); +#endif } __init_refok pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) @@ -125,23 +126,6 @@ pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long address) return ptepage; } -void pte_free_kernel(struct mm_struct *mm, pte_t *pte) -{ -#ifdef CONFIG_SMP - hash_page_sync(); -#endif - free_page((unsigned long)pte); -} - -void pte_free(struct mm_struct *mm, pgtable_t ptepage) -{ -#ifdef CONFIG_SMP - hash_page_sync(); -#endif - pgtable_page_dtor(ptepage); - __free_page(ptepage); -} - void __iomem * ioremap(phys_addr_t addr, unsigned long size) { @@ -194,6 +178,7 @@ __ioremap(phys_addr_t addr, unsigned long size, unsigned long flags) if (p < 16*1024*1024) p += _ISA_MEM_BASE; +#ifndef CONFIG_CRASH_DUMP /* * Don't allow anybody to remap normal RAM that we're using. * mem_init() sets high_memory so only do the check after that. @@ -203,6 +188,7 @@ __ioremap(phys_addr_t addr, unsigned long size, unsigned long flags) (unsigned long long)p, __builtin_return_address(0)); return NULL; } +#endif if (size == 0) return NULL; @@ -288,7 +274,7 @@ int map_page(unsigned long va, phys_addr_t pa, int flags) } /* - * Map in a big chunk of physical memory starting at KERNELBASE. + * Map in a big chunk of physical memory starting at PAGE_OFFSET. */ void __init mapin_ram(void) { @@ -297,7 +283,7 @@ void __init mapin_ram(void) int ktext; s = mmu_mapin_ram(); - v = KERNELBASE + s; + v = PAGE_OFFSET + s; p = memstart_addr + s; for (; s < total_lowmem; s += PAGE_SIZE) { ktext = ((char *) v >= _stext && (char *) v < etext); @@ -363,7 +349,11 @@ static int __change_page_attr(struct page *page, pgprot_t prot) return -EINVAL; set_pte_at(&init_mm, address, kpte, mk_pte(page, prot)); wmb(); - flush_HPTE(0, address, pmd_val(*kpmd)); +#ifdef CONFIG_PPC_STD_MMU + flush_hash_pages(0, address, pmd_val(*kpmd), 1); +#else + flush_tlb_page(NULL, address); +#endif pte_unmap(kpte); return 0; @@ -400,7 +390,7 @@ void kernel_map_pages(struct page *page, int numpages, int enable) #endif /* CONFIG_DEBUG_PAGEALLOC */ static int fixmaps; -unsigned long FIXADDR_TOP = 0xfffff000; +unsigned long FIXADDR_TOP = (-PAGE_SIZE); EXPORT_SYMBOL(FIXADDR_TOP); void __set_fixmap (enum fixed_addresses idx, phys_addr_t phys, pgprot_t flags) diff --git a/arch/powerpc/mm/ppc_mmu_32.c b/arch/powerpc/mm/ppc_mmu_32.c index 6aa12081377531594bea592b94915da93904be78..45d925360b89aa3a2b17f71daa2a823f6b11c7ef 100644 --- a/arch/powerpc/mm/ppc_mmu_32.c +++ b/arch/powerpc/mm/ppc_mmu_32.c @@ -95,16 +95,16 @@ unsigned long __init mmu_mapin_ram(void) break; } - setbat(2, KERNELBASE, 0, bl, _PAGE_RAM); - done = (unsigned long)bat_addrs[2].limit - KERNELBASE + 1; + setbat(2, PAGE_OFFSET, 0, bl, _PAGE_RAM); + done = (unsigned long)bat_addrs[2].limit - PAGE_OFFSET + 1; if ((done < tot) && !bat_addrs[3].limit) { /* use BAT3 to cover a bit more */ tot -= done; for (bl = 128<<10; bl < max_size; bl <<= 1) if (bl * 2 > tot) break; - setbat(3, KERNELBASE+done, done, bl, _PAGE_RAM); - done = (unsigned long)bat_addrs[3].limit - KERNELBASE + 1; + setbat(3, PAGE_OFFSET+done, done, bl, _PAGE_RAM); + done = (unsigned long)bat_addrs[3].limit - PAGE_OFFSET + 1; } return done; @@ -192,7 +192,7 @@ void __init MMU_init_hw(void) extern unsigned int hash_page[]; extern unsigned int flush_hash_patch_A[], flush_hash_patch_B[]; - if (!cpu_has_feature(CPU_FTR_HPTE_TABLE)) { + if (!mmu_has_feature(MMU_FTR_HPTE_TABLE)) { /* * Put a blr (procedure return) instruction at the * start of hash_page, since we can still get DSI diff --git a/arch/powerpc/mm/tlb_32.c b/arch/powerpc/mm/tlb_hash32.c similarity index 97% rename from arch/powerpc/mm/tlb_32.c rename to arch/powerpc/mm/tlb_hash32.c index f9a47fee39278174872a30a7844ff2b01c99d4c1..65190587a365056cb35ce04aebc41d9dc1fb7cd1 100644 --- a/arch/powerpc/mm/tlb_32.c +++ b/arch/powerpc/mm/tlb_hash32.c @@ -137,6 +137,7 @@ void flush_tlb_kernel_range(unsigned long start, unsigned long end) flush_range(&init_mm, start, end); FINISH_FLUSH; } +EXPORT_SYMBOL(flush_tlb_kernel_range); /* * Flush all the (user) entries for the address space described by mm. @@ -160,6 +161,7 @@ void flush_tlb_mm(struct mm_struct *mm) flush_range(mp->vm_mm, mp->vm_start, mp->vm_end); FINISH_FLUSH; } +EXPORT_SYMBOL(flush_tlb_mm); void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr) { @@ -176,6 +178,7 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr) flush_hash_pages(mm->context.id, vmaddr, pmd_val(*pmd), 1); FINISH_FLUSH; } +EXPORT_SYMBOL(flush_tlb_page); /* * For each address in the range, find the pte for the address @@ -188,3 +191,4 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, flush_range(vma->vm_mm, start, end); FINISH_FLUSH; } +EXPORT_SYMBOL(flush_tlb_range); diff --git a/arch/powerpc/mm/tlb_64.c b/arch/powerpc/mm/tlb_hash64.c similarity index 75% rename from arch/powerpc/mm/tlb_64.c rename to arch/powerpc/mm/tlb_hash64.c index be7dd422c0fa703dcc027a0645c98cc180af8448..c931bc7d1079bec0e9241620781aa5eb5251aba6 100644 --- a/arch/powerpc/mm/tlb_64.c +++ b/arch/powerpc/mm/tlb_hash64.c @@ -37,81 +37,6 @@ DEFINE_PER_CPU(struct ppc64_tlb_batch, ppc64_tlb_batch); * arch/powerpc/include/asm/tlb.h file -- tgall */ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); -static DEFINE_PER_CPU(struct pte_freelist_batch *, pte_freelist_cur); -static unsigned long pte_freelist_forced_free; - -struct pte_freelist_batch -{ - struct rcu_head rcu; - unsigned int index; - pgtable_free_t tables[0]; -}; - -#define PTE_FREELIST_SIZE \ - ((PAGE_SIZE - sizeof(struct pte_freelist_batch)) \ - / sizeof(pgtable_free_t)) - -static void pte_free_smp_sync(void *arg) -{ - /* Do nothing, just ensure we sync with all CPUs */ -} - -/* This is only called when we are critically out of memory - * (and fail to get a page in pte_free_tlb). - */ -static void pgtable_free_now(pgtable_free_t pgf) -{ - pte_freelist_forced_free++; - - smp_call_function(pte_free_smp_sync, NULL, 1); - - pgtable_free(pgf); -} - -static void pte_free_rcu_callback(struct rcu_head *head) -{ - struct pte_freelist_batch *batch = - container_of(head, struct pte_freelist_batch, rcu); - unsigned int i; - - for (i = 0; i < batch->index; i++) - pgtable_free(batch->tables[i]); - - free_page((unsigned long)batch); -} - -static void pte_free_submit(struct pte_freelist_batch *batch) -{ - INIT_RCU_HEAD(&batch->rcu); - call_rcu(&batch->rcu, pte_free_rcu_callback); -} - -void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf) -{ - /* This is safe since tlb_gather_mmu has disabled preemption */ - cpumask_t local_cpumask = cpumask_of_cpu(smp_processor_id()); - struct pte_freelist_batch **batchp = &__get_cpu_var(pte_freelist_cur); - - if (atomic_read(&tlb->mm->mm_users) < 2 || - cpus_equal(tlb->mm->cpu_vm_mask, local_cpumask)) { - pgtable_free(pgf); - return; - } - - if (*batchp == NULL) { - *batchp = (struct pte_freelist_batch *)__get_free_page(GFP_ATOMIC); - if (*batchp == NULL) { - pgtable_free_now(pgf); - return; - } - (*batchp)->index = 0; - } - (*batchp)->tables[(*batchp)->index++] = pgf; - if ((*batchp)->index == PTE_FREELIST_SIZE) { - pte_free_submit(*batchp); - *batchp = NULL; - } -} /* * A linux PTE was changed and the corresponding hash table entry @@ -229,17 +154,6 @@ void __flush_tlb_pending(struct ppc64_tlb_batch *batch) batch->index = 0; } -void pte_free_finish(void) -{ - /* This is safe since tlb_gather_mmu has disabled preemption */ - struct pte_freelist_batch **batchp = &__get_cpu_var(pte_freelist_cur); - - if (*batchp == NULL) - return; - pte_free_submit(*batchp); - *batchp = NULL; -} - /** * __flush_hash_table_range - Flush all HPTEs for a given address range * from the hash table (and the TLB). But keeps diff --git a/arch/powerpc/mm/tlb_nohash.c b/arch/powerpc/mm/tlb_nohash.c new file mode 100644 index 0000000000000000000000000000000000000000..803a64c02b06ea3930d273a335db284d9b2f37f4 --- /dev/null +++ b/arch/powerpc/mm/tlb_nohash.c @@ -0,0 +1,209 @@ +/* + * This file contains the routines for TLB flushing. + * On machines where the MMU does not use a hash table to store virtual to + * physical translations (ie, SW loaded TLBs or Book3E compilant processors, + * this does -not- include 603 however which shares the implementation with + * hash based processors) + * + * -- BenH + * + * Copyright 2008 Ben Herrenschmidt + * IBM Corp. + * + * Derived from arch/ppc/mm/init.c: + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au) + * and Cort Dougan (PReP) (cort@cs.nmt.edu) + * Copyright (C) 1996 Paul Mackerras + * + * Derived from "arch/i386/mm/init.c" + * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "mmu_decl.h" + +/* + * Base TLB flushing operations: + * + * - flush_tlb_mm(mm) flushes the specified mm context TLB's + * - flush_tlb_page(vma, vmaddr) flushes one page + * - flush_tlb_range(vma, start, end) flushes a range of pages + * - flush_tlb_kernel_range(start, end) flushes kernel pages + * + * - local_* variants of page and mm only apply to the current + * processor + */ + +/* + * These are the base non-SMP variants of page and mm flushing + */ +void local_flush_tlb_mm(struct mm_struct *mm) +{ + unsigned int pid; + + preempt_disable(); + pid = mm->context.id; + if (pid != MMU_NO_CONTEXT) + _tlbil_pid(pid); + preempt_enable(); +} +EXPORT_SYMBOL(local_flush_tlb_mm); + +void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr) +{ + unsigned int pid; + + preempt_disable(); + pid = vma ? vma->vm_mm->context.id : 0; + if (pid != MMU_NO_CONTEXT) + _tlbil_va(vmaddr, pid); + preempt_enable(); +} +EXPORT_SYMBOL(local_flush_tlb_page); + + +/* + * And here are the SMP non-local implementations + */ +#ifdef CONFIG_SMP + +static DEFINE_SPINLOCK(tlbivax_lock); + +struct tlb_flush_param { + unsigned long addr; + unsigned int pid; +}; + +static void do_flush_tlb_mm_ipi(void *param) +{ + struct tlb_flush_param *p = param; + + _tlbil_pid(p ? p->pid : 0); +} + +static void do_flush_tlb_page_ipi(void *param) +{ + struct tlb_flush_param *p = param; + + _tlbil_va(p->addr, p->pid); +} + + +/* Note on invalidations and PID: + * + * We snapshot the PID with preempt disabled. At this point, it can still + * change either because: + * - our context is being stolen (PID -> NO_CONTEXT) on another CPU + * - we are invaliating some target that isn't currently running here + * and is concurrently acquiring a new PID on another CPU + * - some other CPU is re-acquiring a lost PID for this mm + * etc... + * + * However, this shouldn't be a problem as we only guarantee + * invalidation of TLB entries present prior to this call, so we + * don't care about the PID changing, and invalidating a stale PID + * is generally harmless. + */ + +void flush_tlb_mm(struct mm_struct *mm) +{ + cpumask_t cpu_mask; + unsigned int pid; + + preempt_disable(); + pid = mm->context.id; + if (unlikely(pid == MMU_NO_CONTEXT)) + goto no_context; + cpu_mask = mm->cpu_vm_mask; + cpu_clear(smp_processor_id(), cpu_mask); + if (!cpus_empty(cpu_mask)) { + struct tlb_flush_param p = { .pid = pid }; + smp_call_function_mask(cpu_mask, do_flush_tlb_mm_ipi, &p, 1); + } + _tlbil_pid(pid); + no_context: + preempt_enable(); +} +EXPORT_SYMBOL(flush_tlb_mm); + +void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr) +{ + cpumask_t cpu_mask; + unsigned int pid; + + preempt_disable(); + pid = vma ? vma->vm_mm->context.id : 0; + if (unlikely(pid == MMU_NO_CONTEXT)) + goto bail; + cpu_mask = vma->vm_mm->cpu_vm_mask; + cpu_clear(smp_processor_id(), cpu_mask); + if (!cpus_empty(cpu_mask)) { + /* If broadcast tlbivax is supported, use it */ + if (mmu_has_feature(MMU_FTR_USE_TLBIVAX_BCAST)) { + int lock = mmu_has_feature(MMU_FTR_LOCK_BCAST_INVAL); + if (lock) + spin_lock(&tlbivax_lock); + _tlbivax_bcast(vmaddr, pid); + if (lock) + spin_unlock(&tlbivax_lock); + goto bail; + } else { + struct tlb_flush_param p = { .pid = pid, .addr = vmaddr }; + smp_call_function_mask(cpu_mask, + do_flush_tlb_page_ipi, &p, 1); + } + } + _tlbil_va(vmaddr, pid); + bail: + preempt_enable(); +} +EXPORT_SYMBOL(flush_tlb_page); + +#endif /* CONFIG_SMP */ + +/* + * Flush kernel TLB entries in the given range + */ +void flush_tlb_kernel_range(unsigned long start, unsigned long end) +{ +#ifdef CONFIG_SMP + preempt_disable(); + smp_call_function(do_flush_tlb_mm_ipi, NULL, 1); + _tlbil_pid(0); + preempt_enable(); +#endif + _tlbil_pid(0); +} +EXPORT_SYMBOL(flush_tlb_kernel_range); + +/* + * Currently, for range flushing, we just do a full mm flush. This should + * be optimized based on a threshold on the size of the range, since + * some implementation can stack multiple tlbivax before a tlbsync but + * for now, we keep it that way + */ +void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end) + +{ + flush_tlb_mm(vma->vm_mm); +} +EXPORT_SYMBOL(flush_tlb_range); diff --git a/arch/powerpc/mm/tlb_nohash_low.S b/arch/powerpc/mm/tlb_nohash_low.S new file mode 100644 index 0000000000000000000000000000000000000000..f900a39e6ec409f9a6c7789a5fbf5747777e6ffc --- /dev/null +++ b/arch/powerpc/mm/tlb_nohash_low.S @@ -0,0 +1,166 @@ +/* + * This file contains low-level functions for performing various + * types of TLB invalidations on various processors with no hash + * table. + * + * This file implements the following functions for all no-hash + * processors. Some aren't implemented for some variants. Some + * are inline in tlbflush.h + * + * - tlbil_va + * - tlbil_pid + * - tlbil_all + * - tlbivax_bcast (not yet) + * + * Code mostly moved over from misc_32.S + * + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Partially rewritten by Cort Dougan (cort@cs.nmt.edu) + * Paul Mackerras, Kumar Gala and Benjamin Herrenschmidt. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_40x) + +/* + * 40x implementation needs only tlbil_va + */ +_GLOBAL(_tlbil_va) + /* We run the search with interrupts disabled because we have to change + * the PID and I don't want to preempt when that happens. + */ + mfmsr r5 + mfspr r6,SPRN_PID + wrteei 0 + mtspr SPRN_PID,r4 + tlbsx. r3, 0, r3 + mtspr SPRN_PID,r6 + wrtee r5 + bne 1f + sync + /* There are only 64 TLB entries, so r3 < 64, which means bit 25 is + * clear. Since 25 is the V bit in the TLB_TAG, loading this value + * will invalidate the TLB entry. */ + tlbwe r3, r3, TLB_TAG + isync +1: blr + +#elif defined(CONFIG_8xx) + +/* + * Nothing to do for 8xx, everything is inline + */ + +#elif defined(CONFIG_44x) + +/* + * 440 implementation uses tlbsx/we for tlbil_va and a full sweep + * of the TLB for everything else. + */ +_GLOBAL(_tlbil_va) + mfspr r5,SPRN_MMUCR + rlwimi r5,r4,0,24,31 /* Set TID */ + + /* We have to run the search with interrupts disabled, otherwise + * an interrupt which causes a TLB miss can clobber the MMUCR + * between the mtspr and the tlbsx. + * + * Critical and Machine Check interrupts take care of saving + * and restoring MMUCR, so only normal interrupts have to be + * taken care of. + */ + mfmsr r4 + wrteei 0 + mtspr SPRN_MMUCR,r5 + tlbsx. r3, 0, r3 + wrtee r4 + bne 1f + sync + /* There are only 64 TLB entries, so r3 < 64, + * which means bit 22, is clear. Since 22 is + * the V bit in the TLB_PAGEID, loading this + * value will invalidate the TLB entry. + */ + tlbwe r3, r3, PPC44x_TLB_PAGEID + isync +1: blr + +_GLOBAL(_tlbil_all) +_GLOBAL(_tlbil_pid) + li r3,0 + sync + + /* Load high watermark */ + lis r4,tlb_44x_hwater@ha + lwz r5,tlb_44x_hwater@l(r4) + +1: tlbwe r3,r3,PPC44x_TLB_PAGEID + addi r3,r3,1 + cmpw 0,r3,r5 + ble 1b + + isync + blr + +#elif defined(CONFIG_FSL_BOOKE) +/* + * FSL BookE implementations. Currently _pid and _all are the + * same. This will change when tlbilx is actually supported and + * performs invalidate-by-PID. This change will be driven by + * mmu_features conditional + */ + +/* + * Flush MMU TLB on the local processor + */ +_GLOBAL(_tlbil_pid) +_GLOBAL(_tlbil_all) +#define MMUCSR0_TLBFI (MMUCSR0_TLB0FI | MMUCSR0_TLB1FI | \ + MMUCSR0_TLB2FI | MMUCSR0_TLB3FI) + li r3,(MMUCSR0_TLBFI)@l + mtspr SPRN_MMUCSR0, r3 +1: + mfspr r3,SPRN_MMUCSR0 + andi. r3,r3,MMUCSR0_TLBFI@l + bne 1b + msync + isync + blr + +/* + * Flush MMU TLB for a particular address, but only on the local processor + * (no broadcast) + */ +_GLOBAL(_tlbil_va) + mfmsr r10 + wrteei 0 + slwi r4,r4,16 + mtspr SPRN_MAS6,r4 /* assume AS=0 for now */ + tlbsx 0,r3 + mfspr r4,SPRN_MAS1 /* check valid */ + andis. r3,r4,MAS1_VALID@h + beq 1f + rlwinm r4,r4,0,1,31 + mtspr SPRN_MAS1,r4 + tlbwe + msync + isync +1: wrtee r10 + blr +#elif +#error Unsupported processor type ! +#endif diff --git a/arch/powerpc/platforms/40x/ep405.c b/arch/powerpc/platforms/40x/ep405.c index ae2e7f67c18ecc794af053472fa208000ebed328..4058fd1e7fc7df773cffe2f3a64eb3bfed34d581 100644 --- a/arch/powerpc/platforms/40x/ep405.c +++ b/arch/powerpc/platforms/40x/ep405.c @@ -100,7 +100,7 @@ static void __init ep405_setup_arch(void) /* Find & init the BCSR CPLD */ ep405_init_bcsr(); - ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC; + ppc_pci_set_flags(PPC_PCI_REASSIGN_ALL_RSRC); } static int __init ep405_probe(void) diff --git a/arch/powerpc/platforms/40x/kilauea.c b/arch/powerpc/platforms/40x/kilauea.c index 1dd24ffc0dc1d07496ac4898f748adc0b6e4ceb6..fd7d934dac8b82b6373634dd30ea4f4b11f2c937 100644 --- a/arch/powerpc/platforms/40x/kilauea.c +++ b/arch/powerpc/platforms/40x/kilauea.c @@ -44,7 +44,7 @@ static int __init kilauea_probe(void) if (!of_flat_dt_is_compatible(root, "amcc,kilauea")) return 0; - ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC; + ppc_pci_set_flags(PPC_PCI_REASSIGN_ALL_RSRC); return 1; } diff --git a/arch/powerpc/platforms/40x/ppc40x_simple.c b/arch/powerpc/platforms/40x/ppc40x_simple.c index 4498a86b46c3dfdf61f8ae393200af089487f5fe..f40ac9b8f99f5c9791148b812c5e4bb8f5494b3a 100644 --- a/arch/powerpc/platforms/40x/ppc40x_simple.c +++ b/arch/powerpc/platforms/40x/ppc40x_simple.c @@ -61,7 +61,7 @@ static int __init ppc40x_probe(void) for (i = 0; i < ARRAY_SIZE(board); i++) { if (of_flat_dt_is_compatible(root, board[i])) { - ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC; + ppc_pci_set_flags(PPC_PCI_REASSIGN_ALL_RSRC); return 1; } } diff --git a/arch/powerpc/platforms/44x/ebony.c b/arch/powerpc/platforms/44x/ebony.c index a0e8fe4662f61246ab02f8d7c668453d5ca2a676..88b9117fa691f6f4908c2eb20428c0942c514d57 100644 --- a/arch/powerpc/platforms/44x/ebony.c +++ b/arch/powerpc/platforms/44x/ebony.c @@ -54,7 +54,7 @@ static int __init ebony_probe(void) if (!of_flat_dt_is_compatible(root, "ibm,ebony")) return 0; - ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC; + ppc_pci_set_flags(PPC_PCI_REASSIGN_ALL_RSRC); return 1; } diff --git a/arch/powerpc/platforms/44x/ppc44x_simple.c b/arch/powerpc/platforms/44x/ppc44x_simple.c index 29671262801fd818d2cbcaf7b6f94d13c7b85fc7..76fdc51dac8b64091f2a9fcf6d1b51ef1c02efe5 100644 --- a/arch/powerpc/platforms/44x/ppc44x_simple.c +++ b/arch/powerpc/platforms/44x/ppc44x_simple.c @@ -69,7 +69,7 @@ static int __init ppc44x_probe(void) for (i = 0; i < ARRAY_SIZE(board); i++) { if (of_flat_dt_is_compatible(root, board[i])) { - ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC; + ppc_pci_set_flags(PPC_PCI_REASSIGN_ALL_RSRC); return 1; } } diff --git a/arch/powerpc/platforms/44x/sam440ep.c b/arch/powerpc/platforms/44x/sam440ep.c index 47f10e6477350887ae74f4ef5875fc8d4d1c34d8..a78e8eb6da41147170d66105cf210e00982d3870 100644 --- a/arch/powerpc/platforms/44x/sam440ep.c +++ b/arch/powerpc/platforms/44x/sam440ep.c @@ -51,7 +51,7 @@ static int __init sam440ep_probe(void) if (!of_flat_dt_is_compatible(root, "acube,sam440ep")) return 0; - ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC; + ppc_pci_set_flags(PPC_PCI_REASSIGN_ALL_RSRC); return 1; } diff --git a/arch/powerpc/platforms/52xx/lite5200_pm.c b/arch/powerpc/platforms/52xx/lite5200_pm.c index fe92e65103edad4851465f0a00b4615011c76676..b5c753db125e065a235c123b07d0eefff38620e2 100644 --- a/arch/powerpc/platforms/52xx/lite5200_pm.c +++ b/arch/powerpc/platforms/52xx/lite5200_pm.c @@ -3,7 +3,6 @@ #include #include #include -#include "mpc52xx_pic.h" /* defined in lite5200_sleep.S and only used here */ extern void lite5200_low_power(void __iomem *sram, void __iomem *mbar); diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.c b/arch/powerpc/platforms/52xx/mpc52xx_pci.c index b49a1852766131655a57effc2514439225ba6b9c..c3f2c21024e32d09623fbfde61e68d5420a171a5 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pci.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pci.c @@ -375,7 +375,7 @@ mpc52xx_add_bridge(struct device_node *node) pr_debug("Adding MPC52xx PCI host bridge %s\n", node->full_name); - ppc_pci_flags |= PPC_PCI_REASSIGN_ALL_BUS; + ppc_pci_add_flags(PPC_PCI_REASSIGN_ALL_BUS); if (of_address_to_resource(node, 0, &rsrc) != 0) { printk(KERN_ERR "Can't get %s resources\n", node->full_name); diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c index 8479394e9ab4cb884d6f329ec02cc233934c69c0..72865e8e4b5124b1567c4546d9cee99e499311e8 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c @@ -2,20 +2,100 @@ * * Programmable Interrupt Controller functions for the Freescale MPC52xx. * + * Copyright (C) 2008 Secret Lab Technologies Ltd. * Copyright (C) 2006 bplan GmbH + * Copyright (C) 2004 Sylvain Munaut + * Copyright (C) 2003 Montavista Software, Inc * * Based on the code from the 2.4 kernel by * Dale Farnsworth and Kent Borg. * - * Copyright (C) 2004 Sylvain Munaut - * Copyright (C) 2003 Montavista Software, Inc - * * This file is licensed under the terms of the GNU General Public License * version 2. This program is licensed "as is" without any warranty of any * kind, whether express or implied. * */ +/* + * This is the device driver for the MPC5200 interrupt controller. + * + * hardware overview + * ----------------- + * The MPC5200 interrupt controller groups the all interrupt sources into + * three groups called 'critical', 'main', and 'peripheral'. The critical + * group has 3 irqs, External IRQ0, slice timer 0 irq, and wake from deep + * sleep. Main group include the other 3 external IRQs, slice timer 1, RTC, + * gpios, and the general purpose timers. Peripheral group contains the + * remaining irq sources from all of the on-chip peripherals (PSCs, Ethernet, + * USB, DMA, etc). + * + * virqs + * ----- + * The Linux IRQ subsystem requires that each irq source be assigned a + * system wide unique IRQ number starting at 1 (0 means no irq). Since + * systems can have multiple interrupt controllers, the virtual IRQ (virq) + * infrastructure lets each interrupt controller to define a local set + * of IRQ numbers and the virq infrastructure maps those numbers into + * a unique range of the global IRQ# space. + * + * To define a range of virq numbers for this controller, this driver first + * assigns a number to each of the irq groups (called the level 1 or L1 + * value). Within each group individual irq sources are also assigned a + * number, as defined by the MPC5200 user guide, and refers to it as the + * level 2 or L2 value. The virq number is determined by shifting up the + * L1 value by MPC52xx_IRQ_L1_OFFSET and ORing it with the L2 value. + * + * For example, the TMR0 interrupt is irq 9 in the main group. The + * virq for TMR0 is calculated by ((1 << MPC52xx_IRQ_L1_OFFSET) | 9). + * + * The observant reader will also notice that this driver defines a 4th + * interrupt group called 'bestcomm'. The bestcomm group isn't physically + * part of the MPC5200 interrupt controller, but it is used here to assign + * a separate virq number for each bestcomm task (since any of the 16 + * bestcomm tasks can cause the bestcomm interrupt to be raised). When a + * bestcomm interrupt occurs (peripheral group, irq 0) this driver determines + * which task needs servicing and returns the irq number for that task. This + * allows drivers which use bestcomm to define their own interrupt handlers. + * + * irq_chip structures + * ------------------- + * For actually manipulating IRQs (masking, enabling, clearing, etc) this + * driver defines four separate 'irq_chip' structures, one for the main + * group, one for the peripherals group, one for the bestcomm group and one + * for external interrupts. The irq_chip structures provide the hooks needed + * to manipulate each IRQ source, and since each group is has a separate set + * of registers for controlling the irq, it makes sense to divide up the + * hooks along those lines. + * + * You'll notice that there is not an irq_chip for the critical group and + * you'll also notice that there is an irq_chip defined for external + * interrupts even though there is no external interrupt group. The reason + * for this is that the four external interrupts are all managed with the same + * register even though one of the external IRQs is in the critical group and + * the other three are in the main group. For this reason it makes sense for + * the 4 external irqs to be managed using a separate set of hooks. The + * reason there is no crit irq_chip is that of the 3 irqs in the critical + * group, only external interrupt is actually support at this time by this + * driver and since external interrupt is the only one used, it can just + * be directed to make use of the external irq irq_chip. + * + * device tree bindings + * -------------------- + * The device tree bindings for this controller reflect the two level + * organization of irqs in the device. #interrupt-cells = <3> where the + * first cell is the group number [0..3], the second cell is the irq + * number in the group, and the third cell is the sense type (level/edge). + * For reference, the following is a list of the interrupt property values + * associated with external interrupt sources on the MPC5200 (just because + * it is non-obvious to determine what the interrupts property should be + * when reading the mpc5200 manual and it is a frequently asked question). + * + * External interrupts: + * <0 0 n> external irq0, n is sense (n=0: level high, + * <1 1 n> external irq1, n is sense n=1: edge rising, + * <1 2 n> external irq2, n is sense n=2: edge falling, + * <1 3 n> external irq3, n is sense n=3: level low) + */ #undef DEBUG #include @@ -24,11 +104,19 @@ #include #include #include -#include "mpc52xx_pic.h" -/* - * -*/ +/* HW IRQ mapping */ +#define MPC52xx_IRQ_L1_CRIT (0) +#define MPC52xx_IRQ_L1_MAIN (1) +#define MPC52xx_IRQ_L1_PERP (2) +#define MPC52xx_IRQ_L1_SDMA (3) + +#define MPC52xx_IRQ_L1_OFFSET (6) +#define MPC52xx_IRQ_L1_MASK (0x00c0) +#define MPC52xx_IRQ_L2_MASK (0x003f) + +#define MPC52xx_IRQ_HIGHTESTHWIRQ (0xd0) + /* MPC5200 device tree match tables */ static struct of_device_id mpc52xx_pic_ids[] __initdata = { @@ -53,10 +141,7 @@ static unsigned char mpc52xx_map_senses[4] = { IRQ_TYPE_LEVEL_LOW, }; -/* - * -*/ - +/* Utility functions */ static inline void io_be_setbit(u32 __iomem *addr, int bitno) { out_be32(addr, in_be32(addr) | (1 << bitno)); @@ -69,15 +154,14 @@ static inline void io_be_clrbit(u32 __iomem *addr, int bitno) /* * IRQ[0-3] interrupt irq_chip -*/ - + */ static void mpc52xx_extirq_mask(unsigned int virq) { int irq; int l2irq; irq = irq_map[virq].hwirq; - l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; + l2irq = irq & MPC52xx_IRQ_L2_MASK; pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); @@ -90,7 +174,7 @@ static void mpc52xx_extirq_unmask(unsigned int virq) int l2irq; irq = irq_map[virq].hwirq; - l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; + l2irq = irq & MPC52xx_IRQ_L2_MASK; pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); @@ -103,7 +187,7 @@ static void mpc52xx_extirq_ack(unsigned int virq) int l2irq; irq = irq_map[virq].hwirq; - l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; + l2irq = irq & MPC52xx_IRQ_L2_MASK; pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); @@ -117,7 +201,7 @@ static int mpc52xx_extirq_set_type(unsigned int virq, unsigned int flow_type) int l2irq; irq = irq_map[virq].hwirq; - l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; + l2irq = irq & MPC52xx_IRQ_L2_MASK; pr_debug("%s: irq=%x. l2=%d flow_type=%d\n", __func__, irq, l2irq, flow_type); @@ -156,15 +240,14 @@ static struct irq_chip mpc52xx_extirq_irqchip = { /* * Main interrupt irq_chip -*/ - + */ static void mpc52xx_main_mask(unsigned int virq) { int irq; int l2irq; irq = irq_map[virq].hwirq; - l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; + l2irq = irq & MPC52xx_IRQ_L2_MASK; pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); @@ -177,7 +260,7 @@ static void mpc52xx_main_unmask(unsigned int virq) int l2irq; irq = irq_map[virq].hwirq; - l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; + l2irq = irq & MPC52xx_IRQ_L2_MASK; pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); @@ -193,15 +276,14 @@ static struct irq_chip mpc52xx_main_irqchip = { /* * Peripherals interrupt irq_chip -*/ - + */ static void mpc52xx_periph_mask(unsigned int virq) { int irq; int l2irq; irq = irq_map[virq].hwirq; - l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; + l2irq = irq & MPC52xx_IRQ_L2_MASK; pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); @@ -214,7 +296,7 @@ static void mpc52xx_periph_unmask(unsigned int virq) int l2irq; irq = irq_map[virq].hwirq; - l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; + l2irq = irq & MPC52xx_IRQ_L2_MASK; pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); @@ -230,15 +312,14 @@ static struct irq_chip mpc52xx_periph_irqchip = { /* * SDMA interrupt irq_chip -*/ - + */ static void mpc52xx_sdma_mask(unsigned int virq) { int irq; int l2irq; irq = irq_map[virq].hwirq; - l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; + l2irq = irq & MPC52xx_IRQ_L2_MASK; pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); @@ -251,7 +332,7 @@ static void mpc52xx_sdma_unmask(unsigned int virq) int l2irq; irq = irq_map[virq].hwirq; - l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; + l2irq = irq & MPC52xx_IRQ_L2_MASK; pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); @@ -264,7 +345,7 @@ static void mpc52xx_sdma_ack(unsigned int virq) int l2irq; irq = irq_map[virq].hwirq; - l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; + l2irq = irq & MPC52xx_IRQ_L2_MASK; pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); @@ -278,13 +359,12 @@ static struct irq_chip mpc52xx_sdma_irqchip = { .ack = mpc52xx_sdma_ack, }; -/* - * irq_host -*/ - +/** + * mpc52xx_irqhost_xlate - translate virq# from device tree interrupts property + */ static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct, - u32 * intspec, unsigned int intsize, - irq_hw_number_t * out_hwirq, + u32 *intspec, unsigned int intsize, + irq_hw_number_t *out_hwirq, unsigned int *out_flags) { int intrvect_l1; @@ -299,10 +379,9 @@ static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct, intrvect_l2 = (int)intspec[1]; intrvect_type = (int)intspec[2]; - intrvect_linux = - (intrvect_l1 << MPC52xx_IRQ_L1_OFFSET) & MPC52xx_IRQ_L1_MASK; - intrvect_linux |= - (intrvect_l2 << MPC52xx_IRQ_L2_OFFSET) & MPC52xx_IRQ_L2_MASK; + intrvect_linux = (intrvect_l1 << MPC52xx_IRQ_L1_OFFSET) & + MPC52xx_IRQ_L1_MASK; + intrvect_linux |= intrvect_l2 & MPC52xx_IRQ_L2_MASK; pr_debug("return %x, l1=%d, l2=%d\n", intrvect_linux, intrvect_l1, intrvect_l2); @@ -313,11 +392,11 @@ static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct, return 0; } -/* - * this function retrieves the correct IRQ type out - * of the MPC regs - * Only externals IRQs needs this -*/ +/** + * mpc52xx_irqx_gettype - determine the IRQ sense type (level/edge) + * + * Only external IRQs need this. + */ static int mpc52xx_irqx_gettype(int irq) { int type; @@ -329,6 +408,9 @@ static int mpc52xx_irqx_gettype(int irq) return mpc52xx_map_senses[type]; } +/** + * mpc52xx_irqhost_map - Hook to map from virq to an irq_chip structure + */ static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq, irq_hw_number_t irq) { @@ -339,7 +421,7 @@ static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq, int type; l1irq = (irq & MPC52xx_IRQ_L1_MASK) >> MPC52xx_IRQ_L1_OFFSET; - l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; + l2irq = irq & MPC52xx_IRQ_L2_MASK; /* * Most of ours IRQs will be level low @@ -379,8 +461,7 @@ static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq, break; default: - pr_debug("%s: Error, unknown L1 IRQ (0x%x)\n", __func__, l1irq); - printk(KERN_ERR "Unknow IRQ!\n"); + pr_err("%s: invalid virq requested (0x%x)\n", __func__, virq); return -EINVAL; } @@ -406,10 +487,15 @@ static struct irq_host_ops mpc52xx_irqhost_ops = { .map = mpc52xx_irqhost_map, }; -/* - * init (public) -*/ - +/** + * mpc52xx_init_irq - Initialize and register with the virq subsystem + * + * Hook for setting up IRQs on an mpc5200 system. A pointer to this function + * is to be put into the machine definition structure. + * + * This function searches the device tree for an MPC5200 interrupt controller, + * initializes it, and registers it with the virq subsystem. + */ void __init mpc52xx_init_irq(void) { u32 intr_ctrl; @@ -454,7 +540,6 @@ void __init mpc52xx_init_irq(void) * As last step, add an irq host to translate the real * hw irq information provided by the ofw to linux virq */ - mpc52xx_irqhost = irq_alloc_host(picnode, IRQ_HOST_MAP_LINEAR, MPC52xx_IRQ_HIGHTESTHWIRQ, &mpc52xx_irqhost_ops, -1); @@ -462,12 +547,38 @@ void __init mpc52xx_init_irq(void) if (!mpc52xx_irqhost) panic(__FILE__ ": Cannot allocate the IRQ host\n"); - printk(KERN_INFO "MPC52xx PIC is up and running!\n"); + irq_set_default_host(mpc52xx_irqhost); + + pr_info("MPC52xx PIC is up and running!\n"); } -/* - * get_irq (public) -*/ +/** + * mpc52xx_get_irq - Get pending interrupt number hook function + * + * Called by the interupt handler to determine what IRQ handler needs to be + * executed. + * + * Status of pending interrupts is determined by reading the encoded status + * register. The encoded status register has three fields; one for each of the + * types of interrupts defined by the controller - 'critical', 'main' and + * 'peripheral'. This function reads the status register and returns the IRQ + * number associated with the highest priority pending interrupt. 'Critical' + * interrupts have the highest priority, followed by 'main' interrupts, and + * then 'peripheral'. + * + * The mpc5200 interrupt controller can be configured to boost the priority + * of individual 'peripheral' interrupts. If this is the case then a special + * value will appear in either the crit or main fields indicating a high + * or medium priority peripheral irq has occurred. + * + * This function checks each of the 3 irq request fields and returns the + * first pending interrupt that it finds. + * + * This function also identifies a 4th type of interrupt; 'bestcomm'. Each + * bestcomm DMA task can raise the bestcomm peripheral interrupt. When this + * occurs at task-specific IRQ# is decoded so that each task can have its + * own IRQ handler. + */ unsigned int mpc52xx_get_irq(void) { u32 status; @@ -478,25 +589,21 @@ unsigned int mpc52xx_get_irq(void) irq = (status >> 8) & 0x3; if (irq == 2) /* high priority peripheral */ goto peripheral; - irq |= (MPC52xx_IRQ_L1_CRIT << MPC52xx_IRQ_L1_OFFSET) & - MPC52xx_IRQ_L1_MASK; + irq |= (MPC52xx_IRQ_L1_CRIT << MPC52xx_IRQ_L1_OFFSET); } else if (status & 0x00200000) { /* main */ irq = (status >> 16) & 0x1f; if (irq == 4) /* low priority peripheral */ goto peripheral; - irq |= (MPC52xx_IRQ_L1_MAIN << MPC52xx_IRQ_L1_OFFSET) & - MPC52xx_IRQ_L1_MASK; + irq |= (MPC52xx_IRQ_L1_MAIN << MPC52xx_IRQ_L1_OFFSET); } else if (status & 0x20000000) { /* peripheral */ peripheral: irq = (status >> 24) & 0x1f; if (irq == 0) { /* bestcomm */ status = in_be32(&sdma->IntPend); irq = ffs(status) - 1; - irq |= (MPC52xx_IRQ_L1_SDMA << MPC52xx_IRQ_L1_OFFSET) & - MPC52xx_IRQ_L1_MASK; + irq |= (MPC52xx_IRQ_L1_SDMA << MPC52xx_IRQ_L1_OFFSET); } else { - irq |= (MPC52xx_IRQ_L1_PERP << MPC52xx_IRQ_L1_OFFSET) & - MPC52xx_IRQ_L1_MASK; + irq |= (MPC52xx_IRQ_L1_PERP << MPC52xx_IRQ_L1_OFFSET); } } diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.h b/arch/powerpc/platforms/52xx/mpc52xx_pic.h deleted file mode 100644 index 1a26bcdb30495b6cca4423ee10369916d467e817..0000000000000000000000000000000000000000 --- a/arch/powerpc/platforms/52xx/mpc52xx_pic.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Header file for Freescale MPC52xx Interrupt controller - * - * Copyright (C) 2004-2005 Sylvain Munaut - * Copyright (C) 2003 MontaVista, Software, Inc. - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ - -#ifndef __POWERPC_SYSDEV_MPC52xx_PIC_H__ -#define __POWERPC_SYSDEV_MPC52xx_PIC_H__ - -#include - - -/* HW IRQ mapping */ -#define MPC52xx_IRQ_L1_CRIT (0) -#define MPC52xx_IRQ_L1_MAIN (1) -#define MPC52xx_IRQ_L1_PERP (2) -#define MPC52xx_IRQ_L1_SDMA (3) - -#define MPC52xx_IRQ_L1_OFFSET (6) -#define MPC52xx_IRQ_L1_MASK (0x00c0) - -#define MPC52xx_IRQ_L2_OFFSET (0) -#define MPC52xx_IRQ_L2_MASK (0x003f) - -#define MPC52xx_IRQ_HIGHTESTHWIRQ (0xd0) - - -/* Interrupt controller Register set */ -struct mpc52xx_intr { - u32 per_mask; /* INTR + 0x00 */ - u32 per_pri1; /* INTR + 0x04 */ - u32 per_pri2; /* INTR + 0x08 */ - u32 per_pri3; /* INTR + 0x0c */ - u32 ctrl; /* INTR + 0x10 */ - u32 main_mask; /* INTR + 0x14 */ - u32 main_pri1; /* INTR + 0x18 */ - u32 main_pri2; /* INTR + 0x1c */ - u32 reserved1; /* INTR + 0x20 */ - u32 enc_status; /* INTR + 0x24 */ - u32 crit_status; /* INTR + 0x28 */ - u32 main_status; /* INTR + 0x2c */ - u32 per_status; /* INTR + 0x30 */ - u32 reserved2; /* INTR + 0x34 */ - u32 per_error; /* INTR + 0x38 */ -}; - -#endif /* __POWERPC_SYSDEV_MPC52xx_PIC_H__ */ - diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pm.c b/arch/powerpc/platforms/52xx/mpc52xx_pm.c index c72d3304387ffb8ca692f91d369cc32014105089..a55b0b6813ed2a9f249a2051e861176e572a6d59 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pm.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pm.c @@ -5,9 +5,6 @@ #include #include -#include "mpc52xx_pic.h" - - /* these are defined in mpc52xx_sleep.S, and only used here */ extern void mpc52xx_deep_sleep(void __iomem *sram, void __iomem *sdram_regs, struct mpc52xx_cdm __iomem *, struct mpc52xx_intr __iomem*); diff --git a/arch/powerpc/platforms/82xx/pq2.c b/arch/powerpc/platforms/82xx/pq2.c index 1b75902fad64a9a848e0bd4050c3a01345021c80..9761a59f175fa3bf01b616b576310989a7f7bb3f 100644 --- a/arch/powerpc/platforms/82xx/pq2.c +++ b/arch/powerpc/platforms/82xx/pq2.c @@ -53,7 +53,7 @@ static void __init pq2_pci_add_bridge(struct device_node *np) if (of_address_to_resource(np, 0, &r) || r.end - r.start < 0x10b) goto err; - ppc_pci_flags |= PPC_PCI_REASSIGN_ALL_BUS; + ppc_pci_add_flags(PPC_PCI_REASSIGN_ALL_BUS); hose = pcibios_alloc_controller(np); if (!hose) diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index cb3054e1001d406661c8e6791e668b5f082494db..f0798c09980fe340e3431bc70e226fa67c9dc128 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile @@ -1,6 +1,8 @@ # # Makefile for the PowerPC 85xx linux kernel. # +obj-$(CONFIG_SMP) += smp.o + obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads.o obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads.o obj-$(CONFIG_MPC85xx_CDS) += mpc85xx_cds.o diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ds.c b/arch/powerpc/platforms/85xx/mpc85xx_ds.c index 613bf8c2e30d988b3fac38c2f0297a944551a46f..a8301c8ad5376bb6487f7f968de2f70a3565f91a 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ds.c @@ -63,6 +63,7 @@ void __init mpc85xx_ds_pic_init(void) struct device_node *cascade_node = NULL; int cascade_irq; #endif + unsigned long root = of_get_flat_dt_root(); np = of_find_node_by_type(NULL, "open-pic"); if (np == NULL) { @@ -76,11 +77,19 @@ void __init mpc85xx_ds_pic_init(void) return; } - mpic = mpic_alloc(np, r.start, + if (of_flat_dt_is_compatible(root, "fsl,MPC8572DS-CAMP")) { + mpic = mpic_alloc(np, r.start, + MPIC_PRIMARY | + MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS, + 0, 256, " OpenPIC "); + } else { + mpic = mpic_alloc(np, r.start, MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU, 0, 256, " OpenPIC "); + } + BUG_ON(mpic == NULL); of_node_put(np); diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index 2494c5155919af7114d695621a2dc78d24c3e111..658a36fab3ab8a44c9963d5c6512b8e7d20d437a 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c @@ -231,7 +231,7 @@ static void __init mpc85xx_mds_setup_arch(void) static int __init board_fixups(void) { - char phy_id[BUS_ID_SIZE]; + char phy_id[20]; char *compstrs[2] = {"fsl,gianfar-mdio", "fsl,ucc-mdio"}; struct device_node *mdio; struct resource res; @@ -241,13 +241,15 @@ static int __init board_fixups(void) mdio = of_find_compatible_node(NULL, NULL, compstrs[i]); of_address_to_resource(mdio, 0, &res); - snprintf(phy_id, BUS_ID_SIZE, "%x:%02x", res.start, 1); + snprintf(phy_id, sizeof(phy_id), "%llx:%02x", + (unsigned long long)res.start, 1); phy_register_fixup_for_id(phy_id, mpc8568_fixup_125_clock); phy_register_fixup_for_id(phy_id, mpc8568_mds_phy_fixups); /* Register a workaround for errata */ - snprintf(phy_id, BUS_ID_SIZE, "%x:%02x", res.start, 7); + snprintf(phy_id, sizeof(phy_id), "%llx:%02x", + (unsigned long long)res.start, 7); phy_register_fixup_for_id(phy_id, mpc8568_mds_phy_fixups); of_node_put(mdio); diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c new file mode 100644 index 0000000000000000000000000000000000000000..d652c713f496040f1011d87be69351866bd2140f --- /dev/null +++ b/arch/powerpc/platforms/85xx/smp.c @@ -0,0 +1,104 @@ +/* + * Author: Andy Fleming + * Kumar Gala + * + * Copyright 2006-2008 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +extern volatile unsigned long __secondary_hold_acknowledge; +extern void __early_start(void); + +#define BOOT_ENTRY_ADDR_UPPER 0 +#define BOOT_ENTRY_ADDR_LOWER 1 +#define BOOT_ENTRY_R3_UPPER 2 +#define BOOT_ENTRY_R3_LOWER 3 +#define BOOT_ENTRY_RESV 4 +#define BOOT_ENTRY_PIR 5 +#define BOOT_ENTRY_R6_UPPER 6 +#define BOOT_ENTRY_R6_LOWER 7 +#define NUM_BOOT_ENTRY 8 +#define SIZE_BOOT_ENTRY (NUM_BOOT_ENTRY * sizeof(u32)) + +static void __init +smp_85xx_kick_cpu(int nr) +{ + unsigned long flags; + const u64 *cpu_rel_addr; + __iomem u32 *bptr_vaddr; + struct device_node *np; + int n = 0; + + WARN_ON (nr < 0 || nr >= NR_CPUS); + + pr_debug("smp_85xx_kick_cpu: kick CPU #%d\n", nr); + + local_irq_save(flags); + + np = of_get_cpu_node(nr, NULL); + cpu_rel_addr = of_get_property(np, "cpu-release-addr", NULL); + + if (cpu_rel_addr == NULL) { + printk(KERN_ERR "No cpu-release-addr for cpu %d\n", nr); + return; + } + + /* Map the spin table */ + bptr_vaddr = ioremap(*cpu_rel_addr, SIZE_BOOT_ENTRY); + + out_be32(bptr_vaddr + BOOT_ENTRY_PIR, nr); + out_be32(bptr_vaddr + BOOT_ENTRY_ADDR_LOWER, __pa(__early_start)); + + /* Wait a bit for the CPU to ack. */ + while ((__secondary_hold_acknowledge != nr) && (++n < 1000)) + mdelay(1); + + iounmap(bptr_vaddr); + + local_irq_restore(flags); + + pr_debug("waited %d msecs for CPU #%d.\n", n, nr); +} + +static void __init +smp_85xx_setup_cpu(int cpu_nr) +{ + mpic_setup_this_cpu(); + + /* Clear any pending timer interrupts */ + mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS); + + /* Enable decrementer interrupt */ + mtspr(SPRN_TCR, TCR_DIE); +} + +struct smp_ops_t smp_85xx_ops = { + .message_pass = smp_mpic_message_pass, + .probe = smp_mpic_probe, + .kick_cpu = smp_85xx_kick_cpu, + .setup_cpu = smp_85xx_setup_cpu, +}; + +void __init +mpc85xx_smp_init(void) +{ + smp_ops = &smp_85xx_ops; +} diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig index 77dd797a2580e73f90dce98b08a20d1ed5313b75..8e5693935975f27cf4c4addb308c9f6e28c0f592 100644 --- a/arch/powerpc/platforms/86xx/Kconfig +++ b/arch/powerpc/platforms/86xx/Kconfig @@ -34,6 +34,8 @@ config MPC8610_HPCD config GEF_SBC610 bool "GE Fanuc SBC610" select DEFAULT_UIMAGE + select GENERIC_GPIO + select ARCH_REQUIRE_GPIOLIB select HAS_RAPIDIO help This option enables support for GE Fanuc's SBC610. diff --git a/arch/powerpc/platforms/86xx/Makefile b/arch/powerpc/platforms/86xx/Makefile index 4a56ff619afdee7fc649c4e17203d73104f6d521..31e540c2ebbc559a7a790a3edc6ca078d57c951c 100644 --- a/arch/powerpc/platforms/86xx/Makefile +++ b/arch/powerpc/platforms/86xx/Makefile @@ -7,4 +7,5 @@ obj-$(CONFIG_SMP) += mpc86xx_smp.o obj-$(CONFIG_MPC8641_HPCN) += mpc86xx_hpcn.o obj-$(CONFIG_SBC8641D) += sbc8641d.o obj-$(CONFIG_MPC8610_HPCD) += mpc8610_hpcd.o -obj-$(CONFIG_GEF_SBC610) += gef_sbc610.o gef_pic.o +gef-gpio-$(CONFIG_GPIOLIB) += gef_gpio.o +obj-$(CONFIG_GEF_SBC610) += gef_sbc610.o gef_pic.o $(gef-gpio-y) diff --git a/arch/powerpc/platforms/86xx/gef_gpio.c b/arch/powerpc/platforms/86xx/gef_gpio.c new file mode 100644 index 0000000000000000000000000000000000000000..85b2800f4cb71b18ec622805a98fa29c180c7355 --- /dev/null +++ b/arch/powerpc/platforms/86xx/gef_gpio.c @@ -0,0 +1,143 @@ +/* + * Driver for GE Fanuc's FPGA based GPIO pins + * + * Author: Martyn Welch + * + * 2008 (c) GE Fanuc Intelligent Platforms Embedded Systems, Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +/* TODO + * + * Configuration of output modes (totem-pole/open-drain) + * Interrupt configuration - interrupts are always generated the FPGA relies on + * the I/O interrupt controllers mask to stop them propergating + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GEF_GPIO_DIRECT 0x00 +#define GEF_GPIO_IN 0x04 +#define GEF_GPIO_OUT 0x08 +#define GEF_GPIO_TRIG 0x0C +#define GEF_GPIO_POLAR_A 0x10 +#define GEF_GPIO_POLAR_B 0x14 +#define GEF_GPIO_INT_STAT 0x18 +#define GEF_GPIO_OVERRUN 0x1C +#define GEF_GPIO_MODE 0x20 + +#define NUM_GPIO 19 + +static void _gef_gpio_set(void __iomem *reg, unsigned int offset, int value) +{ + unsigned int data; + + data = ioread32be(reg); + /* value: 0=low; 1=high */ + if (value & 0x1) + data = data | (0x1 << offset); + else + data = data & ~(0x1 << offset); + + iowrite32be(data, reg); +} + + +static int gef_gpio_dir_in(struct gpio_chip *chip, unsigned offset) +{ + unsigned int data; + struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); + + data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT); + data = data | (0x1 << offset); + iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT); + + return 0; +} + +static int gef_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int value) +{ + unsigned int data; + struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); + + /* Set direction before switching to input */ + _gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value); + + data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT); + data = data & ~(0x1 << offset); + iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT); + + return 0; +} + +static int gef_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + unsigned int data; + int state = 0; + struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); + + data = ioread32be(mmchip->regs + GEF_GPIO_IN); + state = (int)((data >> offset) & 0x1); + + return state; +} + +static void gef_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); + + _gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value); +} + +static int __init gef_gpio_init(void) +{ + struct device_node *np; + + for_each_compatible_node(np, NULL, "gef,sbc610-gpio") { + int retval; + struct of_mm_gpio_chip *gef_gpio_chip; + + pr_debug("%s: Initialising GEF GPIO\n", np->full_name); + + /* Allocate chip structure */ + gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL); + if (!gef_gpio_chip) { + pr_err("%s: Unable to allocate structure\n", + np->full_name); + continue; + } + + /* Setup pointers to chip functions */ + gef_gpio_chip->of_gc.gpio_cells = 2; + gef_gpio_chip->of_gc.gc.ngpio = NUM_GPIO; + gef_gpio_chip->of_gc.gc.direction_input = gef_gpio_dir_in; + gef_gpio_chip->of_gc.gc.direction_output = gef_gpio_dir_out; + gef_gpio_chip->of_gc.gc.get = gef_gpio_get; + gef_gpio_chip->of_gc.gc.set = gef_gpio_set; + + /* This function adds a memory mapped GPIO chip */ + retval = of_mm_gpiochip_add(np, gef_gpio_chip); + if (retval) { + kfree(gef_gpio_chip); + pr_err("%s: Unable to add GPIO\n", np->full_name); + } + } + + return 0; +}; +arch_initcall(gef_gpio_init); + +MODULE_DESCRIPTION("GE Fanuc I/O FPGA GPIO driver"); +MODULE_AUTHOR("Martyn Welch #include #include -#include #include #include #include @@ -226,9 +225,6 @@ define_machine(celleb_beat) { .pci_setup_phb = celleb_setup_phb, #ifdef CONFIG_KEXEC .kexec_cpu_down = beat_kexec_cpu_down, - .machine_kexec = default_machine_kexec, - .machine_kexec_prepare = default_machine_kexec_prepare, - .machine_crash_shutdown = default_machine_crash_shutdown, #endif }; @@ -248,9 +244,4 @@ define_machine(celleb_native) { .pci_probe_mode = celleb_pci_probe_mode, .pci_setup_phb = celleb_setup_phb, .init_IRQ = celleb_init_IRQ_native, -#ifdef CONFIG_KEXEC - .machine_kexec = default_machine_kexec, - .machine_kexec_prepare = default_machine_kexec_prepare, - .machine_crash_shutdown = default_machine_crash_shutdown, -#endif }; diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c index 3168272ab0d791cf750606ced53c560699ad90c9..86db4dd170a0e42d89e26e0f7d20c7f388bf355d 100644 --- a/arch/powerpc/platforms/cell/iommu.c +++ b/arch/powerpc/platforms/cell/iommu.c @@ -1053,10 +1053,7 @@ static int __init cell_iommu_fixed_mapping_init(void) } /* We must have dma-ranges properties for fixed mapping to work */ - for (np = NULL; (np = of_find_all_nodes(np));) { - if (of_find_property(np, "dma-ranges", NULL)) - break; - } + np = of_find_node_with_property(NULL, "dma-ranges"); of_node_put(np); if (!np) { diff --git a/arch/powerpc/platforms/cell/qpace_setup.c b/arch/powerpc/platforms/cell/qpace_setup.c new file mode 100644 index 0000000000000000000000000000000000000000..be84e6a16b30cf36b170c7cc39834f7412cc85d2 --- /dev/null +++ b/arch/powerpc/platforms/cell/qpace_setup.c @@ -0,0 +1,152 @@ +/* + * linux/arch/powerpc/platforms/cell/qpace_setup.c + * + * Copyright (C) 1995 Linus Torvalds + * Adapted from 'alpha' version by Gary Thomas + * Modified by Cort Dougan (cort@cs.nmt.edu) + * Modified by PPC64 Team, IBM Corp + * Modified by Cell Team, IBM Deutschland Entwicklung GmbH + * Modified by Benjamin Krill , IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "interrupt.h" +#include "pervasive.h" +#include "ras.h" +#include "io-workarounds.h" + +static void qpace_show_cpuinfo(struct seq_file *m) +{ + struct device_node *root; + const char *model = ""; + + root = of_find_node_by_path("/"); + if (root) + model = of_get_property(root, "model", NULL); + seq_printf(m, "machine\t\t: CHRP %s\n", model); + of_node_put(root); +} + +static void qpace_progress(char *s, unsigned short hex) +{ + printk("*** %04x : %s\n", hex, s ? s : ""); +} + +static int __init qpace_publish_devices(void) +{ + int node; + + /* Publish OF platform devices for southbridge IOs */ + of_platform_bus_probe(NULL, NULL, NULL); + + /* There is no device for the MIC memory controller, thus we create + * a platform device for it to attach the EDAC driver to. + */ + for_each_online_node(node) { + if (cbe_get_cpu_mic_tm_regs(cbe_node_to_cpu(node)) == NULL) + continue; + platform_device_register_simple("cbe-mic", node, NULL, 0); + } + + return 0; +} +machine_subsys_initcall(qpace, qpace_publish_devices); + +extern int qpace_notify(struct device *dev) +{ + /* set dma_ops for of_platform bus */ + if (dev->bus && dev->bus->name + && !strcmp(dev->bus->name, "of_platform")) + set_dma_ops(dev, &dma_direct_ops); + + return 0; +} + +static void __init qpace_setup_arch(void) +{ +#ifdef CONFIG_SPU_BASE + spu_priv1_ops = &spu_priv1_mmio_ops; + spu_management_ops = &spu_management_of_ops; +#endif + + cbe_regs_init(); + +#ifdef CONFIG_CBE_RAS + cbe_ras_init(); +#endif + +#ifdef CONFIG_SMP + smp_init_cell(); +#endif + + /* init to some ~sane value until calibrate_delay() runs */ + loops_per_jiffy = 50000000; + + cbe_pervasive_init(); +#ifdef CONFIG_DUMMY_CONSOLE + conswitchp = &dummy_con; +#endif + + /* set notifier function */ + platform_notify = &qpace_notify; +} + +static int __init qpace_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (!of_flat_dt_is_compatible(root, "IBM,QPACE")) + return 0; + + hpte_init_native(); + + return 1; +} + +define_machine(qpace) { + .name = "QPACE", + .probe = qpace_probe, + .setup_arch = qpace_setup_arch, + .show_cpuinfo = qpace_show_cpuinfo, + .restart = rtas_restart, + .power_off = rtas_power_off, + .halt = rtas_halt, + .get_boot_time = rtas_get_boot_time, + .calibrate_decr = generic_calibrate_decr, + .progress = qpace_progress, + .init_IRQ = iic_init_IRQ, +#ifdef CONFIG_KEXEC + .machine_kexec = default_machine_kexec, + .machine_kexec_prepare = default_machine_kexec_prepare, + .machine_crash_shutdown = default_machine_crash_shutdown, +#endif +}; diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c index ab721b50fbba15129e3037e10532e8ca47b6a2e8..59305369f6b232bb262521a6abe7cd8c3e2f35d6 100644 --- a/arch/powerpc/platforms/cell/setup.c +++ b/arch/powerpc/platforms/cell/setup.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include @@ -289,9 +288,4 @@ define_machine(cell) { .progress = cell_progress, .init_IRQ = cell_init_irq, .pci_setup_phb = cell_setup_phb, -#ifdef CONFIG_KEXEC - .machine_kexec = default_machine_kexec, - .machine_kexec_prepare = default_machine_kexec_prepare, - .machine_crash_shutdown = default_machine_crash_shutdown, -#endif }; diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 1b26071a86ca8f17e1f2c04f22ffb9d60d13e2b8..7106b63d401bce3dbe5f3681c293a845f54c190c 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -273,12 +273,10 @@ spufs_mem_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) return VM_FAULT_NOPAGE; if (ctx->state == SPU_STATE_SAVED) { - vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) - & ~_PAGE_NO_CACHE); + vma->vm_page_prot = pgprot_cached(vma->vm_page_prot); pfn = vmalloc_to_pfn(ctx->csa.lscsa->ls + offset); } else { - vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) - | _PAGE_NO_CACHE); + vma->vm_page_prot = pgprot_noncached_wc(vma->vm_page_prot); pfn = (ctx->spu->local_store_phys + offset) >> PAGE_SHIFT; } vm_insert_pfn(vma, address, pfn); @@ -338,8 +336,7 @@ static int spufs_mem_mmap(struct file *file, struct vm_area_struct *vma) return -EINVAL; vma->vm_flags |= VM_IO | VM_PFNMAP; - vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) - | _PAGE_NO_CACHE); + vma->vm_page_prot = pgprot_noncached_wc(vma->vm_page_prot); vma->vm_ops = &spufs_mem_mmap_vmops; return 0; @@ -452,8 +449,7 @@ static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma) return -EINVAL; vma->vm_flags |= VM_IO | VM_PFNMAP; - vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) - | _PAGE_NO_CACHE | _PAGE_GUARDED); + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); vma->vm_ops = &spufs_cntl_mmap_vmops; return 0; @@ -1155,8 +1151,7 @@ static int spufs_signal1_mmap(struct file *file, struct vm_area_struct *vma) return -EINVAL; vma->vm_flags |= VM_IO | VM_PFNMAP; - vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) - | _PAGE_NO_CACHE | _PAGE_GUARDED); + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); vma->vm_ops = &spufs_signal1_mmap_vmops; return 0; @@ -1292,8 +1287,7 @@ static int spufs_signal2_mmap(struct file *file, struct vm_area_struct *vma) return -EINVAL; vma->vm_flags |= VM_IO | VM_PFNMAP; - vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) - | _PAGE_NO_CACHE | _PAGE_GUARDED); + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); vma->vm_ops = &spufs_signal2_mmap_vmops; return 0; @@ -1414,8 +1408,7 @@ static int spufs_mss_mmap(struct file *file, struct vm_area_struct *vma) return -EINVAL; vma->vm_flags |= VM_IO | VM_PFNMAP; - vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) - | _PAGE_NO_CACHE | _PAGE_GUARDED); + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); vma->vm_ops = &spufs_mss_mmap_vmops; return 0; @@ -1476,8 +1469,7 @@ static int spufs_psmap_mmap(struct file *file, struct vm_area_struct *vma) return -EINVAL; vma->vm_flags |= VM_IO | VM_PFNMAP; - vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) - | _PAGE_NO_CACHE | _PAGE_GUARDED); + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); vma->vm_ops = &spufs_psmap_mmap_vmops; return 0; @@ -1536,8 +1528,7 @@ static int spufs_mfc_mmap(struct file *file, struct vm_area_struct *vma) return -EINVAL; vma->vm_flags |= VM_IO | VM_PFNMAP; - vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) - | _PAGE_NO_CACHE | _PAGE_GUARDED); + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); vma->vm_ops = &spufs_mfc_mmap_vmops; return 0; diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index cb85d237e492b7156745acc396f308fd99068a34..6296bfd9cb0b5646ce7b1cd8d195041f8ed239bf 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -95,8 +95,8 @@ spufs_new_inode(struct super_block *sb, int mode) goto out; inode->i_mode = mode; - inode->i_uid = current->fsuid; - inode->i_gid = current->fsgid; + inode->i_uid = current_fsuid(); + inode->i_gid = current_fsgid(); inode->i_blocks = 0; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; out: @@ -323,7 +323,7 @@ static int spufs_context_open(struct dentry *dentry, struct vfsmount *mnt) goto out; } - filp = dentry_open(dentry, mnt, O_RDONLY); + filp = dentry_open(dentry, mnt, O_RDONLY, current_cred()); if (IS_ERR(filp)) { put_unused_fd(ret); ret = PTR_ERR(filp); @@ -562,7 +562,7 @@ static int spufs_gang_open(struct dentry *dentry, struct vfsmount *mnt) goto out; } - filp = dentry_open(dentry, mnt, O_RDONLY); + filp = dentry_open(dentry, mnt, O_RDONLY, current_cred()); if (IS_ERR(filp)) { put_unused_fd(ret); ret = PTR_ERR(filp); diff --git a/arch/powerpc/platforms/chrp/pci.c b/arch/powerpc/platforms/chrp/pci.c index d3cde6b9d2df68046eaa41512676ed50fea78c66..f6b0c519d5a2b76e8d05f0df51600f9b9abba21e 100644 --- a/arch/powerpc/platforms/chrp/pci.c +++ b/arch/powerpc/platforms/chrp/pci.c @@ -141,6 +141,7 @@ hydra_init(void) of_node_put(np); return 0; } + of_node_put(np); Hydra = ioremap(r.start, r.end-r.start); printk("Hydra Mac I/O at %llx\n", (unsigned long long)r.start); printk("Hydra Feature_Control was %x", @@ -198,7 +199,7 @@ static void __init setup_peg2(struct pci_controller *hose, struct device_node *d printk ("RTAS supporting Pegasos OF not found, please upgrade" " your firmware\n"); } - ppc_pci_flags |= PPC_PCI_REASSIGN_ALL_BUS; + ppc_pci_add_flags(PPC_PCI_REASSIGN_ALL_BUS); /* keep the reference to the root node */ } diff --git a/arch/powerpc/platforms/embedded6xx/c2k.c b/arch/powerpc/platforms/embedded6xx/c2k.c index 32ba0fa0ad032fcac7b06d62f4bc87b99537acb9..8cab5731850f4f9a7a8fad46fb408725c5fffcee 100644 --- a/arch/powerpc/platforms/embedded6xx/c2k.c +++ b/arch/powerpc/platforms/embedded6xx/c2k.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include @@ -147,9 +146,4 @@ define_machine(c2k) { .get_irq = mv64x60_get_irq, .restart = c2k_restart, .calibrate_decr = generic_calibrate_decr, -#ifdef CONFIG_KEXEC - .machine_kexec = default_machine_kexec, - .machine_kexec_prepare = default_machine_kexec_prepare, - .machine_crash_shutdown = default_machine_crash_shutdown, -#endif }; diff --git a/arch/powerpc/platforms/embedded6xx/prpmc2800.c b/arch/powerpc/platforms/embedded6xx/prpmc2800.c index 4c485e984236d57ed2ae012efbe3ca55df9dad55..670035f49a6959c72af1b59ad800eab3edf631c6 100644 --- a/arch/powerpc/platforms/embedded6xx/prpmc2800.c +++ b/arch/powerpc/platforms/embedded6xx/prpmc2800.c @@ -19,7 +19,6 @@ #include #include #include -#include #include @@ -155,9 +154,4 @@ define_machine(prpmc2800){ .get_irq = mv64x60_get_irq, .restart = prpmc2800_restart, .calibrate_decr = generic_calibrate_decr, -#ifdef CONFIG_KEXEC - .machine_kexec = default_machine_kexec, - .machine_kexec_prepare = default_machine_kexec_prepare, - .machine_crash_shutdown = default_machine_crash_shutdown, -#endif }; diff --git a/arch/powerpc/platforms/iseries/Kconfig b/arch/powerpc/platforms/iseries/Kconfig index 45ffd8e542f4b79757dba792031cbe7d8295a704..ed3753d8c1090b5108fd792844b0e91835135be0 100644 --- a/arch/powerpc/platforms/iseries/Kconfig +++ b/arch/powerpc/platforms/iseries/Kconfig @@ -9,6 +9,7 @@ menu "iSeries device drivers" config VIODASD tristate "iSeries Virtual I/O disk support" + depends on BLOCK help If you are running on an iSeries system and you want to use virtual disks created and managed by OS/400, say Y. diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c index d4c61c3c9669fabaf76f7f48670f30a7427a7abd..bfd60e4acceeeb21be02e2f68cc58d251d696395 100644 --- a/arch/powerpc/platforms/maple/setup.c +++ b/arch/powerpc/platforms/maple/setup.c @@ -50,7 +50,6 @@ #include #include #include -#include #include #include #include @@ -335,9 +334,4 @@ define_machine(maple) { .calibrate_decr = generic_calibrate_decr, .progress = maple_progress, .power_save = power4_idle, -#ifdef CONFIG_KEXEC - .machine_kexec = default_machine_kexec, - .machine_kexec_prepare = default_machine_kexec_prepare, - .machine_crash_shutdown = default_machine_crash_shutdown, -#endif }; diff --git a/arch/powerpc/platforms/powermac/cpufreq_32.c b/arch/powerpc/platforms/powermac/cpufreq_32.c index 792d3ce8112e0778425cfc1f3531db3fb8e69776..65c585b8b00df8300661b52922518f19395f1b96 100644 --- a/arch/powerpc/platforms/powermac/cpufreq_32.c +++ b/arch/powerpc/platforms/powermac/cpufreq_32.c @@ -310,7 +310,7 @@ static int pmu_set_cpu_speed(int low_speed) _set_L3CR(save_l3cr); /* Restore userland MMU context */ - set_context(current->active_mm->context.id, current->active_mm->pgd); + switch_mmu_context(NULL, current->active_mm); #ifdef DEBUG_FREQ printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1)); diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c index bcf50d7056e933a6236e3f192390f8035901923e..54b7b76ed4f090242668a145ac8199afac7c80a5 100644 --- a/arch/powerpc/platforms/powermac/pci.c +++ b/arch/powerpc/platforms/powermac/pci.c @@ -729,7 +729,7 @@ static void __init setup_bandit(struct pci_controller *hose, static int __init setup_uninorth(struct pci_controller *hose, struct resource *addr) { - ppc_pci_flags |= PPC_PCI_REASSIGN_ALL_BUS; + ppc_pci_add_flags(PPC_PCI_REASSIGN_ALL_BUS); has_uninorth = 1; hose->ops = ¯isc_pci_ops; hose->cfg_addr = ioremap(addr->start + 0x800000, 0x1000); @@ -996,7 +996,7 @@ void __init pmac_pci_init(void) struct device_node *np, *root; struct device_node *ht = NULL; - ppc_pci_flags = PPC_PCI_CAN_SKIP_ISA_ALIGN; + ppc_pci_set_flags(PPC_PCI_CAN_SKIP_ISA_ALIGN); root = of_find_node_by_path("/"); if (root == NULL) { @@ -1055,7 +1055,7 @@ void __init pmac_pci_init(void) * some offset between bus number and domains for now when we * assign all busses should help for now */ - if (ppc_pci_flags & PPC_PCI_REASSIGN_ALL_BUS) + if (ppc_pci_has_flag(PPC_PCI_REASSIGN_ALL_BUS)) pcibios_assign_bus_offset = 0x10; #endif } diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index 82c14d203d8bcc92dfc7e4ba46a96ea16177cb8e..9b78f5300c2478196287f78f9d7ccdbf28f71c4d 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -60,7 +60,6 @@ #include #include #include -#include #include #include #include @@ -310,9 +309,7 @@ static void __init pmac_setup_arch(void) } /* See if newworld or oldworld */ - for (ic = NULL; (ic = of_find_all_nodes(ic)) != NULL; ) - if (of_get_property(ic, "interrupt-controller", NULL)) - break; + ic = of_find_node_with_property(NULL, "interrupt-controller"); if (ic) { pmac_newworld = 1; of_node_put(ic); @@ -740,11 +737,6 @@ define_machine(powermac) { .pci_probe_mode = pmac_pci_probe_mode, .power_save = power4_idle, .enable_pmcs = power4_enable_pmcs, -#ifdef CONFIG_KEXEC - .machine_kexec = default_machine_kexec, - .machine_kexec_prepare = default_machine_kexec_prepare, - .machine_crash_shutdown = default_machine_crash_shutdown, -#endif #endif /* CONFIG_PPC64 */ #ifdef CONFIG_PPC32 .pcibios_enable_device_hook = pmac_pci_enable_device_hook, diff --git a/arch/powerpc/platforms/powermac/sleep.S b/arch/powerpc/platforms/powermac/sleep.S index adee28da353f9f00095d7d8ed85d3234d8001dab..1c2802fabd573f72a98fe2eb5c2540e12643c6a8 100644 --- a/arch/powerpc/platforms/powermac/sleep.S +++ b/arch/powerpc/platforms/powermac/sleep.S @@ -17,6 +17,7 @@ #include #include #include +#include #define MAGIC 0x4c617273 /* 'Lars' */ @@ -323,7 +324,7 @@ grackle_wake_up: lwz r4,SL_IBAT3+4(r1) mtibatl 3,r4 -BEGIN_FTR_SECTION +BEGIN_MMU_FTR_SECTION li r4,0 mtspr SPRN_DBAT4U,r4 mtspr SPRN_DBAT4L,r4 @@ -341,7 +342,7 @@ BEGIN_FTR_SECTION mtspr SPRN_IBAT6L,r4 mtspr SPRN_IBAT7U,r4 mtspr SPRN_IBAT7L,r4 -END_FTR_SECTION_IFSET(CPU_FTR_HAS_HIGH_BATS) +END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS) /* Flush all TLBs */ lis r4,0x1000 diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index 40f72c2a4699f101dbe90f17abbb2e0d31ab54fd..6b0711c15ecaf9ad506e6b9dfd8eec61677dd978 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c @@ -739,7 +739,7 @@ static void __init smp_core99_setup(int ncpus) /* XXX should get this from reg properties */ for (i = 1; i < ncpus; ++i) - smp_hw_index[i] = i; + set_hard_smp_processor_id(i, i); } #endif diff --git a/arch/powerpc/platforms/ps3/device-init.c b/arch/powerpc/platforms/ps3/device-init.c index ffdd8e963fbdf04032b79afcd640748c4f4b77a9..dbc124e056461038c3620d8cf92a60ed3008bbce 100644 --- a/arch/powerpc/platforms/ps3/device-init.c +++ b/arch/powerpc/platforms/ps3/device-init.c @@ -314,11 +314,17 @@ static int __init ps3_setup_vuart_device(enum ps3_match_id match_id, result = ps3_system_bus_device_register(&p->dev); - if (result) + if (result) { pr_debug("%s:%d ps3_system_bus_device_register failed\n", __func__, __LINE__); - + goto fail_device_register; + } pr_debug(" <- %s:%d\n", __func__, __LINE__); + return 0; + +fail_device_register: + kfree(p); + pr_debug(" <- %s:%d fail\n", __func__, __LINE__); return result; } @@ -463,11 +469,17 @@ static int __init ps3_register_sound_devices(void) result = ps3_system_bus_device_register(&p->dev); - if (result) + if (result) { pr_debug("%s:%d ps3_system_bus_device_register failed\n", __func__, __LINE__); - + goto fail_device_register; + } pr_debug(" <- %s:%d\n", __func__, __LINE__); + return 0; + +fail_device_register: + kfree(p); + pr_debug(" <- %s:%d failed\n", __func__, __LINE__); return result; } @@ -485,17 +497,24 @@ static int __init ps3_register_graphics_devices(void) if (!p) return -ENOMEM; - p->dev.match_id = PS3_MATCH_ID_GRAPHICS; - p->dev.match_sub_id = PS3_MATCH_SUB_ID_FB; + p->dev.match_id = PS3_MATCH_ID_GPU; + p->dev.match_sub_id = PS3_MATCH_SUB_ID_GPU_FB; p->dev.dev_type = PS3_DEVICE_TYPE_IOC0; result = ps3_system_bus_device_register(&p->dev); - if (result) + if (result) { pr_debug("%s:%d ps3_system_bus_device_register failed\n", __func__, __LINE__); + goto fail_device_register; + } pr_debug(" <- %s:%d\n", __func__, __LINE__); + return 0; + +fail_device_register: + kfree(p); + pr_debug(" <- %s:%d failed\n", __func__, __LINE__); return result; } diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c index 3a58ffabccd97063d156aed583f605a3df670022..a4d49dd9e8a9d7f101fe42c8f5f67bda91647392 100644 --- a/arch/powerpc/platforms/ps3/mm.c +++ b/arch/powerpc/platforms/ps3/mm.c @@ -649,7 +649,7 @@ static int dma_sb_region_create(struct ps3_dma_region *r) { int result; - pr_info(" -> %s:%d:\n", __func__, __LINE__); + DBG(" -> %s:%d:\n", __func__, __LINE__); BUG_ON(!r); diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c index 77bc330263c4e3063f6d6dd4686e9c83a532bc0d..35f3e85cf60ea9d79ff873f10090395c791f1c99 100644 --- a/arch/powerpc/platforms/ps3/setup.c +++ b/arch/powerpc/platforms/ps3/setup.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include @@ -42,6 +41,10 @@ #define DBG pr_debug #endif +/* mutex synchronizing GPU accesses and video mode changes */ +DEFINE_MUTEX(ps3_gpu_mutex); +EXPORT_SYMBOL_GPL(ps3_gpu_mutex); + #if !defined(CONFIG_SMP) static void smp_send_stop(void) {} #endif @@ -277,8 +280,5 @@ define_machine(ps3) { .halt = ps3_halt, #if defined(CONFIG_KEXEC) .kexec_cpu_down = ps3_kexec_cpu_down, - .machine_kexec = default_machine_kexec, - .machine_kexec_prepare = default_machine_kexec_prepare, - .machine_crash_shutdown = default_machine_crash_shutdown, #endif }; diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c index 661e9f77ebf6be4c70d5e013e65be1229cf665cb..ee0d22911621751ebecfb1d584f10004a4033b53 100644 --- a/arch/powerpc/platforms/ps3/system-bus.c +++ b/arch/powerpc/platforms/ps3/system-bus.c @@ -31,7 +31,7 @@ #include "platform.h" static struct device ps3_system_bus = { - .bus_id = "ps3_system", + .init_name = "ps3_system", }; /* FIXME: need device usage counters! */ @@ -175,7 +175,7 @@ int ps3_open_hv_device(struct ps3_system_bus_device *dev) return ps3_open_hv_device_sb(dev); case PS3_MATCH_ID_SOUND: - case PS3_MATCH_ID_GRAPHICS: + case PS3_MATCH_ID_GPU: return ps3_open_hv_device_gpu(dev); case PS3_MATCH_ID_AV_SETTINGS: @@ -213,7 +213,7 @@ int ps3_close_hv_device(struct ps3_system_bus_device *dev) return ps3_close_hv_device_sb(dev); case PS3_MATCH_ID_SOUND: - case PS3_MATCH_ID_GRAPHICS: + case PS3_MATCH_ID_GPU: return ps3_close_hv_device_gpu(dev); case PS3_MATCH_ID_AV_SETTINGS: @@ -356,12 +356,12 @@ static int ps3_system_bus_match(struct device *_dev, if (result) pr_info("%s:%d: dev=%u.%u(%s), drv=%u.%u(%s): match\n", __func__, __LINE__, - dev->match_id, dev->match_sub_id, dev->core.bus_id, + dev->match_id, dev->match_sub_id, dev_name(&dev->core), drv->match_id, drv->match_sub_id, drv->core.name); else pr_debug("%s:%d: dev=%u.%u(%s), drv=%u.%u(%s): miss\n", __func__, __LINE__, - dev->match_id, dev->match_sub_id, dev->core.bus_id, + dev->match_id, dev->match_sub_id, dev_name(&dev->core), drv->match_id, drv->match_sub_id, drv->core.name); return result; @@ -383,9 +383,9 @@ static int ps3_system_bus_probe(struct device *_dev) result = drv->probe(dev); else pr_debug("%s:%d: %s no probe method\n", __func__, __LINE__, - dev->core.bus_id); + dev_name(&dev->core)); - pr_debug(" <- %s:%d: %s\n", __func__, __LINE__, dev->core.bus_id); + pr_debug(" <- %s:%d: %s\n", __func__, __LINE__, dev_name(&dev->core)); return result; } @@ -407,7 +407,7 @@ static int ps3_system_bus_remove(struct device *_dev) dev_dbg(&dev->core, "%s:%d %s: no remove method\n", __func__, __LINE__, drv->core.name); - pr_debug(" <- %s:%d: %s\n", __func__, __LINE__, dev->core.bus_id); + pr_debug(" <- %s:%d: %s\n", __func__, __LINE__, dev_name(&dev->core)); return result; } @@ -432,7 +432,7 @@ static void ps3_system_bus_shutdown(struct device *_dev) BUG_ON(!drv); dev_dbg(&dev->core, "%s:%d: %s -> %s\n", __func__, __LINE__, - dev->core.bus_id, drv->core.name); + dev_name(&dev->core), drv->core.name); if (drv->shutdown) drv->shutdown(dev); @@ -453,7 +453,8 @@ static int ps3_system_bus_uevent(struct device *_dev, struct kobj_uevent_env *en { struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); - if (add_uevent_var(env, "MODALIAS=ps3:%d", dev->match_id)) + if (add_uevent_var(env, "MODALIAS=ps3:%d:%d", dev->match_id, + dev->match_sub_id)) return -ENOMEM; return 0; } @@ -462,7 +463,8 @@ static ssize_t modalias_show(struct device *_dev, struct device_attribute *a, char *buf) { struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); - int len = snprintf(buf, PAGE_SIZE, "ps3:%d\n", dev->match_id); + int len = snprintf(buf, PAGE_SIZE, "ps3:%d:%d\n", dev->match_id, + dev->match_sub_id); return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; } @@ -742,22 +744,18 @@ int ps3_system_bus_device_register(struct ps3_system_bus_device *dev) switch (dev->dev_type) { case PS3_DEVICE_TYPE_IOC0: dev->core.archdata.dma_ops = &ps3_ioc0_dma_ops; - snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), - "ioc0_%02x", ++dev_ioc0_count); + dev_set_name(&dev->core, "ioc0_%02x", ++dev_ioc0_count); break; case PS3_DEVICE_TYPE_SB: dev->core.archdata.dma_ops = &ps3_sb_dma_ops; - snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), - "sb_%02x", ++dev_sb_count); + dev_set_name(&dev->core, "sb_%02x", ++dev_sb_count); break; case PS3_DEVICE_TYPE_VUART: - snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), - "vuart_%02x", ++dev_vuart_count); + dev_set_name(&dev->core, "vuart_%02x", ++dev_vuart_count); break; case PS3_DEVICE_TYPE_LPM: - snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), - "lpm_%02x", ++dev_lpm_count); + dev_set_name(&dev->core, "lpm_%02x", ++dev_lpm_count); break; default: BUG(); @@ -766,7 +764,7 @@ int ps3_system_bus_device_register(struct ps3_system_bus_device *dev) dev->core.archdata.of_node = NULL; set_dev_node(&dev->core, 0); - pr_debug("%s:%d add %s\n", __func__, __LINE__, dev->core.bus_id); + pr_debug("%s:%d add %s\n", __func__, __LINE__, dev_name(&dev->core)); result = device_register(&dev->core); return result; diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig index 97619fd51e393870d1c0c1da8a6bdb1926a52a57..ddc2a307cd50c354e8488de69ec01048e171e94c 100644 --- a/arch/powerpc/platforms/pseries/Kconfig +++ b/arch/powerpc/platforms/pseries/Kconfig @@ -54,7 +54,7 @@ config PPC_SMLPAR config CMM tristate "Collaborative memory management" - depends on PPC_SMLPAR + depends on PPC_SMLPAR && !CRASH_DUMP default y help Select this option, if you want to enable the kernel interface diff --git a/arch/powerpc/platforms/pseries/cmm.c b/arch/powerpc/platforms/pseries/cmm.c index 5cd4d276162085f43177ac56d7effb162dcdb090..6567439fe78dda4512e0524332255df66b5816a1 100644 --- a/arch/powerpc/platforms/pseries/cmm.c +++ b/arch/powerpc/platforms/pseries/cmm.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -383,6 +384,26 @@ static void cmm_unregister_sysfs(struct sys_device *sysdev) sysdev_class_unregister(&cmm_sysdev_class); } +/** + * cmm_reboot_notifier - Make sure pages are not still marked as "loaned" + * + **/ +static int cmm_reboot_notifier(struct notifier_block *nb, + unsigned long action, void *unused) +{ + if (action == SYS_RESTART) { + if (cmm_thread_ptr) + kthread_stop(cmm_thread_ptr); + cmm_thread_ptr = NULL; + cmm_free_pages(loaned_pages); + } + return NOTIFY_DONE; +} + +static struct notifier_block cmm_reboot_nb = { + .notifier_call = cmm_reboot_notifier, +}; + /** * cmm_init - Module initialization * @@ -399,9 +420,12 @@ static int cmm_init(void) if ((rc = register_oom_notifier(&cmm_oom_nb)) < 0) return rc; - if ((rc = cmm_sysfs_register(&cmm_sysdev))) + if ((rc = register_reboot_notifier(&cmm_reboot_nb))) goto out_oom_notifier; + if ((rc = cmm_sysfs_register(&cmm_sysdev))) + goto out_reboot_notifier; + if (cmm_disabled) return rc; @@ -415,6 +439,8 @@ static int cmm_init(void) out_unregister_sysfs: cmm_unregister_sysfs(&cmm_sysdev); +out_reboot_notifier: + unregister_reboot_notifier(&cmm_reboot_nb); out_oom_notifier: unregister_oom_notifier(&cmm_oom_nb); return rc; @@ -431,6 +457,7 @@ static void cmm_exit(void) if (cmm_thread_ptr) kthread_stop(cmm_thread_ptr); unregister_oom_notifier(&cmm_oom_nb); + unregister_reboot_notifier(&cmm_reboot_nb); cmm_free_pages(loaned_pages); cmm_unregister_sysfs(&cmm_sysdev); } diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index 54816d75b5787b8d0f134c4de71f78854fd5d27a..989d6462c1547f69674b19f9421feeab75111423 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c @@ -21,6 +21,8 @@ * Please address comments and feedback to Linas Vepstas */ +#undef DEBUG + #include #include #include @@ -488,10 +490,8 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) if (!(pdn->eeh_mode & EEH_MODE_SUPPORTED) || pdn->eeh_mode & EEH_MODE_NOCHECK) { ignored_check++; -#ifdef DEBUG - printk ("EEH:ignored check (%x) for %s %s\n", - pdn->eeh_mode, pci_name (dev), dn->full_name); -#endif + pr_debug("EEH: Ignored check (%x) for %s %s\n", + pdn->eeh_mode, pci_name (dev), dn->full_name); return 0; } @@ -1014,10 +1014,9 @@ static void *early_enable_eeh(struct device_node *dn, void *data) eeh_subsystem_enabled = 1; pdn->eeh_mode |= EEH_MODE_SUPPORTED; -#ifdef DEBUG - printk(KERN_DEBUG "EEH: %s: eeh enabled, config=%x pe_config=%x\n", - dn->full_name, pdn->eeh_config_addr, pdn->eeh_pe_config_addr); -#endif + pr_debug("EEH: %s: eeh enabled, config=%x pe_config=%x\n", + dn->full_name, pdn->eeh_config_addr, + pdn->eeh_pe_config_addr); } else { /* This device doesn't support EEH, but it may have an @@ -1161,13 +1160,17 @@ static void eeh_add_device_late(struct pci_dev *dev) if (!dev || !eeh_subsystem_enabled) return; -#ifdef DEBUG - printk(KERN_DEBUG "EEH: adding device %s\n", pci_name(dev)); -#endif + pr_debug("EEH: Adding device %s\n", pci_name(dev)); - pci_dev_get (dev); dn = pci_device_to_OF_node(dev); pdn = PCI_DN(dn); + if (pdn->pcidev == dev) { + pr_debug("EEH: Already referenced !\n"); + return; + } + WARN_ON(pdn->pcidev); + + pci_dev_get (dev); pdn->pcidev = dev; pci_addr_cache_insert_device(dev); @@ -1206,17 +1209,18 @@ static void eeh_remove_device(struct pci_dev *dev) return; /* Unregister the device with the EEH/PCI address search system */ -#ifdef DEBUG - printk(KERN_DEBUG "EEH: remove device %s\n", pci_name(dev)); -#endif - pci_addr_cache_remove_device(dev); - eeh_sysfs_remove_device(dev); + pr_debug("EEH: Removing device %s\n", pci_name(dev)); dn = pci_device_to_OF_node(dev); - if (PCI_DN(dn)->pcidev) { - PCI_DN(dn)->pcidev = NULL; - pci_dev_put (dev); + if (PCI_DN(dn)->pcidev == NULL) { + pr_debug("EEH: Not referenced !\n"); + return; } + PCI_DN(dn)->pcidev = NULL; + pci_dev_put (dev); + + pci_addr_cache_remove_device(dev); + eeh_sysfs_remove_device(dev); } void eeh_remove_bus_device(struct pci_dev *dev) diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c index 1f032483c026e613b4ab84649ab2f3562fb7c031..a20ead87153db18566a2034179a9041ea6cc456d 100644 --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c @@ -116,7 +116,7 @@ static void pseries_cpu_die(unsigned int cpu) cpu_status = query_cpu_stopped(pcpu); if (cpu_status == 0 || cpu_status == -1) break; - msleep(200); + cpu_relax(); } if (cpu_status != 0) { printk("Querying DEAD? cpu %i (%i) shows %i\n", diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c index 7190493e9bdc5813f4a8c4321f25a0e66d129a89..5e1ed3d60ee501a3a78b03b82aa90e0ba9ffd25b 100644 --- a/arch/powerpc/platforms/pseries/pci_dlpar.c +++ b/arch/powerpc/platforms/pseries/pci_dlpar.c @@ -25,6 +25,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#undef DEBUG + #include #include #include @@ -69,74 +71,25 @@ EXPORT_SYMBOL_GPL(pcibios_find_pci_bus); * Remove all of the PCI devices under this bus both from the * linux pci device tree, and from the powerpc EEH address cache. */ -void -pcibios_remove_pci_devices(struct pci_bus *bus) +void pcibios_remove_pci_devices(struct pci_bus *bus) { - struct pci_dev *dev, *tmp; + struct pci_dev *dev, *tmp; + struct pci_bus *child_bus; + + /* First go down child busses */ + list_for_each_entry(child_bus, &bus->children, node) + pcibios_remove_pci_devices(child_bus); + pr_debug("PCI: Removing devices on bus %04x:%02x\n", + pci_domain_nr(bus), bus->number); list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) { + pr_debug(" * Removing %s...\n", pci_name(dev)); eeh_remove_bus_device(dev); - pci_remove_bus_device(dev); - } + pci_remove_bus_device(dev); + } } EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices); -/* Must be called before pci_bus_add_devices */ -void -pcibios_fixup_new_pci_devices(struct pci_bus *bus) -{ - struct pci_dev *dev; - - list_for_each_entry(dev, &bus->devices, bus_list) { - /* Skip already-added devices */ - if (!dev->is_added) { - int i; - - /* Fill device archdata and setup iommu table */ - pcibios_setup_new_device(dev); - - pci_read_irq_line(dev); - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - struct resource *r = &dev->resource[i]; - - if (r->parent || !r->start || !r->flags) - continue; - pci_claim_resource(dev, i); - } - } - } -} -EXPORT_SYMBOL_GPL(pcibios_fixup_new_pci_devices); - -static int -pcibios_pci_config_bridge(struct pci_dev *dev) -{ - u8 sec_busno; - struct pci_bus *child_bus; - - /* Get busno of downstream bus */ - pci_read_config_byte(dev, PCI_SECONDARY_BUS, &sec_busno); - - /* Add to children of PCI bridge dev->bus */ - child_bus = pci_add_new_bus(dev->bus, dev, sec_busno); - if (!child_bus) { - printk (KERN_ERR "%s: could not add second bus\n", __func__); - return -EIO; - } - sprintf(child_bus->name, "PCI Bus #%02x", child_bus->number); - - pci_scan_child_bus(child_bus); - - /* Fixup new pci devices */ - pcibios_fixup_new_pci_devices(child_bus); - - /* Make the discovered devices available */ - pci_bus_add_devices(child_bus); - - eeh_add_device_tree_late(child_bus); - return 0; -} - /** * pcibios_add_pci_devices - adds new pci devices to bus * @@ -147,10 +100,9 @@ pcibios_pci_config_bridge(struct pci_dev *dev) * is how this routine differs from other, similar pcibios * routines.) */ -void -pcibios_add_pci_devices(struct pci_bus * bus) +void pcibios_add_pci_devices(struct pci_bus * bus) { - int slotno, num, mode; + int slotno, num, mode, pass, max; struct pci_dev *dev; struct device_node *dn = pci_bus_to_OF_node(bus); @@ -162,26 +114,23 @@ pcibios_add_pci_devices(struct pci_bus * bus) if (mode == PCI_PROBE_DEVTREE) { /* use ofdt-based probe */ - of_scan_bus(dn, bus); - if (!list_empty(&bus->devices)) { - pcibios_fixup_new_pci_devices(bus); - pci_bus_add_devices(bus); - eeh_add_device_tree_late(bus); - } + of_rescan_bus(dn, bus); } else if (mode == PCI_PROBE_NORMAL) { /* use legacy probe */ slotno = PCI_SLOT(PCI_DN(dn->child)->devfn); num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0)); - if (num) { - pcibios_fixup_new_pci_devices(bus); - pci_bus_add_devices(bus); - eeh_add_device_tree_late(bus); + if (!num) + return; + pcibios_setup_bus_devices(bus); + max = bus->secondary; + for (pass=0; pass < 2; pass++) + list_for_each_entry(dev, &bus->devices, bus_list) { + if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || + dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) + max = pci_scan_bridge(bus, dev, max, pass); } - - list_for_each_entry(dev, &bus->devices, bus_list) - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) - pcibios_pci_config_bridge(dev); } + pcibios_finish_adding_to_bus(bus); } EXPORT_SYMBOL_GPL(pcibios_add_pci_devices); @@ -190,6 +139,8 @@ struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn) struct pci_controller *phb; int primary; + pr_debug("PCI: Initializing new hotplug PHB %s\n", dn->full_name); + primary = list_empty(&hose_list); phb = pcibios_alloc_controller(dn); if (!phb) @@ -203,11 +154,59 @@ struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn) eeh_add_device_tree_early(dn); scan_phb(phb); - pcibios_allocate_bus_resources(phb->bus); - pcibios_fixup_new_pci_devices(phb->bus); - pci_bus_add_devices(phb->bus); - eeh_add_device_tree_late(phb->bus); + pcibios_finish_adding_to_bus(phb->bus); return phb; } EXPORT_SYMBOL_GPL(init_phb_dynamic); + +/* RPA-specific bits for removing PHBs */ +int remove_phb_dynamic(struct pci_controller *phb) +{ + struct pci_bus *b = phb->bus; + struct resource *res; + int rc, i; + + pr_debug("PCI: Removing PHB %04x:%02x... \n", + pci_domain_nr(b), b->number); + + /* We cannot to remove a root bus that has children */ + if (!(list_empty(&b->children) && list_empty(&b->devices))) + return -EBUSY; + + /* We -know- there aren't any child devices anymore at this stage + * and thus, we can safely unmap the IO space as it's not in use + */ + res = &phb->io_resource; + if (res->flags & IORESOURCE_IO) { + rc = pcibios_unmap_io_space(b); + if (rc) { + printk(KERN_ERR "%s: failed to unmap IO on bus %s\n", + __func__, b->name); + return 1; + } + } + + /* Unregister the bridge device from sysfs and remove the PCI bus */ + device_unregister(b->bridge); + phb->bus = NULL; + pci_remove_bus(b); + + /* Now release the IO resource */ + if (res->flags & IORESOURCE_IO) + release_resource(res); + + /* Release memory resources */ + for (i = 0; i < 3; ++i) { + res = &phb->mem_resources[i]; + if (!(res->flags & IORESOURCE_MEM)) + continue; + release_resource(res); + } + + /* Free pci_controller data structure */ + pcibios_free_controller(phb); + + return 0; +} +EXPORT_SYMBOL_GPL(remove_phb_dynamic); diff --git a/arch/powerpc/platforms/pseries/phyp_dump.c b/arch/powerpc/platforms/pseries/phyp_dump.c index edbc012c2ebca1cff90c13d713d2e442e3ac52a1..6cf35cd8d0b50bd42478843941f696fb1aa9c4d6 100644 --- a/arch/powerpc/platforms/pseries/phyp_dump.c +++ b/arch/powerpc/platforms/pseries/phyp_dump.c @@ -130,6 +130,9 @@ static unsigned long init_dump_header(struct phyp_dump_header *ph) static void print_dump_header(const struct phyp_dump_header *ph) { #ifdef DEBUG + if (ph == NULL) + return; + printk(KERN_INFO "dump header:\n"); /* setup some ph->sections required */ printk(KERN_INFO "version = %d\n", ph->version); @@ -411,6 +414,8 @@ static int __init phyp_dump_setup(void) of_node_put(rtas); } + ibm_configure_kernel_dump = rtas_token("ibm,configure-kernel-dump"); + print_dump_header(dump_header); dump_area_length = init_dump_header(&phdr); /* align down */ diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index e1904774a70fecd21673f6e899d89251905f91d3..f7a69021b7bf8ed9832a94527a48b632dc2477ee 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c @@ -579,7 +579,7 @@ static void xics_update_irq_servers(void) int i, j; struct device_node *np; u32 ilen; - const u32 *ireg, *isize; + const u32 *ireg; u32 hcpuid; /* Find the server numbers for the boot cpu. */ @@ -607,11 +607,6 @@ static void xics_update_irq_servers(void) } } - /* get the bit size of server numbers */ - isize = of_get_property(np, "ibm,interrupt-server#-size", NULL); - if (isize) - interrupt_server_size = *isize; - of_node_put(np); } @@ -682,6 +677,7 @@ void __init xics_init_IRQ(void) struct device_node *np; u32 indx = 0; int found = 0; + const u32 *isize; ppc64_boot_msg(0x20, "XICS Init"); @@ -701,6 +697,26 @@ void __init xics_init_IRQ(void) if (found == 0) return; + /* get the bit size of server numbers */ + found = 0; + + for_each_compatible_node(np, NULL, "ibm,ppc-xics") { + isize = of_get_property(np, "ibm,interrupt-server#-size", NULL); + + if (!isize) + continue; + + if (!found) { + interrupt_server_size = *isize; + found = 1; + } else if (*isize != interrupt_server_size) { + printk(KERN_WARNING "XICS: " + "mismatched ibm,interrupt-server#-size\n"); + interrupt_server_size = max(*isize, + interrupt_server_size); + } + } + xics_update_irq_servers(); xics_init_host(); @@ -728,9 +744,18 @@ static void xics_set_cpu_priority(unsigned char cppr) /* Have the calling processor join or leave the specified global queue */ static void xics_set_cpu_giq(unsigned int gserver, unsigned int join) { - int status = rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE, - (1UL << interrupt_server_size) - 1 - gserver, join); - WARN_ON(status < 0); + int index; + int status; + + if (!rtas_indicator_present(GLOBAL_INTERRUPT_QUEUE, NULL)) + return; + + index = (1UL << interrupt_server_size) - 1 - gserver; + + status = rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE, index, join); + + WARN(status < 0, "set-indicator(%d, %d, %u) returned %d\n", + GLOBAL_INTERRUPT_QUEUE, index, join, status); } void xics_setup_cpu(void) diff --git a/arch/powerpc/sysdev/bestcomm/ata.c b/arch/powerpc/sysdev/bestcomm/ata.c index 1f5258fb38c394aa73e1bcbb5e2a4e4554f3b25d..901c9f91e5dd233df9fadfff7944b877d5189fcc 100644 --- a/arch/powerpc/sysdev/bestcomm/ata.c +++ b/arch/powerpc/sysdev/bestcomm/ata.c @@ -61,6 +61,9 @@ bcom_ata_init(int queue_len, int maxbufsize) struct bcom_ata_var *var; struct bcom_ata_inc *inc; + /* Prefetch breaks ATA DMA. Turn it off for ATA DMA */ + bcom_disable_prefetch(); + tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_ata_bd), 0); if (!tsk) return NULL; diff --git a/arch/powerpc/sysdev/bestcomm/ata.h b/arch/powerpc/sysdev/bestcomm/ata.h index 10982769c46514957d605b06bdb15ac75efa3c5d..0b2371811334fed45093e923f2a6625bc988441d 100644 --- a/arch/powerpc/sysdev/bestcomm/ata.h +++ b/arch/powerpc/sysdev/bestcomm/ata.h @@ -16,22 +16,15 @@ struct bcom_ata_bd { u32 status; - u32 dst_pa; u32 src_pa; + u32 dst_pa; }; -extern struct bcom_task * -bcom_ata_init(int queue_len, int maxbufsize); - -extern void -bcom_ata_rx_prepare(struct bcom_task *tsk); - -extern void -bcom_ata_tx_prepare(struct bcom_task *tsk); - -extern void -bcom_ata_reset_bd(struct bcom_task *tsk); - +extern struct bcom_task * bcom_ata_init(int queue_len, int maxbufsize); +extern void bcom_ata_rx_prepare(struct bcom_task *tsk); +extern void bcom_ata_tx_prepare(struct bcom_task *tsk); +extern void bcom_ata_reset_bd(struct bcom_task *tsk); +extern void bcom_ata_release(struct bcom_task *tsk); #endif /* __BESTCOMM_ATA_H__ */ diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm.c b/arch/powerpc/sysdev/bestcomm/bestcomm.c index 446c9ea85b3018b10a07fb55a9d1d86bff55c2db..378ebd9aac18567af6b249c34138e71698a52dd0 100644 --- a/arch/powerpc/sysdev/bestcomm/bestcomm.c +++ b/arch/powerpc/sysdev/bestcomm/bestcomm.c @@ -279,7 +279,6 @@ bcom_engine_init(void) int task; phys_addr_t tdt_pa, ctx_pa, var_pa, fdt_pa; unsigned int tdt_size, ctx_size, var_size, fdt_size; - u16 regval; /* Allocate & clear SRAM zones for FDT, TDTs, contexts and vars/incs */ tdt_size = BCOM_MAX_TASKS * sizeof(struct bcom_tdt); @@ -331,10 +330,8 @@ bcom_engine_init(void) out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_ALWAYS], BCOM_IPR_ALWAYS); /* Disable COMM Bus Prefetch on the original 5200; it's broken */ - if ((mfspr(SPRN_SVR) & MPC5200_SVR_MASK) == MPC5200_SVR) { - regval = in_be16(&bcom_eng->regs->PtdCntrl); - out_be16(&bcom_eng->regs->PtdCntrl, regval | 1); - } + if ((mfspr(SPRN_SVR) & MPC5200_SVR_MASK) == MPC5200_SVR) + bcom_disable_prefetch(); /* Init lock */ spin_lock_init(&bcom_eng->lock); diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm.h b/arch/powerpc/sysdev/bestcomm/bestcomm.h index c960a8b4965538a78d92bf7c2469f9f4ffed591d..23a95f80dfdb4f3658bcdbacdefa82d95a9fd6e7 100644 --- a/arch/powerpc/sysdev/bestcomm/bestcomm.h +++ b/arch/powerpc/sysdev/bestcomm/bestcomm.h @@ -16,8 +16,19 @@ #ifndef __BESTCOMM_H__ #define __BESTCOMM_H__ -struct bcom_bd; /* defined later on ... */ - +/** + * struct bcom_bd - Structure describing a generic BestComm buffer descriptor + * @status: The current status of this buffer. Exact meaning depends on the + * task type + * @data: An array of u32 extra data. Size of array is task dependant. + * + * Note: Don't dereference a bcom_bd pointer as an array. The size of the + * bcom_bd is variable. Use bcom_get_bd() instead. + */ +struct bcom_bd { + u32 status; + u32 data[0]; /* variable payload size */ +}; /* ======================================================================== */ /* Generic task management */ @@ -84,17 +95,6 @@ bcom_get_task_irq(struct bcom_task *tsk) { /* BD based tasks helpers */ /* ======================================================================== */ -/** - * struct bcom_bd - Structure describing a generic BestComm buffer descriptor - * @status: The current status of this buffer. Exact meaning depends on the - * task type - * @data: An array of u32 whose meaning depends on the task type. - */ -struct bcom_bd { - u32 status; - u32 data[1]; /* variable, but at least 1 */ -}; - #define BCOM_BD_READY 0x40000000ul /** _bcom_next_index - Get next input index. @@ -139,6 +139,19 @@ bcom_queue_full(struct bcom_task *tsk) return tsk->outdex == _bcom_next_index(tsk); } +/** + * bcom_get_bd - Get a BD from the queue + * @tsk: The BestComm task structure + * index: Index of the BD to fetch + */ +static inline struct bcom_bd +*bcom_get_bd(struct bcom_task *tsk, unsigned int index) +{ + /* A cast to (void*) so the address can be incremented by the + * real size instead of by sizeof(struct bcom_bd) */ + return ((void *)tsk->bd) + (index * tsk->bd_size); +} + /** * bcom_buffer_done - Checks if a BestComm * @tsk: The BestComm task structure @@ -146,9 +159,12 @@ bcom_queue_full(struct bcom_task *tsk) static inline int bcom_buffer_done(struct bcom_task *tsk) { + struct bcom_bd *bd; if (bcom_queue_empty(tsk)) return 0; - return !(tsk->bd[tsk->outdex].status & BCOM_BD_READY); + + bd = bcom_get_bd(tsk, tsk->outdex); + return !(bd->status & BCOM_BD_READY); } /** @@ -160,16 +176,21 @@ bcom_buffer_done(struct bcom_task *tsk) static inline struct bcom_bd * bcom_prepare_next_buffer(struct bcom_task *tsk) { - tsk->bd[tsk->index].status = 0; /* cleanup last status */ - return &tsk->bd[tsk->index]; + struct bcom_bd *bd; + + bd = bcom_get_bd(tsk, tsk->index); + bd->status = 0; /* cleanup last status */ + return bd; } static inline void bcom_submit_next_buffer(struct bcom_task *tsk, void *cookie) { + struct bcom_bd *bd = bcom_get_bd(tsk, tsk->index); + tsk->cookie[tsk->index] = cookie; mb(); /* ensure the bd is really up-to-date */ - tsk->bd[tsk->index].status |= BCOM_BD_READY; + bd->status |= BCOM_BD_READY; tsk->index = _bcom_next_index(tsk); if (tsk->flags & BCOM_FLAGS_ENABLE_TASK) bcom_enable(tsk); @@ -179,10 +200,12 @@ static inline void * bcom_retrieve_buffer(struct bcom_task *tsk, u32 *p_status, struct bcom_bd **p_bd) { void *cookie = tsk->cookie[tsk->outdex]; + struct bcom_bd *bd = bcom_get_bd(tsk, tsk->outdex); + if (p_status) - *p_status = tsk->bd[tsk->outdex].status; + *p_status = bd->status; if (p_bd) - *p_bd = &tsk->bd[tsk->outdex]; + *p_bd = bd; tsk->outdex = _bcom_next_outdex(tsk); return cookie; } diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h b/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h index 866a2915ef2fca92f3849480331a81e958bb3d69..eb0d1c883c318434b92278d9623935a95b1c7e98 100644 --- a/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h +++ b/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h @@ -198,8 +198,8 @@ struct bcom_task_header { #define BCOM_IPR_SCTMR_1 2 #define BCOM_IPR_FEC_RX 6 #define BCOM_IPR_FEC_TX 5 -#define BCOM_IPR_ATA_RX 4 -#define BCOM_IPR_ATA_TX 3 +#define BCOM_IPR_ATA_RX 7 +#define BCOM_IPR_ATA_TX 7 #define BCOM_IPR_SCPCI_RX 2 #define BCOM_IPR_SCPCI_TX 2 #define BCOM_IPR_PSC3_RX 2 @@ -241,6 +241,22 @@ extern void bcom_set_initiator(int task, int initiator); #define TASK_ENABLE 0x8000 +/** + * bcom_disable_prefetch - Hook to disable bus prefetching + * + * ATA DMA and the original MPC5200 need this due to silicon bugs. At the + * moment disabling prefetch is a one-way street. There is no mechanism + * in place to turn prefetch back on after it has been disabled. There is + * no reason it couldn't be done, it would just be more complex to implement. + */ +static inline void bcom_disable_prefetch(void) +{ + u16 regval; + + regval = in_be16(&bcom_eng->regs->PtdCntrl); + out_be16(&bcom_eng->regs->PtdCntrl, regval | 1); +}; + static inline void bcom_enable_task(int task) { diff --git a/arch/powerpc/sysdev/dcr-low.S b/arch/powerpc/sysdev/dcr-low.S index 2078f39e2f179a2341b4916bb79d5b32ab6930ae..d3098ef1404a2df72738bd1e01e51dda3f185227 100644 --- a/arch/powerpc/sysdev/dcr-low.S +++ b/arch/powerpc/sysdev/dcr-low.S @@ -11,14 +11,20 @@ #include #include +#include #define DCR_ACCESS_PROLOG(table) \ + cmpli cr0,r3,1024; \ rlwinm r3,r3,4,18,27; \ lis r5,table@h; \ ori r5,r5,table@l; \ add r3,r3,r5; \ + bge- 1f; \ mtctr r3; \ - bctr + bctr; \ +1: trap; \ + EMIT_BUG_ENTRY 1b,__FILE__,__LINE__,0; \ + blr _GLOBAL(__mfdcr) DCR_ACCESS_PROLOG(__mfdcr_table) diff --git a/arch/powerpc/sysdev/dcr.c b/arch/powerpc/sysdev/dcr.c index a8ba9983dd5a8ab0ccc8e04bd82816796e02282b..bb44aa9fd47028cabab4b57a472867e0f77f9136 100644 --- a/arch/powerpc/sysdev/dcr.c +++ b/arch/powerpc/sysdev/dcr.c @@ -124,7 +124,8 @@ EXPORT_SYMBOL_GPL(dcr_write_generic); #endif /* defined(CONFIG_PPC_DCR_NATIVE) && defined(CONFIG_PPC_DCR_MMIO) */ -unsigned int dcr_resource_start(struct device_node *np, unsigned int index) +unsigned int dcr_resource_start(const struct device_node *np, + unsigned int index) { unsigned int ds; const u32 *dr = of_get_property(np, "dcr-reg", &ds); @@ -136,7 +137,7 @@ unsigned int dcr_resource_start(struct device_node *np, unsigned int index) } EXPORT_SYMBOL_GPL(dcr_resource_start); -unsigned int dcr_resource_len(struct device_node *np, unsigned int index) +unsigned int dcr_resource_len(const struct device_node *np, unsigned int index) { unsigned int ds; const u32 *dr = of_get_property(np, "dcr-reg", &ds); diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index 5b264eb4b1f7f6af12115640ed8c17d139cb9e3b..d5f9ae0f1b75e7c4612a2beee8ff28174ac3be9b 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c @@ -187,7 +187,7 @@ int __init fsl_add_bridge(struct device_node *dev, int is_primary) printk(KERN_WARNING "Can't get bus-range for %s, assume" " bus 0\n", dev->full_name); - ppc_pci_flags |= PPC_PCI_REASSIGN_ALL_BUS; + ppc_pci_add_flags(PPC_PCI_REASSIGN_ALL_BUS); hose = pcibios_alloc_controller(dev); if (!hose) return -ENOMEM; @@ -300,7 +300,7 @@ int __init mpc83xx_add_bridge(struct device_node *dev) " bus 0\n", dev->full_name); } - ppc_pci_flags |= PPC_PCI_REASSIGN_ALL_BUS; + ppc_pci_add_flags(PPC_PCI_REASSIGN_ALL_BUS); hose = pcibios_alloc_controller(dev); if (!hose) return -ENOMEM; diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index 26ecb96f9731dec733b23e6368fb3e0f6cf6d629..115cb16351fd97b3dfcac78fca07634f0f0ba8eb 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c @@ -207,236 +207,51 @@ static int __init of_add_fixed_phys(void) arch_initcall(of_add_fixed_phys); #endif /* CONFIG_FIXED_PHY */ -static int gfar_mdio_of_init_one(struct device_node *np) -{ - int k; - struct device_node *child = NULL; - struct gianfar_mdio_data mdio_data; - struct platform_device *mdio_dev; - struct resource res; - int ret; - - memset(&res, 0, sizeof(res)); - memset(&mdio_data, 0, sizeof(mdio_data)); - - ret = of_address_to_resource(np, 0, &res); - if (ret) - return ret; - - /* The gianfar device will try to use the same ID created below to find - * this bus, to coordinate register access (since they share). */ - mdio_dev = platform_device_register_simple("fsl-gianfar_mdio", - res.start&0xfffff, &res, 1); - if (IS_ERR(mdio_dev)) - return PTR_ERR(mdio_dev); - - for (k = 0; k < 32; k++) - mdio_data.irq[k] = PHY_POLL; - - while ((child = of_get_next_child(np, child)) != NULL) { - int irq = irq_of_parse_and_map(child, 0); - if (irq != NO_IRQ) { - const u32 *id = of_get_property(child, "reg", NULL); - mdio_data.irq[*id] = irq; - } - } - - ret = platform_device_add_data(mdio_dev, &mdio_data, - sizeof(struct gianfar_mdio_data)); - if (ret) - platform_device_unregister(mdio_dev); - - return ret; -} - -static int __init gfar_mdio_of_init(void) -{ - struct device_node *np = NULL; - - for_each_compatible_node(np, NULL, "fsl,gianfar-mdio") - gfar_mdio_of_init_one(np); - - /* try the deprecated version */ - for_each_compatible_node(np, "mdio", "gianfar"); - gfar_mdio_of_init_one(np); - - return 0; -} - -arch_initcall(gfar_mdio_of_init); - -static const char *gfar_tx_intr = "tx"; -static const char *gfar_rx_intr = "rx"; -static const char *gfar_err_intr = "error"; - -static int __init gfar_of_init(void) +#ifdef CONFIG_PPC_83xx +static int __init mpc83xx_wdt_init(void) { + struct resource r; struct device_node *np; - unsigned int i; - struct platform_device *gfar_dev; - struct resource res; + struct platform_device *dev; + u32 freq = fsl_get_sys_freq(); int ret; - for (np = NULL, i = 0; - (np = of_find_compatible_node(np, "network", "gianfar")) != NULL; - i++) { - struct resource r[4]; - struct device_node *phy, *mdio; - struct gianfar_platform_data gfar_data; - const unsigned int *id; - const char *model; - const char *ctype; - const void *mac_addr; - const phandle *ph; - int n_res = 2; - - if (!of_device_is_available(np)) - continue; - - memset(r, 0, sizeof(r)); - memset(&gfar_data, 0, sizeof(gfar_data)); - - ret = of_address_to_resource(np, 0, &r[0]); - if (ret) - goto err; - - of_irq_to_resource(np, 0, &r[1]); - - model = of_get_property(np, "model", NULL); - - /* If we aren't the FEC we have multiple interrupts */ - if (model && strcasecmp(model, "FEC")) { - r[1].name = gfar_tx_intr; - - r[2].name = gfar_rx_intr; - of_irq_to_resource(np, 1, &r[2]); + np = of_find_compatible_node(NULL, "watchdog", "mpc83xx_wdt"); - r[3].name = gfar_err_intr; - of_irq_to_resource(np, 2, &r[3]); - - n_res += 2; - } - - gfar_dev = - platform_device_register_simple("fsl-gianfar", i, &r[0], - n_res); - - if (IS_ERR(gfar_dev)) { - ret = PTR_ERR(gfar_dev); - goto err; - } - - mac_addr = of_get_mac_address(np); - if (mac_addr) - memcpy(gfar_data.mac_addr, mac_addr, 6); - - if (model && !strcasecmp(model, "TSEC")) - gfar_data.device_flags = - FSL_GIANFAR_DEV_HAS_GIGABIT | - FSL_GIANFAR_DEV_HAS_COALESCE | - FSL_GIANFAR_DEV_HAS_RMON | - FSL_GIANFAR_DEV_HAS_MULTI_INTR; - if (model && !strcasecmp(model, "eTSEC")) - gfar_data.device_flags = - FSL_GIANFAR_DEV_HAS_GIGABIT | - FSL_GIANFAR_DEV_HAS_COALESCE | - FSL_GIANFAR_DEV_HAS_RMON | - FSL_GIANFAR_DEV_HAS_MULTI_INTR | - FSL_GIANFAR_DEV_HAS_CSUM | - FSL_GIANFAR_DEV_HAS_VLAN | - FSL_GIANFAR_DEV_HAS_EXTENDED_HASH; - - ctype = of_get_property(np, "phy-connection-type", NULL); - - /* We only care about rgmii-id. The rest are autodetected */ - if (ctype && !strcmp(ctype, "rgmii-id")) - gfar_data.interface = PHY_INTERFACE_MODE_RGMII_ID; - else - gfar_data.interface = PHY_INTERFACE_MODE_MII; - - if (of_get_property(np, "fsl,magic-packet", NULL)) - gfar_data.device_flags |= FSL_GIANFAR_DEV_HAS_MAGIC_PACKET; - - ph = of_get_property(np, "phy-handle", NULL); - if (ph == NULL) { - u32 *fixed_link; - - fixed_link = (u32 *)of_get_property(np, "fixed-link", - NULL); - if (!fixed_link) { - ret = -ENODEV; - goto unreg; - } - - snprintf(gfar_data.bus_id, MII_BUS_ID_SIZE, "0"); - gfar_data.phy_id = fixed_link[0]; - } else { - phy = of_find_node_by_phandle(*ph); - - if (phy == NULL) { - ret = -ENODEV; - goto unreg; - } - - mdio = of_get_parent(phy); - - id = of_get_property(phy, "reg", NULL); - ret = of_address_to_resource(mdio, 0, &res); - if (ret) { - of_node_put(phy); - of_node_put(mdio); - goto unreg; - } - - gfar_data.phy_id = *id; - snprintf(gfar_data.bus_id, MII_BUS_ID_SIZE, "%llx", - (unsigned long long)res.start&0xfffff); + if (!np) { + ret = -ENODEV; + goto nodev; + } - of_node_put(phy); - of_node_put(mdio); - } + memset(&r, 0, sizeof(r)); - /* Get MDIO bus controlled by this eTSEC, if any. Normally only - * eTSEC 1 will control an MDIO bus, not necessarily the same - * bus that its PHY is on ('mdio' above), so we can't just use - * that. What we do is look for a gianfar mdio device that has - * overlapping registers with this device. That's really the - * whole point, to find the device sharing our registers to - * coordinate access with it. - */ - for_each_compatible_node(mdio, NULL, "fsl,gianfar-mdio") { - if (of_address_to_resource(mdio, 0, &res)) - continue; - - if (res.start >= r[0].start && res.end <= r[0].end) { - /* Get the ID the mdio bus platform device was - * registered with. gfar_data.bus_id is - * different because it's for finding a PHY, - * while this is for finding a MII bus. - */ - gfar_data.mdio_bus = res.start&0xfffff; - of_node_put(mdio); - break; - } - } + ret = of_address_to_resource(np, 0, &r); + if (ret) + goto err; - ret = - platform_device_add_data(gfar_dev, &gfar_data, - sizeof(struct - gianfar_platform_data)); - if (ret) - goto unreg; + dev = platform_device_register_simple("mpc83xx_wdt", 0, &r, 1); + if (IS_ERR(dev)) { + ret = PTR_ERR(dev); + goto err; } + ret = platform_device_add_data(dev, &freq, sizeof(freq)); + if (ret) + goto unreg; + + of_node_put(np); return 0; unreg: - platform_device_unregister(gfar_dev); + platform_device_unregister(dev); err: + of_node_put(np); +nodev: return ret; } -arch_initcall(gfar_of_init); +arch_initcall(mpc83xx_wdt_init); +#endif static enum fsl_usb2_phy_modes determine_usb_phy(const char *phy_type) { diff --git a/arch/powerpc/sysdev/grackle.c b/arch/powerpc/sysdev/grackle.c index d502927644c68c69a1328c436c2030bed9349f1c..5da37c2f22ee28db96e064aae1172e3b61e4a3c1 100644 --- a/arch/powerpc/sysdev/grackle.c +++ b/arch/powerpc/sysdev/grackle.c @@ -57,7 +57,7 @@ void __init setup_grackle(struct pci_controller *hose) { setup_indirect_pci(hose, 0xfec00000, 0xfee00000, 0); if (machine_is_compatible("PowerMac1,1")) - ppc_pci_flags |= PPC_PCI_REASSIGN_ALL_BUS; + ppc_pci_add_flags(PPC_PCI_REASSIGN_ALL_BUS); if (machine_is_compatible("AAPL,PowerBook1998")) grackle_set_loop_snoop(hose, 1); #if 0 /* Disabled for now, HW problems ??? */ diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 1890fb085cded9bdcc66c61214a4058b579c98e6..c82babb70074963bf4c37f3ead2d0feb4be9bf56 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -661,17 +661,6 @@ static inline void mpic_eoi(struct mpic *mpic) (void)mpic_cpu_read(MPIC_INFO(CPU_WHOAMI)); } -#ifdef CONFIG_SMP -static irqreturn_t mpic_ipi_action(int irq, void *data) -{ - long ipi = (long)data; - - smp_message_recv(ipi); - - return IRQ_HANDLED; -} -#endif /* CONFIG_SMP */ - /* * Linux descriptor level callbacks */ @@ -1548,13 +1537,7 @@ unsigned int mpic_get_mcirq(void) void mpic_request_ipis(void) { struct mpic *mpic = mpic_primary; - long i, err; - static char *ipi_names[] = { - "IPI0 (call function)", - "IPI1 (reschedule)", - "IPI2 (call function single)", - "IPI3 (debugger break)", - }; + int i; BUG_ON(mpic == NULL); printk(KERN_INFO "mpic: requesting IPIs ... \n"); @@ -1563,17 +1546,10 @@ void mpic_request_ipis(void) unsigned int vipi = irq_create_mapping(mpic->irqhost, mpic->ipi_vecs[0] + i); if (vipi == NO_IRQ) { - printk(KERN_ERR "Failed to map IPI %ld\n", i); - break; - } - err = request_irq(vipi, mpic_ipi_action, - IRQF_DISABLED|IRQF_PERCPU, - ipi_names[i], (void *)i); - if (err) { - printk(KERN_ERR "Request of irq %d for IPI %ld failed\n", - vipi, i); - break; + printk(KERN_ERR "Failed to map %s\n", smp_ipi_name[i]); + continue; } + smp_request_message_ipi(vipi, i); } } diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c index d3e4d61030b59039759ad4d4d2eaa9318e32abe0..77fae5f64f2e0741ff6900135f9337cfac6093b0 100644 --- a/arch/powerpc/sysdev/ppc4xx_pci.c +++ b/arch/powerpc/sysdev/ppc4xx_pci.c @@ -194,11 +194,41 @@ static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose, * 4xx PCI 2.x part */ +static int __init ppc4xx_setup_one_pci_PMM(struct pci_controller *hose, + void __iomem *reg, + u64 plb_addr, + u64 pci_addr, + u64 size, + unsigned int flags, + int index) +{ + u32 ma, pcila, pciha; + + if ((plb_addr + size) > 0xffffffffull || !is_power_of_2(size) || + size < 0x1000 || (plb_addr & (size - 1)) != 0) { + printk(KERN_WARNING "%s: Resource out of range\n", + hose->dn->full_name); + return -1; + } + ma = (0xffffffffu << ilog2(size)) | 1; + if (flags & IORESOURCE_PREFETCH) + ma |= 2; + + pciha = RES_TO_U32_HIGH(pci_addr); + pcila = RES_TO_U32_LOW(pci_addr); + + writel(plb_addr, reg + PCIL0_PMM0LA + (0x10 * index)); + writel(pcila, reg + PCIL0_PMM0PCILA + (0x10 * index)); + writel(pciha, reg + PCIL0_PMM0PCIHA + (0x10 * index)); + writel(ma, reg + PCIL0_PMM0MA + (0x10 * index)); + + return 0; +} + static void __init ppc4xx_configure_pci_PMMs(struct pci_controller *hose, void __iomem *reg) { - u32 la, ma, pcila, pciha; - int i, j; + int i, j, found_isa_hole = 0; /* Setup outbound memory windows */ for (i = j = 0; i < 3; i++) { @@ -213,28 +243,29 @@ static void __init ppc4xx_configure_pci_PMMs(struct pci_controller *hose, break; } - /* Calculate register values */ - la = res->start; - pciha = RES_TO_U32_HIGH(res->start - hose->pci_mem_offset); - pcila = RES_TO_U32_LOW(res->start - hose->pci_mem_offset); - - ma = res->end + 1 - res->start; - if (!is_power_of_2(ma) || ma < 0x1000 || ma > 0xffffffffu) { - printk(KERN_WARNING "%s: Resource out of range\n", - hose->dn->full_name); - continue; + /* Configure the resource */ + if (ppc4xx_setup_one_pci_PMM(hose, reg, + res->start, + res->start - hose->pci_mem_offset, + res->end + 1 - res->start, + res->flags, + j) == 0) { + j++; + + /* If the resource PCI address is 0 then we have our + * ISA memory hole + */ + if (res->start == hose->pci_mem_offset) + found_isa_hole = 1; } - ma = (0xffffffffu << ilog2(ma)) | 0x1; - if (res->flags & IORESOURCE_PREFETCH) - ma |= 0x2; - - /* Program register values */ - writel(la, reg + PCIL0_PMM0LA + (0x10 * j)); - writel(pcila, reg + PCIL0_PMM0PCILA + (0x10 * j)); - writel(pciha, reg + PCIL0_PMM0PCIHA + (0x10 * j)); - writel(ma, reg + PCIL0_PMM0MA + (0x10 * j)); - j++; } + + /* Handle ISA memory hole if not already covered */ + if (j <= 2 && !found_isa_hole && hose->isa_mem_size) + if (ppc4xx_setup_one_pci_PMM(hose, reg, hose->isa_mem_phys, 0, + hose->isa_mem_size, 0, j) == 0) + printk(KERN_INFO "%s: Legacy ISA memory support enabled\n", + hose->dn->full_name); } static void __init ppc4xx_configure_pci_PTMs(struct pci_controller *hose, @@ -352,11 +383,52 @@ static void __init ppc4xx_probe_pci_bridge(struct device_node *np) * 4xx PCI-X part */ +static int __init ppc4xx_setup_one_pcix_POM(struct pci_controller *hose, + void __iomem *reg, + u64 plb_addr, + u64 pci_addr, + u64 size, + unsigned int flags, + int index) +{ + u32 lah, lal, pciah, pcial, sa; + + if (!is_power_of_2(size) || size < 0x1000 || + (plb_addr & (size - 1)) != 0) { + printk(KERN_WARNING "%s: Resource out of range\n", + hose->dn->full_name); + return -1; + } + + /* Calculate register values */ + lah = RES_TO_U32_HIGH(plb_addr); + lal = RES_TO_U32_LOW(plb_addr); + pciah = RES_TO_U32_HIGH(pci_addr); + pcial = RES_TO_U32_LOW(pci_addr); + sa = (0xffffffffu << ilog2(size)) | 0x1; + + /* Program register values */ + if (index == 0) { + writel(lah, reg + PCIX0_POM0LAH); + writel(lal, reg + PCIX0_POM0LAL); + writel(pciah, reg + PCIX0_POM0PCIAH); + writel(pcial, reg + PCIX0_POM0PCIAL); + writel(sa, reg + PCIX0_POM0SA); + } else { + writel(lah, reg + PCIX0_POM1LAH); + writel(lal, reg + PCIX0_POM1LAL); + writel(pciah, reg + PCIX0_POM1PCIAH); + writel(pcial, reg + PCIX0_POM1PCIAL); + writel(sa, reg + PCIX0_POM1SA); + } + + return 0; +} + static void __init ppc4xx_configure_pcix_POMs(struct pci_controller *hose, void __iomem *reg) { - u32 lah, lal, pciah, pcial, sa; - int i, j; + int i, j, found_isa_hole = 0; /* Setup outbound memory windows */ for (i = j = 0; i < 3; i++) { @@ -371,36 +443,29 @@ static void __init ppc4xx_configure_pcix_POMs(struct pci_controller *hose, break; } - /* Calculate register values */ - lah = RES_TO_U32_HIGH(res->start); - lal = RES_TO_U32_LOW(res->start); - pciah = RES_TO_U32_HIGH(res->start - hose->pci_mem_offset); - pcial = RES_TO_U32_LOW(res->start - hose->pci_mem_offset); - sa = res->end + 1 - res->start; - if (!is_power_of_2(sa) || sa < 0x100000 || - sa > 0xffffffffu) { - printk(KERN_WARNING "%s: Resource out of range\n", - hose->dn->full_name); - continue; + /* Configure the resource */ + if (ppc4xx_setup_one_pcix_POM(hose, reg, + res->start, + res->start - hose->pci_mem_offset, + res->end + 1 - res->start, + res->flags, + j) == 0) { + j++; + + /* If the resource PCI address is 0 then we have our + * ISA memory hole + */ + if (res->start == hose->pci_mem_offset) + found_isa_hole = 1; } - sa = (0xffffffffu << ilog2(sa)) | 0x1; - - /* Program register values */ - if (j == 0) { - writel(lah, reg + PCIX0_POM0LAH); - writel(lal, reg + PCIX0_POM0LAL); - writel(pciah, reg + PCIX0_POM0PCIAH); - writel(pcial, reg + PCIX0_POM0PCIAL); - writel(sa, reg + PCIX0_POM0SA); - } else { - writel(lah, reg + PCIX0_POM1LAH); - writel(lal, reg + PCIX0_POM1LAL); - writel(pciah, reg + PCIX0_POM1PCIAH); - writel(pcial, reg + PCIX0_POM1PCIAL); - writel(sa, reg + PCIX0_POM1SA); - } - j++; } + + /* Handle ISA memory hole if not already covered */ + if (j <= 1 && !found_isa_hole && hose->isa_mem_size) + if (ppc4xx_setup_one_pcix_POM(hose, reg, hose->isa_mem_phys, 0, + hose->isa_mem_size, 0, j) == 0) + printk(KERN_INFO "%s: Legacy ISA memory support enabled\n", + hose->dn->full_name); } static void __init ppc4xx_configure_pcix_PIMs(struct pci_controller *hose, @@ -1317,12 +1382,72 @@ static struct pci_ops ppc4xx_pciex_pci_ops = .write = ppc4xx_pciex_write_config, }; +static int __init ppc4xx_setup_one_pciex_POM(struct ppc4xx_pciex_port *port, + struct pci_controller *hose, + void __iomem *mbase, + u64 plb_addr, + u64 pci_addr, + u64 size, + unsigned int flags, + int index) +{ + u32 lah, lal, pciah, pcial, sa; + + if (!is_power_of_2(size) || + (index < 2 && size < 0x100000) || + (index == 2 && size < 0x100) || + (plb_addr & (size - 1)) != 0) { + printk(KERN_WARNING "%s: Resource out of range\n", + hose->dn->full_name); + return -1; + } + + /* Calculate register values */ + lah = RES_TO_U32_HIGH(plb_addr); + lal = RES_TO_U32_LOW(plb_addr); + pciah = RES_TO_U32_HIGH(pci_addr); + pcial = RES_TO_U32_LOW(pci_addr); + sa = (0xffffffffu << ilog2(size)) | 0x1; + + /* Program register values */ + switch (index) { + case 0: + out_le32(mbase + PECFG_POM0LAH, pciah); + out_le32(mbase + PECFG_POM0LAL, pcial); + dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAH, lah); + dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAL, lal); + dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKH, 0x7fffffff); + /* Note that 3 here means enabled | single region */ + dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, sa | 3); + break; + case 1: + out_le32(mbase + PECFG_POM1LAH, pciah); + out_le32(mbase + PECFG_POM1LAL, pcial); + dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAH, lah); + dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAL, lal); + dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKH, 0x7fffffff); + /* Note that 3 here means enabled | single region */ + dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKL, sa | 3); + break; + case 2: + out_le32(mbase + PECFG_POM2LAH, pciah); + out_le32(mbase + PECFG_POM2LAL, pcial); + dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAH, lah); + dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAL, lal); + dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKH, 0x7fffffff); + /* Note that 3 here means enabled | IO space !!! */ + dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKL, sa | 3); + break; + } + + return 0; +} + static void __init ppc4xx_configure_pciex_POMs(struct ppc4xx_pciex_port *port, struct pci_controller *hose, void __iomem *mbase) { - u32 lah, lal, pciah, pcial, sa; - int i, j; + int i, j, found_isa_hole = 0; /* Setup outbound memory windows */ for (i = j = 0; i < 3; i++) { @@ -1337,53 +1462,38 @@ static void __init ppc4xx_configure_pciex_POMs(struct ppc4xx_pciex_port *port, break; } - /* Calculate register values */ - lah = RES_TO_U32_HIGH(res->start); - lal = RES_TO_U32_LOW(res->start); - pciah = RES_TO_U32_HIGH(res->start - hose->pci_mem_offset); - pcial = RES_TO_U32_LOW(res->start - hose->pci_mem_offset); - sa = res->end + 1 - res->start; - if (!is_power_of_2(sa) || sa < 0x100000 || - sa > 0xffffffffu) { - printk(KERN_WARNING "%s: Resource out of range\n", - port->node->full_name); - continue; - } - sa = (0xffffffffu << ilog2(sa)) | 0x1; - - /* Program register values */ - switch (j) { - case 0: - out_le32(mbase + PECFG_POM0LAH, pciah); - out_le32(mbase + PECFG_POM0LAL, pcial); - dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAH, lah); - dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAL, lal); - dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKH, 0x7fffffff); - dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, sa | 3); - break; - case 1: - out_le32(mbase + PECFG_POM1LAH, pciah); - out_le32(mbase + PECFG_POM1LAL, pcial); - dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAH, lah); - dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAL, lal); - dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKH, 0x7fffffff); - dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKL, sa | 3); - break; + /* Configure the resource */ + if (ppc4xx_setup_one_pciex_POM(port, hose, mbase, + res->start, + res->start - hose->pci_mem_offset, + res->end + 1 - res->start, + res->flags, + j) == 0) { + j++; + + /* If the resource PCI address is 0 then we have our + * ISA memory hole + */ + if (res->start == hose->pci_mem_offset) + found_isa_hole = 1; } - j++; } - /* Configure IO, always 64K starting at 0 */ - if (hose->io_resource.flags & IORESOURCE_IO) { - lah = RES_TO_U32_HIGH(hose->io_base_phys); - lal = RES_TO_U32_LOW(hose->io_base_phys); - out_le32(mbase + PECFG_POM2LAH, 0); - out_le32(mbase + PECFG_POM2LAL, 0); - dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAH, lah); - dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAL, lal); - dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKH, 0x7fffffff); - dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKL, 0xffff0000 | 3); - } + /* Handle ISA memory hole if not already covered */ + if (j <= 1 && !found_isa_hole && hose->isa_mem_size) + if (ppc4xx_setup_one_pciex_POM(port, hose, mbase, + hose->isa_mem_phys, 0, + hose->isa_mem_size, 0, j) == 0) + printk(KERN_INFO "%s: Legacy ISA memory support enabled\n", + hose->dn->full_name); + + /* Configure IO, always 64K starting at 0. We hard wire it to 64K ! + * Note also that it -has- to be region index 2 on this HW + */ + if (hose->io_resource.flags & IORESOURCE_IO) + ppc4xx_setup_one_pciex_POM(port, hose, mbase, + hose->io_base_phys, 0, + 0x10000, IORESOURCE_IO, 2); } static void __init ppc4xx_configure_pciex_PIMs(struct ppc4xx_pciex_port *port, diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/arch/powerpc/sysdev/qe_lib/qe.c index b3b73ae57d6d6ba96974732f04d81c11956d8fe5..01bce3784b0acb89404c778a9e6ec20cfe0a13d7 100644 --- a/arch/powerpc/sysdev/qe_lib/qe.c +++ b/arch/powerpc/sysdev/qe_lib/qe.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,8 @@ static void qe_snums_init(void); static int qe_sdma_init(void); static DEFINE_SPINLOCK(qe_lock); +DEFINE_SPINLOCK(cmxgcr_lock); +EXPORT_SYMBOL(cmxgcr_lock); /* QE snum state */ enum qe_snum_state { diff --git a/arch/powerpc/sysdev/qe_lib/ucc.c b/arch/powerpc/sysdev/qe_lib/ucc.c index 1d78071aad7d9c80ebaa6a88c78d7cd6752709eb..ebb442ea191770a9dad1d6c69d9a40ac59583a4b 100644 --- a/arch/powerpc/sysdev/qe_lib/ucc.c +++ b/arch/powerpc/sysdev/qe_lib/ucc.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -26,9 +27,6 @@ #include #include -DEFINE_SPINLOCK(cmxgcr_lock); -EXPORT_SYMBOL(cmxgcr_lock); - int ucc_set_qe_mux_mii_mng(unsigned int ucc_num) { unsigned long flags; diff --git a/arch/powerpc/xmon/Makefile b/arch/powerpc/xmon/Makefile index 51d97588e762e6fc9a55cae2d07c6598751343ba..9cb03b71b9d66535dbcb95abe9c44d9910739243 100644 --- a/arch/powerpc/xmon/Makefile +++ b/arch/powerpc/xmon/Makefile @@ -4,7 +4,7 @@ ifdef CONFIG_PPC64 EXTRA_CFLAGS += -mno-minimal-toc endif -obj-y += xmon.o setjmp.o start.o nonstdio.o +obj-y += xmon.o start.o nonstdio.o ifdef CONFIG_XMON_DISASSEMBLY obj-y += ppc-dis.o ppc-opc.o diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index 076368c8b8a95e09f7c5f7cdd1cbf69a012d883c..8dfad7d9a0043298867d6b523347c57457e114b8 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -41,6 +41,7 @@ #include #include #include +#include #ifdef CONFIG_PPC64 #include @@ -159,8 +160,6 @@ static int xmon_no_auto_backtrace; extern void xmon_enter(void); extern void xmon_leave(void); -extern void xmon_save_regs(struct pt_regs *); - #ifdef CONFIG_PPC64 #define REG "%.16lx" #define REGS_PER_LINE 4 @@ -532,7 +531,7 @@ int xmon(struct pt_regs *excp) struct pt_regs regs; if (excp == NULL) { - xmon_save_regs(®s); + ppc_save_regs(®s); excp = ®s; } diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 8116a3328a19dd9b0cc79bbc3cd5b32a10e0234a..8152fefc97b919469f8da42ea2c9b967dd55f049 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -43,6 +43,9 @@ config GENERIC_HWEIGHT config GENERIC_TIME def_bool y +config GENERIC_TIME_VSYSCALL + def_bool y + config GENERIC_CLOCKEVENTS def_bool y @@ -66,10 +69,15 @@ config PGSTE bool default y if KVM +config VIRT_CPU_ACCOUNTING + def_bool y + mainmenu "Linux Kernel Configuration" config S390 def_bool y + select USE_GENERIC_SMP_HELPERS if SMP + select HAVE_FUNCTION_TRACER select HAVE_OPROFILE select HAVE_KPROBES select HAVE_KRETPROBES @@ -225,6 +233,14 @@ config MARCH_Z9_109 Class (z9 BC). The kernel will be slightly faster but will not work on older machines such as the z990, z890, z900, and z800. +config MARCH_Z10 + bool "IBM System z10" + help + Select this to enable optimizations for IBM System z10. The + kernel will be slightly faster but will not work on older + machines such as the z990, z890, z900, z800, z9-109, z9-ec + and z9-bc. + endchoice config PACK_STACK @@ -343,16 +359,6 @@ config QDIO If unsure, say Y. -config QDIO_DEBUG - bool "Extended debugging information" - depends on QDIO - help - Say Y here to get extended debugging output in - /sys/kernel/debug/s390dbf/qdio... - Warning: this option reduces the performance of the QDIO module. - - If unsure, say N. - config CHSC_SCH tristate "Support for CHSC subchannels" help @@ -466,22 +472,9 @@ config PAGE_STATES hypervisor. The ESSA instruction is used to do the states changes between a page that has content and the unused state. -config VIRT_TIMER - bool "Virtual CPU timer support" - help - This provides a kernel interface for virtual CPU timers. - Default is disabled. - -config VIRT_CPU_ACCOUNTING - bool "Base user process accounting on virtual cpu timer" - depends on VIRT_TIMER - help - Select this option to use CPU timer deltas to do user - process accounting. - config APPLDATA_BASE bool "Linux - VM Monitor Stream, base infrastructure" - depends on PROC_FS && VIRT_TIMER=y + depends on PROC_FS help This provides a kernel interface for creating and updating z/VM APPLDATA monitor records. The monitor records are updated at certain time diff --git a/arch/s390/Makefile b/arch/s390/Makefile index 792a4e7743cee19ef0b41d4b896d104df48aa73e..578c61f15a4beff789126dfa98478992e028ca2a 100644 --- a/arch/s390/Makefile +++ b/arch/s390/Makefile @@ -34,6 +34,7 @@ cflags-$(CONFIG_MARCH_G5) += $(call cc-option,-march=g5) cflags-$(CONFIG_MARCH_Z900) += $(call cc-option,-march=z900) cflags-$(CONFIG_MARCH_Z990) += $(call cc-option,-march=z990) cflags-$(CONFIG_MARCH_Z9_109) += $(call cc-option,-march=z9-109) +cflags-$(CONFIG_MARCH_Z10) += $(call cc-option,-march=z10) #KBUILD_IMAGE is necessary for make rpm KBUILD_IMAGE :=arch/s390/boot/image diff --git a/arch/s390/appldata/appldata.h b/arch/s390/appldata/appldata.h index 17a2636fec0a4a2395b5ba67496c504d3c50b550..f0b23fc759ba35db19345bfa86be4dc6cd289859 100644 --- a/arch/s390/appldata/appldata.h +++ b/arch/s390/appldata/appldata.h @@ -26,10 +26,6 @@ #define CTL_APPLDATA_NET_SUM 2125 #define CTL_APPLDATA_PROC 2126 -#define P_INFO(x...) printk(KERN_INFO MY_PRINT_NAME " info: " x) -#define P_ERROR(x...) printk(KERN_ERR MY_PRINT_NAME " error: " x) -#define P_WARNING(x...) printk(KERN_WARNING MY_PRINT_NAME " status: " x) - struct appldata_ops { struct list_head list; struct ctl_table_header *sysctl_header; diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c index a06a47cdd5e06e30efbde7f92b882fd2c948c610..27b70d8a359cd6b9816453626c0fdc6e80789f12 100644 --- a/arch/s390/appldata/appldata_base.c +++ b/arch/s390/appldata/appldata_base.c @@ -10,6 +10,9 @@ * Author: Gerald Schaefer */ +#define KMSG_COMPONENT "appldata" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include @@ -32,7 +35,6 @@ #include "appldata.h" -#define MY_PRINT_NAME "appldata" /* for debug messages, etc. */ #define APPLDATA_CPU_INTERVAL 10000 /* default (CPU) time for sampling interval in milliseconds */ @@ -390,8 +392,8 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp, (unsigned long) ops->data, ops->size, ops->mod_lvl); if (rc != 0) { - P_ERROR("START DIAG 0xDC for %s failed, " - "return code: %d\n", ops->name, rc); + pr_err("Starting the data collection for %s " + "failed with rc=%d\n", ops->name, rc); module_put(ops->owner); } else ops->active = 1; @@ -401,8 +403,8 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp, (unsigned long) ops->data, ops->size, ops->mod_lvl); if (rc != 0) - P_ERROR("STOP DIAG 0xDC for %s failed, " - "return code: %d\n", ops->name, rc); + pr_err("Stopping the data collection for %s " + "failed with rc=%d\n", ops->name, rc); module_put(ops->owner); } spin_unlock(&appldata_ops_lock); diff --git a/arch/s390/appldata/appldata_net_sum.c b/arch/s390/appldata/appldata_net_sum.c index 3b746556e1a39ddce7dcac254538c521b3e835a1..fa741f84c5b9b639b5bbadc1adf4893daa50d6e4 100644 --- a/arch/s390/appldata/appldata_net_sum.c +++ b/arch/s390/appldata/appldata_net_sum.c @@ -67,7 +67,6 @@ static void appldata_get_net_sum_data(void *data) int i; struct appldata_net_sum_data *net_data; struct net_device *dev; - struct net_device_stats *stats; unsigned long rx_packets, tx_packets, rx_bytes, tx_bytes, rx_errors, tx_errors, rx_dropped, tx_dropped, collisions; @@ -86,7 +85,8 @@ static void appldata_get_net_sum_data(void *data) collisions = 0; read_lock(&dev_base_lock); for_each_netdev(&init_net, dev) { - stats = dev->get_stats(dev); + const struct net_device_stats *stats = dev_get_stats(dev); + rx_packets += stats->rx_packets; tx_packets += stats->tx_packets; rx_bytes += stats->rx_bytes; diff --git a/arch/s390/appldata/appldata_os.c b/arch/s390/appldata/appldata_os.c index eb44f9f8ab917c85a4d3ea6476408b4c86bb343b..55c80ffd42b9b9ef5a4fb7e3768c4b2deb462e83 100644 --- a/arch/s390/appldata/appldata_os.c +++ b/arch/s390/appldata/appldata_os.c @@ -9,6 +9,9 @@ * Author: Gerald Schaefer */ +#define KMSG_COMPONENT "appldata" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include @@ -22,7 +25,6 @@ #include "appldata.h" -#define MY_PRINT_NAME "appldata_os" /* for debug messages, etc. */ #define LOAD_INT(x) ((x) >> FSHIFT) #define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100) @@ -143,21 +145,16 @@ static void appldata_get_os_data(void *data) (unsigned long) ops.data, new_size, ops.mod_lvl); if (rc != 0) - P_ERROR("os: START NEW DIAG 0xDC failed, " - "return code: %d, new size = %i\n", rc, - new_size); + pr_err("Starting a new OS data collection " + "failed with rc=%d\n", rc); rc = appldata_diag(APPLDATA_RECORD_OS_ID, APPLDATA_STOP_REC, (unsigned long) ops.data, ops.size, ops.mod_lvl); if (rc != 0) - P_ERROR("os: STOP OLD DIAG 0xDC failed, " - "return code: %d, old size = %i\n", rc, - ops.size); - else - P_INFO("os: old record size = %i stopped\n", - ops.size); + pr_err("Stopping a faulty OS data " + "collection failed with rc=%d\n", rc); } ops.size = new_size; } @@ -178,8 +175,8 @@ static int __init appldata_os_init(void) max_size = sizeof(struct appldata_os_data) + (NR_CPUS * sizeof(struct appldata_os_per_cpu)); if (max_size > APPLDATA_MAX_REC_SIZE) { - P_ERROR("Max. size of OS record = %i, bigger than maximum " - "record size (%i)\n", max_size, APPLDATA_MAX_REC_SIZE); + pr_err("Maximum OS record size %i exceeds the maximum " + "record size %i\n", max_size, APPLDATA_MAX_REC_SIZE); rc = -ENOMEM; goto out; } diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c index e33f32b54c080392f1cf1620fdf4ff86a083b041..c42cd898f68bfdece3e98706e44ab048abe61038 100644 --- a/arch/s390/crypto/aes_s390.c +++ b/arch/s390/crypto/aes_s390.c @@ -17,6 +17,9 @@ * */ +#define KMSG_COMPONENT "aes_s390" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include @@ -169,7 +172,8 @@ static int fallback_init_cip(struct crypto_tfm *tfm) CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK); if (IS_ERR(sctx->fallback.cip)) { - printk(KERN_ERR "Error allocating fallback algo %s\n", name); + pr_err("Allocating AES fallback algorithm %s failed\n", + name); return PTR_ERR(sctx->fallback.blk); } @@ -349,7 +353,8 @@ static int fallback_init_blk(struct crypto_tfm *tfm) CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK); if (IS_ERR(sctx->fallback.blk)) { - printk(KERN_ERR "Error allocating fallback algo %s\n", name); + pr_err("Allocating AES fallback algorithm %s failed\n", + name); return PTR_ERR(sctx->fallback.blk); } @@ -515,9 +520,8 @@ static int __init aes_s390_init(void) /* z9 109 and z9 BC/EC only support 128 bit key length */ if (keylen_flag == AES_KEYLEN_128) - printk(KERN_INFO - "aes_s390: hardware acceleration only available for " - "128 bit keys\n"); + pr_info("AES hardware acceleration is only available for" + " 128-bit keys\n"); ret = crypto_register_alg(&aes_alg); if (ret) diff --git a/arch/s390/hypfs/hypfs_diag.c b/arch/s390/hypfs/hypfs_diag.c index b9a1ce1f28e488e25ab251350316475f1f114395..b1e892a43816974660b7fc73f8ecd085a83b41de 100644 --- a/arch/s390/hypfs/hypfs_diag.c +++ b/arch/s390/hypfs/hypfs_diag.c @@ -3,10 +3,13 @@ * Hypervisor filesystem for Linux on s390. Diag 204 and 224 * implementation. * - * Copyright (C) IBM Corp. 2006 + * Copyright IBM Corp. 2006, 2008 * Author(s): Michael Holzheu */ +#define KMSG_COMPONENT "hypfs" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include @@ -527,13 +530,14 @@ __init int hypfs_diag_init(void) int rc; if (diag204_probe()) { - printk(KERN_ERR "hypfs: diag 204 not working."); + pr_err("The hardware system does not support hypfs\n"); return -ENODATA; } rc = diag224_get_name_table(); if (rc) { diag204_free_buffer(); - printk(KERN_ERR "hypfs: could not get name table.\n"); + pr_err("The hardware system does not provide all " + "functions required by hypfs\n"); } return rc; } diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index 36313801cd5cf29e49d5c2c4d9c4e7a9cd12c104..9d4f8e6c0800e635c8f10b69b9b81400409b75a9 100644 --- a/arch/s390/hypfs/inode.c +++ b/arch/s390/hypfs/inode.c @@ -2,10 +2,13 @@ * arch/s390/hypfs/inode.c * Hypervisor filesystem for Linux on s390. * - * Copyright (C) IBM Corp. 2006 + * Copyright IBM Corp. 2006, 2008 * Author(s): Michael Holzheu */ +#define KMSG_COMPONENT "hypfs" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include @@ -200,7 +203,7 @@ static ssize_t hypfs_aio_write(struct kiocb *iocb, const struct iovec *iov, else rc = hypfs_diag_create_files(sb, sb->s_root); if (rc) { - printk(KERN_ERR "hypfs: Update failed\n"); + pr_err("Updating the hypfs tree failed\n"); hypfs_delete_tree(sb->s_root); goto out; } @@ -252,8 +255,7 @@ static int hypfs_parse_options(char *options, struct super_block *sb) break; case opt_err: default: - printk(KERN_ERR "hypfs: Unrecognized mount option " - "\"%s\" or missing value\n", str); + pr_err("%s is not a valid mount option\n", str); return -EINVAL; } } @@ -280,8 +282,8 @@ static int hypfs_fill_super(struct super_block *sb, void *data, int silent) if (!sbi) return -ENOMEM; mutex_init(&sbi->lock); - sbi->uid = current->uid; - sbi->gid = current->gid; + sbi->uid = current_uid(); + sbi->gid = current_gid(); sb->s_fs_info = sbi; sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; @@ -317,7 +319,7 @@ static int hypfs_fill_super(struct super_block *sb, void *data, int silent) } hypfs_update_update(sb); sb->s_root = root_dentry; - printk(KERN_INFO "hypfs: Hypervisor filesystem mounted\n"); + pr_info("Hypervisor filesystem mounted\n"); return 0; err_tree: @@ -513,7 +515,7 @@ static int __init hypfs_init(void) if (!MACHINE_IS_VM) hypfs_diag_exit(); fail_diag: - printk(KERN_ERR "hypfs: Initialization failed with rc = %i.\n", rc); + pr_err("Initialization of hypfs failed with rc=%i\n", rc); return rc; } diff --git a/arch/s390/include/asm/auxvec.h b/arch/s390/include/asm/auxvec.h index 0d340720fd994486c3effd9272a450010b804710..a1f153e89133935f567d6029c0a196efe780b6b8 100644 --- a/arch/s390/include/asm/auxvec.h +++ b/arch/s390/include/asm/auxvec.h @@ -1,4 +1,6 @@ #ifndef __ASMS390_AUXVEC_H #define __ASMS390_AUXVEC_H +#define AT_SYSINFO_EHDR 33 + #endif diff --git a/arch/s390/include/asm/bug.h b/arch/s390/include/asm/bug.h index 384e3621e3418055feb30164c207f058cf746c58..7efd0abe88871dc494e26adc1ef5b31b7edffcb4 100644 --- a/arch/s390/include/asm/bug.h +++ b/arch/s390/include/asm/bug.h @@ -47,7 +47,10 @@ #endif /* CONFIG_DEBUG_BUGVERBOSE */ -#define BUG() __EMIT_BUG(0) +#define BUG() do { \ + __EMIT_BUG(0); \ + for (;;); \ +} while (0) #define WARN_ON(x) ({ \ int __ret_warn_on = !!(x); \ diff --git a/arch/s390/include/asm/byteorder.h b/arch/s390/include/asm/byteorder.h index 1fe2492baa8d141414c66f343f6ddae3e30eeed5..8bcf277c84680a14e9403c4f113ebf7627016cf3 100644 --- a/arch/s390/include/asm/byteorder.h +++ b/arch/s390/include/asm/byteorder.h @@ -11,32 +11,39 @@ #include -#ifdef __GNUC__ +#define __BIG_ENDIAN + +#ifndef __s390x__ +# define __SWAB_64_THRU_32__ +#endif #ifdef __s390x__ -static inline __u64 ___arch__swab64p(const __u64 *x) +static inline __u64 __arch_swab64p(const __u64 *x) { __u64 result; asm volatile("lrvg %0,%1" : "=d" (result) : "m" (*x)); return result; } +#define __arch_swab64p __arch_swab64p -static inline __u64 ___arch__swab64(__u64 x) +static inline __u64 __arch_swab64(__u64 x) { __u64 result; asm volatile("lrvgr %0,%1" : "=d" (result) : "d" (x)); return result; } +#define __arch_swab64 __arch_swab64 -static inline void ___arch__swab64s(__u64 *x) +static inline void __arch_swab64s(__u64 *x) { - *x = ___arch__swab64p(x); + *x = __arch_swab64p(x); } +#define __arch_swab64s __arch_swab64s #endif /* __s390x__ */ -static inline __u32 ___arch__swab32p(const __u32 *x) +static inline __u32 __arch_swab32p(const __u32 *x) { __u32 result; @@ -53,25 +60,20 @@ static inline __u32 ___arch__swab32p(const __u32 *x) #endif /* __s390x__ */ return result; } +#define __arch_swab32p __arch_swab32p -static inline __u32 ___arch__swab32(__u32 x) +#ifdef __s390x__ +static inline __u32 __arch_swab32(__u32 x) { -#ifndef __s390x__ - return ___arch__swab32p(&x); -#else /* __s390x__ */ __u32 result; asm volatile("lrvr %0,%1" : "=d" (result) : "d" (x)); return result; -#endif /* __s390x__ */ -} - -static __inline__ void ___arch__swab32s(__u32 *x) -{ - *x = ___arch__swab32p(x); } +#define __arch_swab32 __arch_swab32 +#endif /* __s390x__ */ -static __inline__ __u16 ___arch__swab16p(const __u16 *x) +static inline __u16 __arch_swab16p(const __u16 *x) { __u16 result; @@ -86,40 +88,8 @@ static __inline__ __u16 ___arch__swab16p(const __u16 *x) #endif /* __s390x__ */ return result; } +#define __arch_swab16p __arch_swab16p -static __inline__ __u16 ___arch__swab16(__u16 x) -{ - return ___arch__swab16p(&x); -} - -static __inline__ void ___arch__swab16s(__u16 *x) -{ - *x = ___arch__swab16p(x); -} - -#ifdef __s390x__ -#define __arch__swab64(x) ___arch__swab64(x) -#define __arch__swab64p(x) ___arch__swab64p(x) -#define __arch__swab64s(x) ___arch__swab64s(x) -#endif /* __s390x__ */ -#define __arch__swab32(x) ___arch__swab32(x) -#define __arch__swab16(x) ___arch__swab16(x) -#define __arch__swab32p(x) ___arch__swab32p(x) -#define __arch__swab16p(x) ___arch__swab16p(x) -#define __arch__swab32s(x) ___arch__swab32s(x) -#define __arch__swab16s(x) ___arch__swab16s(x) - -#ifndef __s390x__ -#if !defined(__STRICT_ANSI__) || defined(__KERNEL__) -# define __BYTEORDER_HAS_U64__ -# define __SWAB_64_THRU_32__ -#endif -#else /* __s390x__ */ -#define __BYTEORDER_HAS_U64__ -#endif /* __s390x__ */ - -#endif /* __GNUC__ */ - -#include +#include #endif /* _S390_BYTEORDER_H */ diff --git a/arch/s390/include/asm/elf.h b/arch/s390/include/asm/elf.h index 261785ab5b2248f41e274fb8ec93d03e0f4d2f76..d480f39d65e647d74da4c5ae1f97c81c3e3c8e7b 100644 --- a/arch/s390/include/asm/elf.h +++ b/arch/s390/include/asm/elf.h @@ -120,6 +120,10 @@ typedef s390_compat_regs compat_elf_gregset_t; #include /* for save_access_regs */ #include +#include + +extern unsigned int vdso_enabled; + /* * This is used to ensure we don't load something for the wrong architecture. */ @@ -191,4 +195,16 @@ do { \ current->mm->context.noexec == 0; \ }) +#define ARCH_DLINFO \ +do { \ + if (vdso_enabled) \ + NEW_AUX_ENT(AT_SYSINFO_EHDR, \ + (unsigned long)current->mm->context.vdso_base); \ +} while (0) + +struct linux_binprm; + +#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1 +int arch_setup_additional_pages(struct linux_binprm *, int); + #endif diff --git a/arch/s390/include/asm/fcx.h b/arch/s390/include/asm/fcx.h index 8be1f3a58042fb7ef18b8b90472161675c165e1b..ef61709950765bbdd72879c473b49d509c7adf0a 100644 --- a/arch/s390/include/asm/fcx.h +++ b/arch/s390/include/asm/fcx.h @@ -248,8 +248,8 @@ struct dcw { #define TCCB_MAX_SIZE (sizeof(struct tccb_tcah) + \ TCCB_MAX_DCW * sizeof(struct dcw) + \ sizeof(struct tccb_tcat)) -#define TCCB_SAC_DEFAULT 0xf901 -#define TCCB_SAC_INTRG 0xf902 +#define TCCB_SAC_DEFAULT 0x1ffe +#define TCCB_SAC_INTRG 0x1fff /** * struct tccb_tcah - Transport-Command-Area Header (TCAH) diff --git a/arch/s390/include/asm/ftrace.h b/arch/s390/include/asm/ftrace.h new file mode 100644 index 0000000000000000000000000000000000000000..5a5bc75e19d4a3f94866a4da9ef31cf13b942356 --- /dev/null +++ b/arch/s390/include/asm/ftrace.h @@ -0,0 +1,8 @@ +#ifndef _ASM_S390_FTRACE_H +#define _ASM_S390_FTRACE_H + +#ifndef __ASSEMBLY__ +extern void _mcount(void); +#endif + +#endif /* _ASM_S390_FTRACE_H */ diff --git a/arch/s390/include/asm/isc.h b/arch/s390/include/asm/isc.h index 34bb8916db4ff17aff88f27d9680c9f8121f37a7..1420a111594816e18eb8fba6b60168dc63fb13c3 100644 --- a/arch/s390/include/asm/isc.h +++ b/arch/s390/include/asm/isc.h @@ -17,6 +17,7 @@ #define CHSC_SCH_ISC 7 /* CHSC subchannels */ /* Adapter interrupts. */ #define QDIO_AIRQ_ISC IO_SCH_ISC /* I/O subchannel in qdio mode */ +#define AP_ISC 6 /* adjunct processor (crypto) devices */ /* Functions for registration of I/O interruption subclasses */ void isc_register(unsigned int isc); diff --git a/arch/s390/include/asm/mmu.h b/arch/s390/include/asm/mmu.h index d2b4ff831477555abdee98cf7eb2de2873864524..3b59216e6284d861952b8c52150c3c827e1f0dd8 100644 --- a/arch/s390/include/asm/mmu.h +++ b/arch/s390/include/asm/mmu.h @@ -6,6 +6,7 @@ typedef struct { struct list_head pgtable_list; unsigned long asce_bits; unsigned long asce_limit; + unsigned long vdso_base; int noexec; int has_pgste; /* The mmu context has extended page tables */ int alloc_pgste; /* cloned contexts will have extended page tables */ diff --git a/arch/s390/include/asm/page.h b/arch/s390/include/asm/page.h index 991ba939408c5f9c6b1f9bcdfbc159e715f13554..32e8f6aa4384245892a6523943d7819f0c808cb6 100644 --- a/arch/s390/include/asm/page.h +++ b/arch/s390/include/asm/page.h @@ -152,4 +152,6 @@ void arch_alloc_page(struct page *page, int order); #include #include +#define __HAVE_ARCH_GATE_AREA 1 + #endif /* _S390_PAGE_H */ diff --git a/arch/s390/include/asm/pgalloc.h b/arch/s390/include/asm/pgalloc.h index f5b2bf3d7c1d4b7a103e3a1089360be7669cb848..b2658b9220fee47d9512c7b01346474c321f3457 100644 --- a/arch/s390/include/asm/pgalloc.h +++ b/arch/s390/include/asm/pgalloc.h @@ -28,6 +28,8 @@ void disable_noexec(struct mm_struct *, struct task_struct *); static inline void clear_table(unsigned long *s, unsigned long val, size_t n) { + typedef struct { char _[n]; } addrtype; + *s = val; n = (n / 256) - 1; asm volatile( @@ -39,7 +41,8 @@ static inline void clear_table(unsigned long *s, unsigned long val, size_t n) "0: mvc 256(256,%0),0(%0)\n" " la %0,256(%0)\n" " brct %1,0b\n" - : "+a" (s), "+d" (n)); + : "+a" (s), "+d" (n), "=m" (*(addrtype *) s) + : "m" (*(addrtype *) s)); } static inline void crst_table_init(unsigned long *crst, unsigned long entry) diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index 4af80af2a88f8c84ef5af5e2e94145b7537ff377..066b99502e090020e4f08cfc5bd37e03cad38962 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h @@ -13,6 +13,7 @@ #ifndef __ASM_S390_PROCESSOR_H #define __ASM_S390_PROCESSOR_H +#include #include #ifdef __KERNEL__ @@ -258,7 +259,7 @@ static inline void enabled_wait(void) * Function to drop a processor into disabled wait state */ -static inline void disabled_wait(unsigned long code) +static inline void ATTRIB_NORET disabled_wait(unsigned long code) { unsigned long ctl_buf; psw_t dw_psw; @@ -322,6 +323,7 @@ static inline void disabled_wait(unsigned long code) : "=m" (ctl_buf) : "a" (&dw_psw), "a" (&ctl_buf), "m" (dw_psw) : "cc", "0"); #endif /* __s390x__ */ + while (1); } /* diff --git a/arch/s390/include/asm/qdio.h b/arch/s390/include/asm/qdio.h index 4734c3f053546fe3b68f1d3987fbd4e96d0f96f3..27fc1746de1578a7611f97ce92e252d2227ed3c4 100644 --- a/arch/s390/include/asm/qdio.h +++ b/arch/s390/include/asm/qdio.h @@ -373,16 +373,16 @@ struct qdio_initialize { #define QDIO_FLAG_SYNC_OUTPUT 0x02 #define QDIO_FLAG_PCI_OUT 0x10 -extern int qdio_initialize(struct qdio_initialize *init_data); -extern int qdio_allocate(struct qdio_initialize *init_data); -extern int qdio_establish(struct qdio_initialize *init_data); +extern int qdio_initialize(struct qdio_initialize *); +extern int qdio_allocate(struct qdio_initialize *); +extern int qdio_establish(struct qdio_initialize *); extern int qdio_activate(struct ccw_device *); -extern int do_QDIO(struct ccw_device*, unsigned int flags, - int q_nr, int qidx, int count); -extern int qdio_cleanup(struct ccw_device*, int how); -extern int qdio_shutdown(struct ccw_device*, int how); +extern int do_QDIO(struct ccw_device *cdev, unsigned int callflags, + int q_nr, int bufnr, int count); +extern int qdio_cleanup(struct ccw_device*, int); +extern int qdio_shutdown(struct ccw_device*, int); extern int qdio_free(struct ccw_device *); -extern struct qdio_ssqd_desc *qdio_get_ssqd_desc(struct ccw_device *cdev); +extern int qdio_get_ssqd_desc(struct ccw_device *dev, struct qdio_ssqd_desc*); #endif /* __QDIO_H__ */ diff --git a/arch/s390/include/asm/sigp.h b/arch/s390/include/asm/sigp.h index e16d56f8dfe1dd01864c3993c60a2f0a43757799..ec403d4304f81c64d2fa2818187ba9731ef49944 100644 --- a/arch/s390/include/asm/sigp.h +++ b/arch/s390/include/asm/sigp.h @@ -61,6 +61,7 @@ typedef enum { ec_schedule=0, ec_call_function, + ec_call_function_single, ec_bit_last } ec_bit_sig; diff --git a/arch/s390/include/asm/smp.h b/arch/s390/include/asm/smp.h index ae89cf2478fcabee3a0e4acf1834465286a9224e..024b91e06239293b38be4f6598a81631eebd4702 100644 --- a/arch/s390/include/asm/smp.h +++ b/arch/s390/include/asm/smp.h @@ -91,8 +91,9 @@ extern int __cpu_up (unsigned int cpu); extern struct mutex smp_cpu_state_mutex; extern int smp_cpu_polarization[]; -extern int smp_call_function_mask(cpumask_t mask, void (*func)(void *), - void *info, int wait); +extern void arch_send_call_function_single_ipi(int cpu); +extern void arch_send_call_function_ipi(cpumask_t mask); + #endif #ifndef CONFIG_SMP diff --git a/arch/s390/include/asm/sysinfo.h b/arch/s390/include/asm/sysinfo.h index 79d01343f8b0681c41b3eff67ccd33f6d1686b06..ad93212d9e16a3099087f846edb942612de0694c 100644 --- a/arch/s390/include/asm/sysinfo.h +++ b/arch/s390/include/asm/sysinfo.h @@ -118,4 +118,15 @@ static inline int stsi(void *sysinfo, int fc, int sel1, int sel2) return r0; } +/* + * Service level reporting interface. + */ +struct service_level { + struct list_head list; + void (*seq_print)(struct seq_file *, struct service_level *); +}; + +int register_service_level(struct service_level *); +int unregister_service_level(struct service_level *); + #endif /* __ASM_S390_SYSINFO_H */ diff --git a/arch/s390/include/asm/system.h b/arch/s390/include/asm/system.h index 819e7d99ca0c4b0180c4909f0c911c7a810a9988..024ef42ed6d73e44d510466680f7fbc54710b05c 100644 --- a/arch/s390/include/asm/system.h +++ b/arch/s390/include/asm/system.h @@ -12,6 +12,7 @@ #define __ASM_SYSTEM_H #include +#include #include #include #include @@ -98,13 +99,9 @@ static inline void restore_access_regs(unsigned int *acrs) prev = __switch_to(prev,next); \ } while (0) -#ifdef CONFIG_VIRT_CPU_ACCOUNTING extern void account_vtime(struct task_struct *); extern void account_tick_vtime(struct task_struct *); extern void account_system_vtime(struct task_struct *); -#else -#define account_vtime(x) do { /* empty */ } while (0) -#endif #ifdef CONFIG_PFAULT extern void pfault_irq_init(void); @@ -413,8 +410,6 @@ __set_psw_mask(unsigned long mask) #define local_mcck_enable() __set_psw_mask(psw_kernel_bits) #define local_mcck_disable() __set_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK) -int stfle(unsigned long long *list, int doublewords); - #ifdef CONFIG_SMP extern void smp_ctl_set_bit(int cr, int bit); @@ -438,6 +433,23 @@ static inline unsigned int stfl(void) return S390_lowcore.stfl_fac_list; } +static inline int __stfle(unsigned long long *list, int doublewords) +{ + typedef struct { unsigned long long _[doublewords]; } addrtype; + register unsigned long __nr asm("0") = doublewords - 1; + + asm volatile(".insn s,0xb2b00000,%0" /* stfle */ + : "=m" (*(addrtype *) list), "+d" (__nr) : : "cc"); + return __nr + 1; +} + +static inline int stfle(unsigned long long *list, int doublewords) +{ + if (!(stfl() & (1UL << 24))) + return -EOPNOTSUPP; + return __stfle(list, doublewords); +} + static inline unsigned short stap(void) { unsigned short cpu_address; diff --git a/arch/s390/include/asm/timer.h b/arch/s390/include/asm/timer.h index d98d79e35cd6f6d6459110b6a0290e5fe59721d4..61705d60f9955a2dc0d217a445b8be6f0a34b174 100644 --- a/arch/s390/include/asm/timer.h +++ b/arch/s390/include/asm/timer.h @@ -48,18 +48,9 @@ extern int del_virt_timer(struct vtimer_list *timer); extern void init_cpu_vtimer(void); extern void vtime_init(void); -#ifdef CONFIG_VIRT_TIMER - extern void vtime_start_cpu_timer(void); extern void vtime_stop_cpu_timer(void); -#else - -static inline void vtime_start_cpu_timer(void) { } -static inline void vtime_stop_cpu_timer(void) { } - -#endif /* CONFIG_VIRT_TIMER */ - #endif /* __KERNEL__ */ #endif /* _ASM_S390_TIMER_H */ diff --git a/arch/s390/include/asm/vdso.h b/arch/s390/include/asm/vdso.h new file mode 100644 index 0000000000000000000000000000000000000000..a44f4fe16a352286eb66b44fdd7e8eade17c4398 --- /dev/null +++ b/arch/s390/include/asm/vdso.h @@ -0,0 +1,39 @@ +#ifndef __S390_VDSO_H__ +#define __S390_VDSO_H__ + +#ifdef __KERNEL__ + +/* Default link addresses for the vDSOs */ +#define VDSO32_LBASE 0 +#define VDSO64_LBASE 0 + +#define VDSO_VERSION_STRING LINUX_2.6.26 + +#ifndef __ASSEMBLY__ + +/* + * Note about this structure: + * + * NEVER USE THIS IN USERSPACE CODE DIRECTLY. The layout of this + * structure is supposed to be known only to the function in the vdso + * itself and may change without notice. + */ + +struct vdso_data { + __u64 tb_update_count; /* Timebase atomicity ctr 0x00 */ + __u64 xtime_tod_stamp; /* TOD clock for xtime 0x08 */ + __u64 xtime_clock_sec; /* Kernel time 0x10 */ + __u64 xtime_clock_nsec; /* 0x18 */ + __u64 wtom_clock_sec; /* Wall to monotonic clock 0x20 */ + __u64 wtom_clock_nsec; /* 0x28 */ + __u32 tz_minuteswest; /* Minutes west of Greenwich 0x30 */ + __u32 tz_dsttime; /* Type of dst correction 0x34 */ +}; + +extern struct vdso_data *vdso_data; + +#endif /* __ASSEMBLY__ */ + +#endif /* __KERNEL__ */ + +#endif /* __S390_VDSO_H__ */ diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 50f657e773449e29d1fa2d64ad5c8e87047f9bd2..3edc6c6f258b2a06b9f7bb09591964ebbce7ebd3 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -2,6 +2,11 @@ # Makefile for the linux kernel. # +ifdef CONFIG_FUNCTION_TRACER +# Do not trace early boot code +CFLAGS_REMOVE_early.o = -pg +endif + # # Passing null pointers is ok for smp code, since we access the lowcore here. # @@ -12,9 +17,10 @@ CFLAGS_smp.o := -Wno-nonnull # CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"' -obj-y := bitmap.o traps.o time.o process.o base.o early.o \ - setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ - s390_ext.o debug.o irq.o ipl.o dis.o diag.o mem_detect.o +obj-y := bitmap.o traps.o time.o process.o base.o early.o setup.o \ + processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ + s390_ext.o debug.o irq.o ipl.o dis.o diag.o mem_detect.o \ + vdso.o vtime.o obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o) obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o) @@ -30,12 +36,16 @@ obj-$(CONFIG_COMPAT) += compat_linux.o compat_signal.o \ compat_wrapper.o compat_exec_domain.o \ $(compat-obj-y) -obj-$(CONFIG_VIRT_TIMER) += vtime.o obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_KPROBES) += kprobes.o +obj-$(CONFIG_FUNCTION_TRACER) += mcount.o # Kexec part S390_KEXEC_OBJS := machine_kexec.o crash.o S390_KEXEC_OBJS += $(if $(CONFIG_64BIT),relocate_kernel64.o,relocate_kernel.o) obj-$(CONFIG_KEXEC) += $(S390_KEXEC_OBJS) +# vdso +obj-$(CONFIG_64BIT) += vdso64/ +obj-$(CONFIG_32BIT) += vdso32/ +obj-$(CONFIG_COMPAT) += vdso32/ diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index 3d144e6020c6c5b9ce26ad82742b3d2e7b16d51c..e641f60bac99db29aa252e8cc5b33186277c1cfb 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c @@ -6,6 +6,7 @@ #include #include +#include int main(void) { @@ -38,5 +39,19 @@ int main(void) DEFINE(__SF_BACKCHAIN, offsetof(struct stack_frame, back_chain)); DEFINE(__SF_GPRS, offsetof(struct stack_frame, gprs)); DEFINE(__SF_EMPTY, offsetof(struct stack_frame, empty1)); + BLANK(); + /* timeval/timezone offsets for use by vdso */ + DEFINE(__VDSO_UPD_COUNT, offsetof(struct vdso_data, tb_update_count)); + DEFINE(__VDSO_XTIME_STAMP, offsetof(struct vdso_data, xtime_tod_stamp)); + DEFINE(__VDSO_XTIME_SEC, offsetof(struct vdso_data, xtime_clock_sec)); + DEFINE(__VDSO_XTIME_NSEC, offsetof(struct vdso_data, xtime_clock_nsec)); + DEFINE(__VDSO_WTOM_SEC, offsetof(struct vdso_data, wtom_clock_sec)); + DEFINE(__VDSO_WTOM_NSEC, offsetof(struct vdso_data, wtom_clock_nsec)); + DEFINE(__VDSO_TIMEZONE, offsetof(struct vdso_data, tz_minuteswest)); + /* constants used by the vdso */ + DEFINE(CLOCK_REALTIME, CLOCK_REALTIME); + DEFINE(CLOCK_MONOTONIC, CLOCK_MONOTONIC); + DEFINE(CLOCK_REALTIME_RES, MONOTONIC_RES_NSEC); + return 0; } diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c index 4646382af34f1260a547274d69c4341852fb55fb..6cc87d8c8682c356bcc95311f6a19f1c7504ba4b 100644 --- a/arch/s390/kernel/compat_linux.c +++ b/arch/s390/kernel/compat_linux.c @@ -148,9 +148,9 @@ asmlinkage long sys32_getresuid16(u16 __user *ruid, u16 __user *euid, u16 __user { int retval; - if (!(retval = put_user(high2lowuid(current->uid), ruid)) && - !(retval = put_user(high2lowuid(current->euid), euid))) - retval = put_user(high2lowuid(current->suid), suid); + if (!(retval = put_user(high2lowuid(current->cred->uid), ruid)) && + !(retval = put_user(high2lowuid(current->cred->euid), euid))) + retval = put_user(high2lowuid(current->cred->suid), suid); return retval; } @@ -165,9 +165,9 @@ asmlinkage long sys32_getresgid16(u16 __user *rgid, u16 __user *egid, u16 __user { int retval; - if (!(retval = put_user(high2lowgid(current->gid), rgid)) && - !(retval = put_user(high2lowgid(current->egid), egid))) - retval = put_user(high2lowgid(current->sgid), sgid); + if (!(retval = put_user(high2lowgid(current->cred->gid), rgid)) && + !(retval = put_user(high2lowgid(current->cred->egid), egid))) + retval = put_user(high2lowgid(current->cred->sgid), sgid); return retval; } @@ -217,20 +217,20 @@ asmlinkage long sys32_getgroups16(int gidsetsize, u16 __user *grouplist) if (gidsetsize < 0) return -EINVAL; - get_group_info(current->group_info); - i = current->group_info->ngroups; + get_group_info(current->cred->group_info); + i = current->cred->group_info->ngroups; if (gidsetsize) { if (i > gidsetsize) { i = -EINVAL; goto out; } - if (groups16_to_user(grouplist, current->group_info)) { + if (groups16_to_user(grouplist, current->cred->group_info)) { i = -EFAULT; goto out; } } out: - put_group_info(current->group_info); + put_group_info(current->cred->group_info); return i; } @@ -261,22 +261,22 @@ asmlinkage long sys32_setgroups16(int gidsetsize, u16 __user *grouplist) asmlinkage long sys32_getuid16(void) { - return high2lowuid(current->uid); + return high2lowuid(current->cred->uid); } asmlinkage long sys32_geteuid16(void) { - return high2lowuid(current->euid); + return high2lowuid(current->cred->euid); } asmlinkage long sys32_getgid16(void) { - return high2lowgid(current->gid); + return high2lowgid(current->cred->gid); } asmlinkage long sys32_getegid16(void) { - return high2lowgid(current->egid); + return high2lowgid(current->cred->egid); } /* diff --git a/arch/s390/kernel/cpcmd.c b/arch/s390/kernel/cpcmd.c index d8c1131e081568927e7f4460aa4febd912c869bf..3e8b8816f309937c6ac5b2af395c346f98e19bb2 100644 --- a/arch/s390/kernel/cpcmd.c +++ b/arch/s390/kernel/cpcmd.c @@ -7,6 +7,9 @@ * Christian Borntraeger (cborntra@de.ibm.com), */ +#define KMSG_COMPONENT "cpcmd" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include @@ -104,8 +107,8 @@ int cpcmd(const char *cmd, char *response, int rlen, int *response_code) (((unsigned long)response + rlen) >> 31)) { lowbuf = kmalloc(rlen, GFP_KERNEL | GFP_DMA); if (!lowbuf) { - printk(KERN_WARNING - "cpcmd: could not allocate response buffer\n"); + pr_warning("The cpcmd kernel function failed to " + "allocate a response buffer\n"); return -ENOMEM; } spin_lock_irqsave(&cpcmd_lock, flags); diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c index d80fcd4a7fe14210aac75d33d824fa9c6eb1c4a7..ba03fc0a3a569777fc3b1936cbe6f54d254d6e34 100644 --- a/arch/s390/kernel/debug.c +++ b/arch/s390/kernel/debug.c @@ -10,6 +10,9 @@ * Bugreports to: */ +#define KMSG_COMPONENT "s390dbf" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include @@ -388,7 +391,7 @@ debug_info_copy(debug_info_t* in, int mode) debug_info_free(rc); } while (1); - if(!rc || (mode == NO_AREAS)) + if (mode == NO_AREAS) goto out; for(i = 0; i < in->nr_areas; i++){ @@ -693,8 +696,8 @@ debug_info_t *debug_register_mode(const char *name, int pages_per_area, /* Since debugfs currently does not support uid/gid other than root, */ /* we do not allow gid/uid != 0 until we get support for that. */ if ((uid != 0) || (gid != 0)) - printk(KERN_WARNING "debug: Warning - Currently only uid/gid " - "= 0 are supported. Using root as owner now!"); + pr_warning("Root becomes the owner of all s390dbf files " + "in sysfs\n"); if (!initialized) BUG(); mutex_lock(&debug_mutex); @@ -709,7 +712,7 @@ debug_info_t *debug_register_mode(const char *name, int pages_per_area, debug_register_view(rc, &debug_pages_view); out: if (!rc){ - printk(KERN_ERR "debug: debug_register failed for %s\n",name); + pr_err("Registering debug feature %s failed\n", name); } mutex_unlock(&debug_mutex); return rc; @@ -763,8 +766,8 @@ debug_set_size(debug_info_t* id, int nr_areas, int pages_per_area) if(pages_per_area > 0){ new_areas = debug_areas_alloc(pages_per_area, nr_areas); if(!new_areas) { - printk(KERN_WARNING "debug: could not allocate memory "\ - "for pagenumber: %i\n",pages_per_area); + pr_info("Allocating memory for %i pages failed\n", + pages_per_area); rc = -ENOMEM; goto out; } @@ -780,8 +783,7 @@ debug_set_size(debug_info_t* id, int nr_areas, int pages_per_area) memset(id->active_entries,0,sizeof(int)*id->nr_areas); memset(id->active_pages, 0, sizeof(int)*id->nr_areas); spin_unlock_irqrestore(&id->lock,flags); - printk(KERN_INFO "debug: %s: set new size (%i pages)\n"\ - ,id->name, pages_per_area); + pr_info("%s: set new size (%i pages)\n" ,id->name, pages_per_area); out: return rc; } @@ -800,10 +802,9 @@ debug_set_level(debug_info_t* id, int new_level) spin_lock_irqsave(&id->lock,flags); if(new_level == DEBUG_OFF_LEVEL){ id->level = DEBUG_OFF_LEVEL; - printk(KERN_INFO "debug: %s: switched off\n",id->name); + pr_info("%s: switched off\n",id->name); } else if ((new_level > DEBUG_MAX_LEVEL) || (new_level < 0)) { - printk(KERN_INFO - "debug: %s: level %i is out of range (%i - %i)\n", + pr_info("%s: level %i is out of range (%i - %i)\n", id->name, new_level, 0, DEBUG_MAX_LEVEL); } else { id->level = new_level; @@ -1108,8 +1109,8 @@ debug_register_view(debug_info_t * id, struct debug_view *view) pde = debugfs_create_file(view->name, mode, id->debugfs_root_entry, id , &debug_file_ops); if (!pde){ - printk(KERN_WARNING "debug: debugfs_create_file() failed!"\ - " Cannot register view %s/%s\n", id->name,view->name); + pr_err("Registering view %s/%s failed due to out of " + "memory\n", id->name,view->name); rc = -1; goto out; } @@ -1119,10 +1120,8 @@ debug_register_view(debug_info_t * id, struct debug_view *view) break; } if (i == DEBUG_MAX_VIEWS) { - printk(KERN_WARNING "debug: cannot register view %s/%s\n", - id->name,view->name); - printk(KERN_WARNING - "debug: maximum number of views reached (%i)!\n", i); + pr_err("Registering view %s/%s would exceed the maximum " + "number of views %i\n", id->name, view->name, i); debugfs_remove(pde); rc = -1; } else { @@ -1303,7 +1302,8 @@ debug_input_level_fn(debug_info_t * id, struct debug_view *view, new_level = debug_get_uint(str); } if(new_level < 0) { - printk(KERN_INFO "debug: level `%s` is not valid\n", str); + pr_warning("%s is not a valid level for a debug " + "feature\n", str); rc = -EINVAL; } else { debug_set_level(id, new_level); @@ -1380,7 +1380,8 @@ debug_input_flush_fn(debug_info_t * id, struct debug_view *view, goto out; } - printk(KERN_INFO "debug: area `%c` is not valid\n", input_buf[0]); + pr_info("Flushing debug data failed because %c is not a valid " + "area\n", input_buf[0]); out: *offset += user_len; diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 198ea18a534d0d9c74e68f99b44649b92e852c69..55de521aef773f813d8f8228d504c45ece216dfa 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -109,13 +109,6 @@ STACK_SIZE = 1 << STACK_SHIFT * R15 - kernel stack pointer */ - .macro STORE_TIMER lc_offset -#ifdef CONFIG_VIRT_CPU_ACCOUNTING - stpt \lc_offset -#endif - .endm - -#ifdef CONFIG_VIRT_CPU_ACCOUNTING .macro UPDATE_VTIME lc_from,lc_to,lc_sum lm %r10,%r11,\lc_from sl %r10,\lc_to @@ -128,7 +121,6 @@ STACK_SIZE = 1 << STACK_SHIFT al %r10,BASED(.Lc_1) 1: stm %r10,%r11,\lc_sum .endm -#endif .macro SAVE_ALL_BASE savearea stm %r12,%r15,\savearea @@ -198,7 +190,7 @@ STACK_SIZE = 1 << STACK_SHIFT ni \psworg+1,0xfd # clear wait state bit .endif lm %r0,%r15,SP_R0(%r15) # load gprs 0-15 of user - STORE_TIMER __LC_EXIT_TIMER + stpt __LC_EXIT_TIMER lpsw \psworg # back to caller .endm @@ -247,20 +239,18 @@ __critical_start: .globl system_call system_call: - STORE_TIMER __LC_SYNC_ENTER_TIMER + stpt __LC_SYNC_ENTER_TIMER sysc_saveall: SAVE_ALL_BASE __LC_SAVE_AREA SAVE_ALL_SVC __LC_SVC_OLD_PSW,__LC_SAVE_AREA CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA lh %r7,0x8a # get svc number from lowcore -#ifdef CONFIG_VIRT_CPU_ACCOUNTING sysc_vtime: UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER sysc_stime: UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER sysc_update: mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER -#endif sysc_do_svc: l %r9,__LC_THREAD_INFO # load pointer to thread_info struct ltr %r7,%r7 # test for svc 0 @@ -436,7 +426,7 @@ ret_from_fork: basr %r14,%r1 TRACE_IRQS_ON stosm __SF_EMPTY(%r15),0x03 # reenable interrupts - b BASED(sysc_return) + b BASED(sysc_tracenogo) # # kernel_execve function needs to deal with pt_regs that is not @@ -490,20 +480,18 @@ pgm_check_handler: * we just ignore the PER event (FIXME: is there anything we have to do * for LPSW?). */ - STORE_TIMER __LC_SYNC_ENTER_TIMER + stpt __LC_SYNC_ENTER_TIMER SAVE_ALL_BASE __LC_SAVE_AREA tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception bnz BASED(pgm_per) # got per exception -> special case SAVE_ALL_SYNC __LC_PGM_OLD_PSW,__LC_SAVE_AREA CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA -#ifdef CONFIG_VIRT_CPU_ACCOUNTING tm SP_PSW+1(%r15),0x01 # interrupting from user ? bz BASED(pgm_no_vtime) UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER pgm_no_vtime: -#endif l %r9,__LC_THREAD_INFO # load pointer to thread_info struct TRACE_IRQS_OFF l %r3,__LC_PGM_ILC # load program interruption code @@ -536,14 +524,12 @@ pgm_per: pgm_per_std: SAVE_ALL_SYNC __LC_PGM_OLD_PSW,__LC_SAVE_AREA CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA -#ifdef CONFIG_VIRT_CPU_ACCOUNTING tm SP_PSW+1(%r15),0x01 # interrupting from user ? bz BASED(pgm_no_vtime2) UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER pgm_no_vtime2: -#endif l %r9,__LC_THREAD_INFO # load pointer to thread_info struct TRACE_IRQS_OFF l %r1,__TI_task(%r9) @@ -565,11 +551,9 @@ pgm_no_vtime2: pgm_svcper: SAVE_ALL_SYNC __LC_SVC_OLD_PSW,__LC_SAVE_AREA CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA -#ifdef CONFIG_VIRT_CPU_ACCOUNTING UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER -#endif lh %r7,0x8a # get svc number from lowcore l %r9,__LC_THREAD_INFO # load pointer to thread_info struct TRACE_IRQS_OFF @@ -599,19 +583,17 @@ kernel_per: .globl io_int_handler io_int_handler: - STORE_TIMER __LC_ASYNC_ENTER_TIMER + stpt __LC_ASYNC_ENTER_TIMER stck __LC_INT_CLOCK SAVE_ALL_BASE __LC_SAVE_AREA+16 SAVE_ALL_ASYNC __LC_IO_OLD_PSW,__LC_SAVE_AREA+16 CREATE_STACK_FRAME __LC_IO_OLD_PSW,__LC_SAVE_AREA+16 -#ifdef CONFIG_VIRT_CPU_ACCOUNTING tm SP_PSW+1(%r15),0x01 # interrupting from user ? bz BASED(io_no_vtime) UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER io_no_vtime: -#endif l %r9,__LC_THREAD_INFO # load pointer to thread_info struct TRACE_IRQS_OFF l %r1,BASED(.Ldo_IRQ) # load address of do_IRQ @@ -741,19 +723,17 @@ io_notify_resume: .globl ext_int_handler ext_int_handler: - STORE_TIMER __LC_ASYNC_ENTER_TIMER + stpt __LC_ASYNC_ENTER_TIMER stck __LC_INT_CLOCK SAVE_ALL_BASE __LC_SAVE_AREA+16 SAVE_ALL_ASYNC __LC_EXT_OLD_PSW,__LC_SAVE_AREA+16 CREATE_STACK_FRAME __LC_EXT_OLD_PSW,__LC_SAVE_AREA+16 -#ifdef CONFIG_VIRT_CPU_ACCOUNTING tm SP_PSW+1(%r15),0x01 # interrupting from user ? bz BASED(ext_no_vtime) UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER ext_no_vtime: -#endif l %r9,__LC_THREAD_INFO # load pointer to thread_info struct TRACE_IRQS_OFF la %r2,SP_PTREGS(%r15) # address of register-save area @@ -776,7 +756,6 @@ mcck_int_handler: la %r12,__LC_MCK_OLD_PSW tm __LC_MCCK_CODE,0x80 # system damage? bo BASED(mcck_int_main) # yes -> rest of mcck code invalid -#ifdef CONFIG_VIRT_CPU_ACCOUNTING mvc __LC_SAVE_AREA+52(8),__LC_ASYNC_ENTER_TIMER mvc __LC_ASYNC_ENTER_TIMER(8),__LC_CPU_TIMER_SAVE_AREA tm __LC_MCCK_CODE+5,0x02 # stored cpu timer value valid? @@ -793,9 +772,7 @@ mcck_int_handler: la %r14,__LC_LAST_UPDATE_TIMER 0: spt 0(%r14) mvc __LC_ASYNC_ENTER_TIMER(8),0(%r14) -1: -#endif - tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid? +1: tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid? bno BASED(mcck_int_main) # no -> skip cleanup critical tm __LC_MCK_OLD_PSW+1,0x01 # test problem state bit bnz BASED(mcck_int_main) # from user -> load async stack @@ -812,7 +789,6 @@ mcck_int_main: be BASED(0f) l %r15,__LC_PANIC_STACK # load panic stack 0: CREATE_STACK_FRAME __LC_MCK_OLD_PSW,__LC_SAVE_AREA+32 -#ifdef CONFIG_VIRT_CPU_ACCOUNTING tm __LC_MCCK_CODE+2,0x08 # mwp of old psw valid? bno BASED(mcck_no_vtime) # no -> skip cleanup critical tm SP_PSW+1(%r15),0x01 # interrupting from user ? @@ -821,7 +797,6 @@ mcck_int_main: UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER mcck_no_vtime: -#endif l %r9,__LC_THREAD_INFO # load pointer to thread_info struct la %r2,SP_PTREGS(%r15) # load pt_regs l %r1,BASED(.Ls390_mcck) @@ -843,16 +818,13 @@ mcck_no_vtime: mcck_return: mvc __LC_RETURN_MCCK_PSW(8),SP_PSW(%r15) # move return PSW ni __LC_RETURN_MCCK_PSW+1,0xfd # clear wait state bit -#ifdef CONFIG_VIRT_CPU_ACCOUNTING mvc __LC_ASYNC_ENTER_TIMER(8),__LC_SAVE_AREA+52 tm __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ? bno BASED(0f) lm %r0,%r15,SP_R0(%r15) # load gprs 0-15 stpt __LC_EXIT_TIMER lpsw __LC_RETURN_MCCK_PSW # back to caller -0: -#endif - lm %r0,%r15,SP_R0(%r15) # load gprs 0-15 +0: lm %r0,%r15,SP_R0(%r15) # load gprs 0-15 lpsw __LC_RETURN_MCCK_PSW # back to caller RESTORE_ALL __LC_RETURN_MCCK_PSW,0 @@ -976,13 +948,11 @@ cleanup_system_call: b BASED(1f) 0: la %r12,__LC_SAVE_AREA+32 1: -#ifdef CONFIG_VIRT_CPU_ACCOUNTING clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+4) bh BASED(0f) mvc __LC_SYNC_ENTER_TIMER(8),__LC_ASYNC_ENTER_TIMER 0: clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+8) bhe BASED(cleanup_vtime) -#endif clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn) bh BASED(0f) mvc __LC_SAVE_AREA(16),0(%r12) @@ -993,7 +963,6 @@ cleanup_system_call: l %r12,__LC_SAVE_AREA+48 # argh st %r15,12(%r12) lh %r7,0x8a -#ifdef CONFIG_VIRT_CPU_ACCOUNTING cleanup_vtime: clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+12) bhe BASED(cleanup_stime) @@ -1004,18 +973,15 @@ cleanup_stime: UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER cleanup_update: mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER -#endif mvc __LC_RETURN_PSW+4(4),BASED(cleanup_table_system_call+4) la %r12,__LC_RETURN_PSW br %r14 cleanup_system_call_insn: .long sysc_saveall + 0x80000000 -#ifdef CONFIG_VIRT_CPU_ACCOUNTING .long system_call + 0x80000000 .long sysc_vtime + 0x80000000 .long sysc_stime + 0x80000000 .long sysc_update + 0x80000000 -#endif cleanup_sysc_return: mvc __LC_RETURN_PSW(4),0(%r12) @@ -1026,11 +992,9 @@ cleanup_sysc_return: cleanup_sysc_leave: clc 4(4,%r12),BASED(cleanup_sysc_leave_insn) be BASED(2f) -#ifdef CONFIG_VIRT_CPU_ACCOUNTING mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER clc 4(4,%r12),BASED(cleanup_sysc_leave_insn+4) be BASED(2f) -#endif mvc __LC_RETURN_PSW(8),SP_PSW(%r15) c %r12,BASED(.Lmck_old_psw) bne BASED(0f) @@ -1043,9 +1007,7 @@ cleanup_sysc_leave: br %r14 cleanup_sysc_leave_insn: .long sysc_done - 4 + 0x80000000 -#ifdef CONFIG_VIRT_CPU_ACCOUNTING .long sysc_done - 8 + 0x80000000 -#endif cleanup_io_return: mvc __LC_RETURN_PSW(4),0(%r12) @@ -1056,11 +1018,9 @@ cleanup_io_return: cleanup_io_leave: clc 4(4,%r12),BASED(cleanup_io_leave_insn) be BASED(2f) -#ifdef CONFIG_VIRT_CPU_ACCOUNTING mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER clc 4(4,%r12),BASED(cleanup_io_leave_insn+4) be BASED(2f) -#endif mvc __LC_RETURN_PSW(8),SP_PSW(%r15) c %r12,BASED(.Lmck_old_psw) bne BASED(0f) @@ -1073,9 +1033,7 @@ cleanup_io_leave: br %r14 cleanup_io_leave_insn: .long io_done - 4 + 0x80000000 -#ifdef CONFIG_VIRT_CPU_ACCOUNTING .long io_done - 8 + 0x80000000 -#endif /* * Integer constants diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index 89c121ae63391ef0453367cd26efa36d10296cf3..16bb4fd1a403bc2061d0afe55e63611985471a7c 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S @@ -96,20 +96,12 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \ #define LOCKDEP_SYS_EXIT #endif - .macro STORE_TIMER lc_offset -#ifdef CONFIG_VIRT_CPU_ACCOUNTING - stpt \lc_offset -#endif - .endm - -#ifdef CONFIG_VIRT_CPU_ACCOUNTING .macro UPDATE_VTIME lc_from,lc_to,lc_sum lg %r10,\lc_from slg %r10,\lc_to alg %r10,\lc_sum stg %r10,\lc_sum .endm -#endif /* * Register usage in interrupt handlers: @@ -186,7 +178,7 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \ ni \psworg+1,0xfd # clear wait state bit .endif lmg %r0,%r15,SP_R0(%r15) # load gprs 0-15 of user - STORE_TIMER __LC_EXIT_TIMER + stpt __LC_EXIT_TIMER lpswe \psworg # back to caller .endm @@ -233,20 +225,18 @@ __critical_start: .globl system_call system_call: - STORE_TIMER __LC_SYNC_ENTER_TIMER + stpt __LC_SYNC_ENTER_TIMER sysc_saveall: SAVE_ALL_BASE __LC_SAVE_AREA SAVE_ALL_SVC __LC_SVC_OLD_PSW,__LC_SAVE_AREA CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore -#ifdef CONFIG_VIRT_CPU_ACCOUNTING sysc_vtime: UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER sysc_stime: UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER sysc_update: mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER -#endif sysc_do_svc: lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct ltgr %r7,%r7 # test for svc 0 @@ -417,7 +407,7 @@ ret_from_fork: 0: brasl %r14,schedule_tail TRACE_IRQS_ON stosm 24(%r15),0x03 # reenable interrupts - j sysc_return + j sysc_tracenogo # # kernel_execve function needs to deal with pt_regs that is not @@ -469,20 +459,18 @@ pgm_check_handler: * we just ignore the PER event (FIXME: is there anything we have to do * for LPSW?). */ - STORE_TIMER __LC_SYNC_ENTER_TIMER + stpt __LC_SYNC_ENTER_TIMER SAVE_ALL_BASE __LC_SAVE_AREA tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception jnz pgm_per # got per exception -> special case SAVE_ALL_SYNC __LC_PGM_OLD_PSW,__LC_SAVE_AREA CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA -#ifdef CONFIG_VIRT_CPU_ACCOUNTING tm SP_PSW+1(%r15),0x01 # interrupting from user ? jz pgm_no_vtime UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER pgm_no_vtime: -#endif lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct mvc SP_ARGS(8,%r15),__LC_LAST_BREAK TRACE_IRQS_OFF @@ -516,14 +504,12 @@ pgm_per: pgm_per_std: SAVE_ALL_SYNC __LC_PGM_OLD_PSW,__LC_SAVE_AREA CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA -#ifdef CONFIG_VIRT_CPU_ACCOUNTING tm SP_PSW+1(%r15),0x01 # interrupting from user ? jz pgm_no_vtime2 UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER pgm_no_vtime2: -#endif lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct TRACE_IRQS_OFF lg %r1,__TI_task(%r9) @@ -545,11 +531,9 @@ pgm_no_vtime2: pgm_svcper: SAVE_ALL_SYNC __LC_SVC_OLD_PSW,__LC_SAVE_AREA CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA -#ifdef CONFIG_VIRT_CPU_ACCOUNTING UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER -#endif llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct lg %r1,__TI_task(%r9) @@ -575,19 +559,17 @@ kernel_per: */ .globl io_int_handler io_int_handler: - STORE_TIMER __LC_ASYNC_ENTER_TIMER + stpt __LC_ASYNC_ENTER_TIMER stck __LC_INT_CLOCK SAVE_ALL_BASE __LC_SAVE_AREA+32 SAVE_ALL_ASYNC __LC_IO_OLD_PSW,__LC_SAVE_AREA+32 CREATE_STACK_FRAME __LC_IO_OLD_PSW,__LC_SAVE_AREA+32 -#ifdef CONFIG_VIRT_CPU_ACCOUNTING tm SP_PSW+1(%r15),0x01 # interrupting from user ? jz io_no_vtime UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER io_no_vtime: -#endif lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct TRACE_IRQS_OFF la %r2,SP_PTREGS(%r15) # address of register-save area @@ -739,19 +721,17 @@ io_notify_resume: */ .globl ext_int_handler ext_int_handler: - STORE_TIMER __LC_ASYNC_ENTER_TIMER + stpt __LC_ASYNC_ENTER_TIMER stck __LC_INT_CLOCK SAVE_ALL_BASE __LC_SAVE_AREA+32 SAVE_ALL_ASYNC __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32 CREATE_STACK_FRAME __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32 -#ifdef CONFIG_VIRT_CPU_ACCOUNTING tm SP_PSW+1(%r15),0x01 # interrupting from user ? jz ext_no_vtime UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER ext_no_vtime: -#endif lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct TRACE_IRQS_OFF la %r2,SP_PTREGS(%r15) # address of register-save area @@ -773,7 +753,6 @@ mcck_int_handler: la %r12,__LC_MCK_OLD_PSW tm __LC_MCCK_CODE,0x80 # system damage? jo mcck_int_main # yes -> rest of mcck code invalid -#ifdef CONFIG_VIRT_CPU_ACCOUNTING la %r14,4095 mvc __LC_SAVE_AREA+104(8),__LC_ASYNC_ENTER_TIMER mvc __LC_ASYNC_ENTER_TIMER(8),__LC_CPU_TIMER_SAVE_AREA-4095(%r14) @@ -791,9 +770,7 @@ mcck_int_handler: la %r14,__LC_LAST_UPDATE_TIMER 0: spt 0(%r14) mvc __LC_ASYNC_ENTER_TIMER(8),0(%r14) -1: -#endif - tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid? +1: tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid? jno mcck_int_main # no -> skip cleanup critical tm __LC_MCK_OLD_PSW+1,0x01 # test problem state bit jnz mcck_int_main # from user -> load kernel stack @@ -809,7 +786,6 @@ mcck_int_main: jz 0f lg %r15,__LC_PANIC_STACK # load panic stack 0: CREATE_STACK_FRAME __LC_MCK_OLD_PSW,__LC_SAVE_AREA+64 -#ifdef CONFIG_VIRT_CPU_ACCOUNTING tm __LC_MCCK_CODE+2,0x08 # mwp of old psw valid? jno mcck_no_vtime # no -> no timer update tm SP_PSW+1(%r15),0x01 # interrupting from user ? @@ -818,7 +794,6 @@ mcck_int_main: UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER mcck_no_vtime: -#endif lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct la %r2,SP_PTREGS(%r15) # load pt_regs brasl %r14,s390_do_machine_check @@ -839,14 +814,11 @@ mcck_return: mvc __LC_RETURN_MCCK_PSW(16),SP_PSW(%r15) # move return PSW ni __LC_RETURN_MCCK_PSW+1,0xfd # clear wait state bit lmg %r0,%r15,SP_R0(%r15) # load gprs 0-15 -#ifdef CONFIG_VIRT_CPU_ACCOUNTING mvc __LC_ASYNC_ENTER_TIMER(8),__LC_SAVE_AREA+104 tm __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ? jno 0f stpt __LC_EXIT_TIMER -0: -#endif - lpswe __LC_RETURN_MCCK_PSW # back to caller +0: lpswe __LC_RETURN_MCCK_PSW # back to caller /* * Restart interruption handler, kick starter for additional CPUs @@ -964,13 +936,11 @@ cleanup_system_call: j 1f 0: la %r12,__LC_SAVE_AREA+64 1: -#ifdef CONFIG_VIRT_CPU_ACCOUNTING clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+8) jh 0f mvc __LC_SYNC_ENTER_TIMER(8),__LC_ASYNC_ENTER_TIMER 0: clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+16) jhe cleanup_vtime -#endif clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn) jh 0f mvc __LC_SAVE_AREA(32),0(%r12) @@ -981,7 +951,6 @@ cleanup_system_call: lg %r12,__LC_SAVE_AREA+96 # argh stg %r15,24(%r12) llgh %r7,__LC_SVC_INT_CODE -#ifdef CONFIG_VIRT_CPU_ACCOUNTING cleanup_vtime: clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+24) jhe cleanup_stime @@ -992,18 +961,15 @@ cleanup_stime: UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER cleanup_update: mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER -#endif mvc __LC_RETURN_PSW+8(8),BASED(cleanup_table_system_call+8) la %r12,__LC_RETURN_PSW br %r14 cleanup_system_call_insn: .quad sysc_saveall -#ifdef CONFIG_VIRT_CPU_ACCOUNTING .quad system_call .quad sysc_vtime .quad sysc_stime .quad sysc_update -#endif cleanup_sysc_return: mvc __LC_RETURN_PSW(8),0(%r12) @@ -1014,11 +980,9 @@ cleanup_sysc_return: cleanup_sysc_leave: clc 8(8,%r12),BASED(cleanup_sysc_leave_insn) je 2f -#ifdef CONFIG_VIRT_CPU_ACCOUNTING mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER clc 8(8,%r12),BASED(cleanup_sysc_leave_insn+8) je 2f -#endif mvc __LC_RETURN_PSW(16),SP_PSW(%r15) cghi %r12,__LC_MCK_OLD_PSW jne 0f @@ -1031,9 +995,7 @@ cleanup_sysc_leave: br %r14 cleanup_sysc_leave_insn: .quad sysc_done - 4 -#ifdef CONFIG_VIRT_CPU_ACCOUNTING .quad sysc_done - 8 -#endif cleanup_io_return: mvc __LC_RETURN_PSW(8),0(%r12) @@ -1044,11 +1006,9 @@ cleanup_io_return: cleanup_io_leave: clc 8(8,%r12),BASED(cleanup_io_leave_insn) je 2f -#ifdef CONFIG_VIRT_CPU_ACCOUNTING mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER clc 8(8,%r12),BASED(cleanup_io_leave_insn+8) je 2f -#endif mvc __LC_RETURN_PSW(16),SP_PSW(%r15) cghi %r12,__LC_MCK_OLD_PSW jne 0f @@ -1061,9 +1021,7 @@ cleanup_io_leave: br %r14 cleanup_io_leave_insn: .quad io_done - 4 -#ifdef CONFIG_VIRT_CPU_ACCOUNTING .quad io_done - 8 -#endif /* * Integer constants diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S index 83477c7dc743e39bcf79941f0f04a083ad265348..ec7e35f6055b238dc3c18eaeff09054ec7ecfb3f 100644 --- a/arch/s390/kernel/head.S +++ b/arch/s390/kernel/head.S @@ -461,6 +461,55 @@ start: .byte 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7 .byte 0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff +# +# startup-code at 0x10000, running in absolute addressing mode +# this is called either by the ipl loader or directly by PSW restart +# or linload or SALIPL +# + .org 0x10000 +startup:basr %r13,0 # get base +.LPG0: + +#ifndef CONFIG_MARCH_G5 + # check processor version against MARCH_{G5,Z900,Z990,Z9_109,Z10} + stidp __LC_CPUID # store cpuid + lhi %r0,(3f-2f) / 2 + la %r1,2f-.LPG0(%r13) +0: clc __LC_CPUID+4(2),0(%r1) + jne 3f + lpsw 1f-.LPG0(13) # machine type not good enough, crash + .align 16 +1: .long 0x000a0000,0x00000000 +2: +#if defined(CONFIG_MARCH_Z10) + .short 0x9672, 0x2064, 0x2066, 0x2084, 0x2086, 0x2094, 0x2096 +#elif defined(CONFIG_MARCH_Z9_109) + .short 0x9672, 0x2064, 0x2066, 0x2084, 0x2086 +#elif defined(CONFIG_MARCH_Z990) + .short 0x9672, 0x2064, 0x2066 +#elif defined(CONFIG_MARCH_Z900) + .short 0x9672 +#endif +3: la %r1,2(%r1) + brct %r0,0b +#endif + + l %r13,0f-.LPG0(%r13) + b 0(%r13) +0: .long startup_continue + +# +# params at 10400 (setup.h) +# + .org PARMAREA + .long 0,0 # IPL_DEVICE + .long 0,0 # INITRD_START + .long 0,0 # INITRD_SIZE + + .org COMMAND_LINE + .byte "root=/dev/ram0 ro" + .byte 0 + #ifdef CONFIG_64BIT #include "head64.S" #else diff --git a/arch/s390/kernel/head31.S b/arch/s390/kernel/head31.S index a816e2de32b957ce24af24a2e0f45163e3d8e4da..db476d114caabd5c79b016110f503d507de2f312 100644 --- a/arch/s390/kernel/head31.S +++ b/arch/s390/kernel/head31.S @@ -10,34 +10,13 @@ * */ -# -# startup-code at 0x10000, running in absolute addressing mode -# this is called either by the ipl loader or directly by PSW restart -# or linload or SALIPL -# - .org 0x10000 -startup:basr %r13,0 # get base -.LPG0: l %r13,0f-.LPG0(%r13) - b 0(%r13) -0: .long startup_continue - -# -# params at 10400 (setup.h) -# - .org PARMAREA - .long 0,0 # IPL_DEVICE - .long 0,0 # INITRD_START - .long 0,0 # INITRD_SIZE - - .org COMMAND_LINE - .byte "root=/dev/ram0 ro" - .byte 0 - .org 0x11000 startup_continue: basr %r13,0 # get base -.LPG1: mvi __LC_AR_MODE_ID,0 # set ESA flag (mode 0) +.LPG1: + + mvi __LC_AR_MODE_ID,0 # set ESA flag (mode 0) lctl %c0,%c15,.Lctl-.LPG1(%r13) # load control registers l %r12,.Lparmaddr-.LPG1(%r13) # pointer to parameter area # move IPL device to lowcore @@ -50,7 +29,6 @@ startup_continue: ahi %r15,1<<(PAGE_SHIFT+THREAD_ORDER) # init_task_union+THREAD_SIZE st %r15,__LC_KERNEL_STACK # set end of kernel stack ahi %r15,-96 - xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain # # Save ipl parameters, clear bss memory, initialize storage key for kernel pages, # and create a kernel NSS if the SAVESYS= parm is defined diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S index 1d06961e87b328ec1bb27eb019c660194fda58f3..3ccd36b24b8f82b10efe7ccb37d92bf31bf9fb10 100644 --- a/arch/s390/kernel/head64.S +++ b/arch/s390/kernel/head64.S @@ -10,29 +10,6 @@ * */ -# -# startup-code at 0x10000, running in absolute addressing mode -# this is called either by the ipl loader or directly by PSW restart -# or linload or SALIPL -# - .org 0x10000 -startup:basr %r13,0 # get base -.LPG0: l %r13,0f-.LPG0(%r13) - b 0(%r13) -0: .long startup_continue - -# -# params at 10400 (setup.h) -# - .org PARMAREA - .quad 0 # IPL_DEVICE - .quad 0 # INITRD_START - .quad 0 # INITRD_SIZE - - .org COMMAND_LINE - .byte "root=/dev/ram0 ro" - .byte 0 - .org 0x11000 startup_continue: @@ -119,7 +96,6 @@ startup_continue: aghi %r15,1<<(PAGE_SHIFT+THREAD_ORDER) # init_task_union + THREAD_SIZE stg %r15,__LC_KERNEL_STACK # set end of kernel stack aghi %r15,-160 - xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain # # Save ipl parameters, clear bss memory, initialize storage key for kernel pages, # and create a kernel NSS if the SAVESYS= parm is defined diff --git a/arch/s390/kernel/mcount.S b/arch/s390/kernel/mcount.S new file mode 100644 index 0000000000000000000000000000000000000000..397d131a345f53161dc049e7c65896243f7924fd --- /dev/null +++ b/arch/s390/kernel/mcount.S @@ -0,0 +1,56 @@ +/* + * Copyright IBM Corp. 2008 + * + * Author(s): Heiko Carstens , + * + */ + +#ifndef CONFIG_64BIT +.globl _mcount +_mcount: + stm %r0,%r5,8(%r15) + st %r14,56(%r15) + lr %r1,%r15 + ahi %r15,-96 + l %r3,100(%r15) + la %r2,0(%r14) + st %r1,0(%r15) + la %r3,0(%r3) + bras %r14,0f + .long ftrace_trace_function +0: l %r14,0(%r14) + l %r14,0(%r14) + basr %r14,%r14 + ahi %r15,96 + lm %r0,%r5,8(%r15) + l %r14,56(%r15) + br %r14 + +.globl ftrace_stub +ftrace_stub: + br %r14 + +#else /* CONFIG_64BIT */ + +.globl _mcount +_mcount: + stmg %r0,%r5,16(%r15) + stg %r14,112(%r15) + lgr %r1,%r15 + aghi %r15,-160 + stg %r1,0(%r15) + lgr %r2,%r14 + lg %r3,168(%r15) + larl %r14,ftrace_trace_function + lg %r14,0(%r14) + basr %r14,%r14 + aghi %r15,160 + lmg %r0,%r5,16(%r15) + lg %r14,112(%r15) + br %r14 + +.globl ftrace_stub +ftrace_stub: + br %r14 + +#endif /* CONFIG_64BIT */ diff --git a/arch/s390/kernel/processor.c b/arch/s390/kernel/processor.c new file mode 100644 index 0000000000000000000000000000000000000000..82c1872cfe804c03d838b5625c54add169b7cce9 --- /dev/null +++ b/arch/s390/kernel/processor.c @@ -0,0 +1,98 @@ +/* + * arch/s390/kernel/processor.c + * + * Copyright IBM Corp. 2008 + * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) + */ + +#define KMSG_COMPONENT "cpu" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + +#include +#include +#include +#include +#include + +#include +#include +#include + +void __cpuinit print_cpu_info(struct cpuinfo_S390 *cpuinfo) +{ + pr_info("Processor %d started, address %d, identification %06X\n", + cpuinfo->cpu_nr, cpuinfo->cpu_addr, cpuinfo->cpu_id.ident); +} + +/* + * show_cpuinfo - Get information on one CPU for use by procfs. + */ + +static int show_cpuinfo(struct seq_file *m, void *v) +{ + static const char *hwcap_str[8] = { + "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp", + "edat" + }; + struct cpuinfo_S390 *cpuinfo; + unsigned long n = (unsigned long) v - 1; + int i; + + s390_adjust_jiffies(); + preempt_disable(); + if (!n) { + seq_printf(m, "vendor_id : IBM/S390\n" + "# processors : %i\n" + "bogomips per cpu: %lu.%02lu\n", + num_online_cpus(), loops_per_jiffy/(500000/HZ), + (loops_per_jiffy/(5000/HZ))%100); + seq_puts(m, "features\t: "); + for (i = 0; i < 8; i++) + if (hwcap_str[i] && (elf_hwcap & (1UL << i))) + seq_printf(m, "%s ", hwcap_str[i]); + seq_puts(m, "\n"); + } + + if (cpu_online(n)) { +#ifdef CONFIG_SMP + if (smp_processor_id() == n) + cpuinfo = &S390_lowcore.cpu_data; + else + cpuinfo = &lowcore_ptr[n]->cpu_data; +#else + cpuinfo = &S390_lowcore.cpu_data; +#endif + seq_printf(m, "processor %li: " + "version = %02X, " + "identification = %06X, " + "machine = %04X\n", + n, cpuinfo->cpu_id.version, + cpuinfo->cpu_id.ident, + cpuinfo->cpu_id.machine); + } + preempt_enable(); + return 0; +} + +static void *c_start(struct seq_file *m, loff_t *pos) +{ + return *pos < NR_CPUS ? (void *)((unsigned long) *pos + 1) : NULL; +} + +static void *c_next(struct seq_file *m, void *v, loff_t *pos) +{ + ++*pos; + return c_start(m, pos); +} + +static void c_stop(struct seq_file *m, void *v) +{ +} + +const struct seq_operations cpuinfo_op = { + .start = c_start, + .next = c_next, + .stop = c_stop, + .show = show_cpuinfo, +}; + diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 38ff2bce12032d45a16e554b6e4545ea63fae21e..75c496f4f16d2c41900fb4db365f49149e52d022 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -204,7 +204,6 @@ static unsigned long __peek_user(struct task_struct *child, addr_t addr) static int peek_user(struct task_struct *child, addr_t addr, addr_t data) { - struct user *dummy = NULL; addr_t tmp, mask; /* @@ -213,8 +212,8 @@ peek_user(struct task_struct *child, addr_t addr, addr_t data) */ mask = __ADDR_MASK; #ifdef CONFIG_64BIT - if (addr >= (addr_t) &dummy->regs.acrs && - addr < (addr_t) &dummy->regs.orig_gpr2) + if (addr >= (addr_t) &((struct user *) NULL)->regs.acrs && + addr < (addr_t) &((struct user *) NULL)->regs.orig_gpr2) mask = 3; #endif if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK) @@ -312,7 +311,6 @@ static int __poke_user(struct task_struct *child, addr_t addr, addr_t data) static int poke_user(struct task_struct *child, addr_t addr, addr_t data) { - struct user *dummy = NULL; addr_t mask; /* @@ -321,8 +319,8 @@ poke_user(struct task_struct *child, addr_t addr, addr_t data) */ mask = __ADDR_MASK; #ifdef CONFIG_64BIT - if (addr >= (addr_t) &dummy->regs.acrs && - addr < (addr_t) &dummy->regs.orig_gpr2) + if (addr >= (addr_t) &((struct user *) NULL)->regs.acrs && + addr < (addr_t) &((struct user *) NULL)->regs.orig_gpr2) mask = 3; #endif if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK) diff --git a/arch/s390/kernel/s390_ksyms.c b/arch/s390/kernel/s390_ksyms.c index 48238a114ce957a8d706157a2a8b5ed1a843debe..46b90cb03707305bdc4713653479a2f8376d0b3f 100644 --- a/arch/s390/kernel/s390_ksyms.c +++ b/arch/s390/kernel/s390_ksyms.c @@ -14,6 +14,7 @@ #include #include #include +#include #ifdef CONFIG_IP_MULTICAST #include #endif @@ -43,3 +44,7 @@ EXPORT_SYMBOL(csum_fold); EXPORT_SYMBOL(console_mode); EXPORT_SYMBOL(console_devno); EXPORT_SYMBOL(console_irq); + +#ifdef CONFIG_FUNCTION_TRACER +EXPORT_SYMBOL(_mcount); +#endif diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 400b040df7fa05b1028bb9a9744e002957b29f5b..b7a1efd5522cac0d972dde9a9d73f5f8114c51bc 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -14,6 +14,9 @@ * This file handles the architecture-dependent parts of initialization */ +#define KMSG_COMPONENT "setup" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include @@ -32,7 +35,6 @@ #include #include #include -#include #include #include #include @@ -291,8 +293,8 @@ unsigned int switch_amode = 0; #endif EXPORT_SYMBOL_GPL(switch_amode); -static void set_amode_and_uaccess(unsigned long user_amode, - unsigned long user32_amode) +static int set_amode_and_uaccess(unsigned long user_amode, + unsigned long user32_amode) { psw_user_bits = PSW_BASE_BITS | PSW_MASK_DAT | user_amode | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | @@ -309,11 +311,11 @@ static void set_amode_and_uaccess(unsigned long user_amode, PSW_MASK_MCHECK | PSW_DEFAULT_KEY; if (MACHINE_HAS_MVCOS) { - printk("mvcos available.\n"); memcpy(&uaccess, &uaccess_mvcos_switch, sizeof(uaccess)); + return 1; } else { - printk("mvcos not available.\n"); memcpy(&uaccess, &uaccess_pt, sizeof(uaccess)); + return 0; } } @@ -328,9 +330,10 @@ static int __init early_parse_switch_amode(char *p) early_param("switch_amode", early_parse_switch_amode); #else /* CONFIG_S390_SWITCH_AMODE */ -static inline void set_amode_and_uaccess(unsigned long user_amode, - unsigned long user32_amode) +static inline int set_amode_and_uaccess(unsigned long user_amode, + unsigned long user32_amode) { + return 0; } #endif /* CONFIG_S390_SWITCH_AMODE */ @@ -355,11 +358,20 @@ early_param("noexec", early_parse_noexec); static void setup_addressing_mode(void) { if (s390_noexec) { - printk("S390 execute protection active, "); - set_amode_and_uaccess(PSW_ASC_SECONDARY, PSW32_ASC_SECONDARY); + if (set_amode_and_uaccess(PSW_ASC_SECONDARY, + PSW32_ASC_SECONDARY)) + pr_info("Execute protection active, " + "mvcos available\n"); + else + pr_info("Execute protection active, " + "mvcos not available\n"); } else if (switch_amode) { - printk("S390 address spaces switched, "); - set_amode_and_uaccess(PSW_ASC_PRIMARY, PSW32_ASC_PRIMARY); + if (set_amode_and_uaccess(PSW_ASC_PRIMARY, PSW32_ASC_PRIMARY)) + pr_info("Address spaces switched, " + "mvcos available\n"); + else + pr_info("Address spaces switched, " + "mvcos not available\n"); } #ifdef CONFIG_TRACE_IRQFLAGS sysc_restore_trace_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK; @@ -572,15 +584,15 @@ setup_memory(void) start = PFN_PHYS(start_pfn) + bmap_size + PAGE_SIZE; if (start + INITRD_SIZE > memory_end) { - printk("initrd extends beyond end of memory " - "(0x%08lx > 0x%08lx)\n" + pr_err("initrd extends beyond end of " + "memory (0x%08lx > 0x%08lx) " "disabling initrd\n", start + INITRD_SIZE, memory_end); INITRD_START = INITRD_SIZE = 0; } else { - printk("Moving initrd (0x%08lx -> 0x%08lx, " - "size: %ld)\n", - INITRD_START, start, INITRD_SIZE); + pr_info("Moving initrd (0x%08lx -> " + "0x%08lx, size: %ld)\n", + INITRD_START, start, INITRD_SIZE); memmove((void *) start, (void *) INITRD_START, INITRD_SIZE); INITRD_START = start; @@ -642,8 +654,9 @@ setup_memory(void) initrd_start = INITRD_START; initrd_end = initrd_start + INITRD_SIZE; } else { - printk("initrd extends beyond end of memory " - "(0x%08lx > 0x%08lx)\ndisabling initrd\n", + pr_err("initrd extends beyond end of " + "memory (0x%08lx > 0x%08lx) " + "disabling initrd\n", initrd_start + INITRD_SIZE, memory_end); initrd_start = initrd_end = 0; } @@ -651,23 +664,6 @@ setup_memory(void) #endif } -static int __init __stfle(unsigned long long *list, int doublewords) -{ - typedef struct { unsigned long long _[doublewords]; } addrtype; - register unsigned long __nr asm("0") = doublewords - 1; - - asm volatile(".insn s,0xb2b00000,%0" /* stfle */ - : "=m" (*(addrtype *) list), "+d" (__nr) : : "cc"); - return __nr + 1; -} - -int __init stfle(unsigned long long *list, int doublewords) -{ - if (!(stfl() & (1UL << 24))) - return -EOPNOTSUPP; - return __stfle(list, doublewords); -} - /* * Setup hardware capabilities. */ @@ -739,8 +735,13 @@ static void __init setup_hwcaps(void) strcpy(elf_platform, "z990"); break; case 0x2094: + case 0x2096: strcpy(elf_platform, "z9-109"); break; + case 0x2097: + case 0x2098: + strcpy(elf_platform, "z10"); + break; } } @@ -752,25 +753,34 @@ static void __init setup_hwcaps(void) void __init setup_arch(char **cmdline_p) { + /* set up preferred console */ + add_preferred_console("ttyS", 0, NULL); + /* * print what head.S has found out about the machine */ #ifndef CONFIG_64BIT - printk((MACHINE_IS_VM) ? - "We are running under VM (31 bit mode)\n" : - "We are running native (31 bit mode)\n"); - printk((MACHINE_HAS_IEEE) ? - "This machine has an IEEE fpu\n" : - "This machine has no IEEE fpu\n"); + if (MACHINE_IS_VM) + pr_info("Linux is running as a z/VM " + "guest operating system in 31-bit mode\n"); + else + pr_info("Linux is running natively in 31-bit mode\n"); + if (MACHINE_HAS_IEEE) + pr_info("The hardware system has IEEE compatible " + "floating point units\n"); + else + pr_info("The hardware system has no IEEE compatible " + "floating point units\n"); #else /* CONFIG_64BIT */ if (MACHINE_IS_VM) - printk("We are running under VM (64 bit mode)\n"); + pr_info("Linux is running as a z/VM " + "guest operating system in 64-bit mode\n"); else if (MACHINE_IS_KVM) { - printk("We are running under KVM (64 bit mode)\n"); + pr_info("Linux is running under KVM in 64-bit mode\n"); add_preferred_console("hvc", 0, NULL); s390_virtio_console_init(); } else - printk("We are running native (64 bit mode)\n"); + pr_info("Linux is running natively in 64-bit mode\n"); #endif /* CONFIG_64BIT */ /* Have one command line that is parsed and saved in /proc/cmdline */ @@ -818,90 +828,3 @@ setup_arch(char **cmdline_p) /* Setup zfcpdump support */ setup_zfcpdump(console_devno); } - -void __cpuinit print_cpu_info(struct cpuinfo_S390 *cpuinfo) -{ - printk(KERN_INFO "cpu %d " -#ifdef CONFIG_SMP - "phys_idx=%d " -#endif - "vers=%02X ident=%06X machine=%04X unused=%04X\n", - cpuinfo->cpu_nr, -#ifdef CONFIG_SMP - cpuinfo->cpu_addr, -#endif - cpuinfo->cpu_id.version, - cpuinfo->cpu_id.ident, - cpuinfo->cpu_id.machine, - cpuinfo->cpu_id.unused); -} - -/* - * show_cpuinfo - Get information on one CPU for use by procfs. - */ - -static int show_cpuinfo(struct seq_file *m, void *v) -{ - static const char *hwcap_str[8] = { - "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp", - "edat" - }; - struct cpuinfo_S390 *cpuinfo; - unsigned long n = (unsigned long) v - 1; - int i; - - s390_adjust_jiffies(); - preempt_disable(); - if (!n) { - seq_printf(m, "vendor_id : IBM/S390\n" - "# processors : %i\n" - "bogomips per cpu: %lu.%02lu\n", - num_online_cpus(), loops_per_jiffy/(500000/HZ), - (loops_per_jiffy/(5000/HZ))%100); - seq_puts(m, "features\t: "); - for (i = 0; i < 8; i++) - if (hwcap_str[i] && (elf_hwcap & (1UL << i))) - seq_printf(m, "%s ", hwcap_str[i]); - seq_puts(m, "\n"); - } - - if (cpu_online(n)) { -#ifdef CONFIG_SMP - if (smp_processor_id() == n) - cpuinfo = &S390_lowcore.cpu_data; - else - cpuinfo = &lowcore_ptr[n]->cpu_data; -#else - cpuinfo = &S390_lowcore.cpu_data; -#endif - seq_printf(m, "processor %li: " - "version = %02X, " - "identification = %06X, " - "machine = %04X\n", - n, cpuinfo->cpu_id.version, - cpuinfo->cpu_id.ident, - cpuinfo->cpu_id.machine); - } - preempt_enable(); - return 0; -} - -static void *c_start(struct seq_file *m, loff_t *pos) -{ - return *pos < NR_CPUS ? (void *)((unsigned long) *pos + 1) : NULL; -} -static void *c_next(struct seq_file *m, void *v, loff_t *pos) -{ - ++*pos; - return c_start(m, pos); -} -static void c_stop(struct seq_file *m, void *v) -{ -} -const struct seq_operations cpuinfo_op = { - .start = c_start, - .next = c_next, - .stop = c_stop, - .show = show_cpuinfo, -}; - diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index b5595688a47777d72eb803dd00fd8a15b35dee66..6fc78541dc57fee528a712f1cc3a259db97e23de 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -20,6 +20,9 @@ * cpu_number_map in other architectures. */ +#define KMSG_COMPONENT "cpu" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include @@ -77,159 +80,6 @@ static DEFINE_PER_CPU(struct cpu, cpu_devices); static void smp_ext_bitcall(int, ec_bit_sig); -/* - * Structure and data for __smp_call_function_map(). This is designed to - * minimise static memory requirements. It also looks cleaner. - */ -static DEFINE_SPINLOCK(call_lock); - -struct call_data_struct { - void (*func) (void *info); - void *info; - cpumask_t started; - cpumask_t finished; - int wait; -}; - -static struct call_data_struct *call_data; - -/* - * 'Call function' interrupt callback - */ -static void do_call_function(void) -{ - void (*func) (void *info) = call_data->func; - void *info = call_data->info; - int wait = call_data->wait; - - cpu_set(smp_processor_id(), call_data->started); - (*func)(info); - if (wait) - cpu_set(smp_processor_id(), call_data->finished);; -} - -static void __smp_call_function_map(void (*func) (void *info), void *info, - int wait, cpumask_t map) -{ - struct call_data_struct data; - int cpu, local = 0; - - /* - * Can deadlock when interrupts are disabled or if in wrong context. - */ - WARN_ON(irqs_disabled() || in_irq()); - - /* - * Check for local function call. We have to have the same call order - * as in on_each_cpu() because of machine_restart_smp(). - */ - if (cpu_isset(smp_processor_id(), map)) { - local = 1; - cpu_clear(smp_processor_id(), map); - } - - cpus_and(map, map, cpu_online_map); - if (cpus_empty(map)) - goto out; - - data.func = func; - data.info = info; - data.started = CPU_MASK_NONE; - data.wait = wait; - if (wait) - data.finished = CPU_MASK_NONE; - - call_data = &data; - - for_each_cpu_mask(cpu, map) - smp_ext_bitcall(cpu, ec_call_function); - - /* Wait for response */ - while (!cpus_equal(map, data.started)) - cpu_relax(); - if (wait) - while (!cpus_equal(map, data.finished)) - cpu_relax(); -out: - if (local) { - local_irq_disable(); - func(info); - local_irq_enable(); - } -} - -/* - * smp_call_function: - * @func: the function to run; this must be fast and non-blocking - * @info: an arbitrary pointer to pass to the function - * @wait: if true, wait (atomically) until function has completed on other CPUs - * - * Run a function on all other CPUs. - * - * You must not call this function with disabled interrupts, from a - * hardware interrupt handler or from a bottom half. - */ -int smp_call_function(void (*func) (void *info), void *info, int wait) -{ - cpumask_t map; - - spin_lock(&call_lock); - map = cpu_online_map; - cpu_clear(smp_processor_id(), map); - __smp_call_function_map(func, info, wait, map); - spin_unlock(&call_lock); - return 0; -} -EXPORT_SYMBOL(smp_call_function); - -/* - * smp_call_function_single: - * @cpu: the CPU where func should run - * @func: the function to run; this must be fast and non-blocking - * @info: an arbitrary pointer to pass to the function - * @wait: if true, wait (atomically) until function has completed on other CPUs - * - * Run a function on one processor. - * - * You must not call this function with disabled interrupts, from a - * hardware interrupt handler or from a bottom half. - */ -int smp_call_function_single(int cpu, void (*func) (void *info), void *info, - int wait) -{ - spin_lock(&call_lock); - __smp_call_function_map(func, info, wait, cpumask_of_cpu(cpu)); - spin_unlock(&call_lock); - return 0; -} -EXPORT_SYMBOL(smp_call_function_single); - -/** - * smp_call_function_mask(): Run a function on a set of other CPUs. - * @mask: The set of cpus to run on. Must not include the current cpu. - * @func: The function to run. This must be fast and non-blocking. - * @info: An arbitrary pointer to pass to the function. - * @wait: If true, wait (atomically) until function has completed on other CPUs. - * - * Returns 0 on success, else a negative status code. - * - * If @wait is true, then returns once @func has returned; otherwise - * it returns just before the target cpu calls @func. - * - * You must not call this function with disabled interrupts or from a - * hardware interrupt handler or from a bottom half handler. - */ -int smp_call_function_mask(cpumask_t mask, void (*func)(void *), void *info, - int wait) -{ - spin_lock(&call_lock); - cpu_clear(smp_processor_id(), mask); - __smp_call_function_map(func, info, wait, mask); - spin_unlock(&call_lock); - return 0; -} -EXPORT_SYMBOL(smp_call_function_mask); - void smp_send_stop(void) { int cpu, rc; @@ -271,7 +121,10 @@ static void do_ext_call_interrupt(__u16 code) bits = xchg(&S390_lowcore.ext_call_fast, 0); if (test_bit(ec_call_function, &bits)) - do_call_function(); + generic_smp_call_function_interrupt(); + + if (test_bit(ec_call_function_single, &bits)) + generic_smp_call_function_single_interrupt(); } /* @@ -288,6 +141,19 @@ static void smp_ext_bitcall(int cpu, ec_bit_sig sig) udelay(10); } +void arch_send_call_function_ipi(cpumask_t mask) +{ + int cpu; + + for_each_cpu_mask(cpu, mask) + smp_ext_bitcall(cpu, ec_call_function); +} + +void arch_send_call_function_single_ipi(int cpu) +{ + smp_ext_bitcall(cpu, ec_call_function_single); +} + #ifndef CONFIG_64BIT /* * this function sends a 'purge tlb' signal to another CPU. @@ -388,8 +254,8 @@ static void __init smp_get_save_area(unsigned int cpu, unsigned int phy_cpu) if (ipl_info.type != IPL_TYPE_FCP_DUMP) return; if (cpu >= NR_CPUS) { - printk(KERN_WARNING "Registers for cpu %i not saved since dump " - "kernel was compiled with NR_CPUS=%i\n", cpu, NR_CPUS); + pr_warning("CPU %i exceeds the maximum %i and is excluded from " + "the dump\n", cpu, NR_CPUS - 1); return; } zfcpdump_save_areas[cpu] = kmalloc(sizeof(union save_area), GFP_KERNEL); @@ -562,7 +428,7 @@ static void __init smp_detect_cpus(void) } out: kfree(info); - printk(KERN_INFO "CPUs: %d configured, %d standby\n", c_cpus, s_cpus); + pr_info("%d configured CPUs, %d standby CPUs\n", c_cpus, s_cpus); get_online_cpus(); __smp_rescan_cpus(); put_online_cpus(); @@ -578,19 +444,17 @@ int __cpuinit start_secondary(void *cpuvoid) preempt_disable(); /* Enable TOD clock interrupts on the secondary cpu. */ init_cpu_timer(); -#ifdef CONFIG_VIRT_TIMER /* Enable cpu timer interrupts on the secondary cpu. */ init_cpu_vtimer(); -#endif /* Enable pfault pseudo page faults on this cpu. */ pfault_init(); /* call cpu notifiers */ notify_cpu_starting(smp_processor_id()); /* Mark this cpu as online */ - spin_lock(&call_lock); + ipi_call_lock(); cpu_set(smp_processor_id(), cpu_online_map); - spin_unlock(&call_lock); + ipi_call_unlock(); /* Switch on interrupts */ local_irq_enable(); /* Print info about this processor */ @@ -639,18 +503,15 @@ static int __cpuinit smp_alloc_lowcore(int cpu) save_area = get_zeroed_page(GFP_KERNEL); if (!save_area) - goto out_save_area; + goto out; lowcore->extended_save_area_addr = (u32) save_area; } #endif lowcore_ptr[cpu] = lowcore; return 0; -#ifndef CONFIG_64BIT -out_save_area: - free_page(panic_stack); -#endif out: + free_page(panic_stack); free_pages(async_stack, ASYNC_ORDER); free_pages((unsigned long) lowcore, lc_order); return -ENOMEM; @@ -690,12 +551,8 @@ int __cpuinit __cpu_up(unsigned int cpu) ccode = signal_processor_p((__u32)(unsigned long)(lowcore_ptr[cpu]), cpu, sigp_set_prefix); - if (ccode) { - printk("sigp_set_prefix failed for cpu %d " - "with condition code %d\n", - (int) cpu, (int) ccode); + if (ccode) return -EIO; - } idle = current_set[cpu]; cpu_lowcore = lowcore_ptr[cpu]; @@ -778,7 +635,7 @@ void __cpu_die(unsigned int cpu) while (!smp_cpu_not_running(cpu)) cpu_relax(); smp_free_lowcore(cpu); - printk(KERN_INFO "Processor %d spun down\n", cpu); + pr_info("Processor %d stopped\n", cpu); } void cpu_die(void) diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index eccefbbff887dc199b04ec715d25ec9c2ec1201c..5be981a36c3ecadcb66db97b0bd3d88834d1081e 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -12,6 +12,9 @@ * Copyright (C) 1991, 1992, 1995 Linus Torvalds */ +#define KMSG_COMPONENT "time" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include @@ -20,6 +23,8 @@ #include #include #include +#include +#include #include #include #include @@ -36,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -223,6 +229,36 @@ static struct clocksource clocksource_tod = { }; +void update_vsyscall(struct timespec *wall_time, struct clocksource *clock) +{ + if (clock != &clocksource_tod) + return; + + /* Make userspace gettimeofday spin until we're done. */ + ++vdso_data->tb_update_count; + smp_wmb(); + vdso_data->xtime_tod_stamp = clock->cycle_last; + vdso_data->xtime_clock_sec = xtime.tv_sec; + vdso_data->xtime_clock_nsec = xtime.tv_nsec; + vdso_data->wtom_clock_sec = wall_to_monotonic.tv_sec; + vdso_data->wtom_clock_nsec = wall_to_monotonic.tv_nsec; + smp_wmb(); + ++vdso_data->tb_update_count; +} + +extern struct timezone sys_tz; + +void update_vsyscall_tz(void) +{ + /* Make userspace gettimeofday spin until we're done. */ + ++vdso_data->tb_update_count; + smp_wmb(); + vdso_data->tz_minuteswest = sys_tz.tz_minuteswest; + vdso_data->tz_dsttime = sys_tz.tz_dsttime; + smp_wmb(); + ++vdso_data->tb_update_count; +} + /* * Initialize the TOD clock and the CPU timer of * the boot cpu. @@ -253,10 +289,8 @@ void __init time_init(void) /* Enable TOD clock interrupts on the boot cpu. */ init_cpu_timer(); - -#ifdef CONFIG_VIRT_TIMER + /* Enable cpu timer interrupts on the boot cpu. */ vtime_init(); -#endif } /* @@ -288,8 +322,8 @@ static unsigned long long adjust_time(unsigned long long old, } sched_clock_base_cc += delta; if (adjust.offset != 0) { - printk(KERN_NOTICE "etr: time adjusted by %li micro-seconds\n", - adjust.offset); + pr_notice("The ETR interface has adjusted the clock " + "by %li microseconds\n", adjust.offset); adjust.modes = ADJ_OFFSET_SINGLESHOT; do_adjtimex(&adjust); } @@ -360,6 +394,15 @@ static void enable_sync_clock(void) atomic_set_mask(0x80000000, sw_ptr); } +/* Single threaded workqueue used for etr and stp sync events */ +static struct workqueue_struct *time_sync_wq; + +static void __init time_init_wq(void) +{ + if (!time_sync_wq) + time_sync_wq = create_singlethread_workqueue("timesync"); +} + /* * External Time Reference (ETR) code. */ @@ -425,6 +468,7 @@ static struct timer_list etr_timer; static void etr_timeout(unsigned long dummy); static void etr_work_fn(struct work_struct *work); +static DEFINE_MUTEX(etr_work_mutex); static DECLARE_WORK(etr_work, etr_work_fn); /* @@ -440,8 +484,8 @@ static void etr_reset(void) etr_tolec = get_clock(); set_bit(CLOCK_SYNC_HAS_ETR, &clock_sync_flags); } else if (etr_port0_online || etr_port1_online) { - printk(KERN_WARNING "Running on non ETR capable " - "machine, only local mode available.\n"); + pr_warning("The real or virtual hardware system does " + "not provide an ETR interface\n"); etr_port0_online = etr_port1_online = 0; } } @@ -452,17 +496,18 @@ static int __init etr_init(void) if (!test_bit(CLOCK_SYNC_HAS_ETR, &clock_sync_flags)) return 0; + time_init_wq(); /* Check if this machine has the steai instruction. */ if (etr_steai(&aib, ETR_STEAI_STEPPING_PORT) == 0) etr_steai_available = 1; setup_timer(&etr_timer, etr_timeout, 0UL); if (etr_port0_online) { set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events); - schedule_work(&etr_work); + queue_work(time_sync_wq, &etr_work); } if (etr_port1_online) { set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events); - schedule_work(&etr_work); + queue_work(time_sync_wq, &etr_work); } return 0; } @@ -489,7 +534,7 @@ void etr_switch_to_local(void) if (test_bit(CLOCK_SYNC_ETR, &clock_sync_flags)) disable_sync_clock(NULL); set_bit(ETR_EVENT_SWITCH_LOCAL, &etr_events); - schedule_work(&etr_work); + queue_work(time_sync_wq, &etr_work); } /* @@ -505,7 +550,7 @@ void etr_sync_check(void) if (test_bit(CLOCK_SYNC_ETR, &clock_sync_flags)) disable_sync_clock(NULL); set_bit(ETR_EVENT_SYNC_CHECK, &etr_events); - schedule_work(&etr_work); + queue_work(time_sync_wq, &etr_work); } /* @@ -529,13 +574,13 @@ static void etr_timing_alert(struct etr_irq_parm *intparm) * Both ports are not up-to-date now. */ set_bit(ETR_EVENT_PORT_ALERT, &etr_events); - schedule_work(&etr_work); + queue_work(time_sync_wq, &etr_work); } static void etr_timeout(unsigned long dummy) { set_bit(ETR_EVENT_UPDATE, &etr_events); - schedule_work(&etr_work); + queue_work(time_sync_wq, &etr_work); } /* @@ -642,14 +687,16 @@ static int etr_aib_follows(struct etr_aib *a1, struct etr_aib *a2, int p) } struct clock_sync_data { + atomic_t cpus; int in_sync; unsigned long long fixup_cc; + int etr_port; + struct etr_aib *etr_aib; }; -static void clock_sync_cpu_start(void *dummy) +static void clock_sync_cpu(struct clock_sync_data *sync) { - struct clock_sync_data *sync = dummy; - + atomic_dec(&sync->cpus); enable_sync_clock(); /* * This looks like a busy wait loop but it isn't. etr_sync_cpus @@ -675,39 +722,35 @@ static void clock_sync_cpu_start(void *dummy) fixup_clock_comparator(sync->fixup_cc); } -static void clock_sync_cpu_end(void *dummy) -{ -} - /* * Sync the TOD clock using the port refered to by aibp. This port * has to be enabled and the other port has to be disabled. The * last eacr update has to be more than 1.6 seconds in the past. */ -static int etr_sync_clock(struct etr_aib *aib, int port) +static int etr_sync_clock(void *data) { - struct etr_aib *sync_port; - struct clock_sync_data etr_sync; + static int first; unsigned long long clock, old_clock, delay, delta; - int follows; + struct clock_sync_data *etr_sync; + struct etr_aib *sync_port, *aib; + int port; int rc; - /* Check if the current aib is adjacent to the sync port aib. */ - sync_port = (port == 0) ? &etr_port0 : &etr_port1; - follows = etr_aib_follows(sync_port, aib, port); - memcpy(sync_port, aib, sizeof(*aib)); - if (!follows) - return -EAGAIN; + etr_sync = data; - /* - * Catch all other cpus and make them wait until we have - * successfully synced the clock. smp_call_function will - * return after all other cpus are in etr_sync_cpu_start. - */ - memset(&etr_sync, 0, sizeof(etr_sync)); - preempt_disable(); - smp_call_function(clock_sync_cpu_start, &etr_sync, 0); - local_irq_disable(); + if (xchg(&first, 1) == 1) { + /* Slave */ + clock_sync_cpu(etr_sync); + return 0; + } + + /* Wait until all other cpus entered the sync function. */ + while (atomic_read(&etr_sync->cpus) != 0) + cpu_relax(); + + port = etr_sync->etr_port; + aib = etr_sync->etr_aib; + sync_port = (port == 0) ? &etr_port0 : &etr_port1; enable_sync_clock(); /* Set clock to next OTE. */ @@ -724,16 +767,16 @@ static int etr_sync_clock(struct etr_aib *aib, int port) delay = (unsigned long long) (aib->edf2.etv - sync_port->edf2.etv) << 32; delta = adjust_time(old_clock, clock, delay); - etr_sync.fixup_cc = delta; + etr_sync->fixup_cc = delta; fixup_clock_comparator(delta); /* Verify that the clock is properly set. */ if (!etr_aib_follows(sync_port, aib, port)) { /* Didn't work. */ disable_sync_clock(NULL); - etr_sync.in_sync = -EAGAIN; + etr_sync->in_sync = -EAGAIN; rc = -EAGAIN; } else { - etr_sync.in_sync = 1; + etr_sync->in_sync = 1; rc = 0; } } else { @@ -741,12 +784,33 @@ static int etr_sync_clock(struct etr_aib *aib, int port) __ctl_clear_bit(0, 29); __ctl_clear_bit(14, 21); disable_sync_clock(NULL); - etr_sync.in_sync = -EAGAIN; + etr_sync->in_sync = -EAGAIN; rc = -EAGAIN; } - local_irq_enable(); - smp_call_function(clock_sync_cpu_end, NULL, 0); - preempt_enable(); + xchg(&first, 0); + return rc; +} + +static int etr_sync_clock_stop(struct etr_aib *aib, int port) +{ + struct clock_sync_data etr_sync; + struct etr_aib *sync_port; + int follows; + int rc; + + /* Check if the current aib is adjacent to the sync port aib. */ + sync_port = (port == 0) ? &etr_port0 : &etr_port1; + follows = etr_aib_follows(sync_port, aib, port); + memcpy(sync_port, aib, sizeof(*aib)); + if (!follows) + return -EAGAIN; + memset(&etr_sync, 0, sizeof(etr_sync)); + etr_sync.etr_aib = aib; + etr_sync.etr_port = port; + get_online_cpus(); + atomic_set(&etr_sync.cpus, num_online_cpus() - 1); + rc = stop_machine(etr_sync_clock, &etr_sync, &cpu_online_map); + put_online_cpus(); return rc; } @@ -903,7 +967,7 @@ static void etr_update_eacr(struct etr_eacr eacr) } /* - * ETR tasklet. In this function you'll find the main logic. In + * ETR work. In this function you'll find the main logic. In * particular this is the only function that calls etr_update_eacr(), * it "controls" the etr control register. */ @@ -914,6 +978,9 @@ static void etr_work_fn(struct work_struct *work) struct etr_aib aib; int sync_port; + /* prevent multiple execution. */ + mutex_lock(&etr_work_mutex); + /* Create working copy of etr_eacr. */ eacr = etr_eacr; @@ -929,7 +996,7 @@ static void etr_work_fn(struct work_struct *work) del_timer_sync(&etr_timer); etr_update_eacr(eacr); clear_bit(CLOCK_SYNC_ETR, &clock_sync_flags); - return; + goto out_unlock; } /* Store aib to get the current ETR status word. */ @@ -1016,7 +1083,7 @@ static void etr_work_fn(struct work_struct *work) eacr.es || sync_port < 0) { etr_update_eacr(eacr); etr_set_tolec_timeout(now); - return; + goto out_unlock; } /* @@ -1036,7 +1103,7 @@ static void etr_work_fn(struct work_struct *work) etr_update_eacr(eacr); set_bit(CLOCK_SYNC_ETR, &clock_sync_flags); if (now < etr_tolec + (1600000 << 12) || - etr_sync_clock(&aib, sync_port) != 0) { + etr_sync_clock_stop(&aib, sync_port) != 0) { /* Sync failed. Try again in 1/2 second. */ eacr.es = 0; etr_update_eacr(eacr); @@ -1044,6 +1111,8 @@ static void etr_work_fn(struct work_struct *work) etr_set_sync_timeout(); } else etr_set_tolec_timeout(now); +out_unlock: + mutex_unlock(&etr_work_mutex); } /* @@ -1125,13 +1194,13 @@ static ssize_t etr_online_store(struct sys_device *dev, return count; /* Nothing to do. */ etr_port0_online = value; set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events); - schedule_work(&etr_work); + queue_work(time_sync_wq, &etr_work); } else { if (etr_port1_online == value) return count; /* Nothing to do. */ etr_port1_online = value; set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events); - schedule_work(&etr_work); + queue_work(time_sync_wq, &etr_work); } return count; } @@ -1332,6 +1401,7 @@ static struct stp_sstpi stp_info; static void *stp_page; static void stp_work_fn(struct work_struct *work); +static DEFINE_MUTEX(stp_work_mutex); static DECLARE_WORK(stp_work, stp_work_fn); static int __init early_parse_stp(char *p) @@ -1356,7 +1426,8 @@ static void __init stp_reset(void) if (rc == 0) set_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags); else if (stp_online) { - printk(KERN_WARNING "Running on non STP capable machine.\n"); + pr_warning("The real or virtual hardware system does " + "not provide an STP interface\n"); free_bootmem((unsigned long) stp_page, PAGE_SIZE); stp_page = NULL; stp_online = 0; @@ -1365,8 +1436,12 @@ static void __init stp_reset(void) static int __init stp_init(void) { - if (test_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags) && stp_online) - schedule_work(&stp_work); + if (!test_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags)) + return 0; + time_init_wq(); + if (!stp_online) + return 0; + queue_work(time_sync_wq, &stp_work); return 0; } @@ -1383,7 +1458,7 @@ arch_initcall(stp_init); static void stp_timing_alert(struct stp_irq_parm *intparm) { if (intparm->tsc || intparm->lac || intparm->tcpc) - schedule_work(&stp_work); + queue_work(time_sync_wq, &stp_work); } /* @@ -1397,7 +1472,7 @@ void stp_sync_check(void) if (!test_bit(CLOCK_SYNC_STP, &clock_sync_flags)) return; disable_sync_clock(NULL); - schedule_work(&stp_work); + queue_work(time_sync_wq, &stp_work); } /* @@ -1411,46 +1486,34 @@ void stp_island_check(void) if (!test_bit(CLOCK_SYNC_STP, &clock_sync_flags)) return; disable_sync_clock(NULL); - schedule_work(&stp_work); + queue_work(time_sync_wq, &stp_work); } -/* - * STP tasklet. Check for the STP state and take over the clock - * synchronization if the STP clock source is usable. - */ -static void stp_work_fn(struct work_struct *work) + +static int stp_sync_clock(void *data) { - struct clock_sync_data stp_sync; + static int first; unsigned long long old_clock, delta; + struct clock_sync_data *stp_sync; int rc; - if (!stp_online) { - chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000); - return; - } + stp_sync = data; - rc = chsc_sstpc(stp_page, STP_OP_CTRL, 0xb0e0); - if (rc) - return; + if (xchg(&first, 1) == 1) { + /* Slave */ + clock_sync_cpu(stp_sync); + return 0; + } - rc = chsc_sstpi(stp_page, &stp_info, sizeof(struct stp_sstpi)); - if (rc || stp_info.c == 0) - return; + /* Wait until all other cpus entered the sync function. */ + while (atomic_read(&stp_sync->cpus) != 0) + cpu_relax(); - /* - * Catch all other cpus and make them wait until we have - * successfully synced the clock. smp_call_function will - * return after all other cpus are in clock_sync_cpu_start. - */ - memset(&stp_sync, 0, sizeof(stp_sync)); - preempt_disable(); - smp_call_function(clock_sync_cpu_start, &stp_sync, 0); - local_irq_disable(); enable_sync_clock(); set_bit(CLOCK_SYNC_STP, &clock_sync_flags); if (test_and_clear_bit(CLOCK_SYNC_ETR, &clock_sync_flags)) - schedule_work(&etr_work); + queue_work(time_sync_wq, &etr_work); rc = 0; if (stp_info.todoff[0] || stp_info.todoff[1] || @@ -1469,16 +1532,49 @@ static void stp_work_fn(struct work_struct *work) } if (rc) { disable_sync_clock(NULL); - stp_sync.in_sync = -EAGAIN; + stp_sync->in_sync = -EAGAIN; clear_bit(CLOCK_SYNC_STP, &clock_sync_flags); if (etr_port0_online || etr_port1_online) - schedule_work(&etr_work); + queue_work(time_sync_wq, &etr_work); } else - stp_sync.in_sync = 1; + stp_sync->in_sync = 1; + xchg(&first, 0); + return 0; +} + +/* + * STP work. Check for the STP state and take over the clock + * synchronization if the STP clock source is usable. + */ +static void stp_work_fn(struct work_struct *work) +{ + struct clock_sync_data stp_sync; + int rc; + + /* prevent multiple execution. */ + mutex_lock(&stp_work_mutex); + + if (!stp_online) { + chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000); + goto out_unlock; + } + + rc = chsc_sstpc(stp_page, STP_OP_CTRL, 0xb0e0); + if (rc) + goto out_unlock; + + rc = chsc_sstpi(stp_page, &stp_info, sizeof(struct stp_sstpi)); + if (rc || stp_info.c == 0) + goto out_unlock; + + memset(&stp_sync, 0, sizeof(stp_sync)); + get_online_cpus(); + atomic_set(&stp_sync.cpus, num_online_cpus() - 1); + stop_machine(stp_sync_clock, &stp_sync, &cpu_online_map); + put_online_cpus(); - local_irq_enable(); - smp_call_function(clock_sync_cpu_end, NULL, 0); - preempt_enable(); +out_unlock: + mutex_unlock(&stp_work_mutex); } /* @@ -1587,7 +1683,7 @@ static ssize_t stp_online_store(struct sysdev_class *class, if (!test_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags)) return -EOPNOTSUPP; stp_online = value; - schedule_work(&stp_work); + queue_work(time_sync_wq, &stp_work); return count; } diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c index a947899dcba1d55f56f8e00af05ab738293df6a3..90e9ba11eba1940db367d3b23a95187b4b371c70 100644 --- a/arch/s390/kernel/topology.c +++ b/arch/s390/kernel/topology.c @@ -3,6 +3,9 @@ * Author(s): Heiko Carstens */ +#define KMSG_COMPONENT "cpu" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include @@ -12,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -57,11 +61,11 @@ struct core_info { cpumask_t mask; }; +static int topology_enabled; static void topology_work_fn(struct work_struct *work); static struct tl_info *tl_info; static struct core_info core_info; static int machine_has_topology; -static int machine_has_topology_irq; static struct timer_list topology_timer; static void set_topology_timer(void); static DECLARE_WORK(topology_work, topology_work_fn); @@ -77,8 +81,8 @@ cpumask_t cpu_coregroup_map(unsigned int cpu) cpumask_t mask; cpus_clear(mask); - if (!machine_has_topology) - return cpu_present_map; + if (!topology_enabled || !machine_has_topology) + return cpu_possible_map; spin_lock_irqsave(&topology_lock, flags); while (core) { if (cpu_isset(cpu, core->mask)) { @@ -168,7 +172,7 @@ static void topology_update_polarization_simple(void) int cpu; mutex_lock(&smp_cpu_state_mutex); - for_each_present_cpu(cpu) + for_each_possible_cpu(cpu) smp_cpu_polarization[cpu] = POLARIZATION_HRZ; mutex_unlock(&smp_cpu_state_mutex); } @@ -199,7 +203,7 @@ int topology_set_cpu_management(int fc) rc = ptf(PTF_HORIZONTAL); if (rc) return -EBUSY; - for_each_present_cpu(cpu) + for_each_possible_cpu(cpu) smp_cpu_polarization[cpu] = POLARIZATION_UNKNWN; return rc; } @@ -208,11 +212,11 @@ static void update_cpu_core_map(void) { int cpu; - for_each_present_cpu(cpu) + for_each_possible_cpu(cpu) cpu_core_map[cpu] = cpu_coregroup_map(cpu); } -void arch_update_cpu_topology(void) +int arch_update_cpu_topology(void) { struct tl_info *info = tl_info; struct sys_device *sysdev; @@ -221,7 +225,7 @@ void arch_update_cpu_topology(void) if (!machine_has_topology) { update_cpu_core_map(); topology_update_polarization_simple(); - return; + return 0; } stsi(info, 15, 1, 2); tl_to_cores(info); @@ -230,11 +234,12 @@ void arch_update_cpu_topology(void) sysdev = get_cpu_sysdev(cpu); kobject_uevent(&sysdev->kobj, KOBJ_CHANGE); } + return 1; } static void topology_work_fn(struct work_struct *work) { - arch_reinit_sched_domains(); + rebuild_sched_domains(); } void topology_schedule_update(void) @@ -257,10 +262,14 @@ static void set_topology_timer(void) add_timer(&topology_timer); } -static void topology_interrupt(__u16 code) +static int __init early_parse_topology(char *p) { - schedule_work(&topology_work); + if (strncmp(p, "on", 2)) + return 0; + topology_enabled = 1; + return 0; } +early_param("topology", early_parse_topology); static int __init init_topology_update(void) { @@ -272,14 +281,7 @@ static int __init init_topology_update(void) goto out; } init_timer_deferrable(&topology_timer); - if (machine_has_topology_irq) { - rc = register_external_interrupt(0x2005, topology_interrupt); - if (rc) - goto out; - ctl_set_bit(0, 8); - } - else - set_topology_timer(); + set_topology_timer(); out: update_cpu_core_map(); return rc; @@ -300,9 +302,6 @@ void __init s390_init_cpu_topology(void) return; machine_has_topology = 1; - if (facility_bits & (1ULL << 51)) - machine_has_topology_irq = 1; - tl_info = alloc_bootmem_pages(PAGE_SIZE); info = tl_info; stsi(info, 15, 1, 2); @@ -311,7 +310,7 @@ void __init s390_init_cpu_topology(void) for (i = 0; i < info->mnest - 2; i++) nr_cores *= info->mag[NR_MAG - 3 - i]; - printk(KERN_INFO "CPU topology:"); + pr_info("The CPU configuration topology of the machine is:"); for (i = 0; i < NR_MAG; i++) printk(" %d", info->mag[i]); printk(" / %d\n", info->mnest); @@ -326,5 +325,4 @@ void __init s390_init_cpu_topology(void) return; error: machine_has_topology = 0; - machine_has_topology_irq = 0; } diff --git a/arch/s390/kernel/vdso.c b/arch/s390/kernel/vdso.c new file mode 100644 index 0000000000000000000000000000000000000000..10a6ccef441224d5f0166767200f3918063fe2a8 --- /dev/null +++ b/arch/s390/kernel/vdso.c @@ -0,0 +1,234 @@ +/* + * vdso setup for s390 + * + * Copyright IBM Corp. 2008 + * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License (version 2 only) + * as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* Max supported size for symbol names */ +#define MAX_SYMNAME 64 + +#if defined(CONFIG_32BIT) || defined(CONFIG_COMPAT) +extern char vdso32_start, vdso32_end; +static void *vdso32_kbase = &vdso32_start; +static unsigned int vdso32_pages; +static struct page **vdso32_pagelist; +#endif + +#ifdef CONFIG_64BIT +extern char vdso64_start, vdso64_end; +static void *vdso64_kbase = &vdso64_start; +static unsigned int vdso64_pages; +static struct page **vdso64_pagelist; +#endif /* CONFIG_64BIT */ + +/* + * Should the kernel map a VDSO page into processes and pass its + * address down to glibc upon exec()? + */ +unsigned int __read_mostly vdso_enabled = 1; + +static int __init vdso_setup(char *s) +{ + vdso_enabled = simple_strtoul(s, NULL, 0); + return 1; +} +__setup("vdso=", vdso_setup); + +/* + * The vdso data page + */ +static union { + struct vdso_data data; + u8 page[PAGE_SIZE]; +} vdso_data_store __attribute__((__section__(".data.page_aligned"))); +struct vdso_data *vdso_data = &vdso_data_store.data; + +/* + * This is called from binfmt_elf, we create the special vma for the + * vDSO and insert it into the mm struct tree + */ +int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) +{ + struct mm_struct *mm = current->mm; + struct page **vdso_pagelist; + unsigned long vdso_pages; + unsigned long vdso_base; + int rc; + + if (!vdso_enabled) + return 0; + /* + * Only map the vdso for dynamically linked elf binaries. + */ + if (!uses_interp) + return 0; + + vdso_base = mm->mmap_base; +#ifdef CONFIG_64BIT + vdso_pagelist = vdso64_pagelist; + vdso_pages = vdso64_pages; +#ifdef CONFIG_COMPAT + if (test_thread_flag(TIF_31BIT)) { + vdso_pagelist = vdso32_pagelist; + vdso_pages = vdso32_pages; + } +#endif +#else + vdso_pagelist = vdso32_pagelist; + vdso_pages = vdso32_pages; +#endif + + /* + * vDSO has a problem and was disabled, just don't "enable" it for + * the process + */ + if (vdso_pages == 0) + return 0; + + current->mm->context.vdso_base = 0; + + /* + * pick a base address for the vDSO in process space. We try to put + * it at vdso_base which is the "natural" base for it, but we might + * fail and end up putting it elsewhere. + */ + down_write(&mm->mmap_sem); + vdso_base = get_unmapped_area(NULL, vdso_base, + vdso_pages << PAGE_SHIFT, 0, 0); + if (IS_ERR_VALUE(vdso_base)) { + rc = vdso_base; + goto out_up; + } + + /* + * our vma flags don't have VM_WRITE so by default, the process + * isn't allowed to write those pages. + * gdb can break that with ptrace interface, and thus trigger COW + * on those pages but it's then your responsibility to never do that + * on the "data" page of the vDSO or you'll stop getting kernel + * updates and your nice userland gettimeofday will be totally dead. + * It's fine to use that for setting breakpoints in the vDSO code + * pages though + * + * Make sure the vDSO gets into every core dump. + * Dumping its contents makes post-mortem fully interpretable later + * without matching up the same kernel and hardware config to see + * what PC values meant. + */ + rc = install_special_mapping(mm, vdso_base, vdso_pages << PAGE_SHIFT, + VM_READ|VM_EXEC| + VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC| + VM_ALWAYSDUMP, + vdso_pagelist); + if (rc) + goto out_up; + + /* Put vDSO base into mm struct */ + current->mm->context.vdso_base = vdso_base; + + up_write(&mm->mmap_sem); + return 0; + +out_up: + up_write(&mm->mmap_sem); + return rc; +} + +const char *arch_vma_name(struct vm_area_struct *vma) +{ + if (vma->vm_mm && vma->vm_start == vma->vm_mm->context.vdso_base) + return "[vdso]"; + return NULL; +} + +static int __init vdso_init(void) +{ + int i; + +#if defined(CONFIG_32BIT) || defined(CONFIG_COMPAT) + /* Calculate the size of the 32 bit vDSO */ + vdso32_pages = ((&vdso32_end - &vdso32_start + + PAGE_SIZE - 1) >> PAGE_SHIFT) + 1; + + /* Make sure pages are in the correct state */ + vdso32_pagelist = kzalloc(sizeof(struct page *) * (vdso32_pages + 1), + GFP_KERNEL); + BUG_ON(vdso32_pagelist == NULL); + for (i = 0; i < vdso32_pages - 1; i++) { + struct page *pg = virt_to_page(vdso32_kbase + i*PAGE_SIZE); + ClearPageReserved(pg); + get_page(pg); + vdso32_pagelist[i] = pg; + } + vdso32_pagelist[vdso32_pages - 1] = virt_to_page(vdso_data); + vdso32_pagelist[vdso32_pages] = NULL; +#endif + +#ifdef CONFIG_64BIT + /* Calculate the size of the 64 bit vDSO */ + vdso64_pages = ((&vdso64_end - &vdso64_start + + PAGE_SIZE - 1) >> PAGE_SHIFT) + 1; + + /* Make sure pages are in the correct state */ + vdso64_pagelist = kzalloc(sizeof(struct page *) * (vdso64_pages + 1), + GFP_KERNEL); + BUG_ON(vdso64_pagelist == NULL); + for (i = 0; i < vdso64_pages - 1; i++) { + struct page *pg = virt_to_page(vdso64_kbase + i*PAGE_SIZE); + ClearPageReserved(pg); + get_page(pg); + vdso64_pagelist[i] = pg; + } + vdso64_pagelist[vdso64_pages - 1] = virt_to_page(vdso_data); + vdso64_pagelist[vdso64_pages] = NULL; +#endif /* CONFIG_64BIT */ + + get_page(virt_to_page(vdso_data)); + + smp_wmb(); + + return 0; +} +arch_initcall(vdso_init); + +int in_gate_area_no_task(unsigned long addr) +{ + return 0; +} + +int in_gate_area(struct task_struct *task, unsigned long addr) +{ + return 0; +} + +struct vm_area_struct *get_gate_vma(struct task_struct *tsk) +{ + return NULL; +} diff --git a/arch/s390/kernel/vdso32/Makefile b/arch/s390/kernel/vdso32/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ca78ad60ba2490c9d2bb7682ad23aa7b9e922ddb --- /dev/null +++ b/arch/s390/kernel/vdso32/Makefile @@ -0,0 +1,55 @@ +# List of files in the vdso, has to be asm only for now + +obj-vdso32 = gettimeofday.o clock_getres.o clock_gettime.o note.o + +# Build rules + +targets := $(obj-vdso32) vdso32.so vdso32.so.dbg +obj-vdso32 := $(addprefix $(obj)/, $(obj-vdso32)) + +KBUILD_AFLAGS_31 := $(filter-out -m64,$(KBUILD_AFLAGS)) +KBUILD_AFLAGS_31 += -m31 -s + +KBUILD_CFLAGS_31 := $(filter-out -m64,$(KBUILD_CFLAGS)) +KBUILD_CFLAGS_31 += -m31 -fPIC -shared -fno-common -fno-builtin +KBUILD_CFLAGS_31 += -nostdlib -Wl,-soname=linux-vdso32.so.1 \ + $(call ld-option, -Wl$(comma)--hash-style=sysv) + +$(targets:%=$(obj)/%.dbg): KBUILD_CFLAGS = $(KBUILD_CFLAGS_31) +$(targets:%=$(obj)/%.dbg): KBUILD_AFLAGS = $(KBUILD_AFLAGS_31) + +obj-y += vdso32_wrapper.o +extra-y += vdso32.lds +CPPFLAGS_vdso32.lds += -P -C -U$(ARCH) + +# Force dependency (incbin is bad) +$(obj)/vdso32_wrapper.o : $(obj)/vdso32.so + +# link rule for the .so file, .lds has to be first +$(obj)/vdso32.so.dbg: $(src)/vdso32.lds $(obj-vdso32) + $(call if_changed,vdso32ld) + +# strip rule for the .so file +$(obj)/%.so: OBJCOPYFLAGS := -S +$(obj)/%.so: $(obj)/%.so.dbg FORCE + $(call if_changed,objcopy) + +# assembly rules for the .S files +$(obj-vdso32): %.o: %.S + $(call if_changed_dep,vdso32as) + +# actual build commands +quiet_cmd_vdso32ld = VDSO32L $@ + cmd_vdso32ld = $(CC) $(c_flags) -Wl,-T $^ -o $@ +quiet_cmd_vdso32as = VDSO32A $@ + cmd_vdso32as = $(CC) $(a_flags) -c -o $@ $< + +# install commands for the unstripped file +quiet_cmd_vdso_install = INSTALL $@ + cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@ + +vdso32.so: $(obj)/vdso32.so.dbg + @mkdir -p $(MODLIB)/vdso + $(call cmd,vdso_install) + +vdso_install: vdso32.so diff --git a/arch/s390/kernel/vdso32/clock_getres.S b/arch/s390/kernel/vdso32/clock_getres.S new file mode 100644 index 0000000000000000000000000000000000000000..9532c4e6a9d2fb12e5cd77f5a7c05ae99fa99f8c --- /dev/null +++ b/arch/s390/kernel/vdso32/clock_getres.S @@ -0,0 +1,39 @@ +/* + * Userland implementation of clock_getres() for 32 bits processes in a + * s390 kernel for use in the vDSO + * + * Copyright IBM Corp. 2008 + * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License (version 2 only) + * as published by the Free Software Foundation. + */ +#include +#include +#include + + .text + .align 4 + .globl __kernel_clock_getres + .type __kernel_clock_getres,@function +__kernel_clock_getres: + .cfi_startproc + chi %r2,CLOCK_REALTIME + je 0f + chi %r2,CLOCK_MONOTONIC + jne 3f +0: ltr %r3,%r3 + jz 2f /* res == NULL */ + basr %r1,0 +1: l %r0,4f-1b(%r1) + xc 0(4,%r3),0(%r3) /* set tp->tv_sec to zero */ + st %r0,4(%r3) /* store tp->tv_usec */ +2: lhi %r2,0 + br %r14 +3: lhi %r1,__NR_clock_getres /* fallback to svc */ + svc 0 + br %r14 +4: .long CLOCK_REALTIME_RES + .cfi_endproc + .size __kernel_clock_getres,.-__kernel_clock_getres diff --git a/arch/s390/kernel/vdso32/clock_gettime.S b/arch/s390/kernel/vdso32/clock_gettime.S new file mode 100644 index 0000000000000000000000000000000000000000..4a98909a83100c40fe5440822302a453403dcf4a --- /dev/null +++ b/arch/s390/kernel/vdso32/clock_gettime.S @@ -0,0 +1,128 @@ +/* + * Userland implementation of clock_gettime() for 32 bits processes in a + * s390 kernel for use in the vDSO + * + * Copyright IBM Corp. 2008 + * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License (version 2 only) + * as published by the Free Software Foundation. + */ +#include +#include +#include + + .text + .align 4 + .globl __kernel_clock_gettime + .type __kernel_clock_gettime,@function +__kernel_clock_gettime: + .cfi_startproc + basr %r5,0 +0: al %r5,21f-0b(%r5) /* get &_vdso_data */ + chi %r2,CLOCK_REALTIME + je 10f + chi %r2,CLOCK_MONOTONIC + jne 19f + + /* CLOCK_MONOTONIC */ + ltr %r3,%r3 + jz 9f /* tp == NULL */ +1: l %r4,__VDSO_UPD_COUNT+4(%r5) /* load update counter */ + tml %r4,0x0001 /* pending update ? loop */ + jnz 1b + stck 24(%r15) /* Store TOD clock */ + lm %r0,%r1,24(%r15) + s %r0,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */ + sl %r1,__VDSO_XTIME_STAMP+4(%r5) + brc 3,2f + ahi %r0,-1 +2: mhi %r0,1000 /* cyc2ns(clock,cycle_delta) */ + lr %r2,%r0 + lhi %r0,1000 + ltr %r1,%r1 + mr %r0,%r0 + jnm 3f + ahi %r0,1000 +3: alr %r0,%r2 + srdl %r0,12 + al %r0,__VDSO_XTIME_NSEC(%r5) /* + xtime */ + al %r1,__VDSO_XTIME_NSEC+4(%r5) + brc 12,4f + ahi %r0,1 +4: l %r2,__VDSO_XTIME_SEC+4(%r5) + al %r0,__VDSO_WTOM_NSEC(%r5) /* + wall_to_monotonic */ + al %r1,__VDSO_WTOM_NSEC+4(%r5) + brc 12,5f + ahi %r0,1 +5: al %r2,__VDSO_WTOM_SEC+4(%r5) + cl %r4,__VDSO_UPD_COUNT+4(%r5) /* check update counter */ + jne 1b + basr %r5,0 +6: ltr %r0,%r0 + jnz 7f + cl %r1,20f-6b(%r5) + jl 8f +7: ahi %r2,1 + sl %r1,20f-6b(%r5) + brc 3,6b + ahi %r0,-1 + j 6b +8: st %r2,0(%r3) /* store tp->tv_sec */ + st %r1,4(%r3) /* store tp->tv_nsec */ +9: lhi %r2,0 + br %r14 + + /* CLOCK_REALTIME */ +10: ltr %r3,%r3 /* tp == NULL */ + jz 18f +11: l %r4,__VDSO_UPD_COUNT+4(%r5) /* load update counter */ + tml %r4,0x0001 /* pending update ? loop */ + jnz 11b + stck 24(%r15) /* Store TOD clock */ + lm %r0,%r1,24(%r15) + s %r0,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */ + sl %r1,__VDSO_XTIME_STAMP+4(%r5) + brc 3,12f + ahi %r0,-1 +12: mhi %r0,1000 /* cyc2ns(clock,cycle_delta) */ + lr %r2,%r0 + lhi %r0,1000 + ltr %r1,%r1 + mr %r0,%r0 + jnm 13f + ahi %r0,1000 +13: alr %r0,%r2 + srdl %r0,12 + al %r0,__VDSO_XTIME_NSEC(%r5) /* + xtime */ + al %r1,__VDSO_XTIME_NSEC+4(%r5) + brc 12,14f + ahi %r0,1 +14: l %r2,__VDSO_XTIME_SEC+4(%r5) + cl %r4,__VDSO_UPD_COUNT+4(%r5) /* check update counter */ + jne 11b + basr %r5,0 +15: ltr %r0,%r0 + jnz 16f + cl %r1,20f-15b(%r5) + jl 17f +16: ahi %r2,1 + sl %r1,20f-15b(%r5) + brc 3,15b + ahi %r0,-1 + j 15b +17: st %r2,0(%r3) /* store tp->tv_sec */ + st %r1,4(%r3) /* store tp->tv_nsec */ +18: lhi %r2,0 + br %r14 + + /* Fallback to system call */ +19: lhi %r1,__NR_clock_gettime + svc 0 + br %r14 + +20: .long 1000000000 +21: .long _vdso_data - 0b + .cfi_endproc + .size __kernel_clock_gettime,.-__kernel_clock_gettime diff --git a/arch/s390/kernel/vdso32/gettimeofday.S b/arch/s390/kernel/vdso32/gettimeofday.S new file mode 100644 index 0000000000000000000000000000000000000000..c32f29c3d70c7a62de324fe94b35d376bafae6f2 --- /dev/null +++ b/arch/s390/kernel/vdso32/gettimeofday.S @@ -0,0 +1,82 @@ +/* + * Userland implementation of gettimeofday() for 32 bits processes in a + * s390 kernel for use in the vDSO + * + * Copyright IBM Corp. 2008 + * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License (version 2 only) + * as published by the Free Software Foundation. + */ +#include +#include +#include + +#include +#include +#include + + .text + .align 4 + .globl __kernel_gettimeofday + .type __kernel_gettimeofday,@function +__kernel_gettimeofday: + .cfi_startproc + basr %r5,0 +0: al %r5,13f-0b(%r5) /* get &_vdso_data */ +1: ltr %r3,%r3 /* check if tz is NULL */ + je 2f + mvc 0(8,%r3),__VDSO_TIMEZONE(%r5) +2: ltr %r2,%r2 /* check if tv is NULL */ + je 10f + l %r4,__VDSO_UPD_COUNT+4(%r5) /* load update counter */ + tml %r4,0x0001 /* pending update ? loop */ + jnz 1b + stck 24(%r15) /* Store TOD clock */ + lm %r0,%r1,24(%r15) + s %r0,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */ + sl %r1,__VDSO_XTIME_STAMP+4(%r5) + brc 3,3f + ahi %r0,-1 +3: mhi %r0,1000 /* cyc2ns(clock,cycle_delta) */ + st %r0,24(%r15) + lhi %r0,1000 + ltr %r1,%r1 + mr %r0,%r0 + jnm 4f + ahi %r0,1000 +4: al %r0,24(%r15) + srdl %r0,12 + al %r0,__VDSO_XTIME_NSEC(%r5) /* + xtime */ + al %r1,__VDSO_XTIME_NSEC+4(%r5) + brc 12,5f + ahi %r0,1 +5: mvc 24(4,%r15),__VDSO_XTIME_SEC+4(%r5) + cl %r4,__VDSO_UPD_COUNT+4(%r5) /* check update counter */ + jne 1b + l %r4,24(%r15) /* get tv_sec from stack */ + basr %r5,0 +6: ltr %r0,%r0 + jnz 7f + cl %r1,11f-6b(%r5) + jl 8f +7: ahi %r4,1 + sl %r1,11f-6b(%r5) + brc 3,6b + ahi %r0,-1 + j 6b +8: st %r4,0(%r2) /* store tv->tv_sec */ + ltr %r1,%r1 + m %r0,12f-6b(%r5) + jnm 9f + al %r0,12f-6b(%r5) +9: srl %r0,6 + st %r0,4(%r2) /* store tv->tv_usec */ +10: slr %r2,%r2 + br %r14 +11: .long 1000000000 +12: .long 274877907 +13: .long _vdso_data - 0b + .cfi_endproc + .size __kernel_gettimeofday,.-__kernel_gettimeofday diff --git a/arch/s390/kernel/vdso32/note.S b/arch/s390/kernel/vdso32/note.S new file mode 100644 index 0000000000000000000000000000000000000000..79a071e4357e4bc51f8813427d0f0ffa4c5ba56c --- /dev/null +++ b/arch/s390/kernel/vdso32/note.S @@ -0,0 +1,12 @@ +/* + * This supplies .note.* sections to go into the PT_NOTE inside the vDSO text. + * Here we can supply some information useful to userland. + */ + +#include +#include +#include + +ELFNOTE_START(Linux, 0, "a") + .long LINUX_VERSION_CODE +ELFNOTE_END diff --git a/arch/s390/kernel/vdso32/vdso32.lds.S b/arch/s390/kernel/vdso32/vdso32.lds.S new file mode 100644 index 0000000000000000000000000000000000000000..a8c379fa12478565da21bfcd615f7975dc099af7 --- /dev/null +++ b/arch/s390/kernel/vdso32/vdso32.lds.S @@ -0,0 +1,138 @@ +/* + * This is the infamous ld script for the 32 bits vdso + * library + */ +#include + +OUTPUT_FORMAT("elf32-s390", "elf32-s390", "elf32-s390") +OUTPUT_ARCH(s390:31-bit) +ENTRY(_start) + +SECTIONS +{ + . = VDSO32_LBASE + SIZEOF_HEADERS; + + .hash : { *(.hash) } :text + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + + .note : { *(.note.*) } :text :note + + . = ALIGN(16); + .text : { + *(.text .stub .text.* .gnu.linkonce.t.*) + } :text + PROVIDE(__etext = .); + PROVIDE(_etext = .); + PROVIDE(etext = .); + + /* + * Other stuff is appended to the text segment: + */ + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + + .dynamic : { *(.dynamic) } :text :dynamic + + .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr + .eh_frame : { KEEP (*(.eh_frame)) } :text + .gcc_except_table : { *(.gcc_except_table .gcc_except_table.*) } + + .rela.dyn ALIGN(8) : { *(.rela.dyn) } + .got ALIGN(8) : { *(.got .toc) } + + _end = .; + PROVIDE(end = .); + + /* + * Stabs debugging sections are here too. + */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + + /* + * DWARF debug sections. + * Symbols in the DWARF debugging sections are relative to the + * beginning of the section so we begin them at 0. + */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } + + . = ALIGN(4096); + PROVIDE(_vdso_data = .); + + /DISCARD/ : { + *(.note.GNU-stack) + *(.branch_lt) + *(.data .data.* .gnu.linkonce.d.* .sdata*) + *(.bss .sbss .dynbss .dynsbss) + } +} + +/* + * Very old versions of ld do not recognize this name token; use the constant. + */ +#define PT_GNU_EH_FRAME 0x6474e550 + +/* + * We must supply the ELF program headers explicitly to get just one + * PT_LOAD segment, and set the flags explicitly to make segments read-only. + */ +PHDRS +{ + text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */ + dynamic PT_DYNAMIC FLAGS(4); /* PF_R */ + note PT_NOTE FLAGS(4); /* PF_R */ + eh_frame_hdr PT_GNU_EH_FRAME; +} + +/* + * This controls what symbols we export from the DSO. + */ +VERSION +{ + VDSO_VERSION_STRING { + global: + /* + * Has to be there for the kernel to find + */ + __kernel_gettimeofday; + __kernel_clock_gettime; + __kernel_clock_getres; + + local: *; + }; +} diff --git a/arch/s390/kernel/vdso32/vdso32_wrapper.S b/arch/s390/kernel/vdso32/vdso32_wrapper.S new file mode 100644 index 0000000000000000000000000000000000000000..61639a89e70b93e7c7355eb080c7afcf07e79b2d --- /dev/null +++ b/arch/s390/kernel/vdso32/vdso32_wrapper.S @@ -0,0 +1,13 @@ +#include +#include + + .section ".data.page_aligned" + + .globl vdso32_start, vdso32_end + .balign PAGE_SIZE +vdso32_start: + .incbin "arch/s390/kernel/vdso32/vdso32.so" + .balign PAGE_SIZE +vdso32_end: + + .previous diff --git a/arch/s390/kernel/vdso64/Makefile b/arch/s390/kernel/vdso64/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6fc8e829258c50be575bf1870d40ca4879b88a00 --- /dev/null +++ b/arch/s390/kernel/vdso64/Makefile @@ -0,0 +1,55 @@ +# List of files in the vdso, has to be asm only for now + +obj-vdso64 = gettimeofday.o clock_getres.o clock_gettime.o note.o + +# Build rules + +targets := $(obj-vdso64) vdso64.so vdso64.so.dbg +obj-vdso64 := $(addprefix $(obj)/, $(obj-vdso64)) + +KBUILD_AFLAGS_64 := $(filter-out -m64,$(KBUILD_AFLAGS)) +KBUILD_AFLAGS_64 += -m64 -s + +KBUILD_CFLAGS_64 := $(filter-out -m64,$(KBUILD_CFLAGS)) +KBUILD_CFLAGS_64 += -m64 -fPIC -shared -fno-common -fno-builtin +KBUILD_CFLAGS_64 += -nostdlib -Wl,-soname=linux-vdso64.so.1 \ + $(call ld-option, -Wl$(comma)--hash-style=sysv) + +$(targets:%=$(obj)/%.dbg): KBUILD_CFLAGS = $(KBUILD_CFLAGS_64) +$(targets:%=$(obj)/%.dbg): KBUILD_AFLAGS = $(KBUILD_AFLAGS_64) + +obj-y += vdso64_wrapper.o +extra-y += vdso64.lds +CPPFLAGS_vdso64.lds += -P -C -U$(ARCH) + +# Force dependency (incbin is bad) +$(obj)/vdso64_wrapper.o : $(obj)/vdso64.so + +# link rule for the .so file, .lds has to be first +$(obj)/vdso64.so.dbg: $(src)/vdso64.lds $(obj-vdso64) + $(call if_changed,vdso64ld) + +# strip rule for the .so file +$(obj)/%.so: OBJCOPYFLAGS := -S +$(obj)/%.so: $(obj)/%.so.dbg FORCE + $(call if_changed,objcopy) + +# assembly rules for the .S files +$(obj-vdso64): %.o: %.S + $(call if_changed_dep,vdso64as) + +# actual build commands +quiet_cmd_vdso64ld = VDSO64L $@ + cmd_vdso64ld = $(CC) $(c_flags) -Wl,-T $^ -o $@ +quiet_cmd_vdso64as = VDSO64A $@ + cmd_vdso64as = $(CC) $(a_flags) -c -o $@ $< + +# install commands for the unstripped file +quiet_cmd_vdso_install = INSTALL $@ + cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@ + +vdso64.so: $(obj)/vdso64.so.dbg + @mkdir -p $(MODLIB)/vdso + $(call cmd,vdso_install) + +vdso_install: vdso64.so diff --git a/arch/s390/kernel/vdso64/clock_getres.S b/arch/s390/kernel/vdso64/clock_getres.S new file mode 100644 index 0000000000000000000000000000000000000000..488e31a3c0e7ba1714542f3d7010d8fd449088e7 --- /dev/null +++ b/arch/s390/kernel/vdso64/clock_getres.S @@ -0,0 +1,39 @@ +/* + * Userland implementation of clock_getres() for 64 bits processes in a + * s390 kernel for use in the vDSO + * + * Copyright IBM Corp. 2008 + * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License (version 2 only) + * as published by the Free Software Foundation. + */ +#include +#include +#include + + .text + .align 4 + .globl __kernel_clock_getres + .type __kernel_clock_getres,@function +__kernel_clock_getres: + .cfi_startproc + cghi %r2,CLOCK_REALTIME + je 0f + cghi %r2,CLOCK_MONOTONIC + jne 2f +0: ltgr %r3,%r3 + jz 1f /* res == NULL */ + larl %r1,3f + lg %r0,0(%r1) + xc 0(8,%r3),0(%r3) /* set tp->tv_sec to zero */ + stg %r0,8(%r3) /* store tp->tv_usec */ +1: lghi %r2,0 + br %r14 +2: lghi %r1,__NR_clock_getres /* fallback to svc */ + svc 0 + br %r14 +3: .quad CLOCK_REALTIME_RES + .cfi_endproc + .size __kernel_clock_getres,.-__kernel_clock_getres diff --git a/arch/s390/kernel/vdso64/clock_gettime.S b/arch/s390/kernel/vdso64/clock_gettime.S new file mode 100644 index 0000000000000000000000000000000000000000..738a410b7eb28ec27d7185e1a5a70633a3380b8a --- /dev/null +++ b/arch/s390/kernel/vdso64/clock_gettime.S @@ -0,0 +1,89 @@ +/* + * Userland implementation of clock_gettime() for 64 bits processes in a + * s390 kernel for use in the vDSO + * + * Copyright IBM Corp. 2008 + * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License (version 2 only) + * as published by the Free Software Foundation. + */ +#include +#include +#include + + .text + .align 4 + .globl __kernel_clock_gettime + .type __kernel_clock_gettime,@function +__kernel_clock_gettime: + .cfi_startproc + larl %r5,_vdso_data + cghi %r2,CLOCK_REALTIME + je 4f + cghi %r2,CLOCK_MONOTONIC + jne 9f + + /* CLOCK_MONOTONIC */ + ltgr %r3,%r3 + jz 3f /* tp == NULL */ +0: lg %r4,__VDSO_UPD_COUNT(%r5) /* load update counter */ + tmll %r4,0x0001 /* pending update ? loop */ + jnz 0b + stck 48(%r15) /* Store TOD clock */ + lg %r1,48(%r15) + sg %r1,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */ + mghi %r1,1000 + srlg %r1,%r1,12 /* cyc2ns(clock,cycle_delta) */ + alg %r1,__VDSO_XTIME_NSEC(%r5) /* + xtime */ + lg %r0,__VDSO_XTIME_SEC(%r5) + alg %r1,__VDSO_WTOM_NSEC(%r5) /* + wall_to_monotonic */ + alg %r0,__VDSO_WTOM_SEC(%r5) + clg %r4,__VDSO_UPD_COUNT(%r5) /* check update counter */ + jne 0b + larl %r5,10f +1: clg %r1,0(%r5) + jl 2f + slg %r1,0(%r5) + aghi %r0,1 + j 1b +2: stg %r0,0(%r3) /* store tp->tv_sec */ + stg %r1,8(%r3) /* store tp->tv_nsec */ +3: lghi %r2,0 + br %r14 + + /* CLOCK_REALTIME */ +4: ltr %r3,%r3 /* tp == NULL */ + jz 8f +5: lg %r4,__VDSO_UPD_COUNT(%r5) /* load update counter */ + tmll %r4,0x0001 /* pending update ? loop */ + jnz 5b + stck 48(%r15) /* Store TOD clock */ + lg %r1,48(%r15) + sg %r1,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */ + mghi %r1,1000 + srlg %r1,%r1,12 /* cyc2ns(clock,cycle_delta) */ + alg %r1,__VDSO_XTIME_NSEC(%r5) /* + xtime */ + lg %r0,__VDSO_XTIME_SEC(%r5) + clg %r4,__VDSO_UPD_COUNT(%r5) /* check update counter */ + jne 5b + larl %r5,10f +6: clg %r1,0(%r5) + jl 7f + slg %r1,0(%r5) + aghi %r0,1 + j 6b +7: stg %r0,0(%r3) /* store tp->tv_sec */ + stg %r1,8(%r3) /* store tp->tv_nsec */ +8: lghi %r2,0 + br %r14 + + /* Fallback to system call */ +9: lghi %r1,__NR_clock_gettime + svc 0 + br %r14 + +10: .quad 1000000000 + .cfi_endproc + .size __kernel_clock_gettime,.-__kernel_clock_gettime diff --git a/arch/s390/kernel/vdso64/gettimeofday.S b/arch/s390/kernel/vdso64/gettimeofday.S new file mode 100644 index 0000000000000000000000000000000000000000..f873e75634e1b1041a4df34caa9083c604ce5e45 --- /dev/null +++ b/arch/s390/kernel/vdso64/gettimeofday.S @@ -0,0 +1,56 @@ +/* + * Userland implementation of gettimeofday() for 64 bits processes in a + * s390 kernel for use in the vDSO + * + * Copyright IBM Corp. 2008 + * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License (version 2 only) + * as published by the Free Software Foundation. + */ +#include +#include +#include + + .text + .align 4 + .globl __kernel_gettimeofday + .type __kernel_gettimeofday,@function +__kernel_gettimeofday: + .cfi_startproc + larl %r5,_vdso_data +0: ltgr %r3,%r3 /* check if tz is NULL */ + je 1f + mvc 0(8,%r3),__VDSO_TIMEZONE(%r5) +1: ltgr %r2,%r2 /* check if tv is NULL */ + je 4f + lg %r4,__VDSO_UPD_COUNT(%r5) /* load update counter */ + tmll %r4,0x0001 /* pending update ? loop */ + jnz 0b + stck 48(%r15) /* Store TOD clock */ + lg %r1,48(%r15) + sg %r1,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */ + mghi %r1,1000 + srlg %r1,%r1,12 /* cyc2ns(clock,cycle_delta) */ + alg %r1,__VDSO_XTIME_NSEC(%r5) /* + xtime.tv_nsec */ + lg %r0,__VDSO_XTIME_SEC(%r5) /* xtime.tv_sec */ + clg %r4,__VDSO_UPD_COUNT(%r5) /* check update counter */ + jne 0b + larl %r5,5f +2: clg %r1,0(%r5) + jl 3f + slg %r1,0(%r5) + aghi %r0,1 + j 2b +3: stg %r0,0(%r2) /* store tv->tv_sec */ + slgr %r0,%r0 /* tv_nsec -> tv_usec */ + ml %r0,8(%r5) + srlg %r0,%r0,6 + stg %r0,8(%r2) /* store tv->tv_usec */ +4: lghi %r2,0 + br %r14 +5: .quad 1000000000 + .long 274877907 + .cfi_endproc + .size __kernel_gettimeofday,.-__kernel_gettimeofday diff --git a/arch/s390/kernel/vdso64/note.S b/arch/s390/kernel/vdso64/note.S new file mode 100644 index 0000000000000000000000000000000000000000..79a071e4357e4bc51f8813427d0f0ffa4c5ba56c --- /dev/null +++ b/arch/s390/kernel/vdso64/note.S @@ -0,0 +1,12 @@ +/* + * This supplies .note.* sections to go into the PT_NOTE inside the vDSO text. + * Here we can supply some information useful to userland. + */ + +#include +#include +#include + +ELFNOTE_START(Linux, 0, "a") + .long LINUX_VERSION_CODE +ELFNOTE_END diff --git a/arch/s390/kernel/vdso64/vdso64.lds.S b/arch/s390/kernel/vdso64/vdso64.lds.S new file mode 100644 index 0000000000000000000000000000000000000000..9f5979d102a904bb68eaff8eab7b827cb878f268 --- /dev/null +++ b/arch/s390/kernel/vdso64/vdso64.lds.S @@ -0,0 +1,138 @@ +/* + * This is the infamous ld script for the 64 bits vdso + * library + */ +#include + +OUTPUT_FORMAT("elf64-s390", "elf64-s390", "elf64-s390") +OUTPUT_ARCH(s390:64-bit) +ENTRY(_start) + +SECTIONS +{ + . = VDSO64_LBASE + SIZEOF_HEADERS; + + .hash : { *(.hash) } :text + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + + .note : { *(.note.*) } :text :note + + . = ALIGN(16); + .text : { + *(.text .stub .text.* .gnu.linkonce.t.*) + } :text + PROVIDE(__etext = .); + PROVIDE(_etext = .); + PROVIDE(etext = .); + + /* + * Other stuff is appended to the text segment: + */ + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + + .dynamic : { *(.dynamic) } :text :dynamic + + .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr + .eh_frame : { KEEP (*(.eh_frame)) } :text + .gcc_except_table : { *(.gcc_except_table .gcc_except_table.*) } + + .rela.dyn ALIGN(8) : { *(.rela.dyn) } + .got ALIGN(8) : { *(.got .toc) } + + _end = .; + PROVIDE(end = .); + + /* + * Stabs debugging sections are here too. + */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + + /* + * DWARF debug sections. + * Symbols in the DWARF debugging sections are relative to the + * beginning of the section so we begin them at 0. + */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } + + . = ALIGN(4096); + PROVIDE(_vdso_data = .); + + /DISCARD/ : { + *(.note.GNU-stack) + *(.branch_lt) + *(.data .data.* .gnu.linkonce.d.* .sdata*) + *(.bss .sbss .dynbss .dynsbss) + } +} + +/* + * Very old versions of ld do not recognize this name token; use the constant. + */ +#define PT_GNU_EH_FRAME 0x6474e550 + +/* + * We must supply the ELF program headers explicitly to get just one + * PT_LOAD segment, and set the flags explicitly to make segments read-only. + */ +PHDRS +{ + text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */ + dynamic PT_DYNAMIC FLAGS(4); /* PF_R */ + note PT_NOTE FLAGS(4); /* PF_R */ + eh_frame_hdr PT_GNU_EH_FRAME; +} + +/* + * This controls what symbols we export from the DSO. + */ +VERSION +{ + VDSO_VERSION_STRING { + global: + /* + * Has to be there for the kernel to find + */ + __kernel_gettimeofday; + __kernel_clock_gettime; + __kernel_clock_getres; + + local: *; + }; +} diff --git a/arch/s390/kernel/vdso64/vdso64_wrapper.S b/arch/s390/kernel/vdso64/vdso64_wrapper.S new file mode 100644 index 0000000000000000000000000000000000000000..d8e2ac14d564d057bef615266bcf17abf90083cf --- /dev/null +++ b/arch/s390/kernel/vdso64/vdso64_wrapper.S @@ -0,0 +1,13 @@ +#include +#include + + .section ".data.page_aligned" + + .globl vdso64_start, vdso64_end + .balign PAGE_SIZE +vdso64_start: + .incbin "arch/s390/kernel/vdso64/vdso64.so" + .balign PAGE_SIZE +vdso64_end: + + .previous diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index 0fa5dc5d68e1dc2973459d60a71c491f59c6b631..75a6e62ea9737e09471fcfd57d13b0c8fcfbed01 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c @@ -27,7 +27,6 @@ static ext_int_info_t ext_int_info_timer; static DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer); -#ifdef CONFIG_VIRT_CPU_ACCOUNTING /* * Update process times based on virtual cpu times stored by entry.S * to the lowcore fields user_timer, system_timer & steal_clock. @@ -125,16 +124,6 @@ static inline void set_vtimer(__u64 expires) /* store expire time for this CPU timer */ __get_cpu_var(virt_cpu_timer).to_expire = expires; } -#else -static inline void set_vtimer(__u64 expires) -{ - S390_lowcore.last_update_timer = expires; - asm volatile ("SPT %0" : : "m" (S390_lowcore.last_update_timer)); - - /* store expire time for this CPU timer */ - __get_cpu_var(virt_cpu_timer).to_expire = expires; -} -#endif void vtime_start_cpu_timer(void) { diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c index 580fc64cc735f343f2576baaba0bebb8eef2b3e9..5c8457129603233e020c6799101360707f51354c 100644 --- a/arch/s390/mm/extmem.c +++ b/arch/s390/mm/extmem.c @@ -7,6 +7,9 @@ * (C) IBM Corporation 2002-2004 */ +#define KMSG_COMPONENT "extmem" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include @@ -24,19 +27,6 @@ #include #include -#define DCSS_DEBUG /* Debug messages on/off */ - -#define DCSS_NAME "extmem" -#ifdef DCSS_DEBUG -#define PRINT_DEBUG(x...) printk(KERN_DEBUG DCSS_NAME " debug:" x) -#else -#define PRINT_DEBUG(x...) do {} while (0) -#endif -#define PRINT_INFO(x...) printk(KERN_INFO DCSS_NAME " info:" x) -#define PRINT_WARN(x...) printk(KERN_WARNING DCSS_NAME " warning:" x) -#define PRINT_ERR(x...) printk(KERN_ERR DCSS_NAME " error:" x) - - #define DCSS_LOADSHR 0x00 #define DCSS_LOADNSR 0x04 #define DCSS_PURGESEG 0x08 @@ -286,7 +276,7 @@ query_segment_type (struct dcss_segment *seg) goto out_free; } if (diag_cc > 1) { - PRINT_WARN ("segment_type: diag returned error %ld\n", vmrc); + pr_warning("Querying a DCSS type failed with rc=%ld\n", vmrc); rc = dcss_diag_translate_rc (vmrc); goto out_free; } @@ -368,7 +358,6 @@ query_segment_type (struct dcss_segment *seg) * -EIO : could not perform query diagnose * -ENOENT : no such segment * -ENOTSUPP: multi-part segment cannot be used with linux - * -ENOSPC : segment cannot be used (overlaps with storage) * -ENOMEM : out of memory * 0 .. 6 : type of segment as defined in include/asm-s390/extmem.h */ @@ -480,9 +469,8 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long goto out_resource; } if (diag_cc > 1) { - PRINT_WARN ("segment_load: could not load segment %s - " - "diag returned error (%ld)\n", - name, end_addr); + pr_warning("Loading DCSS %s failed with rc=%ld\n", name, + end_addr); rc = dcss_diag_translate_rc(end_addr); dcss_diag(&purgeseg_scode, seg->dcss_name, &dummy, &dummy); @@ -496,15 +484,13 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long *addr = seg->start_addr; *end = seg->end; if (do_nonshared) - PRINT_INFO ("segment_load: loaded segment %s range %p .. %p " - "type %s in non-shared mode\n", name, - (void*)seg->start_addr, (void*)seg->end, - segtype_string[seg->vm_segtype]); + pr_info("DCSS %s of range %p to %p and type %s loaded as " + "exclusive-writable\n", name, (void*) seg->start_addr, + (void*) seg->end, segtype_string[seg->vm_segtype]); else { - PRINT_INFO ("segment_load: loaded segment %s range %p .. %p " - "type %s in shared mode\n", name, - (void*)seg->start_addr, (void*)seg->end, - segtype_string[seg->vm_segtype]); + pr_info("DCSS %s of range %p to %p and type %s loaded in " + "shared access mode\n", name, (void*) seg->start_addr, + (void*) seg->end, segtype_string[seg->vm_segtype]); } goto out; out_resource: @@ -593,14 +579,14 @@ segment_modify_shared (char *name, int do_nonshared) goto out_unlock; } if (do_nonshared == seg->do_nonshared) { - PRINT_INFO ("segment_modify_shared: not reloading segment %s" - " - already in requested mode\n",name); + pr_info("DCSS %s is already in the requested access " + "mode\n", name); rc = 0; goto out_unlock; } if (atomic_read (&seg->ref_count) != 1) { - PRINT_WARN ("segment_modify_shared: not reloading segment %s - " - "segment is in use by other driver(s)\n",name); + pr_warning("DCSS %s is in use and cannot be reloaded\n", + name); rc = -EAGAIN; goto out_unlock; } @@ -613,8 +599,8 @@ segment_modify_shared (char *name, int do_nonshared) seg->res->flags |= IORESOURCE_READONLY; if (request_resource(&iomem_resource, seg->res)) { - PRINT_WARN("segment_modify_shared: could not reload segment %s" - " - overlapping resources\n", name); + pr_warning("DCSS %s overlaps with used memory resources " + "and cannot be reloaded\n", name); rc = -EBUSY; kfree(seg->res); goto out_del_mem; @@ -632,9 +618,8 @@ segment_modify_shared (char *name, int do_nonshared) goto out_del_res; } if (diag_cc > 1) { - PRINT_WARN ("segment_modify_shared: could not reload segment %s" - " - diag returned error (%ld)\n", - name, end_addr); + pr_warning("Reloading DCSS %s failed with rc=%ld\n", name, + end_addr); rc = dcss_diag_translate_rc(end_addr); goto out_del_res; } @@ -673,8 +658,7 @@ segment_unload(char *name) mutex_lock(&dcss_lock); seg = segment_by_name (name); if (seg == NULL) { - PRINT_ERR ("could not find segment %s in segment_unload, " - "please report to linux390@de.ibm.com\n",name); + pr_err("Unloading unknown DCSS %s failed\n", name); goto out_unlock; } if (atomic_dec_return(&seg->ref_count) != 0) @@ -709,8 +693,7 @@ segment_save(char *name) seg = segment_by_name (name); if (seg == NULL) { - PRINT_ERR("could not find segment %s in segment_save, please " - "report to linux390@de.ibm.com\n", name); + pr_err("Saving unknown DCSS %s failed\n", name); goto out; } @@ -727,14 +710,14 @@ segment_save(char *name) response = 0; cpcmd(cmd1, NULL, 0, &response); if (response) { - PRINT_ERR("segment_save: DEFSEG failed with response code %i\n", - response); + pr_err("Saving a DCSS failed with DEFSEG response code " + "%i\n", response); goto out; } cpcmd(cmd2, NULL, 0, &response); if (response) { - PRINT_ERR("segment_save: SAVESEG failed with response code %i\n", - response); + pr_err("Saving a DCSS failed with SAVESEG response code " + "%i\n", response); goto out; } out: @@ -749,44 +732,41 @@ void segment_warning(int rc, char *seg_name) { switch (rc) { case -ENOENT: - PRINT_WARN("cannot load/query segment %s, " - "does not exist\n", seg_name); + pr_err("DCSS %s cannot be loaded or queried\n", seg_name); break; case -ENOSYS: - PRINT_WARN("cannot load/query segment %s, " - "not running on VM\n", seg_name); + pr_err("DCSS %s cannot be loaded or queried without " + "z/VM\n", seg_name); break; case -EIO: - PRINT_WARN("cannot load/query segment %s, " - "hardware error\n", seg_name); + pr_err("Loading or querying DCSS %s resulted in a " + "hardware error\n", seg_name); break; case -ENOTSUPP: - PRINT_WARN("cannot load/query segment %s, " - "is a multi-part segment\n", seg_name); + pr_err("DCSS %s has multiple page ranges and cannot be " + "loaded or queried\n", seg_name); break; case -ENOSPC: - PRINT_WARN("cannot load/query segment %s, " - "overlaps with storage\n", seg_name); + pr_err("DCSS %s overlaps with used storage and cannot " + "be loaded\n", seg_name); break; case -EBUSY: - PRINT_WARN("cannot load/query segment %s, " - "overlaps with already loaded dcss\n", seg_name); + pr_err("%s needs used memory resources and cannot be " + "loaded or queried\n", seg_name); break; case -EPERM: - PRINT_WARN("cannot load/query segment %s, " - "already loaded in incompatible mode\n", seg_name); + pr_err("DCSS %s is already loaded in a different access " + "mode\n", seg_name); break; case -ENOMEM: - PRINT_WARN("cannot load/query segment %s, " - "out of memory\n", seg_name); + pr_err("There is not enough memory to load or query " + "DCSS %s\n", seg_name); break; case -ERANGE: - PRINT_WARN("cannot load/query segment %s, " - "exceeds kernel mapping range\n", seg_name); + pr_err("DCSS %s exceeds the kernel mapping range (%lu) " + "and cannot be loaded\n", seg_name, VMEM_MAX_PHYS); break; default: - PRINT_WARN("cannot load/query segment %s, " - "return value %i\n", seg_name, rc); break; } } diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 5c9cbfc14c4d5ad9ad06bf18f3a4b2f523eebd0b..f32a5197128dcdce45374563cba26c67fed2f78e 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -13,6 +13,7 @@ config SUPERH select HAVE_OPROFILE select HAVE_GENERIC_DMA_COHERENT select HAVE_IOREMAP_PROT if MMU + select HAVE_ARCH_TRACEHOOK help The SuperH is a RISC processor targeted for use in embedded systems and consumer electronics; it was also used in the Sega Dreamcast @@ -23,8 +24,10 @@ config SUPERH32 def_bool !SUPERH64 select HAVE_KPROBES select HAVE_KRETPROBES - select HAVE_ARCH_TRACEHOOK select HAVE_FUNCTION_TRACER + select HAVE_FTRACE_MCOUNT_RECORD + select HAVE_DYNAMIC_FTRACE + select HAVE_ARCH_KGDB config SUPERH64 def_bool y if CPU_SH5 @@ -55,8 +58,6 @@ config GENERIC_HARDIRQS config GENERIC_HARDIRQS_NO__DO_IRQ def_bool y - depends on SUPERH32 && (!SH_DREAMCAST && !SH_SH4202_MICRODEV && \ - !SH_7751_SYSTEMH && !HD64461) config GENERIC_IRQ_PROBE def_bool y @@ -85,10 +86,17 @@ config GENERIC_LOCKBREAK config SYS_SUPPORTS_PM bool + depends on !SMP + +config ARCH_SUSPEND_POSSIBLE + def_bool n + +config ARCH_HIBERNATION_POSSIBLE + def_bool n config SYS_SUPPORTS_APM_EMULATION bool - select SYS_SUPPORTS_PM + select ARCH_SUSPEND_POSSIBLE config SYS_SUPPORTS_SMP bool @@ -183,6 +191,11 @@ config CPU_SUBTYPE_SH7619 # SH-2A Processor Support +config CPU_SUBTYPE_SH7201 + bool "Support SH7201 processor" + select CPU_SH2A + select CPU_HAS_FPU + config CPU_SUBTYPE_SH7203 bool "Support SH7203 processor" select CPU_SH2A @@ -456,8 +469,12 @@ config SH_CPU_FREQ depends on CPU_FREQ select CPU_FREQ_TABLE help - This adds the cpufreq driver for SuperH. At present, only - the SH-4 is supported. + This adds the cpufreq driver for SuperH. Any CPU that supports + clock rate rounding through the clock framework can use this + driver. While it will make the kernel slightly larger, this is + harmless for CPUs that don't support rate rounding. The driver + will also generate a notice in the boot log before disabling + itself if the CPU in question is not capable of rate rounding. For details, take a look at . @@ -469,9 +486,6 @@ source "arch/sh/drivers/Kconfig" endmenu -config ISA_DMA_API - bool - menu "Kernel features" source kernel/Kconfig.hz @@ -688,49 +702,6 @@ config MAPLE Dreamcast with a serial line terminal or a remote network connection. -config CF_ENABLER - bool "Compact Flash Enabler support" - depends on SOLUTION_ENGINE || SH_SH03 - ---help--- - Compact Flash is a small, removable mass storage device introduced - in 1994 originally as a PCMCIA device. If you say `Y' here, you - compile in support for Compact Flash devices directly connected to - a SuperH processor. A Compact Flash FAQ is available at - . - - If your board has "Directly Connected" CompactFlash at area 5 or 6, - you may want to enable this option. Then, you can use CF as - primary IDE drive (only tested for SanDisk). - - If in doubt, select 'N'. - -choice - prompt "Compact Flash Connection Area" - depends on CF_ENABLER - default CF_AREA6 - -config CF_AREA5 - bool "Area5" - help - If your board has "Directly Connected" CompactFlash, You should - select the area where your CF is connected to. - - - "Area5" if CompactFlash is connected to Area 5 (0x14000000) - - "Area6" if it is connected to Area 6 (0x18000000) - - "Area6" will work for most boards. - -config CF_AREA6 - bool "Area6" - -endchoice - -config CF_BASE_ADDR - hex - depends on CF_ENABLER - default "0xb8000000" if CF_AREA6 - default "0xb4000000" if CF_AREA5 - source "arch/sh/drivers/pci/Kconfig" source "drivers/pci/Kconfig" @@ -748,13 +719,11 @@ source "fs/Kconfig.binfmt" endmenu menu "Power management options (EXPERIMENTAL)" -depends on EXPERIMENTAL && SYS_SUPPORTS_PM +depends on EXPERIMENTAL -config ARCH_SUSPEND_POSSIBLE - def_bool y - depends on !SMP +source "kernel/power/Kconfig" -source kernel/power/Kconfig +source "drivers/cpuidle/Kconfig" endmenu diff --git a/arch/sh/Kconfig.debug b/arch/sh/Kconfig.debug index e6d2c8b11abdaea5490fe00e83d750d7d141017b..0d62681f72a092830134b0d5a80186fede6e59e0 100644 --- a/arch/sh/Kconfig.debug +++ b/arch/sh/Kconfig.debug @@ -98,18 +98,29 @@ config IRQSTACKS for handling hard and soft interrupts. This can help avoid overflowing the process kernel stacks. -config SH_KGDB - bool "Include KGDB kernel debugger" - select FRAME_POINTER - select DEBUG_INFO - depends on CPU_SH3 || CPU_SH4 +config DUMP_CODE + bool "Show disassembly of nearby code in register dumps" + depends on DEBUG_KERNEL && SUPERH32 + default y if DEBUG_BUGVERBOSE + default n + help + This prints out a code trace of the instructions leading up to + the faulting instruction as a debugging aid. As this does grow + the kernel in size a bit, most users will want to say N here. + + Those looking for more verbose debugging output should say Y. + +config SH_NO_BSS_INIT + bool "Avoid zeroing BSS (to speed-up startup on suitable platforms)" + depends on DEBUG_KERNEL + default n help - Include in-kernel hooks for kgdb, the Linux kernel source level - debugger. See for more information. - Unless you are intending to debug the kernel, say N here. + If running in painfully slow environments, such as an RTL + simulation or from remote memory via SHdebug, where the memory + can already be gauranteed to ber zeroed on boot, say Y. -menu "KGDB configuration options" - depends on SH_KGDB + For all other cases, say N. If this option seems perplexing, or + you aren't sure, say N. config MORE_COMPILE_OPTIONS bool "Add any additional compile options" @@ -122,85 +133,16 @@ config COMPILE_OPTIONS string "Additional compile arguments" depends on MORE_COMPILE_OPTIONS -config KGDB_NMI - def_bool n - prompt "Enter KGDB on NMI" - -config SH_KGDB_CONSOLE - def_bool n - prompt "Console messages through GDB" - depends on !SERIAL_SH_SCI_CONSOLE && SERIAL_SH_SCI=y - select SERIAL_CORE_CONSOLE - -config KGDB_SYSRQ - def_bool y - prompt "Allow SysRq 'G' to enter KGDB" - depends on MAGIC_SYSRQ - -comment "Serial port setup" - -config KGDB_DEFPORT - int "Port number (ttySCn)" - default "1" - -config KGDB_DEFBAUD - int "Baud rate" - default "115200" - -choice - prompt "Parity" - depends on SH_KGDB - default KGDB_DEFPARITY_N - -config KGDB_DEFPARITY_N - bool "None" - -config KGDB_DEFPARITY_E - bool "Even" - -config KGDB_DEFPARITY_O - bool "Odd" - -endchoice - -choice - prompt "Data bits" - depends on SH_KGDB - default KGDB_DEFBITS_8 - -config KGDB_DEFBITS_8 - bool "8" - -config KGDB_DEFBITS_7 - bool "7" - -endchoice - -endmenu - -if SUPERH64 - -config SH64_PROC_ASIDS - bool "Debug: report ASIDs through /proc/asids" - depends on PROC_FS && MMU - config SH64_SR_WATCH bool "Debug: set SR.WATCH to enable hardware watchpoints and trace" + depends on SUPERH64 config POOR_MANS_STRACE bool "Debug: enable rudimentary strace facility" + depends on SUPERH64 help This option allows system calls to be traced to the console. It also aids in detecting kernel stack underflow. It is useful for debugging early-userland problems (e.g. init incurring fatal exceptions.) -config SH_ALPHANUMERIC - bool "Enable debug outputs to on-board alphanumeric display" - depends on SH_CAYMAN - -config SH_NO_BSS_INIT - bool "Avoid zeroing BSS (to speed-up startup on suitable platforms)" - -endif - endmenu diff --git a/arch/sh/Makefile b/arch/sh/Makefile index c43eb0d7fa3bd2ac088cff7a21bf96387845b8a2..4067b0d9287b5000290784cdf07a9322cf90aa1c 100644 --- a/arch/sh/Makefile +++ b/arch/sh/Makefile @@ -32,6 +32,7 @@ cflags-$(CONFIG_CPU_SH4) := $(call cc-option,-m4,) \ $(call cc-option,-mno-implicit-fp,-m4-nofpu) cflags-$(CONFIG_CPU_SH4A) += $(call cc-option,-m4a,) \ $(call cc-option,-m4a-nofpu,) +cflags-$(CONFIG_CPU_SH4AL_DSP) += $(call cc-option,-m4al,) cflags-$(CONFIG_CPU_SH5) := $(call cc-option,-m5-32media-nofpu,) ifeq ($(cflags-y),) @@ -39,22 +40,16 @@ ifeq ($(cflags-y),) # In the case where we are stuck with a compiler that has been uselessly # restricted to a particular ISA, a favourite default of newer GCCs when # extensive multilib targets are not provided, ensure we get the best fit -# regarding FP generation. This is necessary to avoid references to FP -# variants in libgcc where integer variants exist, which otherwise result -# in link errors. This is intentionally stupid (albeit many orders of -# magnitude less than GCC's default behaviour), as anything with a large -# number of multilib targets better have been built correctly for -# the target in mind. +# regarding FP generation. This is intentionally stupid (albeit many +# orders of magnitude less than GCC's default behaviour), as anything +# with a large number of multilib targets better have been built +# correctly for the target in mind. # cflags-y += $(shell $(CC) $(KBUILD_CFLAGS) -print-multi-lib | \ grep nofpu | sed q | sed -e 's/^/-/;s/;.*$$//') -endif - -cflags-$(CONFIG_CPU_BIG_ENDIAN) += -mb -cflags-$(CONFIG_CPU_LITTLE_ENDIAN) += -ml - -cflags-y += $(call cc-option,-mno-fdpic) - +# At this point, anything goes. +isaflags-y := $(call as-option,-Wa$(comma)-isa=any,) +else # # -Wa,-isa= tuning implies -Wa,-dsp for the versions of binutils that # support it, while -Wa,-dsp by itself limits the range of usable opcodes @@ -67,7 +62,12 @@ isaflags-y := $(call as-option,-Wa$(comma)-isa=$(isa-y),) isaflags-$(CONFIG_SH_DSP) := \ $(call as-option,-Wa$(comma)-isa=$(isa-y),-Wa$(comma)-dsp) +endif +cflags-$(CONFIG_CPU_BIG_ENDIAN) += -mb +cflags-$(CONFIG_CPU_LITTLE_ENDIAN) += -ml + +cflags-y += $(call cc-option,-mno-fdpic) cflags-y += $(isaflags-y) -ffreestanding cflags-$(CONFIG_MORE_COMPILE_OPTIONS) += \ @@ -79,6 +79,9 @@ OBJCOPYFLAGS := -O binary -R .note -R .note.gnu.build-id -R .comment \ # Give the various platforms the opportunity to set default image types defaultimage-$(CONFIG_SUPERH32) := zImage defaultimage-$(CONFIG_SH_SH7785LCR) := uImage +defaultimage-$(CONFIG_SH_RSK) := uImage +defaultimage-$(CONFIG_SH_7206_SOLUTION_ENGINE) := vmlinux +defaultimage-$(CONFIG_SH_7619_SOLUTION_ENGINE) := vmlinux # Set some sensible Kbuild defaults KBUILD_DEFCONFIG := shx3_defconfig @@ -132,6 +135,7 @@ machdir-$(CONFIG_SH_LANDISK) += mach-landisk machdir-$(CONFIG_SH_TITAN) += mach-titan machdir-$(CONFIG_SH_LBOX_RE2) += mach-lboxre2 machdir-$(CONFIG_SH_CAYMAN) += mach-cayman +machdir-$(CONFIG_SH_RSK) += mach-rsk ifneq ($(machdir-y),) core-y += $(addprefix arch/sh/boards/, \ @@ -173,11 +177,8 @@ KBUILD_CFLAGS += -pipe $(cflags-y) KBUILD_CPPFLAGS += $(cflags-y) KBUILD_AFLAGS += $(cflags-y) -LIBGCC := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name) - libs-$(CONFIG_SUPERH32) := arch/sh/lib/ $(libs-y) libs-$(CONFIG_SUPERH64) := arch/sh/lib64/ $(libs-y) -libs-y += $(LIBGCC) PHONY += maketools FORCE diff --git a/arch/sh/boards/Kconfig b/arch/sh/boards/Kconfig index 50467f9d0d0bf70844d03f9915846dd00bad9bf0..861914747e4ecf4d2ea2ab2ad81e5c0c4a690d9c 100644 --- a/arch/sh/boards/Kconfig +++ b/arch/sh/boards/Kconfig @@ -126,10 +126,12 @@ config SH_RTS7751R2D Select RTS7751R2D if configuring for a Renesas Technology Sales SH-Graphics board. -config SH_RSK7203 - bool "RSK7203" - select GENERIC_GPIO - depends on CPU_SUBTYPE_SH7203 +config SH_RSK + bool "Renesas Starter Kit" + depends on CPU_SUBTYPE_SH7201 || CPU_SUBTYPE_SH7203 + help + Select this option if configuring for any of the RSK+ MCU + evaluation platforms. config SH_SDK7780 bool "SDK7780R3" @@ -253,6 +255,7 @@ source "arch/sh/boards/mach-r2d/Kconfig" source "arch/sh/boards/mach-highlander/Kconfig" source "arch/sh/boards/mach-sdk7780/Kconfig" source "arch/sh/boards/mach-migor/Kconfig" +source "arch/sh/boards/mach-rsk/Kconfig" if SH_MAGIC_PANEL_R2 diff --git a/arch/sh/boards/Makefile b/arch/sh/boards/Makefile index d9efa3923721d356131608196690c6d0ccebcb5f..269ae2be49ef5cc7b966d671488cc62368cd4c35 100644 --- a/arch/sh/boards/Makefile +++ b/arch/sh/boards/Makefile @@ -3,7 +3,6 @@ # obj-$(CONFIG_SH_AP325RXA) += board-ap325rxa.o obj-$(CONFIG_SH_MAGIC_PANEL_R2) += board-magicpanelr2.o -obj-$(CONFIG_SH_RSK7203) += board-rsk7203.o obj-$(CONFIG_SH_SH7785LCR) += board-sh7785lcr.o obj-$(CONFIG_SH_SHMIN) += board-shmin.o obj-$(CONFIG_SH_EDOSK7760) += board-edosk7760.o diff --git a/arch/sh/boards/board-ap325rxa.c b/arch/sh/boards/board-ap325rxa.c index 8881a643ac320c86cb3b2473b4e466e27c7151ae..1c67cba6e34f1929cd53f616f35783e83e097518 100644 --- a/arch/sh/boards/board-ap325rxa.c +++ b/arch/sh/boards/board-ap325rxa.c @@ -197,6 +197,10 @@ static struct resource lcdc_resources[] = { .end = 0xfe941fff, .flags = IORESOURCE_MEM, }, + [1] = { + .start = 28, + .flags = IORESOURCE_IRQ, + }, }; static struct platform_device lcdc_device = { @@ -303,6 +307,7 @@ static struct resource ceu_resources[] = { static struct platform_device ceu_device = { .name = "sh_mobile_ceu", + .id = 0, /* "ceu0" clock */ .num_resources = ARRAY_SIZE(ceu_resources), .resource = ceu_resources, .dev = { @@ -344,7 +349,6 @@ static int __init ap325rxa_devices_setup(void) gpio_export(GPIO_PTF7, 0); /* LCDC */ - clk_always_enable("mstp200"); gpio_request(GPIO_FN_LCDD15, NULL); gpio_request(GPIO_FN_LCDD14, NULL); gpio_request(GPIO_FN_LCDD13, NULL); @@ -375,7 +379,6 @@ static int __init ap325rxa_devices_setup(void) gpio_direction_output(GPIO_PTS3, 1); /* CEU */ - clk_always_enable("mstp203"); gpio_request(GPIO_FN_VIO_CLK2, NULL); gpio_request(GPIO_FN_VIO_VD2, NULL); gpio_request(GPIO_FN_VIO_HD2, NULL); diff --git a/arch/sh/boards/board-shmin.c b/arch/sh/boards/board-shmin.c index 5cc0867de5ab88809d37cb8f1e36dda5f0e580b3..b1dcbbc89188856d51cadc0292bee7c1cfe0986d 100644 --- a/arch/sh/boards/board-shmin.c +++ b/arch/sh/boards/board-shmin.c @@ -22,21 +22,13 @@ static void __init init_shmin_irq(void) plat_irq_setup_pins(IRQ_MODE_IRQ); } -static void __iomem *shmin_ioport_map(unsigned long port, unsigned int size) +static void __init shmin_setup(char **cmdline_p) { - static int dummy; - - if ((port & ~0x1f) == SHMIN_NE_BASE) - return (void __iomem *)(SHMIN_IO_BASE + port); - - dummy = 0; - - return &dummy; - + __set_io_port_base(SHMIN_IO_BASE); } static struct sh_machine_vector mv_shmin __initmv = { .mv_name = "SHMIN", + .mv_setup = shmin_setup, .mv_init_irq = init_shmin_irq, - .mv_ioport_map = shmin_ioport_map, }; diff --git a/arch/sh/boards/mach-cayman/Makefile b/arch/sh/boards/mach-cayman/Makefile index 489a8f8673681e94e5d63654627e9bf8d4dbfc3f..cafe1ac3b29c288570e0ac5cd14743b35174e7fe 100644 --- a/arch/sh/boards/mach-cayman/Makefile +++ b/arch/sh/boards/mach-cayman/Makefile @@ -2,4 +2,3 @@ # Makefile for the Hitachi Cayman specific parts of the kernel # obj-y := setup.o irq.o -obj-$(CONFIG_HEARTBEAT) += led.o diff --git a/arch/sh/boards/mach-cayman/irq.c b/arch/sh/boards/mach-cayman/irq.c index ceb37ae92c7045d8f0d10f31fadbc122f0e97ea6..da62ad516994bc74aecd4823502d682c21ee5660 100644 --- a/arch/sh/boards/mach-cayman/irq.c +++ b/arch/sh/boards/mach-cayman/irq.c @@ -94,31 +94,11 @@ static void ack_cayman_irq(unsigned int irq) disable_cayman_irq(irq); } -static void end_cayman_irq(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - enable_cayman_irq(irq); -} - -static unsigned int startup_cayman_irq(unsigned int irq) -{ - enable_cayman_irq(irq); - return 0; /* never anything pending */ -} - -static void shutdown_cayman_irq(unsigned int irq) -{ - disable_cayman_irq(irq); -} - -struct hw_interrupt_type cayman_irq_type = { - .typename = "Cayman-IRQ", - .startup = startup_cayman_irq, - .shutdown = shutdown_cayman_irq, - .enable = enable_cayman_irq, - .disable = disable_cayman_irq, - .ack = ack_cayman_irq, - .end = end_cayman_irq, +struct irq_chip cayman_irq_type = { + .name = "Cayman-IRQ", + .unmask = enable_cayman_irq, + .mask = disable_cayman_irq, + .mask_ack = ack_cayman_irq, }; int cayman_irq_demux(int evt) @@ -187,8 +167,9 @@ void init_cayman_irq(void) return; } - for (i=0; i - * - * May be copied or modified under the terms of the GNU General Public - * License. See linux/COPYING for more information. - * - * Flash the LEDs - */ -#include - -/* -** It is supposed these functions to be used for a low level -** debugging (via Cayman LEDs), hence to be available as soon -** as possible. -** Unfortunately Cayman LEDs relies on Cayman EPLD to be mapped -** (this happen when IRQ are initialized... quite late). -** These triky dependencies should be removed. Temporary, it -** may be enough to NOP until EPLD is mapped. -*/ - -extern unsigned long epld_virt; - -#define LED_ADDR (epld_virt + 0x008) -#define HDSP2534_ADDR (epld_virt + 0x100) - -void mach_led(int position, int value) -{ - if (!epld_virt) - return; - - if (value) - ctrl_outl(0, LED_ADDR); - else - ctrl_outl(1, LED_ADDR); - -} - -void mach_alphanum(int position, unsigned char value) -{ - if (!epld_virt) - return; - - ctrl_outb(value, HDSP2534_ADDR + 0xe0 + (position << 2)); -} - -void mach_alphanum_brightness(int setting) -{ - ctrl_outb(setting & 7, HDSP2534_ADDR + 0xc0); -} diff --git a/arch/sh/boards/mach-dreamcast/irq.c b/arch/sh/boards/mach-dreamcast/irq.c index 67bdc33dd411b26c104d51c2a8c724983ef653f6..f55fc8e795e9ef3bd11b381df49b5f903aa7a17d 100644 --- a/arch/sh/boards/mach-dreamcast/irq.c +++ b/arch/sh/boards/mach-dreamcast/irq.c @@ -10,106 +10,90 @@ */ #include -#include +#include #include #include -/* Dreamcast System ASIC Hardware Events - - - The Dreamcast's System ASIC (a.k.a. Holly) is responsible for receiving - hardware events from system peripherals and triggering an SH7750 IRQ. - Hardware events can trigger IRQs 13, 11, or 9 depending on which bits are - set in the Event Mask Registers (EMRs). When a hardware event is - triggered, it's corresponding bit in the Event Status Registers (ESRs) - is set, and that bit should be rewritten to the ESR to acknowledge that - event. - - There are three 32-bit ESRs located at 0xa05f8900 - 0xa05f6908. Event - types can be found in include/asm-sh/dreamcast/sysasic.h. There are three - groups of EMRs that parallel the ESRs. Each EMR group corresponds to an - IRQ, so 0xa05f6910 - 0xa05f6918 triggers IRQ 13, 0xa05f6920 - 0xa05f6928 - triggers IRQ 11, and 0xa05f6930 - 0xa05f6938 triggers IRQ 9. - - In the kernel, these events are mapped to virtual IRQs so that drivers can - respond to them as they would a normal interrupt. In order to keep this - mapping simple, the events are mapped as: - - 6900/6910 - Events 0-31, IRQ 13 - 6904/6924 - Events 32-63, IRQ 11 - 6908/6938 - Events 64-95, IRQ 9 - -*/ +/* + * Dreamcast System ASIC Hardware Events - + * + * The Dreamcast's System ASIC (a.k.a. Holly) is responsible for receiving + * hardware events from system peripherals and triggering an SH7750 IRQ. + * Hardware events can trigger IRQs 13, 11, or 9 depending on which bits are + * set in the Event Mask Registers (EMRs). When a hardware event is + * triggered, its corresponding bit in the Event Status Registers (ESRs) + * is set, and that bit should be rewritten to the ESR to acknowledge that + * event. + * + * There are three 32-bit ESRs located at 0xa05f6900 - 0xa05f6908. Event + * types can be found in arch/sh/include/mach-dreamcast/mach/sysasic.h. + * There are three groups of EMRs that parallel the ESRs. Each EMR group + * corresponds to an IRQ, so 0xa05f6910 - 0xa05f6918 triggers IRQ 13, + * 0xa05f6920 - 0xa05f6928 triggers IRQ 11, and 0xa05f6930 - 0xa05f6938 + * triggers IRQ 9. + * + * In the kernel, these events are mapped to virtual IRQs so that drivers can + * respond to them as they would a normal interrupt. In order to keep this + * mapping simple, the events are mapped as: + * + * 6900/6910 - Events 0-31, IRQ 13 + * 6904/6924 - Events 32-63, IRQ 11 + * 6908/6938 - Events 64-95, IRQ 9 + * + */ #define ESR_BASE 0x005f6900 /* Base event status register */ #define EMR_BASE 0x005f6910 /* Base event mask register */ -/* Helps us determine the EMR group that this event belongs to: 0 = 0x6910, - 1 = 0x6920, 2 = 0x6930; also determine the event offset */ +/* + * Helps us determine the EMR group that this event belongs to: 0 = 0x6910, + * 1 = 0x6920, 2 = 0x6930; also determine the event offset. + */ #define LEVEL(event) (((event) - HW_EVENT_IRQ_BASE) / 32) /* Return the hardware event's bit positon within the EMR/ESR */ #define EVENT_BIT(event) (((event) - HW_EVENT_IRQ_BASE) & 31) -/* For each of these *_irq routines, the IRQ passed in is the virtual IRQ - (logically mapped to the corresponding bit for the hardware event). */ +/* + * For each of these *_irq routines, the IRQ passed in is the virtual IRQ + * (logically mapped to the corresponding bit for the hardware event). + */ /* Disable the hardware event by masking its bit in its EMR */ static inline void disable_systemasic_irq(unsigned int irq) { - __u32 emr = EMR_BASE + (LEVEL(irq) << 4) + (LEVEL(irq) << 2); - __u32 mask; + __u32 emr = EMR_BASE + (LEVEL(irq) << 4) + (LEVEL(irq) << 2); + __u32 mask; - mask = inl(emr); - mask &= ~(1 << EVENT_BIT(irq)); - outl(mask, emr); + mask = inl(emr); + mask &= ~(1 << EVENT_BIT(irq)); + outl(mask, emr); } /* Enable the hardware event by setting its bit in its EMR */ static inline void enable_systemasic_irq(unsigned int irq) { - __u32 emr = EMR_BASE + (LEVEL(irq) << 4) + (LEVEL(irq) << 2); - __u32 mask; + __u32 emr = EMR_BASE + (LEVEL(irq) << 4) + (LEVEL(irq) << 2); + __u32 mask; - mask = inl(emr); - mask |= (1 << EVENT_BIT(irq)); - outl(mask, emr); + mask = inl(emr); + mask |= (1 << EVENT_BIT(irq)); + outl(mask, emr); } /* Acknowledge a hardware event by writing its bit back to its ESR */ -static void ack_systemasic_irq(unsigned int irq) -{ - __u32 esr = ESR_BASE + (LEVEL(irq) << 2); - disable_systemasic_irq(irq); - outl((1 << EVENT_BIT(irq)), esr); -} - -/* After a IRQ has been ack'd and responded to, it needs to be renabled */ -static void end_systemasic_irq(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - enable_systemasic_irq(irq); -} - -static unsigned int startup_systemasic_irq(unsigned int irq) -{ - enable_systemasic_irq(irq); - - return 0; -} - -static void shutdown_systemasic_irq(unsigned int irq) +static void mask_ack_systemasic_irq(unsigned int irq) { - disable_systemasic_irq(irq); + __u32 esr = ESR_BASE + (LEVEL(irq) << 2); + disable_systemasic_irq(irq); + outl((1 << EVENT_BIT(irq)), esr); } -struct hw_interrupt_type systemasic_int = { - .typename = "System ASIC", - .startup = startup_systemasic_irq, - .shutdown = shutdown_systemasic_irq, - .enable = enable_systemasic_irq, - .disable = disable_systemasic_irq, - .ack = ack_systemasic_irq, - .end = end_systemasic_irq, +struct irq_chip systemasic_int = { + .name = "System ASIC", + .mask = disable_systemasic_irq, + .mask_ack = mask_ack_systemasic_irq, + .unmask = enable_systemasic_irq, }; /* @@ -117,37 +101,37 @@ struct hw_interrupt_type systemasic_int = { */ int systemasic_irq_demux(int irq) { - __u32 emr, esr, status, level; - __u32 j, bit; - - switch (irq) { - case 13: - level = 0; - break; - case 11: - level = 1; - break; - case 9: - level = 2; - break; - default: - return irq; - } - emr = EMR_BASE + (level << 4) + (level << 2); - esr = ESR_BASE + (level << 2); - - /* Mask the ESR to filter any spurious, unwanted interrupts */ - status = inl(esr); - status &= inl(emr); - - /* Now scan and find the first set bit as the event to map */ - for (bit = 1, j = 0; j < 32; bit <<= 1, j++) { - if (status & bit) { - irq = HW_EVENT_IRQ_BASE + j + (level << 5); - return irq; - } - } - - /* Not reached */ - return irq; + __u32 emr, esr, status, level; + __u32 j, bit; + + switch (irq) { + case 13: + level = 0; + break; + case 11: + level = 1; + break; + case 9: + level = 2; + break; + default: + return irq; + } + emr = EMR_BASE + (level << 4) + (level << 2); + esr = ESR_BASE + (level << 2); + + /* Mask the ESR to filter any spurious, unwanted interrupts */ + status = inl(esr); + status &= inl(emr); + + /* Now scan and find the first set bit as the event to map */ + for (bit = 1, j = 0; j < 32; bit <<= 1, j++) { + if (status & bit) { + irq = HW_EVENT_IRQ_BASE + j + (level << 5); + return irq; + } + } + + /* Not reached */ + return irq; } diff --git a/arch/sh/boards/mach-dreamcast/setup.c b/arch/sh/boards/mach-dreamcast/setup.c index 7d944fc75e93498c2d25f3854274026972394d67..d1bee4884cd667da313e0105e490cd2b5a5e6750 100644 --- a/arch/sh/boards/mach-dreamcast/setup.c +++ b/arch/sh/boards/mach-dreamcast/setup.c @@ -28,7 +28,7 @@ #include #include -extern struct hw_interrupt_type systemasic_int; +extern struct irq_chip systemasic_int; extern void aica_time_init(void); extern int gapspci_init(void); extern int systemasic_irq_demux(int); @@ -47,7 +47,8 @@ static void __init dreamcast_setup(char **cmdline_p) /* Assign all virtual IRQs to the System ASIC int. handler */ for (i = HW_EVENT_IRQ_BASE; i < HW_EVENT_IRQ_MAX; i++) - irq_desc[i].chip = &systemasic_int; + set_irq_chip_and_handler(i, &systemasic_int, + handle_level_irq); board_time_init = aica_time_init; diff --git a/arch/sh/boards/mach-edosk7705/Makefile b/arch/sh/boards/mach-edosk7705/Makefile index 14bdd531f11627be815e69df5206bff15c3deeaf..cd54acb5149998f258fab8fce040daf49c1e56a9 100644 --- a/arch/sh/boards/mach-edosk7705/Makefile +++ b/arch/sh/boards/mach-edosk7705/Makefile @@ -3,4 +3,3 @@ # obj-y := setup.o io.o - diff --git a/arch/sh/boards/mach-edosk7705/io.c b/arch/sh/boards/mach-edosk7705/io.c index 7d153e50a01b73df05466c71d6825308333b4679..5b9c57c43241dbbcdafde5862b5328bc178fa0bb 100644 --- a/arch/sh/boards/mach-edosk7705/io.c +++ b/arch/sh/boards/mach-edosk7705/io.c @@ -10,28 +10,24 @@ #include #include -#include +#include #include #include #define SMC_IOADDR 0xA2000000 -#define maybebadio(name,port) \ - printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \ - #name, (port), (__u32) __builtin_return_address(0)) - /* Map the Ethernet addresses as if it is at 0x300 - 0x320 */ -unsigned long sh_edosk7705_isa_port2addr(unsigned long port) +static unsigned long sh_edosk7705_isa_port2addr(unsigned long port) { - if (port >= 0x300 && port < 0x320) { - /* SMC91C96 registers are 4 byte aligned rather than the - * usual 2 byte! - */ - return SMC_IOADDR + ( (port - 0x300) * 2); - } + /* + * SMC91C96 registers are 4 byte aligned rather than the + * usual 2 byte! + */ + if (port >= 0x300 && port < 0x320) + return SMC_IOADDR + ((port - 0x300) * 2); - maybebadio(sh_edosk7705_isa_port2addr, port); - return port; + maybebadio(port); + return port; } /* Trying to read / write bytes on odd-byte boundaries to the Ethernet @@ -42,53 +38,34 @@ unsigned long sh_edosk7705_isa_port2addr(unsigned long port) */ unsigned char sh_edosk7705_inb(unsigned long port) { - if (port >= 0x300 && port < 0x320 && port & 0x01) { - return (volatile unsigned char)(generic_inw(port -1) >> 8); - } - return *(volatile unsigned char *)sh_edosk7705_isa_port2addr(port); -} + if (port >= 0x300 && port < 0x320 && port & 0x01) + return __raw_readw(port - 1) >> 8; -unsigned int sh_edosk7705_inl(unsigned long port) -{ - return *(volatile unsigned long *)port; + return __raw_readb(sh_edosk7705_isa_port2addr(port)); } void sh_edosk7705_outb(unsigned char value, unsigned long port) { if (port >= 0x300 && port < 0x320 && port & 0x01) { - generic_outw(((unsigned short)value << 8), port -1); + __raw_writew(((unsigned short)value << 8), port - 1); return; } - *(volatile unsigned char *)sh_edosk7705_isa_port2addr(port) = value; -} -void sh_edosk7705_outl(unsigned int value, unsigned long port) -{ - *(volatile unsigned long *)port = value; + __raw_writeb(value, sh_edosk7705_isa_port2addr(port)); } void sh_edosk7705_insb(unsigned long port, void *addr, unsigned long count) { unsigned char *p = addr; - while (count--) *p++ = sh_edosk7705_inb(port); -} -void sh_edosk7705_insl(unsigned long port, void *addr, unsigned long count) -{ - unsigned long *p = (unsigned long*)addr; while (count--) - *p++ = *(volatile unsigned long *)port; + *p++ = sh_edosk7705_inb(port); } void sh_edosk7705_outsb(unsigned long port, const void *addr, unsigned long count) { - unsigned char *p = (unsigned char*)addr; - while (count--) sh_edosk7705_outb(*p++, port); -} + unsigned char *p = (unsigned char *)addr; -void sh_edosk7705_outsl(unsigned long port, const void *addr, unsigned long count) -{ - unsigned long *p = (unsigned long*)addr; - while (count--) sh_edosk7705_outl(*p++, port); + while (count--) + sh_edosk7705_outb(*p++, port); } - diff --git a/arch/sh/boards/mach-edosk7705/setup.c b/arch/sh/boards/mach-edosk7705/setup.c index ab3f47bffdf3ea2f644391f25cd8870d2a8d489b..d59225e26fb997bfb1b8032e0c7ff12168f43347 100644 --- a/arch/sh/boards/mach-edosk7705/setup.c +++ b/arch/sh/boards/mach-edosk7705/setup.c @@ -9,6 +9,7 @@ * board by S. Dunn, 2003. */ #include +#include #include #include @@ -26,18 +27,10 @@ static struct sh_machine_vector mv_edosk7705 __initmv = { .mv_nr_irqs = 80, .mv_inb = sh_edosk7705_inb, - .mv_inl = sh_edosk7705_inl, .mv_outb = sh_edosk7705_outb, - .mv_outl = sh_edosk7705_outl, - - .mv_inl_p = sh_edosk7705_inl, - .mv_outl_p = sh_edosk7705_outl, .mv_insb = sh_edosk7705_insb, - .mv_insl = sh_edosk7705_insl, .mv_outsb = sh_edosk7705_outsb, - .mv_outsl = sh_edosk7705_outsl, - .mv_isa_port2addr = sh_edosk7705_isa_port2addr, .mv_init_irq = sh_edosk7705_init_irq, }; diff --git a/arch/sh/boards/mach-hp6xx/pm.c b/arch/sh/boards/mach-hp6xx/pm.c index 64af1f2eef05707b3925ab9ccd6ed3e1ec0ef420..d936c1af7620263244d6471fb4890432a0b54184 100644 --- a/arch/sh/boards/mach-hp6xx/pm.c +++ b/arch/sh/boards/mach-hp6xx/pm.c @@ -10,15 +10,91 @@ #include #include #include +#include +#include #include #include #include #include -#include +#include +#include + +#define INTR_OFFSET 0x600 #define STBCR 0xffffff82 #define STBCR2 0xffffff88 +#define STBCR_STBY 0x80 +#define STBCR_MSTP2 0x04 + +#define MCR 0xffffff68 +#define RTCNT 0xffffff70 + +#define MCR_RMODE 2 +#define MCR_RFSH 4 + +extern u8 wakeup_start; +extern u8 wakeup_end; + +static void pm_enter(void) +{ + u8 stbcr, csr; + u16 frqcr, mcr; + u32 vbr_new, vbr_old; + + set_bl_bit(); + + /* set wdt */ + csr = sh_wdt_read_csr(); + csr &= ~WTCSR_TME; + csr |= WTCSR_CKS_4096; + sh_wdt_write_csr(csr); + csr = sh_wdt_read_csr(); + sh_wdt_write_cnt(0); + + /* disable PLL1 */ + frqcr = ctrl_inw(FRQCR); + frqcr &= ~(FRQCR_PLLEN | FRQCR_PSTBY); + ctrl_outw(frqcr, FRQCR); + + /* enable standby */ + stbcr = ctrl_inb(STBCR); + ctrl_outb(stbcr | STBCR_STBY | STBCR_MSTP2, STBCR); + + /* set self-refresh */ + mcr = ctrl_inw(MCR); + ctrl_outw(mcr & ~MCR_RFSH, MCR); + + /* set interrupt handler */ + asm volatile("stc vbr, %0" : "=r" (vbr_old)); + vbr_new = get_zeroed_page(GFP_ATOMIC); + udelay(50); + memcpy((void*)(vbr_new + INTR_OFFSET), + &wakeup_start, &wakeup_end - &wakeup_start); + asm volatile("ldc %0, vbr" : : "r" (vbr_new)); + + ctrl_outw(0, RTCNT); + ctrl_outw(mcr | MCR_RFSH | MCR_RMODE, MCR); + + cpu_sleep(); + + asm volatile("ldc %0, vbr" : : "r" (vbr_old)); + + free_page(vbr_new); + + /* enable PLL1 */ + frqcr = ctrl_inw(FRQCR); + frqcr |= FRQCR_PSTBY; + ctrl_outw(frqcr, FRQCR); + udelay(50); + frqcr |= FRQCR_PLLEN; + ctrl_outw(frqcr, FRQCR); + + ctrl_outb(stbcr, STBCR); + + clear_bl_bit(); +} + static int hp6x0_pm_enter(suspend_state_t state) { u8 stbcr, stbcr2; diff --git a/arch/sh/boards/mach-microdev/Makefile b/arch/sh/boards/mach-microdev/Makefile index 1387dd6c85eb53281a35a296ac6632e6b1db2985..4e3588e8806bb80efc6a9e4a1ae76c1b60358cd0 100644 --- a/arch/sh/boards/mach-microdev/Makefile +++ b/arch/sh/boards/mach-microdev/Makefile @@ -2,7 +2,4 @@ # Makefile for the SuperH MicroDev specific parts of the kernel # -obj-y := setup.o irq.o io.o - -obj-$(CONFIG_HEARTBEAT) += led.o - +obj-y := setup.o irq.o io.o fdc37c93xapm.o diff --git a/arch/sh/boards/mach-microdev/fdc37c93xapm.c b/arch/sh/boards/mach-microdev/fdc37c93xapm.c new file mode 100644 index 0000000000000000000000000000000000000000..458a7cf5fb46472a31756907812b0090b7773c87 --- /dev/null +++ b/arch/sh/boards/mach-microdev/fdc37c93xapm.c @@ -0,0 +1,160 @@ +/* + * + * Setup for the SMSC FDC37C93xAPM + * + * Copyright (C) 2003 Sean McGoogan (Sean.McGoogan@superh.com) + * Copyright (C) 2003, 2004 SuperH, Inc. + * Copyright (C) 2004, 2005 Paul Mundt + * + * SuperH SH4-202 MicroDev board support. + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + */ +#include +#include +#include +#include +#include + +#define SMSC_CONFIG_PORT_ADDR (0x3F0) +#define SMSC_INDEX_PORT_ADDR SMSC_CONFIG_PORT_ADDR +#define SMSC_DATA_PORT_ADDR (SMSC_INDEX_PORT_ADDR + 1) + +#define SMSC_ENTER_CONFIG_KEY 0x55 +#define SMSC_EXIT_CONFIG_KEY 0xaa + +#define SMCS_LOGICAL_DEV_INDEX 0x07 /* Logical Device Number */ +#define SMSC_DEVICE_ID_INDEX 0x20 /* Device ID */ +#define SMSC_DEVICE_REV_INDEX 0x21 /* Device Revision */ +#define SMSC_ACTIVATE_INDEX 0x30 /* Activate */ +#define SMSC_PRIMARY_BASE_INDEX 0x60 /* Primary Base Address */ +#define SMSC_SECONDARY_BASE_INDEX 0x62 /* Secondary Base Address */ +#define SMSC_PRIMARY_INT_INDEX 0x70 /* Primary Interrupt Select */ +#define SMSC_SECONDARY_INT_INDEX 0x72 /* Secondary Interrupt Select */ +#define SMSC_HDCS0_INDEX 0xf0 /* HDCS0 Address Decoder */ +#define SMSC_HDCS1_INDEX 0xf1 /* HDCS1 Address Decoder */ + +#define SMSC_IDE1_DEVICE 1 /* IDE #1 logical device */ +#define SMSC_IDE2_DEVICE 2 /* IDE #2 logical device */ +#define SMSC_PARALLEL_DEVICE 3 /* Parallel Port logical device */ +#define SMSC_SERIAL1_DEVICE 4 /* Serial #1 logical device */ +#define SMSC_SERIAL2_DEVICE 5 /* Serial #2 logical device */ +#define SMSC_KEYBOARD_DEVICE 7 /* Keyboard logical device */ +#define SMSC_CONFIG_REGISTERS 8 /* Configuration Registers (Aux I/O) */ + +#define SMSC_READ_INDEXED(index) ({ \ + outb((index), SMSC_INDEX_PORT_ADDR); \ + inb(SMSC_DATA_PORT_ADDR); }) +#define SMSC_WRITE_INDEXED(val, index) ({ \ + outb((index), SMSC_INDEX_PORT_ADDR); \ + outb((val), SMSC_DATA_PORT_ADDR); }) + +#define IDE1_PRIMARY_BASE 0x01f0 /* Task File Registe base for IDE #1 */ +#define IDE1_SECONDARY_BASE 0x03f6 /* Miscellaneous AT registers for IDE #1 */ +#define IDE2_PRIMARY_BASE 0x0170 /* Task File Registe base for IDE #2 */ +#define IDE2_SECONDARY_BASE 0x0376 /* Miscellaneous AT registers for IDE #2 */ + +#define SERIAL1_PRIMARY_BASE 0x03f8 +#define SERIAL2_PRIMARY_BASE 0x02f8 + +#define MSB(x) ( (x) >> 8 ) +#define LSB(x) ( (x) & 0xff ) + + /* General-Purpose base address on CPU-board FPGA */ +#define MICRODEV_FPGA_GP_BASE 0xa6100000ul + +static int __init smsc_superio_setup(void) +{ + + unsigned char devid, devrev; + + /* Initially the chip is in run state */ + /* Put it into configuration state */ + outb(SMSC_ENTER_CONFIG_KEY, SMSC_CONFIG_PORT_ADDR); + + /* Read device ID info */ + devid = SMSC_READ_INDEXED(SMSC_DEVICE_ID_INDEX); + devrev = SMSC_READ_INDEXED(SMSC_DEVICE_REV_INDEX); + + if ((devid == 0x30) && (devrev == 0x01)) + printk("SMSC FDC37C93xAPM SuperIO device detected\n"); + else + return -ENODEV; + + /* Select the keyboard device */ + SMSC_WRITE_INDEXED(SMSC_KEYBOARD_DEVICE, SMCS_LOGICAL_DEV_INDEX); + /* enable it */ + SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX); + /* enable the interrupts */ + SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_KEYBOARD, SMSC_PRIMARY_INT_INDEX); + SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_MOUSE, SMSC_SECONDARY_INT_INDEX); + + /* Select the Serial #1 device */ + SMSC_WRITE_INDEXED(SMSC_SERIAL1_DEVICE, SMCS_LOGICAL_DEV_INDEX); + /* enable it */ + SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX); + /* program with port addresses */ + SMSC_WRITE_INDEXED(MSB(SERIAL1_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+0); + SMSC_WRITE_INDEXED(LSB(SERIAL1_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+1); + SMSC_WRITE_INDEXED(0x00, SMSC_HDCS0_INDEX); + /* enable the interrupts */ + SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_SERIAL1, SMSC_PRIMARY_INT_INDEX); + + /* Select the Serial #2 device */ + SMSC_WRITE_INDEXED(SMSC_SERIAL2_DEVICE, SMCS_LOGICAL_DEV_INDEX); + /* enable it */ + SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX); + /* program with port addresses */ + SMSC_WRITE_INDEXED(MSB(SERIAL2_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+0); + SMSC_WRITE_INDEXED(LSB(SERIAL2_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+1); + SMSC_WRITE_INDEXED(0x00, SMSC_HDCS0_INDEX); + /* enable the interrupts */ + SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_SERIAL2, SMSC_PRIMARY_INT_INDEX); + + /* Select the IDE#1 device */ + SMSC_WRITE_INDEXED(SMSC_IDE1_DEVICE, SMCS_LOGICAL_DEV_INDEX); + /* enable it */ + SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX); + /* program with port addresses */ + SMSC_WRITE_INDEXED(MSB(IDE1_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+0); + SMSC_WRITE_INDEXED(LSB(IDE1_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+1); + SMSC_WRITE_INDEXED(MSB(IDE1_SECONDARY_BASE), SMSC_SECONDARY_BASE_INDEX+0); + SMSC_WRITE_INDEXED(LSB(IDE1_SECONDARY_BASE), SMSC_SECONDARY_BASE_INDEX+1); + SMSC_WRITE_INDEXED(0x0c, SMSC_HDCS0_INDEX); + SMSC_WRITE_INDEXED(0x00, SMSC_HDCS1_INDEX); + /* select the interrupt */ + SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_IDE1, SMSC_PRIMARY_INT_INDEX); + + /* Select the IDE#2 device */ + SMSC_WRITE_INDEXED(SMSC_IDE2_DEVICE, SMCS_LOGICAL_DEV_INDEX); + /* enable it */ + SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX); + /* program with port addresses */ + SMSC_WRITE_INDEXED(MSB(IDE2_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+0); + SMSC_WRITE_INDEXED(LSB(IDE2_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+1); + SMSC_WRITE_INDEXED(MSB(IDE2_SECONDARY_BASE), SMSC_SECONDARY_BASE_INDEX+0); + SMSC_WRITE_INDEXED(LSB(IDE2_SECONDARY_BASE), SMSC_SECONDARY_BASE_INDEX+1); + /* select the interrupt */ + SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_IDE2, SMSC_PRIMARY_INT_INDEX); + + /* Select the configuration registers */ + SMSC_WRITE_INDEXED(SMSC_CONFIG_REGISTERS, SMCS_LOGICAL_DEV_INDEX); + /* enable the appropriate GPIO pins for IDE functionality: + * bit[0] In/Out 1==input; 0==output + * bit[1] Polarity 1==invert; 0==no invert + * bit[2] Int Enb #1 1==Enable Combined IRQ #1; 0==disable + * bit[3:4] Function Select 00==original; 01==Alternate Function #1 + */ + SMSC_WRITE_INDEXED(0x00, 0xc2); /* GP42 = nIDE1_OE */ + SMSC_WRITE_INDEXED(0x01, 0xc5); /* GP45 = IDE1_IRQ */ + SMSC_WRITE_INDEXED(0x00, 0xc6); /* GP46 = nIOROP */ + SMSC_WRITE_INDEXED(0x00, 0xc7); /* GP47 = nIOWOP */ + SMSC_WRITE_INDEXED(0x08, 0xe8); /* GP20 = nIDE2_OE */ + + /* Exit the configuration state */ + outb(SMSC_EXIT_CONFIG_KEY, SMSC_CONFIG_PORT_ADDR); + + return 0; +} +device_initcall(smsc_superio_setup); diff --git a/arch/sh/boards/mach-microdev/irq.c b/arch/sh/boards/mach-microdev/irq.c index 702753cbd28f2b418027839b0d20e83e0b21e1fe..b551963579c1c792f21bd4cc61abc381f6103a0b 100644 --- a/arch/sh/boards/mach-microdev/irq.c +++ b/arch/sh/boards/mach-microdev/irq.c @@ -67,27 +67,13 @@ static const struct { static void enable_microdev_irq(unsigned int irq); static void disable_microdev_irq(unsigned int irq); - - /* shutdown is same as "disable" */ -#define shutdown_microdev_irq disable_microdev_irq - static void mask_and_ack_microdev(unsigned int); -static void end_microdev_irq(unsigned int irq); - -static unsigned int startup_microdev_irq(unsigned int irq) -{ - enable_microdev_irq(irq); - return 0; /* never anything pending */ -} -static struct hw_interrupt_type microdev_irq_type = { - .typename = "MicroDev-IRQ", - .startup = startup_microdev_irq, - .shutdown = shutdown_microdev_irq, - .enable = enable_microdev_irq, - .disable = disable_microdev_irq, +static struct irq_chip microdev_irq_type = { + .name = "MicroDev-IRQ", + .unmask = enable_microdev_irq, + .mask = disable_microdev_irq, .ack = mask_and_ack_microdev, - .end = end_microdev_irq }; static void disable_microdev_irq(unsigned int irq) @@ -130,11 +116,11 @@ static void enable_microdev_irq(unsigned int irq) ctrl_outl(MICRODEV_FPGA_INTC_MASK(fpgaIrq), MICRODEV_FPGA_INTENB_REG); } - /* This functions sets the desired irq handler to be a MicroDev type */ +/* This function sets the desired irq handler to be a MicroDev type */ static void __init make_microdev_irq(unsigned int irq) { disable_irq_nosync(irq); - irq_desc[irq].chip = µdev_irq_type; + set_irq_chip_and_handler(irq, µdev_irq_type, handle_level_irq); disable_microdev_irq(irq); } @@ -143,17 +129,11 @@ static void mask_and_ack_microdev(unsigned int irq) disable_microdev_irq(irq); } -static void end_microdev_irq(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - enable_microdev_irq(irq); -} - extern void __init init_microdev_irq(void) { int i; - /* disable interrupts on the FPGA INTC register */ + /* disable interrupts on the FPGA INTC register */ ctrl_outl(~0ul, MICRODEV_FPGA_INTDSB_REG); for (i = 0; i < NUM_EXTERNAL_IRQS; i++) @@ -179,5 +159,3 @@ extern void microdev_print_fpga_intc_status(void) printk("FPGA_INTPRI[3..0] = %08x:%08x:%08x:%08x\n", *intprid, *intpric, *intprib, *intpria); printk("-------------------------------------------------------------------------------\n"); } - - diff --git a/arch/sh/boards/mach-microdev/led.c b/arch/sh/boards/mach-microdev/led.c deleted file mode 100644 index 36e54b47a752dda9cc67f97e8b162a4430958be4..0000000000000000000000000000000000000000 --- a/arch/sh/boards/mach-microdev/led.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * linux/arch/sh/boards/superh/microdev/led.c - * - * Copyright (C) 2002 Stuart Menefy - * Copyright (C) 2003 Richard Curnow (Richard.Curnow@superh.com) - * - * May be copied or modified under the terms of the GNU General Public - * License. See linux/COPYING for more information. - * - */ - -#include - -#define LED_REGISTER 0xa6104d20 - -static void mach_led_d9(int value) -{ - unsigned long reg; - reg = ctrl_inl(LED_REGISTER); - reg &= ~1; - reg |= (value & 1); - ctrl_outl(reg, LED_REGISTER); - return; -} - -static void mach_led_d10(int value) -{ - unsigned long reg; - reg = ctrl_inl(LED_REGISTER); - reg &= ~2; - reg |= ((value & 1) << 1); - ctrl_outl(reg, LED_REGISTER); - return; -} - - -#ifdef CONFIG_HEARTBEAT -#include - -static unsigned char banner_table[] = { - 0x11, 0x01, 0x11, 0x01, 0x11, 0x03, - 0x11, 0x01, 0x11, 0x01, 0x13, 0x03, - 0x11, 0x01, 0x13, 0x01, 0x13, 0x01, 0x11, 0x03, - 0x11, 0x03, - 0x11, 0x01, 0x13, 0x01, 0x11, 0x03, - 0x11, 0x01, 0x11, 0x01, 0x11, 0x01, 0x11, 0x07, - 0x13, 0x01, 0x13, 0x03, - 0x11, 0x01, 0x11, 0x03, - 0x13, 0x01, 0x11, 0x01, 0x13, 0x01, 0x11, 0x03, - 0x11, 0x01, 0x13, 0x01, 0x11, 0x03, - 0x13, 0x01, 0x13, 0x01, 0x13, 0x03, - 0x13, 0x01, 0x11, 0x01, 0x11, 0x03, - 0x11, 0x03, - 0x11, 0x01, 0x11, 0x01, 0x11, 0x01, 0x13, 0x07, - 0xff -}; - -static void banner(void) -{ - static int pos = 0; - static int count = 0; - - if (count) { - count--; - } else { - int val = banner_table[pos]; - if (val == 0xff) { - pos = 0; - val = banner_table[pos]; - } - pos++; - mach_led_d10((val >> 4) & 1); - count = 10 * (val & 0xf); - } -} - -/* From heartbeat_harp in the stboards directory */ -/* acts like an actual heart beat -- ie thump-thump-pause... */ -void microdev_heartbeat(void) -{ - static unsigned cnt = 0, period = 0, dist = 0; - - if (cnt == 0 || cnt == dist) - mach_led_d9(1); - else if (cnt == 7 || cnt == dist+7) - mach_led_d9(0); - - if (++cnt > period) { - cnt = 0; - /* The hyperbolic function below modifies the heartbeat period - * length in dependency of the current (5min) load. It goes - * through the points f(0)=126, f(1)=86, f(5)=51, - * f(inf)->30. */ - period = ((672< #include #include - -extern void microdev_heartbeat(void); - - -/****************************************************************************/ - - - /* - * Setup for the SMSC FDC37C93xAPM - */ -#define SMSC_CONFIG_PORT_ADDR (0x3F0) -#define SMSC_INDEX_PORT_ADDR SMSC_CONFIG_PORT_ADDR -#define SMSC_DATA_PORT_ADDR (SMSC_INDEX_PORT_ADDR + 1) - -#define SMSC_ENTER_CONFIG_KEY 0x55 -#define SMSC_EXIT_CONFIG_KEY 0xaa - -#define SMCS_LOGICAL_DEV_INDEX 0x07 /* Logical Device Number */ -#define SMSC_DEVICE_ID_INDEX 0x20 /* Device ID */ -#define SMSC_DEVICE_REV_INDEX 0x21 /* Device Revision */ -#define SMSC_ACTIVATE_INDEX 0x30 /* Activate */ -#define SMSC_PRIMARY_BASE_INDEX 0x60 /* Primary Base Address */ -#define SMSC_SECONDARY_BASE_INDEX 0x62 /* Secondary Base Address */ -#define SMSC_PRIMARY_INT_INDEX 0x70 /* Primary Interrupt Select */ -#define SMSC_SECONDARY_INT_INDEX 0x72 /* Secondary Interrupt Select */ -#define SMSC_HDCS0_INDEX 0xf0 /* HDCS0 Address Decoder */ -#define SMSC_HDCS1_INDEX 0xf1 /* HDCS1 Address Decoder */ - -#define SMSC_IDE1_DEVICE 1 /* IDE #1 logical device */ -#define SMSC_IDE2_DEVICE 2 /* IDE #2 logical device */ -#define SMSC_PARALLEL_DEVICE 3 /* Parallel Port logical device */ -#define SMSC_SERIAL1_DEVICE 4 /* Serial #1 logical device */ -#define SMSC_SERIAL2_DEVICE 5 /* Serial #2 logical device */ -#define SMSC_KEYBOARD_DEVICE 7 /* Keyboard logical device */ -#define SMSC_CONFIG_REGISTERS 8 /* Configuration Registers (Aux I/O) */ - -#define SMSC_READ_INDEXED(index) ({ \ - outb((index), SMSC_INDEX_PORT_ADDR); \ - inb(SMSC_DATA_PORT_ADDR); }) -#define SMSC_WRITE_INDEXED(val, index) ({ \ - outb((index), SMSC_INDEX_PORT_ADDR); \ - outb((val), SMSC_DATA_PORT_ADDR); }) - -#define IDE1_PRIMARY_BASE 0x01f0 /* Task File Registe base for IDE #1 */ -#define IDE1_SECONDARY_BASE 0x03f6 /* Miscellaneous AT registers for IDE #1 */ -#define IDE2_PRIMARY_BASE 0x0170 /* Task File Registe base for IDE #2 */ -#define IDE2_SECONDARY_BASE 0x0376 /* Miscellaneous AT registers for IDE #2 */ - -#define SERIAL1_PRIMARY_BASE 0x03f8 -#define SERIAL2_PRIMARY_BASE 0x02f8 - -#define MSB(x) ( (x) >> 8 ) -#define LSB(x) ( (x) & 0xff ) - - /* General-Purpose base address on CPU-board FPGA */ -#define MICRODEV_FPGA_GP_BASE 0xa6100000ul - - /* assume a Keyboard Controller is present */ -int microdev_kbd_controller_present = 1; +#include static struct resource smc91x_resources[] = { [0] = { .start = 0x300, - .end = 0x300 + 0x0001000 - 1, + .end = 0x300 + SZ_4K - 1, .flags = IORESOURCE_MEM, }, [1] = { @@ -97,7 +39,6 @@ static struct platform_device smc91x_device = { .resource = smc91x_resources, }; -#ifdef CONFIG_FB_S1D13XXX static struct s1d13xxxfb_regval s1d13806_initregs[] = { { S1DREG_MISC, 0x00 }, { S1DREG_COM_DISP_MODE, 0x00 }, @@ -216,12 +157,12 @@ static struct s1d13xxxfb_pdata s1d13806_platform_data = { static struct resource s1d13806_resources[] = { [0] = { .start = 0x07200000, - .end = 0x07200000 + 0x00200000 - 1, + .end = 0x07200000 + SZ_2M - 1, .flags = IORESOURCE_MEM, }, [1] = { .start = 0x07000000, - .end = 0x07000000 + 0x00200000 - 1, + .end = 0x07000000 + SZ_2M - 1, .flags = IORESOURCE_MEM, }, }; @@ -236,145 +177,24 @@ static struct platform_device s1d13806_device = { .platform_data = &s1d13806_platform_data, }, }; -#endif static struct platform_device *microdev_devices[] __initdata = { &smc91x_device, -#ifdef CONFIG_FB_S1D13XXX &s1d13806_device, -#endif }; static int __init microdev_devices_setup(void) { return platform_add_devices(microdev_devices, ARRAY_SIZE(microdev_devices)); } - -/* - * Setup for the SMSC FDC37C93xAPM - */ -static int __init smsc_superio_setup(void) -{ - - unsigned char devid, devrev; - - /* Initially the chip is in run state */ - /* Put it into configuration state */ - outb(SMSC_ENTER_CONFIG_KEY, SMSC_CONFIG_PORT_ADDR); - - /* Read device ID info */ - devid = SMSC_READ_INDEXED(SMSC_DEVICE_ID_INDEX); - devrev = SMSC_READ_INDEXED(SMSC_DEVICE_REV_INDEX); - if ( (devid==0x30) && (devrev==0x01) ) - { - printk("SMSC FDC37C93xAPM SuperIO device detected\n"); - } - else - { /* not the device identity we expected */ - printk("Not detected a SMSC FDC37C93xAPM SuperIO device (devid=0x%02x, rev=0x%02x)\n", - devid, devrev); - /* inform the keyboard driver that we have no keyboard controller */ - microdev_kbd_controller_present = 0; - /* little point in doing anything else in this functon */ - return 0; - } - - /* Select the keyboard device */ - SMSC_WRITE_INDEXED(SMSC_KEYBOARD_DEVICE, SMCS_LOGICAL_DEV_INDEX); - /* enable it */ - SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX); - /* enable the interrupts */ - SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_KEYBOARD, SMSC_PRIMARY_INT_INDEX); - SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_MOUSE, SMSC_SECONDARY_INT_INDEX); - - /* Select the Serial #1 device */ - SMSC_WRITE_INDEXED(SMSC_SERIAL1_DEVICE, SMCS_LOGICAL_DEV_INDEX); - /* enable it */ - SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX); - /* program with port addresses */ - SMSC_WRITE_INDEXED(MSB(SERIAL1_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+0); - SMSC_WRITE_INDEXED(LSB(SERIAL1_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+1); - SMSC_WRITE_INDEXED(0x00, SMSC_HDCS0_INDEX); - /* enable the interrupts */ - SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_SERIAL1, SMSC_PRIMARY_INT_INDEX); - - /* Select the Serial #2 device */ - SMSC_WRITE_INDEXED(SMSC_SERIAL2_DEVICE, SMCS_LOGICAL_DEV_INDEX); - /* enable it */ - SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX); - /* program with port addresses */ - SMSC_WRITE_INDEXED(MSB(SERIAL2_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+0); - SMSC_WRITE_INDEXED(LSB(SERIAL2_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+1); - SMSC_WRITE_INDEXED(0x00, SMSC_HDCS0_INDEX); - /* enable the interrupts */ - SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_SERIAL2, SMSC_PRIMARY_INT_INDEX); - - /* Select the IDE#1 device */ - SMSC_WRITE_INDEXED(SMSC_IDE1_DEVICE, SMCS_LOGICAL_DEV_INDEX); - /* enable it */ - SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX); - /* program with port addresses */ - SMSC_WRITE_INDEXED(MSB(IDE1_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+0); - SMSC_WRITE_INDEXED(LSB(IDE1_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+1); - SMSC_WRITE_INDEXED(MSB(IDE1_SECONDARY_BASE), SMSC_SECONDARY_BASE_INDEX+0); - SMSC_WRITE_INDEXED(LSB(IDE1_SECONDARY_BASE), SMSC_SECONDARY_BASE_INDEX+1); - SMSC_WRITE_INDEXED(0x0c, SMSC_HDCS0_INDEX); - SMSC_WRITE_INDEXED(0x00, SMSC_HDCS1_INDEX); - /* select the interrupt */ - SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_IDE1, SMSC_PRIMARY_INT_INDEX); - - /* Select the IDE#2 device */ - SMSC_WRITE_INDEXED(SMSC_IDE2_DEVICE, SMCS_LOGICAL_DEV_INDEX); - /* enable it */ - SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX); - /* program with port addresses */ - SMSC_WRITE_INDEXED(MSB(IDE2_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+0); - SMSC_WRITE_INDEXED(LSB(IDE2_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+1); - SMSC_WRITE_INDEXED(MSB(IDE2_SECONDARY_BASE), SMSC_SECONDARY_BASE_INDEX+0); - SMSC_WRITE_INDEXED(LSB(IDE2_SECONDARY_BASE), SMSC_SECONDARY_BASE_INDEX+1); - /* select the interrupt */ - SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_IDE2, SMSC_PRIMARY_INT_INDEX); - - /* Select the configuration registers */ - SMSC_WRITE_INDEXED(SMSC_CONFIG_REGISTERS, SMCS_LOGICAL_DEV_INDEX); - /* enable the appropriate GPIO pins for IDE functionality: - * bit[0] In/Out 1==input; 0==output - * bit[1] Polarity 1==invert; 0==no invert - * bit[2] Int Enb #1 1==Enable Combined IRQ #1; 0==disable - * bit[3:4] Function Select 00==original; 01==Alternate Function #1 - */ - SMSC_WRITE_INDEXED(0x00, 0xc2); /* GP42 = nIDE1_OE */ - SMSC_WRITE_INDEXED(0x01, 0xc5); /* GP45 = IDE1_IRQ */ - SMSC_WRITE_INDEXED(0x00, 0xc6); /* GP46 = nIOROP */ - SMSC_WRITE_INDEXED(0x00, 0xc7); /* GP47 = nIOWOP */ - SMSC_WRITE_INDEXED(0x08, 0xe8); /* GP20 = nIDE2_OE */ - - /* Exit the configuration state */ - outb(SMSC_EXIT_CONFIG_KEY, SMSC_CONFIG_PORT_ADDR); - - return 0; -} - -static void __init microdev_setup(char **cmdline_p) -{ - int * const fpgaRevisionRegister = (int*)(MICRODEV_FPGA_GP_BASE + 0x8ul); - const int fpgaRevision = *fpgaRevisionRegister; - int * const CacheControlRegister = (int*)CCR; - - device_initcall(microdev_devices_setup); - device_initcall(smsc_superio_setup); - - printk("SuperH %s board (FPGA rev: 0x%0x, CCR: 0x%0x)\n", - get_system_type(), fpgaRevision, *CacheControlRegister); -} +device_initcall(microdev_devices_setup); /* * The Machine Vector */ static struct sh_machine_vector mv_sh4202_microdev __initmv = { .mv_name = "SH4-202 MicroDev", - .mv_setup = microdev_setup, - .mv_nr_irqs = 72, /* QQQ need to check this - use the MACRO */ + .mv_nr_irqs = 72, .mv_inb = microdev_inb, .mv_inw = microdev_inw, @@ -398,8 +218,4 @@ static struct sh_machine_vector mv_sh4202_microdev __initmv = { .mv_outsl = microdev_outsl, .mv_init_irq = init_microdev_irq, - -#ifdef CONFIG_HEARTBEAT - .mv_heartbeat = microdev_heartbeat, -#endif }; diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c index 97528198029997ba34f814b35d8aa7f63cbf8f22..cc1408119c243bd5e4c5f3035ab9a2e0d83732a5 100644 --- a/arch/sh/boards/mach-migor/setup.c +++ b/arch/sh/boards/mach-migor/setup.c @@ -89,6 +89,7 @@ static struct resource sh_keysc_resources[] = { static struct platform_device sh_keysc_device = { .name = "sh_keysc", + .id = 0, /* "keysc0" clock */ .num_resources = ARRAY_SIZE(sh_keysc_resources), .resource = sh_keysc_resources, .dev = { @@ -261,6 +262,8 @@ static struct sh_mobile_lcdc_info sh_mobile_lcdc_info = { .sys_bus_cfg = { .ldmt2r = 0x06000a09, .ldmt3r = 0x180e3418, + /* set 1s delay to encourage fsync() */ + .deferred_io_msec = 1000, }, } #endif @@ -273,6 +276,10 @@ static struct resource migor_lcdc_resources[] = { .end = 0xfe941fff, .flags = IORESOURCE_MEM, }, + [1] = { + .start = 28, + .flags = IORESOURCE_IRQ, + }, }; static struct platform_device migor_lcdc_device = { @@ -300,6 +307,7 @@ static void camera_power_on(void) gpio_set_value(GPIO_PTT3, 0); mdelay(10); gpio_set_value(GPIO_PTT3, 1); + mdelay(10); /* wait to let chip come out of reset */ } static void camera_power_off(void) @@ -432,6 +440,7 @@ static struct resource migor_ceu_resources[] = { static struct platform_device migor_ceu_device = { .name = "sh_mobile_ceu", + .id = 0, /* "ceu0" clock */ .num_resources = ARRAY_SIZE(migor_ceu_resources), .resource = migor_ceu_resources, .dev = { @@ -479,7 +488,6 @@ static int __init migor_devices_setup(void) ctrl_outl(0x00110080, BSC_CS4WCR); /* KEYSC */ - clk_always_enable("mstp214"); /* KEYSC */ gpio_request(GPIO_FN_KEYOUT0, NULL); gpio_request(GPIO_FN_KEYOUT1, NULL); gpio_request(GPIO_FN_KEYOUT2, NULL); @@ -501,7 +509,6 @@ static int __init migor_devices_setup(void) gpio_request(GPIO_FN_IRQ6, NULL); /* LCD Panel */ - clk_always_enable("mstp200"); /* LCDC */ #ifdef CONFIG_SH_MIGOR_QVGA /* LCDC - QVGA - Enable SYS Interface signals */ gpio_request(GPIO_FN_LCDD17, NULL); gpio_request(GPIO_FN_LCDD16, NULL); @@ -554,7 +561,6 @@ static int __init migor_devices_setup(void) #endif /* CEU */ - clk_always_enable("mstp203"); /* CEU */ gpio_request(GPIO_FN_VIO_CLK2, NULL); gpio_request(GPIO_FN_VIO_VD2, NULL); gpio_request(GPIO_FN_VIO_HD2, NULL); @@ -589,12 +595,3 @@ static int __init migor_devices_setup(void) return platform_add_devices(migor_devices, ARRAY_SIZE(migor_devices)); } __initcall(migor_devices_setup); - -static void __init migor_setup(char **cmdline_p) -{ -} - -static struct sh_machine_vector mv_migor __initmv = { - .mv_name = "Migo-R", - .mv_setup = migor_setup, -}; diff --git a/arch/sh/boards/mach-rsk/Kconfig b/arch/sh/boards/mach-rsk/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..bff095dffc02bbb41525c9c81a3042a00d5b4433 --- /dev/null +++ b/arch/sh/boards/mach-rsk/Kconfig @@ -0,0 +1,18 @@ +if SH_RSK + +choice + prompt "RSK+ options" + default SH_RSK7203 + +config SH_RSK7201 + bool "RSK7201" + depends on CPU_SUBTYPE_SH7201 + +config SH_RSK7203 + bool "RSK7203" + select GENERIC_GPIO + depends on CPU_SUBTYPE_SH7203 + +endchoice + +endif diff --git a/arch/sh/boards/mach-rsk/Makefile b/arch/sh/boards/mach-rsk/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..498da75ce38b747ef35f992336dbe6d2f6ee79e3 --- /dev/null +++ b/arch/sh/boards/mach-rsk/Makefile @@ -0,0 +1,2 @@ +obj-y := setup.o +obj-$(CONFIG_SH_RSK7203) += devices-rsk7203.o diff --git a/arch/sh/boards/board-rsk7203.c b/arch/sh/boards/mach-rsk/devices-rsk7203.c similarity index 58% rename from arch/sh/boards/board-rsk7203.c rename to arch/sh/boards/mach-rsk/devices-rsk7203.c index 58266f06134ae5a187673e23eb89765a3c171510..73f743b9be8ddef2728ec1d06d2a7c742ed22b96 100644 --- a/arch/sh/boards/board-rsk7203.c +++ b/arch/sh/boards/mach-rsk/devices-rsk7203.c @@ -50,73 +50,6 @@ static struct platform_device smc911x_device = { }, }; -static const char *probes[] = { "cmdlinepart", NULL }; - -static struct mtd_partition *parsed_partitions; - -static struct mtd_partition rsk7203_partitions[] = { - { - .name = "Bootloader", - .offset = 0x00000000, - .size = 0x00040000, - .mask_flags = MTD_WRITEABLE, - }, { - .name = "Kernel", - .offset = MTDPART_OFS_NXTBLK, - .size = 0x001c0000, - }, { - .name = "Flash_FS", - .offset = MTDPART_OFS_NXTBLK, - .size = MTDPART_SIZ_FULL, - } -}; - -static struct physmap_flash_data flash_data = { - .width = 2, -}; - -static struct resource flash_resource = { - .start = 0x20000000, - .end = 0x20400000, - .flags = IORESOURCE_MEM, -}; - -static struct platform_device flash_device = { - .name = "physmap-flash", - .id = -1, - .resource = &flash_resource, - .num_resources = 1, - .dev = { - .platform_data = &flash_data, - }, -}; - -static struct mtd_info *flash_mtd; - -static struct map_info rsk7203_flash_map = { - .name = "RSK+ Flash", - .size = 0x400000, - .bankwidth = 2, -}; - -static void __init set_mtd_partitions(void) -{ - int nr_parts = 0; - - simple_map_init(&rsk7203_flash_map); - flash_mtd = do_map_probe("cfi_probe", &rsk7203_flash_map); - nr_parts = parse_mtd_partitions(flash_mtd, probes, - &parsed_partitions, 0); - /* If there is no partition table, used the hard coded table */ - if (nr_parts <= 0) { - flash_data.parts = rsk7203_partitions; - flash_data.nr_parts = ARRAY_SIZE(rsk7203_partitions); - } else { - flash_data.nr_parts = nr_parts; - flash_data.parts = parsed_partitions; - } -} - static struct gpio_led rsk7203_gpio_leds[] = { { .name = "green", @@ -155,7 +88,6 @@ static struct platform_device led_device = { static struct platform_device *rsk7203_devices[] __initdata = { &smc911x_device, - &flash_device, &led_device, }; @@ -165,15 +97,7 @@ static int __init rsk7203_devices_setup(void) gpio_request(GPIO_FN_TXD0, NULL); gpio_request(GPIO_FN_RXD0, NULL); - set_mtd_partitions(); return platform_add_devices(rsk7203_devices, ARRAY_SIZE(rsk7203_devices)); } device_initcall(rsk7203_devices_setup); - -/* - * The Machine Vector - */ -static struct sh_machine_vector mv_rsk7203 __initmv = { - .mv_name = "RSK+7203", -}; diff --git a/arch/sh/boards/mach-rsk/setup.c b/arch/sh/boards/mach-rsk/setup.c new file mode 100644 index 0000000000000000000000000000000000000000..af64d030a5c7027a09be844ca28014a8ee728e49 --- /dev/null +++ b/arch/sh/boards/mach-rsk/setup.c @@ -0,0 +1,106 @@ +/* + * Renesas Technology Europe RSK+ Support. + * + * Copyright (C) 2008 Paul Mundt + * Copyright (C) 2008 Peter Griffin + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const char *probes[] = { "cmdlinepart", NULL }; + +static struct mtd_partition *parsed_partitions; + +static struct mtd_partition rsk_partitions[] = { + { + .name = "Bootloader", + .offset = 0x00000000, + .size = 0x00040000, + .mask_flags = MTD_WRITEABLE, + }, { + .name = "Kernel", + .offset = MTDPART_OFS_NXTBLK, + .size = 0x001c0000, + }, { + .name = "Flash_FS", + .offset = MTDPART_OFS_NXTBLK, + .size = MTDPART_SIZ_FULL, + } +}; + +static struct physmap_flash_data flash_data = { + .width = 2, +}; + +static struct resource flash_resource = { + .start = 0x20000000, + .end = 0x20400000, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device flash_device = { + .name = "physmap-flash", + .id = -1, + .resource = &flash_resource, + .num_resources = 1, + .dev = { + .platform_data = &flash_data, + }, +}; + +static struct mtd_info *flash_mtd; + +static struct map_info rsk_flash_map = { + .name = "RSK+ Flash", + .size = 0x400000, + .bankwidth = 2, +}; + +static void __init set_mtd_partitions(void) +{ + int nr_parts = 0; + + simple_map_init(&rsk_flash_map); + flash_mtd = do_map_probe("cfi_probe", &rsk_flash_map); + nr_parts = parse_mtd_partitions(flash_mtd, probes, + &parsed_partitions, 0); + /* If there is no partition table, used the hard coded table */ + if (nr_parts <= 0) { + flash_data.parts = rsk_partitions; + flash_data.nr_parts = ARRAY_SIZE(rsk_partitions); + } else { + flash_data.nr_parts = nr_parts; + flash_data.parts = parsed_partitions; + } +} + +static struct platform_device *rsk_devices[] __initdata = { + &flash_device, +}; + +static int __init rsk_devices_setup(void) +{ + set_mtd_partitions(); + return platform_add_devices(rsk_devices, + ARRAY_SIZE(rsk_devices)); +} +device_initcall(rsk_devices_setup); + +/* + * The Machine Vector + */ +static struct sh_machine_vector mv_rsk __initmv = { + .mv_name = "RSK+", +}; diff --git a/arch/sh/boards/mach-se/7343/Makefile b/arch/sh/boards/mach-se/7343/Makefile index 3024796c6203b61771592cd6de0c701d4d367c41..4c3666a93790603f831ee4cb2b9dd5570bb42828 100644 --- a/arch/sh/boards/mach-se/7343/Makefile +++ b/arch/sh/boards/mach-se/7343/Makefile @@ -2,4 +2,4 @@ # Makefile for the 7343 SolutionEngine specific parts of the kernel # -obj-y := setup.o io.o irq.o +obj-y := setup.o irq.o diff --git a/arch/sh/boards/mach-se/7343/io.c b/arch/sh/boards/mach-se/7343/io.c deleted file mode 100644 index 8741abc1da7b108cab538fa652eab7f2c2b9286c..0000000000000000000000000000000000000000 --- a/arch/sh/boards/mach-se/7343/io.c +++ /dev/null @@ -1,273 +0,0 @@ -/* - * arch/sh/boards/se/7343/io.c - * - * I/O routine for SH-Mobile3AS 7343 SolutionEngine. - * - */ -#include -#include -#include - -#define badio(fn, a) panic("bad i/o operation %s for %08lx.", #fn, a) - -struct iop { - unsigned long start, end; - unsigned long base; - struct iop *(*check) (struct iop * p, unsigned long port); - unsigned char (*inb) (struct iop * p, unsigned long port); - unsigned short (*inw) (struct iop * p, unsigned long port); - void (*outb) (struct iop * p, unsigned char value, unsigned long port); - void (*outw) (struct iop * p, unsigned short value, unsigned long port); -}; - -struct iop * -simple_check(struct iop *p, unsigned long port) -{ - static int count; - - if (count < 100) - count++; - - port &= 0xFFFF; - - if ((p->start <= port) && (port <= p->end)) - return p; - else - badio(check, port); -} - -struct iop * -ide_check(struct iop *p, unsigned long port) -{ - if (((0x1f0 <= port) && (port <= 0x1f7)) || (port == 0x3f7)) - return p; - return NULL; -} - -unsigned char -simple_inb(struct iop *p, unsigned long port) -{ - return *(unsigned char *) (p->base + port); -} - -unsigned short -simple_inw(struct iop *p, unsigned long port) -{ - return *(unsigned short *) (p->base + port); -} - -void -simple_outb(struct iop *p, unsigned char value, unsigned long port) -{ - *(unsigned char *) (p->base + port) = value; -} - -void -simple_outw(struct iop *p, unsigned short value, unsigned long port) -{ - *(unsigned short *) (p->base + port) = value; -} - -unsigned char -pcc_inb(struct iop *p, unsigned long port) -{ - unsigned long addr = p->base + port + 0x40000; - unsigned long v; - - if (port & 1) - addr += 0x00400000; - v = *(volatile unsigned char *) addr; - return v; -} - -void -pcc_outb(struct iop *p, unsigned char value, unsigned long port) -{ - unsigned long addr = p->base + port + 0x40000; - - if (port & 1) - addr += 0x00400000; - *(volatile unsigned char *) addr = value; -} - -unsigned char -bad_inb(struct iop *p, unsigned long port) -{ - badio(inb, port); -} - -void -bad_outb(struct iop *p, unsigned char value, unsigned long port) -{ - badio(inw, port); -} - -#ifdef CONFIG_SMC91X -/* MSTLANEX01 LAN at 0xb400:0000 */ -static struct iop laniop = { - .start = 0x00, - .end = 0x0F, - .base = 0x04000000, - .check = simple_check, - .inb = simple_inb, - .inw = simple_inw, - .outb = simple_outb, - .outw = simple_outw, -}; -#endif - -#ifdef CONFIG_NE2000 -/* NE2000 pc card NIC */ -static struct iop neiop = { - .start = 0x280, - .end = 0x29f, - .base = 0xb0600000 + 0x80, /* soft 0x280 -> hard 0x300 */ - .check = simple_check, - .inb = pcc_inb, - .inw = simple_inw, - .outb = pcc_outb, - .outw = simple_outw, -}; -#endif - -#ifdef CONFIG_IDE -/* CF in CF slot */ -static struct iop cfiop = { - .base = 0xb0600000, - .check = ide_check, - .inb = pcc_inb, - .inw = simple_inw, - .outb = pcc_outb, - .outw = simple_outw, -}; -#endif - -static __inline__ struct iop * -port2iop(unsigned long port) -{ - if (0) ; -#if defined(CONFIG_SMC91X) - else if (laniop.check(&laniop, port)) - return &laniop; -#endif -#if defined(CONFIG_NE2000) - else if (neiop.check(&neiop, port)) - return &neiop; -#endif -#if defined(CONFIG_IDE) - else if (cfiop.check(&cfiop, port)) - return &cfiop; -#endif - else - return NULL; -} - -static inline void -delay(void) -{ - ctrl_inw(0xac000000); - ctrl_inw(0xac000000); -} - -unsigned char -sh7343se_inb(unsigned long port) -{ - struct iop *p = port2iop(port); - return (p->inb) (p, port); -} - -unsigned char -sh7343se_inb_p(unsigned long port) -{ - unsigned char v = sh7343se_inb(port); - delay(); - return v; -} - -unsigned short -sh7343se_inw(unsigned long port) -{ - struct iop *p = port2iop(port); - return (p->inw) (p, port); -} - -unsigned int -sh7343se_inl(unsigned long port) -{ - badio(inl, port); -} - -void -sh7343se_outb(unsigned char value, unsigned long port) -{ - struct iop *p = port2iop(port); - (p->outb) (p, value, port); -} - -void -sh7343se_outb_p(unsigned char value, unsigned long port) -{ - sh7343se_outb(value, port); - delay(); -} - -void -sh7343se_outw(unsigned short value, unsigned long port) -{ - struct iop *p = port2iop(port); - (p->outw) (p, value, port); -} - -void -sh7343se_outl(unsigned int value, unsigned long port) -{ - badio(outl, port); -} - -void -sh7343se_insb(unsigned long port, void *addr, unsigned long count) -{ - unsigned char *a = addr; - struct iop *p = port2iop(port); - while (count--) - *a++ = (p->inb) (p, port); -} - -void -sh7343se_insw(unsigned long port, void *addr, unsigned long count) -{ - unsigned short *a = addr; - struct iop *p = port2iop(port); - while (count--) - *a++ = (p->inw) (p, port); -} - -void -sh7343se_insl(unsigned long port, void *addr, unsigned long count) -{ - badio(insl, port); -} - -void -sh7343se_outsb(unsigned long port, const void *addr, unsigned long count) -{ - unsigned char *a = (unsigned char *) addr; - struct iop *p = port2iop(port); - while (count--) - (p->outb) (p, *a++, port); -} - -void -sh7343se_outsw(unsigned long port, const void *addr, unsigned long count) -{ - unsigned short *a = (unsigned short *) addr; - struct iop *p = port2iop(port); - while (count--) - (p->outw) (p, *a++, port); -} - -void -sh7343se_outsl(unsigned long port, const void *addr, unsigned long count) -{ - badio(outsw, port); -} diff --git a/arch/sh/boards/mach-se/7343/setup.c b/arch/sh/boards/mach-se/7343/setup.c index 486f40bf9274af768a169e5a38b035779c2b6336..4de56f35f41905ed07a48191b1e7d6267bd018fb 100644 --- a/arch/sh/boards/mach-se/7343/setup.c +++ b/arch/sh/boards/mach-se/7343/setup.c @@ -1,36 +1,16 @@ #include #include #include +#include +#include +#include +#include #include #include #include #include #include -static struct resource smc91x_resources[] = { - [0] = { - .start = 0x10000000, - .end = 0x1000000F, - .flags = IORESOURCE_MEM, - }, - [1] = { - /* - * shared with other devices via externel - * interrupt controller in FPGA... - */ - .start = SMC_IRQ, - .end = SMC_IRQ, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device smc91x_device = { - .name = "smc91x", - .id = 0, - .num_resources = ARRAY_SIZE(smc91x_resources), - .resource = smc91x_resources, -}; - static struct resource heartbeat_resources[] = { [0] = { .start = PA_LED, @@ -94,10 +74,83 @@ static struct platform_device nor_flash_device = { .resource = nor_flash_resources, }; +#define ST16C2550C_FLAGS (UPF_BOOT_AUTOCONF | UPF_IOREMAP) + +static struct plat_serial8250_port serial_platform_data[] = { + [0] = { + .iotype = UPIO_MEM, + .mapbase = 0x16000000, + .regshift = 1, + .flags = ST16C2550C_FLAGS, + .irq = UARTA_IRQ, + .uartclk = 7372800, + }, + [1] = { + .iotype = UPIO_MEM, + .mapbase = 0x17000000, + .regshift = 1, + .flags = ST16C2550C_FLAGS, + .irq = UARTB_IRQ, + .uartclk = 7372800, + }, + { }, +}; + +static struct platform_device uart_device = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = serial_platform_data, + }, +}; + +static void isp116x_delay(struct device *dev, int delay) +{ + ndelay(delay); +} + +static struct resource usb_resources[] = { + [0] = { + .start = 0x11800000, + .end = 0x11800001, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = 0x11800002, + .end = 0x11800003, + .flags = IORESOURCE_MEM, + }, + [2] = { + .start = USB_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct isp116x_platform_data usb_platform_data = { + .sel15Kres = 1, + .oc_enable = 1, + .int_act_high = 0, + .int_edge_triggered = 0, + .remote_wakeup_enable = 0, + .delay = isp116x_delay, +}; + +static struct platform_device usb_device = { + .name = "isp116x-hcd", + .id = -1, + .num_resources = ARRAY_SIZE(usb_resources), + .resource = usb_resources, + .dev = { + .platform_data = &usb_platform_data, + }, + +}; + static struct platform_device *sh7343se_platform_devices[] __initdata = { - &smc91x_device, &heartbeat_device, &nor_flash_device, + &uart_device, + &usb_device, }; static int __init sh7343se_devices_setup(void) @@ -126,27 +179,6 @@ static void __init sh7343se_setup(char **cmdline_p) static struct sh_machine_vector mv_7343se __initmv = { .mv_name = "SolutionEngine 7343", .mv_setup = sh7343se_setup, - .mv_nr_irqs = 108, - .mv_inb = sh7343se_inb, - .mv_inw = sh7343se_inw, - .mv_inl = sh7343se_inl, - .mv_outb = sh7343se_outb, - .mv_outw = sh7343se_outw, - .mv_outl = sh7343se_outl, - - .mv_inb_p = sh7343se_inb_p, - .mv_inw_p = sh7343se_inw, - .mv_inl_p = sh7343se_inl, - .mv_outb_p = sh7343se_outb_p, - .mv_outw_p = sh7343se_outw, - .mv_outl_p = sh7343se_outl, - - .mv_insb = sh7343se_insb, - .mv_insw = sh7343se_insw, - .mv_insl = sh7343se_insl, - .mv_outsb = sh7343se_outsb, - .mv_outsw = sh7343se_outsw, - .mv_outsl = sh7343se_outsl, - + .mv_nr_irqs = SE7343_FPGA_IRQ_BASE + SE7343_FPGA_IRQ_NR, .mv_init_irq = init_7343se_IRQ, }; diff --git a/arch/sh/boards/mach-se/770x/setup.c b/arch/sh/boards/mach-se/770x/setup.c index 9123d9687bf7c0c0ea07be94dd76e5b630644d82..527eb6b12610289248be45bff91d28dc66b993fc 100644 --- a/arch/sh/boards/mach-se/770x/setup.c +++ b/arch/sh/boards/mach-se/770x/setup.c @@ -8,8 +8,9 @@ */ #include #include -#include #include +#include +#include #include #include #include @@ -175,6 +176,7 @@ static struct platform_device *se_devices[] __initdata = { static int __init se_devices_setup(void) { + mrshpc_setup_windows(); return platform_add_devices(se_devices, ARRAY_SIZE(se_devices)); } device_initcall(se_devices_setup); diff --git a/arch/sh/boards/mach-se/7721/setup.c b/arch/sh/boards/mach-se/7721/setup.c index d3fc80ff4d833e1707a7c57fc1b29e93d9059c12..55af4c36b43a1f9d52b45f91edd00b8b56af11a6 100644 --- a/arch/sh/boards/mach-se/7721/setup.c +++ b/arch/sh/boards/mach-se/7721/setup.c @@ -12,8 +12,9 @@ */ #include #include -#include #include +#include +#include #include #include @@ -74,8 +75,8 @@ static struct platform_device *se7721_devices[] __initdata = { static int __init se7721_devices_setup(void) { - return platform_add_devices(se7721_devices, - ARRAY_SIZE(se7721_devices)); + mrshpc_setup_windows(); + return platform_add_devices(se7721_devices, ARRAY_SIZE(se7721_devices)); } device_initcall(se7721_devices_setup); diff --git a/arch/sh/boards/mach-se/7722/setup.c b/arch/sh/boards/mach-se/7722/setup.c index fe6f96517e12dbd4a83f0fcea06ca3048649c482..af84904ed86f0f5e6a0f0f0d999a782c3bd6a5b2 100644 --- a/arch/sh/boards/mach-se/7722/setup.c +++ b/arch/sh/boards/mach-se/7722/setup.c @@ -15,9 +15,10 @@ #include #include #include +#include +#include #include #include -#include #include #include #include @@ -130,6 +131,7 @@ static struct resource sh_keysc_resources[] = { static struct platform_device sh_keysc_device = { .name = "sh_keysc", + .id = 0, /* "keysc0" clock */ .num_resources = ARRAY_SIZE(sh_keysc_resources), .resource = sh_keysc_resources, .dev = { @@ -146,10 +148,8 @@ static struct platform_device *se7722_devices[] __initdata = { static int __init se7722_devices_setup(void) { - clk_always_enable("mstp214"); /* KEYSC */ - - return platform_add_devices(se7722_devices, - ARRAY_SIZE(se7722_devices)); + mrshpc_setup_windows(); + return platform_add_devices(se7722_devices, ARRAY_SIZE(se7722_devices)); } device_initcall(se7722_devices_setup); diff --git a/arch/sh/boards/mach-sh03/setup.c b/arch/sh/boards/mach-sh03/setup.c index 5771219be3fdcf03673705003b22362bb03f1355..74cfb4b8b03d520ca654164483a77bbf4cdf40bd 100644 --- a/arch/sh/boards/mach-sh03/setup.c +++ b/arch/sh/boards/mach-sh03/setup.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -20,19 +21,6 @@ static void __init init_sh03_IRQ(void) plat_irq_setup_pins(IRQ_MODE_IRQ); } -extern void *cf_io_base; - -static void __iomem *sh03_ioport_map(unsigned long port, unsigned int size) -{ - if (PXSEG(port)) - return (void __iomem *)port; - /* CompactFlash (IDE) */ - if (((port >= 0x1f0) && (port <= 0x1f7)) || (port == 0x3f6)) - return (void __iomem *)((unsigned long)cf_io_base + port); - - return (void __iomem *)(port + PCI_IO_BASE); -} - /* arch/sh/boards/sh03/rtc.c */ void sh03_time_init(void); @@ -41,6 +29,30 @@ static void __init sh03_setup(char **cmdline_p) board_time_init = sh03_time_init; } +static struct resource cf_ide_resources[] = { + [0] = { + .start = 0x1f0, + .end = 0x1f0 + 8, + .flags = IORESOURCE_IO, + }, + [1] = { + .start = 0x1f0 + 0x206, + .end = 0x1f0 +8 + 0x206 + 8, + .flags = IORESOURCE_IO, + }, + [2] = { + .start = IRL2_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device cf_ide_device = { + .name = "pata_platform", + .id = -1, + .num_resources = ARRAY_SIZE(cf_ide_resources), + .resource = cf_ide_resources, +}; + static struct resource heartbeat_resources[] = { [0] = { .start = 0xa0800000, @@ -58,10 +70,30 @@ static struct platform_device heartbeat_device = { static struct platform_device *sh03_devices[] __initdata = { &heartbeat_device, + &cf_ide_device, }; static int __init sh03_devices_setup(void) { + pgprot_t prot; + unsigned long paddrbase; + void *cf_ide_base; + + /* open I/O area window */ + paddrbase = virt_to_phys((void *)PA_AREA5_IO); + prot = PAGE_KERNEL_PCC(1, _PAGE_PCC_IO16); + cf_ide_base = p3_ioremap(paddrbase, PAGE_SIZE, prot.pgprot); + if (!cf_ide_base) { + printk("allocate_cf_area : can't open CF I/O window!\n"); + return -ENOMEM; + } + + /* IDE cmd address : 0x1f0-0x1f7 and 0x3f6 */ + cf_ide_resources[0].start += (unsigned long)cf_ide_base; + cf_ide_resources[0].end += (unsigned long)cf_ide_base; + cf_ide_resources[1].start += (unsigned long)cf_ide_base; + cf_ide_resources[1].end += (unsigned long)cf_ide_base; + return platform_add_devices(sh03_devices, ARRAY_SIZE(sh03_devices)); } __initcall(sh03_devices_setup); @@ -70,6 +102,5 @@ static struct sh_machine_vector mv_sh03 __initmv = { .mv_name = "Interface (CTP/PCI-SH03)", .mv_setup = sh03_setup, .mv_nr_irqs = 48, - .mv_ioport_map = sh03_ioport_map, .mv_init_irq = init_sh03_IRQ, }; diff --git a/arch/sh/boards/mach-systemh/irq.c b/arch/sh/boards/mach-systemh/irq.c index 538406872a8923dce7aa0b4d98d8888aba9ee168..986a0e71d22004b7e56b89427a25f80aba00a362 100644 --- a/arch/sh/boards/mach-systemh/irq.c +++ b/arch/sh/boards/mach-systemh/irq.c @@ -12,8 +12,8 @@ #include #include #include +#include -#include #include #include @@ -24,35 +24,17 @@ static unsigned long *systemh_irq_mask_register = (unsigned long *)0xB3F10004; static unsigned long *systemh_irq_request_register = (unsigned long *)0xB3F10000; /* forward declaration */ -static unsigned int startup_systemh_irq(unsigned int irq); -static void shutdown_systemh_irq(unsigned int irq); static void enable_systemh_irq(unsigned int irq); static void disable_systemh_irq(unsigned int irq); static void mask_and_ack_systemh(unsigned int); -static void end_systemh_irq(unsigned int irq); -/* hw_interrupt_type */ -static struct hw_interrupt_type systemh_irq_type = { - .typename = " SystemH Register", - .startup = startup_systemh_irq, - .shutdown = shutdown_systemh_irq, - .enable = enable_systemh_irq, - .disable = disable_systemh_irq, +static struct irq_chip systemh_irq_type = { + .name = " SystemH Register", + .unmask = enable_systemh_irq, + .mask = disable_systemh_irq, .ack = mask_and_ack_systemh, - .end = end_systemh_irq }; -static unsigned int startup_systemh_irq(unsigned int irq) -{ - enable_systemh_irq(irq); - return 0; /* never anything pending */ -} - -static void shutdown_systemh_irq(unsigned int irq) -{ - disable_systemh_irq(irq); -} - static void disable_systemh_irq(unsigned int irq) { if (systemh_irq_mask_register) { @@ -86,16 +68,9 @@ static void mask_and_ack_systemh(unsigned int irq) disable_systemh_irq(irq); } -static void end_systemh_irq(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - enable_systemh_irq(irq); -} - void make_systemh_irq(unsigned int irq) { disable_irq_nosync(irq); - irq_desc[irq].chip = &systemh_irq_type; + set_irq_chip_and_handler(irq, &systemh_irq_type, handle_level_irq); disable_systemh_irq(irq); } - diff --git a/arch/sh/cchips/hd6446x/hd64461.c b/arch/sh/cchips/hd6446x/hd64461.c index f1a4a0763c5991dac9e150007c37bbc8c3a1789f..27ceeb948bb1059a142f627c540d07848993e52b 100644 --- a/arch/sh/cchips/hd6446x/hd64461.c +++ b/arch/sh/cchips/hd6446x/hd64461.c @@ -10,99 +10,49 @@ #include #include #include -#include +#include #include #include /* This belongs in cpu specific */ #define INTC_ICR1 0xA4140010UL -static void disable_hd64461_irq(unsigned int irq) +static void hd64461_mask_irq(unsigned int irq) { unsigned short nimr; unsigned short mask = 1 << (irq - HD64461_IRQBASE); - nimr = inw(HD64461_NIMR); + nimr = __raw_readw(HD64461_NIMR); nimr |= mask; - outw(nimr, HD64461_NIMR); + __raw_writew(nimr, HD64461_NIMR); } -static void enable_hd64461_irq(unsigned int irq) +static void hd64461_unmask_irq(unsigned int irq) { unsigned short nimr; unsigned short mask = 1 << (irq - HD64461_IRQBASE); - nimr = inw(HD64461_NIMR); + nimr = __raw_readw(HD64461_NIMR); nimr &= ~mask; - outw(nimr, HD64461_NIMR); + __raw_writew(nimr, HD64461_NIMR); } -static void mask_and_ack_hd64461(unsigned int irq) +static void hd64461_mask_and_ack_irq(unsigned int irq) { - disable_hd64461_irq(irq); + hd64461_mask_irq(irq); #ifdef CONFIG_HD64461_ENABLER if (irq == HD64461_IRQBASE + 13) - outb(0x00, HD64461_PCC1CSCR); + __raw_writeb(0x00, HD64461_PCC1CSCR); #endif } -static void end_hd64461_irq(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - enable_hd64461_irq(irq); -} - -static unsigned int startup_hd64461_irq(unsigned int irq) -{ - enable_hd64461_irq(irq); - return 0; -} - -static void shutdown_hd64461_irq(unsigned int irq) -{ - disable_hd64461_irq(irq); -} - -static struct hw_interrupt_type hd64461_irq_type = { - .typename = "HD64461-IRQ", - .startup = startup_hd64461_irq, - .shutdown = shutdown_hd64461_irq, - .enable = enable_hd64461_irq, - .disable = disable_hd64461_irq, - .ack = mask_and_ack_hd64461, - .end = end_hd64461_irq, +static struct irq_chip hd64461_irq_chip = { + .name = "HD64461-IRQ", + .mask = hd64461_mask_irq, + .mask_ack = hd64461_mask_and_ack_irq, + .unmask = hd64461_unmask_irq, }; -static irqreturn_t hd64461_interrupt(int irq, void *dev_id) -{ - printk(KERN_INFO - "HD64461: spurious interrupt, nirr: 0x%x nimr: 0x%x\n", - inw(HD64461_NIRR), inw(HD64461_NIMR)); - - return IRQ_NONE; -} - -static struct { - int (*func) (int, void *); - void *dev; -} hd64461_demux[HD64461_IRQ_NUM]; - -void hd64461_register_irq_demux(int irq, - int (*demux) (int irq, void *dev), void *dev) -{ - hd64461_demux[irq - HD64461_IRQBASE].func = demux; - hd64461_demux[irq - HD64461_IRQBASE].dev = dev; -} - -EXPORT_SYMBOL(hd64461_register_irq_demux); - -void hd64461_unregister_irq_demux(int irq) -{ - hd64461_demux[irq - HD64461_IRQBASE].func = 0; -} - -EXPORT_SYMBOL(hd64461_unregister_irq_demux); - int hd64461_irq_demux(int irq) { if (irq == CONFIG_HD64461_IRQ) { @@ -115,25 +65,11 @@ int hd64461_irq_demux(int irq) for (bit = 1, i = 0; i < 16; bit <<= 1, i++) if (nirr & bit) break; - if (i == 16) - irq = CONFIG_HD64461_IRQ; - else { - irq = HD64461_IRQBASE + i; - if (hd64461_demux[i].func != 0) { - irq = hd64461_demux[i].func(irq, hd64461_demux[i].dev); - } - } + irq = HD64461_IRQBASE + i; } return irq; } -static struct irqaction irq0 = { - .handler = hd64461_interrupt, - .flags = IRQF_DISABLED, - .mask = CPU_MASK_NONE, - .name = "HD64461", -}; - int __init setup_hd64461(void) { int i; @@ -146,22 +82,21 @@ int __init setup_hd64461(void) CONFIG_HD64461_IOBASE, CONFIG_HD64461_IRQ, HD64461_IRQBASE, HD64461_IRQBASE + 15); -#if defined(CONFIG_CPU_SUBTYPE_SH7709) /* Should be at processor specific part.. */ - outw(0x2240, INTC_ICR1); +/* Should be at processor specific part.. */ +#if defined(CONFIG_CPU_SUBTYPE_SH7709) + __raw_writew(0x2240, INTC_ICR1); #endif - outw(0xffff, HD64461_NIMR); + __raw_writew(0xffff, HD64461_NIMR); /* IRQ 80 -> 95 belongs to HD64461 */ - for (i = HD64461_IRQBASE; i < HD64461_IRQBASE + 16; i++) { - irq_desc[i].chip = &hd64461_irq_type; - } - - setup_irq(CONFIG_HD64461_IRQ, &irq0); + for (i = HD64461_IRQBASE; i < HD64461_IRQBASE + 16; i++) + set_irq_chip_and_handler(i, &hd64461_irq_chip, + handle_level_irq); #ifdef CONFIG_HD64461_ENABLER printk(KERN_INFO "HD64461: enabling PCMCIA devices\n"); - outb(0x4c, HD64461_PCC1CSCIER); - outb(0x00, HD64461_PCC1CSCR); + __raw_writeb(0x4c, HD64461_PCC1CSCIER); + __raw_writeb(0x00, HD64461_PCC1CSCR); #endif return 0; diff --git a/arch/sh/configs/edosk7705_defconfig b/arch/sh/configs/edosk7705_defconfig new file mode 100644 index 0000000000000000000000000000000000000000..8f4329fbbd39779df91a22c692ece79ff191db52 --- /dev/null +++ b/arch/sh/configs/edosk7705_defconfig @@ -0,0 +1,438 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.28-rc6 +# Wed Dec 17 13:53:02 2008 +# +CONFIG_SUPERH=y +CONFIG_SUPERH32=y +CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig" +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y +CONFIG_GENERIC_IRQ_PROBE=y +# CONFIG_GENERIC_GPIO is not set +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_CLOCKEVENTS=y +# CONFIG_ARCH_SUSPEND_POSSIBLE is not set +# CONFIG_ARCH_HIBERNATION_POSSIBLE is not set +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_HAVE_LATENCYTOP_SUPPORT=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_ARCH_NO_VIRT_TO_BUS=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +# CONFIG_EXPERIMENTAL is not set +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +# CONFIG_SYSVIPC is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=17 +# CONFIG_CGROUPS is not set +# CONFIG_RELAY is not set +# CONFIG_NAMESPACES is not set +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_EMBEDDED=y +# CONFIG_UID16 is not set +# CONFIG_SYSCTL_SYSCALL is not set +# CONFIG_KALLSYMS is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PRINTK is not set +# CONFIG_BUG is not set +# CONFIG_ELF_CORE is not set +# CONFIG_COMPAT_BRK is not set +# CONFIG_BASE_FULL is not set +# CONFIG_FUTEX is not set +# CONFIG_EPOLL is not set +# CONFIG_SIGNALFD is not set +# CONFIG_TIMERFD is not set +# CONFIG_EVENTFD is not set +CONFIG_SHMEM=y +# CONFIG_AIO is not set +# CONFIG_VM_EVENT_COUNTERS is not set +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +# CONFIG_MARKERS is not set +CONFIG_HAVE_OPROFILE=y +CONFIG_HAVE_IOREMAP_PROT=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=1 +# CONFIG_MODULES is not set +# CONFIG_BLOCK is not set +CONFIG_CLASSIC_RCU=y +# CONFIG_FREEZER is not set + +# +# System type +# +CONFIG_CPU_SH3=y +# CONFIG_CPU_SUBTYPE_SH7619 is not set +# CONFIG_CPU_SUBTYPE_SH7201 is not set +# CONFIG_CPU_SUBTYPE_SH7203 is not set +# CONFIG_CPU_SUBTYPE_SH7206 is not set +# CONFIG_CPU_SUBTYPE_SH7263 is not set +# CONFIG_CPU_SUBTYPE_MXG is not set +CONFIG_CPU_SUBTYPE_SH7705=y +# CONFIG_CPU_SUBTYPE_SH7706 is not set +# CONFIG_CPU_SUBTYPE_SH7707 is not set +# CONFIG_CPU_SUBTYPE_SH7708 is not set +# CONFIG_CPU_SUBTYPE_SH7709 is not set +# CONFIG_CPU_SUBTYPE_SH7710 is not set +# CONFIG_CPU_SUBTYPE_SH7712 is not set +# CONFIG_CPU_SUBTYPE_SH7720 is not set +# CONFIG_CPU_SUBTYPE_SH7721 is not set +# CONFIG_CPU_SUBTYPE_SH7750 is not set +# CONFIG_CPU_SUBTYPE_SH7091 is not set +# CONFIG_CPU_SUBTYPE_SH7750R is not set +# CONFIG_CPU_SUBTYPE_SH7750S is not set +# CONFIG_CPU_SUBTYPE_SH7751 is not set +# CONFIG_CPU_SUBTYPE_SH7751R is not set +# CONFIG_CPU_SUBTYPE_SH7760 is not set +# CONFIG_CPU_SUBTYPE_SH4_202 is not set +# CONFIG_CPU_SUBTYPE_SH7723 is not set +# CONFIG_CPU_SUBTYPE_SH7763 is not set +# CONFIG_CPU_SUBTYPE_SH7770 is not set +# CONFIG_CPU_SUBTYPE_SH7780 is not set +# CONFIG_CPU_SUBTYPE_SH7785 is not set +# CONFIG_CPU_SUBTYPE_SHX3 is not set +# CONFIG_CPU_SUBTYPE_SH7343 is not set +# CONFIG_CPU_SUBTYPE_SH7722 is not set +# CONFIG_CPU_SUBTYPE_SH7366 is not set +# CONFIG_CPU_SUBTYPE_SH5_101 is not set +# CONFIG_CPU_SUBTYPE_SH5_103 is not set + +# +# Memory management options +# +CONFIG_QUICKLIST=y +CONFIG_MMU=y +CONFIG_PAGE_OFFSET=0x80000000 +CONFIG_MEMORY_START=0x08000000 +CONFIG_MEMORY_SIZE=0x04000000 +CONFIG_29BIT=y +CONFIG_VSYSCALL=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_MAX_ACTIVE_REGIONS=1 +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y +CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_8KB is not set +# CONFIG_PAGE_SIZE_16KB is not set +# CONFIG_PAGE_SIZE_64KB is not set +CONFIG_ENTRY_OFFSET=0x00001000 +CONFIG_SELECT_MEMORY_MODEL=y +# CONFIG_FLATMEM_MANUAL is not set +# CONFIG_DISCONTIGMEM_MANUAL is not set +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y +CONFIG_HAVE_MEMORY_PRESENT=y +CONFIG_SPARSEMEM_STATIC=y +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_MIGRATION=y +# CONFIG_RESOURCES_64BIT is not set +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_NR_QUICK=2 +CONFIG_UNEVICTABLE_LRU=y + +# +# Cache configuration +# +CONFIG_SH7705_CACHE_32KB=y +# CONFIG_SH_DIRECT_MAPPED is not set +CONFIG_CACHE_WRITEBACK=y +# CONFIG_CACHE_WRITETHROUGH is not set +# CONFIG_CACHE_OFF is not set + +# +# Processor features +# +CONFIG_CPU_LITTLE_ENDIAN=y +# CONFIG_CPU_BIG_ENDIAN is not set +CONFIG_SH_ADC=y +CONFIG_CPU_HAS_INTEVT=y +CONFIG_CPU_HAS_SR_RB=y + +# +# Board support +# +# CONFIG_SH_SOLUTION_ENGINE is not set +CONFIG_SH_EDOSK7705=y + +# +# Timer and clock configuration +# +CONFIG_SH_TMU=y +CONFIG_SH_TIMER_IRQ=16 +CONFIG_SH_PCLK_FREQ=31250000 +# CONFIG_NO_HZ is not set +# CONFIG_HIGH_RES_TIMERS is not set +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y + +# +# CPU Frequency scaling +# +# CONFIG_CPU_FREQ is not set + +# +# DMA support +# +# CONFIG_SH_DMA is not set + +# +# Companion Chips +# + +# +# Additional SuperH Device Drivers +# +# CONFIG_HEARTBEAT is not set +# CONFIG_PUSH_SWITCH is not set + +# +# Kernel features +# +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +# CONFIG_SCHED_HRTICK is not set +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_GUSA=y +# CONFIG_GUSA_RB is not set + +# +# Boot options +# +CONFIG_ZERO_PAGE_OFFSET=0x00001000 +CONFIG_BOOT_LINK_OFFSET=0x00800000 +# CONFIG_CMDLINE_BOOL is not set + +# +# Bus options +# +# CONFIG_ARCH_SUPPORTS_MSI is not set + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +# CONFIG_HAVE_AOUT is not set +# CONFIG_BINFMT_MISC is not set +# CONFIG_NET is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +# CONFIG_PREVENT_FIRMWARE_BUILD is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_MTD is not set +# CONFIG_PARPORT is not set +# CONFIG_MISC_DEVICES is not set +CONFIG_HAVE_IDE=y + +# +# SCSI device support +# +# CONFIG_SCSI_DMA is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +# CONFIG_INPUT is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_DEVKMEM is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_SH_SCI is not set +# CONFIG_UNIX98_PTYS is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_R3964 is not set +# CONFIG_I2C is not set +# CONFIG_SPI is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set +# CONFIG_THERMAL is not set +# CONFIG_THERMAL_HWMON is not set +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_REGULATOR is not set + +# +# Multimedia devices +# + +# +# Multimedia core support +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_VIDEO_MEDIA is not set + +# +# Multimedia drivers +# +# CONFIG_DAB is not set + +# +# Graphics support +# +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +# CONFIG_FB is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_SOUND is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_RTC_CLASS is not set +# CONFIG_DMADEVICES is not set +# CONFIG_UIO is not set +# CONFIG_STAGING is not set +CONFIG_STAGING_EXCLUDE_BUILD=y + +# +# File systems +# +# CONFIG_DNOTIFY is not set +# CONFIG_INOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# Pseudo filesystems +# +# CONFIG_PROC_FS is not set +# CONFIG_SYSFS is not set +# CONFIG_TMPFS is not set +# CONFIG_HUGETLBFS is not set +# CONFIG_HUGETLB_PAGE is not set + +# +# Miscellaneous filesystems +# +# CONFIG_NLS is not set + +# +# Kernel hacking +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_FRAME_WARN=1024 +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_RCU_CPU_STALL_DETECTOR is not set +# CONFIG_LATENCYTOP is not set +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y + +# +# Tracers +# +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_SH_STANDARD_BIOS is not set +# CONFIG_EARLY_SCIF_CONSOLE is not set +# CONFIG_MORE_COMPILE_OPTIONS is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITYFS is not set +# CONFIG_SECURITY_FILE_CAPABILITIES is not set +# CONFIG_CRYPTO is not set + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +# CONFIG_CRC32 is not set +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y diff --git a/arch/sh/configs/rsk7201_defconfig b/arch/sh/configs/rsk7201_defconfig new file mode 100644 index 0000000000000000000000000000000000000000..014c18cbf46a57aa9d5606394a234073ec2dd1ae --- /dev/null +++ b/arch/sh/configs/rsk7201_defconfig @@ -0,0 +1,703 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.28-rc6 +# Mon Dec 8 14:48:02 2008 +# +CONFIG_SUPERH=y +CONFIG_SUPERH32=y +CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig" +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y +CONFIG_GENERIC_IRQ_PROBE=y +# CONFIG_GENERIC_GPIO is not set +# CONFIG_GENERIC_TIME is not set +# CONFIG_GENERIC_CLOCKEVENTS is not set +# CONFIG_ARCH_SUSPEND_POSSIBLE is not set +# CONFIG_ARCH_HIBERNATION_POSSIBLE is not set +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_HAVE_LATENCYTOP_SUPPORT=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_ARCH_NO_VIRT_TO_BUS=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +CONFIG_IKCONFIG=y +# CONFIG_IKCONFIG_PROC is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_CGROUPS is not set +# CONFIG_GROUP_SCHED is not set +# CONFIG_SYSFS_DEPRECATED_V2 is not set +# CONFIG_RELAY is not set +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_IPC_NS=y +CONFIG_USER_NS=y +CONFIG_PID_NS=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_COMPAT_BRK=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +# CONFIG_AIO is not set +CONFIG_VM_EVENT_COUNTERS=y +# CONFIG_SLAB is not set +# CONFIG_SLUB is not set +CONFIG_SLOB=y +CONFIG_PROFILING=y +# CONFIG_MARKERS is not set +CONFIG_OPROFILE=y +CONFIG_HAVE_OPROFILE=y +# CONFIG_KPROBES is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_RT_MUTEXES=y +CONFIG_TINY_SHMEM=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +# CONFIG_MODULE_UNLOAD is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_KMOD=y +CONFIG_BLOCK=y +# CONFIG_LBD is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +# CONFIG_IOSCHED_DEADLINE is not set +# CONFIG_IOSCHED_CFQ is not set +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +CONFIG_DEFAULT_NOOP=y +CONFIG_DEFAULT_IOSCHED="noop" +CONFIG_CLASSIC_RCU=y +# CONFIG_FREEZER is not set + +# +# System type +# +CONFIG_CPU_SH2=y +CONFIG_CPU_SH2A=y +# CONFIG_CPU_SUBTYPE_SH7619 is not set +CONFIG_CPU_SUBTYPE_SH7201=y +# CONFIG_CPU_SUBTYPE_SH7203 is not set +# CONFIG_CPU_SUBTYPE_SH7206 is not set +# CONFIG_CPU_SUBTYPE_SH7263 is not set +# CONFIG_CPU_SUBTYPE_MXG is not set +# CONFIG_CPU_SUBTYPE_SH7705 is not set +# CONFIG_CPU_SUBTYPE_SH7706 is not set +# CONFIG_CPU_SUBTYPE_SH7707 is not set +# CONFIG_CPU_SUBTYPE_SH7708 is not set +# CONFIG_CPU_SUBTYPE_SH7709 is not set +# CONFIG_CPU_SUBTYPE_SH7710 is not set +# CONFIG_CPU_SUBTYPE_SH7712 is not set +# CONFIG_CPU_SUBTYPE_SH7720 is not set +# CONFIG_CPU_SUBTYPE_SH7721 is not set +# CONFIG_CPU_SUBTYPE_SH7750 is not set +# CONFIG_CPU_SUBTYPE_SH7091 is not set +# CONFIG_CPU_SUBTYPE_SH7750R is not set +# CONFIG_CPU_SUBTYPE_SH7750S is not set +# CONFIG_CPU_SUBTYPE_SH7751 is not set +# CONFIG_CPU_SUBTYPE_SH7751R is not set +# CONFIG_CPU_SUBTYPE_SH7760 is not set +# CONFIG_CPU_SUBTYPE_SH4_202 is not set +# CONFIG_CPU_SUBTYPE_SH7723 is not set +# CONFIG_CPU_SUBTYPE_SH7763 is not set +# CONFIG_CPU_SUBTYPE_SH7770 is not set +# CONFIG_CPU_SUBTYPE_SH7780 is not set +# CONFIG_CPU_SUBTYPE_SH7785 is not set +# CONFIG_CPU_SUBTYPE_SHX3 is not set +# CONFIG_CPU_SUBTYPE_SH7343 is not set +# CONFIG_CPU_SUBTYPE_SH7722 is not set +# CONFIG_CPU_SUBTYPE_SH7366 is not set +# CONFIG_CPU_SUBTYPE_SH5_101 is not set +# CONFIG_CPU_SUBTYPE_SH5_103 is not set + +# +# Memory management options +# +CONFIG_QUICKLIST=y +CONFIG_PAGE_OFFSET=0x00000000 +CONFIG_MEMORY_START=0x08000000 +CONFIG_MEMORY_SIZE=0x01000000 +CONFIG_29BIT=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_MAX_ACTIVE_REGIONS=1 +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_8KB is not set +# CONFIG_PAGE_SIZE_16KB is not set +# CONFIG_PAGE_SIZE_64KB is not set +CONFIG_ENTRY_OFFSET=0x00001000 +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_SPARSEMEM_STATIC=y +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_NR_QUICK=2 + +# +# Cache configuration +# +# CONFIG_SH_DIRECT_MAPPED is not set +CONFIG_CACHE_WRITEBACK=y +# CONFIG_CACHE_WRITETHROUGH is not set +# CONFIG_CACHE_OFF is not set + +# +# Processor features +# +# CONFIG_CPU_LITTLE_ENDIAN is not set +CONFIG_CPU_BIG_ENDIAN=y +CONFIG_SH_FPU=y +CONFIG_CPU_HAS_FPU=y + +# +# Board support +# +CONFIG_SH_RSK=y +CONFIG_SH_RSK7201=y +# CONFIG_SH_RSK7203 is not set + +# +# Timer and clock configuration +# +# CONFIG_SH_CMT is not set +CONFIG_SH_MTU2=y +CONFIG_SH_TIMER_IRQ=16 +CONFIG_SH_PCLK_FREQ=40000000 +CONFIG_SH_CLK_MD=0 + +# +# CPU Frequency scaling +# +# CONFIG_CPU_FREQ is not set + +# +# DMA support +# + +# +# Companion Chips +# + +# +# Additional SuperH Device Drivers +# +# CONFIG_HEARTBEAT is not set +# CONFIG_PUSH_SWITCH is not set + +# +# Kernel features +# +# CONFIG_HZ_100 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_300 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 +# CONFIG_SCHED_HRTICK is not set +# CONFIG_KEXEC is not set +# CONFIG_CRASH_DUMP is not set +# CONFIG_SECCOMP is not set +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_GUSA=y + +# +# Boot options +# +CONFIG_ZERO_PAGE_OFFSET=0x00001000 +CONFIG_BOOT_LINK_OFFSET=0x00800000 +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="console=ttySC0,115200 earlyprintk=serial ignore_loglevel" + +# +# Bus options +# +# CONFIG_ARCH_SUPPORTS_MSI is not set +# CONFIG_PCCARD is not set + +# +# Executable file formats +# +CONFIG_BINFMT_ELF_FDPIC=y +CONFIG_BINFMT_FLAT=y +CONFIG_BINFMT_ZFLAT=y +CONFIG_BINFMT_SHARED_FLAT=y +# CONFIG_HAVE_AOUT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Power management options (EXPERIMENTAL) +# +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +# CONFIG_NET is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +# CONFIG_STANDALONE is not set +# CONFIG_PREVENT_FIRMWARE_BUILD is not set +# CONFIG_FW_LOADER is not set +# CONFIG_SYS_HYPERVISOR is not set +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_CONCAT=y +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_REDBOOT_PARTS=y +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set +# CONFIG_MTD_CMDLINE_PARTS is not set +# CONFIG_MTD_AR7_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set +# CONFIG_MTD_OOPS is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_START=0x0 +CONFIG_MTD_PHYSMAP_LEN=0x0 +CONFIG_MTD_PHYSMAP_BANKWIDTH=4 +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_ONENAND is not set + +# +# UBI - Unsorted block images +# +# CONFIG_MTD_UBI is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_MISC_DEVICES=y +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_C2PORT is not set +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_DMA is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_DEVKMEM=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_SH_SCI=y +CONFIG_SERIAL_SH_SCI_NR_UARTS=8 +CONFIG_SERIAL_SH_SCI_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_UNIX98_PTYS is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_I2C is not set +# CONFIG_SPI is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set +CONFIG_THERMAL=y +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_REGULATOR is not set + +# +# Multimedia devices +# + +# +# Multimedia core support +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_VIDEO_MEDIA is not set + +# +# Multimedia drivers +# +CONFIG_DAB=y + +# +# Graphics support +# +# CONFIG_VGASTATE is not set +CONFIG_VIDEO_OUTPUT_CONTROL=y +# CONFIG_FB is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_SOUND is not set +# CONFIG_HID_SUPPORT is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_ACCESSIBILITY is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# SPI RTC drivers +# + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# +CONFIG_RTC_DRV_SH=y +# CONFIG_DMADEVICES is not set +# CONFIG_UIO is not set +# CONFIG_STAGING is not set +CONFIG_STAGING_EXCLUDE_BUILD=y + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_FILE_LOCKING is not set +# CONFIG_XFS_FS is not set +# CONFIG_DNOTIFY is not set +# CONFIG_INOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +# CONFIG_TMPFS is not set +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +# CONFIG_JFFS2_SUMMARY is not set +# CONFIG_JFFS2_FS_XATTR is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +# CONFIG_JFFS2_LZO is not set +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +CONFIG_ROMFS_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_NLS is not set + +# +# Kernel hacking +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_WARN_DEPRECATED=y +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_FRAME_WARN=1024 +CONFIG_MAGIC_SYSRQ=y +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_RCU_CPU_STALL_DETECTOR is not set +# CONFIG_LATENCYTOP is not set +CONFIG_SYSCTL_SYSCALL_CHECK=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y + +# +# Tracers +# +# CONFIG_DYNAMIC_PRINTK_DEBUG is not set +# CONFIG_SAMPLES is not set +# CONFIG_SH_STANDARD_BIOS is not set +# CONFIG_EARLY_SCIF_CONSOLE is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +# CONFIG_SECURITY_FILE_CAPABILITIES is not set +# CONFIG_CRYPTO is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y diff --git a/arch/sh/configs/rsk7203_defconfig b/arch/sh/configs/rsk7203_defconfig index 85b0ac4fc66737944b912229a6b2e72d547a6e7a..dcdef31cf19b5ea7757536ba29520528361e59ab 100644 --- a/arch/sh/configs/rsk7203_defconfig +++ b/arch/sh/configs/rsk7203_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.27 -# Tue Oct 21 12:58:47 2008 +# Linux kernel version: 2.6.28-rc6 +# Mon Dec 8 14:35:03 2008 # CONFIG_SUPERH=y CONFIG_SUPERH32=y @@ -16,6 +16,8 @@ CONFIG_GENERIC_IRQ_PROBE=y CONFIG_GENERIC_GPIO=y # CONFIG_GENERIC_TIME is not set # CONFIG_GENERIC_CLOCKEVENTS is not set +# CONFIG_ARCH_SUSPEND_POSSIBLE is not set +# CONFIG_ARCH_HIBERNATION_POSSIBLE is not set CONFIG_STACKTRACE_SUPPORT=y CONFIG_LOCKDEP_SUPPORT=y CONFIG_HAVE_LATENCYTOP_SUPPORT=y @@ -75,7 +77,6 @@ CONFIG_TIMERFD=y CONFIG_EVENTFD=y CONFIG_AIO=y CONFIG_VM_EVENT_COUNTERS=y -CONFIG_PCI_QUIRKS=y # CONFIG_SLAB is not set # CONFIG_SLUB is not set CONFIG_SLOB=y @@ -126,6 +127,7 @@ CONFIG_CLASSIC_RCU=y CONFIG_CPU_SH2=y CONFIG_CPU_SH2A=y # CONFIG_CPU_SUBTYPE_SH7619 is not set +# CONFIG_CPU_SUBTYPE_SH7201 is not set CONFIG_CPU_SUBTYPE_SH7203=y # CONFIG_CPU_SUBTYPE_SH7206 is not set # CONFIG_CPU_SUBTYPE_SH7263 is not set @@ -211,6 +213,8 @@ CONFIG_CPU_HAS_FPU=y # # Board support # +CONFIG_SH_RSK=y +# CONFIG_SH_RSK7201 is not set CONFIG_SH_RSK7203=y # @@ -296,6 +300,14 @@ CONFIG_BINFMT_ZFLAT=y CONFIG_BINFMT_SHARED_FLAT=y # CONFIG_HAVE_AOUT is not set # CONFIG_BINFMT_MISC is not set + +# +# Power management options (EXPERIMENTAL) +# +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y CONFIG_NET=y # @@ -477,6 +489,7 @@ CONFIG_BLK_DEV=y CONFIG_MISC_DEVICES=y # CONFIG_EEPROM_93CX6 is not set # CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_C2PORT is not set CONFIG_HAVE_IDE=y # CONFIG_IDE is not set @@ -603,11 +616,11 @@ CONFIG_SERIAL_CORE_CONSOLE=y # CONFIG_HWMON is not set CONFIG_THERMAL=y # CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y # # Sonics Silicon Backplane # -CONFIG_SSB_POSSIBLE=y # CONFIG_SSB is not set # @@ -617,7 +630,11 @@ CONFIG_SSB_POSSIBLE=y # CONFIG_MFD_SM501 is not set # CONFIG_HTC_PASIC3 is not set # CONFIG_MFD_TMIO is not set -# CONFIG_MFD_WM8400 is not set +CONFIG_REGULATOR=y +# CONFIG_REGULATOR_DEBUG is not set +# CONFIG_REGULATOR_FIXED_VOLTAGE is not set +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REGULATOR_BQ24022 is not set # # Multimedia devices @@ -702,19 +719,22 @@ CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_DEVICEFS=y CONFIG_USB_DEVICE_CLASS=y # CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_SUSPEND is not set # CONFIG_USB_OTG is not set # CONFIG_USB_OTG_WHITELIST is not set # CONFIG_USB_OTG_BLACKLIST_HUB is not set CONFIG_USB_MON=y +# CONFIG_USB_WUSB is not set +# CONFIG_USB_WUSB_CBAF is not set # # USB Host Controller Drivers # # CONFIG_USB_C67X00_HCD is not set # CONFIG_USB_ISP116X_HCD is not set -# CONFIG_USB_ISP1760_HCD is not set # CONFIG_USB_SL811_HCD is not set CONFIG_USB_R8A66597_HCD=y +# CONFIG_USB_HWA_HCD is not set # # USB Device Class drivers @@ -725,11 +745,11 @@ CONFIG_USB_R8A66597_HCD=y # CONFIG_USB_TMC is not set # -# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed; # # -# may also be needed; see USB_STORAGE Help for more information +# see USB_STORAGE Help for more information # # CONFIG_USB_LIBUSUAL is not set @@ -770,7 +790,22 @@ CONFIG_USB_R8A66597_HCD=y # CONFIG_USB_GADGET is not set # CONFIG_MMC is not set # CONFIG_MEMSTICK is not set -# CONFIG_NEW_LEDS is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y + +# +# LED drivers +# +CONFIG_LEDS_GPIO=y + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_BACKLIGHT=y +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y # CONFIG_ACCESSIBILITY is not set CONFIG_RTC_LIB=y CONFIG_RTC_CLASS=y @@ -812,6 +847,7 @@ CONFIG_RTC_DRV_SH=y # CONFIG_DMADEVICES is not set # CONFIG_UIO is not set # CONFIG_STAGING is not set +CONFIG_STAGING_EXCLUDE_BUILD=y # # File systems @@ -950,9 +986,14 @@ CONFIG_FRAME_POINTER=y # CONFIG_FAULT_INJECTION is not set # CONFIG_LATENCYTOP is not set CONFIG_SYSCTL_SYSCALL_CHECK=y -CONFIG_NOP_TRACER=y -CONFIG_HAVE_FTRACE=y -# CONFIG_FTRACE is not set +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y + +# +# Tracers +# +# CONFIG_FUNCTION_TRACER is not set # CONFIG_SCHED_TRACER is not set # CONFIG_CONTEXT_SWITCH_TRACER is not set # CONFIG_BOOT_TRACER is not set diff --git a/arch/sh/configs/rts7751r2dplus_qemu_defconfig b/arch/sh/configs/rts7751r2dplus_qemu_defconfig deleted file mode 100644 index ae8f63000fbfb031b2a2c7f6bededccff63bd542..0000000000000000000000000000000000000000 --- a/arch/sh/configs/rts7751r2dplus_qemu_defconfig +++ /dev/null @@ -1,949 +0,0 @@ -# -# Automatically generated make config: don't edit -# Linux kernel version: 2.6.27 -# Wed Oct 22 18:51:20 2008 -# -CONFIG_SUPERH=y -CONFIG_SUPERH32=y -CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig" -CONFIG_RWSEM_GENERIC_SPINLOCK=y -CONFIG_GENERIC_BUG=y -CONFIG_GENERIC_FIND_NEXT_BIT=y -CONFIG_GENERIC_HWEIGHT=y -CONFIG_GENERIC_HARDIRQS=y -CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y -CONFIG_GENERIC_IRQ_PROBE=y -# CONFIG_GENERIC_GPIO is not set -CONFIG_GENERIC_TIME=y -CONFIG_GENERIC_CLOCKEVENTS=y -CONFIG_SYS_SUPPORTS_PCI=y -CONFIG_STACKTRACE_SUPPORT=y -CONFIG_LOCKDEP_SUPPORT=y -CONFIG_HAVE_LATENCYTOP_SUPPORT=y -# CONFIG_ARCH_HAS_ILOG2_U32 is not set -# CONFIG_ARCH_HAS_ILOG2_U64 is not set -CONFIG_ARCH_NO_VIRT_TO_BUS=y -CONFIG_IO_TRAPPED=y -CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" - -# -# General setup -# -CONFIG_EXPERIMENTAL=y -CONFIG_BROKEN_ON_SMP=y -CONFIG_INIT_ENV_ARG_LIMIT=32 -CONFIG_LOCALVERSION="" -CONFIG_LOCALVERSION_AUTO=y -CONFIG_SWAP=y -CONFIG_SYSVIPC=y -CONFIG_SYSVIPC_SYSCTL=y -# CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_IKCONFIG=y -CONFIG_IKCONFIG_PROC=y -CONFIG_LOG_BUF_SHIFT=14 -# CONFIG_CGROUPS is not set -CONFIG_GROUP_SCHED=y -CONFIG_FAIR_GROUP_SCHED=y -# CONFIG_RT_GROUP_SCHED is not set -CONFIG_USER_SCHED=y -# CONFIG_CGROUP_SCHED is not set -CONFIG_SYSFS_DEPRECATED=y -CONFIG_SYSFS_DEPRECATED_V2=y -# CONFIG_RELAY is not set -# CONFIG_NAMESPACES is not set -CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="" -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_SYSCTL=y -CONFIG_EMBEDDED=y -CONFIG_UID16=y -# CONFIG_SYSCTL_SYSCALL is not set -CONFIG_KALLSYMS=y -# CONFIG_KALLSYMS_ALL is not set -# CONFIG_KALLSYMS_EXTRA_PASS is not set -# CONFIG_HOTPLUG is not set -CONFIG_PRINTK=y -CONFIG_BUG=y -CONFIG_ELF_CORE=y -CONFIG_COMPAT_BRK=y -CONFIG_BASE_FULL=y -CONFIG_FUTEX=y -CONFIG_ANON_INODES=y -CONFIG_EPOLL=y -CONFIG_SIGNALFD=y -CONFIG_TIMERFD=y -CONFIG_EVENTFD=y -CONFIG_SHMEM=y -CONFIG_AIO=y -CONFIG_VM_EVENT_COUNTERS=y -CONFIG_PCI_QUIRKS=y -CONFIG_SLAB=y -# CONFIG_SLUB is not set -# CONFIG_SLOB is not set -CONFIG_PROFILING=y -# CONFIG_MARKERS is not set -CONFIG_OPROFILE=y -CONFIG_HAVE_OPROFILE=y -# CONFIG_KPROBES is not set -CONFIG_HAVE_IOREMAP_PROT=y -CONFIG_HAVE_KPROBES=y -CONFIG_HAVE_KRETPROBES=y -CONFIG_HAVE_ARCH_TRACEHOOK=y -CONFIG_HAVE_CLK=y -CONFIG_HAVE_GENERIC_DMA_COHERENT=y -CONFIG_SLABINFO=y -CONFIG_RT_MUTEXES=y -# CONFIG_TINY_SHMEM is not set -CONFIG_BASE_SMALL=0 -CONFIG_MODULES=y -# CONFIG_MODULE_FORCE_LOAD is not set -# CONFIG_MODULE_UNLOAD is not set -# CONFIG_MODVERSIONS is not set -# CONFIG_MODULE_SRCVERSION_ALL is not set -CONFIG_KMOD=y -CONFIG_BLOCK=y -# CONFIG_LBD is not set -# CONFIG_BLK_DEV_IO_TRACE is not set -# CONFIG_LSF is not set -# CONFIG_BLK_DEV_BSG is not set -# CONFIG_BLK_DEV_INTEGRITY is not set - -# -# IO Schedulers -# -CONFIG_IOSCHED_NOOP=y -CONFIG_IOSCHED_AS=y -CONFIG_IOSCHED_DEADLINE=y -CONFIG_IOSCHED_CFQ=y -CONFIG_DEFAULT_AS=y -# CONFIG_DEFAULT_DEADLINE is not set -# CONFIG_DEFAULT_CFQ is not set -# CONFIG_DEFAULT_NOOP is not set -CONFIG_DEFAULT_IOSCHED="anticipatory" -CONFIG_CLASSIC_RCU=y -# CONFIG_FREEZER is not set - -# -# System type -# -CONFIG_CPU_SH4=y -# CONFIG_CPU_SUBTYPE_SH7619 is not set -# CONFIG_CPU_SUBTYPE_SH7203 is not set -# CONFIG_CPU_SUBTYPE_SH7206 is not set -# CONFIG_CPU_SUBTYPE_SH7263 is not set -# CONFIG_CPU_SUBTYPE_MXG is not set -# CONFIG_CPU_SUBTYPE_SH7705 is not set -# CONFIG_CPU_SUBTYPE_SH7706 is not set -# CONFIG_CPU_SUBTYPE_SH7707 is not set -# CONFIG_CPU_SUBTYPE_SH7708 is not set -# CONFIG_CPU_SUBTYPE_SH7709 is not set -# CONFIG_CPU_SUBTYPE_SH7710 is not set -# CONFIG_CPU_SUBTYPE_SH7712 is not set -# CONFIG_CPU_SUBTYPE_SH7720 is not set -# CONFIG_CPU_SUBTYPE_SH7721 is not set -# CONFIG_CPU_SUBTYPE_SH7750 is not set -# CONFIG_CPU_SUBTYPE_SH7091 is not set -# CONFIG_CPU_SUBTYPE_SH7750R is not set -# CONFIG_CPU_SUBTYPE_SH7750S is not set -# CONFIG_CPU_SUBTYPE_SH7751 is not set -CONFIG_CPU_SUBTYPE_SH7751R=y -# CONFIG_CPU_SUBTYPE_SH7760 is not set -# CONFIG_CPU_SUBTYPE_SH4_202 is not set -# CONFIG_CPU_SUBTYPE_SH7723 is not set -# CONFIG_CPU_SUBTYPE_SH7763 is not set -# CONFIG_CPU_SUBTYPE_SH7770 is not set -# CONFIG_CPU_SUBTYPE_SH7780 is not set -# CONFIG_CPU_SUBTYPE_SH7785 is not set -# CONFIG_CPU_SUBTYPE_SHX3 is not set -# CONFIG_CPU_SUBTYPE_SH7343 is not set -# CONFIG_CPU_SUBTYPE_SH7722 is not set -# CONFIG_CPU_SUBTYPE_SH7366 is not set -# CONFIG_CPU_SUBTYPE_SH5_101 is not set -# CONFIG_CPU_SUBTYPE_SH5_103 is not set - -# -# Memory management options -# -CONFIG_QUICKLIST=y -CONFIG_MMU=y -CONFIG_PAGE_OFFSET=0x80000000 -CONFIG_MEMORY_START=0x0c000000 -CONFIG_MEMORY_SIZE=0x04000000 -CONFIG_29BIT=y -CONFIG_VSYSCALL=y -CONFIG_ARCH_FLATMEM_ENABLE=y -CONFIG_ARCH_SPARSEMEM_ENABLE=y -CONFIG_ARCH_SPARSEMEM_DEFAULT=y -CONFIG_MAX_ACTIVE_REGIONS=1 -CONFIG_ARCH_POPULATES_NODE_MAP=y -CONFIG_ARCH_SELECT_MEMORY_MODEL=y -CONFIG_PAGE_SIZE_4KB=y -# CONFIG_PAGE_SIZE_8KB is not set -# CONFIG_PAGE_SIZE_16KB is not set -# CONFIG_PAGE_SIZE_64KB is not set -CONFIG_ENTRY_OFFSET=0x00001000 -CONFIG_SELECT_MEMORY_MODEL=y -CONFIG_FLATMEM_MANUAL=y -# CONFIG_DISCONTIGMEM_MANUAL is not set -# CONFIG_SPARSEMEM_MANUAL is not set -CONFIG_FLATMEM=y -CONFIG_FLAT_NODE_MEM_MAP=y -CONFIG_SPARSEMEM_STATIC=y -CONFIG_PAGEFLAGS_EXTENDED=y -CONFIG_SPLIT_PTLOCK_CPUS=4 -# CONFIG_RESOURCES_64BIT is not set -# CONFIG_PHYS_ADDR_T_64BIT is not set -CONFIG_ZONE_DMA_FLAG=0 -CONFIG_NR_QUICK=2 -CONFIG_UNEVICTABLE_LRU=y - -# -# Cache configuration -# -# CONFIG_SH_DIRECT_MAPPED is not set -CONFIG_CACHE_WRITEBACK=y -# CONFIG_CACHE_WRITETHROUGH is not set -# CONFIG_CACHE_OFF is not set - -# -# Processor features -# -CONFIG_CPU_LITTLE_ENDIAN=y -# CONFIG_CPU_BIG_ENDIAN is not set -CONFIG_SH_FPU=y -# CONFIG_SH_STORE_QUEUES is not set -CONFIG_CPU_HAS_INTEVT=y -CONFIG_CPU_HAS_SR_RB=y -CONFIG_CPU_HAS_PTEA=y -CONFIG_CPU_HAS_FPU=y - -# -# Board support -# -# CONFIG_SH_7751_SYSTEMH is not set -# CONFIG_SH_SECUREEDGE5410 is not set -CONFIG_SH_RTS7751R2D=y -# CONFIG_SH_LANDISK is not set -# CONFIG_SH_TITAN is not set -# CONFIG_SH_LBOX_RE2 is not set - -# -# RTS7751R2D Board Revision -# -CONFIG_RTS7751R2D_PLUS=y -# CONFIG_RTS7751R2D_1 is not set - -# -# Timer and clock configuration -# -CONFIG_SH_TMU=y -CONFIG_SH_TIMER_IRQ=16 -CONFIG_SH_PCLK_FREQ=60000000 -# CONFIG_NO_HZ is not set -# CONFIG_HIGH_RES_TIMERS is not set -CONFIG_GENERIC_CLOCKEVENTS_BUILD=y - -# -# CPU Frequency scaling -# -# CONFIG_CPU_FREQ is not set - -# -# DMA support -# -# CONFIG_SH_DMA is not set - -# -# Companion Chips -# - -# -# Additional SuperH Device Drivers -# -CONFIG_HEARTBEAT=y -# CONFIG_PUSH_SWITCH is not set - -# -# Kernel features -# -# CONFIG_HZ_100 is not set -CONFIG_HZ_250=y -# CONFIG_HZ_300 is not set -# CONFIG_HZ_1000 is not set -CONFIG_HZ=250 -# CONFIG_SCHED_HRTICK is not set -# CONFIG_KEXEC is not set -# CONFIG_CRASH_DUMP is not set -CONFIG_SECCOMP=y -CONFIG_PREEMPT_NONE=y -# CONFIG_PREEMPT_VOLUNTARY is not set -# CONFIG_PREEMPT is not set -CONFIG_GUSA=y -# CONFIG_GUSA_RB is not set - -# -# Boot options -# -CONFIG_ZERO_PAGE_OFFSET=0x00010000 -CONFIG_BOOT_LINK_OFFSET=0x00800000 -# CONFIG_UBC_WAKEUP is not set -CONFIG_CMDLINE_BOOL=y -CONFIG_CMDLINE="console=tty0 console=ttySC0,115200 root=/dev/sda1 earlyprintk=serial" - -# -# Bus options -# -# CONFIG_PCI is not set -# CONFIG_ARCH_SUPPORTS_MSI is not set - -# -# Executable file formats -# -CONFIG_BINFMT_ELF=y -# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set -# CONFIG_HAVE_AOUT is not set -# CONFIG_BINFMT_MISC is not set -# CONFIG_NET is not set - -# -# Device Drivers -# - -# -# Generic Driver Options -# -CONFIG_STANDALONE=y -CONFIG_PREVENT_FIRMWARE_BUILD=y -# CONFIG_DEBUG_DRIVER is not set -# CONFIG_DEBUG_DEVRES is not set -# CONFIG_SYS_HYPERVISOR is not set -# CONFIG_MTD is not set -# CONFIG_PARPORT is not set -CONFIG_BLK_DEV=y -# CONFIG_BLK_DEV_COW_COMMON is not set -# CONFIG_BLK_DEV_LOOP is not set -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_COUNT=16 -CONFIG_BLK_DEV_RAM_SIZE=4096 -# CONFIG_BLK_DEV_XIP is not set -# CONFIG_CDROM_PKTCDVD is not set -# CONFIG_BLK_DEV_HD is not set -CONFIG_MISC_DEVICES=y -# CONFIG_EEPROM_93CX6 is not set -# CONFIG_ENCLOSURE_SERVICES is not set -CONFIG_HAVE_IDE=y -# CONFIG_IDE is not set - -# -# SCSI device support -# -# CONFIG_RAID_ATTRS is not set -CONFIG_SCSI=y -CONFIG_SCSI_DMA=y -# CONFIG_SCSI_TGT is not set -# CONFIG_SCSI_NETLINK is not set -CONFIG_SCSI_PROC_FS=y - -# -# SCSI support type (disk, tape, CD-ROM) -# -CONFIG_BLK_DEV_SD=y -# CONFIG_CHR_DEV_ST is not set -# CONFIG_CHR_DEV_OSST is not set -# CONFIG_BLK_DEV_SR is not set -# CONFIG_CHR_DEV_SG is not set -# CONFIG_CHR_DEV_SCH is not set - -# -# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -# -# CONFIG_SCSI_MULTI_LUN is not set -# CONFIG_SCSI_CONSTANTS is not set -# CONFIG_SCSI_LOGGING is not set -# CONFIG_SCSI_SCAN_ASYNC is not set -CONFIG_SCSI_WAIT_SCAN=m - -# -# SCSI Transports -# -# CONFIG_SCSI_SPI_ATTRS is not set -# CONFIG_SCSI_FC_ATTRS is not set -# CONFIG_SCSI_SAS_LIBSAS is not set -# CONFIG_SCSI_SRP_ATTRS is not set -CONFIG_SCSI_LOWLEVEL=y -# CONFIG_SCSI_DEBUG is not set -# CONFIG_SCSI_DH is not set -CONFIG_ATA=y -# CONFIG_ATA_NONSTANDARD is not set -CONFIG_SATA_PMP=y -CONFIG_ATA_SFF=y -# CONFIG_SATA_MV is not set -# CONFIG_PATA_PLATFORM is not set -# CONFIG_MD is not set -# CONFIG_PHONE is not set - -# -# Input device support -# -CONFIG_INPUT=y -# CONFIG_INPUT_FF_MEMLESS is not set -# CONFIG_INPUT_POLLDEV is not set - -# -# Userland interfaces -# -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_EVDEV is not set -# CONFIG_INPUT_EVBUG is not set - -# -# Input Device Drivers -# -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_INPUT_JOYSTICK is not set -# CONFIG_INPUT_TABLET is not set -# CONFIG_INPUT_TOUCHSCREEN is not set -# CONFIG_INPUT_MISC is not set - -# -# Hardware I/O ports -# -# CONFIG_SERIO is not set -# CONFIG_GAMEPORT is not set - -# -# Character devices -# -CONFIG_VT=y -CONFIG_CONSOLE_TRANSLATIONS=y -CONFIG_VT_CONSOLE=y -CONFIG_HW_CONSOLE=y -CONFIG_VT_HW_CONSOLE_BINDING=y -CONFIG_DEVKMEM=y -# CONFIG_SERIAL_NONSTANDARD is not set - -# -# Serial drivers -# -CONFIG_SERIAL_8250=y -# CONFIG_SERIAL_8250_CONSOLE is not set -CONFIG_SERIAL_8250_NR_UARTS=4 -CONFIG_SERIAL_8250_RUNTIME_UARTS=4 -# CONFIG_SERIAL_8250_EXTENDED is not set - -# -# Non-8250 serial port support -# -CONFIG_SERIAL_SH_SCI=y -CONFIG_SERIAL_SH_SCI_NR_UARTS=1 -CONFIG_SERIAL_SH_SCI_CONSOLE=y -CONFIG_SERIAL_CORE=y -CONFIG_SERIAL_CORE_CONSOLE=y -CONFIG_UNIX98_PTYS=y -CONFIG_LEGACY_PTYS=y -CONFIG_LEGACY_PTY_COUNT=256 -# CONFIG_IPMI_HANDLER is not set -CONFIG_HW_RANDOM=y -# CONFIG_R3964 is not set -# CONFIG_RAW_DRIVER is not set -# CONFIG_TCG_TPM is not set -# CONFIG_I2C is not set -CONFIG_SPI=y -# CONFIG_SPI_DEBUG is not set -CONFIG_SPI_MASTER=y - -# -# SPI Master Controller Drivers -# -CONFIG_SPI_BITBANG=y -# CONFIG_SPI_SH_SCI is not set - -# -# SPI Protocol Masters -# -# CONFIG_SPI_AT25 is not set -# CONFIG_SPI_SPIDEV is not set -# CONFIG_SPI_TLE62X0 is not set -# CONFIG_W1 is not set -# CONFIG_POWER_SUPPLY is not set -CONFIG_HWMON=y -# CONFIG_HWMON_VID is not set -# CONFIG_SENSORS_ADCXX is not set -# CONFIG_SENSORS_F71805F is not set -# CONFIG_SENSORS_F71882FG is not set -# CONFIG_SENSORS_IT87 is not set -# CONFIG_SENSORS_LM70 is not set -# CONFIG_SENSORS_MAX1111 is not set -# CONFIG_SENSORS_PC87360 is not set -# CONFIG_SENSORS_PC87427 is not set -# CONFIG_SENSORS_SMSC47M1 is not set -# CONFIG_SENSORS_SMSC47B397 is not set -# CONFIG_SENSORS_VT1211 is not set -# CONFIG_SENSORS_W83627HF is not set -# CONFIG_SENSORS_W83627EHF is not set -# CONFIG_HWMON_DEBUG_CHIP is not set -# CONFIG_THERMAL is not set -# CONFIG_THERMAL_HWMON is not set -# CONFIG_WATCHDOG is not set - -# -# Sonics Silicon Backplane -# -CONFIG_SSB_POSSIBLE=y -# CONFIG_SSB is not set - -# -# Multifunction device drivers -# -# CONFIG_MFD_CORE is not set -CONFIG_MFD_SM501=y -# CONFIG_HTC_PASIC3 is not set -# CONFIG_MFD_TMIO is not set -# CONFIG_MFD_WM8400 is not set - -# -# Multimedia devices -# - -# -# Multimedia core support -# -# CONFIG_VIDEO_DEV is not set -# CONFIG_VIDEO_MEDIA is not set - -# -# Multimedia drivers -# -CONFIG_DAB=y - -# -# Graphics support -# -# CONFIG_VGASTATE is not set -CONFIG_VIDEO_OUTPUT_CONTROL=m -CONFIG_FB=y -# CONFIG_FIRMWARE_EDID is not set -# CONFIG_FB_DDC is not set -# CONFIG_FB_BOOT_VESA_SUPPORT is not set -CONFIG_FB_CFB_FILLRECT=y -CONFIG_FB_CFB_COPYAREA=y -CONFIG_FB_CFB_IMAGEBLIT=y -# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set -# CONFIG_FB_SYS_FILLRECT is not set -# CONFIG_FB_SYS_COPYAREA is not set -# CONFIG_FB_SYS_IMAGEBLIT is not set -# CONFIG_FB_FOREIGN_ENDIAN is not set -# CONFIG_FB_SYS_FOPS is not set -# CONFIG_FB_SVGALIB is not set -# CONFIG_FB_MACMODES is not set -# CONFIG_FB_BACKLIGHT is not set -# CONFIG_FB_MODE_HELPERS is not set -# CONFIG_FB_TILEBLITTING is not set - -# -# Frame buffer hardware drivers -# -# CONFIG_FB_S1D13XXX is not set -CONFIG_FB_SH_MOBILE_LCDC=m -CONFIG_FB_SM501=y -# CONFIG_FB_VIRTUAL is not set -# CONFIG_FB_METRONOME is not set -# CONFIG_BACKLIGHT_LCD_SUPPORT is not set - -# -# Display device support -# -# CONFIG_DISPLAY_SUPPORT is not set - -# -# Console display driver support -# -CONFIG_DUMMY_CONSOLE=y -CONFIG_FRAMEBUFFER_CONSOLE=y -# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set -# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set -# CONFIG_FONTS is not set -CONFIG_FONT_8x8=y -CONFIG_FONT_8x16=y -CONFIG_LOGO=y -# CONFIG_LOGO_LINUX_MONO is not set -# CONFIG_LOGO_LINUX_VGA16 is not set -# CONFIG_LOGO_LINUX_CLUT224 is not set -# CONFIG_LOGO_SUPERH_MONO is not set -# CONFIG_LOGO_SUPERH_VGA16 is not set -CONFIG_LOGO_SUPERH_CLUT224=y -CONFIG_SOUND=y -CONFIG_SOUND_OSS_CORE=y -CONFIG_SND=m -# CONFIG_SND_SEQUENCER is not set -# CONFIG_SND_MIXER_OSS is not set -# CONFIG_SND_PCM_OSS is not set -# CONFIG_SND_DYNAMIC_MINORS is not set -CONFIG_SND_SUPPORT_OLD_API=y -CONFIG_SND_VERBOSE_PROCFS=y -# CONFIG_SND_VERBOSE_PRINTK is not set -# CONFIG_SND_DEBUG is not set -CONFIG_SND_DRIVERS=y -# CONFIG_SND_DUMMY is not set -# CONFIG_SND_MTPAV is not set -# CONFIG_SND_SERIAL_U16550 is not set -# CONFIG_SND_MPU401 is not set -CONFIG_SND_SPI=y -CONFIG_SND_SUPERH=y -# CONFIG_SND_SOC is not set -CONFIG_SOUND_PRIME=m -CONFIG_HID_SUPPORT=y -CONFIG_HID=y -# CONFIG_HID_DEBUG is not set -# CONFIG_HIDRAW is not set -# CONFIG_HID_PID is not set - -# -# Special HID drivers -# -CONFIG_HID_COMPAT=y -# CONFIG_USB_SUPPORT is not set -# CONFIG_MMC is not set -# CONFIG_MEMSTICK is not set -# CONFIG_NEW_LEDS is not set -# CONFIG_ACCESSIBILITY is not set -CONFIG_RTC_LIB=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_HCTOSYS=y -CONFIG_RTC_HCTOSYS_DEVICE="rtc0" -# CONFIG_RTC_DEBUG is not set - -# -# RTC interfaces -# -CONFIG_RTC_INTF_SYSFS=y -CONFIG_RTC_INTF_PROC=y -CONFIG_RTC_INTF_DEV=y -# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set -# CONFIG_RTC_DRV_TEST is not set - -# -# SPI RTC drivers -# -# CONFIG_RTC_DRV_M41T94 is not set -# CONFIG_RTC_DRV_DS1305 is not set -# CONFIG_RTC_DRV_MAX6902 is not set -CONFIG_RTC_DRV_R9701=y -# CONFIG_RTC_DRV_RS5C348 is not set -# CONFIG_RTC_DRV_DS3234 is not set - -# -# Platform RTC drivers -# -# CONFIG_RTC_DRV_DS1286 is not set -# CONFIG_RTC_DRV_DS1511 is not set -# CONFIG_RTC_DRV_DS1553 is not set -# CONFIG_RTC_DRV_DS1742 is not set -# CONFIG_RTC_DRV_STK17TA8 is not set -# CONFIG_RTC_DRV_M48T86 is not set -# CONFIG_RTC_DRV_M48T35 is not set -# CONFIG_RTC_DRV_M48T59 is not set -# CONFIG_RTC_DRV_BQ4802 is not set -# CONFIG_RTC_DRV_V3020 is not set - -# -# on-CPU RTC drivers -# -# CONFIG_RTC_DRV_SH is not set -# CONFIG_DMADEVICES is not set -# CONFIG_UIO is not set -# CONFIG_STAGING is not set - -# -# File systems -# -CONFIG_EXT2_FS=y -# CONFIG_EXT2_FS_XATTR is not set -# CONFIG_EXT2_FS_XIP is not set -# CONFIG_EXT3_FS is not set -# CONFIG_EXT4_FS is not set -# CONFIG_REISERFS_FS is not set -# CONFIG_JFS_FS is not set -# CONFIG_FS_POSIX_ACL is not set -CONFIG_FILE_LOCKING=y -# CONFIG_XFS_FS is not set -CONFIG_DNOTIFY=y -CONFIG_INOTIFY=y -CONFIG_INOTIFY_USER=y -# CONFIG_QUOTA is not set -# CONFIG_AUTOFS_FS is not set -# CONFIG_AUTOFS4_FS is not set -# CONFIG_FUSE_FS is not set - -# -# CD-ROM/DVD Filesystems -# -# CONFIG_ISO9660_FS is not set -# CONFIG_UDF_FS is not set - -# -# DOS/FAT/NT Filesystems -# -CONFIG_FAT_FS=y -CONFIG_MSDOS_FS=y -CONFIG_VFAT_FS=y -CONFIG_FAT_DEFAULT_CODEPAGE=437 -CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" -# CONFIG_NTFS_FS is not set - -# -# Pseudo filesystems -# -CONFIG_PROC_FS=y -CONFIG_PROC_KCORE=y -CONFIG_PROC_SYSCTL=y -CONFIG_PROC_PAGE_MONITOR=y -CONFIG_SYSFS=y -CONFIG_TMPFS=y -# CONFIG_TMPFS_POSIX_ACL is not set -# CONFIG_HUGETLBFS is not set -# CONFIG_HUGETLB_PAGE is not set -# CONFIG_CONFIGFS_FS is not set - -# -# Miscellaneous filesystems -# -# CONFIG_ADFS_FS is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_HFSPLUS_FS is not set -# CONFIG_BEFS_FS is not set -# CONFIG_BFS_FS is not set -# CONFIG_EFS_FS is not set -# CONFIG_CRAMFS is not set -# CONFIG_VXFS_FS is not set -CONFIG_MINIX_FS=y -# CONFIG_OMFS_FS is not set -# CONFIG_HPFS_FS is not set -# CONFIG_QNX4FS_FS is not set -# CONFIG_ROMFS_FS is not set -# CONFIG_SYSV_FS is not set -# CONFIG_UFS_FS is not set - -# -# Partition Types -# -# CONFIG_PARTITION_ADVANCED is not set -CONFIG_MSDOS_PARTITION=y -CONFIG_NLS=y -CONFIG_NLS_DEFAULT="iso8859-1" -# CONFIG_NLS_CODEPAGE_437 is not set -# CONFIG_NLS_CODEPAGE_737 is not set -# CONFIG_NLS_CODEPAGE_775 is not set -# CONFIG_NLS_CODEPAGE_850 is not set -# CONFIG_NLS_CODEPAGE_852 is not set -# CONFIG_NLS_CODEPAGE_855 is not set -# CONFIG_NLS_CODEPAGE_857 is not set -# CONFIG_NLS_CODEPAGE_860 is not set -# CONFIG_NLS_CODEPAGE_861 is not set -# CONFIG_NLS_CODEPAGE_862 is not set -# CONFIG_NLS_CODEPAGE_863 is not set -# CONFIG_NLS_CODEPAGE_864 is not set -# CONFIG_NLS_CODEPAGE_865 is not set -# CONFIG_NLS_CODEPAGE_866 is not set -# CONFIG_NLS_CODEPAGE_869 is not set -# CONFIG_NLS_CODEPAGE_936 is not set -# CONFIG_NLS_CODEPAGE_950 is not set -CONFIG_NLS_CODEPAGE_932=y -# CONFIG_NLS_CODEPAGE_949 is not set -# CONFIG_NLS_CODEPAGE_874 is not set -# CONFIG_NLS_ISO8859_8 is not set -# CONFIG_NLS_CODEPAGE_1250 is not set -# CONFIG_NLS_CODEPAGE_1251 is not set -# CONFIG_NLS_ASCII is not set -# CONFIG_NLS_ISO8859_1 is not set -# CONFIG_NLS_ISO8859_2 is not set -# CONFIG_NLS_ISO8859_3 is not set -# CONFIG_NLS_ISO8859_4 is not set -# CONFIG_NLS_ISO8859_5 is not set -# CONFIG_NLS_ISO8859_6 is not set -# CONFIG_NLS_ISO8859_7 is not set -# CONFIG_NLS_ISO8859_9 is not set -# CONFIG_NLS_ISO8859_13 is not set -# CONFIG_NLS_ISO8859_14 is not set -# CONFIG_NLS_ISO8859_15 is not set -# CONFIG_NLS_KOI8_R is not set -# CONFIG_NLS_KOI8_U is not set -# CONFIG_NLS_UTF8 is not set - -# -# Kernel hacking -# -CONFIG_TRACE_IRQFLAGS_SUPPORT=y -# CONFIG_PRINTK_TIME is not set -CONFIG_ENABLE_WARN_DEPRECATED=y -CONFIG_ENABLE_MUST_CHECK=y -CONFIG_FRAME_WARN=1024 -# CONFIG_MAGIC_SYSRQ is not set -# CONFIG_UNUSED_SYMBOLS is not set -CONFIG_DEBUG_FS=y -# CONFIG_HEADERS_CHECK is not set -CONFIG_DEBUG_KERNEL=y -# CONFIG_DEBUG_SHIRQ is not set -CONFIG_DETECT_SOFTLOCKUP=y -# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set -CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 -CONFIG_SCHED_DEBUG=y -# CONFIG_SCHEDSTATS is not set -# CONFIG_TIMER_STATS is not set -# CONFIG_DEBUG_OBJECTS is not set -# CONFIG_DEBUG_SLAB is not set -# CONFIG_DEBUG_RT_MUTEXES is not set -# CONFIG_RT_MUTEX_TESTER is not set -# CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_DEBUG_MUTEXES is not set -# CONFIG_DEBUG_LOCK_ALLOC is not set -# CONFIG_PROVE_LOCKING is not set -# CONFIG_LOCK_STAT is not set -# CONFIG_DEBUG_SPINLOCK_SLEEP is not set -# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set -# CONFIG_DEBUG_KOBJECT is not set -# CONFIG_DEBUG_BUGVERBOSE is not set -CONFIG_DEBUG_INFO=y -# CONFIG_DEBUG_VM is not set -# CONFIG_DEBUG_WRITECOUNT is not set -# CONFIG_DEBUG_MEMORY_INIT is not set -# CONFIG_DEBUG_LIST is not set -# CONFIG_DEBUG_SG is not set -# CONFIG_FRAME_POINTER is not set -# CONFIG_RCU_TORTURE_TEST is not set -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -# CONFIG_BACKTRACE_SELF_TEST is not set -# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set -# CONFIG_FAULT_INJECTION is not set -# CONFIG_LATENCYTOP is not set -CONFIG_NOP_TRACER=y -CONFIG_HAVE_FTRACE=y -# CONFIG_FTRACE is not set -# CONFIG_IRQSOFF_TRACER is not set -# CONFIG_SCHED_TRACER is not set -# CONFIG_CONTEXT_SWITCH_TRACER is not set -# CONFIG_BOOT_TRACER is not set -# CONFIG_STACK_TRACER is not set -# CONFIG_DYNAMIC_PRINTK_DEBUG is not set -# CONFIG_SAMPLES is not set -# CONFIG_SH_STANDARD_BIOS is not set -CONFIG_EARLY_SCIF_CONSOLE=y -CONFIG_EARLY_SCIF_CONSOLE_PORT=0xffe80000 -CONFIG_EARLY_PRINTK=y -# CONFIG_DEBUG_BOOTMEM is not set -# CONFIG_DEBUG_STACKOVERFLOW is not set -# CONFIG_DEBUG_STACK_USAGE is not set -# CONFIG_4KSTACKS is not set -# CONFIG_IRQSTACKS is not set -# CONFIG_SH_KGDB is not set - -# -# Security options -# -# CONFIG_KEYS is not set -# CONFIG_SECURITY is not set -# CONFIG_SECURITYFS is not set -# CONFIG_SECURITY_FILE_CAPABILITIES is not set -CONFIG_CRYPTO=y - -# -# Crypto core or helper -# -# CONFIG_CRYPTO_FIPS is not set -# CONFIG_CRYPTO_MANAGER is not set -# CONFIG_CRYPTO_GF128MUL is not set -# CONFIG_CRYPTO_NULL is not set -# CONFIG_CRYPTO_CRYPTD is not set -# CONFIG_CRYPTO_AUTHENC is not set -# CONFIG_CRYPTO_TEST is not set - -# -# Authenticated Encryption with Associated Data -# -# CONFIG_CRYPTO_CCM is not set -# CONFIG_CRYPTO_GCM is not set -# CONFIG_CRYPTO_SEQIV is not set - -# -# Block modes -# -# CONFIG_CRYPTO_CBC is not set -# CONFIG_CRYPTO_CTR is not set -# CONFIG_CRYPTO_CTS is not set -# CONFIG_CRYPTO_ECB is not set -# CONFIG_CRYPTO_LRW is not set -# CONFIG_CRYPTO_PCBC is not set -# CONFIG_CRYPTO_XTS is not set - -# -# Hash modes -# -# CONFIG_CRYPTO_HMAC is not set -# CONFIG_CRYPTO_XCBC is not set - -# -# Digest -# -# CONFIG_CRYPTO_CRC32C is not set -# CONFIG_CRYPTO_MD4 is not set -# CONFIG_CRYPTO_MD5 is not set -# CONFIG_CRYPTO_MICHAEL_MIC is not set -# CONFIG_CRYPTO_RMD128 is not set -# CONFIG_CRYPTO_RMD160 is not set -# CONFIG_CRYPTO_RMD256 is not set -# CONFIG_CRYPTO_RMD320 is not set -# CONFIG_CRYPTO_SHA1 is not set -# CONFIG_CRYPTO_SHA256 is not set -# CONFIG_CRYPTO_SHA512 is not set -# CONFIG_CRYPTO_TGR192 is not set -# CONFIG_CRYPTO_WP512 is not set - -# -# Ciphers -# -# CONFIG_CRYPTO_AES is not set -# CONFIG_CRYPTO_ANUBIS is not set -# CONFIG_CRYPTO_ARC4 is not set -# CONFIG_CRYPTO_BLOWFISH is not set -# CONFIG_CRYPTO_CAMELLIA is not set -# CONFIG_CRYPTO_CAST5 is not set -# CONFIG_CRYPTO_CAST6 is not set -# CONFIG_CRYPTO_DES is not set -# CONFIG_CRYPTO_FCRYPT is not set -# CONFIG_CRYPTO_KHAZAD is not set -# CONFIG_CRYPTO_SALSA20 is not set -# CONFIG_CRYPTO_SEED is not set -# CONFIG_CRYPTO_SERPENT is not set -# CONFIG_CRYPTO_TEA is not set -# CONFIG_CRYPTO_TWOFISH is not set - -# -# Compression -# -# CONFIG_CRYPTO_DEFLATE is not set -# CONFIG_CRYPTO_LZO is not set - -# -# Random Number Generation -# -# CONFIG_CRYPTO_ANSI_CPRNG is not set -CONFIG_CRYPTO_HW=y - -# -# Library routines -# -CONFIG_BITREVERSE=y -# CONFIG_CRC_CCITT is not set -# CONFIG_CRC16 is not set -CONFIG_CRC_T10DIF=y -# CONFIG_CRC_ITU_T is not set -CONFIG_CRC32=y -# CONFIG_CRC7 is not set -# CONFIG_LIBCRC32C is not set -CONFIG_PLIST=y -CONFIG_HAS_IOMEM=y -CONFIG_HAS_IOPORT=y -CONFIG_HAS_DMA=y diff --git a/arch/sh/configs/se7343_defconfig b/arch/sh/configs/se7343_defconfig index 075f42ed5b09bcb0ade08d69b08d12e73dcbeb08..be246f381507af0a1c5772b189ff52516461cc07 100644 --- a/arch/sh/configs/se7343_defconfig +++ b/arch/sh/configs/se7343_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.27 -# Wed Oct 22 19:00:21 2008 +# Linux kernel version: 2.6.28-rc6 +# Thu Dec 4 16:40:25 2008 # CONFIG_SUPERH=y CONFIG_SUPERH32=y @@ -74,7 +74,6 @@ CONFIG_EVENTFD=y # CONFIG_SHMEM is not set CONFIG_AIO=y CONFIG_VM_EVENT_COUNTERS=y -CONFIG_PCI_QUIRKS=y CONFIG_SLAB=y # CONFIG_SLUB is not set # CONFIG_SLOB is not set @@ -127,6 +126,7 @@ CONFIG_CPU_SH4=y CONFIG_CPU_SH4A=y CONFIG_CPU_SH4AL_DSP=y # CONFIG_CPU_SUBTYPE_SH7619 is not set +# CONFIG_CPU_SUBTYPE_SH7201 is not set # CONFIG_CPU_SUBTYPE_SH7203 is not set # CONFIG_CPU_SUBTYPE_SH7206 is not set # CONFIG_CPU_SUBTYPE_SH7263 is not set @@ -227,7 +227,7 @@ CONFIG_SH_7343_SOLUTION_ENGINE=y # CONFIG_SH_TMU=y CONFIG_SH_TIMER_IRQ=16 -CONFIG_SH_PCLK_FREQ=27000000 +CONFIG_SH_PCLK_FREQ=33333333 # CONFIG_NO_HZ is not set # CONFIG_HIGH_RES_TIMERS is not set CONFIG_GENERIC_CLOCKEVENTS_BUILD=y @@ -274,7 +274,8 @@ CONFIG_GUSA=y # CONFIG_ZERO_PAGE_OFFSET=0x00001000 CONFIG_BOOT_LINK_OFFSET=0x00800000 -# CONFIG_CMDLINE_BOOL is not set +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="console=ttySC0,115200" # # Bus options @@ -463,6 +464,7 @@ CONFIG_BLK_DEV=y # CONFIG_BLK_DEV_COW_COMMON is not set # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_UB is not set # CONFIG_BLK_DEV_RAM is not set # CONFIG_CDROM_PKTCDVD is not set # CONFIG_ATA_OVER_ETH is not set @@ -519,23 +521,10 @@ CONFIG_NETDEVICES=y # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set # CONFIG_VETH is not set -# CONFIG_PHYLIB is not set -CONFIG_NET_ETHERNET=y +# CONFIG_NET_ETHERNET is not set CONFIG_MII=y -# CONFIG_AX88796 is not set -# CONFIG_STNIC is not set -CONFIG_SMC91X=y -# CONFIG_SMC911X is not set -# CONFIG_IBM_NEW_EMAC_ZMII is not set -# CONFIG_IBM_NEW_EMAC_RGMII is not set -# CONFIG_IBM_NEW_EMAC_TAH is not set -# CONFIG_IBM_NEW_EMAC_EMAC4 is not set -# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set -# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set -# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set -# CONFIG_B44 is not set -CONFIG_NETDEV_1000=y -CONFIG_NETDEV_10000=y +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set # # Wireless LAN @@ -543,6 +532,26 @@ CONFIG_NETDEV_10000=y # CONFIG_WLAN_PRE80211 is not set # CONFIG_WLAN_80211 is not set # CONFIG_IWLWIFI_LEDS is not set + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +CONFIG_USB_USBNET=y +# CONFIG_USB_NET_AX8817X is not set +CONFIG_USB_NET_CDCETHER=y +CONFIG_USB_NET_DM9601=y +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_GL620A is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +# CONFIG_USB_NET_CDC_SUBSET is not set +# CONFIG_USB_NET_ZAURUS is not set # CONFIG_WAN is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set @@ -597,13 +606,17 @@ CONFIG_DEVKMEM=y # # Serial drivers # -# CONFIG_SERIAL_8250 is not set +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_CONSOLE is not set +CONFIG_SERIAL_8250_NR_UARTS=2 +CONFIG_SERIAL_8250_RUNTIME_UARTS=2 +# CONFIG_SERIAL_8250_EXTENDED is not set # # Non-8250 serial port support # CONFIG_SERIAL_SH_SCI=y -CONFIG_SERIAL_SH_SCI_NR_UARTS=2 +CONFIG_SERIAL_SH_SCI_NR_UARTS=4 CONFIG_SERIAL_SH_SCI_CONSOLE=y CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y @@ -615,7 +628,51 @@ CONFIG_HW_RANDOM=y # CONFIG_R3964 is not set # CONFIG_RAW_DRIVER is not set # CONFIG_TCG_TPM is not set -# CONFIG_I2C is not set +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +# CONFIG_I2C_CHARDEV is not set +CONFIG_I2C_HELPER_AUTO=y + +# +# I2C Hardware Bus support +# + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_OCORES is not set +CONFIG_I2C_SH_MOBILE=y +# CONFIG_I2C_SIMTEC is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_STUB is not set + +# +# Miscellaneous I2C Chip support +# +# CONFIG_DS1682 is not set +# CONFIG_AT24 is not set +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_PCF8575 is not set +# CONFIG_SENSORS_PCA9539 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_MAX6875 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set # CONFIG_SPI is not set # CONFIG_W1 is not set # CONFIG_POWER_SUPPLY is not set @@ -623,11 +680,11 @@ CONFIG_HW_RANDOM=y # CONFIG_THERMAL is not set # CONFIG_THERMAL_HWMON is not set # CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y # # Sonics Silicon Backplane # -CONFIG_SSB_POSSIBLE=y # CONFIG_SSB is not set # @@ -637,7 +694,10 @@ CONFIG_SSB_POSSIBLE=y # CONFIG_MFD_SM501 is not set # CONFIG_HTC_PASIC3 is not set # CONFIG_MFD_TMIO is not set +# CONFIG_PMIC_DA903X is not set # CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_REGULATOR is not set # # Multimedia devices @@ -657,6 +717,16 @@ CONFIG_VIDEO_MEDIA=y # Multimedia drivers # # CONFIG_MEDIA_ATTACH is not set +CONFIG_MEDIA_TUNER=y +# CONFIG_MEDIA_TUNER_CUSTOMIZE is not set +CONFIG_MEDIA_TUNER_SIMPLE=y +CONFIG_MEDIA_TUNER_TDA8290=y +CONFIG_MEDIA_TUNER_TDA9887=y +CONFIG_MEDIA_TUNER_TEA5761=y +CONFIG_MEDIA_TUNER_TEA5767=y +CONFIG_MEDIA_TUNER_MT20XX=y +CONFIG_MEDIA_TUNER_XC2028=y +CONFIG_MEDIA_TUNER_XC5000=y CONFIG_VIDEO_V4L2=y CONFIG_VIDEO_V4L1=y CONFIG_VIDEO_CAPTURE_DRIVERS=y @@ -665,8 +735,57 @@ CONFIG_VIDEO_CAPTURE_DRIVERS=y CONFIG_VIDEO_HELPER_CHIPS_AUTO=y # CONFIG_VIDEO_VIVI is not set # CONFIG_VIDEO_CPIA is not set +# CONFIG_VIDEO_CPIA2 is not set +# CONFIG_VIDEO_SAA5246A is not set +# CONFIG_VIDEO_SAA5249 is not set # CONFIG_SOC_CAMERA is not set +CONFIG_V4L_USB_DRIVERS=y +# CONFIG_USB_VIDEO_CLASS is not set +CONFIG_USB_GSPCA=m +# CONFIG_USB_M5602 is not set +# CONFIG_USB_GSPCA_CONEX is not set +# CONFIG_USB_GSPCA_ETOMS is not set +# CONFIG_USB_GSPCA_FINEPIX is not set +# CONFIG_USB_GSPCA_MARS is not set +# CONFIG_USB_GSPCA_OV519 is not set +# CONFIG_USB_GSPCA_PAC207 is not set +# CONFIG_USB_GSPCA_PAC7311 is not set +# CONFIG_USB_GSPCA_SONIXB is not set +# CONFIG_USB_GSPCA_SONIXJ is not set +# CONFIG_USB_GSPCA_SPCA500 is not set +# CONFIG_USB_GSPCA_SPCA501 is not set +# CONFIG_USB_GSPCA_SPCA505 is not set +# CONFIG_USB_GSPCA_SPCA506 is not set +# CONFIG_USB_GSPCA_SPCA508 is not set +# CONFIG_USB_GSPCA_SPCA561 is not set +# CONFIG_USB_GSPCA_STK014 is not set +# CONFIG_USB_GSPCA_SUNPLUS is not set +# CONFIG_USB_GSPCA_T613 is not set +# CONFIG_USB_GSPCA_TV8532 is not set +# CONFIG_USB_GSPCA_VC032X is not set +# CONFIG_USB_GSPCA_ZC3XX is not set +# CONFIG_VIDEO_PVRUSB2 is not set +# CONFIG_VIDEO_EM28XX is not set +# CONFIG_VIDEO_USBVISION is not set +# CONFIG_USB_VICAM is not set +# CONFIG_USB_IBMCAM is not set +# CONFIG_USB_KONICAWC is not set +# CONFIG_USB_QUICKCAM_MESSENGER is not set +# CONFIG_USB_ET61X251 is not set +# CONFIG_VIDEO_OVCAMCHIP is not set +# CONFIG_USB_OV511 is not set +# CONFIG_USB_SE401 is not set +# CONFIG_USB_SN9C102 is not set +# CONFIG_USB_STV680 is not set +# CONFIG_USB_ZC0301 is not set +# CONFIG_USB_PWC is not set +# CONFIG_USB_ZR364XX is not set +# CONFIG_USB_STKWEBCAM is not set +# CONFIG_USB_S2255 is not set CONFIG_RADIO_ADAPTERS=y +# CONFIG_USB_DSBR is not set +# CONFIG_USB_SI470X is not set +# CONFIG_USB_MR800 is not set # CONFIG_DAB is not set # @@ -700,6 +819,7 @@ CONFIG_FB_CFB_IMAGEBLIT=m CONFIG_FB_SH_MOBILE_LCDC=m # CONFIG_FB_VIRTUAL is not set # CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set # CONFIG_BACKLIGHT_LCD_SUPPORT is not set # @@ -737,27 +857,147 @@ CONFIG_SND_DRIVERS=y # CONFIG_SND_SERIAL_U16550 is not set # CONFIG_SND_MPU401 is not set CONFIG_SND_SUPERH=y +CONFIG_SND_USB=y +# CONFIG_SND_USB_AUDIO is not set +# CONFIG_SND_USB_CAIAQ is not set # CONFIG_SND_SOC is not set # CONFIG_SOUND_PRIME is not set CONFIG_HID_SUPPORT=y CONFIG_HID=y # CONFIG_HID_DEBUG is not set # CONFIG_HIDRAW is not set + +# +# USB Input Devices +# +CONFIG_USB_HID=y # CONFIG_HID_PID is not set +# CONFIG_USB_HIDDEV is not set # # Special HID drivers # CONFIG_HID_COMPAT=y -# CONFIG_USB_SUPPORT is not set +CONFIG_HID_A4TECH=y +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_BRIGHT=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_DELL=y +CONFIG_HID_EZKEY=y +CONFIG_HID_GYRATION=y +CONFIG_HID_LOGITECH=y +# CONFIG_LOGITECH_FF is not set +# CONFIG_LOGIRUMBLEPAD2_FF is not set +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_HID_PANTHERLORD=y +# CONFIG_PANTHERLORD_FF is not set +CONFIG_HID_PETALYNX=y +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SONY=y +CONFIG_HID_SUNPLUS=y +# CONFIG_THRUSTMASTER_FF is not set +# CONFIG_ZEROPLUS_FF is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_ARCH_HAS_HCD=y +# CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set +CONFIG_USB=y +CONFIG_USB_DEBUG=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +CONFIG_USB_DEVICE_CLASS=y +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_MON is not set +# CONFIG_USB_WUSB is not set +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +CONFIG_USB_ISP116X_HCD=y +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_HWA_HCD is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed; +# + +# +# see USB_STORAGE Help for more information +# +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_LIBUSUAL is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB port drivers +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_BERRY_CHARGE is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGET is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_VST is not set +# CONFIG_USB_GADGET is not set # CONFIG_MMC is not set # CONFIG_MEMSTICK is not set # CONFIG_NEW_LEDS is not set # CONFIG_ACCESSIBILITY is not set # CONFIG_RTC_CLASS is not set # CONFIG_DMADEVICES is not set -# CONFIG_UIO is not set +CONFIG_UIO=y +# CONFIG_UIO_PDRV is not set +# CONFIG_UIO_PDRV_GENIRQ is not set +# CONFIG_UIO_SMX is not set +# CONFIG_UIO_SERCOS3 is not set # CONFIG_STAGING is not set +CONFIG_STAGING_EXCLUDE_BUILD=y # # File systems @@ -889,8 +1129,13 @@ CONFIG_FRAME_WARN=1024 # CONFIG_DEBUG_MEMORY_INIT is not set # CONFIG_RCU_CPU_STALL_DETECTOR is not set # CONFIG_LATENCYTOP is not set -CONFIG_NOP_TRACER=y -CONFIG_HAVE_FTRACE=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y + +# +# Tracers +# # CONFIG_DYNAMIC_PRINTK_DEBUG is not set # CONFIG_SAMPLES is not set # CONFIG_SH_STANDARD_BIOS is not set diff --git a/arch/sh/drivers/dma/Makefile b/arch/sh/drivers/dma/Makefile index 1ac812d2448837dd02ae30a784ab91d69554f349..ab956adacb47688505f53061a105eae22134eb38 100644 --- a/arch/sh/drivers/dma/Makefile +++ b/arch/sh/drivers/dma/Makefile @@ -3,7 +3,6 @@ # obj-$(CONFIG_SH_DMA_API) += dma-api.o dma-sysfs.o -obj-$(CONFIG_ISA_DMA_API) += dma-isa.o obj-$(CONFIG_SH_DMA) += dma-sh.o obj-$(CONFIG_SH_DREAMCAST) += dma-pvr2.o dma-g2.o obj-$(CONFIG_SH_DMABRG) += dmabrg.o diff --git a/arch/sh/drivers/dma/dma-isa.c b/arch/sh/drivers/dma/dma-isa.c deleted file mode 100644 index 5fb044b791c37ecf9342cdec533cf1d19462f1de..0000000000000000000000000000000000000000 --- a/arch/sh/drivers/dma/dma-isa.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * arch/sh/drivers/dma/dma-isa.c - * - * Generic ISA DMA wrapper for SH DMA API - * - * Copyright (C) 2003, 2004 Paul Mundt - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ -#include -#include -#include - -/* - * This implements a small wrapper set to make code using the old ISA DMA API - * work with the SH DMA API. Since most of the work in the new API happens - * at ops->xfer() time, we simply use the various set_dma_xxx() routines to - * fill in per-channel info, and then hand hand this off to ops->xfer() at - * enable_dma() time. - * - * For channels that are doing on-demand data transfer via cascading, the - * channel itself will still need to be configured through the new API. As - * such, this code is meant for only the simplest of tasks (and shouldn't be - * used in any new drivers at all). - * - * NOTE: ops->xfer() is the preferred way of doing things. However, there - * are some users of the ISA DMA API that exist in common code that we - * don't necessarily want to go out of our way to break, so we still - * allow for some compatibility at that level. Any new code is strongly - * advised to run far away from the ISA DMA API and use the SH DMA API - * directly. - */ -unsigned long claim_dma_lock(void) -{ - unsigned long flags; - - spin_lock_irqsave(&dma_spin_lock, flags); - - return flags; -} -EXPORT_SYMBOL(claim_dma_lock); - -void release_dma_lock(unsigned long flags) -{ - spin_unlock_irqrestore(&dma_spin_lock, flags); -} -EXPORT_SYMBOL(release_dma_lock); - -void disable_dma(unsigned int chan) -{ - /* Nothing */ -} -EXPORT_SYMBOL(disable_dma); - -void enable_dma(unsigned int chan) -{ - struct dma_info *info = get_dma_info(chan); - struct dma_channel *channel = &info->channels[chan]; - - info->ops->xfer(channel); -} -EXPORT_SYMBOL(enable_dma); - -void clear_dma_ff(unsigned int chan) -{ - /* Nothing */ -} -EXPORT_SYMBOL(clear_dma_ff); - -void set_dma_mode(unsigned int chan, char mode) -{ - struct dma_info *info = get_dma_info(chan); - struct dma_channel *channel = &info->channels[chan]; - - channel->mode = mode; -} -EXPORT_SYMBOL(set_dma_mode); - -void set_dma_addr(unsigned int chan, unsigned int addr) -{ - struct dma_info *info = get_dma_info(chan); - struct dma_channel *channel = &info->channels[chan]; - - /* - * Single address mode is the only thing supported through - * this interface. - */ - if ((channel->mode & DMA_MODE_MASK) == DMA_MODE_READ) { - channel->sar = addr; - } else { - channel->dar = addr; - } -} -EXPORT_SYMBOL(set_dma_addr); - -void set_dma_count(unsigned int chan, unsigned int count) -{ - struct dma_info *info = get_dma_info(chan); - struct dma_channel *channel = &info->channels[chan]; - - channel->count = count; -} -EXPORT_SYMBOL(set_dma_count); - diff --git a/arch/sh/drivers/dma/dma-sh.c b/arch/sh/drivers/dma/dma-sh.c index b2ffe649c7c039d9bc3a03c7527ad37922a62552..50887a592dd02e3a13a0360357069ada0277a2e6 100644 --- a/arch/sh/drivers/dma/dma-sh.c +++ b/arch/sh/drivers/dma/dma-sh.c @@ -205,7 +205,8 @@ static int sh_dmac_get_dma_residue(struct dma_channel *chan) #if defined(CONFIG_CPU_SUBTYPE_SH7720) || \ defined(CONFIG_CPU_SUBTYPE_SH7721) || \ - defined(CONFIG_CPU_SUBTYPE_SH7780) + defined(CONFIG_CPU_SUBTYPE_SH7780) || \ + defined(CONFIG_CPU_SUBTYPE_SH7709) #define dmaor_read_reg() ctrl_inw(DMAOR) #define dmaor_write_reg(data) ctrl_outw(data, DMAOR) #else diff --git a/arch/sh/drivers/dma/dma-sh.h b/arch/sh/drivers/dma/dma-sh.h index b05af34fc15de0b6e5f40e500784bbf98b12cf31..05fecd5428e4af7bb53a4bfd04b4078d88b4080f 100644 --- a/arch/sh/drivers/dma/dma-sh.h +++ b/arch/sh/drivers/dma/dma-sh.h @@ -29,6 +29,7 @@ #define RS_IN 0x00000200 #define RS_OUT 0x00000300 #define TS_BLK 0x00000040 +#define TM_BUR 0x00000020 #define CHCR_DE 0x00000001 #define CHCR_TE 0x00000002 #define CHCR_IE 0x00000004 diff --git a/arch/sh/drivers/pci/ops-sh03.c b/arch/sh/drivers/pci/ops-sh03.c index ebb58e605d9d27ddd47fecc45ce30d3a1e11a5db..e1703ff5a4d237339264e9e4c699dcb8dc4c2073 100644 --- a/arch/sh/drivers/pci/ops-sh03.c +++ b/arch/sh/drivers/pci/ops-sh03.c @@ -18,7 +18,8 @@ */ int __init pcibios_init_platform(void) { - return 1; + __set_io_port_base(SH7751_PCI_IO_BASE); + return 1; } static struct resource sh7751_io_resource = { diff --git a/arch/sh/drivers/pci/pci-sh7780.c b/arch/sh/drivers/pci/pci-sh7780.c index b2a2bfa3c1bd244397ac17b5749abe2bf25172c5..078dc44d6b08b8a6e5fc2090e832e8f5d6fcb977 100644 --- a/arch/sh/drivers/pci/pci-sh7780.c +++ b/arch/sh/drivers/pci/pci-sh7780.c @@ -123,16 +123,14 @@ int __init sh7780_pcic_init(struct sh4_pci_address_map *map) * Window0 = map->window0.size @ non-cached area base = SDRAM * Window1 = map->window1.size @ cached area base = SDRAM */ - word = ((map->window0.size - 1) & 0x1ff00001) | 0x01; - pci_write_reg(0x07f00001, SH4_PCILSR0); - word = ((map->window1.size - 1) & 0x1ff00001) | 0x01; + word = (CONFIG_MEMORY_SIZE - 0x00100000) | 0x00000001; + pci_write_reg(word, SH4_PCILSR0); pci_write_reg(0x00000001, SH4_PCILSR1); /* Set the values on window 0 PCI config registers */ - word = P2SEGADDR(map->window0.base); - pci_write_reg(0xa8000000, SH4_PCILAR0); - pci_write_reg(0x08000000, SH7780_PCIMBAR0); + word = (CONFIG_MEMORY_SIZE > 0x08000000) ? 0x10000000 : 0x08000000; + pci_write_reg(word | 0xa0000000, SH4_PCILAR0); + pci_write_reg(word, SH7780_PCIMBAR0); /* Set the values on window 1 PCI config registers */ - word = P2SEGADDR(map->window1.base); pci_write_reg(0x00000000, SH4_PCILAR1); pci_write_reg(0x00000000, SH7780_PCIMBAR1); diff --git a/arch/sh/include/asm/addrspace.h b/arch/sh/include/asm/addrspace.h index 2702d81bfc0db77048cdf1670304e20ed08c39f2..36736c7e93dbd7a7621b9874047e7957294e4397 100644 --- a/arch/sh/include/asm/addrspace.h +++ b/arch/sh/include/asm/addrspace.h @@ -49,5 +49,16 @@ /* Check if an address can be reached in 29 bits */ #define IS_29BIT(a) (((unsigned long)(a)) < 0x20000000) +#ifdef CONFIG_SH_STORE_QUEUES +/* + * This is a special case for the SH-4 store queues, as pages for this + * space still need to be faulted in before it's possible to flush the + * store queue cache for writeout to the remapped region. + */ +#define P3_ADDR_MAX (P4SEG_STORE_QUE + 0x04000000) +#else +#define P3_ADDR_MAX P4SEG +#endif + #endif /* __KERNEL__ */ #endif /* __ASM_SH_ADDRSPACE_H */ diff --git a/arch/sh/include/asm/bitops-grb.h b/arch/sh/include/asm/bitops-grb.h index a5907b94395beee0cdfb88e39f8d53a56302efcf..e73af33acbf416df0aa0f124a240df423a8242c8 100644 --- a/arch/sh/include/asm/bitops-grb.h +++ b/arch/sh/include/asm/bitops-grb.h @@ -166,4 +166,7 @@ static inline int test_and_change_bit(int nr, volatile void * addr) return retval; } + +#include + #endif /* __ASM_SH_BITOPS_GRB_H */ diff --git a/arch/sh/include/asm/bitops-irq.h b/arch/sh/include/asm/bitops-irq.h deleted file mode 100644 index 653a12750584628130054485e529a2848f19f76a..0000000000000000000000000000000000000000 --- a/arch/sh/include/asm/bitops-irq.h +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef __ASM_SH_BITOPS_IRQ_H -#define __ASM_SH_BITOPS_IRQ_H - -static inline void set_bit(int nr, volatile void *addr) -{ - int mask; - volatile unsigned int *a = addr; - unsigned long flags; - - a += nr >> 5; - mask = 1 << (nr & 0x1f); - local_irq_save(flags); - *a |= mask; - local_irq_restore(flags); -} - -static inline void clear_bit(int nr, volatile void *addr) -{ - int mask; - volatile unsigned int *a = addr; - unsigned long flags; - - a += nr >> 5; - mask = 1 << (nr & 0x1f); - local_irq_save(flags); - *a &= ~mask; - local_irq_restore(flags); -} - -static inline void change_bit(int nr, volatile void *addr) -{ - int mask; - volatile unsigned int *a = addr; - unsigned long flags; - - a += nr >> 5; - mask = 1 << (nr & 0x1f); - local_irq_save(flags); - *a ^= mask; - local_irq_restore(flags); -} - -static inline int test_and_set_bit(int nr, volatile void *addr) -{ - int mask, retval; - volatile unsigned int *a = addr; - unsigned long flags; - - a += nr >> 5; - mask = 1 << (nr & 0x1f); - local_irq_save(flags); - retval = (mask & *a) != 0; - *a |= mask; - local_irq_restore(flags); - - return retval; -} - -static inline int test_and_clear_bit(int nr, volatile void *addr) -{ - int mask, retval; - volatile unsigned int *a = addr; - unsigned long flags; - - a += nr >> 5; - mask = 1 << (nr & 0x1f); - local_irq_save(flags); - retval = (mask & *a) != 0; - *a &= ~mask; - local_irq_restore(flags); - - return retval; -} - -static inline int test_and_change_bit(int nr, volatile void *addr) -{ - int mask, retval; - volatile unsigned int *a = addr; - unsigned long flags; - - a += nr >> 5; - mask = 1 << (nr & 0x1f); - local_irq_save(flags); - retval = (mask & *a) != 0; - *a ^= mask; - local_irq_restore(flags); - - return retval; -} - -#endif /* __ASM_SH_BITOPS_IRQ_H */ diff --git a/arch/sh/include/asm/bitops-llsc.h b/arch/sh/include/asm/bitops-llsc.h index 43b8e1a8239e70ac6a63509ab21fdbc177dea1f9..1d2fc0b010adf1a608375d3a59c6cce57e42002a 100644 --- a/arch/sh/include/asm/bitops-llsc.h +++ b/arch/sh/include/asm/bitops-llsc.h @@ -141,4 +141,6 @@ static inline int test_and_change_bit(int nr, volatile void * addr) return retval != 0; } +#include + #endif /* __ASM_SH_BITOPS_LLSC_H */ diff --git a/arch/sh/include/asm/bitops-op32.h b/arch/sh/include/asm/bitops-op32.h new file mode 100644 index 0000000000000000000000000000000000000000..f0ae7e9218e0cb6291f38425eb2e66981633d664 --- /dev/null +++ b/arch/sh/include/asm/bitops-op32.h @@ -0,0 +1,142 @@ +#ifndef __ASM_SH_BITOPS_OP32_H +#define __ASM_SH_BITOPS_OP32_H + +/* + * The bit modifying instructions on SH-2A are only capable of working + * with a 3-bit immediate, which signifies the shift position for the bit + * being worked on. + */ +#if defined(__BIG_ENDIAN) +#define BITOP_LE_SWIZZLE ((BITS_PER_LONG-1) & ~0x7) +#define BYTE_NUMBER(nr) ((nr ^ BITOP_LE_SWIZZLE) / BITS_PER_BYTE) +#define BYTE_OFFSET(nr) ((nr ^ BITOP_LE_SWIZZLE) % BITS_PER_BYTE) +#else +#define BYTE_NUMBER(nr) ((nr) / BITS_PER_BYTE) +#define BYTE_OFFSET(nr) ((nr) % BITS_PER_BYTE) +#endif + +#define IS_IMMEDIATE(nr) (__builtin_constant_p(nr)) + +static inline void __set_bit(int nr, volatile unsigned long *addr) +{ + if (IS_IMMEDIATE(nr)) { + __asm__ __volatile__ ( + "bset.b %1, @(%O2,%0) ! __set_bit\n\t" + : "+r" (addr) + : "i" (BYTE_OFFSET(nr)), "i" (BYTE_NUMBER(nr)) + : "t", "memory" + ); + } else { + unsigned long mask = BIT_MASK(nr); + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + + *p |= mask; + } +} + +static inline void __clear_bit(int nr, volatile unsigned long *addr) +{ + if (IS_IMMEDIATE(nr)) { + __asm__ __volatile__ ( + "bclr.b %1, @(%O2,%0) ! __clear_bit\n\t" + : "+r" (addr) + : "i" (BYTE_OFFSET(nr)), + "i" (BYTE_NUMBER(nr)) + : "t", "memory" + ); + } else { + unsigned long mask = BIT_MASK(nr); + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + + *p &= ~mask; + } +} + +/** + * __change_bit - Toggle a bit in memory + * @nr: the bit to change + * @addr: the address to start counting from + * + * Unlike change_bit(), this function is non-atomic and may be reordered. + * If it's called on the same region of memory simultaneously, the effect + * may be that only one operation succeeds. + */ +static inline void __change_bit(int nr, volatile unsigned long *addr) +{ + if (IS_IMMEDIATE(nr)) { + __asm__ __volatile__ ( + "bxor.b %1, @(%O2,%0) ! __change_bit\n\t" + : "+r" (addr) + : "i" (BYTE_OFFSET(nr)), + "i" (BYTE_NUMBER(nr)) + : "t", "memory" + ); + } else { + unsigned long mask = BIT_MASK(nr); + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + + *p ^= mask; + } +} + +/** + * __test_and_set_bit - Set a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is non-atomic and can be reordered. + * If two examples of this operation race, one can appear to succeed + * but actually fail. You must protect multiple accesses with a lock. + */ +static inline int __test_and_set_bit(int nr, volatile unsigned long *addr) +{ + unsigned long mask = BIT_MASK(nr); + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + unsigned long old = *p; + + *p = old | mask; + return (old & mask) != 0; +} + +/** + * __test_and_clear_bit - Clear a bit and return its old value + * @nr: Bit to clear + * @addr: Address to count from + * + * This operation is non-atomic and can be reordered. + * If two examples of this operation race, one can appear to succeed + * but actually fail. You must protect multiple accesses with a lock. + */ +static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr) +{ + unsigned long mask = BIT_MASK(nr); + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + unsigned long old = *p; + + *p = old & ~mask; + return (old & mask) != 0; +} + +/* WARNING: non atomic and it can be reordered! */ +static inline int __test_and_change_bit(int nr, + volatile unsigned long *addr) +{ + unsigned long mask = BIT_MASK(nr); + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + unsigned long old = *p; + + *p = old ^ mask; + return (old & mask) != 0; +} + +/** + * test_bit - Determine whether a bit is set + * @nr: bit number to test + * @addr: Address to start counting from + */ +static inline int test_bit(int nr, const volatile unsigned long *addr) +{ + return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); +} + +#endif /* __ASM_SH_BITOPS_OP32_H */ diff --git a/arch/sh/include/asm/bitops.h b/arch/sh/include/asm/bitops.h index 367930d8e5aeff378a49db60bf367af0b89bf235..ebe595b7ab1f06deed170345804ffc288ad41ed3 100644 --- a/arch/sh/include/asm/bitops.h +++ b/arch/sh/include/asm/bitops.h @@ -13,21 +13,22 @@ #ifdef CONFIG_GUSA_RB #include +#elif defined(CONFIG_CPU_SH2A) +#include +#include #elif defined(CONFIG_CPU_SH4A) #include #else -#include +#include +#include #endif - /* * clear_bit() doesn't provide any barrier for the compiler. */ #define smp_mb__before_clear_bit() barrier() #define smp_mb__after_clear_bit() barrier() -#include - #ifdef CONFIG_SUPERH32 static inline unsigned long ffz(unsigned long word) { diff --git a/arch/sh/include/asm/bugs.h b/arch/sh/include/asm/bugs.h index 121b2ecddfc35d46042677e1304913461937b71d..4924ff6f543948138ef835f400eb282780e3093d 100644 --- a/arch/sh/include/asm/bugs.h +++ b/arch/sh/include/asm/bugs.h @@ -25,7 +25,7 @@ static void __init check_bugs(void) case CPU_SH7619: *p++ = '2'; break; - case CPU_SH7203 ... CPU_MXG: + case CPU_SH7201 ... CPU_MXG: *p++ = '2'; *p++ = 'a'; break; diff --git a/arch/sh/include/asm/elf.h b/arch/sh/include/asm/elf.h index 9eb9036a1bdc27e9a1fb50efe636ed9150e9c3f1..ccb1d93bb04361678b967fd80151c43427263b27 100644 --- a/arch/sh/include/asm/elf.h +++ b/arch/sh/include/asm/elf.h @@ -108,13 +108,11 @@ typedef struct user_fpu_struct elf_fpregset_t; #define elf_check_fdpic(x) ((x)->e_flags & EF_SH_FDPIC) #define elf_check_const_displacement(x) ((x)->e_flags & EF_SH_PIC) -#ifdef CONFIG_SUPERH32 /* * Enable dump using regset. * This covers all of general/DSP/FPU regs. */ #define CORE_DUMP_USE_REGSET -#endif #define USE_ELF_CORE_DUMP #define ELF_FDPIC_CORE_EFLAGS EF_SH_FDPIC @@ -204,7 +202,7 @@ do { \ #define ARCH_HAS_SETUP_ADDITIONAL_PAGES struct linux_binprm; extern int arch_setup_additional_pages(struct linux_binprm *bprm, - int executable_stack); + int uses_interp); extern unsigned int vdso_enabled; extern void __kernel_vsyscall; diff --git a/arch/sh/include/asm/ftrace.h b/arch/sh/include/asm/ftrace.h index 3aed362c9463a6ccb492f6ef20ae4bb14ce27a75..8fea7d8c8258946038bbc3a10cd25b8fa8675ab9 100644 --- a/arch/sh/include/asm/ftrace.h +++ b/arch/sh/include/asm/ftrace.h @@ -1,8 +1,34 @@ #ifndef __ASM_SH_FTRACE_H #define __ASM_SH_FTRACE_H +#ifdef CONFIG_FUNCTION_TRACER + +#define MCOUNT_INSN_SIZE 4 /* sizeof mcount call */ + #ifndef __ASSEMBLY__ extern void mcount(void); -#endif + +#define MCOUNT_ADDR ((long)(mcount)) + +#ifdef CONFIG_DYNAMIC_FTRACE +#define CALLER_ADDR ((long)(ftrace_caller)) +#define STUB_ADDR ((long)(ftrace_stub)) + +#define MCOUNT_INSN_OFFSET ((STUB_ADDR - CALLER_ADDR) >> 1) + +struct dyn_arch_ftrace { + /* No extra data needed on sh */ +}; + +#endif /* CONFIG_DYNAMIC_FTRACE */ + +static inline unsigned long ftrace_call_adjust(unsigned long addr) +{ + /* 'addr' is the memory table address. */ + return addr; +} + +#endif /* __ASSEMBLY__ */ +#endif /* CONFIG_FUNCTION_TRACER */ #endif /* __ASM_SH_FTRACE_H */ diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h index 65eaae34e753035209455a1916dc68cc4e7b22d6..61f6dae40534831195c12972091f859ad2d14214 100644 --- a/arch/sh/include/asm/io.h +++ b/arch/sh/include/asm/io.h @@ -260,6 +260,10 @@ __ioremap_mode(unsigned long offset, unsigned long size, unsigned long flags) return (void __iomem *)P2SEGADDR(offset); } + + /* P4 above the store queues are always mapped. */ + if (unlikely(offset >= P3_ADDR_MAX)) + return (void __iomem *)P4SEGADDR(offset); #endif return __ioremap(offset, size, flags); diff --git a/arch/sh/include/asm/kgdb.h b/arch/sh/include/asm/kgdb.h index 24e42078f36fa80e780cebd92204bacb62ab3e5e..72704ed725e550586b730e843a1a47b5c433c922 100644 --- a/arch/sh/include/asm/kgdb.h +++ b/arch/sh/include/asm/kgdb.h @@ -1,21 +1,7 @@ -/* - * May be copied or modified under the terms of the GNU General Public - * License. See linux/COPYING for more information. - * - * Based on original code by Glenn Engel, Jim Kingdon, - * David Grothe , Tigran Aivazian, and - * Amit S. Kale - * - * Super-H port based on sh-stub.c (Ben Lee and Steve Chamberlain) by - * Henry Bell - * - * Header file for low-level support for remote debug using GDB. - * - */ - -#ifndef __KGDB_H -#define __KGDB_H +#ifndef __ASM_SH_KGDB_H +#define __ASM_SH_KGDB_H +#include #include /* Same as pt_regs but has vbr in place of syscall_nr */ @@ -30,40 +16,26 @@ struct kgdb_regs { unsigned long vbr; }; -/* State info */ -extern char kgdb_in_gdb_mode; -extern int kgdb_nofault; /* Ignore bus errors (in gdb mem access) */ -extern char in_nmi; /* Debounce flag to prevent NMI reentry*/ +enum regnames { + GDB_R0, GDB_R1, GDB_R2, GDB_R3, GDB_R4, GDB_R5, GDB_R6, GDB_R7, + GDB_R8, GDB_R9, GDB_R10, GDB_R11, GDB_R12, GDB_R13, GDB_R14, GDB_R15, -/* SCI */ -extern int kgdb_portnum; -extern int kgdb_baud; -extern char kgdb_parity; -extern char kgdb_bits; + GDB_PC, GDB_PR, GDB_SR, GDB_GBR, GDB_MACH, GDB_MACL, GDB_VBR, +}; -/* Init and interface stuff */ -extern int kgdb_init(void); -extern int (*kgdb_getchar)(void); -extern void (*kgdb_putchar)(int); +#define NUMREGBYTES ((GDB_VBR + 1) * 4) -/* Trap functions */ -typedef void (kgdb_debug_hook_t)(struct pt_regs *regs); -typedef void (kgdb_bus_error_hook_t)(void); -extern kgdb_debug_hook_t *kgdb_debug_hook; -extern kgdb_bus_error_hook_t *kgdb_bus_err_hook; +static inline void arch_kgdb_breakpoint(void) +{ + __asm__ __volatile__ ("trapa #0x3c\n"); +} -/* Console */ -struct console; -void kgdb_console_write(struct console *co, const char *s, unsigned count); -extern int kgdb_console_setup(struct console *, char *); +/* State info */ +extern char in_nmi; /* Debounce flag to prevent NMI reentry*/ -/* Prototypes for jmp fns */ -#define _JBLEN 9 -typedef int jmp_buf[_JBLEN]; -extern void longjmp(jmp_buf __jmpb, int __retval); -extern int setjmp(jmp_buf __jmpb); +#define BUFMAX 2048 -/* Forced breakpoint */ -#define breakpoint() __asm__ __volatile__("trapa #0x3c") +#define CACHE_FLUSH_IS_SAFE 1 +#define BREAK_INSTR_SIZE 2 -#endif +#endif /* __ASM_SH_KGDB_H */ diff --git a/arch/sh/include/asm/machvec.h b/arch/sh/include/asm/machvec.h index f1bae02ef7b6398c8620a83427a51ef368c0df1d..64b1c16a0f03559dc53695ccb572c8ca9643de57 100644 --- a/arch/sh/include/asm/machvec.h +++ b/arch/sh/include/asm/machvec.h @@ -14,8 +14,6 @@ #include #include -struct device; - struct sh_machine_vector { void (*mv_setup)(char **cmdline_p); const char *mv_name; @@ -45,9 +43,6 @@ struct sh_machine_vector { int (*mv_irq_demux)(int irq); void (*mv_init_irq)(void); - void (*mv_init_pci)(void); - - void (*mv_heartbeat)(void); void __iomem *(*mv_ioport_map)(unsigned long port, unsigned int size); void (*mv_ioport_unmap)(void __iomem *); diff --git a/arch/sh/include/asm/mmu_context.h b/arch/sh/include/asm/mmu_context.h index 04c0c9733ad62b19bc1323bf002b655eea47590c..5d9157bd474df7b6988f512e85389b1b31da0d5a 100644 --- a/arch/sh/include/asm/mmu_context.h +++ b/arch/sh/include/asm/mmu_context.h @@ -22,7 +22,7 @@ #define MMU_CONTEXT_ASID_MASK 0x000000ff #define MMU_CONTEXT_VERSION_MASK 0xffffff00 #define MMU_CONTEXT_FIRST_VERSION 0x00000100 -#define NO_CONTEXT 0 +#define NO_CONTEXT 0UL /* ASID is 8-bit value, so it can't be 0x100 */ #define MMU_NO_ASID 0x100 @@ -130,7 +130,7 @@ static inline void switch_mm(struct mm_struct *prev, #define destroy_context(mm) do { } while (0) #define set_asid(asid) do { } while (0) #define get_asid() (0) -#define cpu_asid(cpu, mm) ({ (void)cpu; 0; }) +#define cpu_asid(cpu, mm) ({ (void)cpu; NO_CONTEXT; }) #define switch_and_save_asid(asid) (0) #define set_TTB(pgd) do { } while (0) #define get_TTB() (0) diff --git a/arch/sh/include/asm/mutex-llsc.h b/arch/sh/include/asm/mutex-llsc.h new file mode 100644 index 0000000000000000000000000000000000000000..ee839ee58ac84894515d328b78f1bb73dc43119f --- /dev/null +++ b/arch/sh/include/asm/mutex-llsc.h @@ -0,0 +1,112 @@ +/* + * arch/sh/include/asm/mutex-llsc.h + * + * SH-4A optimized mutex locking primitives + * + * Please look into asm-generic/mutex-xchg.h for a formal definition. + */ +#ifndef __ASM_SH_MUTEX_LLSC_H +#define __ASM_SH_MUTEX_LLSC_H + +/* + * Attempting to lock a mutex on SH4A is done like in ARMv6+ architecure. + * with a bastardized atomic decrement (it is not a reliable atomic decrement + * but it satisfies the defined semantics for our purpose, while being + * smaller and faster than a real atomic decrement or atomic swap. + * The idea is to attempt decrementing the lock value only once. If once + * decremented it isn't zero, or if its store-back fails due to a dispute + * on the exclusive store, we simply bail out immediately through the slow + * path where the lock will be reattempted until it succeeds. + */ +static inline void +__mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *)) +{ + int __ex_flag, __res; + + __asm__ __volatile__ ( + "movli.l @%2, %0 \n" + "add #-1, %0 \n" + "movco.l %0, @%2 \n" + "movt %1 \n" + : "=&z" (__res), "=&r" (__ex_flag) + : "r" (&(count)->counter) + : "t"); + + __res |= !__ex_flag; + if (unlikely(__res != 0)) + fail_fn(count); +} + +static inline int +__mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *)) +{ + int __ex_flag, __res; + + __asm__ __volatile__ ( + "movli.l @%2, %0 \n" + "add #-1, %0 \n" + "movco.l %0, @%2 \n" + "movt %1 \n" + : "=&z" (__res), "=&r" (__ex_flag) + : "r" (&(count)->counter) + : "t"); + + __res |= !__ex_flag; + if (unlikely(__res != 0)) + __res = fail_fn(count); + + return __res; +} + +static inline void +__mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *)) +{ + int __ex_flag, __res; + + __asm__ __volatile__ ( + "movli.l @%2, %0 \n\t" + "add #1, %0 \n\t" + "movco.l %0, @%2 \n\t" + "movt %1 \n\t" + : "=&z" (__res), "=&r" (__ex_flag) + : "r" (&(count)->counter) + : "t"); + + __res |= !__ex_flag; + if (unlikely(__res <= 0)) + fail_fn(count); +} + +/* + * If the unlock was done on a contended lock, or if the unlock simply fails + * then the mutex remains locked. + */ +#define __mutex_slowpath_needs_to_unlock() 1 + +/* + * For __mutex_fastpath_trylock we do an atomic decrement and check the + * result and put it in the __res variable. + */ +static inline int +__mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *)) +{ + int __res, __orig; + + __asm__ __volatile__ ( + "1: movli.l @%2, %0 \n\t" + "dt %0 \n\t" + "movco.l %0,@%2 \n\t" + "bf 1b \n\t" + "cmp/eq #0,%0 \n\t" + "bt 2f \n\t" + "mov #0, %1 \n\t" + "bf 3f \n\t" + "2: mov #1, %1 \n\t" + "3: " + : "=&z" (__orig), "=&r" (__res) + : "r" (&count->counter) + : "t"); + + return __res; +} +#endif /* __ASM_SH_MUTEX_LLSC_H */ diff --git a/arch/sh/include/asm/mutex.h b/arch/sh/include/asm/mutex.h index 458c1f7fbc1808d48982aa0c5fe89bfe3df2098c..d8e37716a4a03bc4d132fee396666aa4b4b0ddc2 100644 --- a/arch/sh/include/asm/mutex.h +++ b/arch/sh/include/asm/mutex.h @@ -5,5 +5,8 @@ * implementation in place, or pick the atomic_xchg() based generic * implementation. (see asm-generic/mutex-xchg.h for details) */ - +#if defined(CONFIG_CPU_SH4A) +#include +#else #include +#endif diff --git a/arch/sh/include/asm/pm.h b/arch/sh/include/asm/pm.h deleted file mode 100644 index 56fdbd6b1c94fc8ea2b2788f42c00449ad1a8418..0000000000000000000000000000000000000000 --- a/arch/sh/include/asm/pm.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright 2006 (c) Andriy Skulysh - * - */ -#ifndef __ASM_SH_PM_H -#define __ASM_SH_PM_H - -extern u8 wakeup_start; -extern u8 wakeup_end; - -void pm_enter(void); - -#endif diff --git a/arch/sh/include/asm/processor.h b/arch/sh/include/asm/processor.h index 693364a20ad72e331a18ccdf391c01ac1b1a0a2b..1ef4b24d7619551306f0b0fd5a84f989149fb535 100644 --- a/arch/sh/include/asm/processor.h +++ b/arch/sh/include/asm/processor.h @@ -18,7 +18,7 @@ enum cpu_type { CPU_SH7619, /* SH-2A types */ - CPU_SH7203, CPU_SH7206, CPU_SH7263, CPU_MXG, + CPU_SH7201, CPU_SH7203, CPU_SH7206, CPU_SH7263, CPU_MXG, /* SH-3 types */ CPU_SH7705, CPU_SH7706, CPU_SH7707, @@ -82,6 +82,9 @@ extern struct sh_cpuinfo cpu_data[]; #define current_cpu_data cpu_data[smp_processor_id()] #define raw_current_cpu_data cpu_data[raw_smp_processor_id()] +#define cpu_sleep() __asm__ __volatile__ ("sleep" : : : "memory") +#define cpu_relax() barrier() + /* Forward decl */ struct seq_operations; diff --git a/arch/sh/include/asm/processor_32.h b/arch/sh/include/asm/processor_32.h index a46a0207e977933469438928dee0dd0336571ab5..d79063c5eb9c1ebb531425dda142c031115cfca2 100644 --- a/arch/sh/include/asm/processor_32.h +++ b/arch/sh/include/asm/processor_32.h @@ -175,6 +175,15 @@ static __inline__ void enable_fpu(void) void show_trace(struct task_struct *tsk, unsigned long *sp, struct pt_regs *regs); + +#ifdef CONFIG_DUMP_CODE +void show_code(struct pt_regs *regs); +#else +static inline void show_code(struct pt_regs *regs) +{ +} +#endif + extern unsigned long get_wchan(struct task_struct *p); #define KSTK_EIP(tsk) (task_pt_regs(tsk)->pc) @@ -182,9 +191,6 @@ extern unsigned long get_wchan(struct task_struct *p); #define user_stack_pointer(regs) ((regs)->regs[15]) -#define cpu_sleep() __asm__ __volatile__ ("sleep" : : : "memory") -#define cpu_relax() barrier() - #if defined(CONFIG_CPU_SH2A) || defined(CONFIG_CPU_SH3) || \ defined(CONFIG_CPU_SH4) #define PREFETCH_STRIDE L1_CACHE_BYTES diff --git a/arch/sh/include/asm/processor_64.h b/arch/sh/include/asm/processor_64.h index b0b4824dfc4ce9d081de5e250081681685e84252..803177fcf0868b1e5f3a84462a6d3fe514f101c8 100644 --- a/arch/sh/include/asm/processor_64.h +++ b/arch/sh/include/asm/processor_64.h @@ -226,9 +226,7 @@ extern unsigned long get_wchan(struct task_struct *p); #define KSTK_EIP(tsk) ((tsk)->thread.pc) #define KSTK_ESP(tsk) ((tsk)->thread.sp) -#define user_stack_pointer(regs) ((regs)->sp) - -#define cpu_relax() barrier() +#define user_stack_pointer(regs) ((regs)->regs[15]) #endif /* __ASSEMBLY__ */ #endif /* __ASM_SH_PROCESSOR_64_H */ diff --git a/arch/sh/include/asm/ptrace.h b/arch/sh/include/asm/ptrace.h index 3ad18e91bca61cfab3ac9451c0bbfa394ddc5891..12912ab80c15be73c0d21b7e76df1e166183e09c 100644 --- a/arch/sh/include/asm/ptrace.h +++ b/arch/sh/include/asm/ptrace.h @@ -86,6 +86,7 @@ struct pt_dspregs { unsigned long re; unsigned long mod; }; +#endif #define PTRACE_GETREGS 12 /* General registers */ #define PTRACE_SETREGS 13 @@ -100,7 +101,6 @@ struct pt_dspregs { #define PTRACE_GETDSPREGS 55 /* DSP registers */ #define PTRACE_SETDSPREGS 56 -#endif #ifdef __KERNEL__ #include diff --git a/arch/sh/include/asm/sh_bios.h b/arch/sh/include/asm/sh_bios.h index 0ca261956e3de0d8117db724c6c5893003ab41ab..d9c96d7cf6c77c77ddeb744a21ea2d7b822c25ca 100644 --- a/arch/sh/include/asm/sh_bios.h +++ b/arch/sh/include/asm/sh_bios.h @@ -10,7 +10,6 @@ extern void sh_bios_console_write(const char *buf, unsigned int len); extern void sh_bios_char_out(char ch); -extern int sh_bios_in_gdb_mode(void); extern void sh_bios_gdb_detach(void); extern void sh_bios_get_node_addr(unsigned char *node_addr); diff --git a/arch/sh/include/asm/string_64.h b/arch/sh/include/asm/string_64.h index aa1fef229c7847c652edb5ffd0f6af1ac3a1e709..742007172624199800510a72c37cb064c72a5c2e 100644 --- a/arch/sh/include/asm/string_64.h +++ b/arch/sh/include/asm/string_64.h @@ -1,17 +1,20 @@ #ifndef __ASM_SH_STRING_64_H #define __ASM_SH_STRING_64_H -/* - * include/asm-sh/string_64.h - * - * Copyright (C) 2000, 2001 Paolo Alberelli - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ +#ifdef __KERNEL__ + +#define __HAVE_ARCH_MEMSET +extern void *memset(void *__s, int __c, size_t __count); #define __HAVE_ARCH_MEMCPY extern void *memcpy(void *dest, const void *src, size_t count); +#define __HAVE_ARCH_STRLEN +extern size_t strlen(const char *); + +#define __HAVE_ARCH_STRCPY +extern char *strcpy(char *__dest, const char *__src); + +#endif /* __KERNEL__ */ + #endif /* __ASM_SH_STRING_64_H */ diff --git a/arch/sh/include/asm/syscall_32.h b/arch/sh/include/asm/syscall_32.h index 54773f26cd4480daecfc6161ae511069ab0537b9..05a868a71ef5a7502736fd81586c540acc80ffea 100644 --- a/arch/sh/include/asm/syscall_32.h +++ b/arch/sh/include/asm/syscall_32.h @@ -5,7 +5,7 @@ #include #include -/* The system call number is given by the user in %g1 */ +/* The system call number is given by the user in R3 */ static inline long syscall_get_nr(struct task_struct *task, struct pt_regs *regs) { diff --git a/arch/sh/include/asm/syscall_64.h b/arch/sh/include/asm/syscall_64.h index bcaaa8ca4d700c29425188e58cbf6eea7137def3..e1143b9784d62d9247760efe5738b8ba4c642d92 100644 --- a/arch/sh/include/asm/syscall_64.h +++ b/arch/sh/include/asm/syscall_64.h @@ -1,6 +1,80 @@ #ifndef __ASM_SH_SYSCALL_64_H #define __ASM_SH_SYSCALL_64_H -#include +#include +#include +#include + +/* The system call number is given by the user in R9 */ +static inline long syscall_get_nr(struct task_struct *task, + struct pt_regs *regs) +{ + return (regs->syscall_nr >= 0) ? regs->regs[9] : -1L; +} + +static inline void syscall_rollback(struct task_struct *task, + struct pt_regs *regs) +{ + /* + * XXX: This needs some thought. On SH we don't + * save away the original R9 value anywhere. + */ +} + +static inline bool syscall_has_error(struct pt_regs *regs) +{ + return (regs->sr & 0x1) ? true : false; +} +static inline void syscall_set_error(struct pt_regs *regs) +{ + regs->sr |= 0x1; +} +static inline void syscall_clear_error(struct pt_regs *regs) +{ + regs->sr &= ~0x1; +} + +static inline long syscall_get_error(struct task_struct *task, + struct pt_regs *regs) +{ + return syscall_has_error(regs) ? regs->regs[9] : 0; +} + +static inline long syscall_get_return_value(struct task_struct *task, + struct pt_regs *regs) +{ + return regs->regs[9]; +} + +static inline void syscall_set_return_value(struct task_struct *task, + struct pt_regs *regs, + int error, long val) +{ + if (error) { + syscall_set_error(regs); + regs->regs[9] = -error; + } else { + syscall_clear_error(regs); + regs->regs[9] = val; + } +} + +static inline void syscall_get_arguments(struct task_struct *task, + struct pt_regs *regs, + unsigned int i, unsigned int n, + unsigned long *args) +{ + BUG_ON(i + n > 6); + memcpy(args, ®s->regs[2 + i], n * sizeof(args[0])); +} + +static inline void syscall_set_arguments(struct task_struct *task, + struct pt_regs *regs, + unsigned int i, unsigned int n, + const unsigned long *args) +{ + BUG_ON(i + n > 6); + memcpy(®s->regs[2 + i], args, n * sizeof(args[0])); +} #endif /* __ASM_SH_SYSCALL_64_H */ diff --git a/arch/sh/include/asm/system.h b/arch/sh/include/asm/system.h index 6160fe445161e12071f6daeabbca709350563da2..c9ec6af8e7456a387063bae8eecdbab52342f401 100644 --- a/arch/sh/include/asm/system.h +++ b/arch/sh/include/asm/system.h @@ -175,6 +175,8 @@ asmlinkage void name##_trap_handler(unsigned int vec, struct pt_regs *regs) BUILD_TRAP_HANDLER(address_error); BUILD_TRAP_HANDLER(debug); BUILD_TRAP_HANDLER(bug); +BUILD_TRAP_HANDLER(breakpoint); +BUILD_TRAP_HANDLER(singlestep); BUILD_TRAP_HANDLER(fpu_error); BUILD_TRAP_HANDLER(fpu_state_restore); diff --git a/arch/sh/include/asm/unaligned-sh4a.h b/arch/sh/include/asm/unaligned-sh4a.h new file mode 100644 index 0000000000000000000000000000000000000000..d8f89770275bca443434336a71cbd92dfc94757c --- /dev/null +++ b/arch/sh/include/asm/unaligned-sh4a.h @@ -0,0 +1,258 @@ +#ifndef __ASM_SH_UNALIGNED_SH4A_H +#define __ASM_SH_UNALIGNED_SH4A_H + +/* + * SH-4A has support for unaligned 32-bit loads, and 32-bit loads only. + * Support for 16 and 64-bit accesses are done through shifting and + * masking relative to the endianness. Unaligned stores are not supported + * by the instruction encoding, so these continue to use the packed + * struct. + * + * The same note as with the movli.l/movco.l pair applies here, as long + * as the load is gauranteed to be inlined, nothing else will hook in to + * r0 and we get the return value for free. + * + * NOTE: Due to the fact we require r0 encoding, care should be taken to + * avoid mixing these heavily with other r0 consumers, such as the atomic + * ops. Failure to adhere to this can result in the compiler running out + * of spill registers and blowing up when building at low optimization + * levels. See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34777. + */ +#include +#include + +static __always_inline u32 __get_unaligned_cpu32(const u8 *p) +{ + unsigned long unaligned; + + __asm__ __volatile__ ( + "movua.l @%1, %0\n\t" + : "=z" (unaligned) + : "r" (p) + ); + + return unaligned; +} + +struct __una_u16 { u16 x __attribute__((packed)); }; +struct __una_u32 { u32 x __attribute__((packed)); }; +struct __una_u64 { u64 x __attribute__((packed)); }; + +static inline u16 __get_unaligned_cpu16(const u8 *p) +{ +#ifdef __LITTLE_ENDIAN + return __get_unaligned_cpu32(p) & 0xffff; +#else + return __get_unaligned_cpu32(p) >> 16; +#endif +} + +/* + * Even though movua.l supports auto-increment on the read side, it can + * only store to r0 due to instruction encoding constraints, so just let + * the compiler sort it out on its own. + */ +static inline u64 __get_unaligned_cpu64(const u8 *p) +{ +#ifdef __LITTLE_ENDIAN + return (u64)__get_unaligned_cpu32(p + 4) << 32 | + __get_unaligned_cpu32(p); +#else + return (u64)__get_unaligned_cpu32(p) << 32 | + __get_unaligned_cpu32(p + 4); +#endif +} + +static inline u16 get_unaligned_le16(const void *p) +{ + return le16_to_cpu(__get_unaligned_cpu16(p)); +} + +static inline u32 get_unaligned_le32(const void *p) +{ + return le32_to_cpu(__get_unaligned_cpu32(p)); +} + +static inline u64 get_unaligned_le64(const void *p) +{ + return le64_to_cpu(__get_unaligned_cpu64(p)); +} + +static inline u16 get_unaligned_be16(const void *p) +{ + return be16_to_cpu(__get_unaligned_cpu16(p)); +} + +static inline u32 get_unaligned_be32(const void *p) +{ + return be32_to_cpu(__get_unaligned_cpu32(p)); +} + +static inline u64 get_unaligned_be64(const void *p) +{ + return be64_to_cpu(__get_unaligned_cpu64(p)); +} + +static inline void __put_le16_noalign(u8 *p, u16 val) +{ + *p++ = val; + *p++ = val >> 8; +} + +static inline void __put_le32_noalign(u8 *p, u32 val) +{ + __put_le16_noalign(p, val); + __put_le16_noalign(p + 2, val >> 16); +} + +static inline void __put_le64_noalign(u8 *p, u64 val) +{ + __put_le32_noalign(p, val); + __put_le32_noalign(p + 4, val >> 32); +} + +static inline void __put_be16_noalign(u8 *p, u16 val) +{ + *p++ = val >> 8; + *p++ = val; +} + +static inline void __put_be32_noalign(u8 *p, u32 val) +{ + __put_be16_noalign(p, val >> 16); + __put_be16_noalign(p + 2, val); +} + +static inline void __put_be64_noalign(u8 *p, u64 val) +{ + __put_be32_noalign(p, val >> 32); + __put_be32_noalign(p + 4, val); +} + +static inline void put_unaligned_le16(u16 val, void *p) +{ +#ifdef __LITTLE_ENDIAN + ((struct __una_u16 *)p)->x = val; +#else + __put_le16_noalign(p, val); +#endif +} + +static inline void put_unaligned_le32(u32 val, void *p) +{ +#ifdef __LITTLE_ENDIAN + ((struct __una_u32 *)p)->x = val; +#else + __put_le32_noalign(p, val); +#endif +} + +static inline void put_unaligned_le64(u64 val, void *p) +{ +#ifdef __LITTLE_ENDIAN + ((struct __una_u64 *)p)->x = val; +#else + __put_le64_noalign(p, val); +#endif +} + +static inline void put_unaligned_be16(u16 val, void *p) +{ +#ifdef __BIG_ENDIAN + ((struct __una_u16 *)p)->x = val; +#else + __put_be16_noalign(p, val); +#endif +} + +static inline void put_unaligned_be32(u32 val, void *p) +{ +#ifdef __BIG_ENDIAN + ((struct __una_u32 *)p)->x = val; +#else + __put_be32_noalign(p, val); +#endif +} + +static inline void put_unaligned_be64(u64 val, void *p) +{ +#ifdef __BIG_ENDIAN + ((struct __una_u64 *)p)->x = val; +#else + __put_be64_noalign(p, val); +#endif +} + +/* + * Cause a link-time error if we try an unaligned access other than + * 1,2,4 or 8 bytes long + */ +extern void __bad_unaligned_access_size(void); + +#define __get_unaligned_le(ptr) ((__force typeof(*(ptr)))({ \ + __builtin_choose_expr(sizeof(*(ptr)) == 1, *(ptr), \ + __builtin_choose_expr(sizeof(*(ptr)) == 2, get_unaligned_le16((ptr)), \ + __builtin_choose_expr(sizeof(*(ptr)) == 4, get_unaligned_le32((ptr)), \ + __builtin_choose_expr(sizeof(*(ptr)) == 8, get_unaligned_le64((ptr)), \ + __bad_unaligned_access_size())))); \ + })) + +#define __get_unaligned_be(ptr) ((__force typeof(*(ptr)))({ \ + __builtin_choose_expr(sizeof(*(ptr)) == 1, *(ptr), \ + __builtin_choose_expr(sizeof(*(ptr)) == 2, get_unaligned_be16((ptr)), \ + __builtin_choose_expr(sizeof(*(ptr)) == 4, get_unaligned_be32((ptr)), \ + __builtin_choose_expr(sizeof(*(ptr)) == 8, get_unaligned_be64((ptr)), \ + __bad_unaligned_access_size())))); \ + })) + +#define __put_unaligned_le(val, ptr) ({ \ + void *__gu_p = (ptr); \ + switch (sizeof(*(ptr))) { \ + case 1: \ + *(u8 *)__gu_p = (__force u8)(val); \ + break; \ + case 2: \ + put_unaligned_le16((__force u16)(val), __gu_p); \ + break; \ + case 4: \ + put_unaligned_le32((__force u32)(val), __gu_p); \ + break; \ + case 8: \ + put_unaligned_le64((__force u64)(val), __gu_p); \ + break; \ + default: \ + __bad_unaligned_access_size(); \ + break; \ + } \ + (void)0; }) + +#define __put_unaligned_be(val, ptr) ({ \ + void *__gu_p = (ptr); \ + switch (sizeof(*(ptr))) { \ + case 1: \ + *(u8 *)__gu_p = (__force u8)(val); \ + break; \ + case 2: \ + put_unaligned_be16((__force u16)(val), __gu_p); \ + break; \ + case 4: \ + put_unaligned_be32((__force u32)(val), __gu_p); \ + break; \ + case 8: \ + put_unaligned_be64((__force u64)(val), __gu_p); \ + break; \ + default: \ + __bad_unaligned_access_size(); \ + break; \ + } \ + (void)0; }) + +#ifdef __LITTLE_ENDIAN +# define get_unaligned __get_unaligned_le +# define put_unaligned __put_unaligned_le +#else +# define get_unaligned __get_unaligned_be +# define put_unaligned __put_unaligned_be +#endif + +#endif /* __ASM_SH_UNALIGNED_SH4A_H */ diff --git a/arch/sh/include/asm/unaligned.h b/arch/sh/include/asm/unaligned.h index c1641a01d50ff738d9f4bacd628b59155f400cce..8c0ad5e4487aff72faceeff9d36fe915d96f01dc 100644 --- a/arch/sh/include/asm/unaligned.h +++ b/arch/sh/include/asm/unaligned.h @@ -1,7 +1,11 @@ #ifndef _ASM_SH_UNALIGNED_H #define _ASM_SH_UNALIGNED_H -/* SH can't handle unaligned accesses. */ +#ifdef CONFIG_CPU_SH4A +/* SH-4A can handle unaligned loads in a relatively neutered fashion. */ +#include +#else +/* Otherwise, SH can't handle unaligned accesses. */ #ifdef __LITTLE_ENDIAN__ # include # include @@ -15,5 +19,6 @@ # define get_unaligned __get_unaligned_be # define put_unaligned __put_unaligned_be #endif +#endif #endif /* _ASM_SH_UNALIGNED_H */ diff --git a/arch/sh/include/cpu-sh3/cpu/gpio.h b/arch/sh/include/cpu-sh3/cpu/gpio.h index 4e53eb314b8fc9b9b4c6584fda2f290c9353dc56..9a22b882f3dc27392beaf0983ca32befccb3443d 100644 --- a/arch/sh/include/cpu-sh3/cpu/gpio.h +++ b/arch/sh/include/cpu-sh3/cpu/gpio.h @@ -62,6 +62,20 @@ #define PORT_PSELC 0xA4050128UL #define PORT_PSELD 0xA405012AUL +#elif defined(CONFIG_CPU_SUBTYPE_SH7709) + +/* Control registers */ +#define PORT_PACR 0xa4000100UL +#define PORT_PBCR 0xa4000102UL +#define PORT_PCCR 0xa4000104UL +#define PORT_PFCR 0xa400010aUL + +/* Data registers */ +#define PORT_PADR 0xa4000120UL +#define PORT_PBDR 0xa4000122UL +#define PORT_PCDR 0xa4000124UL +#define PORT_PFDR 0xa400012aUL + #endif #endif diff --git a/arch/sh/include/mach-common/mach/edosk7705.h b/arch/sh/include/mach-common/mach/edosk7705.h index 5bdc9d9be3de9cacad4a972338157b890f8fb365..efc43b323466b433610a93f50efbc1d52f0340fe 100644 --- a/arch/sh/include/mach-common/mach/edosk7705.h +++ b/arch/sh/include/mach-common/mach/edosk7705.h @@ -1,30 +1,7 @@ -/* - * include/asm-sh/edosk7705.h - * - * Modified version of io_se.h for the EDOSK7705 specific functions. - * - * May be copied or modified under the terms of the GNU General Public - * License. See linux/COPYING for more information. - * - * IO functions for an Hitachi EDOSK7705 development board - */ - -#ifndef __ASM_SH_EDOSK7705_IO_H -#define __ASM_SH_EDOSK7705_IO_H +#ifndef __ASM_SH_EDOSK7705_H +#define __ASM_SH_EDOSK7705_H +#define __IO_PREFIX sh_edosk7705 #include -extern unsigned char sh_edosk7705_inb(unsigned long port); -extern unsigned int sh_edosk7705_inl(unsigned long port); - -extern void sh_edosk7705_outb(unsigned char value, unsigned long port); -extern void sh_edosk7705_outl(unsigned int value, unsigned long port); - -extern void sh_edosk7705_insb(unsigned long port, void *addr, unsigned long count); -extern void sh_edosk7705_insl(unsigned long port, void *addr, unsigned long count); -extern void sh_edosk7705_outsb(unsigned long port, const void *addr, unsigned long count); -extern void sh_edosk7705_outsl(unsigned long port, const void *addr, unsigned long count); - -extern unsigned long sh_edosk7705_isa_port2addr(unsigned long offset); - -#endif /* __ASM_SH_EDOSK7705_IO_H */ +#endif /* __ASM_SH_EDOSK7705_H */ diff --git a/arch/sh/include/mach-se/mach/mrshpc.h b/arch/sh/include/mach-se/mach/mrshpc.h new file mode 100644 index 0000000000000000000000000000000000000000..56287ee8563a33d687bdd1930dbf85f3aff99bcc --- /dev/null +++ b/arch/sh/include/mach-se/mach/mrshpc.h @@ -0,0 +1,52 @@ +#ifndef __MACH_SE_MRSHPC_H +#define __MACH_SE_MRSHPC_H + +#include + +static inline void __init mrshpc_setup_windows(void) +{ + if ((__raw_readw(MRSHPC_CSR) & 0x000c) != 0) + return; /* Not detected */ + + if ((__raw_readw(MRSHPC_CSR) & 0x0080) == 0) { + __raw_writew(0x0674, MRSHPC_CPWCR); /* Card Vcc is 3.3v? */ + } else { + __raw_writew(0x0678, MRSHPC_CPWCR); /* Card Vcc is 5V */ + } + + /* + * PC-Card window open + * flag == COMMON/ATTRIBUTE/IO + */ + /* common window open */ + __raw_writew(0x8a84, MRSHPC_MW0CR1); + if((__raw_readw(MRSHPC_CSR) & 0x4000) != 0) + /* common mode & bus width 16bit SWAP = 1*/ + __raw_writew(0x0b00, MRSHPC_MW0CR2); + else + /* common mode & bus width 16bit SWAP = 0*/ + __raw_writew(0x0300, MRSHPC_MW0CR2); + + /* attribute window open */ + __raw_writew(0x8a85, MRSHPC_MW1CR1); + if ((__raw_readw(MRSHPC_CSR) & 0x4000) != 0) + /* attribute mode & bus width 16bit SWAP = 1*/ + __raw_writew(0x0a00, MRSHPC_MW1CR2); + else + /* attribute mode & bus width 16bit SWAP = 0*/ + __raw_writew(0x0200, MRSHPC_MW1CR2); + + /* I/O window open */ + __raw_writew(0x8a86, MRSHPC_IOWCR1); + __raw_writew(0x0008, MRSHPC_CDCR); /* I/O card mode */ + if ((__raw_readw(MRSHPC_CSR) & 0x4000) != 0) + __raw_writew(0x0a00, MRSHPC_IOWCR2); /* bus width 16bit SWAP = 1*/ + else + __raw_writew(0x0200, MRSHPC_IOWCR2); /* bus width 16bit SWAP = 0*/ + + __raw_writew(0x2000, MRSHPC_ICR); + __raw_writeb(0x00, PA_MRSHPC_MW2 + 0x206); + __raw_writeb(0x42, PA_MRSHPC_MW2 + 0x200); +} + +#endif /* __MACH_SE_MRSHPC_H */ diff --git a/arch/sh/include/mach-se/mach/se.h b/arch/sh/include/mach-se/mach/se.h index eb23000e1bbee1526410891891423fa3919fa259..14be91c5a2f0f7f1c062d6afbe8aac38cf1ea953 100644 --- a/arch/sh/include/mach-se/mach/se.h +++ b/arch/sh/include/mach-se/mach/se.h @@ -68,6 +68,24 @@ #define BCR_ILCRF (PA_BCR + 10) #define BCR_ILCRG (PA_BCR + 12) +#if defined(CONFIG_CPU_SUBTYPE_SH7709) +#define INTC_IRR0 0xa4000004UL +#define INTC_IRR1 0xa4000006UL +#define INTC_IRR2 0xa4000008UL + +#define INTC_ICR0 0xfffffee0UL +#define INTC_ICR1 0xa4000010UL +#define INTC_ICR2 0xa4000012UL +#define INTC_INTER 0xa4000014UL + +#define INTC_IPRC 0xa4000016UL +#define INTC_IPRD 0xa4000018UL +#define INTC_IPRE 0xa400001aUL + +#define IRQ0_IRQ 32 +#define IRQ1_IRQ 33 +#endif + #if defined(CONFIG_CPU_SUBTYPE_SH7705) #define IRQ_STNIC 12 #define IRQ_CFCARD 14 diff --git a/arch/sh/include/mach-se/mach/se7343.h b/arch/sh/include/mach-se/mach/se7343.h index 98458460e632e58dec0f98f79bbf9d0e8df7fab8..749914b400fbe7a187840e744b31e384e20cc324 100644 --- a/arch/sh/include/mach-se/mach/se7343.h +++ b/arch/sh/include/mach-se/mach/se7343.h @@ -118,9 +118,6 @@ #define FPGA_IN 0xb1400000 #define FPGA_OUT 0xb1400002 -#define __IO_PREFIX sh7343se -#include - #define IRQ0_IRQ 32 #define IRQ1_IRQ 33 #define IRQ4_IRQ 36 @@ -132,8 +129,10 @@ #define SE7343_FPGA_IRQ_MRSHPC3 3 #define SE7343_FPGA_IRQ_SMC 6 /* EXT_IRQ2 */ #define SE7343_FPGA_IRQ_USB 8 +#define SE7343_FPGA_IRQ_UARTA 10 +#define SE7343_FPGA_IRQ_UARTB 11 -#define SE7343_FPGA_IRQ_NR 11 +#define SE7343_FPGA_IRQ_NR 12 #define SE7343_FPGA_IRQ_BASE 120 #define MRSHPC_IRQ3 (SE7343_FPGA_IRQ_BASE + SE7343_FPGA_IRQ_MRSHPC3) @@ -142,6 +141,8 @@ #define MRSHPC_IRQ0 (SE7343_FPGA_IRQ_BASE + SE7343_FPGA_IRQ_MRSHPC0) #define SMC_IRQ (SE7343_FPGA_IRQ_BASE + SE7343_FPGA_IRQ_SMC) #define USB_IRQ (SE7343_FPGA_IRQ_BASE + SE7343_FPGA_IRQ_USB) +#define UARTA_IRQ (SE7343_FPGA_IRQ_BASE + SE7343_FPGA_IRQ_UARTA) +#define UARTB_IRQ (SE7343_FPGA_IRQ_BASE + SE7343_FPGA_IRQ_UARTB) /* arch/sh/boards/se/7343/irq.c */ void init_7343se_IRQ(void); diff --git a/arch/sh/kernel/Makefile_32 b/arch/sh/kernel/Makefile_32 index 48edfb145fb4f9acdd58ca8c48081420c11e198e..2e1b86e16ab54184d5d99a720e1b76e8c88adadb 100644 --- a/arch/sh/kernel/Makefile_32 +++ b/arch/sh/kernel/Makefile_32 @@ -4,25 +4,31 @@ extra-y := head_32.o init_task.o vmlinux.lds -obj-y := debugtraps.o io.o io_generic.o irq.o machvec.o process_32.o \ - ptrace_32.o setup.o signal_32.o sys_sh.o sys_sh32.o \ - syscalls_32.o time_32.o topology.o traps.o traps_32.o +ifdef CONFIG_FUNCTION_TRACER +# Do not profile debug and lowlevel utilities +CFLAGS_REMOVE_ftrace.o = -pg +endif + +obj-y := debugtraps.o idle.o io.o io_generic.o irq.o \ + machvec.o process_32.o ptrace_32.o setup.o signal_32.o \ + sys_sh.o sys_sh32.o syscalls_32.o time_32.o topology.o \ + traps.o traps_32.o obj-y += cpu/ timers/ obj-$(CONFIG_VSYSCALL) += vsyscall/ obj-$(CONFIG_SMP) += smp.o -obj-$(CONFIG_CF_ENABLER) += cf-enabler.o obj-$(CONFIG_SH_STANDARD_BIOS) += sh_bios.o -obj-$(CONFIG_SH_KGDB) += kgdb_stub.o kgdb_jmp.o +obj-$(CONFIG_KGDB) += kgdb.o obj-$(CONFIG_SH_CPU_FREQ) += cpufreq.o obj-$(CONFIG_MODULES) += sh_ksyms_32.o module.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o -obj-$(CONFIG_PM) += pm.o obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_IO_TRAPPED) += io_trapped.o obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_GENERIC_GPIO) += gpio.o +obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o +obj-$(CONFIG_DUMP_CODE) += disassemble.o EXTRA_CFLAGS += -Werror diff --git a/arch/sh/kernel/Makefile_64 b/arch/sh/kernel/Makefile_64 index c97660b2b48d11be65fcf440c80c841acd433bb6..fe425d7f6871be9d43a151723e584b3b438598a4 100644 --- a/arch/sh/kernel/Makefile_64 +++ b/arch/sh/kernel/Makefile_64 @@ -1,21 +1,18 @@ extra-y := head_64.o init_task.o vmlinux.lds -obj-y := debugtraps.o io.o io_generic.o irq.o machvec.o process_64.o \ +obj-y := debugtraps.o idle.o io.o io_generic.o irq.o machvec.o process_64.o \ ptrace_64.o setup.o signal_64.o sys_sh.o sys_sh64.o \ syscalls_64.o time_64.o topology.o traps.o traps_64.o obj-y += cpu/ timers/ obj-$(CONFIG_VSYSCALL) += vsyscall/ obj-$(CONFIG_SMP) += smp.o -obj-$(CONFIG_CF_ENABLER) += cf-enabler.o obj-$(CONFIG_SH_STANDARD_BIOS) += sh_bios.o -obj-$(CONFIG_SH_KGDB) += kgdb_stub.o kgdb_jmp.o obj-$(CONFIG_SH_CPU_FREQ) += cpufreq.o obj-$(CONFIG_MODULES) += sh_ksyms_64.o module.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o -obj-$(CONFIG_PM) += pm.o obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_IO_TRAPPED) += io_trapped.o obj-$(CONFIG_GENERIC_GPIO) += gpio.o diff --git a/arch/sh/kernel/cf-enabler.c b/arch/sh/kernel/cf-enabler.c deleted file mode 100644 index bea40339919ba0b3b372024b49fc84b8d3edcf17..0000000000000000000000000000000000000000 --- a/arch/sh/kernel/cf-enabler.c +++ /dev/null @@ -1,168 +0,0 @@ -/* $Id: cf-enabler.c,v 1.4 2004/02/22 22:44:36 kkojima Exp $ - * - * linux/drivers/block/cf-enabler.c - * - * Copyright (C) 1999 Niibe Yutaka - * Copyright (C) 2000 Toshiharu Nozawa - * Copyright (C) 2001 A&D Co., Ltd. - * - * Enable the CF configuration. - */ - -#include -#include -#include -#include -#include -#include - -/* - * You can connect Compact Flash directly to the bus of SuperH. - * This is the enabler for that. - * - * SIM: How generic is this really? It looks pretty board, or at - * least SH sub-type, specific to me. - * I know it doesn't work on the Overdrive! - */ - -/* - * 0xB8000000 : Attribute - * 0xB8001000 : Common Memory - * 0xBA000000 : I/O - */ -#if defined(CONFIG_CPU_SH4) -/* SH4 can't access PCMCIA interface through P2 area. - * we must remap it with appropriate attribute bit of the page set. - * this part is based on Greg Banks' hd64465_ss.c implementation - Masahiro Abe */ - -#if defined(CONFIG_CF_AREA6) -#define slot_no 0 -#else -#define slot_no 1 -#endif - -/* use this pointer to access to directly connected compact flash io area*/ -void *cf_io_base; - -static int __init allocate_cf_area(void) -{ - pgprot_t prot; - unsigned long paddrbase, psize; - - /* open I/O area window */ - paddrbase = virt_to_phys((void*)CONFIG_CF_BASE_ADDR); - psize = PAGE_SIZE; - prot = PAGE_KERNEL_PCC(slot_no, _PAGE_PCC_IO16); - cf_io_base = p3_ioremap(paddrbase, psize, prot.pgprot); - if (!cf_io_base) { - printk("allocate_cf_area : can't open CF I/O window!\n"); - return -ENOMEM; - } -/* printk("p3_ioremap(paddr=0x%08lx, psize=0x%08lx, prot=0x%08lx)=0x%08lx\n", - paddrbase, psize, prot.pgprot, cf_io_base);*/ - - /* XXX : do we need attribute and common-memory area also? */ - - return 0; -} -#endif - -static int __init cf_init_default(void) -{ -/* You must have enabled the card, and set the level interrupt - * before reaching this point. Possibly in boot ROM or boot loader. - */ -#if defined(CONFIG_CPU_SH4) - allocate_cf_area(); -#endif - - return 0; -} - -#if defined(CONFIG_SH_SOLUTION_ENGINE) -#include -#elif defined(CONFIG_SH_7722_SOLUTION_ENGINE) -#include -#elif defined(CONFIG_SH_7721_SOLUTION_ENGINE) -#include -#endif - -/* - * SolutionEngine Seriese - * - * about MS770xSE - * 0xB8400000 : Common Memory - * 0xB8500000 : Attribute - * 0xB8600000 : I/O - * - * about MS7722SE - * 0xB0400000 : Common Memory - * 0xB0500000 : Attribute - * 0xB0600000 : I/O - */ - -#if defined(CONFIG_SH_SOLUTION_ENGINE) || \ - defined(CONFIG_SH_7722_SOLUTION_ENGINE) || \ - defined(CONFIG_SH_7721_SOLUTION_ENGINE) -static int __init cf_init_se(void) -{ - if ((ctrl_inw(MRSHPC_CSR) & 0x000c) != 0) - return 0; /* Not detected */ - - if ((ctrl_inw(MRSHPC_CSR) & 0x0080) == 0) { - ctrl_outw(0x0674, MRSHPC_CPWCR); /* Card Vcc is 3.3v? */ - } else { - ctrl_outw(0x0678, MRSHPC_CPWCR); /* Card Vcc is 5V */ - } - - /* - * PC-Card window open - * flag == COMMON/ATTRIBUTE/IO - */ - /* common window open */ - ctrl_outw(0x8a84, MRSHPC_MW0CR1); - if((ctrl_inw(MRSHPC_CSR) & 0x4000) != 0) - /* common mode & bus width 16bit SWAP = 1*/ - ctrl_outw(0x0b00, MRSHPC_MW0CR2); - else - /* common mode & bus width 16bit SWAP = 0*/ - ctrl_outw(0x0300, MRSHPC_MW0CR2); - - /* attribute window open */ - ctrl_outw(0x8a85, MRSHPC_MW1CR1); - if ((ctrl_inw(MRSHPC_CSR) & 0x4000) != 0) - /* attribute mode & bus width 16bit SWAP = 1*/ - ctrl_outw(0x0a00, MRSHPC_MW1CR2); - else - /* attribute mode & bus width 16bit SWAP = 0*/ - ctrl_outw(0x0200, MRSHPC_MW1CR2); - - /* I/O window open */ - ctrl_outw(0x8a86, MRSHPC_IOWCR1); - ctrl_outw(0x0008, MRSHPC_CDCR); /* I/O card mode */ - if ((ctrl_inw(MRSHPC_CSR) & 0x4000) != 0) - ctrl_outw(0x0a00, MRSHPC_IOWCR2); /* bus width 16bit SWAP = 1*/ - else - ctrl_outw(0x0200, MRSHPC_IOWCR2); /* bus width 16bit SWAP = 0*/ - - ctrl_outw(0x2000, MRSHPC_ICR); - ctrl_outb(0x00, PA_MRSHPC_MW2 + 0x206); - ctrl_outb(0x42, PA_MRSHPC_MW2 + 0x200); - return 0; -} -#else -static int __init cf_init_se(void) -{ - return -1; -} -#endif - -static int __init cf_init(void) -{ - if (mach_is_se() || mach_is_7722se() || mach_is_7721se()) - return cf_init_se(); - - return cf_init_default(); -} - -__initcall (cf_init); diff --git a/arch/sh/kernel/cpu/clock.c b/arch/sh/kernel/cpu/clock.c index b7e46d5bba439057a6f503d72b509515554db89a..7b17137536d622c3909e7ee8f6cac6ac78bb56c3 100644 --- a/arch/sh/kernel/cpu/clock.c +++ b/arch/sh/kernel/cpu/clock.c @@ -117,6 +117,11 @@ int clk_enable(struct clk *clk) unsigned long flags; int ret; + if (!clk) + return -EINVAL; + + clk_enable(clk->parent); + spin_lock_irqsave(&clock_lock, flags); ret = __clk_enable(clk); spin_unlock_irqrestore(&clock_lock, flags); @@ -147,9 +152,14 @@ void clk_disable(struct clk *clk) { unsigned long flags; + if (!clk) + return; + spin_lock_irqsave(&clock_lock, flags); __clk_disable(clk); spin_unlock_irqrestore(&clock_lock, flags); + + clk_disable(clk->parent); } EXPORT_SYMBOL_GPL(clk_disable); diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c index 75fb03d3567008e733748d2748366ab4fb3d1654..d29e69c156f0a75a48cd0322e688c1b5d6f3add8 100644 --- a/arch/sh/kernel/cpu/init.c +++ b/arch/sh/kernel/cpu/init.c @@ -261,9 +261,11 @@ asmlinkage void __init sh_cpu_init(void) cache_init(); if (raw_smp_processor_id() == 0) { +#ifdef CONFIG_MMU shm_align_mask = max_t(unsigned long, current_cpu_data.dcache.way_size - 1, PAGE_SIZE - 1); +#endif /* Boot CPU sets the cache shape */ detect_cache_shape(); diff --git a/arch/sh/kernel/cpu/sh2a/Makefile b/arch/sh/kernel/cpu/sh2a/Makefile index 428450cc0809d8c48476ac6ef604759d0614b64e..45f85c77ef75dc614940c4bdab0d18573a53b8bc 100644 --- a/arch/sh/kernel/cpu/sh2a/Makefile +++ b/arch/sh/kernel/cpu/sh2a/Makefile @@ -8,9 +8,10 @@ common-y += ex.o entry.o obj-$(CONFIG_SH_FPU) += fpu.o -obj-$(CONFIG_CPU_SUBTYPE_SH7206) += setup-sh7206.o clock-sh7206.o +obj-$(CONFIG_CPU_SUBTYPE_SH7201) += setup-sh7201.o clock-sh7201.o obj-$(CONFIG_CPU_SUBTYPE_SH7203) += setup-sh7203.o clock-sh7203.o obj-$(CONFIG_CPU_SUBTYPE_SH7263) += setup-sh7203.o clock-sh7203.o +obj-$(CONFIG_CPU_SUBTYPE_SH7206) += setup-sh7206.o clock-sh7206.o obj-$(CONFIG_CPU_SUBTYPE_MXG) += setup-mxg.o clock-sh7206.o # Pinmux setup diff --git a/arch/sh/kernel/cpu/sh2a/clock-sh7201.c b/arch/sh/kernel/cpu/sh2a/clock-sh7201.c new file mode 100644 index 0000000000000000000000000000000000000000..020a96fe961a0b1cfa682cd919b22ab4f3af92cf --- /dev/null +++ b/arch/sh/kernel/cpu/sh2a/clock-sh7201.c @@ -0,0 +1,85 @@ +/* + * arch/sh/kernel/cpu/sh2a/clock-sh7201.c + * + * SH7201 support for the clock framework + * + * Copyright (C) 2008 Peter Griffin + * + * Based on clock-sh4.c + * Copyright (C) 2005 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include +#include +#include + +const static int pll1rate[]={1,2,3,4,6,8}; +const static int pfc_divisors[]={1,2,3,4,6,8,12}; +#define ifc_divisors pfc_divisors + +#if (CONFIG_SH_CLK_MD == 0) +#define PLL2 (4) +#elif (CONFIG_SH_CLK_MD == 2) +#define PLL2 (2) +#elif (CONFIG_SH_CLK_MD == 3) +#define PLL2 (1) +#else +#error "Illegal Clock Mode!" +#endif + +static void master_clk_init(struct clk *clk) +{ + clk->rate = 10000000 * PLL2 * pll1rate[(ctrl_inw(FREQCR) >> 8) & 0x0007]; +} + +static struct clk_ops sh7201_master_clk_ops = { + .init = master_clk_init, +}; + +static void module_clk_recalc(struct clk *clk) +{ + int idx = (ctrl_inw(FREQCR) & 0x0007); + clk->rate = clk->parent->rate / pfc_divisors[idx]; +} + +static struct clk_ops sh7201_module_clk_ops = { + .recalc = module_clk_recalc, +}; + +static void bus_clk_recalc(struct clk *clk) +{ + int idx = (ctrl_inw(FREQCR) & 0x0007); + clk->rate = clk->parent->rate / pfc_divisors[idx]; +} + +static struct clk_ops sh7201_bus_clk_ops = { + .recalc = bus_clk_recalc, +}; + +static void cpu_clk_recalc(struct clk *clk) +{ + int idx = ((ctrl_inw(FREQCR) >> 4) & 0x0007); + clk->rate = clk->parent->rate / ifc_divisors[idx]; +} + +static struct clk_ops sh7201_cpu_clk_ops = { + .recalc = cpu_clk_recalc, +}; + +static struct clk_ops *sh7201_clk_ops[] = { + &sh7201_master_clk_ops, + &sh7201_module_clk_ops, + &sh7201_bus_clk_ops, + &sh7201_cpu_clk_ops, +}; + +void __init arch_init_clk_ops(struct clk_ops **ops, int idx) +{ + if (idx < ARRAY_SIZE(sh7201_clk_ops)) + *ops = sh7201_clk_ops[idx]; +} diff --git a/arch/sh/kernel/cpu/sh2a/probe.c b/arch/sh/kernel/cpu/sh2a/probe.c index 6e79132f6f3047dc275bd912de3d95710fd2f8d1..e098e2f6aa087bd43b88c72f147464413c6fb497 100644 --- a/arch/sh/kernel/cpu/sh2a/probe.c +++ b/arch/sh/kernel/cpu/sh2a/probe.c @@ -18,16 +18,17 @@ int __init detect_cpu_and_cache_system(void) /* All SH-2A CPUs have support for 16 and 32-bit opcodes.. */ boot_cpu_data.flags |= CPU_HAS_OP32; -#if defined(CONFIG_CPU_SUBTYPE_SH7203) +#if defined(CONFIG_CPU_SUBTYPE_SH7201) + boot_cpu_data.type = CPU_SH7201; + boot_cpu_data.flags |= CPU_HAS_FPU; +#elif defined(CONFIG_CPU_SUBTYPE_SH7203) boot_cpu_data.type = CPU_SH7203; - /* SH7203 has an FPU.. */ boot_cpu_data.flags |= CPU_HAS_FPU; #elif defined(CONFIG_CPU_SUBTYPE_SH7263) boot_cpu_data.type = CPU_SH7263; boot_cpu_data.flags |= CPU_HAS_FPU; #elif defined(CONFIG_CPU_SUBTYPE_SH7206) boot_cpu_data.type = CPU_SH7206; - /* While SH7206 has a DSP.. */ boot_cpu_data.flags |= CPU_HAS_DSP; #elif defined(CONFIG_CPU_SUBTYPE_MXG) boot_cpu_data.type = CPU_MXG; diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7201.c b/arch/sh/kernel/cpu/sh2a/setup-sh7201.c new file mode 100644 index 0000000000000000000000000000000000000000..0631e421c022710e6964eca336a98869c7bef793 --- /dev/null +++ b/arch/sh/kernel/cpu/sh2a/setup-sh7201.c @@ -0,0 +1,331 @@ +/* + * SH7201 setup + * + * Copyright (C) 2008 Peter Griffin pgriffin@mpc-data.co.uk + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include +#include + +enum { + UNUSED = 0, + + /* interrupt sources */ + IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7, + PINT0, PINT1, PINT2, PINT3, PINT4, PINT5, PINT6, PINT7, + ADC_ADI, + MTU2_TGI0A, MTU2_TGI0B, MTU2_TGI0C, MTU2_TGI0D, + MTU2_TCI0V, MTU2_TGI0E, MTU2_TGI0F, + MTU2_TGI1A, MTU2_TGI1B, MTU2_TCI1V, MTU2_TCI1U, + MTU2_TGI2A, MTU2_TGI2B, MTU2_TCI2V, MTU2_TCI2U, + MTU2_TGI3A, MTU2_TGI3B, MTU2_TGI3C, MTU2_TGI3D, MTU2_TCI3V, + MTU2_TGI4A, MTU2_TGI4B, MTU2_TGI4C, MTU2_TGI4D, MTU2_TCI4V, + MTU2_TGI5U, MTU2_TGI5V, MTU2_TGI5W, + RTC_ARM, RTC_PRD, RTC_CUP, + WDT, + IIC30_STPI, IIC30_NAKI, IIC30_RXI, IIC30_TXI, IIC30_TEI, + IIC31_STPI, IIC31_NAKI, IIC31_RXI, IIC31_TXI, IIC31_TEI, + IIC32_STPI, IIC32_NAKI, IIC32_RXI, IIC32_TXI, IIC32_TEI, + + DMAC0_DMINT0, DMAC1_DMINT1, + DMAC2_DMINT2, DMAC3_DMINT3, + + SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI, + SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI, + SCIF2_BRI, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI, + SCIF3_BRI, SCIF3_ERI, SCIF3_RXI, SCIF3_TXI, + SCIF4_BRI, SCIF4_ERI, SCIF4_RXI, SCIF4_TXI, + SCIF5_BRI, SCIF5_ERI, SCIF5_RXI, SCIF5_TXI, + SCIF6_BRI, SCIF6_ERI, SCIF6_RXI, SCIF6_TXI, + SCIF7_BRI, SCIF7_ERI, SCIF7_RXI, SCIF7_TXI, + + DMAC0_DMINTA, DMAC4_DMINT4, DMAC5_DMINT5, DMAC6_DMINT6, + DMAC7_DMINT7, + + RCAN0_ERS, RCAN0_OVR, + RCAN0_SLE, + RCAN0_RM0, RCAN0_RM1, + + RCAN1_ERS, RCAN1_OVR, + RCAN1_SLE, + RCAN1_RM0, RCAN1_RM1, + + SSI0_SSII, SSI1_SSII, + + TMR0_CMIA0, TMR0_CMIB0, TMR0_OVI0, + TMR1_CMIA1, TMR1_CMIB1, TMR1_OVI1, + + /* interrupt groups */ + + IRQ, PINT, ADC, + MTU20_ABCD, MTU20_VEF, MTU21_AB, MTU21_VU, MTU22_AB, MTU22_VU, + MTU23_ABCD, MTU24_ABCD, MTU25_UVW, + RTC, IIC30, IIC31, IIC32, + SCIF0, SCIF1, SCIF2, SCIF3, SCIF4, SCIF5, SCIF6, SCIF7, + RCAN0, RCAN1, TMR0, TMR1 + +}; + +static struct intc_vect vectors[] __initdata = { + INTC_IRQ(IRQ0, 64), INTC_IRQ(IRQ1, 65), + INTC_IRQ(IRQ2, 66), INTC_IRQ(IRQ3, 67), + INTC_IRQ(IRQ4, 68), INTC_IRQ(IRQ5, 69), + INTC_IRQ(IRQ6, 70), INTC_IRQ(IRQ7, 71), + INTC_IRQ(PINT0, 80), INTC_IRQ(PINT1, 81), + INTC_IRQ(PINT2, 82), INTC_IRQ(PINT3, 83), + INTC_IRQ(PINT4, 84), INTC_IRQ(PINT5, 85), + INTC_IRQ(PINT6, 86), INTC_IRQ(PINT7, 87), + + INTC_IRQ(ADC_ADI, 92), + + INTC_IRQ(MTU2_TGI0A, 108), INTC_IRQ(MTU2_TGI0B, 109), + INTC_IRQ(MTU2_TGI0C, 110), INTC_IRQ(MTU2_TGI0D, 111), + INTC_IRQ(MTU2_TCI0V, 112), + INTC_IRQ(MTU2_TGI0E, 113), INTC_IRQ(MTU2_TGI0F, 114), + + INTC_IRQ(MTU2_TGI1A, 116), INTC_IRQ(MTU2_TGI1B, 117), + INTC_IRQ(MTU2_TCI1V, 120), INTC_IRQ(MTU2_TCI1U, 121), + + INTC_IRQ(MTU2_TGI2A, 124), INTC_IRQ(MTU2_TGI2B, 125), + INTC_IRQ(MTU2_TCI2V, 128), INTC_IRQ(MTU2_TCI2U, 129), + + INTC_IRQ(MTU2_TGI3A, 132), INTC_IRQ(MTU2_TGI3B, 133), + INTC_IRQ(MTU2_TGI3C, 134), INTC_IRQ(MTU2_TGI3D, 135), + INTC_IRQ(MTU2_TCI3V, 136), + + INTC_IRQ(MTU2_TGI4A, 140), INTC_IRQ(MTU2_TGI4B, 141), + INTC_IRQ(MTU2_TGI4C, 142), INTC_IRQ(MTU2_TGI4D, 143), + INTC_IRQ(MTU2_TCI4V, 144), + + INTC_IRQ(MTU2_TGI5U, 148), INTC_IRQ(MTU2_TGI5V, 149), + INTC_IRQ(MTU2_TGI5W, 150), + + INTC_IRQ(RTC_ARM, 152), INTC_IRQ(RTC_PRD, 153), + INTC_IRQ(RTC_CUP, 154), INTC_IRQ(WDT, 156), + + INTC_IRQ(IIC30_STPI, 157), INTC_IRQ(IIC30_NAKI, 158), + INTC_IRQ(IIC30_RXI, 159), INTC_IRQ(IIC30_TXI, 160), + INTC_IRQ(IIC30_TEI, 161), + + INTC_IRQ(IIC31_STPI, 164), INTC_IRQ(IIC31_NAKI, 165), + INTC_IRQ(IIC31_RXI, 166), INTC_IRQ(IIC31_TXI, 167), + INTC_IRQ(IIC31_TEI, 168), + + INTC_IRQ(IIC32_STPI, 170), INTC_IRQ(IIC32_NAKI, 171), + INTC_IRQ(IIC32_RXI, 172), INTC_IRQ(IIC32_TXI, 173), + INTC_IRQ(IIC32_TEI, 174), + + INTC_IRQ(DMAC0_DMINT0, 176), INTC_IRQ(DMAC1_DMINT1, 177), + INTC_IRQ(DMAC2_DMINT2, 178), INTC_IRQ(DMAC3_DMINT3, 179), + + INTC_IRQ(SCIF0_BRI, 180), INTC_IRQ(SCIF0_ERI, 181), + INTC_IRQ(SCIF0_RXI, 182), INTC_IRQ(SCIF0_TXI, 183), + INTC_IRQ(SCIF1_BRI, 184), INTC_IRQ(SCIF1_ERI, 185), + INTC_IRQ(SCIF1_RXI, 186), INTC_IRQ(SCIF1_TXI, 187), + INTC_IRQ(SCIF2_BRI, 188), INTC_IRQ(SCIF2_ERI, 189), + INTC_IRQ(SCIF2_RXI, 190), INTC_IRQ(SCIF2_TXI, 191), + INTC_IRQ(SCIF3_BRI, 192), INTC_IRQ(SCIF3_ERI, 193), + INTC_IRQ(SCIF3_RXI, 194), INTC_IRQ(SCIF3_TXI, 195), + INTC_IRQ(SCIF4_BRI, 196), INTC_IRQ(SCIF4_ERI, 197), + INTC_IRQ(SCIF4_RXI, 198), INTC_IRQ(SCIF4_TXI, 199), + INTC_IRQ(SCIF5_BRI, 200), INTC_IRQ(SCIF5_ERI, 201), + INTC_IRQ(SCIF5_RXI, 202), INTC_IRQ(SCIF5_TXI, 203), + INTC_IRQ(SCIF6_BRI, 204), INTC_IRQ(SCIF6_ERI, 205), + INTC_IRQ(SCIF6_RXI, 206), INTC_IRQ(SCIF6_TXI, 207), + INTC_IRQ(SCIF7_BRI, 208), INTC_IRQ(SCIF7_ERI, 209), + INTC_IRQ(SCIF7_RXI, 210), INTC_IRQ(SCIF7_TXI, 211), + + INTC_IRQ(DMAC0_DMINTA, 212), INTC_IRQ(DMAC4_DMINT4, 216), + INTC_IRQ(DMAC5_DMINT5, 217), INTC_IRQ(DMAC6_DMINT6, 218), + INTC_IRQ(DMAC7_DMINT7, 219), + + INTC_IRQ(RCAN0_ERS, 228), INTC_IRQ(RCAN0_OVR, 229), + INTC_IRQ(RCAN0_SLE, 230), + INTC_IRQ(RCAN0_RM0, 231), INTC_IRQ(RCAN0_RM1, 232), + + INTC_IRQ(RCAN1_ERS, 234), INTC_IRQ(RCAN1_OVR, 235), + INTC_IRQ(RCAN1_SLE, 236), + INTC_IRQ(RCAN1_RM0, 237), INTC_IRQ(RCAN1_RM1, 238), + + INTC_IRQ(SSI0_SSII, 244), INTC_IRQ(SSI1_SSII, 245), + + INTC_IRQ(TMR0_CMIA0, 246), INTC_IRQ(TMR0_CMIB0, 247), + INTC_IRQ(TMR0_OVI0, 248), + + INTC_IRQ(TMR1_CMIA1, 252), INTC_IRQ(TMR1_CMIB1, 253), + INTC_IRQ(TMR1_OVI1, 254), + +}; + +static struct intc_group groups[] __initdata = { + INTC_GROUP(PINT, PINT0, PINT1, PINT2, PINT3, + PINT4, PINT5, PINT6, PINT7), + INTC_GROUP(MTU20_ABCD, MTU2_TGI0A, MTU2_TGI0B, MTU2_TGI0C, MTU2_TGI0D), + INTC_GROUP(MTU20_VEF, MTU2_TCI0V, MTU2_TGI0E, MTU2_TGI0F), + + INTC_GROUP(MTU21_AB, MTU2_TGI1A, MTU2_TGI1B), + INTC_GROUP(MTU21_VU, MTU2_TCI1V, MTU2_TCI1U), + INTC_GROUP(MTU22_AB, MTU2_TGI2A, MTU2_TGI2B), + INTC_GROUP(MTU22_VU, MTU2_TCI2V, MTU2_TCI2U), + INTC_GROUP(MTU23_ABCD, MTU2_TGI3A, MTU2_TGI3B, MTU2_TGI3C, MTU2_TGI3D), + INTC_GROUP(MTU24_ABCD, MTU2_TGI4A, MTU2_TGI4B, MTU2_TGI4C, MTU2_TGI4D), + INTC_GROUP(MTU25_UVW, MTU2_TGI5U, MTU2_TGI5V, MTU2_TGI5W), + INTC_GROUP(RTC, RTC_ARM, RTC_PRD, RTC_CUP ), + + INTC_GROUP(IIC30, IIC30_STPI, IIC30_NAKI, IIC30_RXI, IIC30_TXI, + IIC30_TEI), + INTC_GROUP(IIC31, IIC31_STPI, IIC31_NAKI, IIC31_RXI, IIC31_TXI, + IIC31_TEI), + INTC_GROUP(IIC32, IIC32_STPI, IIC32_NAKI, IIC32_RXI, IIC32_TXI, + IIC32_TEI), + + INTC_GROUP(SCIF0, SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI), + INTC_GROUP(SCIF1, SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI), + INTC_GROUP(SCIF2, SCIF2_BRI, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI), + INTC_GROUP(SCIF3, SCIF3_BRI, SCIF3_ERI, SCIF3_RXI, SCIF3_TXI), + INTC_GROUP(SCIF4, SCIF4_BRI, SCIF4_ERI, SCIF4_RXI, SCIF4_TXI), + INTC_GROUP(SCIF5, SCIF5_BRI, SCIF5_ERI, SCIF5_RXI, SCIF5_TXI), + INTC_GROUP(SCIF6, SCIF6_BRI, SCIF6_ERI, SCIF6_RXI, SCIF6_TXI), + INTC_GROUP(SCIF7, SCIF7_BRI, SCIF7_ERI, SCIF7_RXI, SCIF7_TXI), + + INTC_GROUP(RCAN0, RCAN0_ERS, RCAN0_OVR, RCAN0_RM0, RCAN0_RM1, + RCAN0_SLE), + INTC_GROUP(RCAN1, RCAN1_ERS, RCAN1_OVR, RCAN1_RM0, RCAN1_RM1, + RCAN1_SLE), + + INTC_GROUP(TMR0, TMR0_CMIA0, TMR0_CMIB0, TMR0_OVI0), + INTC_GROUP(TMR1, TMR1_CMIA1, TMR1_CMIB1, TMR1_OVI1), +}; + +static struct intc_prio_reg prio_registers[] __initdata = { + { 0xfffe9418, 0, 16, 4, /* IPR01 */ { IRQ0, IRQ1, IRQ2, IRQ3 } }, + { 0xfffe941a, 0, 16, 4, /* IPR02 */ { IRQ4, IRQ5, IRQ6, IRQ7 } }, + { 0xfffe9420, 0, 16, 4, /* IPR05 */ { PINT, 0, ADC_ADI, 0 } }, + { 0xfffe9800, 0, 16, 4, /* IPR06 */ { 0, MTU20_ABCD, MTU20_VEF, MTU21_AB } }, + { 0xfffe9802, 0, 16, 4, /* IPR07 */ { MTU21_VU, MTU22_AB, MTU22_VU, MTU23_ABCD } }, + { 0xfffe9804, 0, 16, 4, /* IPR08 */ { MTU2_TCI3V, MTU24_ABCD, MTU2_TCI4V, MTU25_UVW } }, + + { 0xfffe9806, 0, 16, 4, /* IPR09 */ { RTC, WDT, IIC30, 0 } }, + { 0xfffe9808, 0, 16, 4, /* IPR10 */ { IIC31, IIC32, DMAC0_DMINT0, DMAC1_DMINT1 } }, + { 0xfffe980a, 0, 16, 4, /* IPR11 */ { DMAC2_DMINT2, DMAC3_DMINT3, SCIF0 , SCIF1 } }, + { 0xfffe980c, 0, 16, 4, /* IPR12 */ { SCIF2, SCIF3, SCIF4, SCIF5 } }, + { 0xfffe980e, 0, 16, 4, /* IPR13 */ { SCIF6, SCIF7, DMAC0_DMINTA, DMAC4_DMINT4 } }, + { 0xfffe9810, 0, 16, 4, /* IPR14 */ { DMAC5_DMINT5, DMAC6_DMINT6, DMAC7_DMINT7, 0 } }, + { 0xfffe9812, 0, 16, 4, /* IPR15 */ { 0, RCAN0, RCAN1, 0 } }, + { 0xfffe9814, 0, 16, 4, /* IPR16 */ { SSI0_SSII, SSI1_SSII, TMR0, TMR1 } }, +}; + +static struct intc_mask_reg mask_registers[] __initdata = { + { 0xfffe9408, 0, 16, /* PINTER */ + { 0, 0, 0, 0, 0, 0, 0, 0, + PINT7, PINT6, PINT5, PINT4, PINT3, PINT2, PINT1, PINT0 } }, +}; + +static DECLARE_INTC_DESC(intc_desc, "sh7201", vectors, groups, + mask_registers, prio_registers, NULL); + +static struct plat_sci_port sci_platform_data[] = { + { + .mapbase = 0xfffe8000, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_SCIF, + .irqs = { 181, 182, 183, 180} + }, { + .mapbase = 0xfffe8800, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_SCIF, + .irqs = { 185, 186, 187, 184} + }, { + .mapbase = 0xfffe9000, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_SCIF, + .irqs = { 189, 186, 187, 188} + }, { + .mapbase = 0xfffe9800, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_SCIF, + .irqs = { 193, 194, 195, 192} + }, { + .mapbase = 0xfffea000, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_SCIF, + .irqs = { 196, 198, 199, 196} + }, { + .mapbase = 0xfffea800, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_SCIF, + .irqs = { 201, 202, 203, 200} + }, { + .mapbase = 0xfffeb000, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_SCIF, + .irqs = { 205, 206, 207, 204} + }, { + .mapbase = 0xfffeb800, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_SCIF, + .irqs = { 209, 210, 211, 208} + }, { + .flags = 0, + } +}; + +static struct platform_device sci_device = { + .name = "sh-sci", + .id = -1, + .dev = { + .platform_data = sci_platform_data, + }, +}; + +static struct resource rtc_resources[] = { + [0] = { + .start = 0xffff0800, + .end = 0xffff2000 + 0x58 - 1, + .flags = IORESOURCE_IO, + }, + [1] = { + /* Period IRQ */ + .start = 153, + .flags = IORESOURCE_IRQ, + }, + [2] = { + /* Carry IRQ */ + .start = 154, + .flags = IORESOURCE_IRQ, + }, + [3] = { + /* Alarm IRQ */ + .start = 152, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device rtc_device = { + .name = "sh-rtc", + .id = -1, + .num_resources = ARRAY_SIZE(rtc_resources), + .resource = rtc_resources, +}; + +static struct platform_device *sh7201_devices[] __initdata = { + &sci_device, + &rtc_device, +}; + +static int __init sh7201_devices_setup(void) +{ + return platform_add_devices(sh7201_devices, + ARRAY_SIZE(sh7201_devices)); +} +__initcall(sh7201_devices_setup); + +void __init plat_irq_setup(void) +{ + register_intc_controller(&intc_desc); +} diff --git a/arch/sh/kernel/cpu/sh3/entry.S b/arch/sh/kernel/cpu/sh3/entry.S index 3fe482dd05c164a3b7cce794f17833e115b4af44..b4106d0c68ec0e0c8fc3db9365b5c289b15a961d 100644 --- a/arch/sh/kernel/cpu/sh3/entry.S +++ b/arch/sh/kernel/cpu/sh3/entry.S @@ -52,7 +52,7 @@ * syscall # * */ -#if defined(CONFIG_KGDB_NMI) +#if defined(CONFIG_KGDB) NMI_VEC = 0x1c0 ! Must catch early for debounce #endif @@ -307,7 +307,7 @@ skip_restore: 6: or k0, k2 ! Set the IMASK-bits ldc k2, ssr ! -#if defined(CONFIG_KGDB_NMI) +#if defined(CONFIG_KGDB) ! Clear in_nmi mov.l 6f, k0 mov #0, k1 @@ -320,7 +320,7 @@ skip_restore: .align 2 5: .long 0x00001000 ! DSP -#ifdef CONFIG_KGDB_NMI +#ifdef CONFIG_KGDB 6: .long in_nmi #endif 7: .long 0x30000000 @@ -376,9 +376,9 @@ tlb_miss: ! .balign 512,0,512 interrupt: - mov.l 2f, k2 mov.l 3f, k3 -#if defined(CONFIG_KGDB_NMI) +#if defined(CONFIG_KGDB) + mov.l 2f, k2 ! Debounce (filter nested NMI) mov.l @k2, k0 mov.l 5f, k1 @@ -390,16 +390,16 @@ interrupt: rte nop .align 2 +2: .long INTEVT 5: .long NMI_VEC 6: .long in_nmi 0: -#endif /* defined(CONFIG_KGDB_NMI) */ +#endif /* defined(CONFIG_KGDB) */ bra handle_exception mov #-1, k2 ! interrupt exception marker .align 2 1: .long EXPEVT -2: .long INTEVT 3: .long ret_from_irq 4: .long ret_from_exception diff --git a/arch/sh/kernel/cpu/sh3/ex.S b/arch/sh/kernel/cpu/sh3/ex.S index dac42972689932b00100fd1c3a654a26aa61d1e9..e5a0de39a2dbab62054d9714b4fd420e7efb29a2 100644 --- a/arch/sh/kernel/cpu/sh3/ex.S +++ b/arch/sh/kernel/cpu/sh3/ex.S @@ -26,7 +26,7 @@ #define fpu_error_trap_handler exception_error #endif -#if !defined(CONFIG_KGDB_NMI) +#if !defined(CONFIG_KGDB) #define kgdb_handle_exception exception_error #endif diff --git a/arch/sh/kernel/cpu/sh4/softfloat.c b/arch/sh/kernel/cpu/sh4/softfloat.c index 2b747f3b02bd34d22290eab0ec5e9ca2a948ea10..42edf2e54e85430b1df930625cb0378d48711bc0 100644 --- a/arch/sh/kernel/cpu/sh4/softfloat.c +++ b/arch/sh/kernel/cpu/sh4/softfloat.c @@ -37,6 +37,7 @@ */ #include #include +#include #define LIT64( a ) a##LL @@ -67,16 +68,16 @@ typedef unsigned long long float64; extern void float_raise(unsigned int flags); /* in fpu.c */ extern int float_rounding_mode(void); /* in fpu.c */ -inline bits64 extractFloat64Frac(float64 a); -inline flag extractFloat64Sign(float64 a); -inline int16 extractFloat64Exp(float64 a); -inline int16 extractFloat32Exp(float32 a); -inline flag extractFloat32Sign(float32 a); -inline bits32 extractFloat32Frac(float32 a); -inline float64 packFloat64(flag zSign, int16 zExp, bits64 zSig); -inline void shift64RightJamming(bits64 a, int16 count, bits64 * zPtr); -inline float32 packFloat32(flag zSign, int16 zExp, bits32 zSig); -inline void shift32RightJamming(bits32 a, int16 count, bits32 * zPtr); +bits64 extractFloat64Frac(float64 a); +flag extractFloat64Sign(float64 a); +int16 extractFloat64Exp(float64 a); +int16 extractFloat32Exp(float32 a); +flag extractFloat32Sign(float32 a); +bits32 extractFloat32Frac(float32 a); +float64 packFloat64(flag zSign, int16 zExp, bits64 zSig); +void shift64RightJamming(bits64 a, int16 count, bits64 * zPtr); +float32 packFloat32(flag zSign, int16 zExp, bits32 zSig); +void shift32RightJamming(bits32 a, int16 count, bits32 * zPtr); float64 float64_sub(float64 a, float64 b); float32 float32_sub(float32 a, float32 b); float32 float32_add(float32 a, float32 b); @@ -86,11 +87,11 @@ float32 float32_div(float32 a, float32 b); float32 float32_mul(float32 a, float32 b); float64 float64_mul(float64 a, float64 b); float32 float64_to_float32(float64 a); -inline void add128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr, +void add128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr, bits64 * z1Ptr); -inline void sub128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr, +void sub128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr, bits64 * z1Ptr); -inline void mul64To128(bits64 a, bits64 b, bits64 * z0Ptr, bits64 * z1Ptr); +void mul64To128(bits64 a, bits64 b, bits64 * z0Ptr, bits64 * z1Ptr); static int8 countLeadingZeros32(bits32 a); static int8 countLeadingZeros64(bits64 a); @@ -110,42 +111,42 @@ static bits64 estimateDiv128To64(bits64 a0, bits64 a1, bits64 b); static void normalizeFloat32Subnormal(bits32 aSig, int16 * zExpPtr, bits32 * zSigPtr); -inline bits64 extractFloat64Frac(float64 a) +bits64 extractFloat64Frac(float64 a) { return a & LIT64(0x000FFFFFFFFFFFFF); } -inline flag extractFloat64Sign(float64 a) +flag extractFloat64Sign(float64 a) { return a >> 63; } -inline int16 extractFloat64Exp(float64 a) +int16 extractFloat64Exp(float64 a) { return (a >> 52) & 0x7FF; } -inline int16 extractFloat32Exp(float32 a) +int16 extractFloat32Exp(float32 a) { return (a >> 23) & 0xFF; } -inline flag extractFloat32Sign(float32 a) +flag extractFloat32Sign(float32 a) { return a >> 31; } -inline bits32 extractFloat32Frac(float32 a) +bits32 extractFloat32Frac(float32 a) { return a & 0x007FFFFF; } -inline float64 packFloat64(flag zSign, int16 zExp, bits64 zSig) +float64 packFloat64(flag zSign, int16 zExp, bits64 zSig) { return (((bits64) zSign) << 63) + (((bits64) zExp) << 52) + zSig; } -inline void shift64RightJamming(bits64 a, int16 count, bits64 * zPtr) +void shift64RightJamming(bits64 a, int16 count, bits64 * zPtr) { bits64 z; @@ -338,12 +339,12 @@ static float64 addFloat64Sigs(float64 a, float64 b, flag zSign) } -inline float32 packFloat32(flag zSign, int16 zExp, bits32 zSig) +float32 packFloat32(flag zSign, int16 zExp, bits32 zSig) { return (((bits32) zSign) << 31) + (((bits32) zExp) << 23) + zSig; } -inline void shift32RightJamming(bits32 a, int16 count, bits32 * zPtr) +void shift32RightJamming(bits32 a, int16 count, bits32 * zPtr) { bits32 z; if (count == 0) { @@ -634,7 +635,7 @@ normalizeFloat64Subnormal(bits64 aSig, int16 * zExpPtr, bits64 * zSigPtr) *zExpPtr = 1 - shiftCount; } -inline void add128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr, +void add128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr, bits64 * z1Ptr) { bits64 z1; @@ -644,7 +645,7 @@ inline void add128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr, *z0Ptr = a0 + b0 + (z1 < a1); } -inline void +void sub128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr, bits64 * z1Ptr) { @@ -656,11 +657,14 @@ static bits64 estimateDiv128To64(bits64 a0, bits64 a1, bits64 b) { bits64 b0, b1; bits64 rem0, rem1, term0, term1; - bits64 z; + bits64 z, tmp; if (b <= a0) return LIT64(0xFFFFFFFFFFFFFFFF); b0 = b >> 32; - z = (b0 << 32 <= a0) ? LIT64(0xFFFFFFFF00000000) : (a0 / b0) << 32; + tmp = a0; + do_div(tmp, b0); + + z = (b0 << 32 <= a0) ? LIT64(0xFFFFFFFF00000000) : tmp << 32; mul64To128(b, z, &term0, &term1); sub128(a0, a1, term0, term1, &rem0, &rem1); while (((sbits64) rem0) < 0) { @@ -669,11 +673,13 @@ static bits64 estimateDiv128To64(bits64 a0, bits64 a1, bits64 b) add128(rem0, rem1, b0, b1, &rem0, &rem1); } rem0 = (rem0 << 32) | (rem1 >> 32); - z |= (b0 << 32 <= rem0) ? 0xFFFFFFFF : rem0 / b0; + tmp = rem0; + do_div(tmp, b0); + z |= (b0 << 32 <= rem0) ? 0xFFFFFFFF : tmp; return z; } -inline void mul64To128(bits64 a, bits64 b, bits64 * z0Ptr, bits64 * z1Ptr) +void mul64To128(bits64 a, bits64 b, bits64 * z0Ptr, bits64 * z1Ptr) { bits32 aHigh, aLow, bHigh, bLow; bits64 z0, zMiddleA, zMiddleB, z1; @@ -769,7 +775,8 @@ float32 float32_div(float32 a, float32 b) { flag aSign, bSign, zSign; int16 aExp, bExp, zExp; - bits32 aSig, bSig, zSig; + bits32 aSig, bSig; + uint64_t zSig; aSig = extractFloat32Frac(a); aExp = extractFloat32Exp(a); @@ -804,11 +811,13 @@ float32 float32_div(float32 a, float32 b) aSig >>= 1; ++zExp; } - zSig = (((bits64) aSig) << 32) / bSig; + zSig = (((bits64) aSig) << 32); + do_div(zSig, bSig); + if ((zSig & 0x3F) == 0) { zSig |= (((bits64) bSig) * zSig != ((bits64) aSig) << 32); } - return roundAndPackFloat32(zSign, zExp, zSig); + return roundAndPackFloat32(zSign, zExp, (bits32)zSig); } diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c index db913855c2fd24fc81e3a1cac39997a4df1b09d1..0e174af21874123497614da2e36f0eb0a7e66cfa 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c @@ -229,7 +229,7 @@ struct frqcr_context sh7722_get_clk_context(const char *name) } /** - * sh7722_find_divisors - find divisor for setting rate + * sh7722_find_div_index - find divisor for setting rate * * All sh7722 clocks use the same set of multipliers/divisors. This function * chooses correct divisor to set the rate of clock with parent clock that @@ -238,7 +238,7 @@ struct frqcr_context sh7722_get_clk_context(const char *name) * @parent_rate: rate of parent clock * @rate: requested rate to be set */ -static int sh7722_find_divisors(unsigned long parent_rate, unsigned rate) +static int sh7722_find_div_index(unsigned long parent_rate, unsigned rate) { unsigned div2 = parent_rate * 2 / rate; int index; @@ -247,12 +247,12 @@ static int sh7722_find_divisors(unsigned long parent_rate, unsigned rate) return -EINVAL; for (index = 1; index < ARRAY_SIZE(divisors2); index++) { - if (div2 > divisors2[index] && div2 <= divisors2[index]) + if (div2 > divisors2[index - 1] && div2 <= divisors2[index]) break; } if (index >= ARRAY_SIZE(divisors2)) index = ARRAY_SIZE(divisors2) - 1; - return divisors2[index]; + return index; } static void sh7722_frqcr_recalc(struct clk *clk) @@ -279,12 +279,12 @@ static int sh7722_frqcr_set_rate(struct clk *clk, unsigned long rate, return -EINVAL; /* look for multiplier/divisor pair */ - div = sh7722_find_divisors(parent_rate, rate); + div = sh7722_find_div_index(parent_rate, rate); if (div<0) return div; /* calculate new value of clock rate */ - clk->rate = parent_rate * 2 / div; + clk->rate = parent_rate * 2 / divisors2[div]; frqcr = ctrl_inl(FRQCR); /* FIXME: adjust as algo_id specifies */ @@ -353,7 +353,7 @@ static int sh7722_frqcr_set_rate(struct clk *clk, unsigned long rate, int part_div; if (likely(!err)) { - part_div = sh7722_find_divisors(parent_rate, + part_div = sh7722_find_div_index(parent_rate, rate); if (part_div > 0) { part_ctx = sh7722_get_clk_context( @@ -394,12 +394,12 @@ static long sh7722_frqcr_round_rate(struct clk *clk, unsigned long rate) int div; /* look for multiplier/divisor pair */ - div = sh7722_find_divisors(parent_rate, rate); + div = sh7722_find_div_index(parent_rate, rate); if (div < 0) return clk->rate; /* calculate new value of clock rate */ - return parent_rate * 2 / div; + return parent_rate * 2 / divisors2[div]; } static struct clk_ops sh7722_frqcr_clk_ops = { @@ -421,7 +421,7 @@ static int sh7722_siu_set_rate(struct clk *clk, unsigned long rate, int algo_id) int div; r = ctrl_inl(clk->arch_flags); - div = sh7722_find_divisors(clk->parent->rate, rate); + div = sh7722_find_div_index(clk->parent->rate, rate); if (div < 0) return div; r = (r & ~0xF) | div; @@ -516,16 +516,19 @@ static struct clk_ops sh7722_video_clk_ops = { static struct clk sh7722_umem_clock = { .name = "umem_clk", .ops = &sh7722_frqcr_clk_ops, + .flags = CLK_RATE_PROPAGATES, }; static struct clk sh7722_sh_clock = { .name = "sh_clk", .ops = &sh7722_frqcr_clk_ops, + .flags = CLK_RATE_PROPAGATES, }; static struct clk sh7722_peripheral_clock = { .name = "peripheral_clk", .ops = &sh7722_frqcr_clk_ops, + .flags = CLK_RATE_PROPAGATES, }; static struct clk sh7722_sdram_clock = { @@ -533,6 +536,11 @@ static struct clk sh7722_sdram_clock = { .ops = &sh7722_frqcr_clk_ops, }; +static struct clk sh7722_r_clock = { + .name = "r_clk", + .rate = 32768, + .flags = CLK_RATE_PROPAGATES, +}; #ifndef CONFIG_CPU_SUBTYPE_SH7343 @@ -567,12 +575,30 @@ static struct clk sh7722_video_clock = { .ops = &sh7722_video_clk_ops, }; -static int sh7722_mstpcr_start_stop(struct clk *clk, unsigned long reg, - int enable) +#define MSTPCR_ARCH_FLAGS(reg, bit) (((reg) << 8) | (bit)) +#define MSTPCR_ARCH_FLAGS_REG(value) ((value) >> 8) +#define MSTPCR_ARCH_FLAGS_BIT(value) ((value) & 0xff) + +static int sh7722_mstpcr_start_stop(struct clk *clk, int enable) { - unsigned long bit = clk->arch_flags; + unsigned long bit = MSTPCR_ARCH_FLAGS_BIT(clk->arch_flags); + unsigned long reg; unsigned long r; + switch(MSTPCR_ARCH_FLAGS_REG(clk->arch_flags)) { + case 0: + reg = MSTPCR0; + break; + case 1: + reg = MSTPCR1; + break; + case 2: + reg = MSTPCR2; + break; + default: + return -EINVAL; + } + r = ctrl_inl(reg); if (enable) @@ -584,96 +610,175 @@ static int sh7722_mstpcr_start_stop(struct clk *clk, unsigned long reg, return 0; } -static void sh7722_mstpcr0_enable(struct clk *clk) -{ - sh7722_mstpcr_start_stop(clk, MSTPCR0, 1); -} - -static void sh7722_mstpcr0_disable(struct clk *clk) -{ - sh7722_mstpcr_start_stop(clk, MSTPCR0, 0); -} - -static void sh7722_mstpcr1_enable(struct clk *clk) -{ - sh7722_mstpcr_start_stop(clk, MSTPCR1, 1); -} - -static void sh7722_mstpcr1_disable(struct clk *clk) +static void sh7722_mstpcr_enable(struct clk *clk) { - sh7722_mstpcr_start_stop(clk, MSTPCR1, 0); + sh7722_mstpcr_start_stop(clk, 1); } -static void sh7722_mstpcr2_enable(struct clk *clk) +static void sh7722_mstpcr_disable(struct clk *clk) { - sh7722_mstpcr_start_stop(clk, MSTPCR2, 1); + sh7722_mstpcr_start_stop(clk, 0); } -static void sh7722_mstpcr2_disable(struct clk *clk) +static void sh7722_mstpcr_recalc(struct clk *clk) { - sh7722_mstpcr_start_stop(clk, MSTPCR2, 0); + if (clk->parent) + clk->rate = clk->parent->rate; } -static struct clk_ops sh7722_mstpcr0_clk_ops = { - .enable = sh7722_mstpcr0_enable, - .disable = sh7722_mstpcr0_disable, -}; - -static struct clk_ops sh7722_mstpcr1_clk_ops = { - .enable = sh7722_mstpcr1_enable, - .disable = sh7722_mstpcr1_disable, +static struct clk_ops sh7722_mstpcr_clk_ops = { + .enable = sh7722_mstpcr_enable, + .disable = sh7722_mstpcr_disable, + .recalc = sh7722_mstpcr_recalc, }; -static struct clk_ops sh7722_mstpcr2_clk_ops = { - .enable = sh7722_mstpcr2_enable, - .disable = sh7722_mstpcr2_disable, -}; - -#define DECLARE_MSTPCRN(regnr, bitnr, bitstr) \ -{ \ - .name = "mstp" __stringify(regnr) bitstr, \ - .arch_flags = bitnr, \ - .ops = &sh7722_mstpcr ## regnr ## _clk_ops, \ +#define MSTPCR(_name, _parent, regnr, bitnr) \ +{ \ + .name = _name, \ + .arch_flags = MSTPCR_ARCH_FLAGS(regnr, bitnr), \ + .ops = (void *)_parent, \ } -#define DECLARE_MSTPCR(regnr) \ - DECLARE_MSTPCRN(regnr, 31, "31"), \ - DECLARE_MSTPCRN(regnr, 30, "30"), \ - DECLARE_MSTPCRN(regnr, 29, "29"), \ - DECLARE_MSTPCRN(regnr, 28, "28"), \ - DECLARE_MSTPCRN(regnr, 27, "27"), \ - DECLARE_MSTPCRN(regnr, 26, "26"), \ - DECLARE_MSTPCRN(regnr, 25, "25"), \ - DECLARE_MSTPCRN(regnr, 24, "24"), \ - DECLARE_MSTPCRN(regnr, 23, "23"), \ - DECLARE_MSTPCRN(regnr, 22, "22"), \ - DECLARE_MSTPCRN(regnr, 21, "21"), \ - DECLARE_MSTPCRN(regnr, 20, "20"), \ - DECLARE_MSTPCRN(regnr, 19, "19"), \ - DECLARE_MSTPCRN(regnr, 18, "18"), \ - DECLARE_MSTPCRN(regnr, 17, "17"), \ - DECLARE_MSTPCRN(regnr, 16, "16"), \ - DECLARE_MSTPCRN(regnr, 15, "15"), \ - DECLARE_MSTPCRN(regnr, 14, "14"), \ - DECLARE_MSTPCRN(regnr, 13, "13"), \ - DECLARE_MSTPCRN(regnr, 12, "12"), \ - DECLARE_MSTPCRN(regnr, 11, "11"), \ - DECLARE_MSTPCRN(regnr, 10, "10"), \ - DECLARE_MSTPCRN(regnr, 9, "09"), \ - DECLARE_MSTPCRN(regnr, 8, "08"), \ - DECLARE_MSTPCRN(regnr, 7, "07"), \ - DECLARE_MSTPCRN(regnr, 6, "06"), \ - DECLARE_MSTPCRN(regnr, 5, "05"), \ - DECLARE_MSTPCRN(regnr, 4, "04"), \ - DECLARE_MSTPCRN(regnr, 3, "03"), \ - DECLARE_MSTPCRN(regnr, 2, "02"), \ - DECLARE_MSTPCRN(regnr, 1, "01"), \ - DECLARE_MSTPCRN(regnr, 0, "00") - -static struct clk sh7722_mstpcr[] = { - DECLARE_MSTPCR(0), - DECLARE_MSTPCR(1), - DECLARE_MSTPCR(2), +static struct clk sh7722_mstpcr_clocks[] = { +#if defined(CONFIG_CPU_SUBTYPE_SH7722) + MSTPCR("uram0", "umem_clk", 0, 28), + MSTPCR("xymem0", "bus_clk", 0, 26), + MSTPCR("tmu0", "peripheral_clk", 0, 15), + MSTPCR("cmt0", "r_clk", 0, 14), + MSTPCR("rwdt0", "r_clk", 0, 13), + MSTPCR("flctl0", "peripheral_clk", 0, 10), + MSTPCR("scif0", "peripheral_clk", 0, 7), + MSTPCR("scif1", "peripheral_clk", 0, 6), + MSTPCR("scif2", "peripheral_clk", 0, 5), + MSTPCR("i2c0", "peripheral_clk", 1, 9), + MSTPCR("rtc0", "r_clk", 1, 8), + MSTPCR("sdhi0", "peripheral_clk", 2, 18), + MSTPCR("keysc0", "r_clk", 2, 14), + MSTPCR("usbf0", "peripheral_clk", 2, 11), + MSTPCR("2dg0", "bus_clk", 2, 9), + MSTPCR("siu0", "bus_clk", 2, 8), + MSTPCR("vou0", "bus_clk", 2, 5), + MSTPCR("jpu0", "bus_clk", 2, 6), + MSTPCR("beu0", "bus_clk", 2, 4), + MSTPCR("ceu0", "bus_clk", 2, 3), + MSTPCR("veu0", "bus_clk", 2, 2), + MSTPCR("vpu0", "bus_clk", 2, 1), + MSTPCR("lcdc0", "bus_clk", 2, 0), +#endif +#if defined(CONFIG_CPU_SUBTYPE_SH7723) + /* See page 60 of Datasheet V1.0: Overview -> Block Diagram */ + MSTPCR("tlb0", "cpu_clk", 0, 31), + MSTPCR("ic0", "cpu_clk", 0, 30), + MSTPCR("oc0", "cpu_clk", 0, 29), + MSTPCR("l2c0", "sh_clk", 0, 28), + MSTPCR("ilmem0", "cpu_clk", 0, 27), + MSTPCR("fpu0", "cpu_clk", 0, 24), + MSTPCR("intc0", "cpu_clk", 0, 22), + MSTPCR("dmac0", "bus_clk", 0, 21), + MSTPCR("sh0", "sh_clk", 0, 20), + MSTPCR("hudi0", "peripheral_clk", 0, 19), + MSTPCR("ubc0", "cpu_clk", 0, 17), + MSTPCR("tmu0", "peripheral_clk", 0, 15), + MSTPCR("cmt0", "r_clk", 0, 14), + MSTPCR("rwdt0", "r_clk", 0, 13), + MSTPCR("dmac1", "bus_clk", 0, 12), + MSTPCR("tmu1", "peripheral_clk", 0, 11), + MSTPCR("flctl0", "peripheral_clk", 0, 10), + MSTPCR("scif0", "peripheral_clk", 0, 9), + MSTPCR("scif1", "peripheral_clk", 0, 8), + MSTPCR("scif2", "peripheral_clk", 0, 7), + MSTPCR("scif3", "bus_clk", 0, 6), + MSTPCR("scif4", "bus_clk", 0, 5), + MSTPCR("scif5", "bus_clk", 0, 4), + MSTPCR("msiof0", "bus_clk", 0, 2), + MSTPCR("msiof1", "bus_clk", 0, 1), + MSTPCR("meram0", "sh_clk", 0, 0), + MSTPCR("i2c0", "peripheral_clk", 1, 9), + MSTPCR("rtc0", "r_clk", 1, 8), + MSTPCR("atapi0", "sh_clk", 2, 28), + MSTPCR("adc0", "peripheral_clk", 2, 28), + MSTPCR("tpu0", "bus_clk", 2, 25), + MSTPCR("irda0", "peripheral_clk", 2, 24), + MSTPCR("tsif0", "bus_clk", 2, 22), + MSTPCR("icb0", "bus_clk", 2, 21), + MSTPCR("sdhi0", "bus_clk", 2, 18), + MSTPCR("sdhi1", "bus_clk", 2, 17), + MSTPCR("keysc0", "r_clk", 2, 14), + MSTPCR("usb0", "bus_clk", 2, 11), + MSTPCR("2dg0", "bus_clk", 2, 10), + MSTPCR("siu0", "bus_clk", 2, 8), + MSTPCR("veu1", "bus_clk", 2, 6), + MSTPCR("vou0", "bus_clk", 2, 5), + MSTPCR("beu0", "bus_clk", 2, 4), + MSTPCR("ceu0", "bus_clk", 2, 3), + MSTPCR("veu0", "bus_clk", 2, 2), + MSTPCR("vpu0", "bus_clk", 2, 1), + MSTPCR("lcdc0", "bus_clk", 2, 0), +#endif +#if defined(CONFIG_CPU_SUBTYPE_SH7343) + MSTPCR("uram0", "umem_clk", 0, 28), + MSTPCR("xymem0", "bus_clk", 0, 26), + MSTPCR("tmu0", "peripheral_clk", 0, 15), + MSTPCR("cmt0", "r_clk", 0, 14), + MSTPCR("rwdt0", "r_clk", 0, 13), + MSTPCR("scif0", "peripheral_clk", 0, 7), + MSTPCR("scif1", "peripheral_clk", 0, 6), + MSTPCR("scif2", "peripheral_clk", 0, 5), + MSTPCR("scif3", "peripheral_clk", 0, 4), + MSTPCR("i2c0", "peripheral_clk", 1, 9), + MSTPCR("i2c1", "peripheral_clk", 1, 8), + MSTPCR("sdhi0", "peripheral_clk", 2, 18), + MSTPCR("keysc0", "r_clk", 2, 14), + MSTPCR("usbf0", "peripheral_clk", 2, 11), + MSTPCR("siu0", "bus_clk", 2, 8), + MSTPCR("jpu0", "bus_clk", 2, 6), + MSTPCR("vou0", "bus_clk", 2, 5), + MSTPCR("beu0", "bus_clk", 2, 4), + MSTPCR("ceu0", "bus_clk", 2, 3), + MSTPCR("veu0", "bus_clk", 2, 2), + MSTPCR("vpu0", "bus_clk", 2, 1), + MSTPCR("lcdc0", "bus_clk", 2, 0), +#endif +#if defined(CONFIG_CPU_SUBTYPE_SH7366) + /* See page 52 of Datasheet V0.40: Overview -> Block Diagram */ + MSTPCR("tlb0", "cpu_clk", 0, 31), + MSTPCR("ic0", "cpu_clk", 0, 30), + MSTPCR("oc0", "cpu_clk", 0, 29), + MSTPCR("rsmem0", "sh_clk", 0, 28), + MSTPCR("xymem0", "cpu_clk", 0, 26), + MSTPCR("intc30", "peripheral_clk", 0, 23), + MSTPCR("intc0", "peripheral_clk", 0, 22), + MSTPCR("dmac0", "bus_clk", 0, 21), + MSTPCR("sh0", "sh_clk", 0, 20), + MSTPCR("hudi0", "peripheral_clk", 0, 19), + MSTPCR("ubc0", "cpu_clk", 0, 17), + MSTPCR("tmu0", "peripheral_clk", 0, 15), + MSTPCR("cmt0", "r_clk", 0, 14), + MSTPCR("rwdt0", "r_clk", 0, 13), + MSTPCR("flctl0", "peripheral_clk", 0, 10), + MSTPCR("scif0", "peripheral_clk", 0, 7), + MSTPCR("scif1", "bus_clk", 0, 6), + MSTPCR("scif2", "bus_clk", 0, 5), + MSTPCR("msiof0", "peripheral_clk", 0, 2), + MSTPCR("sbr0", "peripheral_clk", 0, 1), + MSTPCR("i2c0", "peripheral_clk", 1, 9), + MSTPCR("icb0", "bus_clk", 2, 27), + MSTPCR("meram0", "sh_clk", 2, 26), + MSTPCR("dacc0", "peripheral_clk", 2, 24), + MSTPCR("dacy0", "peripheral_clk", 2, 23), + MSTPCR("tsif0", "bus_clk", 2, 22), + MSTPCR("sdhi0", "bus_clk", 2, 18), + MSTPCR("mmcif0", "bus_clk", 2, 17), + MSTPCR("usb0", "bus_clk", 2, 11), + MSTPCR("siu0", "bus_clk", 2, 8), + MSTPCR("veu1", "bus_clk", 2, 7), + MSTPCR("vou0", "bus_clk", 2, 5), + MSTPCR("beu0", "bus_clk", 2, 4), + MSTPCR("ceu0", "bus_clk", 2, 3), + MSTPCR("veu0", "bus_clk", 2, 2), + MSTPCR("vpu0", "bus_clk", 2, 1), + MSTPCR("lcdc0", "bus_clk", 2, 0), +#endif }; static struct clk *sh7722_clocks[] = { @@ -710,21 +815,30 @@ arch_init_clk_ops(struct clk_ops **ops, int type) int __init arch_clk_init(void) { - struct clk *master; + struct clk *clk; int i; - master = clk_get(NULL, "master_clk"); + clk = clk_get(NULL, "master_clk"); for (i = 0; i < ARRAY_SIZE(sh7722_clocks); i++) { pr_debug( "Registering clock '%s'\n", sh7722_clocks[i]->name); - sh7722_clocks[i]->parent = master; + sh7722_clocks[i]->parent = clk; clk_register(sh7722_clocks[i]); } - clk_put(master); - - for (i = 0; i < ARRAY_SIZE(sh7722_mstpcr); i++) { - pr_debug( "Registering mstpcr '%s'\n", sh7722_mstpcr[i].name); - clk_register(&sh7722_mstpcr[i]); + clk_put(clk); + + clk_register(&sh7722_r_clock); + + for (i = 0; i < ARRAY_SIZE(sh7722_mstpcr_clocks); i++) { + pr_debug( "Registering mstpcr clock '%s'\n", + sh7722_mstpcr_clocks[i].name); + clk = clk_get(NULL, (void *) sh7722_mstpcr_clocks[i].ops); + sh7722_mstpcr_clocks[i].parent = clk; + sh7722_mstpcr_clocks[i].ops = &sh7722_mstpcr_clk_ops; + clk_register(&sh7722_mstpcr_clocks[i]); + clk_put(clk); } + clk_recalc_rate(&sh7722_r_clock); /* make sure rate gets propagated */ + return 0; } diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7343.c b/arch/sh/kernel/cpu/sh4a/setup-sh7343.c index 78881b4214da8e8a94ad366e0e3843cc586f9360..0623e377f488c7f30b2d388b470a8ac49bd879ef 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7343.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7343.c @@ -30,6 +30,7 @@ static struct resource iic0_resources[] = { static struct platform_device iic0_device = { .name = "i2c-sh_mobile", + .id = 0, /* "i2c0" clock */ .num_resources = ARRAY_SIZE(iic0_resources), .resource = iic0_resources, }; @@ -50,6 +51,7 @@ static struct resource iic1_resources[] = { static struct platform_device iic1_device = { .name = "i2c-sh_mobile", + .id = 1, /* "i2c1" clock */ .num_resources = ARRAY_SIZE(iic1_resources), .resource = iic1_resources, }; @@ -115,7 +117,22 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xffe00000, .flags = UPF_BOOT_AUTOCONF, .type = PORT_SCIF, - .irqs = { 80, 81, 83, 82 }, + .irqs = { 80, 80, 80, 80 }, + }, { + .mapbase = 0xffe10000, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_SCIF, + .irqs = { 81, 81, 81, 81 }, + }, { + .mapbase = 0xffe20000, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_SCIF, + .irqs = { 82, 82, 82, 82 }, + }, { + .mapbase = 0xffe30000, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_SCIF, + .irqs = { 83, 83, 83, 83 }, }, { .flags = 0, } @@ -139,18 +156,10 @@ static struct platform_device *sh7343_devices[] __initdata = { static int __init sh7343_devices_setup(void) { - clk_always_enable("mstp031"); /* TLB */ - clk_always_enable("mstp030"); /* IC */ - clk_always_enable("mstp029"); /* OC */ - clk_always_enable("mstp028"); /* URAM */ - clk_always_enable("mstp026"); /* XYMEM */ - clk_always_enable("mstp023"); /* INTC3 */ - clk_always_enable("mstp022"); /* INTC */ - clk_always_enable("mstp020"); /* SuperHyway */ - clk_always_enable("mstp109"); /* I2C0 */ - clk_always_enable("mstp108"); /* I2C1 */ - clk_always_enable("mstp202"); /* VEU */ - clk_always_enable("mstp201"); /* VPU */ + clk_always_enable("uram0"); /* URAM */ + clk_always_enable("xymem0"); /* XYMEM */ + clk_always_enable("veu0"); /* VEU */ + clk_always_enable("vpu0"); /* VPU */ platform_resource_setup_memory(&vpu_device, "vpu", 1 << 20); platform_resource_setup_memory(&veu_device, "veu", 2 << 20); @@ -171,7 +180,7 @@ enum { MMC_ERR, MMC_TRAN, MMC_FSTAT, MMC_FRDY, DMAC4, DMAC5, DMAC_DADERR, KEYSC, - SCIF, SCIF1, SCIF2, SCIF3, SCIF4, + SCIF, SCIF1, SCIF2, SCIF3, SIOF0, SIOF1, SIO, FLCTL_FLSTEI, FLCTL_FLENDI, FLCTL_FLTREQ0I, FLCTL_FLTREQ1I, I2C0_ALI, I2C0_TACKI, I2C0_WAITI, I2C0_DTEI, diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7366.c b/arch/sh/kernel/cpu/sh4a/setup-sh7366.c index e17db39b97aa17e0065f22c396b0723b81a6b228..839ae97a7fd2de8e708bd7fa82f484d012edae42 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7366.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7366.c @@ -32,6 +32,7 @@ static struct resource iic_resources[] = { static struct platform_device iic_device = { .name = "i2c-sh_mobile", + .id = 0, /* "i2c0" clock */ .num_resources = ARRAY_SIZE(iic_resources), .resource = iic_resources, }; @@ -176,19 +177,11 @@ static struct platform_device *sh7366_devices[] __initdata = { static int __init sh7366_devices_setup(void) { - clk_always_enable("mstp031"); /* TLB */ - clk_always_enable("mstp030"); /* IC */ - clk_always_enable("mstp029"); /* OC */ - clk_always_enable("mstp028"); /* RSMEM */ - clk_always_enable("mstp026"); /* XYMEM */ - clk_always_enable("mstp023"); /* INTC3 */ - clk_always_enable("mstp022"); /* INTC */ - clk_always_enable("mstp020"); /* SuperHyway */ - clk_always_enable("mstp109"); /* I2C */ - clk_always_enable("mstp211"); /* USB */ - clk_always_enable("mstp207"); /* VEU-2 */ - clk_always_enable("mstp202"); /* VEU-1 */ - clk_always_enable("mstp201"); /* VPU */ + clk_always_enable("rsmem0"); /* RSMEM */ + clk_always_enable("xymem0"); /* XYMEM */ + clk_always_enable("veu1"); /* VEU-2 */ + clk_always_enable("veu0"); /* VEU-1 */ + clk_always_enable("vpu0"); /* VPU */ platform_resource_setup_memory(&vpu_device, "vpu", 2 << 20); platform_resource_setup_memory(&veu0_device, "veu0", 2 << 20); diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c index ef77ee1d9f5320705b66cdb92df38ddd8ebe04ef..50cf6838ec4144fc0fbbddfcdb1cad600371b26e 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c @@ -62,7 +62,7 @@ static struct resource usbf_resources[] = { static struct platform_device usbf_device = { .name = "m66592_udc", - .id = -1, + .id = 0, /* "usbf0" clock */ .dev = { .dma_mask = NULL, .coherent_dma_mask = 0xffffffff, @@ -87,6 +87,7 @@ static struct resource iic_resources[] = { static struct platform_device iic_device = { .name = "i2c-sh_mobile", + .id = 0, /* "i2c0" clock */ .num_resources = ARRAY_SIZE(iic_resources), .resource = iic_resources, }; @@ -147,6 +148,34 @@ static struct platform_device veu_device = { .num_resources = ARRAY_SIZE(veu_resources), }; +static struct uio_info jpu_platform_data = { + .name = "JPU", + .version = "0", + .irq = 27, +}; + +static struct resource jpu_resources[] = { + [0] = { + .name = "JPU", + .start = 0xfea00000, + .end = 0xfea102d0, + .flags = IORESOURCE_MEM, + }, + [1] = { + /* place holder for contiguous memory */ + }, +}; + +static struct platform_device jpu_device = { + .name = "uio_pdrv_genirq", + .id = 2, + .dev = { + .platform_data = &jpu_platform_data, + }, + .resource = jpu_resources, + .num_resources = ARRAY_SIZE(jpu_resources), +}; + static struct plat_sci_port sci_platform_data[] = { { .mapbase = 0xffe00000, @@ -186,24 +215,21 @@ static struct platform_device *sh7722_devices[] __initdata = { &sci_device, &vpu_device, &veu_device, + &jpu_device, }; static int __init sh7722_devices_setup(void) { - clk_always_enable("mstp031"); /* TLB */ - clk_always_enable("mstp030"); /* IC */ - clk_always_enable("mstp029"); /* OC */ - clk_always_enable("mstp028"); /* URAM */ - clk_always_enable("mstp026"); /* XYMEM */ - clk_always_enable("mstp022"); /* INTC */ - clk_always_enable("mstp020"); /* SuperHyway */ - clk_always_enable("mstp109"); /* I2C */ - clk_always_enable("mstp211"); /* USB */ - clk_always_enable("mstp202"); /* VEU */ - clk_always_enable("mstp201"); /* VPU */ + clk_always_enable("uram0"); /* URAM */ + clk_always_enable("xymem0"); /* XYMEM */ + clk_always_enable("rtc0"); /* RTC */ + clk_always_enable("veu0"); /* VEU */ + clk_always_enable("vpu0"); /* VPU */ + clk_always_enable("jpu0"); /* JPU */ platform_resource_setup_memory(&vpu_device, "vpu", 1 << 20); platform_resource_setup_memory(&veu_device, "veu", 2 << 20); + platform_resource_setup_memory(&jpu_device, "jpu", 2 << 20); return platform_add_devices(sh7722_devices, ARRAY_SIZE(sh7722_devices)); diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7723.c b/arch/sh/kernel/cpu/sh4a/setup-sh7723.c index 6d9e6972cfc9d8d1cecf57bffb3fe8ab9f72136e..849770d780aed9e5b2de0479b32887c80f374ebf 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7723.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7723.c @@ -215,6 +215,7 @@ static struct resource iic_resources[] = { static struct platform_device iic_device = { .name = "i2c-sh_mobile", + .id = 0, /* "i2c0" clock */ .num_resources = ARRAY_SIZE(iic_resources), .resource = iic_resources, }; @@ -231,19 +232,11 @@ static struct platform_device *sh7723_devices[] __initdata = { static int __init sh7723_devices_setup(void) { - clk_always_enable("mstp031"); /* TLB */ - clk_always_enable("mstp030"); /* IC */ - clk_always_enable("mstp029"); /* OC */ - clk_always_enable("mstp024"); /* FPU */ - clk_always_enable("mstp022"); /* INTC */ - clk_always_enable("mstp020"); /* SuperHyway */ - clk_always_enable("mstp000"); /* MERAM */ - clk_always_enable("mstp109"); /* I2C */ - clk_always_enable("mstp108"); /* RTC */ - clk_always_enable("mstp211"); /* USB */ - clk_always_enable("mstp206"); /* VEU2H1 */ - clk_always_enable("mstp202"); /* VEU2H0 */ - clk_always_enable("mstp201"); /* VPU */ + clk_always_enable("meram0"); /* MERAM */ + clk_always_enable("rtc0"); /* RTC */ + clk_always_enable("veu1"); /* VEU2H1 */ + clk_always_enable("veu0"); /* VEU2H0 */ + clk_always_enable("vpu0"); /* VPU */ platform_resource_setup_memory(&vpu_device, "vpu", 2 << 20); platform_resource_setup_memory(&veu0_device, "veu0", 2 << 20); diff --git a/arch/sh/kernel/debugtraps.S b/arch/sh/kernel/debugtraps.S index 13b66746410ac249f69800936cc1849a1e5ca52f..591741383ee6addd2fe537aa800d869b24ac26c0 100644 --- a/arch/sh/kernel/debugtraps.S +++ b/arch/sh/kernel/debugtraps.S @@ -3,7 +3,7 @@ * * Debug trap jump tables for SuperH * - * Copyright (C) 2006 Paul Mundt + * Copyright (C) 2006 - 2008 Paul Mundt * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -12,12 +12,13 @@ #include #include -#if !defined(CONFIG_SH_KGDB) -#define kgdb_handle_exception debug_trap_handler +#if !defined(CONFIG_KGDB) +#define breakpoint_trap_handler debug_trap_handler +#define singlestep_trap_handler debug_trap_handler #endif #if !defined(CONFIG_SH_STANDARD_BIOS) -#define sh_bios_handler debug_trap_handler +#define sh_bios_handler debug_trap_handler #endif .data @@ -35,7 +36,7 @@ ENTRY(debug_trap_table) .long debug_trap_handler /* 0x39 */ .long debug_trap_handler /* 0x3a */ .long debug_trap_handler /* 0x3b */ - .long kgdb_handle_exception /* 0x3c */ - .long debug_trap_handler /* 0x3d */ + .long breakpoint_trap_handler /* 0x3c */ + .long singlestep_trap_handler /* 0x3d */ .long bug_trap_handler /* 0x3e */ .long sh_bios_handler /* 0x3f */ diff --git a/arch/sh/kernel/disassemble.c b/arch/sh/kernel/disassemble.c new file mode 100644 index 0000000000000000000000000000000000000000..64d5d8dded7c1546b1c1c45a8ff6b55f55c84502 --- /dev/null +++ b/arch/sh/kernel/disassemble.c @@ -0,0 +1,573 @@ +/* + * Disassemble SuperH instructions. + * + * Copyright (C) 1999 kaz Kojima + * Copyright (C) 2008 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include + +/* + * Format of an instruction in memory. + */ +typedef enum { + HEX_0, HEX_1, HEX_2, HEX_3, HEX_4, HEX_5, HEX_6, HEX_7, + HEX_8, HEX_9, HEX_A, HEX_B, HEX_C, HEX_D, HEX_E, HEX_F, + REG_N, REG_M, REG_NM, REG_B, + BRANCH_12, BRANCH_8, + DISP_8, DISP_4, + IMM_4, IMM_4BY2, IMM_4BY4, PCRELIMM_8BY2, PCRELIMM_8BY4, + IMM_8, IMM_8BY2, IMM_8BY4, +} sh_nibble_type; + +typedef enum { + A_END, A_BDISP12, A_BDISP8, + A_DEC_M, A_DEC_N, + A_DISP_GBR, A_DISP_PC, A_DISP_REG_M, A_DISP_REG_N, + A_GBR, + A_IMM, + A_INC_M, A_INC_N, + A_IND_M, A_IND_N, A_IND_R0_REG_M, A_IND_R0_REG_N, + A_MACH, A_MACL, + A_PR, A_R0, A_R0_GBR, A_REG_M, A_REG_N, A_REG_B, + A_SR, A_VBR, A_SSR, A_SPC, A_SGR, A_DBR, + F_REG_N, F_REG_M, D_REG_N, D_REG_M, + X_REG_N, /* Only used for argument parsing */ + X_REG_M, /* Only used for argument parsing */ + DX_REG_N, DX_REG_M, V_REG_N, V_REG_M, + FD_REG_N, + XMTRX_M4, + F_FR0, + FPUL_N, FPUL_M, FPSCR_N, FPSCR_M, +} sh_arg_type; + +static struct sh_opcode_info { + char *name; + sh_arg_type arg[7]; + sh_nibble_type nibbles[4]; +} sh_table[] = { + {"add",{A_IMM,A_REG_N},{HEX_7,REG_N,IMM_8}}, + {"add",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_C}}, + {"addc",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_E}}, + {"addv",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_F}}, + {"and",{A_IMM,A_R0},{HEX_C,HEX_9,IMM_8}}, + {"and",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_9}}, + {"and.b",{A_IMM,A_R0_GBR},{HEX_C,HEX_D,IMM_8}}, + {"bra",{A_BDISP12},{HEX_A,BRANCH_12}}, + {"bsr",{A_BDISP12},{HEX_B,BRANCH_12}}, + {"bt",{A_BDISP8},{HEX_8,HEX_9,BRANCH_8}}, + {"bf",{A_BDISP8},{HEX_8,HEX_B,BRANCH_8}}, + {"bt.s",{A_BDISP8},{HEX_8,HEX_D,BRANCH_8}}, + {"bt/s",{A_BDISP8},{HEX_8,HEX_D,BRANCH_8}}, + {"bf.s",{A_BDISP8},{HEX_8,HEX_F,BRANCH_8}}, + {"bf/s",{A_BDISP8},{HEX_8,HEX_F,BRANCH_8}}, + {"clrmac",{0},{HEX_0,HEX_0,HEX_2,HEX_8}}, + {"clrs",{0},{HEX_0,HEX_0,HEX_4,HEX_8}}, + {"clrt",{0},{HEX_0,HEX_0,HEX_0,HEX_8}}, + {"cmp/eq",{A_IMM,A_R0},{HEX_8,HEX_8,IMM_8}}, + {"cmp/eq",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_0}}, + {"cmp/ge",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_3}}, + {"cmp/gt",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_7}}, + {"cmp/hi",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_6}}, + {"cmp/hs",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_2}}, + {"cmp/pl",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_5}}, + {"cmp/pz",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_1}}, + {"cmp/str",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_C}}, + {"div0s",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_7}}, + {"div0u",{0},{HEX_0,HEX_0,HEX_1,HEX_9}}, + {"div1",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_4}}, + {"exts.b",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_E}}, + {"exts.w",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_F}}, + {"extu.b",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_C}}, + {"extu.w",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_D}}, + {"jmp",{A_IND_N},{HEX_4,REG_N,HEX_2,HEX_B}}, + {"jsr",{A_IND_N},{HEX_4,REG_N,HEX_0,HEX_B}}, + {"ldc",{A_REG_N,A_SR},{HEX_4,REG_N,HEX_0,HEX_E}}, + {"ldc",{A_REG_N,A_GBR},{HEX_4,REG_N,HEX_1,HEX_E}}, + {"ldc",{A_REG_N,A_VBR},{HEX_4,REG_N,HEX_2,HEX_E}}, + {"ldc",{A_REG_N,A_SSR},{HEX_4,REG_N,HEX_3,HEX_E}}, + {"ldc",{A_REG_N,A_SPC},{HEX_4,REG_N,HEX_4,HEX_E}}, + {"ldc",{A_REG_N,A_DBR},{HEX_4,REG_N,HEX_7,HEX_E}}, + {"ldc",{A_REG_N,A_REG_B},{HEX_4,REG_N,REG_B,HEX_E}}, + {"ldc.l",{A_INC_N,A_SR},{HEX_4,REG_N,HEX_0,HEX_7}}, + {"ldc.l",{A_INC_N,A_GBR},{HEX_4,REG_N,HEX_1,HEX_7}}, + {"ldc.l",{A_INC_N,A_VBR},{HEX_4,REG_N,HEX_2,HEX_7}}, + {"ldc.l",{A_INC_N,A_SSR},{HEX_4,REG_N,HEX_3,HEX_7}}, + {"ldc.l",{A_INC_N,A_SPC},{HEX_4,REG_N,HEX_4,HEX_7}}, + {"ldc.l",{A_INC_N,A_DBR},{HEX_4,REG_N,HEX_7,HEX_7}}, + {"ldc.l",{A_INC_N,A_REG_B},{HEX_4,REG_N,REG_B,HEX_7}}, + {"lds",{A_REG_N,A_MACH},{HEX_4,REG_N,HEX_0,HEX_A}}, + {"lds",{A_REG_N,A_MACL},{HEX_4,REG_N,HEX_1,HEX_A}}, + {"lds",{A_REG_N,A_PR},{HEX_4,REG_N,HEX_2,HEX_A}}, + {"lds",{A_REG_M,FPUL_N},{HEX_4,REG_M,HEX_5,HEX_A}}, + {"lds",{A_REG_M,FPSCR_N},{HEX_4,REG_M,HEX_6,HEX_A}}, + {"lds.l",{A_INC_N,A_MACH},{HEX_4,REG_N,HEX_0,HEX_6}}, + {"lds.l",{A_INC_N,A_MACL},{HEX_4,REG_N,HEX_1,HEX_6}}, + {"lds.l",{A_INC_N,A_PR},{HEX_4,REG_N,HEX_2,HEX_6}}, + {"lds.l",{A_INC_M,FPUL_N},{HEX_4,REG_M,HEX_5,HEX_6}}, + {"lds.l",{A_INC_M,FPSCR_N},{HEX_4,REG_M,HEX_6,HEX_6}}, + {"ldtlb",{0},{HEX_0,HEX_0,HEX_3,HEX_8}}, + {"mac.w",{A_INC_M,A_INC_N},{HEX_4,REG_N,REG_M,HEX_F}}, + {"mov",{A_IMM,A_REG_N},{HEX_E,REG_N,IMM_8}}, + {"mov",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_3}}, + {"mov.b",{ A_REG_M,A_IND_R0_REG_N},{HEX_0,REG_N,REG_M,HEX_4}}, + {"mov.b",{ A_REG_M,A_DEC_N},{HEX_2,REG_N,REG_M,HEX_4}}, + {"mov.b",{ A_REG_M,A_IND_N},{HEX_2,REG_N,REG_M,HEX_0}}, + {"mov.b",{A_DISP_REG_M,A_R0},{HEX_8,HEX_4,REG_M,IMM_4}}, + {"mov.b",{A_DISP_GBR,A_R0},{HEX_C,HEX_4,IMM_8}}, + {"mov.b",{A_IND_R0_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_C}}, + {"mov.b",{A_INC_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_4}}, + {"mov.b",{A_IND_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_0}}, + {"mov.b",{A_R0,A_DISP_REG_M},{HEX_8,HEX_0,REG_M,IMM_4}}, + {"mov.b",{A_R0,A_DISP_GBR},{HEX_C,HEX_0,IMM_8}}, + {"mov.l",{ A_REG_M,A_DISP_REG_N},{HEX_1,REG_N,REG_M,IMM_4BY4}}, + {"mov.l",{ A_REG_M,A_IND_R0_REG_N},{HEX_0,REG_N,REG_M,HEX_6}}, + {"mov.l",{ A_REG_M,A_DEC_N},{HEX_2,REG_N,REG_M,HEX_6}}, + {"mov.l",{ A_REG_M,A_IND_N},{HEX_2,REG_N,REG_M,HEX_2}}, + {"mov.l",{A_DISP_REG_M,A_REG_N},{HEX_5,REG_N,REG_M,IMM_4BY4}}, + {"mov.l",{A_DISP_GBR,A_R0},{HEX_C,HEX_6,IMM_8BY4}}, + {"mov.l",{A_DISP_PC,A_REG_N},{HEX_D,REG_N,PCRELIMM_8BY4}}, + {"mov.l",{A_IND_R0_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_E}}, + {"mov.l",{A_INC_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_6}}, + {"mov.l",{A_IND_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_2}}, + {"mov.l",{A_R0,A_DISP_GBR},{HEX_C,HEX_2,IMM_8BY4}}, + {"mov.w",{ A_REG_M,A_IND_R0_REG_N},{HEX_0,REG_N,REG_M,HEX_5}}, + {"mov.w",{ A_REG_M,A_DEC_N},{HEX_2,REG_N,REG_M,HEX_5}}, + {"mov.w",{ A_REG_M,A_IND_N},{HEX_2,REG_N,REG_M,HEX_1}}, + {"mov.w",{A_DISP_REG_M,A_R0},{HEX_8,HEX_5,REG_M,IMM_4BY2}}, + {"mov.w",{A_DISP_GBR,A_R0},{HEX_C,HEX_5,IMM_8BY2}}, + {"mov.w",{A_DISP_PC,A_REG_N},{HEX_9,REG_N,PCRELIMM_8BY2}}, + {"mov.w",{A_IND_R0_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_D}}, + {"mov.w",{A_INC_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_5}}, + {"mov.w",{A_IND_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_1}}, + {"mov.w",{A_R0,A_DISP_REG_M},{HEX_8,HEX_1,REG_M,IMM_4BY2}}, + {"mov.w",{A_R0,A_DISP_GBR},{HEX_C,HEX_1,IMM_8BY2}}, + {"mova",{A_DISP_PC,A_R0},{HEX_C,HEX_7,PCRELIMM_8BY4}}, + {"movca.l",{A_R0,A_IND_N},{HEX_0,REG_N,HEX_C,HEX_3}}, + {"movt",{A_REG_N},{HEX_0,REG_N,HEX_2,HEX_9}}, + {"muls",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_F}}, + {"mul.l",{ A_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_7}}, + {"mulu",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_E}}, + {"neg",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_B}}, + {"negc",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_A}}, + {"nop",{0},{HEX_0,HEX_0,HEX_0,HEX_9}}, + {"not",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_7}}, + {"ocbi",{A_IND_N},{HEX_0,REG_N,HEX_9,HEX_3}}, + {"ocbp",{A_IND_N},{HEX_0,REG_N,HEX_A,HEX_3}}, + {"ocbwb",{A_IND_N},{HEX_0,REG_N,HEX_B,HEX_3}}, + {"or",{A_IMM,A_R0},{HEX_C,HEX_B,IMM_8}}, + {"or",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_B}}, + {"or.b",{A_IMM,A_R0_GBR},{HEX_C,HEX_F,IMM_8}}, + {"pref",{A_IND_N},{HEX_0,REG_N,HEX_8,HEX_3}}, + {"rotcl",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_4}}, + {"rotcr",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_5}}, + {"rotl",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_4}}, + {"rotr",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_5}}, + {"rte",{0},{HEX_0,HEX_0,HEX_2,HEX_B}}, + {"rts",{0},{HEX_0,HEX_0,HEX_0,HEX_B}}, + {"sets",{0},{HEX_0,HEX_0,HEX_5,HEX_8}}, + {"sett",{0},{HEX_0,HEX_0,HEX_1,HEX_8}}, + {"shad",{ A_REG_M,A_REG_N},{HEX_4,REG_N,REG_M,HEX_C}}, + {"shld",{ A_REG_M,A_REG_N},{HEX_4,REG_N,REG_M,HEX_D}}, + {"shal",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_0}}, + {"shar",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_1}}, + {"shll",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_0}}, + {"shll16",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_8}}, + {"shll2",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_8}}, + {"shll8",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_8}}, + {"shlr",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_1}}, + {"shlr16",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_9}}, + {"shlr2",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_9}}, + {"shlr8",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_9}}, + {"sleep",{0},{HEX_0,HEX_0,HEX_1,HEX_B}}, + {"stc",{A_SR,A_REG_N},{HEX_0,REG_N,HEX_0,HEX_2}}, + {"stc",{A_GBR,A_REG_N},{HEX_0,REG_N,HEX_1,HEX_2}}, + {"stc",{A_VBR,A_REG_N},{HEX_0,REG_N,HEX_2,HEX_2}}, + {"stc",{A_SSR,A_REG_N},{HEX_0,REG_N,HEX_3,HEX_2}}, + {"stc",{A_SPC,A_REG_N},{HEX_0,REG_N,HEX_4,HEX_2}}, + {"stc",{A_SGR,A_REG_N},{HEX_0,REG_N,HEX_6,HEX_2}}, + {"stc",{A_DBR,A_REG_N},{HEX_0,REG_N,HEX_7,HEX_2}}, + {"stc",{A_REG_B,A_REG_N},{HEX_0,REG_N,REG_B,HEX_2}}, + {"stc.l",{A_SR,A_DEC_N},{HEX_4,REG_N,HEX_0,HEX_3}}, + {"stc.l",{A_GBR,A_DEC_N},{HEX_4,REG_N,HEX_1,HEX_3}}, + {"stc.l",{A_VBR,A_DEC_N},{HEX_4,REG_N,HEX_2,HEX_3}}, + {"stc.l",{A_SSR,A_DEC_N},{HEX_4,REG_N,HEX_3,HEX_3}}, + {"stc.l",{A_SPC,A_DEC_N},{HEX_4,REG_N,HEX_4,HEX_3}}, + {"stc.l",{A_SGR,A_DEC_N},{HEX_4,REG_N,HEX_6,HEX_3}}, + {"stc.l",{A_DBR,A_DEC_N},{HEX_4,REG_N,HEX_7,HEX_3}}, + {"stc.l",{A_REG_B,A_DEC_N},{HEX_4,REG_N,REG_B,HEX_3}}, + {"sts",{A_MACH,A_REG_N},{HEX_0,REG_N,HEX_0,HEX_A}}, + {"sts",{A_MACL,A_REG_N},{HEX_0,REG_N,HEX_1,HEX_A}}, + {"sts",{A_PR,A_REG_N},{HEX_0,REG_N,HEX_2,HEX_A}}, + {"sts",{FPUL_M,A_REG_N},{HEX_0,REG_N,HEX_5,HEX_A}}, + {"sts",{FPSCR_M,A_REG_N},{HEX_0,REG_N,HEX_6,HEX_A}}, + {"sts.l",{A_MACH,A_DEC_N},{HEX_4,REG_N,HEX_0,HEX_2}}, + {"sts.l",{A_MACL,A_DEC_N},{HEX_4,REG_N,HEX_1,HEX_2}}, + {"sts.l",{A_PR,A_DEC_N},{HEX_4,REG_N,HEX_2,HEX_2}}, + {"sts.l",{FPUL_M,A_DEC_N},{HEX_4,REG_N,HEX_5,HEX_2}}, + {"sts.l",{FPSCR_M,A_DEC_N},{HEX_4,REG_N,HEX_6,HEX_2}}, + {"sub",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_8}}, + {"subc",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_A}}, + {"subv",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_B}}, + {"swap.b",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_8}}, + {"swap.w",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_9}}, + {"tas.b",{A_IND_N},{HEX_4,REG_N,HEX_1,HEX_B}}, + {"trapa",{A_IMM},{HEX_C,HEX_3,IMM_8}}, + {"tst",{A_IMM,A_R0},{HEX_C,HEX_8,IMM_8}}, + {"tst",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_8}}, + {"tst.b",{A_IMM,A_R0_GBR},{HEX_C,HEX_C,IMM_8}}, + {"xor",{A_IMM,A_R0},{HEX_C,HEX_A,IMM_8}}, + {"xor",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_A}}, + {"xor.b",{A_IMM,A_R0_GBR},{HEX_C,HEX_E,IMM_8}}, + {"xtrct",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_D}}, + {"mul.l",{ A_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_7}}, + {"dt",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_0}}, + {"dmuls.l",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_D}}, + {"dmulu.l",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_5}}, + {"mac.l",{A_INC_M,A_INC_N},{HEX_0,REG_N,REG_M,HEX_F}}, + {"braf",{A_REG_N},{HEX_0,REG_N,HEX_2,HEX_3}}, + {"bsrf",{A_REG_N},{HEX_0,REG_N,HEX_0,HEX_3}}, + {"fabs",{FD_REG_N},{HEX_F,REG_N,HEX_5,HEX_D}}, + {"fadd",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_0}}, + {"fadd",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_0}}, + {"fcmp/eq",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_4}}, + {"fcmp/eq",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_4}}, + {"fcmp/gt",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_5}}, + {"fcmp/gt",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_5}}, + {"fcnvds",{D_REG_N,FPUL_M},{HEX_F,REG_N,HEX_B,HEX_D}}, + {"fcnvsd",{FPUL_M,D_REG_N},{HEX_F,REG_N,HEX_A,HEX_D}}, + {"fdiv",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_3}}, + {"fdiv",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_3}}, + {"fipr",{V_REG_M,V_REG_N},{HEX_F,REG_NM,HEX_E,HEX_D}}, + {"fldi0",{F_REG_N},{HEX_F,REG_N,HEX_8,HEX_D}}, + {"fldi1",{F_REG_N},{HEX_F,REG_N,HEX_9,HEX_D}}, + {"flds",{F_REG_N,FPUL_M},{HEX_F,REG_N,HEX_1,HEX_D}}, + {"float",{FPUL_M,FD_REG_N},{HEX_F,REG_N,HEX_2,HEX_D}}, + {"fmac",{F_FR0,F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_E}}, + {"fmov",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_C}}, + {"fmov",{DX_REG_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_C}}, + {"fmov",{A_IND_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_8}}, + {"fmov",{A_IND_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_8}}, + {"fmov",{F_REG_M,A_IND_N},{HEX_F,REG_N,REG_M,HEX_A}}, + {"fmov",{DX_REG_M,A_IND_N},{HEX_F,REG_N,REG_M,HEX_A}}, + {"fmov",{A_INC_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_9}}, + {"fmov",{A_INC_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_9}}, + {"fmov",{F_REG_M,A_DEC_N},{HEX_F,REG_N,REG_M,HEX_B}}, + {"fmov",{DX_REG_M,A_DEC_N},{HEX_F,REG_N,REG_M,HEX_B}}, + {"fmov",{A_IND_R0_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_6}}, + {"fmov",{A_IND_R0_REG_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_6}}, + {"fmov",{F_REG_M,A_IND_R0_REG_N},{HEX_F,REG_N,REG_M,HEX_7}}, + {"fmov",{DX_REG_M,A_IND_R0_REG_N},{HEX_F,REG_N,REG_M,HEX_7}}, + {"fmov.d",{A_IND_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_8}}, + {"fmov.d",{DX_REG_M,A_IND_N},{HEX_F,REG_N,REG_M,HEX_A}}, + {"fmov.d",{A_INC_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_9}}, + {"fmov.d",{DX_REG_M,A_DEC_N},{HEX_F,REG_N,REG_M,HEX_B}}, + {"fmov.d",{A_IND_R0_REG_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_6}}, + {"fmov.d",{DX_REG_M,A_IND_R0_REG_N},{HEX_F,REG_N,REG_M,HEX_7}}, + {"fmov.s",{A_IND_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_8}}, + {"fmov.s",{F_REG_M,A_IND_N},{HEX_F,REG_N,REG_M,HEX_A}}, + {"fmov.s",{A_INC_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_9}}, + {"fmov.s",{F_REG_M,A_DEC_N},{HEX_F,REG_N,REG_M,HEX_B}}, + {"fmov.s",{A_IND_R0_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_6}}, + {"fmov.s",{F_REG_M,A_IND_R0_REG_N},{HEX_F,REG_N,REG_M,HEX_7}}, + {"fmul",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_2}}, + {"fmul",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_2}}, + {"fneg",{FD_REG_N},{HEX_F,REG_N,HEX_4,HEX_D}}, + {"frchg",{0},{HEX_F,HEX_B,HEX_F,HEX_D}}, + {"fschg",{0},{HEX_F,HEX_3,HEX_F,HEX_D}}, + {"fsqrt",{FD_REG_N},{HEX_F,REG_N,HEX_6,HEX_D}}, + {"fsts",{FPUL_M,F_REG_N},{HEX_F,REG_N,HEX_0,HEX_D}}, + {"fsub",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_1}}, + {"fsub",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_1}}, + {"ftrc",{FD_REG_N,FPUL_M},{HEX_F,REG_N,HEX_3,HEX_D}}, + {"ftrv",{XMTRX_M4,V_REG_N},{HEX_F,REG_NM,HEX_F,HEX_D}}, + { 0 }, +}; + +static void print_sh_insn(u32 memaddr, u16 insn) +{ + int relmask = ~0; + int nibs[4] = { (insn >> 12) & 0xf, (insn >> 8) & 0xf, (insn >> 4) & 0xf, insn & 0xf}; + int lastsp; + struct sh_opcode_info *op = sh_table; + + for (; op->name; op++) { + int n; + int imm = 0; + int rn = 0; + int rm = 0; + int rb = 0; + int disp_pc; + int disp_pc_addr = 0; + + for (n = 0; n < 4; n++) { + int i = op->nibbles[n]; + + if (i < 16) { + if (nibs[n] == i) + continue; + goto fail; + } + switch (i) { + case BRANCH_8: + imm = (nibs[2] << 4) | (nibs[3]); + if (imm & 0x80) + imm |= ~0xff; + imm = ((char)imm) * 2 + 4 ; + goto ok; + case BRANCH_12: + imm = ((nibs[1]) << 8) | (nibs[2] << 4) | (nibs[3]); + if (imm & 0x800) + imm |= ~0xfff; + imm = imm * 2 + 4; + goto ok; + case IMM_4: + imm = nibs[3]; + goto ok; + case IMM_4BY2: + imm = nibs[3] <<1; + goto ok; + case IMM_4BY4: + imm = nibs[3] <<2; + goto ok; + case IMM_8: + imm = (nibs[2] << 4) | nibs[3]; + goto ok; + case PCRELIMM_8BY2: + imm = ((nibs[2] << 4) | nibs[3]) <<1; + relmask = ~1; + goto ok; + case PCRELIMM_8BY4: + imm = ((nibs[2] << 4) | nibs[3]) <<2; + relmask = ~3; + goto ok; + case IMM_8BY2: + imm = ((nibs[2] << 4) | nibs[3]) <<1; + goto ok; + case IMM_8BY4: + imm = ((nibs[2] << 4) | nibs[3]) <<2; + goto ok; + case DISP_8: + imm = (nibs[2] << 4) | (nibs[3]); + goto ok; + case DISP_4: + imm = nibs[3]; + goto ok; + case REG_N: + rn = nibs[n]; + break; + case REG_M: + rm = nibs[n]; + break; + case REG_NM: + rn = (nibs[n] & 0xc) >> 2; + rm = (nibs[n] & 0x3); + break; + case REG_B: + rb = nibs[n] & 0x07; + break; + default: + return; + } + } + + ok: + printk("%-8s ", op->name); + lastsp = (op->arg[0] == A_END); + disp_pc = 0; + for (n = 0; n < 6 && op->arg[n] != A_END; n++) { + if (n && op->arg[1] != A_END) + printk(", "); + switch (op->arg[n]) { + case A_IMM: + printk("#%d", (char)(imm)); + break; + case A_R0: + printk("r0"); + break; + case A_REG_N: + printk("r%d", rn); + break; + case A_INC_N: + printk("@r%d+", rn); + break; + case A_DEC_N: + printk("@-r%d", rn); + break; + case A_IND_N: + printk("@r%d", rn); + break; + case A_DISP_REG_N: + printk("@(%d,r%d)", imm, rn); + break; + case A_REG_M: + printk("r%d", rm); + break; + case A_INC_M: + printk("@r%d+", rm); + break; + case A_DEC_M: + printk("@-r%d", rm); + break; + case A_IND_M: + printk("@r%d", rm); + break; + case A_DISP_REG_M: + printk("@(%d,r%d)", imm, rm); + break; + case A_REG_B: + printk("r%d_bank", rb); + break; + case A_DISP_PC: + disp_pc = 1; + disp_pc_addr = imm + 4 + (memaddr & relmask); + printk("%08x <%pS>", disp_pc_addr, + (void *)disp_pc_addr); + break; + case A_IND_R0_REG_N: + printk("@(r0,r%d)", rn); + break; + case A_IND_R0_REG_M: + printk("@(r0,r%d)", rm); + break; + case A_DISP_GBR: + printk("@(%d,gbr)",imm); + break; + case A_R0_GBR: + printk("@(r0,gbr)"); + break; + case A_BDISP12: + case A_BDISP8: + printk("%08x", imm + memaddr); + break; + case A_SR: + printk("sr"); + break; + case A_GBR: + printk("gbr"); + break; + case A_VBR: + printk("vbr"); + break; + case A_SSR: + printk("ssr"); + break; + case A_SPC: + printk("spc"); + break; + case A_MACH: + printk("mach"); + break; + case A_MACL: + printk("macl"); + break; + case A_PR: + printk("pr"); + break; + case A_SGR: + printk("sgr"); + break; + case A_DBR: + printk("dbr"); + break; + case FD_REG_N: + if (0) + goto d_reg_n; + case F_REG_N: + printk("fr%d", rn); + break; + case F_REG_M: + printk("fr%d", rm); + break; + case DX_REG_N: + if (rn & 1) { + printk("xd%d", rn & ~1); + break; + } + d_reg_n: + case D_REG_N: + printk("dr%d", rn); + break; + case DX_REG_M: + if (rm & 1) { + printk("xd%d", rm & ~1); + break; + } + case D_REG_M: + printk("dr%d", rm); + break; + case FPSCR_M: + case FPSCR_N: + printk("fpscr"); + break; + case FPUL_M: + case FPUL_N: + printk("fpul"); + break; + case F_FR0: + printk("fr0"); + break; + case V_REG_N: + printk("fv%d", rn*4); + break; + case V_REG_M: + printk("fv%d", rm*4); + break; + case XMTRX_M4: + printk("xmtrx"); + break; + default: + return; + } + } + + if (disp_pc && strcmp(op->name, "mova") != 0) { + u32 val; + + if (relmask == ~1) + __get_user(val, (u16 *)disp_pc_addr); + else + __get_user(val, (u32 *)disp_pc_addr); + + printk(" ! %08x <%pS>", val, (void *)val); + } + + return; + fail: + ; + + } + + printk(".word 0x%x%x%x%x", nibs[0], nibs[1], nibs[2], nibs[3]); +} + +void show_code(struct pt_regs *regs) +{ + unsigned short *pc = (unsigned short *)regs->pc; + long i; + + if (regs->pc & 0x1) + return; + + printk("Code:\n"); + + for (i = -3 ; i < 6 ; i++) { + unsigned short insn; + + if (__get_user(insn, pc + i)) { + printk(" (Bad address in pc)\n"); + break; + } + + printk("%s%08lx: ", (i ? " ": "->"), (unsigned long)(pc + i)); + print_sh_insn((unsigned long)(pc + i), insn); + printk("\n"); + } + + printk("\n"); +} diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S index 5b7efc4016fa549be0cac212fc51e3e5866e9d37..d62359cfbbe20723e39a7b304b02446dc78c686d 100644 --- a/arch/sh/kernel/entry-common.S +++ b/arch/sh/kernel/entry-common.S @@ -308,15 +308,19 @@ ENTRY(system_call) mov.l 1f, r9 mov.l @r9, r8 ! Read from TRA (Trap Address) Register #endif + + mov #OFF_TRA, r10 + add r15, r10 + mov.l r8, @r10 ! set TRA value to tra + /* * Check the trap type */ mov #((0x20 << 2) - 1), r9 cmp/hi r9, r8 bt/s debug_trap ! it's a debug trap.. - mov #OFF_TRA, r9 - add r15, r9 - mov.l r8, @r9 ! set TRA value to tra + nop + #ifdef CONFIG_TRACE_IRQFLAGS mov.l 5f, r10 jsr @r10 @@ -371,47 +375,3 @@ syscall_exit: #endif 7: .long do_syscall_trace_enter 8: .long do_syscall_trace_leave - -#ifdef CONFIG_FUNCTION_TRACER - .align 2 - .globl _mcount - .type _mcount,@function - .globl mcount - .type mcount,@function -_mcount: -mcount: - mov.l r4, @-r15 - mov.l r5, @-r15 - mov.l r6, @-r15 - mov.l r7, @-r15 - sts.l pr, @-r15 - - mov.l @(20,r15),r4 - sts pr, r5 - - mov.l 1f, r6 - mov.l ftrace_stub, r7 - cmp/eq r6, r7 - bt skip_trace - - mov.l @r6, r6 - jsr @r6 - nop - -skip_trace: - - lds.l @r15+, pr - mov.l @r15+, r7 - mov.l @r15+, r6 - mov.l @r15+, r5 - rts - mov.l @r15+, r4 - - .align 2 -1: .long ftrace_trace_function - - .globl ftrace_stub -ftrace_stub: - rts - nop -#endif /* CONFIG_FUNCTION_TRACER */ diff --git a/arch/sh/kernel/ftrace.c b/arch/sh/kernel/ftrace.c new file mode 100644 index 0000000000000000000000000000000000000000..4c3247477aa36be3a804c212c64d1f075a486b21 --- /dev/null +++ b/arch/sh/kernel/ftrace.c @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2008 Matt Fleming + * Copyright (C) 2008 Paul Mundt + * + * Code for replacing ftrace calls with jumps. + * + * Copyright (C) 2007-2008 Steven Rostedt + * + * Thanks goes to Ingo Molnar, for suggesting the idea. + * Mathieu Desnoyers, for suggesting postponing the modifications. + * Arjan van de Ven, for keeping me straight, and explaining to me + * the dangers of modifying code on the run. + */ +#include +#include +#include +#include +#include +#include +#include + +static unsigned char ftrace_nop[] = { + 0x09, 0x00, /* nop */ + 0x09, 0x00, /* nop */ +}; + +static unsigned char ftrace_replaced_code[MCOUNT_INSN_SIZE]; + +unsigned char *ftrace_nop_replace(void) +{ + return ftrace_nop; +} + +static int is_sh_nop(unsigned char *ip) +{ + return strncmp(ip, ftrace_nop, sizeof(ftrace_nop)); +} + +unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) +{ + /* Place the address in the memory table. */ + if (addr == CALLER_ADDR) + __raw_writel(addr + MCOUNT_INSN_OFFSET, ftrace_replaced_code); + else + __raw_writel(addr, ftrace_replaced_code); + + /* + * No locking needed, this must be called via kstop_machine + * which in essence is like running on a uniprocessor machine. + */ + return ftrace_replaced_code; +} + +int ftrace_modify_code(unsigned long ip, unsigned char *old_code, + unsigned char *new_code) +{ + unsigned char replaced[MCOUNT_INSN_SIZE]; + + /* + * Note: Due to modules and __init, code can + * disappear and change, we need to protect against faulting + * as well as code changing. We do this by using the + * probe_kernel_* functions. + * + * No real locking needed, this code is run through + * kstop_machine, or before SMP starts. + */ + + /* + * If we're trying to nop out a call to a function, we instead + * place a call to the address after the memory table. + */ + if (is_sh_nop(new_code) == 0) + __raw_writel(ip + MCOUNT_INSN_SIZE, (unsigned long)new_code); + + /* read the text we want to modify */ + if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE)) + return -EFAULT; + + /* Make sure it is what we expect it to be */ + if (memcmp(replaced, old_code, MCOUNT_INSN_SIZE) != 0) + return -EINVAL; + + /* replace the text with the new text */ + if (probe_kernel_write((void *)ip, new_code, MCOUNT_INSN_SIZE)) + return -EPERM; + + flush_icache_range(ip, ip + MCOUNT_INSN_SIZE); + + return 0; +} + +int ftrace_update_ftrace_func(ftrace_func_t func) +{ + unsigned long ip = (unsigned long)(&ftrace_call); + unsigned char old[MCOUNT_INSN_SIZE], *new; + + memcpy(old, (unsigned char *)(ip + MCOUNT_INSN_OFFSET), MCOUNT_INSN_SIZE); + new = ftrace_call_replace(ip, (unsigned long)func); + + return ftrace_modify_code(ip + MCOUNT_INSN_OFFSET, old, new); +} + +int ftrace_make_nop(struct module *mod, + struct dyn_ftrace *rec, unsigned long addr) +{ + unsigned char *new, *old; + unsigned long ip = rec->ip; + + old = ftrace_call_replace(ip, addr); + new = ftrace_nop_replace(); + + return ftrace_modify_code(rec->ip, old, new); +} + +int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) +{ + unsigned char *new, *old; + unsigned long ip = rec->ip; + + old = ftrace_nop_replace(); + new = ftrace_call_replace(ip, addr); + + return ftrace_modify_code(rec->ip, old, new); +} + +int __init ftrace_dyn_arch_init(void *data) +{ + /* The return code is retured via data */ + __raw_writel(0, (unsigned long)data); + + return 0; +} diff --git a/arch/sh/kernel/head_32.S b/arch/sh/kernel/head_32.S index ae0a382a82ebbf0f18d54767413c3d31ff87685a..788605ff7088d9ec5dc7b9684c3d85ad171c232a 100644 --- a/arch/sh/kernel/head_32.S +++ b/arch/sh/kernel/head_32.S @@ -80,8 +80,14 @@ ENTRY(_stext) mov.l 7f, r0 ldc r0, r7_bank ! ... and initial thread_info #endif - - ! Clear BSS area + +#ifndef CONFIG_SH_NO_BSS_INIT + /* + * Don't clear BSS if running on slow platforms such as an RTL simulation, + * remote memory via SHdebug link, etc. For these the memory can be guaranteed + * to be all zero on boot anyway. + */ + ! Clear BSS area #ifdef CONFIG_SMP mov.l 3f, r0 cmp/eq #0, r0 ! skip clear if set to zero @@ -97,6 +103,8 @@ ENTRY(_stext) mov.l r0,@-r2 10: +#endif + ! Additional CPU initialization mov.l 6f, r0 jsr @r0 diff --git a/arch/sh/kernel/idle.c b/arch/sh/kernel/idle.c new file mode 100644 index 0000000000000000000000000000000000000000..fe59ccfc115287af6221bacb53f5ef5c6c0ee974 --- /dev/null +++ b/arch/sh/kernel/idle.c @@ -0,0 +1,81 @@ +/* + * The idle loop for all SuperH platforms. + * + * Copyright (C) 2002 - 2008 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int hlt_counter; +void (*pm_idle)(void); +void (*pm_power_off)(void); +EXPORT_SYMBOL(pm_power_off); + +static int __init nohlt_setup(char *__unused) +{ + hlt_counter = 1; + return 1; +} +__setup("nohlt", nohlt_setup); + +static int __init hlt_setup(char *__unused) +{ + hlt_counter = 0; + return 1; +} +__setup("hlt", hlt_setup); + +static void default_idle(void) +{ + if (!hlt_counter) { + clear_thread_flag(TIF_POLLING_NRFLAG); + smp_mb__after_clear_bit(); + set_bl_bit(); + stop_critical_timings(); + + while (!need_resched()) + cpu_sleep(); + + start_critical_timings(); + clear_bl_bit(); + set_thread_flag(TIF_POLLING_NRFLAG); + } else + while (!need_resched()) + cpu_relax(); +} + +void cpu_idle(void) +{ + set_thread_flag(TIF_POLLING_NRFLAG); + + /* endless idle loop with no priority at all */ + while (1) { + void (*idle)(void) = pm_idle; + + if (!idle) + idle = default_idle; + + tick_nohz_stop_sched_tick(1); + while (!need_resched()) + idle(); + tick_nohz_restart_sched_tick(); + + preempt_enable_no_resched(); + schedule(); + preempt_disable(); + check_pgt_cache(); + } +} diff --git a/arch/sh/kernel/kgdb.c b/arch/sh/kernel/kgdb.c new file mode 100644 index 0000000000000000000000000000000000000000..7c747e7d71b86c35b2fe5eb58b17160a4e563931 --- /dev/null +++ b/arch/sh/kernel/kgdb.c @@ -0,0 +1,285 @@ +/* + * SuperH KGDB support + * + * Copyright (C) 2008 Paul Mundt + * + * Single stepping taken from the old stub by Henry Bell and Jeremy Siegel. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include +#include +#include + +char in_nmi = 0; /* Set during NMI to prevent re-entry */ + +/* Macros for single step instruction identification */ +#define OPCODE_BT(op) (((op) & 0xff00) == 0x8900) +#define OPCODE_BF(op) (((op) & 0xff00) == 0x8b00) +#define OPCODE_BTF_DISP(op) (((op) & 0x80) ? (((op) | 0xffffff80) << 1) : \ + (((op) & 0x7f ) << 1)) +#define OPCODE_BFS(op) (((op) & 0xff00) == 0x8f00) +#define OPCODE_BTS(op) (((op) & 0xff00) == 0x8d00) +#define OPCODE_BRA(op) (((op) & 0xf000) == 0xa000) +#define OPCODE_BRA_DISP(op) (((op) & 0x800) ? (((op) | 0xfffff800) << 1) : \ + (((op) & 0x7ff) << 1)) +#define OPCODE_BRAF(op) (((op) & 0xf0ff) == 0x0023) +#define OPCODE_BRAF_REG(op) (((op) & 0x0f00) >> 8) +#define OPCODE_BSR(op) (((op) & 0xf000) == 0xb000) +#define OPCODE_BSR_DISP(op) (((op) & 0x800) ? (((op) | 0xfffff800) << 1) : \ + (((op) & 0x7ff) << 1)) +#define OPCODE_BSRF(op) (((op) & 0xf0ff) == 0x0003) +#define OPCODE_BSRF_REG(op) (((op) >> 8) & 0xf) +#define OPCODE_JMP(op) (((op) & 0xf0ff) == 0x402b) +#define OPCODE_JMP_REG(op) (((op) >> 8) & 0xf) +#define OPCODE_JSR(op) (((op) & 0xf0ff) == 0x400b) +#define OPCODE_JSR_REG(op) (((op) >> 8) & 0xf) +#define OPCODE_RTS(op) ((op) == 0xb) +#define OPCODE_RTE(op) ((op) == 0x2b) + +#define SR_T_BIT_MASK 0x1 +#define STEP_OPCODE 0xc33d + +/* Calculate the new address for after a step */ +static short *get_step_address(struct pt_regs *linux_regs) +{ + opcode_t op = __raw_readw(linux_regs->pc); + long addr; + + /* BT */ + if (OPCODE_BT(op)) { + if (linux_regs->sr & SR_T_BIT_MASK) + addr = linux_regs->pc + 4 + OPCODE_BTF_DISP(op); + else + addr = linux_regs->pc + 2; + } + + /* BTS */ + else if (OPCODE_BTS(op)) { + if (linux_regs->sr & SR_T_BIT_MASK) + addr = linux_regs->pc + 4 + OPCODE_BTF_DISP(op); + else + addr = linux_regs->pc + 4; /* Not in delay slot */ + } + + /* BF */ + else if (OPCODE_BF(op)) { + if (!(linux_regs->sr & SR_T_BIT_MASK)) + addr = linux_regs->pc + 4 + OPCODE_BTF_DISP(op); + else + addr = linux_regs->pc + 2; + } + + /* BFS */ + else if (OPCODE_BFS(op)) { + if (!(linux_regs->sr & SR_T_BIT_MASK)) + addr = linux_regs->pc + 4 + OPCODE_BTF_DISP(op); + else + addr = linux_regs->pc + 4; /* Not in delay slot */ + } + + /* BRA */ + else if (OPCODE_BRA(op)) + addr = linux_regs->pc + 4 + OPCODE_BRA_DISP(op); + + /* BRAF */ + else if (OPCODE_BRAF(op)) + addr = linux_regs->pc + 4 + + linux_regs->regs[OPCODE_BRAF_REG(op)]; + + /* BSR */ + else if (OPCODE_BSR(op)) + addr = linux_regs->pc + 4 + OPCODE_BSR_DISP(op); + + /* BSRF */ + else if (OPCODE_BSRF(op)) + addr = linux_regs->pc + 4 + + linux_regs->regs[OPCODE_BSRF_REG(op)]; + + /* JMP */ + else if (OPCODE_JMP(op)) + addr = linux_regs->regs[OPCODE_JMP_REG(op)]; + + /* JSR */ + else if (OPCODE_JSR(op)) + addr = linux_regs->regs[OPCODE_JSR_REG(op)]; + + /* RTS */ + else if (OPCODE_RTS(op)) + addr = linux_regs->pr; + + /* RTE */ + else if (OPCODE_RTE(op)) + addr = linux_regs->regs[15]; + + /* Other */ + else + addr = linux_regs->pc + instruction_size(op); + + flush_icache_range(addr, addr + instruction_size(op)); + return (short *)addr; +} + +/* + * Replace the instruction immediately after the current instruction + * (i.e. next in the expected flow of control) with a trap instruction, + * so that returning will cause only a single instruction to be executed. + * Note that this model is slightly broken for instructions with delay + * slots (e.g. B[TF]S, BSR, BRA etc), where both the branch and the + * instruction in the delay slot will be executed. + */ + +static unsigned long stepped_address; +static opcode_t stepped_opcode; + +static void do_single_step(struct pt_regs *linux_regs) +{ + /* Determine where the target instruction will send us to */ + unsigned short *addr = get_step_address(linux_regs); + + stepped_address = (int)addr; + + /* Replace it */ + stepped_opcode = __raw_readw((long)addr); + *addr = STEP_OPCODE; + + /* Flush and return */ + flush_icache_range((long)addr, (long)addr + + instruction_size(stepped_opcode)); +} + +/* Undo a single step */ +static void undo_single_step(struct pt_regs *linux_regs) +{ + /* If we have stepped, put back the old instruction */ + /* Use stepped_address in case we stopped elsewhere */ + if (stepped_opcode != 0) { + __raw_writew(stepped_opcode, stepped_address); + flush_icache_range(stepped_address, stepped_address + 2); + } + + stepped_opcode = 0; +} + +void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) +{ + int i; + + for (i = 0; i < 16; i++) + gdb_regs[GDB_R0 + i] = regs->regs[i]; + + gdb_regs[GDB_PC] = regs->pc; + gdb_regs[GDB_PR] = regs->pr; + gdb_regs[GDB_SR] = regs->sr; + gdb_regs[GDB_GBR] = regs->gbr; + gdb_regs[GDB_MACH] = regs->mach; + gdb_regs[GDB_MACL] = regs->macl; + + __asm__ __volatile__ ("stc vbr, %0" : "=r" (gdb_regs[GDB_VBR])); +} + +void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) +{ + int i; + + for (i = 0; i < 16; i++) + regs->regs[GDB_R0 + i] = gdb_regs[GDB_R0 + i]; + + regs->pc = gdb_regs[GDB_PC]; + regs->pr = gdb_regs[GDB_PR]; + regs->sr = gdb_regs[GDB_SR]; + regs->gbr = gdb_regs[GDB_GBR]; + regs->mach = gdb_regs[GDB_MACH]; + regs->macl = gdb_regs[GDB_MACL]; + + __asm__ __volatile__ ("ldc %0, vbr" : : "r" (gdb_regs[GDB_VBR])); +} + +void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) +{ + gdb_regs[GDB_R15] = p->thread.sp; + gdb_regs[GDB_PC] = p->thread.pc; +} + +int kgdb_arch_handle_exception(int e_vector, int signo, int err_code, + char *remcomInBuffer, char *remcomOutBuffer, + struct pt_regs *linux_regs) +{ + unsigned long addr; + char *ptr; + + /* Undo any stepping we may have done */ + undo_single_step(linux_regs); + + switch (remcomInBuffer[0]) { + case 'c': + case 's': + /* try to read optional parameter, pc unchanged if no parm */ + ptr = &remcomInBuffer[1]; + if (kgdb_hex2long(&ptr, &addr)) + linux_regs->pc = addr; + case 'D': + case 'k': + atomic_set(&kgdb_cpu_doing_single_step, -1); + + if (remcomInBuffer[0] == 's') { + do_single_step(linux_regs); + kgdb_single_step = 1; + + atomic_set(&kgdb_cpu_doing_single_step, + raw_smp_processor_id()); + } + + return 0; + } + + /* this means that we do not want to exit from the handler: */ + return -1; +} + +/* + * The primary entry points for the kgdb debug trap table entries. + */ +BUILD_TRAP_HANDLER(singlestep) +{ + unsigned long flags; + TRAP_HANDLER_DECL; + + local_irq_save(flags); + regs->pc -= instruction_size(__raw_readw(regs->pc - 4)); + kgdb_handle_exception(vec >> 2, SIGTRAP, 0, regs); + local_irq_restore(flags); +} + + +BUILD_TRAP_HANDLER(breakpoint) +{ + unsigned long flags; + TRAP_HANDLER_DECL; + + local_irq_save(flags); + kgdb_handle_exception(vec >> 2, SIGTRAP, 0, regs); + local_irq_restore(flags); +} + +int kgdb_arch_init(void) +{ + return 0; +} + +void kgdb_arch_exit(void) +{ +} + +struct kgdb_arch arch_kgdb_ops = { + /* Breakpoint instruction: trapa #0x3c */ +#ifdef CONFIG_CPU_LITTLE_ENDIAN + .gdb_bpt_instr = { 0x3c, 0xc3 }, +#else + .gdb_bpt_instr = { 0xc3, 0x3c }, +#endif +}; diff --git a/arch/sh/kernel/kgdb_jmp.S b/arch/sh/kernel/kgdb_jmp.S deleted file mode 100644 index 339bb1d7ff0b316d8020b3f7bdd8015ead6bd4d2..0000000000000000000000000000000000000000 --- a/arch/sh/kernel/kgdb_jmp.S +++ /dev/null @@ -1,33 +0,0 @@ -#include - -ENTRY(setjmp) - add #(9*4), r4 - sts.l pr, @-r4 - mov.l r15, @-r4 - mov.l r14, @-r4 - mov.l r13, @-r4 - mov.l r12, @-r4 - mov.l r11, @-r4 - mov.l r10, @-r4 - mov.l r9, @-r4 - mov.l r8, @-r4 - rts - mov #0, r0 - -ENTRY(longjmp) - mov.l @r4+, r8 - mov.l @r4+, r9 - mov.l @r4+, r10 - mov.l @r4+, r11 - mov.l @r4+, r12 - mov.l @r4+, r13 - mov.l @r4+, r14 - mov.l @r4+, r15 - lds.l @r4+, pr - mov r5, r0 - tst r0, r0 - bf 1f - mov #1, r0 ! in case val==0 -1: rts - nop - diff --git a/arch/sh/kernel/kgdb_stub.c b/arch/sh/kernel/kgdb_stub.c deleted file mode 100644 index bf8ac4c716402c2b37178a8df448d318dd60af1c..0000000000000000000000000000000000000000 --- a/arch/sh/kernel/kgdb_stub.c +++ /dev/null @@ -1,1052 +0,0 @@ -/* - * May be copied or modified under the terms of the GNU General Public - * License. See linux/COPYING for more information. - * - * Contains extracts from code by Glenn Engel, Jim Kingdon, - * David Grothe , Tigran Aivazian , - * Amit S. Kale , William Gatliff , - * Ben Lee, Steve Chamberlain and Benoit Miller . - * - * This version by Henry Bell - * Minor modifications by Jeremy Siegel - * - * Contains low-level support for remote debug using GDB. - * - * To enable debugger support, two things need to happen. A call to - * set_debug_traps() is necessary in order to allow any breakpoints - * or error conditions to be properly intercepted and reported to gdb. - * A breakpoint also needs to be generated to begin communication. This - * is most easily accomplished by a call to breakpoint() which does - * a trapa if the initialisation phase has been successfully completed. - * - * In this case, set_debug_traps() is not used to "take over" exceptions; - * other kernel code is modified instead to enter the kgdb functions here - * when appropriate (see entry.S for breakpoint traps and NMI interrupts, - * see traps.c for kernel error exceptions). - * - * The following gdb commands are supported: - * - * Command Function Return value - * - * g return the value of the CPU registers hex data or ENN - * G set the value of the CPU registers OK or ENN - * - * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN - * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN - * XAA..AA,LLLL: Same, but data is binary (not hex) OK or ENN - * - * c Resume at current address SNN ( signal NN) - * cAA..AA Continue at address AA..AA SNN - * CNN; Resume at current address with signal SNN - * CNN;AA..AA Resume at address AA..AA with signal SNN - * - * s Step one instruction SNN - * sAA..AA Step one instruction from AA..AA SNN - * SNN; Step one instruction with signal SNN - * SNNAA..AA Step one instruction from AA..AA w/NN SNN - * - * k kill (Detach GDB) - * - * d Toggle debug flag - * D Detach GDB - * - * Hct Set thread t for operations, OK or ENN - * c = 'c' (step, cont), c = 'g' (other - * operations) - * - * qC Query current thread ID QCpid - * qfThreadInfo Get list of current threads (first) m - * qsThreadInfo " " " " " (subsequent) - * qOffsets Get section offsets Text=x;Data=y;Bss=z - * - * TXX Find if thread XX is alive OK or ENN - * ? What was the last sigval ? SNN (signal NN) - * O Output to GDB console - * - * Remote communication protocol. - * - * A debug packet whose contents are is encapsulated for - * transmission in the form: - * - * $ # CSUM1 CSUM2 - * - * must be ASCII alphanumeric and cannot include characters - * '$' or '#'. If starts with two characters followed by - * ':', then the existing stubs interpret this as a sequence number. - * - * CSUM1 and CSUM2 are ascii hex representation of an 8-bit - * checksum of , the most significant nibble is sent first. - * the hex digits 0-9,a-f are used. - * - * Receiver responds with: - * - * + - if CSUM is correct and ready for next packet - * - - if CSUM is incorrect - * - * Responses can be run-length encoded to save space. A '*' means that - * the next character is an ASCII encoding giving a repeat count which - * stands for that many repetitions of the character preceding the '*'. - * The encoding is n+29, yielding a printable character where n >=3 - * (which is where RLE starts to win). Don't use an n > 126. - * - * So "0* " means the same as "0000". - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Function pointers for linkage */ -kgdb_debug_hook_t *kgdb_debug_hook; -kgdb_bus_error_hook_t *kgdb_bus_err_hook; - -int (*kgdb_getchar)(void); -EXPORT_SYMBOL_GPL(kgdb_getchar); -void (*kgdb_putchar)(int); -EXPORT_SYMBOL_GPL(kgdb_putchar); - -static void put_debug_char(int c) -{ - if (!kgdb_putchar) - return; - (*kgdb_putchar)(c); -} -static int get_debug_char(void) -{ - if (!kgdb_getchar) - return -1; - return (*kgdb_getchar)(); -} - -/* Num chars in in/out bound buffers, register packets need NUMREGBYTES * 2 */ -#define BUFMAX 1024 -#define NUMREGBYTES (MAXREG*4) -#define OUTBUFMAX (NUMREGBYTES*2+512) - -enum { - R0 = 0, R1, R2, R3, R4, R5, R6, R7, - R8, R9, R10, R11, R12, R13, R14, R15, - PC, PR, GBR, VBR, MACH, MACL, SR, - /* */ - MAXREG -}; - -static unsigned int registers[MAXREG]; -struct kgdb_regs trap_registers; - -char kgdb_in_gdb_mode; -char in_nmi; /* Set during NMI to prevent reentry */ -int kgdb_nofault; /* Boolean to ignore bus errs (i.e. in GDB) */ - -/* Default values for SCI (can override via kernel args in setup.c) */ -#ifndef CONFIG_KGDB_DEFPORT -#define CONFIG_KGDB_DEFPORT 1 -#endif - -#ifndef CONFIG_KGDB_DEFBAUD -#define CONFIG_KGDB_DEFBAUD 115200 -#endif - -#if defined(CONFIG_KGDB_DEFPARITY_E) -#define CONFIG_KGDB_DEFPARITY 'E' -#elif defined(CONFIG_KGDB_DEFPARITY_O) -#define CONFIG_KGDB_DEFPARITY 'O' -#else /* CONFIG_KGDB_DEFPARITY_N */ -#define CONFIG_KGDB_DEFPARITY 'N' -#endif - -#ifdef CONFIG_KGDB_DEFBITS_7 -#define CONFIG_KGDB_DEFBITS '7' -#else /* CONFIG_KGDB_DEFBITS_8 */ -#define CONFIG_KGDB_DEFBITS '8' -#endif - -/* SCI/UART settings, used in kgdb_console_setup() */ -int kgdb_portnum = CONFIG_KGDB_DEFPORT; -EXPORT_SYMBOL_GPL(kgdb_portnum); -int kgdb_baud = CONFIG_KGDB_DEFBAUD; -EXPORT_SYMBOL_GPL(kgdb_baud); -char kgdb_parity = CONFIG_KGDB_DEFPARITY; -EXPORT_SYMBOL_GPL(kgdb_parity); -char kgdb_bits = CONFIG_KGDB_DEFBITS; -EXPORT_SYMBOL_GPL(kgdb_bits); - -/* Jump buffer for setjmp/longjmp */ -static jmp_buf rem_com_env; - -/* TRA differs sh3/4 */ -#if defined(CONFIG_CPU_SH3) -#define TRA 0xffffffd0 -#elif defined(CONFIG_CPU_SH4) -#define TRA 0xff000020 -#endif - -/* Macros for single step instruction identification */ -#define OPCODE_BT(op) (((op) & 0xff00) == 0x8900) -#define OPCODE_BF(op) (((op) & 0xff00) == 0x8b00) -#define OPCODE_BTF_DISP(op) (((op) & 0x80) ? (((op) | 0xffffff80) << 1) : \ - (((op) & 0x7f ) << 1)) -#define OPCODE_BFS(op) (((op) & 0xff00) == 0x8f00) -#define OPCODE_BTS(op) (((op) & 0xff00) == 0x8d00) -#define OPCODE_BRA(op) (((op) & 0xf000) == 0xa000) -#define OPCODE_BRA_DISP(op) (((op) & 0x800) ? (((op) | 0xfffff800) << 1) : \ - (((op) & 0x7ff) << 1)) -#define OPCODE_BRAF(op) (((op) & 0xf0ff) == 0x0023) -#define OPCODE_BRAF_REG(op) (((op) & 0x0f00) >> 8) -#define OPCODE_BSR(op) (((op) & 0xf000) == 0xb000) -#define OPCODE_BSR_DISP(op) (((op) & 0x800) ? (((op) | 0xfffff800) << 1) : \ - (((op) & 0x7ff) << 1)) -#define OPCODE_BSRF(op) (((op) & 0xf0ff) == 0x0003) -#define OPCODE_BSRF_REG(op) (((op) >> 8) & 0xf) -#define OPCODE_JMP(op) (((op) & 0xf0ff) == 0x402b) -#define OPCODE_JMP_REG(op) (((op) >> 8) & 0xf) -#define OPCODE_JSR(op) (((op) & 0xf0ff) == 0x400b) -#define OPCODE_JSR_REG(op) (((op) >> 8) & 0xf) -#define OPCODE_RTS(op) ((op) == 0xb) -#define OPCODE_RTE(op) ((op) == 0x2b) - -#define SR_T_BIT_MASK 0x1 -#define STEP_OPCODE 0xc320 -#define BIOS_CALL_TRAP 0x3f - -/* Exception codes as per SH-4 core manual */ -#define ADDRESS_ERROR_LOAD_VEC 7 -#define ADDRESS_ERROR_STORE_VEC 8 -#define TRAP_VEC 11 -#define INVALID_INSN_VEC 12 -#define INVALID_SLOT_VEC 13 -#define NMI_VEC 14 -#define USER_BREAK_VEC 15 -#define SERIAL_BREAK_VEC 58 - -/* Misc static */ -static int stepped_address; -static short stepped_opcode; -static char in_buffer[BUFMAX]; -static char out_buffer[OUTBUFMAX]; - -static void kgdb_to_gdb(const char *s); - -/* Convert ch to hex */ -static int hex(const char ch) -{ - if ((ch >= 'a') && (ch <= 'f')) - return (ch - 'a' + 10); - if ((ch >= '0') && (ch <= '9')) - return (ch - '0'); - if ((ch >= 'A') && (ch <= 'F')) - return (ch - 'A' + 10); - return (-1); -} - -/* Convert the memory pointed to by mem into hex, placing result in buf. - Returns a pointer to the last char put in buf (null) */ -static char *mem_to_hex(const char *mem, char *buf, const int count) -{ - int i; - int ch; - unsigned short s_val; - unsigned long l_val; - - /* Check for 16 or 32 */ - if (count == 2 && ((long) mem & 1) == 0) { - s_val = *(unsigned short *) mem; - mem = (char *) &s_val; - } else if (count == 4 && ((long) mem & 3) == 0) { - l_val = *(unsigned long *) mem; - mem = (char *) &l_val; - } - for (i = 0; i < count; i++) { - ch = *mem++; - buf = pack_hex_byte(buf, ch); - } - *buf = 0; - return (buf); -} - -/* Convert the hex array pointed to by buf into binary, to be placed in mem. - Return a pointer to the character after the last byte written */ -static char *hex_to_mem(const char *buf, char *mem, const int count) -{ - int i; - unsigned char ch; - - for (i = 0; i < count; i++) { - ch = hex(*buf++) << 4; - ch = ch + hex(*buf++); - *mem++ = ch; - } - return (mem); -} - -/* While finding valid hex chars, convert to an integer, then return it */ -static int hex_to_int(char **ptr, int *int_value) -{ - int num_chars = 0; - int hex_value; - - *int_value = 0; - - while (**ptr) { - hex_value = hex(**ptr); - if (hex_value >= 0) { - *int_value = (*int_value << 4) | hex_value; - num_chars++; - } else - break; - (*ptr)++; - } - return num_chars; -} - -/* Copy the binary array pointed to by buf into mem. Fix $, #, - and 0x7d escaped with 0x7d. Return a pointer to the character - after the last byte written. */ -static char *ebin_to_mem(const char *buf, char *mem, int count) -{ - for (; count > 0; count--, buf++) { - if (*buf == 0x7d) - *mem++ = *(++buf) ^ 0x20; - else - *mem++ = *buf; - } - return mem; -} - -/* Scan for the start char '$', read the packet and check the checksum */ -static void get_packet(char *buffer, int buflen) -{ - unsigned char checksum; - unsigned char xmitcsum; - int i; - int count; - char ch; - - do { - /* Ignore everything until the start character */ - while ((ch = get_debug_char()) != '$'); - - checksum = 0; - xmitcsum = -1; - count = 0; - - /* Now, read until a # or end of buffer is found */ - while (count < (buflen - 1)) { - ch = get_debug_char(); - - if (ch == '#') - break; - - checksum = checksum + ch; - buffer[count] = ch; - count = count + 1; - } - - buffer[count] = 0; - - /* Continue to read checksum following # */ - if (ch == '#') { - xmitcsum = hex(get_debug_char()) << 4; - xmitcsum += hex(get_debug_char()); - - /* Checksum */ - if (checksum != xmitcsum) - put_debug_char('-'); /* Failed checksum */ - else { - /* Ack successful transfer */ - put_debug_char('+'); - - /* If a sequence char is present, reply - the sequence ID */ - if (buffer[2] == ':') { - put_debug_char(buffer[0]); - put_debug_char(buffer[1]); - - /* Remove sequence chars from buffer */ - count = strlen(buffer); - for (i = 3; i <= count; i++) - buffer[i - 3] = buffer[i]; - } - } - } - } - while (checksum != xmitcsum); /* Keep trying while we fail */ -} - -/* Send the packet in the buffer with run-length encoding */ -static void put_packet(char *buffer) -{ - int checksum; - char *src; - int runlen; - int encode; - - do { - src = buffer; - put_debug_char('$'); - checksum = 0; - - /* Continue while we still have chars left */ - while (*src) { - /* Check for runs up to 99 chars long */ - for (runlen = 1; runlen < 99; runlen++) { - if (src[0] != src[runlen]) - break; - } - - if (runlen > 3) { - /* Got a useful amount, send encoding */ - encode = runlen + ' ' - 4; - put_debug_char(*src); checksum += *src; - put_debug_char('*'); checksum += '*'; - put_debug_char(encode); checksum += encode; - src += runlen; - } else { - /* Otherwise just send the current char */ - put_debug_char(*src); checksum += *src; - src += 1; - } - } - - /* '#' Separator, put high and low components of checksum */ - put_debug_char('#'); - put_debug_char(hex_asc_hi(checksum)); - put_debug_char(hex_asc_lo(checksum)); - } - while ((get_debug_char()) != '+'); /* While no ack */ -} - -/* A bus error has occurred - perform a longjmp to return execution and - allow handling of the error */ -static void kgdb_handle_bus_error(void) -{ - longjmp(rem_com_env, 1); -} - -/* Translate SH-3/4 exception numbers to unix-like signal values */ -static int compute_signal(const int excep_code) -{ - int sigval; - - switch (excep_code) { - - case INVALID_INSN_VEC: - case INVALID_SLOT_VEC: - sigval = SIGILL; - break; - case ADDRESS_ERROR_LOAD_VEC: - case ADDRESS_ERROR_STORE_VEC: - sigval = SIGSEGV; - break; - - case SERIAL_BREAK_VEC: - case NMI_VEC: - sigval = SIGINT; - break; - - case USER_BREAK_VEC: - case TRAP_VEC: - sigval = SIGTRAP; - break; - - default: - sigval = SIGBUS; /* "software generated" */ - break; - } - - return (sigval); -} - -/* Make a local copy of the registers passed into the handler (bletch) */ -static void kgdb_regs_to_gdb_regs(const struct kgdb_regs *regs, - int *gdb_regs) -{ - gdb_regs[R0] = regs->regs[R0]; - gdb_regs[R1] = regs->regs[R1]; - gdb_regs[R2] = regs->regs[R2]; - gdb_regs[R3] = regs->regs[R3]; - gdb_regs[R4] = regs->regs[R4]; - gdb_regs[R5] = regs->regs[R5]; - gdb_regs[R6] = regs->regs[R6]; - gdb_regs[R7] = regs->regs[R7]; - gdb_regs[R8] = regs->regs[R8]; - gdb_regs[R9] = regs->regs[R9]; - gdb_regs[R10] = regs->regs[R10]; - gdb_regs[R11] = regs->regs[R11]; - gdb_regs[R12] = regs->regs[R12]; - gdb_regs[R13] = regs->regs[R13]; - gdb_regs[R14] = regs->regs[R14]; - gdb_regs[R15] = regs->regs[R15]; - gdb_regs[PC] = regs->pc; - gdb_regs[PR] = regs->pr; - gdb_regs[GBR] = regs->gbr; - gdb_regs[MACH] = regs->mach; - gdb_regs[MACL] = regs->macl; - gdb_regs[SR] = regs->sr; - gdb_regs[VBR] = regs->vbr; -} - -/* Copy local gdb registers back to kgdb regs, for later copy to kernel */ -static void gdb_regs_to_kgdb_regs(const int *gdb_regs, - struct kgdb_regs *regs) -{ - regs->regs[R0] = gdb_regs[R0]; - regs->regs[R1] = gdb_regs[R1]; - regs->regs[R2] = gdb_regs[R2]; - regs->regs[R3] = gdb_regs[R3]; - regs->regs[R4] = gdb_regs[R4]; - regs->regs[R5] = gdb_regs[R5]; - regs->regs[R6] = gdb_regs[R6]; - regs->regs[R7] = gdb_regs[R7]; - regs->regs[R8] = gdb_regs[R8]; - regs->regs[R9] = gdb_regs[R9]; - regs->regs[R10] = gdb_regs[R10]; - regs->regs[R11] = gdb_regs[R11]; - regs->regs[R12] = gdb_regs[R12]; - regs->regs[R13] = gdb_regs[R13]; - regs->regs[R14] = gdb_regs[R14]; - regs->regs[R15] = gdb_regs[R15]; - regs->pc = gdb_regs[PC]; - regs->pr = gdb_regs[PR]; - regs->gbr = gdb_regs[GBR]; - regs->mach = gdb_regs[MACH]; - regs->macl = gdb_regs[MACL]; - regs->sr = gdb_regs[SR]; - regs->vbr = gdb_regs[VBR]; -} - -/* Calculate the new address for after a step */ -static short *get_step_address(void) -{ - short op = *(short *) trap_registers.pc; - long addr; - - /* BT */ - if (OPCODE_BT(op)) { - if (trap_registers.sr & SR_T_BIT_MASK) - addr = trap_registers.pc + 4 + OPCODE_BTF_DISP(op); - else - addr = trap_registers.pc + 2; - } - - /* BTS */ - else if (OPCODE_BTS(op)) { - if (trap_registers.sr & SR_T_BIT_MASK) - addr = trap_registers.pc + 4 + OPCODE_BTF_DISP(op); - else - addr = trap_registers.pc + 4; /* Not in delay slot */ - } - - /* BF */ - else if (OPCODE_BF(op)) { - if (!(trap_registers.sr & SR_T_BIT_MASK)) - addr = trap_registers.pc + 4 + OPCODE_BTF_DISP(op); - else - addr = trap_registers.pc + 2; - } - - /* BFS */ - else if (OPCODE_BFS(op)) { - if (!(trap_registers.sr & SR_T_BIT_MASK)) - addr = trap_registers.pc + 4 + OPCODE_BTF_DISP(op); - else - addr = trap_registers.pc + 4; /* Not in delay slot */ - } - - /* BRA */ - else if (OPCODE_BRA(op)) - addr = trap_registers.pc + 4 + OPCODE_BRA_DISP(op); - - /* BRAF */ - else if (OPCODE_BRAF(op)) - addr = trap_registers.pc + 4 - + trap_registers.regs[OPCODE_BRAF_REG(op)]; - - /* BSR */ - else if (OPCODE_BSR(op)) - addr = trap_registers.pc + 4 + OPCODE_BSR_DISP(op); - - /* BSRF */ - else if (OPCODE_BSRF(op)) - addr = trap_registers.pc + 4 - + trap_registers.regs[OPCODE_BSRF_REG(op)]; - - /* JMP */ - else if (OPCODE_JMP(op)) - addr = trap_registers.regs[OPCODE_JMP_REG(op)]; - - /* JSR */ - else if (OPCODE_JSR(op)) - addr = trap_registers.regs[OPCODE_JSR_REG(op)]; - - /* RTS */ - else if (OPCODE_RTS(op)) - addr = trap_registers.pr; - - /* RTE */ - else if (OPCODE_RTE(op)) - addr = trap_registers.regs[15]; - - /* Other */ - else - addr = trap_registers.pc + 2; - - flush_icache_range(addr, addr + 2); - return (short *) addr; -} - -/* Set up a single-step. Replace the instruction immediately after the - current instruction (i.e. next in the expected flow of control) with a - trap instruction, so that returning will cause only a single instruction - to be executed. Note that this model is slightly broken for instructions - with delay slots (e.g. B[TF]S, BSR, BRA etc), where both the branch - and the instruction in the delay slot will be executed. */ -static void do_single_step(void) -{ - unsigned short *addr = 0; - - /* Determine where the target instruction will send us to */ - addr = get_step_address(); - stepped_address = (int)addr; - - /* Replace it */ - stepped_opcode = *(short *)addr; - *addr = STEP_OPCODE; - - /* Flush and return */ - flush_icache_range((long) addr, (long) addr + 2); -} - -/* Undo a single step */ -static void undo_single_step(void) -{ - /* If we have stepped, put back the old instruction */ - /* Use stepped_address in case we stopped elsewhere */ - if (stepped_opcode != 0) { - *(short*)stepped_address = stepped_opcode; - flush_icache_range(stepped_address, stepped_address + 2); - } - stepped_opcode = 0; -} - -/* Send a signal message */ -static void send_signal_msg(const int signum) -{ - out_buffer[0] = 'S'; - out_buffer[1] = hex_asc_hi(signum); - out_buffer[2] = hex_asc_lo(signum); - out_buffer[3] = 0; - put_packet(out_buffer); -} - -/* Reply that all was well */ -static void send_ok_msg(void) -{ - strcpy(out_buffer, "OK"); - put_packet(out_buffer); -} - -/* Reply that an error occurred */ -static void send_err_msg(void) -{ - strcpy(out_buffer, "E01"); - put_packet(out_buffer); -} - -/* Empty message indicates unrecognised command */ -static void send_empty_msg(void) -{ - put_packet(""); -} - -/* Read memory due to 'm' message */ -static void read_mem_msg(void) -{ - char *ptr; - int addr; - int length; - - /* Jmp, disable bus error handler */ - if (setjmp(rem_com_env) == 0) { - - kgdb_nofault = 1; - - /* Walk through, have m, */ - ptr = &in_buffer[1]; - if (hex_to_int(&ptr, &addr) && (*ptr++ == ',')) - if (hex_to_int(&ptr, &length)) { - ptr = 0; - if (length * 2 > OUTBUFMAX) - length = OUTBUFMAX / 2; - mem_to_hex((char *) addr, out_buffer, length); - } - if (ptr) - send_err_msg(); - else - put_packet(out_buffer); - } else - send_err_msg(); - - /* Restore bus error handler */ - kgdb_nofault = 0; -} - -/* Write memory due to 'M' or 'X' message */ -static void write_mem_msg(int binary) -{ - char *ptr; - int addr; - int length; - - if (setjmp(rem_com_env) == 0) { - - kgdb_nofault = 1; - - /* Walk through, have M,: */ - ptr = &in_buffer[1]; - if (hex_to_int(&ptr, &addr) && (*ptr++ == ',')) - if (hex_to_int(&ptr, &length) && (*ptr++ == ':')) { - if (binary) - ebin_to_mem(ptr, (char*)addr, length); - else - hex_to_mem(ptr, (char*)addr, length); - flush_icache_range(addr, addr + length); - ptr = 0; - send_ok_msg(); - } - if (ptr) - send_err_msg(); - } else - send_err_msg(); - - /* Restore bus error handler */ - kgdb_nofault = 0; -} - -/* Continue message */ -static void continue_msg(void) -{ - /* Try to read optional parameter, PC unchanged if none */ - char *ptr = &in_buffer[1]; - int addr; - - if (hex_to_int(&ptr, &addr)) - trap_registers.pc = addr; -} - -/* Continue message with signal */ -static void continue_with_sig_msg(void) -{ - int signal; - char *ptr = &in_buffer[1]; - int addr; - - /* Report limitation */ - kgdb_to_gdb("Cannot force signal in kgdb, continuing anyway.\n"); - - /* Signal */ - hex_to_int(&ptr, &signal); - if (*ptr == ';') - ptr++; - - /* Optional address */ - if (hex_to_int(&ptr, &addr)) - trap_registers.pc = addr; -} - -/* Step message */ -static void step_msg(void) -{ - continue_msg(); - do_single_step(); -} - -/* Step message with signal */ -static void step_with_sig_msg(void) -{ - continue_with_sig_msg(); - do_single_step(); -} - -/* Send register contents */ -static void send_regs_msg(void) -{ - kgdb_regs_to_gdb_regs(&trap_registers, registers); - mem_to_hex((char *) registers, out_buffer, NUMREGBYTES); - put_packet(out_buffer); -} - -/* Set register contents - currently can't set other thread's registers */ -static void set_regs_msg(void) -{ - kgdb_regs_to_gdb_regs(&trap_registers, registers); - hex_to_mem(&in_buffer[1], (char *) registers, NUMREGBYTES); - gdb_regs_to_kgdb_regs(registers, &trap_registers); - send_ok_msg(); -} - -#ifdef CONFIG_SH_KGDB_CONSOLE -/* - * Bring up the ports.. - */ -static int __init kgdb_serial_setup(void) -{ - struct console dummy; - return kgdb_console_setup(&dummy, 0); -} -#else -#define kgdb_serial_setup() 0 -#endif - -/* The command loop, read and act on requests */ -static void kgdb_command_loop(const int excep_code, const int trapa_value) -{ - int sigval; - - /* Enter GDB mode (e.g. after detach) */ - if (!kgdb_in_gdb_mode) { - /* Do serial setup, notify user, issue preemptive ack */ - printk(KERN_NOTICE "KGDB: Waiting for GDB\n"); - kgdb_in_gdb_mode = 1; - put_debug_char('+'); - } - - /* Reply to host that an exception has occurred */ - sigval = compute_signal(excep_code); - send_signal_msg(sigval); - - /* TRAP_VEC exception indicates a software trap inserted in place of - code by GDB so back up PC by one instruction, as this instruction - will later be replaced by its original one. Do NOT do this for - trap 0xff, since that indicates a compiled-in breakpoint which - will not be replaced (and we would retake the trap forever) */ - if ((excep_code == TRAP_VEC) && (trapa_value != (0x3c << 2))) - trap_registers.pc -= 2; - - /* Undo any stepping we may have done */ - undo_single_step(); - - while (1) { - out_buffer[0] = 0; - get_packet(in_buffer, BUFMAX); - - /* Examine first char of buffer to see what we need to do */ - switch (in_buffer[0]) { - case '?': /* Send which signal we've received */ - send_signal_msg(sigval); - break; - - case 'g': /* Return the values of the CPU registers */ - send_regs_msg(); - break; - - case 'G': /* Set the value of the CPU registers */ - set_regs_msg(); - break; - - case 'm': /* Read LLLL bytes address AA..AA */ - read_mem_msg(); - break; - - case 'M': /* Write LLLL bytes address AA..AA, ret OK */ - write_mem_msg(0); /* 0 = data in hex */ - break; - - case 'X': /* Write LLLL bytes esc bin address AA..AA */ - if (kgdb_bits == '8') - write_mem_msg(1); /* 1 = data in binary */ - else - send_empty_msg(); - break; - - case 'C': /* Continue, signum included, we ignore it */ - continue_with_sig_msg(); - return; - - case 'c': /* Continue at address AA..AA (optional) */ - continue_msg(); - return; - - case 'S': /* Step, signum included, we ignore it */ - step_with_sig_msg(); - return; - - case 's': /* Step one instruction from AA..AA */ - step_msg(); - return; - - case 'k': /* 'Kill the program' with a kernel ? */ - break; - - case 'D': /* Detach from program, send reply OK */ - kgdb_in_gdb_mode = 0; - send_ok_msg(); - get_debug_char(); - return; - - default: - send_empty_msg(); - break; - } - } -} - -/* There has been an exception, most likely a breakpoint. */ -static void handle_exception(struct pt_regs *regs) -{ - int excep_code, vbr_val; - int count; - int trapa_value = ctrl_inl(TRA); - - /* Copy kernel regs (from stack) */ - for (count = 0; count < 16; count++) - trap_registers.regs[count] = regs->regs[count]; - trap_registers.pc = regs->pc; - trap_registers.pr = regs->pr; - trap_registers.sr = regs->sr; - trap_registers.gbr = regs->gbr; - trap_registers.mach = regs->mach; - trap_registers.macl = regs->macl; - - asm("stc vbr, %0":"=r"(vbr_val)); - trap_registers.vbr = vbr_val; - - /* Get excode for command loop call, user access */ - asm("stc r2_bank, %0":"=r"(excep_code)); - - /* Act on the exception */ - kgdb_command_loop(excep_code, trapa_value); - - /* Copy back the (maybe modified) registers */ - for (count = 0; count < 16; count++) - regs->regs[count] = trap_registers.regs[count]; - regs->pc = trap_registers.pc; - regs->pr = trap_registers.pr; - regs->sr = trap_registers.sr; - regs->gbr = trap_registers.gbr; - regs->mach = trap_registers.mach; - regs->macl = trap_registers.macl; - - vbr_val = trap_registers.vbr; - asm("ldc %0, vbr": :"r"(vbr_val)); -} - -asmlinkage void kgdb_handle_exception(unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7, - struct pt_regs __regs) -{ - struct pt_regs *regs = RELOC_HIDE(&__regs, 0); - handle_exception(regs); -} - -/* Initialise the KGDB data structures and serial configuration */ -int __init kgdb_init(void) -{ - in_nmi = 0; - kgdb_nofault = 0; - stepped_opcode = 0; - kgdb_in_gdb_mode = 0; - - if (kgdb_serial_setup() != 0) { - printk(KERN_NOTICE "KGDB: serial setup error\n"); - return -1; - } - - /* Init ptr to exception handler */ - kgdb_debug_hook = handle_exception; - kgdb_bus_err_hook = kgdb_handle_bus_error; - - /* Enter kgdb now if requested, or just report init done */ - printk(KERN_NOTICE "KGDB: stub is initialized.\n"); - - return 0; -} - -/* Make function available for "user messages"; console will use it too. */ - -char gdbmsgbuf[BUFMAX]; -#define MAXOUT ((BUFMAX-2)/2) - -static void kgdb_msg_write(const char *s, unsigned count) -{ - int i; - int wcount; - char *bufptr; - - /* 'O'utput */ - gdbmsgbuf[0] = 'O'; - - /* Fill and send buffers... */ - while (count > 0) { - bufptr = gdbmsgbuf + 1; - - /* Calculate how many this time */ - wcount = (count > MAXOUT) ? MAXOUT : count; - - /* Pack in hex chars */ - for (i = 0; i < wcount; i++) - bufptr = pack_hex_byte(bufptr, s[i]); - *bufptr = '\0'; - - /* Move up */ - s += wcount; - count -= wcount; - - /* Write packet */ - put_packet(gdbmsgbuf); - } -} - -static void kgdb_to_gdb(const char *s) -{ - kgdb_msg_write(s, strlen(s)); -} - -#ifdef CONFIG_SH_KGDB_CONSOLE -void kgdb_console_write(struct console *co, const char *s, unsigned count) -{ - /* Bail if we're not talking to GDB */ - if (!kgdb_in_gdb_mode) - return; - - kgdb_msg_write(s, count); -} -#endif - -#ifdef CONFIG_KGDB_SYSRQ -static void sysrq_handle_gdb(int key, struct tty_struct *tty) -{ - printk("Entering GDB stub\n"); - breakpoint(); -} - -static struct sysrq_key_op sysrq_gdb_op = { - .handler = sysrq_handle_gdb, - .help_msg = "Gdb", - .action_msg = "GDB", -}; - -static int gdb_register_sysrq(void) -{ - printk("Registering GDB sysrq handler\n"); - register_sysrq_key('g', &sysrq_gdb_op); - return 0; -} -module_init(gdb_register_sysrq); -#endif diff --git a/arch/sh/kernel/pm.c b/arch/sh/kernel/pm.c deleted file mode 100644 index 10ab62c9aedeced5070e8e7e38b2659787183b64..0000000000000000000000000000000000000000 --- a/arch/sh/kernel/pm.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Generic Power Management Routine - * - * Copyright (c) 2006 Andriy Skulysh - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License. - */ -#include -#include -#include -#include -#include -#include -#include - -#define INTR_OFFSET 0x600 - -#define STBCR 0xffffff82 -#define STBCR2 0xffffff88 - -#define STBCR_STBY 0x80 -#define STBCR_MSTP2 0x04 - -#define MCR 0xffffff68 -#define RTCNT 0xffffff70 - -#define MCR_RMODE 2 -#define MCR_RFSH 4 - -void pm_enter(void) -{ - u8 stbcr, csr; - u16 frqcr, mcr; - u32 vbr_new, vbr_old; - - set_bl_bit(); - - /* set wdt */ - csr = sh_wdt_read_csr(); - csr &= ~WTCSR_TME; - csr |= WTCSR_CKS_4096; - sh_wdt_write_csr(csr); - csr = sh_wdt_read_csr(); - sh_wdt_write_cnt(0); - - /* disable PLL1 */ - frqcr = ctrl_inw(FRQCR); - frqcr &= ~(FRQCR_PLLEN | FRQCR_PSTBY); - ctrl_outw(frqcr, FRQCR); - - /* enable standby */ - stbcr = ctrl_inb(STBCR); - ctrl_outb(stbcr | STBCR_STBY | STBCR_MSTP2, STBCR); - - /* set self-refresh */ - mcr = ctrl_inw(MCR); - ctrl_outw(mcr & ~MCR_RFSH, MCR); - - /* set interrupt handler */ - asm volatile("stc vbr, %0" : "=r" (vbr_old)); - vbr_new = get_zeroed_page(GFP_ATOMIC); - udelay(50); - memcpy((void*)(vbr_new + INTR_OFFSET), - &wakeup_start, &wakeup_end - &wakeup_start); - asm volatile("ldc %0, vbr" : : "r" (vbr_new)); - - ctrl_outw(0, RTCNT); - ctrl_outw(mcr | MCR_RFSH | MCR_RMODE, MCR); - - cpu_sleep(); - - asm volatile("ldc %0, vbr" : : "r" (vbr_old)); - - free_page(vbr_new); - - /* enable PLL1 */ - frqcr = ctrl_inw(FRQCR); - frqcr |= FRQCR_PSTBY; - ctrl_outw(frqcr, FRQCR); - udelay(50); - frqcr |= FRQCR_PLLEN; - ctrl_outw(frqcr, FRQCR); - - ctrl_outb(stbcr, STBCR); - - clear_bl_bit(); -} diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c index b965f0282c7dab650ec30fa1b02d532ed6674be5..ddafbbbab2abe041dbdca39aa000dc4637f21137 100644 --- a/arch/sh/kernel/process_32.c +++ b/arch/sh/kernel/process_32.c @@ -32,65 +32,8 @@ #include #include -static int hlt_counter; int ubc_usercnt = 0; -void (*pm_idle)(void); -void (*pm_power_off)(void); -EXPORT_SYMBOL(pm_power_off); - -static int __init nohlt_setup(char *__unused) -{ - hlt_counter = 1; - return 1; -} -__setup("nohlt", nohlt_setup); - -static int __init hlt_setup(char *__unused) -{ - hlt_counter = 0; - return 1; -} -__setup("hlt", hlt_setup); - -static void default_idle(void) -{ - if (!hlt_counter) { - clear_thread_flag(TIF_POLLING_NRFLAG); - smp_mb__after_clear_bit(); - set_bl_bit(); - while (!need_resched()) - cpu_sleep(); - clear_bl_bit(); - set_thread_flag(TIF_POLLING_NRFLAG); - } else - while (!need_resched()) - cpu_relax(); -} - -void cpu_idle(void) -{ - set_thread_flag(TIF_POLLING_NRFLAG); - - /* endless idle loop with no priority at all */ - while (1) { - void (*idle)(void) = pm_idle; - - if (!idle) - idle = default_idle; - - tick_nohz_stop_sched_tick(1); - while (!need_resched()) - idle(); - tick_nohz_restart_sched_tick(); - - preempt_enable_no_resched(); - schedule(); - preempt_disable(); - check_pgt_cache(); - } -} - void machine_restart(char * __unused) { /* SR.BL=1 and invoke address error to let CPU reset (manual reset) */ @@ -115,8 +58,8 @@ void machine_power_off(void) void show_regs(struct pt_regs * regs) { printk("\n"); - printk("Pid : %d, Comm: %20s\n", task_pid_nr(current), current->comm); - printk("CPU : %d %s (%s %.*s)\n", + printk("Pid : %d, Comm: \t\t%s\n", task_pid_nr(current), current->comm); + printk("CPU : %d \t\t%s (%s %.*s)\n\n", smp_processor_id(), print_tainted(), init_utsname()->release, (int)strcspn(init_utsname()->version, " "), init_utsname()->version); @@ -148,26 +91,16 @@ void show_regs(struct pt_regs * regs) regs->mach, regs->macl, regs->gbr, regs->pr); show_trace(NULL, (unsigned long *)regs->regs[15], regs); + show_code(regs); } /* * Create a kernel thread */ - -/* - * This is the mechanism for creating a new kernel thread. - * - */ -extern void kernel_thread_helper(void); -__asm__(".align 5\n" - "kernel_thread_helper:\n\t" - "jsr @r5\n\t" - " nop\n\t" - "mov.l 1f, r1\n\t" - "jsr @r1\n\t" - " mov r0, r4\n\t" - ".align 2\n\t" - "1:.long do_exit"); +ATTRIB_NORET void kernel_thread_helper(void *arg, int (*fn)(void *)) +{ + do_exit(fn(arg)); +} /* Don't use this in BL=1(cli). Or else, CPU resets! */ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) diff --git a/arch/sh/kernel/process_64.c b/arch/sh/kernel/process_64.c index b7aa09235b51a65202119a5afaa324549d172b35..a7e5f2e74bacd20fd9bced8573715bcc5b8301dd 100644 --- a/arch/sh/kernel/process_64.c +++ b/arch/sh/kernel/process_64.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -33,56 +32,6 @@ struct task_struct *last_task_used_math = NULL; -static int hlt_counter = 1; - -#define HARD_IDLE_TIMEOUT (HZ / 3) - -static int __init nohlt_setup(char *__unused) -{ - hlt_counter = 1; - return 1; -} - -static int __init hlt_setup(char *__unused) -{ - hlt_counter = 0; - return 1; -} - -__setup("nohlt", nohlt_setup); -__setup("hlt", hlt_setup); - -static inline void hlt(void) -{ - __asm__ __volatile__ ("sleep" : : : "memory"); -} - -/* - * The idle loop on a uniprocessor SH.. - */ -void cpu_idle(void) -{ - /* endless idle loop with no priority at all */ - while (1) { - if (hlt_counter) { - while (!need_resched()) - cpu_relax(); - } else { - local_irq_disable(); - while (!need_resched()) { - local_irq_enable(); - hlt(); - local_irq_disable(); - } - local_irq_enable(); - } - preempt_enable_no_resched(); - schedule(); - preempt_disable(); - } - -} - void machine_restart(char * __unused) { extern void phys_stext(void); @@ -97,13 +46,6 @@ void machine_halt(void) void machine_power_off(void) { -#if 0 - /* Disable watchdog timer */ - ctrl_outl(0xa5000000, WTCSR); - /* Configure deep standby on sleep */ - ctrl_outl(0x03, STBCR); -#endif - __asm__ __volatile__ ( "sleep\n\t" "synci\n\t" @@ -113,9 +55,6 @@ void machine_power_off(void) panic("Unexpected wakeup!\n"); } -void (*pm_power_off)(void) = machine_power_off; -EXPORT_SYMBOL(pm_power_off); - void show_regs(struct pt_regs * regs) { unsigned long long ah, al, bh, bl, ch, cl; @@ -365,18 +304,6 @@ void show_regs(struct pt_regs * regs) } } -struct task_struct * alloc_task_struct(void) -{ - /* Get task descriptor pages */ - return (struct task_struct *) - __get_free_pages(GFP_KERNEL, get_order(THREAD_SIZE)); -} - -void free_task_struct(struct task_struct *p) -{ - free_pages((unsigned long) p, get_order(THREAD_SIZE)); -} - /* * Create a kernel thread */ @@ -662,41 +589,3 @@ unsigned long get_wchan(struct task_struct *p) #endif return pc; } - -/* Provide a /proc/asids file that lists out the - ASIDs currently associated with the processes. (If the DM.PC register is - examined through the debug link, this shows ASID + PC. To make use of this, - the PID->ASID relationship needs to be known. This is primarily for - debugging.) - */ - -#if defined(CONFIG_SH64_PROC_ASIDS) -static int -asids_proc_info(char *buf, char **start, off_t fpos, int length, int *eof, void *data) -{ - int len=0; - struct task_struct *p; - read_lock(&tasklist_lock); - for_each_process(p) { - int pid = p->pid; - - if (!pid) - continue; - if (p->mm) - len += sprintf(buf+len, "%5d : %02lx\n", pid, - asid_cache(smp_processor_id())); - else - len += sprintf(buf+len, "%5d : (none)\n", pid); - } - read_unlock(&tasklist_lock); - *eof = 1; - return len; -} - -static int __init register_proc_asids(void) -{ - create_proc_read_entry("asids", 0, NULL, asids_proc_info, NULL); - return 0; -} -__initcall(register_proc_asids); -#endif diff --git a/arch/sh/kernel/ptrace_64.c b/arch/sh/kernel/ptrace_64.c index e15b099c1f069f8856e43caa7db2187ab129cb7e..695097438f0207e72de50bd370d8e36d3d7c391c 100644 --- a/arch/sh/kernel/ptrace_64.c +++ b/arch/sh/kernel/ptrace_64.c @@ -2,7 +2,7 @@ * arch/sh/kernel/ptrace_64.c * * Copyright (C) 2000, 2001 Paolo Alberelli - * Copyright (C) 2003 - 2007 Paul Mundt + * Copyright (C) 2003 - 2008 Paul Mundt * * Started from SH3/4 version: * SuperH version: Copyright (C) 1999, 2000 Kaz Kojima & Niibe Yutaka @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include #include #include @@ -137,6 +139,165 @@ void user_disable_single_step(struct task_struct *child) regs->sr &= ~SR_SSTEP; } +static int genregs_get(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + void *kbuf, void __user *ubuf) +{ + const struct pt_regs *regs = task_pt_regs(target); + int ret; + + /* PC, SR, SYSCALL */ + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + ®s->pc, + 0, 3 * sizeof(unsigned long long)); + + /* R1 -> R63 */ + if (!ret) + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + regs->regs, + offsetof(struct pt_regs, regs[0]), + 63 * sizeof(unsigned long long)); + /* TR0 -> TR7 */ + if (!ret) + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + regs->tregs, + offsetof(struct pt_regs, tregs[0]), + 8 * sizeof(unsigned long long)); + + if (!ret) + ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, + sizeof(struct pt_regs), -1); + + return ret; +} + +static int genregs_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + struct pt_regs *regs = task_pt_regs(target); + int ret; + + /* PC, SR, SYSCALL */ + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + ®s->pc, + 0, 3 * sizeof(unsigned long long)); + + /* R1 -> R63 */ + if (!ret && count > 0) + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + regs->regs, + offsetof(struct pt_regs, regs[0]), + 63 * sizeof(unsigned long long)); + + /* TR0 -> TR7 */ + if (!ret && count > 0) + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + regs->tregs, + offsetof(struct pt_regs, tregs[0]), + 8 * sizeof(unsigned long long)); + + if (!ret) + ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, + sizeof(struct pt_regs), -1); + + return ret; +} + +#ifdef CONFIG_SH_FPU +int fpregs_get(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + void *kbuf, void __user *ubuf) +{ + int ret; + + ret = init_fpu(target); + if (ret) + return ret; + + return user_regset_copyout(&pos, &count, &kbuf, &ubuf, + &target->thread.fpu.hard, 0, -1); +} + +static int fpregs_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + int ret; + + ret = init_fpu(target); + if (ret) + return ret; + + set_stopped_child_used_math(target); + + return user_regset_copyin(&pos, &count, &kbuf, &ubuf, + &target->thread.fpu.hard, 0, -1); +} + +static int fpregs_active(struct task_struct *target, + const struct user_regset *regset) +{ + return tsk_used_math(target) ? regset->n : 0; +} +#endif + +/* + * These are our native regset flavours. + */ +enum sh_regset { + REGSET_GENERAL, +#ifdef CONFIG_SH_FPU + REGSET_FPU, +#endif +}; + +static const struct user_regset sh_regsets[] = { + /* + * Format is: + * PC, SR, SYSCALL, + * R1 --> R63, + * TR0 --> TR7, + */ + [REGSET_GENERAL] = { + .core_note_type = NT_PRSTATUS, + .n = ELF_NGREG, + .size = sizeof(long long), + .align = sizeof(long long), + .get = genregs_get, + .set = genregs_set, + }, + +#ifdef CONFIG_SH_FPU + [REGSET_FPU] = { + .core_note_type = NT_PRFPREG, + .n = sizeof(struct user_fpu_struct) / + sizeof(long long), + .size = sizeof(long long), + .align = sizeof(long long), + .get = fpregs_get, + .set = fpregs_set, + .active = fpregs_active, + }, +#endif +}; + +static const struct user_regset_view user_sh64_native_view = { + .name = "sh64", + .e_machine = EM_SH, + .regsets = sh_regsets, + .n = ARRAY_SIZE(sh_regsets), +}; + +const struct user_regset_view *task_user_regset_view(struct task_struct *task) +{ + return &user_sh64_native_view; +} + long arch_ptrace(struct task_struct *child, long request, long addr, long data) { int ret; @@ -195,10 +356,33 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) } break; + case PTRACE_GETREGS: + return copy_regset_to_user(child, &user_sh64_native_view, + REGSET_GENERAL, + 0, sizeof(struct pt_regs), + (void __user *)data); + case PTRACE_SETREGS: + return copy_regset_from_user(child, &user_sh64_native_view, + REGSET_GENERAL, + 0, sizeof(struct pt_regs), + (const void __user *)data); +#ifdef CONFIG_SH_FPU + case PTRACE_GETFPREGS: + return copy_regset_to_user(child, &user_sh64_native_view, + REGSET_FPU, + 0, sizeof(struct user_fpu_struct), + (void __user *)data); + case PTRACE_SETFPREGS: + return copy_regset_from_user(child, &user_sh64_native_view, + REGSET_FPU, + 0, sizeof(struct user_fpu_struct), + (const void __user *)data); +#endif default: ret = ptrace_request(child, request, addr, data); break; } + return ret; } diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index e7152cc6930e38bd4b3dc7bd36cd37ae1caf1cb4..5342475085724c3a2de5959e5cda9ea3e9d6f623 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c @@ -417,6 +417,7 @@ void __init setup_arch(char **cmdline_p) } static const char *cpu_name[] = { + [CPU_SH7201] = "SH7201", [CPU_SH7203] = "SH7203", [CPU_SH7263] = "SH7263", [CPU_SH7206] = "SH7206", [CPU_SH7619] = "SH7619", [CPU_SH7705] = "SH7705", [CPU_SH7706] = "SH7706", diff --git a/arch/sh/kernel/sh_bios.c b/arch/sh/kernel/sh_bios.c index d1bcac4fa2690419e3e4855b2ed97760248f7476..c852f780572803b53ac346eefd3ceed994a20223 100644 --- a/arch/sh/kernel/sh_bios.c +++ b/arch/sh/kernel/sh_bios.c @@ -8,69 +8,50 @@ #include #include -#define BIOS_CALL_CONSOLE_WRITE 0 -#define BIOS_CALL_READ_BLOCK 1 +#define BIOS_CALL_CONSOLE_WRITE 0 #define BIOS_CALL_ETH_NODE_ADDR 10 #define BIOS_CALL_SHUTDOWN 11 -#define BIOS_CALL_CHAR_OUT 0x1f /* TODO: hack */ -#define BIOS_CALL_GDB_GET_MODE_PTR 0xfe -#define BIOS_CALL_GDB_DETACH 0xff +#define BIOS_CALL_CHAR_OUT 0x1f /* TODO: hack */ +#define BIOS_CALL_GDB_DETACH 0xff -static __inline__ long sh_bios_call(long func, long arg0, long arg1, long arg2, long arg3) +static inline long sh_bios_call(long func, long arg0, long arg1, long arg2, + long arg3) { - register long r0 __asm__("r0") = func; - register long r4 __asm__("r4") = arg0; - register long r5 __asm__("r5") = arg1; - register long r6 __asm__("r6") = arg2; - register long r7 __asm__("r7") = arg3; - __asm__ __volatile__("trapa #0x3f" - : "=z" (r0) - : "0" (r0), "r" (r4), "r" (r5), "r" (r6), "r" (r7) - : "memory"); - return r0; + register long r0 __asm__("r0") = func; + register long r4 __asm__("r4") = arg0; + register long r5 __asm__("r5") = arg1; + register long r6 __asm__("r6") = arg2; + register long r7 __asm__("r7") = arg3; + + __asm__ __volatile__("trapa #0x3f":"=z"(r0) + :"0"(r0), "r"(r4), "r"(r5), "r"(r6), "r"(r7) + :"memory"); + return r0; } - void sh_bios_console_write(const char *buf, unsigned int len) { - sh_bios_call(BIOS_CALL_CONSOLE_WRITE, (long)buf, (long)len, 0, 0); + sh_bios_call(BIOS_CALL_CONSOLE_WRITE, (long)buf, (long)len, 0, 0); } - void sh_bios_char_out(char ch) { - sh_bios_call(BIOS_CALL_CHAR_OUT, ch, 0, 0, 0); -} - - -int sh_bios_in_gdb_mode(void) -{ - static char queried = 0; - static char *gdb_mode_p = 0; - - if (!queried) - { - /* Query the gdb stub for address of its gdb mode variable */ - long r = sh_bios_call(BIOS_CALL_GDB_GET_MODE_PTR, 0, 0, 0, 0); - if (r != ~0) /* BIOS returns -1 for unknown function */ - gdb_mode_p = (char *)r; - queried = 1; - } - return (gdb_mode_p != 0 ? *gdb_mode_p : 0); + sh_bios_call(BIOS_CALL_CHAR_OUT, ch, 0, 0, 0); } void sh_bios_gdb_detach(void) { - sh_bios_call(BIOS_CALL_GDB_DETACH, 0, 0, 0, 0); + sh_bios_call(BIOS_CALL_GDB_DETACH, 0, 0, 0, 0); } -EXPORT_SYMBOL(sh_bios_gdb_detach); +EXPORT_SYMBOL_GPL(sh_bios_gdb_detach); -void sh_bios_get_node_addr (unsigned char *node_addr) +void sh_bios_get_node_addr(unsigned char *node_addr) { - sh_bios_call(BIOS_CALL_ETH_NODE_ADDR, 0, (long)node_addr, 0, 0); + sh_bios_call(BIOS_CALL_ETH_NODE_ADDR, 0, (long)node_addr, 0, 0); } +EXPORT_SYMBOL_GPL(sh_bios_get_node_addr); void sh_bios_shutdown(unsigned int how) { - sh_bios_call(BIOS_CALL_SHUTDOWN, how, 0, 0, 0); + sh_bios_call(BIOS_CALL_SHUTDOWN, how, 0, 0, 0); } diff --git a/arch/sh/kernel/sh_ksyms_32.c b/arch/sh/kernel/sh_ksyms_32.c index 92ae5e6c099e4c5e65f8c8affc2cf8fa5404b1c2..528de2955c814dcc4286fd83011439635535f766 100644 --- a/arch/sh/kernel/sh_ksyms_32.c +++ b/arch/sh/kernel/sh_ksyms_32.c @@ -52,16 +52,12 @@ EXPORT_SYMBOL(__const_udelay); #define DECLARE_EXPORT(name) \ extern void name(void);EXPORT_SYMBOL(name) -#define MAYBE_DECLARE_EXPORT(name) \ - extern void name(void) __weak;EXPORT_SYMBOL(name) -/* These symbols are generated by the compiler itself */ DECLARE_EXPORT(__udivsi3); DECLARE_EXPORT(__sdivsi3); +DECLARE_EXPORT(__lshrsi3); DECLARE_EXPORT(__ashrsi3); DECLARE_EXPORT(__ashlsi3); -DECLARE_EXPORT(__ashrdi3); -DECLARE_EXPORT(__ashldi3); DECLARE_EXPORT(__ashiftrt_r4_6); DECLARE_EXPORT(__ashiftrt_r4_7); DECLARE_EXPORT(__ashiftrt_r4_8); @@ -79,8 +75,7 @@ DECLARE_EXPORT(__ashiftrt_r4_23); DECLARE_EXPORT(__ashiftrt_r4_24); DECLARE_EXPORT(__ashiftrt_r4_27); DECLARE_EXPORT(__ashiftrt_r4_30); -DECLARE_EXPORT(__lshrsi3); -DECLARE_EXPORT(__lshrdi3); +DECLARE_EXPORT(__movstr); DECLARE_EXPORT(__movstrSI8); DECLARE_EXPORT(__movstrSI12); DECLARE_EXPORT(__movstrSI16); @@ -95,31 +90,17 @@ DECLARE_EXPORT(__movstrSI48); DECLARE_EXPORT(__movstrSI52); DECLARE_EXPORT(__movstrSI56); DECLARE_EXPORT(__movstrSI60); -#if __GNUC__ == 4 -DECLARE_EXPORT(__movmem); -#else -DECLARE_EXPORT(__movstr); -#endif - -#if __GNUC__ == 4 +DECLARE_EXPORT(__movstr_i4_even); +DECLARE_EXPORT(__movstr_i4_odd); +DECLARE_EXPORT(__movstrSI12_i4); DECLARE_EXPORT(__movmem_i4_even); DECLARE_EXPORT(__movmem_i4_odd); DECLARE_EXPORT(__movmemSI12_i4); - -#if (__GNUC_MINOR__ >= 2 || defined(__GNUC_STM_RELEASE__)) -/* - * GCC >= 4.2 emits these for division, as do GCC 4.1.x versions of the ST - * compiler which include backported patches. - */ DECLARE_EXPORT(__udiv_qrnnd_16); -MAYBE_DECLARE_EXPORT(__sdivsi3_i4i); -MAYBE_DECLARE_EXPORT(__udivsi3_i4i); -#endif -#else /* GCC 3.x */ -DECLARE_EXPORT(__movstr_i4_even); -DECLARE_EXPORT(__movstr_i4_odd); -DECLARE_EXPORT(__movstrSI12_i4); -#endif /* __GNUC__ == 4 */ +DECLARE_EXPORT(__sdivsi3_i4); +DECLARE_EXPORT(__udivsi3_i4); +DECLARE_EXPORT(__sdivsi3_i4i); +DECLARE_EXPORT(__udivsi3_i4i); #if !defined(CONFIG_CACHE_OFF) && (defined(CONFIG_CPU_SH4) || \ defined(CONFIG_SH7705_CACHE_32KB)) diff --git a/arch/sh/kernel/sh_ksyms_64.c b/arch/sh/kernel/sh_ksyms_64.c index 9324d32adacc669c6159a39f6752f59cf286c394..0d74d6b8774e422b1895b7ec1e3b0feb3b4c427e 100644 --- a/arch/sh/kernel/sh_ksyms_64.c +++ b/arch/sh/kernel/sh_ksyms_64.c @@ -65,15 +65,16 @@ EXPORT_SYMBOL(copy_page); EXPORT_SYMBOL(__copy_user); EXPORT_SYMBOL(empty_zero_page); EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(memset); EXPORT_SYMBOL(__udelay); EXPORT_SYMBOL(__ndelay); EXPORT_SYMBOL(__const_udelay); +EXPORT_SYMBOL(strlen); +EXPORT_SYMBOL(strcpy); /* Ugh. These come in from libgcc.a at link time. */ #define DECLARE_EXPORT(name) extern void name(void);EXPORT_SYMBOL(name) DECLARE_EXPORT(__sdivsi3); -DECLARE_EXPORT(__sdivsi3_2); -DECLARE_EXPORT(__muldi3); DECLARE_EXPORT(__udivsi3); DECLARE_EXPORT(__div_table); diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c index 69d09c0b3498e672057fc92f7a5d740be853ef6b..77c21bde376aa7d203870969c8571182049df6db 100644 --- a/arch/sh/kernel/signal_32.c +++ b/arch/sh/kernel/signal_32.c @@ -533,7 +533,6 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, { int ret; - /* Set up the stack frame */ if (ka->sa.sa_flags & SA_SIGINFO) ret = setup_rt_frame(sig, ka, info, oldset, regs); diff --git a/arch/sh/kernel/signal_64.c b/arch/sh/kernel/signal_64.c index ce3e851dffcbca6906f85ebbbfca80421469d461..b22fdfaaa19188667e3d926d3f8433378e8544df 100644 --- a/arch/sh/kernel/signal_64.c +++ b/arch/sh/kernel/signal_64.c @@ -2,7 +2,7 @@ * arch/sh/kernel/signal_64.c * * Copyright (C) 2000, 2001 Paolo Alberelli - * Copyright (C) 2003 Paul Mundt + * Copyright (C) 2003 - 2008 Paul Mundt * Copyright (C) 2004 Richard Curnow * * This file is subject to the terms and conditions of the GNU General Public @@ -43,10 +43,38 @@ #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) -static void +static int handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, sigset_t *oldset, struct pt_regs * regs); +static inline void +handle_syscall_restart(struct pt_regs *regs, struct sigaction *sa) +{ + /* If we're not from a syscall, bail out */ + if (regs->syscall_nr < 0) + return; + + /* check for system call restart.. */ + switch (regs->regs[REG_RET]) { + case -ERESTART_RESTARTBLOCK: + case -ERESTARTNOHAND: + no_system_call_restart: + regs->regs[REG_RET] = -EINTR; + regs->sr |= 1; + break; + + case -ERESTARTSYS: + if (!(sa->sa_flags & SA_RESTART)) + goto no_system_call_restart; + /* fallthrough */ + case -ERESTARTNOINTR: + /* Decode syscall # */ + regs->regs[REG_RET] = regs->syscall_nr; + regs->pc -= 4; + break; + } +} + /* * Note that 'init' is a special process: it doesn't get signals it doesn't * want to handle. Thus you cannot kill init even with a SIGKILL even by @@ -80,21 +108,23 @@ static int do_signal(struct pt_regs *regs, sigset_t *oldset) oldset = ¤t->blocked; signr = get_signal_to_deliver(&info, &ka, regs, 0); - if (signr > 0) { - /* Whee! Actually deliver the signal. */ - handle_signal(signr, &info, &ka, oldset, regs); + if (regs->sr & 1) + handle_syscall_restart(regs, &ka.sa); - /* - * If a signal was successfully delivered, the saved sigmask - * is in its frame, and we can clear the TIF_RESTORE_SIGMASK - * flag. - */ - if (test_thread_flag(TIF_RESTORE_SIGMASK)) - clear_thread_flag(TIF_RESTORE_SIGMASK); - - tracehook_signal_handler(signr, &info, &ka, regs, 0); - return 1; + /* Whee! Actually deliver the signal. */ + if (handle_signal(signr, &info, &ka, oldset, regs) == 0) { + /* + * If a signal was successfully delivered, the + * saved sigmask is in its frame, and we can + * clear the TIF_RESTORE_SIGMASK flag. + */ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + clear_thread_flag(TIF_RESTORE_SIGMASK); + + tracehook_signal_handler(signr, &info, &ka, regs, 0); + return 1; + } } no_signal: @@ -129,7 +159,6 @@ static int do_signal(struct pt_regs *regs, sigset_t *oldset) /* * Atomically swap in the new signal mask, and wait for a signal. */ - asmlinkage int sys_sigsuspend(old_sigset_t mask, unsigned long r3, unsigned long r4, unsigned long r5, @@ -235,20 +264,16 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, return do_sigaltstack(uss, uoss, REF_REG_SP); } - /* * Do a signal return; undo the signal stack. */ - -struct sigframe -{ +struct sigframe { struct sigcontext sc; unsigned long extramask[_NSIG_WORDS-1]; long long retcode[2]; }; -struct rt_sigframe -{ +struct rt_sigframe { struct siginfo __user *pinfo; void *puc; struct siginfo info; @@ -450,7 +475,6 @@ asmlinkage int sys_rt_sigreturn(unsigned long r2, unsigned long r3, /* * Set up a signal frame. */ - static int setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, unsigned long mask) @@ -504,8 +528,8 @@ get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) void sa_default_restorer(void); /* See comments below */ void sa_default_rt_restorer(void); /* See comments below */ -static void setup_frame(int sig, struct k_sigaction *ka, - sigset_t *set, struct pt_regs *regs) +static int setup_frame(int sig, struct k_sigaction *ka, + sigset_t *set, struct pt_regs *regs) { struct sigframe __user *frame; int err = 0; @@ -596,23 +620,21 @@ static void setup_frame(int sig, struct k_sigaction *ka, set_fs(USER_DS); -#if DEBUG_SIG /* Broken %016Lx */ - printk("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n", - signal, - current->comm, current->pid, frame, - regs->pc >> 32, regs->pc & 0xffffffff, - DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff); -#endif + pr_debug("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n", + signal, current->comm, current->pid, frame, + regs->pc >> 32, regs->pc & 0xffffffff, + DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff); - return; + return 0; give_sigsegv: force_sigsegv(sig, current); + return -EFAULT; } -static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, - sigset_t *set, struct pt_regs *regs) +static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *set, struct pt_regs *regs) { struct rt_sigframe __user *frame; int err = 0; @@ -702,62 +724,46 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, set_fs(USER_DS); -#if DEBUG_SIG - /* Broken %016Lx */ - printk("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n", - signal, - current->comm, current->pid, frame, - regs->pc >> 32, regs->pc & 0xffffffff, - DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff); -#endif + pr_debug("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n", + signal, current->comm, current->pid, frame, + regs->pc >> 32, regs->pc & 0xffffffff, + DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff); - return; + return 0; give_sigsegv: force_sigsegv(sig, current); + return -EFAULT; } /* * OK, we're invoking a handler */ - -static void +static int handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, sigset_t *oldset, struct pt_regs * regs) { - /* Are we from a system call? */ - if (regs->syscall_nr >= 0) { - /* If so, check system call restarting.. */ - switch (regs->regs[REG_RET]) { - case -ERESTART_RESTARTBLOCK: - case -ERESTARTNOHAND: - no_system_call_restart: - regs->regs[REG_RET] = -EINTR; - break; - - case -ERESTARTSYS: - if (!(ka->sa.sa_flags & SA_RESTART)) - goto no_system_call_restart; - /* fallthrough */ - case -ERESTARTNOINTR: - /* Decode syscall # */ - regs->regs[REG_RET] = regs->syscall_nr; - regs->pc -= 4; - } - } + int ret; /* Set up the stack frame */ if (ka->sa.sa_flags & SA_SIGINFO) - setup_rt_frame(sig, ka, info, oldset, regs); + ret = setup_rt_frame(sig, ka, info, oldset, regs); else - setup_frame(sig, ka, oldset, regs); + ret = setup_frame(sig, ka, oldset, regs); + + if (ka->sa.sa_flags & SA_ONESHOT) + ka->sa.sa_handler = SIG_DFL; + + if (ret == 0) { + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NODEFER)) + sigaddset(¤t->blocked,sig); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + } - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); - if (!(ka->sa.sa_flags & SA_NODEFER)) - sigaddset(¤t->blocked,sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + return ret; } asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags) diff --git a/arch/sh/kernel/sys_sh.c b/arch/sh/kernel/sys_sh.c index 38f098c9c72de2e2fd6eb47cbe4b3c874420aa72..58dfc02c7af13bd92431cf16dfc44d8ea9c75f31 100644 --- a/arch/sh/kernel/sys_sh.c +++ b/arch/sh/kernel/sys_sh.c @@ -22,102 +22,10 @@ #include #include #include -#include #include #include #include -unsigned long shm_align_mask = PAGE_SIZE - 1; /* Sane caches */ -EXPORT_SYMBOL(shm_align_mask); - -#ifdef CONFIG_MMU -/* - * To avoid cache aliases, we map the shared page with same color. - */ -#define COLOUR_ALIGN(addr, pgoff) \ - ((((addr) + shm_align_mask) & ~shm_align_mask) + \ - (((pgoff) << PAGE_SHIFT) & shm_align_mask)) - -unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, - unsigned long len, unsigned long pgoff, unsigned long flags) -{ - struct mm_struct *mm = current->mm; - struct vm_area_struct *vma; - unsigned long start_addr; - int do_colour_align; - - if (flags & MAP_FIXED) { - /* We do not accept a shared mapping if it would violate - * cache aliasing constraints. - */ - if ((flags & MAP_SHARED) && (addr & shm_align_mask)) - return -EINVAL; - return addr; - } - - if (unlikely(len > TASK_SIZE)) - return -ENOMEM; - - do_colour_align = 0; - if (filp || (flags & MAP_SHARED)) - do_colour_align = 1; - - if (addr) { - if (do_colour_align) - addr = COLOUR_ALIGN(addr, pgoff); - else - addr = PAGE_ALIGN(addr); - - vma = find_vma(mm, addr); - if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vma->vm_start)) - return addr; - } - - if (len > mm->cached_hole_size) { - start_addr = addr = mm->free_area_cache; - } else { - mm->cached_hole_size = 0; - start_addr = addr = TASK_UNMAPPED_BASE; - } - -full_search: - if (do_colour_align) - addr = COLOUR_ALIGN(addr, pgoff); - else - addr = PAGE_ALIGN(mm->free_area_cache); - - for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { - /* At this point: (!vma || addr < vma->vm_end). */ - if (unlikely(TASK_SIZE - len < addr)) { - /* - * Start a new search - just in case we missed - * some holes. - */ - if (start_addr != TASK_UNMAPPED_BASE) { - start_addr = addr = TASK_UNMAPPED_BASE; - mm->cached_hole_size = 0; - goto full_search; - } - return -ENOMEM; - } - if (likely(!vma || addr + len <= vma->vm_start)) { - /* - * Remember the place where we stopped the search: - */ - mm->free_area_cache = addr + len; - return addr; - } - if (addr + mm->cached_hole_size < vma->vm_start) - mm->cached_hole_size = vma->vm_start - addr; - - addr = vma->vm_end; - if (do_colour_align) - addr = COLOUR_ALIGN(addr, pgoff); - } -} -#endif /* CONFIG_MMU */ - static inline long do_mmap2(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, int fd, unsigned long pgoff) diff --git a/arch/sh/kernel/time_32.c b/arch/sh/kernel/time_32.c index 23ca711c27d2af9e6e15106a17bcdb8e92bea47c..8457f83242c536a35cc47fb6086a64e01bdb0a80 100644 --- a/arch/sh/kernel/time_32.c +++ b/arch/sh/kernel/time_32.c @@ -125,11 +125,6 @@ void handle_timer_tick(void) if (current->pid) profile_tick(CPU_PROFILING); -#ifdef CONFIG_HEARTBEAT - if (sh_mv.mv_heartbeat != NULL) - sh_mv.mv_heartbeat(); -#endif - /* * Here we are in the timer irq handler. We just have irqs locally * disabled but we don't know if the timer_bh is running on the other @@ -277,11 +272,4 @@ void __init time_init(void) ((sh_hpt_frequency + 500) / 1000) / 1000, ((sh_hpt_frequency + 500) / 1000) % 1000); -#if defined(CONFIG_SH_KGDB) - /* - * Set up kgdb as requested. We do it here because the serial - * init uses the timer vars we just set up for figuring baud. - */ - kgdb_init(); -#endif } diff --git a/arch/sh/kernel/time_64.c b/arch/sh/kernel/time_64.c index bbb2af1004d9eb2639598c1eef87b8954e147ef8..59d2a03e8b3c475763ff1d228e6177454f27fe1d 100644 --- a/arch/sh/kernel/time_64.c +++ b/arch/sh/kernel/time_64.c @@ -240,11 +240,6 @@ static inline void do_timer_interrupt(void) do_timer(1); -#ifdef CONFIG_HEARTBEAT - if (sh_mv.mv_heartbeat != NULL) - sh_mv.mv_heartbeat(); -#endif - /* * If we have an externally synchronized Linux clock, then update * RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be diff --git a/arch/sh/kernel/timers/timer-mtu2.c b/arch/sh/kernel/timers/timer-mtu2.c index fe453c01f9c9d533ab4d3fd5e4e1356c4bba6aa8..c3d237e1d566e4c91704284b07a8ced28ce2ba1d 100644 --- a/arch/sh/kernel/timers/timer-mtu2.c +++ b/arch/sh/kernel/timers/timer-mtu2.c @@ -34,7 +34,12 @@ #define MTU2_TIER_1 0xfffe4384 #define MTU2_TSR_1 0xfffe4385 #define MTU2_TCNT_1 0xfffe4386 /* 16-bit counter */ + +#if defined(CONFIG_CPU_SUBTYPE_SH7201) +#define MTU2_TGRA_1 0xfffe4388 +#else #define MTU2_TGRA_1 0xfffe438a +#endif #define STBCR3 0xfffe0408 diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c index 1e5c74efbacc35d4f729b17cb08b342bbca2045f..88807a2aacc32c583d7b5d1e2392ad0961a87181 100644 --- a/arch/sh/kernel/traps_32.c +++ b/arch/sh/kernel/traps_32.c @@ -28,17 +28,6 @@ #include #include -#ifdef CONFIG_SH_KGDB -#include -#define CHK_REMOTE_DEBUG(regs) \ -{ \ - if (kgdb_debug_hook && !user_mode(regs))\ - (*kgdb_debug_hook)(regs); \ -} -#else -#define CHK_REMOTE_DEBUG(regs) -#endif - #ifdef CONFIG_CPU_SH2 # define TRAP_RESERVED_INST 4 # define TRAP_ILLEGAL_SLOT_INST 6 @@ -94,7 +83,6 @@ void die(const char * str, struct pt_regs * regs, long err) printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter); - CHK_REMOTE_DEBUG(regs); print_modules(); show_regs(regs); @@ -683,13 +671,12 @@ asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5, error_code = lookup_exception_vector(); local_irq_enable(); - CHK_REMOTE_DEBUG(regs); force_sig(SIGILL, tsk); die_if_no_fixup("reserved instruction", regs, error_code); } #ifdef CONFIG_SH_FPU_EMU -static int emulate_branch(unsigned short inst, struct pt_regs* regs) +static int emulate_branch(unsigned short inst, struct pt_regs *regs) { /* * bfs: 8fxx: PC+=d*2+4; @@ -702,27 +689,32 @@ static int emulate_branch(unsigned short inst, struct pt_regs* regs) * jsr: 4x0b: PC=Rn after PR=PC+4; * rts: 000b: PC=PR; */ - if ((inst & 0xfd00) == 0x8d00) { + if (((inst & 0xf000) == 0xb000) || /* bsr */ + ((inst & 0xf0ff) == 0x0003) || /* bsrf */ + ((inst & 0xf0ff) == 0x400b)) /* jsr */ + regs->pr = regs->pc + 4; + + if ((inst & 0xfd00) == 0x8d00) { /* bfs, bts */ regs->pc += SH_PC_8BIT_OFFSET(inst); return 0; } - if ((inst & 0xe000) == 0xa000) { + if ((inst & 0xe000) == 0xa000) { /* bra, bsr */ regs->pc += SH_PC_12BIT_OFFSET(inst); return 0; } - if ((inst & 0xf0df) == 0x0003) { + if ((inst & 0xf0df) == 0x0003) { /* braf, bsrf */ regs->pc += regs->regs[(inst & 0x0f00) >> 8] + 4; return 0; } - if ((inst & 0xf0df) == 0x400b) { + if ((inst & 0xf0df) == 0x400b) { /* jmp, jsr */ regs->pc = regs->regs[(inst & 0x0f00) >> 8]; return 0; } - if ((inst & 0xffff) == 0x000b) { + if ((inst & 0xffff) == 0x000b) { /* rts */ regs->pc = regs->pr; return 0; } @@ -756,7 +748,6 @@ asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5, inst = lookup_exception_vector(); local_irq_enable(); - CHK_REMOTE_DEBUG(regs); force_sig(SIGILL, tsk); die_if_no_fixup("illegal slot instruction", regs, inst); } @@ -868,10 +859,7 @@ void show_trace(struct task_struct *tsk, unsigned long *sp, if (regs && user_mode(regs)) return; - printk("\nCall trace: "); -#ifdef CONFIG_KALLSYMS - printk("\n"); -#endif + printk("\nCall trace:\n"); while (!kstack_end(sp)) { addr = *sp++; diff --git a/arch/sh/kernel/vsyscall/vsyscall.c b/arch/sh/kernel/vsyscall/vsyscall.c index 95f4de0800ec71ceaf167d7801168d5011d95d4e..3f7e415be86ade5ee681e11b174754d91f231d6b 100644 --- a/arch/sh/kernel/vsyscall/vsyscall.c +++ b/arch/sh/kernel/vsyscall/vsyscall.c @@ -59,8 +59,7 @@ int __init vsyscall_init(void) } /* Setup a VMA at program startup for the vsyscall page */ -int arch_setup_additional_pages(struct linux_binprm *bprm, - int executable_stack) +int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) { struct mm_struct *mm = current->mm; unsigned long addr; diff --git a/arch/sh/lib/Makefile b/arch/sh/lib/Makefile index 8596cc78e18d0927cb938466f934bd4d8fc22ec8..aaea580b65bba98ccf687296fe4a6a735fe72ccc 100644 --- a/arch/sh/lib/Makefile +++ b/arch/sh/lib/Makefile @@ -5,12 +5,26 @@ lib-y = delay.o memset.o memmove.o memchr.o \ checksum.o strlen.o div64.o div64-generic.o +# Extracted from libgcc +lib-y += movmem.o ashldi3.o ashrdi3.o lshrdi3.o \ + ashlsi3.o ashrsi3.o ashiftrt.o lshrsi3.o \ + udiv_qrnnd.o + +udivsi3-y := udivsi3_i4i-Os.o + +ifneq ($(CONFIG_CC_OPTIMIZE_FOR_SIZE),y) +udivsi3-$(CONFIG_CPU_SH3) := udivsi3_i4i.o +udivsi3-$(CONFIG_CPU_SH4) := udivsi3_i4i.o +endif +udivsi3-y += udivsi3.o + obj-y += io.o memcpy-y := memcpy.o memcpy-$(CONFIG_CPU_SH4) := memcpy-sh4.o lib-$(CONFIG_MMU) += copy_page.o clear_page.o -lib-y += $(memcpy-y) +lib-$(CONFIG_FUNCTION_TRACER) += mcount.o +lib-y += $(memcpy-y) $(udivsi3-y) EXTRA_CFLAGS += -Werror diff --git a/arch/sh/lib/ashiftrt.S b/arch/sh/lib/ashiftrt.S new file mode 100644 index 0000000000000000000000000000000000000000..45ce86558f461419d019e84002b885bfdf8e349a --- /dev/null +++ b/arch/sh/lib/ashiftrt.S @@ -0,0 +1,149 @@ +/* Copyright (C) 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003, + 2004, 2005, 2006 + Free Software Foundation, Inc. + +This file is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file into combinations with other programs, +and to distribute those combinations without any restriction coming +from the use of this file. (The General Public License restrictions +do apply in other respects; for example, they cover modification of +the file, and distribution when not linked into a combine +executable.) + +This file is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +!! libgcc routines for the Renesas / SuperH SH CPUs. +!! Contributed by Steve Chamberlain. +!! sac@cygnus.com + +!! ashiftrt_r4_x, ___ashrsi3, ___ashlsi3, ___lshrsi3 routines +!! recoded in assembly by Toshiyasu Morita +!! tm@netcom.com + +/* SH2 optimizations for ___ashrsi3, ___ashlsi3, ___lshrsi3 and + ELF local label prefixes by J"orn Rennecke + amylaar@cygnus.com */ + + .global __ashiftrt_r4_0 + .global __ashiftrt_r4_1 + .global __ashiftrt_r4_2 + .global __ashiftrt_r4_3 + .global __ashiftrt_r4_4 + .global __ashiftrt_r4_5 + .global __ashiftrt_r4_6 + .global __ashiftrt_r4_7 + .global __ashiftrt_r4_8 + .global __ashiftrt_r4_9 + .global __ashiftrt_r4_10 + .global __ashiftrt_r4_11 + .global __ashiftrt_r4_12 + .global __ashiftrt_r4_13 + .global __ashiftrt_r4_14 + .global __ashiftrt_r4_15 + .global __ashiftrt_r4_16 + .global __ashiftrt_r4_17 + .global __ashiftrt_r4_18 + .global __ashiftrt_r4_19 + .global __ashiftrt_r4_20 + .global __ashiftrt_r4_21 + .global __ashiftrt_r4_22 + .global __ashiftrt_r4_23 + .global __ashiftrt_r4_24 + .global __ashiftrt_r4_25 + .global __ashiftrt_r4_26 + .global __ashiftrt_r4_27 + .global __ashiftrt_r4_28 + .global __ashiftrt_r4_29 + .global __ashiftrt_r4_30 + .global __ashiftrt_r4_31 + .global __ashiftrt_r4_32 + + .align 1 +__ashiftrt_r4_32: +__ashiftrt_r4_31: + rotcl r4 + rts + subc r4,r4 +__ashiftrt_r4_30: + shar r4 +__ashiftrt_r4_29: + shar r4 +__ashiftrt_r4_28: + shar r4 +__ashiftrt_r4_27: + shar r4 +__ashiftrt_r4_26: + shar r4 +__ashiftrt_r4_25: + shar r4 +__ashiftrt_r4_24: + shlr16 r4 + shlr8 r4 + rts + exts.b r4,r4 +__ashiftrt_r4_23: + shar r4 +__ashiftrt_r4_22: + shar r4 +__ashiftrt_r4_21: + shar r4 +__ashiftrt_r4_20: + shar r4 +__ashiftrt_r4_19: + shar r4 +__ashiftrt_r4_18: + shar r4 +__ashiftrt_r4_17: + shar r4 +__ashiftrt_r4_16: + shlr16 r4 + rts + exts.w r4,r4 +__ashiftrt_r4_15: + shar r4 +__ashiftrt_r4_14: + shar r4 +__ashiftrt_r4_13: + shar r4 +__ashiftrt_r4_12: + shar r4 +__ashiftrt_r4_11: + shar r4 +__ashiftrt_r4_10: + shar r4 +__ashiftrt_r4_9: + shar r4 +__ashiftrt_r4_8: + shar r4 +__ashiftrt_r4_7: + shar r4 +__ashiftrt_r4_6: + shar r4 +__ashiftrt_r4_5: + shar r4 +__ashiftrt_r4_4: + shar r4 +__ashiftrt_r4_3: + shar r4 +__ashiftrt_r4_2: + shar r4 +__ashiftrt_r4_1: + rts + shar r4 +__ashiftrt_r4_0: + rts + nop diff --git a/arch/sh/lib/ashldi3.c b/arch/sh/lib/ashldi3.c new file mode 100644 index 0000000000000000000000000000000000000000..beb80f3160957b3acd833c65158be177c8a6f7ea --- /dev/null +++ b/arch/sh/lib/ashldi3.c @@ -0,0 +1,29 @@ +#include + +#include "libgcc.h" + +long long __ashldi3(long long u, word_type b) +{ + DWunion uu, w; + word_type bm; + + if (b == 0) + return u; + + uu.ll = u; + bm = 32 - b; + + if (bm <= 0) { + w.s.low = 0; + w.s.high = (unsigned int) uu.s.low << -bm; + } else { + const unsigned int carries = (unsigned int) uu.s.low >> bm; + + w.s.low = (unsigned int) uu.s.low << b; + w.s.high = ((unsigned int) uu.s.high << b) | carries; + } + + return w.ll; +} + +EXPORT_SYMBOL(__ashldi3); diff --git a/arch/sh/lib/ashlsi3.S b/arch/sh/lib/ashlsi3.S new file mode 100644 index 0000000000000000000000000000000000000000..bd47e9b403a5bc605fa3b424c5001269ab519e3c --- /dev/null +++ b/arch/sh/lib/ashlsi3.S @@ -0,0 +1,193 @@ +/* Copyright (C) 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003, + 2004, 2005, 2006 + Free Software Foundation, Inc. + +This file is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file into combinations with other programs, +and to distribute those combinations without any restriction coming +from the use of this file. (The General Public License restrictions +do apply in other respects; for example, they cover modification of +the file, and distribution when not linked into a combine +executable.) + +This file is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +!! libgcc routines for the Renesas / SuperH SH CPUs. +!! Contributed by Steve Chamberlain. +!! sac@cygnus.com + +!! ashiftrt_r4_x, ___ashrsi3, ___ashlsi3, ___lshrsi3 routines +!! recoded in assembly by Toshiyasu Morita +!! tm@netcom.com + +/* SH2 optimizations for ___ashrsi3, ___ashlsi3, ___lshrsi3 and + ELF local label prefixes by J"orn Rennecke + amylaar@cygnus.com */ + +! +! __ashlsi3 +! +! Entry: +! +! r4: Value to shift +! r5: Shifts +! +! Exit: +! +! r0: Result +! +! Destroys: +! +! (none) +! + .global __ashlsi3 + + .align 2 +__ashlsi3: + mov #31,r0 + and r0,r5 + mova ashlsi3_table,r0 + mov.b @(r0,r5),r5 +#ifdef __sh1__ + add r5,r0 + jmp @r0 +#else + braf r5 +#endif + mov r4,r0 + + .align 2 +ashlsi3_table: + .byte ashlsi3_0-ashlsi3_table + .byte ashlsi3_1-ashlsi3_table + .byte ashlsi3_2-ashlsi3_table + .byte ashlsi3_3-ashlsi3_table + .byte ashlsi3_4-ashlsi3_table + .byte ashlsi3_5-ashlsi3_table + .byte ashlsi3_6-ashlsi3_table + .byte ashlsi3_7-ashlsi3_table + .byte ashlsi3_8-ashlsi3_table + .byte ashlsi3_9-ashlsi3_table + .byte ashlsi3_10-ashlsi3_table + .byte ashlsi3_11-ashlsi3_table + .byte ashlsi3_12-ashlsi3_table + .byte ashlsi3_13-ashlsi3_table + .byte ashlsi3_14-ashlsi3_table + .byte ashlsi3_15-ashlsi3_table + .byte ashlsi3_16-ashlsi3_table + .byte ashlsi3_17-ashlsi3_table + .byte ashlsi3_18-ashlsi3_table + .byte ashlsi3_19-ashlsi3_table + .byte ashlsi3_20-ashlsi3_table + .byte ashlsi3_21-ashlsi3_table + .byte ashlsi3_22-ashlsi3_table + .byte ashlsi3_23-ashlsi3_table + .byte ashlsi3_24-ashlsi3_table + .byte ashlsi3_25-ashlsi3_table + .byte ashlsi3_26-ashlsi3_table + .byte ashlsi3_27-ashlsi3_table + .byte ashlsi3_28-ashlsi3_table + .byte ashlsi3_29-ashlsi3_table + .byte ashlsi3_30-ashlsi3_table + .byte ashlsi3_31-ashlsi3_table + +ashlsi3_6: + shll2 r0 +ashlsi3_4: + shll2 r0 +ashlsi3_2: + rts + shll2 r0 + +ashlsi3_7: + shll2 r0 +ashlsi3_5: + shll2 r0 +ashlsi3_3: + shll2 r0 +ashlsi3_1: + rts + shll r0 + +ashlsi3_14: + shll2 r0 +ashlsi3_12: + shll2 r0 +ashlsi3_10: + shll2 r0 +ashlsi3_8: + rts + shll8 r0 + +ashlsi3_15: + shll2 r0 +ashlsi3_13: + shll2 r0 +ashlsi3_11: + shll2 r0 +ashlsi3_9: + shll8 r0 + rts + shll r0 + +ashlsi3_22: + shll2 r0 +ashlsi3_20: + shll2 r0 +ashlsi3_18: + shll2 r0 +ashlsi3_16: + rts + shll16 r0 + +ashlsi3_23: + shll2 r0 +ashlsi3_21: + shll2 r0 +ashlsi3_19: + shll2 r0 +ashlsi3_17: + shll16 r0 + rts + shll r0 + +ashlsi3_30: + shll2 r0 +ashlsi3_28: + shll2 r0 +ashlsi3_26: + shll2 r0 +ashlsi3_24: + shll16 r0 + rts + shll8 r0 + +ashlsi3_31: + shll2 r0 +ashlsi3_29: + shll2 r0 +ashlsi3_27: + shll2 r0 +ashlsi3_25: + shll16 r0 + shll8 r0 + rts + shll r0 + +ashlsi3_0: + rts + nop diff --git a/arch/sh/lib/ashrdi3.c b/arch/sh/lib/ashrdi3.c new file mode 100644 index 0000000000000000000000000000000000000000..c884a912b660ea28c88abe9d923d2a7214ccadcd --- /dev/null +++ b/arch/sh/lib/ashrdi3.c @@ -0,0 +1,31 @@ +#include + +#include "libgcc.h" + +long long __ashrdi3(long long u, word_type b) +{ + DWunion uu, w; + word_type bm; + + if (b == 0) + return u; + + uu.ll = u; + bm = 32 - b; + + if (bm <= 0) { + /* w.s.high = 1..1 or 0..0 */ + w.s.high = + uu.s.high >> 31; + w.s.low = uu.s.high >> -bm; + } else { + const unsigned int carries = (unsigned int) uu.s.high << bm; + + w.s.high = uu.s.high >> b; + w.s.low = ((unsigned int) uu.s.low >> b) | carries; + } + + return w.ll; +} + +EXPORT_SYMBOL(__ashrdi3); diff --git a/arch/sh/lib/ashrsi3.S b/arch/sh/lib/ashrsi3.S new file mode 100644 index 0000000000000000000000000000000000000000..6f3cf46b77c2c1cac502030cb3a0c7a8acdb1308 --- /dev/null +++ b/arch/sh/lib/ashrsi3.S @@ -0,0 +1,185 @@ +/* Copyright (C) 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003, + 2004, 2005, 2006 + Free Software Foundation, Inc. + +This file is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file into combinations with other programs, +and to distribute those combinations without any restriction coming +from the use of this file. (The General Public License restrictions +do apply in other respects; for example, they cover modification of +the file, and distribution when not linked into a combine +executable.) + +This file is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +!! libgcc routines for the Renesas / SuperH SH CPUs. +!! Contributed by Steve Chamberlain. +!! sac@cygnus.com + +!! ashiftrt_r4_x, ___ashrsi3, ___ashlsi3, ___lshrsi3 routines +!! recoded in assembly by Toshiyasu Morita +!! tm@netcom.com + +/* SH2 optimizations for ___ashrsi3, ___ashlsi3, ___lshrsi3 and + ELF local label prefixes by J"orn Rennecke + amylaar@cygnus.com */ + +! +! __ashrsi3 +! +! Entry: +! +! r4: Value to shift +! r5: Shifts +! +! Exit: +! +! r0: Result +! +! Destroys: +! +! (none) +! + + .global __ashrsi3 + + .align 2 +__ashrsi3: + mov #31,r0 + and r0,r5 + mova ashrsi3_table,r0 + mov.b @(r0,r5),r5 +#ifdef __sh1__ + add r5,r0 + jmp @r0 +#else + braf r5 +#endif + mov r4,r0 + + .align 2 +ashrsi3_table: + .byte ashrsi3_0-ashrsi3_table + .byte ashrsi3_1-ashrsi3_table + .byte ashrsi3_2-ashrsi3_table + .byte ashrsi3_3-ashrsi3_table + .byte ashrsi3_4-ashrsi3_table + .byte ashrsi3_5-ashrsi3_table + .byte ashrsi3_6-ashrsi3_table + .byte ashrsi3_7-ashrsi3_table + .byte ashrsi3_8-ashrsi3_table + .byte ashrsi3_9-ashrsi3_table + .byte ashrsi3_10-ashrsi3_table + .byte ashrsi3_11-ashrsi3_table + .byte ashrsi3_12-ashrsi3_table + .byte ashrsi3_13-ashrsi3_table + .byte ashrsi3_14-ashrsi3_table + .byte ashrsi3_15-ashrsi3_table + .byte ashrsi3_16-ashrsi3_table + .byte ashrsi3_17-ashrsi3_table + .byte ashrsi3_18-ashrsi3_table + .byte ashrsi3_19-ashrsi3_table + .byte ashrsi3_20-ashrsi3_table + .byte ashrsi3_21-ashrsi3_table + .byte ashrsi3_22-ashrsi3_table + .byte ashrsi3_23-ashrsi3_table + .byte ashrsi3_24-ashrsi3_table + .byte ashrsi3_25-ashrsi3_table + .byte ashrsi3_26-ashrsi3_table + .byte ashrsi3_27-ashrsi3_table + .byte ashrsi3_28-ashrsi3_table + .byte ashrsi3_29-ashrsi3_table + .byte ashrsi3_30-ashrsi3_table + .byte ashrsi3_31-ashrsi3_table + +ashrsi3_31: + rotcl r0 + rts + subc r0,r0 + +ashrsi3_30: + shar r0 +ashrsi3_29: + shar r0 +ashrsi3_28: + shar r0 +ashrsi3_27: + shar r0 +ashrsi3_26: + shar r0 +ashrsi3_25: + shar r0 +ashrsi3_24: + shlr16 r0 + shlr8 r0 + rts + exts.b r0,r0 + +ashrsi3_23: + shar r0 +ashrsi3_22: + shar r0 +ashrsi3_21: + shar r0 +ashrsi3_20: + shar r0 +ashrsi3_19: + shar r0 +ashrsi3_18: + shar r0 +ashrsi3_17: + shar r0 +ashrsi3_16: + shlr16 r0 + rts + exts.w r0,r0 + +ashrsi3_15: + shar r0 +ashrsi3_14: + shar r0 +ashrsi3_13: + shar r0 +ashrsi3_12: + shar r0 +ashrsi3_11: + shar r0 +ashrsi3_10: + shar r0 +ashrsi3_9: + shar r0 +ashrsi3_8: + shar r0 +ashrsi3_7: + shar r0 +ashrsi3_6: + shar r0 +ashrsi3_5: + shar r0 +ashrsi3_4: + shar r0 +ashrsi3_3: + shar r0 +ashrsi3_2: + shar r0 +ashrsi3_1: + rts + shar r0 + +ashrsi3_0: + rts + nop diff --git a/arch/sh/lib/libgcc.h b/arch/sh/lib/libgcc.h new file mode 100644 index 0000000000000000000000000000000000000000..3f19d1c5d942207525766dae07f95139bb35dc59 --- /dev/null +++ b/arch/sh/lib/libgcc.h @@ -0,0 +1,26 @@ +#ifndef __ASM_LIBGCC_H +#define __ASM_LIBGCC_H + +#include + +typedef int word_type __attribute__ ((mode (__word__))); + +#ifdef __BIG_ENDIAN +struct DWstruct { + int high, low; +}; +#elif defined(__LITTLE_ENDIAN) +struct DWstruct { + int low, high; +}; +#else +#error I feel sick. +#endif + +typedef union +{ + struct DWstruct s; + long long ll; +} DWunion; + +#endif /* __ASM_LIBGCC_H */ diff --git a/arch/sh/lib/lshrdi3.c b/arch/sh/lib/lshrdi3.c new file mode 100644 index 0000000000000000000000000000000000000000..dcf8d6810b7c1c940fd5bbb2f4eb9c7cb826d639 --- /dev/null +++ b/arch/sh/lib/lshrdi3.c @@ -0,0 +1,29 @@ +#include + +#include "libgcc.h" + +long long __lshrdi3(long long u, word_type b) +{ + DWunion uu, w; + word_type bm; + + if (b == 0) + return u; + + uu.ll = u; + bm = 32 - b; + + if (bm <= 0) { + w.s.high = 0; + w.s.low = (unsigned int) uu.s.high >> -bm; + } else { + const unsigned int carries = (unsigned int) uu.s.high << bm; + + w.s.high = (unsigned int) uu.s.high >> b; + w.s.low = ((unsigned int) uu.s.low >> b) | carries; + } + + return w.ll; +} + +EXPORT_SYMBOL(__lshrdi3); diff --git a/arch/sh/lib/lshrsi3.S b/arch/sh/lib/lshrsi3.S new file mode 100644 index 0000000000000000000000000000000000000000..1e7aaa55713035f8d9ba8c5a4e08adfe1268265d --- /dev/null +++ b/arch/sh/lib/lshrsi3.S @@ -0,0 +1,193 @@ +/* Copyright (C) 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003, + 2004, 2005, 2006 + Free Software Foundation, Inc. + +This file is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file into combinations with other programs, +and to distribute those combinations without any restriction coming +from the use of this file. (The General Public License restrictions +do apply in other respects; for example, they cover modification of +the file, and distribution when not linked into a combine +executable.) + +This file is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +!! libgcc routines for the Renesas / SuperH SH CPUs. +!! Contributed by Steve Chamberlain. +!! sac@cygnus.com + +!! ashiftrt_r4_x, ___ashrsi3, ___ashlsi3, ___lshrsi3 routines +!! recoded in assembly by Toshiyasu Morita +!! tm@netcom.com + +/* SH2 optimizations for ___ashrsi3, ___ashlsi3, ___lshrsi3 and + ELF local label prefixes by J"orn Rennecke + amylaar@cygnus.com */ + +! +! __lshrsi3 +! +! Entry: +! +! r4: Value to shift +! r5: Shifts +! +! Exit: +! +! r0: Result +! +! Destroys: +! +! (none) +! + .global __lshrsi3 + + .align 2 +__lshrsi3: + mov #31,r0 + and r0,r5 + mova lshrsi3_table,r0 + mov.b @(r0,r5),r5 +#ifdef __sh1__ + add r5,r0 + jmp @r0 +#else + braf r5 +#endif + mov r4,r0 + + .align 2 +lshrsi3_table: + .byte lshrsi3_0-lshrsi3_table + .byte lshrsi3_1-lshrsi3_table + .byte lshrsi3_2-lshrsi3_table + .byte lshrsi3_3-lshrsi3_table + .byte lshrsi3_4-lshrsi3_table + .byte lshrsi3_5-lshrsi3_table + .byte lshrsi3_6-lshrsi3_table + .byte lshrsi3_7-lshrsi3_table + .byte lshrsi3_8-lshrsi3_table + .byte lshrsi3_9-lshrsi3_table + .byte lshrsi3_10-lshrsi3_table + .byte lshrsi3_11-lshrsi3_table + .byte lshrsi3_12-lshrsi3_table + .byte lshrsi3_13-lshrsi3_table + .byte lshrsi3_14-lshrsi3_table + .byte lshrsi3_15-lshrsi3_table + .byte lshrsi3_16-lshrsi3_table + .byte lshrsi3_17-lshrsi3_table + .byte lshrsi3_18-lshrsi3_table + .byte lshrsi3_19-lshrsi3_table + .byte lshrsi3_20-lshrsi3_table + .byte lshrsi3_21-lshrsi3_table + .byte lshrsi3_22-lshrsi3_table + .byte lshrsi3_23-lshrsi3_table + .byte lshrsi3_24-lshrsi3_table + .byte lshrsi3_25-lshrsi3_table + .byte lshrsi3_26-lshrsi3_table + .byte lshrsi3_27-lshrsi3_table + .byte lshrsi3_28-lshrsi3_table + .byte lshrsi3_29-lshrsi3_table + .byte lshrsi3_30-lshrsi3_table + .byte lshrsi3_31-lshrsi3_table + +lshrsi3_6: + shlr2 r0 +lshrsi3_4: + shlr2 r0 +lshrsi3_2: + rts + shlr2 r0 + +lshrsi3_7: + shlr2 r0 +lshrsi3_5: + shlr2 r0 +lshrsi3_3: + shlr2 r0 +lshrsi3_1: + rts + shlr r0 + +lshrsi3_14: + shlr2 r0 +lshrsi3_12: + shlr2 r0 +lshrsi3_10: + shlr2 r0 +lshrsi3_8: + rts + shlr8 r0 + +lshrsi3_15: + shlr2 r0 +lshrsi3_13: + shlr2 r0 +lshrsi3_11: + shlr2 r0 +lshrsi3_9: + shlr8 r0 + rts + shlr r0 + +lshrsi3_22: + shlr2 r0 +lshrsi3_20: + shlr2 r0 +lshrsi3_18: + shlr2 r0 +lshrsi3_16: + rts + shlr16 r0 + +lshrsi3_23: + shlr2 r0 +lshrsi3_21: + shlr2 r0 +lshrsi3_19: + shlr2 r0 +lshrsi3_17: + shlr16 r0 + rts + shlr r0 + +lshrsi3_30: + shlr2 r0 +lshrsi3_28: + shlr2 r0 +lshrsi3_26: + shlr2 r0 +lshrsi3_24: + shlr16 r0 + rts + shlr8 r0 + +lshrsi3_31: + shlr2 r0 +lshrsi3_29: + shlr2 r0 +lshrsi3_27: + shlr2 r0 +lshrsi3_25: + shlr16 r0 + shlr8 r0 + rts + shlr r0 + +lshrsi3_0: + rts + nop diff --git a/arch/sh/lib/mcount.S b/arch/sh/lib/mcount.S new file mode 100644 index 0000000000000000000000000000000000000000..110fbfe1831f87cb04fe8d21675dc4055d66f61e --- /dev/null +++ b/arch/sh/lib/mcount.S @@ -0,0 +1,90 @@ +/* + * arch/sh/lib/mcount.S + * + * Copyright (C) 2008 Paul Mundt + * Copyright (C) 2008 Matt Fleming + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include + +#define MCOUNT_ENTER() \ + mov.l r4, @-r15; \ + mov.l r5, @-r15; \ + mov.l r6, @-r15; \ + mov.l r7, @-r15; \ + sts.l pr, @-r15; \ + \ + mov.l @(20,r15),r4; \ + sts pr, r5 + +#define MCOUNT_LEAVE() \ + lds.l @r15+, pr; \ + mov.l @r15+, r7; \ + mov.l @r15+, r6; \ + mov.l @r15+, r5; \ + rts; \ + mov.l @r15+, r4 + + .align 2 + .globl _mcount + .type _mcount,@function + .globl mcount + .type mcount,@function +_mcount: +mcount: + MCOUNT_ENTER() + +#ifdef CONFIG_DYNAMIC_FTRACE + .globl mcount_call +mcount_call: + mov.l .Lftrace_stub, r6 +#else + mov.l .Lftrace_trace_function, r6 + mov.l ftrace_stub, r7 + cmp/eq r6, r7 + bt skip_trace + mov.l @r6, r6 +#endif + + jsr @r6 + nop + +skip_trace: + MCOUNT_LEAVE() + + .align 2 +.Lftrace_trace_function: + .long ftrace_trace_function + +#ifdef CONFIG_DYNAMIC_FTRACE + .globl ftrace_caller +ftrace_caller: + MCOUNT_ENTER() + + .globl ftrace_call +ftrace_call: + mov.l .Lftrace_stub, r6 + jsr @r6 + nop + + MCOUNT_LEAVE() +#endif /* CONFIG_DYNAMIC_FTRACE */ + +/* + * NOTE: From here on the locations of the .Lftrace_stub label and + * ftrace_stub itself are fixed. Adding additional data here will skew + * the displacement for the memory table and break the block replacement. + * Place new labels either after the ftrace_stub body, or before + * ftrace_caller. You have been warned. + */ + .align 2 +.Lftrace_stub: + .long ftrace_stub + + .globl ftrace_stub +ftrace_stub: + rts + nop diff --git a/arch/sh/lib/movmem.S b/arch/sh/lib/movmem.S new file mode 100644 index 0000000000000000000000000000000000000000..62075f6bc67ca4ad74ea91bc9a5b43c451fad653 --- /dev/null +++ b/arch/sh/lib/movmem.S @@ -0,0 +1,238 @@ +/* Copyright (C) 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003, + 2004, 2005, 2006 + Free Software Foundation, Inc. + +This file is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file into combinations with other programs, +and to distribute those combinations without any restriction coming +from the use of this file. (The General Public License restrictions +do apply in other respects; for example, they cover modification of +the file, and distribution when not linked into a combine +executable.) + +This file is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +!! libgcc routines for the Renesas / SuperH SH CPUs. +!! Contributed by Steve Chamberlain. +!! sac@cygnus.com + +!! ashiftrt_r4_x, ___ashrsi3, ___ashlsi3, ___lshrsi3 routines +!! recoded in assembly by Toshiyasu Morita +!! tm@netcom.com + +/* SH2 optimizations for ___ashrsi3, ___ashlsi3, ___lshrsi3 and + ELF local label prefixes by J"orn Rennecke + amylaar@cygnus.com */ + + .text + .balign 4 + .global __movmem + .global __movstr + .set __movstr, __movmem + /* This would be a lot simpler if r6 contained the byte count + minus 64, and we wouldn't be called here for a byte count of 64. */ +__movmem: + sts.l pr,@-r15 + shll2 r6 + bsr __movmemSI52+2 + mov.l @(48,r5),r0 + .balign 4 +movmem_loop: /* Reached with rts */ + mov.l @(60,r5),r0 + add #-64,r6 + mov.l r0,@(60,r4) + tst r6,r6 + mov.l @(56,r5),r0 + bt movmem_done + mov.l r0,@(56,r4) + cmp/pl r6 + mov.l @(52,r5),r0 + add #64,r5 + mov.l r0,@(52,r4) + add #64,r4 + bt __movmemSI52 +! done all the large groups, do the remainder +! jump to movmem+ + mova __movmemSI4+4,r0 + add r6,r0 + jmp @r0 +movmem_done: ! share slot insn, works out aligned. + lds.l @r15+,pr + mov.l r0,@(56,r4) + mov.l @(52,r5),r0 + rts + mov.l r0,@(52,r4) + .balign 4 + + .global __movmemSI64 + .global __movstrSI64 + .set __movstrSI64, __movmemSI64 +__movmemSI64: + mov.l @(60,r5),r0 + mov.l r0,@(60,r4) + .global __movmemSI60 + .global __movstrSI60 + .set __movstrSI60, __movmemSI60 +__movmemSI60: + mov.l @(56,r5),r0 + mov.l r0,@(56,r4) + .global __movmemSI56 + .global __movstrSI56 + .set __movstrSI56, __movmemSI56 +__movmemSI56: + mov.l @(52,r5),r0 + mov.l r0,@(52,r4) + .global __movmemSI52 + .global __movstrSI52 + .set __movstrSI52, __movmemSI52 +__movmemSI52: + mov.l @(48,r5),r0 + mov.l r0,@(48,r4) + .global __movmemSI48 + .global __movstrSI48 + .set __movstrSI48, __movmemSI48 +__movmemSI48: + mov.l @(44,r5),r0 + mov.l r0,@(44,r4) + .global __movmemSI44 + .global __movstrSI44 + .set __movstrSI44, __movmemSI44 +__movmemSI44: + mov.l @(40,r5),r0 + mov.l r0,@(40,r4) + .global __movmemSI40 + .global __movstrSI40 + .set __movstrSI40, __movmemSI40 +__movmemSI40: + mov.l @(36,r5),r0 + mov.l r0,@(36,r4) + .global __movmemSI36 + .global __movstrSI36 + .set __movstrSI36, __movmemSI36 +__movmemSI36: + mov.l @(32,r5),r0 + mov.l r0,@(32,r4) + .global __movmemSI32 + .global __movstrSI32 + .set __movstrSI32, __movmemSI32 +__movmemSI32: + mov.l @(28,r5),r0 + mov.l r0,@(28,r4) + .global __movmemSI28 + .global __movstrSI28 + .set __movstrSI28, __movmemSI28 +__movmemSI28: + mov.l @(24,r5),r0 + mov.l r0,@(24,r4) + .global __movmemSI24 + .global __movstrSI24 + .set __movstrSI24, __movmemSI24 +__movmemSI24: + mov.l @(20,r5),r0 + mov.l r0,@(20,r4) + .global __movmemSI20 + .global __movstrSI20 + .set __movstrSI20, __movmemSI20 +__movmemSI20: + mov.l @(16,r5),r0 + mov.l r0,@(16,r4) + .global __movmemSI16 + .global __movstrSI16 + .set __movstrSI16, __movmemSI16 +__movmemSI16: + mov.l @(12,r5),r0 + mov.l r0,@(12,r4) + .global __movmemSI12 + .global __movstrSI12 + .set __movstrSI12, __movmemSI12 +__movmemSI12: + mov.l @(8,r5),r0 + mov.l r0,@(8,r4) + .global __movmemSI8 + .global __movstrSI8 + .set __movstrSI8, __movmemSI8 +__movmemSI8: + mov.l @(4,r5),r0 + mov.l r0,@(4,r4) + .global __movmemSI4 + .global __movstrSI4 + .set __movstrSI4, __movmemSI4 +__movmemSI4: + mov.l @(0,r5),r0 + rts + mov.l r0,@(0,r4) + + .global __movmem_i4_even + .global __movstr_i4_even + .set __movstr_i4_even, __movmem_i4_even + + .global __movmem_i4_odd + .global __movstr_i4_odd + .set __movstr_i4_odd, __movmem_i4_odd + + .global __movmemSI12_i4 + .global __movstrSI12_i4 + .set __movstrSI12_i4, __movmemSI12_i4 + + .p2align 5 +L_movmem_2mod4_end: + mov.l r0,@(16,r4) + rts + mov.l r1,@(20,r4) + + .p2align 2 + +__movmem_i4_even: + mov.l @r5+,r0 + bra L_movmem_start_even + mov.l @r5+,r1 + +__movmem_i4_odd: + mov.l @r5+,r1 + add #-4,r4 + mov.l @r5+,r2 + mov.l @r5+,r3 + mov.l r1,@(4,r4) + mov.l r2,@(8,r4) + +L_movmem_loop: + mov.l r3,@(12,r4) + dt r6 + mov.l @r5+,r0 + bt/s L_movmem_2mod4_end + mov.l @r5+,r1 + add #16,r4 +L_movmem_start_even: + mov.l @r5+,r2 + mov.l @r5+,r3 + mov.l r0,@r4 + dt r6 + mov.l r1,@(4,r4) + bf/s L_movmem_loop + mov.l r2,@(8,r4) + rts + mov.l r3,@(12,r4) + + .p2align 4 +__movmemSI12_i4: + mov.l @r5,r0 + mov.l @(4,r5),r1 + mov.l @(8,r5),r2 + mov.l r0,@r4 + mov.l r1,@(4,r4) + rts + mov.l r2,@(8,r4) diff --git a/arch/sh/lib/udiv_qrnnd.S b/arch/sh/lib/udiv_qrnnd.S new file mode 100644 index 0000000000000000000000000000000000000000..32b9a36de943ff824263b3cc41d52c650a6f1de0 --- /dev/null +++ b/arch/sh/lib/udiv_qrnnd.S @@ -0,0 +1,81 @@ +/* Copyright (C) 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003, + 2004, 2005, 2006 + Free Software Foundation, Inc. + +This file is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file into combinations with other programs, +and to distribute those combinations without any restriction coming +from the use of this file. (The General Public License restrictions +do apply in other respects; for example, they cover modification of +the file, and distribution when not linked into a combine +executable.) + +This file is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +!! libgcc routines for the Renesas / SuperH SH CPUs. +!! Contributed by Steve Chamberlain. +!! sac@cygnus.com + +!! ashiftrt_r4_x, ___ashrsi3, ___ashlsi3, ___lshrsi3 routines +!! recoded in assembly by Toshiyasu Morita +!! tm@netcom.com + +/* SH2 optimizations for ___ashrsi3, ___ashlsi3, ___lshrsi3 and + ELF local label prefixes by J"orn Rennecke + amylaar@cygnus.com */ + + /* r0: rn r1: qn */ /* r0: n1 r4: n0 r5: d r6: d1 */ /* r2: __m */ + /* n1 < d, but n1 might be larger than d1. */ + .global __udiv_qrnnd_16 + .balign 8 +__udiv_qrnnd_16: + div0u + cmp/hi r6,r0 + bt .Lots + .rept 16 + div1 r6,r0 + .endr + extu.w r0,r1 + bt 0f + add r6,r0 +0: rotcl r1 + mulu.w r1,r5 + xtrct r4,r0 + swap.w r0,r0 + sts macl,r2 + cmp/hs r2,r0 + sub r2,r0 + bt 0f + addc r5,r0 + add #-1,r1 + bt 0f +1: add #-1,r1 + rts + add r5,r0 + .balign 8 +.Lots: + sub r5,r0 + swap.w r4,r1 + xtrct r0,r1 + clrt + mov r1,r0 + addc r5,r0 + mov #-1,r1 + bf/s 1b + shlr16 r1 +0: rts + nop diff --git a/arch/sh/lib/udivsi3.S b/arch/sh/lib/udivsi3.S new file mode 100644 index 0000000000000000000000000000000000000000..72157ab5c314619942743574a80aa81f63e1130e --- /dev/null +++ b/arch/sh/lib/udivsi3.S @@ -0,0 +1,87 @@ +/* Copyright (C) 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003, + 2004, 2005 + Free Software Foundation, Inc. + +This file is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file into combinations with other programs, +and to distribute those combinations without any restriction coming +from the use of this file. (The General Public License restrictions +do apply in other respects; for example, they cover modification of +the file, and distribution when not linked into a combine +executable.) + +This file is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +!! libgcc routines for the Renesas / SuperH SH CPUs. +!! Contributed by Steve Chamberlain. +!! sac@cygnus.com + + .balign 4 + .global __udivsi3 + .type __udivsi3, @function +div8: + div1 r5,r4 +div7: + div1 r5,r4; div1 r5,r4; div1 r5,r4 + div1 r5,r4; div1 r5,r4; div1 r5,r4; rts; div1 r5,r4 + +divx4: + div1 r5,r4; rotcl r0 + div1 r5,r4; rotcl r0 + div1 r5,r4; rotcl r0 + rts; div1 r5,r4 + +__udivsi3: + sts.l pr,@-r15 + extu.w r5,r0 + cmp/eq r5,r0 + bf/s large_divisor + div0u + swap.w r4,r0 + shlr16 r4 + bsr div8 + shll16 r5 + bsr div7 + div1 r5,r4 + xtrct r4,r0 + xtrct r0,r4 + bsr div8 + swap.w r4,r4 + bsr div7 + div1 r5,r4 + lds.l @r15+,pr + xtrct r4,r0 + swap.w r0,r0 + rotcl r0 + rts + shlr16 r5 + +large_divisor: + mov #0,r0 + xtrct r4,r0 + xtrct r0,r4 + bsr divx4 + rotcl r0 + bsr divx4 + rotcl r0 + bsr divx4 + rotcl r0 + bsr divx4 + rotcl r0 + lds.l @r15+,pr + rts + rotcl r0 diff --git a/arch/sh/lib/udivsi3_i4i-Os.S b/arch/sh/lib/udivsi3_i4i-Os.S new file mode 100644 index 0000000000000000000000000000000000000000..4835553e1ea90f68198133bfde564b703f7e284b --- /dev/null +++ b/arch/sh/lib/udivsi3_i4i-Os.S @@ -0,0 +1,149 @@ +/* Copyright (C) 2006 Free Software Foundation, Inc. + +This file is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file into combinations with other programs, +and to distribute those combinations without any restriction coming +from the use of this file. (The General Public License restrictions +do apply in other respects; for example, they cover modification of +the file, and distribution when not linked into a combine +executable.) + +This file is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* Moderately Space-optimized libgcc routines for the Renesas SH / + STMicroelectronics ST40 CPUs. + Contributed by J"orn Rennecke joern.rennecke@st.com. */ + +/* Size: 186 bytes jointly for udivsi3_i4i and sdivsi3_i4i + sh4-200 run times: + udiv small divisor: 55 cycles + udiv large divisor: 52 cycles + sdiv small divisor, positive result: 59 cycles + sdiv large divisor, positive result: 56 cycles + sdiv small divisor, negative result: 65 cycles (*) + sdiv large divisor, negative result: 62 cycles (*) + (*): r2 is restored in the rts delay slot and has a lingering latency + of two more cycles. */ + .balign 4 + .global __udivsi3_i4i + .global __udivsi3_i4 + .set __udivsi3_i4, __udivsi3_i4i + .type __udivsi3_i4i, @function + .type __sdivsi3_i4i, @function +__udivsi3_i4i: + sts pr,r1 + mov.l r4,@-r15 + extu.w r5,r0 + cmp/eq r5,r0 + swap.w r4,r0 + shlr16 r4 + bf/s large_divisor + div0u + mov.l r5,@-r15 + shll16 r5 +sdiv_small_divisor: + div1 r5,r4 + bsr div6 + div1 r5,r4 + div1 r5,r4 + bsr div6 + div1 r5,r4 + xtrct r4,r0 + xtrct r0,r4 + bsr div7 + swap.w r4,r4 + div1 r5,r4 + bsr div7 + div1 r5,r4 + xtrct r4,r0 + mov.l @r15+,r5 + swap.w r0,r0 + mov.l @r15+,r4 + jmp @r1 + rotcl r0 +div7: + div1 r5,r4 +div6: + div1 r5,r4; div1 r5,r4; div1 r5,r4 + div1 r5,r4; div1 r5,r4; rts; div1 r5,r4 + +divx3: + rotcl r0 + div1 r5,r4 + rotcl r0 + div1 r5,r4 + rotcl r0 + rts + div1 r5,r4 + +large_divisor: + mov.l r5,@-r15 +sdiv_large_divisor: + xor r4,r0 + .rept 4 + rotcl r0 + bsr divx3 + div1 r5,r4 + .endr + mov.l @r15+,r5 + mov.l @r15+,r4 + jmp @r1 + rotcl r0 + + .global __sdivsi3_i4i + .global __sdivsi3_i4 + .global __sdivsi3 + .set __sdivsi3_i4, __sdivsi3_i4i + .set __sdivsi3, __sdivsi3_i4i +__sdivsi3_i4i: + mov.l r4,@-r15 + cmp/pz r5 + mov.l r5,@-r15 + bt/s pos_divisor + cmp/pz r4 + neg r5,r5 + extu.w r5,r0 + bt/s neg_result + cmp/eq r5,r0 + neg r4,r4 +pos_result: + swap.w r4,r0 + bra sdiv_check_divisor + sts pr,r1 +pos_divisor: + extu.w r5,r0 + bt/s pos_result + cmp/eq r5,r0 + neg r4,r4 +neg_result: + mova negate_result,r0 + ; + mov r0,r1 + swap.w r4,r0 + lds r2,macl + sts pr,r2 +sdiv_check_divisor: + shlr16 r4 + bf/s sdiv_large_divisor + div0u + bra sdiv_small_divisor + shll16 r5 + .balign 4 +negate_result: + neg r0,r0 + jmp @r2 + sts macl,r2 diff --git a/arch/sh/lib/udivsi3_i4i.S b/arch/sh/lib/udivsi3_i4i.S new file mode 100644 index 0000000000000000000000000000000000000000..f1a79d9c5015f382565d4f796694c6c7e6883a7d --- /dev/null +++ b/arch/sh/lib/udivsi3_i4i.S @@ -0,0 +1,666 @@ +/* Copyright (C) 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003, + 2004, 2005, 2006 + Free Software Foundation, Inc. + +This file is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file into combinations with other programs, +and to distribute those combinations without any restriction coming +from the use of this file. (The General Public License restrictions +do apply in other respects; for example, they cover modification of +the file, and distribution when not linked into a combine +executable.) + +This file is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +!! libgcc routines for the Renesas / SuperH SH CPUs. +!! Contributed by Steve Chamberlain. +!! sac@cygnus.com + +!! ashiftrt_r4_x, ___ashrsi3, ___ashlsi3, ___lshrsi3 routines +!! recoded in assembly by Toshiyasu Morita +!! tm@netcom.com + +/* SH2 optimizations for ___ashrsi3, ___ashlsi3, ___lshrsi3 and + ELF local label prefixes by J"orn Rennecke + amylaar@cygnus.com */ + +/* This code used shld, thus is not suitable for SH1 / SH2. */ + +/* Signed / unsigned division without use of FPU, optimized for SH4. + Uses a lookup table for divisors in the range -128 .. +128, and + div1 with case distinction for larger divisors in three more ranges. + The code is lumped together with the table to allow the use of mova. */ +#ifdef CONFIG_CPU_LITTLE_ENDIAN +#define L_LSB 0 +#define L_LSWMSB 1 +#define L_MSWLSB 2 +#else +#define L_LSB 3 +#define L_LSWMSB 2 +#define L_MSWLSB 1 +#endif + + .balign 4 + .global __udivsi3_i4i + .global __udivsi3_i4 + .set __udivsi3_i4, __udivsi3_i4i + .type __udivsi3_i4i, @function +__udivsi3_i4i: + mov.w c128_w, r1 + div0u + mov r4,r0 + shlr8 r0 + cmp/hi r1,r5 + extu.w r5,r1 + bf udiv_le128 + cmp/eq r5,r1 + bf udiv_ge64k + shlr r0 + mov r5,r1 + shll16 r5 + mov.l r4,@-r15 + div1 r5,r0 + mov.l r1,@-r15 + div1 r5,r0 + div1 r5,r0 + bra udiv_25 + div1 r5,r0 + +div_le128: + mova div_table_ix,r0 + bra div_le128_2 + mov.b @(r0,r5),r1 +udiv_le128: + mov.l r4,@-r15 + mova div_table_ix,r0 + mov.b @(r0,r5),r1 + mov.l r5,@-r15 +div_le128_2: + mova div_table_inv,r0 + mov.l @(r0,r1),r1 + mov r5,r0 + tst #0xfe,r0 + mova div_table_clz,r0 + dmulu.l r1,r4 + mov.b @(r0,r5),r1 + bt/s div_by_1 + mov r4,r0 + mov.l @r15+,r5 + sts mach,r0 + /* clrt */ + addc r4,r0 + mov.l @r15+,r4 + rotcr r0 + rts + shld r1,r0 + +div_by_1_neg: + neg r4,r0 +div_by_1: + mov.l @r15+,r5 + rts + mov.l @r15+,r4 + +div_ge64k: + bt/s div_r8 + div0u + shll8 r5 + bra div_ge64k_2 + div1 r5,r0 +udiv_ge64k: + cmp/hi r0,r5 + mov r5,r1 + bt udiv_r8 + shll8 r5 + mov.l r4,@-r15 + div1 r5,r0 + mov.l r1,@-r15 +div_ge64k_2: + div1 r5,r0 + mov.l zero_l,r1 + .rept 4 + div1 r5,r0 + .endr + mov.l r1,@-r15 + div1 r5,r0 + mov.w m256_w,r1 + div1 r5,r0 + mov.b r0,@(L_LSWMSB,r15) + xor r4,r0 + and r1,r0 + bra div_ge64k_end + xor r4,r0 + +div_r8: + shll16 r4 + bra div_r8_2 + shll8 r4 +udiv_r8: + mov.l r4,@-r15 + shll16 r4 + clrt + shll8 r4 + mov.l r5,@-r15 +div_r8_2: + rotcl r4 + mov r0,r1 + div1 r5,r1 + mov r4,r0 + rotcl r0 + mov r5,r4 + div1 r5,r1 + .rept 5 + rotcl r0; div1 r5,r1 + .endr + rotcl r0 + mov.l @r15+,r5 + div1 r4,r1 + mov.l @r15+,r4 + rts + rotcl r0 + + .global __sdivsi3_i4i + .global __sdivsi3_i4 + .global __sdivsi3 + .set __sdivsi3_i4, __sdivsi3_i4i + .set __sdivsi3, __sdivsi3_i4i + .type __sdivsi3_i4i, @function + /* This is link-compatible with a __sdivsi3 call, + but we effectively clobber only r1. */ +__sdivsi3_i4i: + mov.l r4,@-r15 + cmp/pz r5 + mov.w c128_w, r1 + bt/s pos_divisor + cmp/pz r4 + mov.l r5,@-r15 + neg r5,r5 + bt/s neg_result + cmp/hi r1,r5 + neg r4,r4 +pos_result: + extu.w r5,r0 + bf div_le128 + cmp/eq r5,r0 + mov r4,r0 + shlr8 r0 + bf/s div_ge64k + cmp/hi r0,r5 + div0u + shll16 r5 + div1 r5,r0 + div1 r5,r0 + div1 r5,r0 +udiv_25: + mov.l zero_l,r1 + div1 r5,r0 + div1 r5,r0 + mov.l r1,@-r15 + .rept 3 + div1 r5,r0 + .endr + mov.b r0,@(L_MSWLSB,r15) + xtrct r4,r0 + swap.w r0,r0 + .rept 8 + div1 r5,r0 + .endr + mov.b r0,@(L_LSWMSB,r15) +div_ge64k_end: + .rept 8 + div1 r5,r0 + .endr + mov.l @r15+,r4 ! zero-extension and swap using LS unit. + extu.b r0,r0 + mov.l @r15+,r5 + or r4,r0 + mov.l @r15+,r4 + rts + rotcl r0 + +div_le128_neg: + tst #0xfe,r0 + mova div_table_ix,r0 + mov.b @(r0,r5),r1 + mova div_table_inv,r0 + bt/s div_by_1_neg + mov.l @(r0,r1),r1 + mova div_table_clz,r0 + dmulu.l r1,r4 + mov.b @(r0,r5),r1 + mov.l @r15+,r5 + sts mach,r0 + /* clrt */ + addc r4,r0 + mov.l @r15+,r4 + rotcr r0 + shld r1,r0 + rts + neg r0,r0 + +pos_divisor: + mov.l r5,@-r15 + bt/s pos_result + cmp/hi r1,r5 + neg r4,r4 +neg_result: + extu.w r5,r0 + bf div_le128_neg + cmp/eq r5,r0 + mov r4,r0 + shlr8 r0 + bf/s div_ge64k_neg + cmp/hi r0,r5 + div0u + mov.l zero_l,r1 + shll16 r5 + div1 r5,r0 + mov.l r1,@-r15 + .rept 7 + div1 r5,r0 + .endr + mov.b r0,@(L_MSWLSB,r15) + xtrct r4,r0 + swap.w r0,r0 + .rept 8 + div1 r5,r0 + .endr + mov.b r0,@(L_LSWMSB,r15) +div_ge64k_neg_end: + .rept 8 + div1 r5,r0 + .endr + mov.l @r15+,r4 ! zero-extension and swap using LS unit. + extu.b r0,r1 + mov.l @r15+,r5 + or r4,r1 +div_r8_neg_end: + mov.l @r15+,r4 + rotcl r1 + rts + neg r1,r0 + +div_ge64k_neg: + bt/s div_r8_neg + div0u + shll8 r5 + mov.l zero_l,r1 + .rept 6 + div1 r5,r0 + .endr + mov.l r1,@-r15 + div1 r5,r0 + mov.w m256_w,r1 + div1 r5,r0 + mov.b r0,@(L_LSWMSB,r15) + xor r4,r0 + and r1,r0 + bra div_ge64k_neg_end + xor r4,r0 + +c128_w: + .word 128 + +div_r8_neg: + clrt + shll16 r4 + mov r4,r1 + shll8 r1 + mov r5,r4 + .rept 7 + rotcl r1; div1 r5,r0 + .endr + mov.l @r15+,r5 + rotcl r1 + bra div_r8_neg_end + div1 r4,r0 + +m256_w: + .word 0xff00 +/* This table has been generated by divtab-sh4.c. */ + .balign 4 +div_table_clz: + .byte 0 + .byte 1 + .byte 0 + .byte -1 + .byte -1 + .byte -2 + .byte -2 + .byte -2 + .byte -2 + .byte -3 + .byte -3 + .byte -3 + .byte -3 + .byte -3 + .byte -3 + .byte -3 + .byte -3 + .byte -4 + .byte -4 + .byte -4 + .byte -4 + .byte -4 + .byte -4 + .byte -4 + .byte -4 + .byte -4 + .byte -4 + .byte -4 + .byte -4 + .byte -4 + .byte -4 + .byte -4 + .byte -4 + .byte -5 + .byte -5 + .byte -5 + .byte -5 + .byte -5 + .byte -5 + .byte -5 + .byte -5 + .byte -5 + .byte -5 + .byte -5 + .byte -5 + .byte -5 + .byte -5 + .byte -5 + .byte -5 + .byte -5 + .byte -5 + .byte -5 + .byte -5 + .byte -5 + .byte -5 + .byte -5 + .byte -5 + .byte -5 + .byte -5 + .byte -5 + .byte -5 + .byte -5 + .byte -5 + .byte -5 + .byte -5 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 + .byte -6 +/* Lookup table translating positive divisor to index into table of + normalized inverse. N.B. the '0' entry is also the last entry of the + previous table, and causes an unaligned access for division by zero. */ +div_table_ix: + .byte -6 + .byte -128 + .byte -128 + .byte 0 + .byte -128 + .byte -64 + .byte 0 + .byte 64 + .byte -128 + .byte -96 + .byte -64 + .byte -32 + .byte 0 + .byte 32 + .byte 64 + .byte 96 + .byte -128 + .byte -112 + .byte -96 + .byte -80 + .byte -64 + .byte -48 + .byte -32 + .byte -16 + .byte 0 + .byte 16 + .byte 32 + .byte 48 + .byte 64 + .byte 80 + .byte 96 + .byte 112 + .byte -128 + .byte -120 + .byte -112 + .byte -104 + .byte -96 + .byte -88 + .byte -80 + .byte -72 + .byte -64 + .byte -56 + .byte -48 + .byte -40 + .byte -32 + .byte -24 + .byte -16 + .byte -8 + .byte 0 + .byte 8 + .byte 16 + .byte 24 + .byte 32 + .byte 40 + .byte 48 + .byte 56 + .byte 64 + .byte 72 + .byte 80 + .byte 88 + .byte 96 + .byte 104 + .byte 112 + .byte 120 + .byte -128 + .byte -124 + .byte -120 + .byte -116 + .byte -112 + .byte -108 + .byte -104 + .byte -100 + .byte -96 + .byte -92 + .byte -88 + .byte -84 + .byte -80 + .byte -76 + .byte -72 + .byte -68 + .byte -64 + .byte -60 + .byte -56 + .byte -52 + .byte -48 + .byte -44 + .byte -40 + .byte -36 + .byte -32 + .byte -28 + .byte -24 + .byte -20 + .byte -16 + .byte -12 + .byte -8 + .byte -4 + .byte 0 + .byte 4 + .byte 8 + .byte 12 + .byte 16 + .byte 20 + .byte 24 + .byte 28 + .byte 32 + .byte 36 + .byte 40 + .byte 44 + .byte 48 + .byte 52 + .byte 56 + .byte 60 + .byte 64 + .byte 68 + .byte 72 + .byte 76 + .byte 80 + .byte 84 + .byte 88 + .byte 92 + .byte 96 + .byte 100 + .byte 104 + .byte 108 + .byte 112 + .byte 116 + .byte 120 + .byte 124 + .byte -128 +/* 1/64 .. 1/127, normalized. There is an implicit leading 1 in bit 32. */ + .balign 4 +zero_l: + .long 0x0 + .long 0xF81F81F9 + .long 0xF07C1F08 + .long 0xE9131AC0 + .long 0xE1E1E1E2 + .long 0xDAE6076C + .long 0xD41D41D5 + .long 0xCD856891 + .long 0xC71C71C8 + .long 0xC0E07039 + .long 0xBACF914D + .long 0xB4E81B4F + .long 0xAF286BCB + .long 0xA98EF607 + .long 0xA41A41A5 + .long 0x9EC8E952 + .long 0x9999999A + .long 0x948B0FCE + .long 0x8F9C18FA + .long 0x8ACB90F7 + .long 0x86186187 + .long 0x81818182 + .long 0x7D05F418 + .long 0x78A4C818 + .long 0x745D1746 + .long 0x702E05C1 + .long 0x6C16C16D + .long 0x68168169 + .long 0x642C8591 + .long 0x60581606 + .long 0x5C9882BA + .long 0x58ED2309 +div_table_inv: + .long 0x55555556 + .long 0x51D07EAF + .long 0x4E5E0A73 + .long 0x4AFD6A06 + .long 0x47AE147B + .long 0x446F8657 + .long 0x41414142 + .long 0x3E22CBCF + .long 0x3B13B13C + .long 0x38138139 + .long 0x3521CFB3 + .long 0x323E34A3 + .long 0x2F684BDB + .long 0x2C9FB4D9 + .long 0x29E4129F + .long 0x27350B89 + .long 0x24924925 + .long 0x21FB7813 + .long 0x1F7047DD + .long 0x1CF06ADB + .long 0x1A7B9612 + .long 0x18118119 + .long 0x15B1E5F8 + .long 0x135C8114 + .long 0x11111112 + .long 0xECF56BF + .long 0xC9714FC + .long 0xA6810A7 + .long 0x8421085 + .long 0x624DD30 + .long 0x4104105 + .long 0x2040811 + /* maximum error: 0.987342 scaled: 0.921875*/ diff --git a/arch/sh/lib64/Makefile b/arch/sh/lib64/Makefile index 9950966923a01aa2ec01a782d85fad6bfcf04929..4bacb9e834789873629021f34660c980f5c338b5 100644 --- a/arch/sh/lib64/Makefile +++ b/arch/sh/lib64/Makefile @@ -2,7 +2,7 @@ # Makefile for the SH-5 specific library files.. # # Copyright (C) 2000, 2001 Paolo Alberelli -# Copyright (C) 2003 Paul Mundt +# Copyright (C) 2003 - 2008 Paul Mundt # # This file is subject to the terms and conditions of the GNU General Public # License. See the file "COPYING" in the main directory of this archive @@ -10,6 +10,8 @@ # # Panic should really be compiled as PIC -lib-y := udelay.o c-checksum.o dbg.o panic.o memcpy.o copy_user_memcpy.o \ - copy_page.o clear_page.o +lib-y := udelay.o c-checksum.o dbg.o panic.o memcpy.o memset.o \ + copy_user_memcpy.o copy_page.o clear_page.o strcpy.o strlen.o +# Extracted from libgcc +lib-y += udivsi3.o udivdi3.o sdivsi3.o diff --git a/arch/sh/lib64/c-checksum.c b/arch/sh/lib64/c-checksum.c index 5c284e0cff9c66c0fd298de301e173da94d99c97..73c0877e3a29aa57f48431f050438c25a49b2ec8 100644 --- a/arch/sh/lib64/c-checksum.c +++ b/arch/sh/lib64/c-checksum.c @@ -35,7 +35,7 @@ static inline unsigned short foldto16(unsigned long x) static inline unsigned short myfoldto16(unsigned long long x) { - /* Fold down to 32-bits so we don't loose in the typedef-less + /* Fold down to 32-bits so we don't lose in the typedef-less network stack. */ /* 64 to 33 */ x = (x & 0xffffffff) + (x >> 32); @@ -199,7 +199,7 @@ __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr, result = (__force u64) saddr + (__force u64) daddr + (__force u64) sum + ((len + proto) << 8); - /* Fold down to 32-bits so we don't loose in the typedef-less + /* Fold down to 32-bits so we don't lose in the typedef-less network stack. */ /* 64 to 33 */ result = (result & 0xffffffff) + (result >> 32); diff --git a/arch/sh/lib64/memcpy.S b/arch/sh/lib64/memcpy.S new file mode 100644 index 0000000000000000000000000000000000000000..dd300c372ce1966148910c86bd472d87b3066d16 --- /dev/null +++ b/arch/sh/lib64/memcpy.S @@ -0,0 +1,201 @@ +/* Cloned and hacked for uClibc by Paul Mundt, December 2003 */ +/* Modified by SuperH, Inc. September 2003 */ +! +! Fast SH memcpy +! +! by Toshiyasu Morita (tm@netcom.com) +! hacked by J"orn Rernnecke (joern.rennecke@superh.com) ("o for o-umlaut) +! SH5 code Copyright 2002 SuperH Ltd. +! +! Entry: ARG0: destination pointer +! ARG1: source pointer +! ARG2: byte count +! +! Exit: RESULT: destination pointer +! any other registers in the range r0-r7: trashed +! +! Notes: Usually one wants to do small reads and write a longword, but +! unfortunately it is difficult in some cases to concatanate bytes +! into a longword on the SH, so this does a longword read and small +! writes. +! +! This implementation makes two assumptions about how it is called: +! +! 1.: If the byte count is nonzero, the address of the last byte to be +! copied is unsigned greater than the address of the first byte to +! be copied. This could be easily swapped for a signed comparison, +! but the algorithm used needs some comparison. +! +! 2.: When there are two or three bytes in the last word of an 11-or-more +! bytes memory chunk to b copied, the rest of the word can be read +! without side effects. +! This could be easily changed by increasing the minumum size of +! a fast memcpy and the amount subtracted from r7 before L_2l_loop be 2, +! however, this would cost a few extra cyles on average. +! For SHmedia, the assumption is that any quadword can be read in its +! enirety if at least one byte is included in the copy. +! + + .section .text..SHmedia32,"ax" + .globl memcpy + .type memcpy, @function + .align 5 + +memcpy: + +#define LDUAQ(P,O,D0,D1) ldlo.q P,O,D0; ldhi.q P,O+7,D1 +#define STUAQ(P,O,D0,D1) stlo.q P,O,D0; sthi.q P,O+7,D1 +#define LDUAL(P,O,D0,D1) ldlo.l P,O,D0; ldhi.l P,O+3,D1 +#define STUAL(P,O,D0,D1) stlo.l P,O,D0; sthi.l P,O+3,D1 + + ld.b r3,0,r63 + pta/l Large,tr0 + movi 25,r0 + bgeu/u r4,r0,tr0 + nsb r4,r0 + shlli r0,5,r0 + movi (L1-L0+63*32 + 1) & 0xffff,r1 + sub r1, r0, r0 +L0: ptrel r0,tr0 + add r2,r4,r5 + ptabs r18,tr1 + add r3,r4,r6 + blink tr0,r63 + +/* Rearranged to make cut2 safe */ + .balign 8 +L4_7: /* 4..7 byte memcpy cntd. */ + stlo.l r2, 0, r0 + or r6, r7, r6 + sthi.l r5, -1, r6 + stlo.l r5, -4, r6 + blink tr1,r63 + + .balign 8 +L1: /* 0 byte memcpy */ + nop + blink tr1,r63 + nop + nop + nop + nop + +L2_3: /* 2 or 3 byte memcpy cntd. */ + st.b r5,-1,r6 + blink tr1,r63 + + /* 1 byte memcpy */ + ld.b r3,0,r0 + st.b r2,0,r0 + blink tr1,r63 + +L8_15: /* 8..15 byte memcpy cntd. */ + stlo.q r2, 0, r0 + or r6, r7, r6 + sthi.q r5, -1, r6 + stlo.q r5, -8, r6 + blink tr1,r63 + + /* 2 or 3 byte memcpy */ + ld.b r3,0,r0 + ld.b r2,0,r63 + ld.b r3,1,r1 + st.b r2,0,r0 + pta/l L2_3,tr0 + ld.b r6,-1,r6 + st.b r2,1,r1 + blink tr0, r63 + + /* 4 .. 7 byte memcpy */ + LDUAL (r3, 0, r0, r1) + pta L4_7, tr0 + ldlo.l r6, -4, r7 + or r0, r1, r0 + sthi.l r2, 3, r0 + ldhi.l r6, -1, r6 + blink tr0, r63 + + /* 8 .. 15 byte memcpy */ + LDUAQ (r3, 0, r0, r1) + pta L8_15, tr0 + ldlo.q r6, -8, r7 + or r0, r1, r0 + sthi.q r2, 7, r0 + ldhi.q r6, -1, r6 + blink tr0, r63 + + /* 16 .. 24 byte memcpy */ + LDUAQ (r3, 0, r0, r1) + LDUAQ (r3, 8, r8, r9) + or r0, r1, r0 + sthi.q r2, 7, r0 + or r8, r9, r8 + sthi.q r2, 15, r8 + ldlo.q r6, -8, r7 + ldhi.q r6, -1, r6 + stlo.q r2, 8, r8 + stlo.q r2, 0, r0 + or r6, r7, r6 + sthi.q r5, -1, r6 + stlo.q r5, -8, r6 + blink tr1,r63 + +Large: + ld.b r2, 0, r63 + pta/l Loop_ua, tr1 + ori r3, -8, r7 + sub r2, r7, r22 + sub r3, r2, r6 + add r2, r4, r5 + ldlo.q r3, 0, r0 + addi r5, -16, r5 + movi 64+8, r27 // could subtract r7 from that. + stlo.q r2, 0, r0 + sthi.q r2, 7, r0 + ldx.q r22, r6, r0 + bgtu/l r27, r4, tr1 + + addi r5, -48, r27 + pta/l Loop_line, tr0 + addi r6, 64, r36 + addi r6, -24, r19 + addi r6, -16, r20 + addi r6, -8, r21 + +Loop_line: + ldx.q r22, r36, r63 + alloco r22, 32 + addi r22, 32, r22 + ldx.q r22, r19, r23 + sthi.q r22, -25, r0 + ldx.q r22, r20, r24 + ldx.q r22, r21, r25 + stlo.q r22, -32, r0 + ldx.q r22, r6, r0 + sthi.q r22, -17, r23 + sthi.q r22, -9, r24 + sthi.q r22, -1, r25 + stlo.q r22, -24, r23 + stlo.q r22, -16, r24 + stlo.q r22, -8, r25 + bgeu r27, r22, tr0 + +Loop_ua: + addi r22, 8, r22 + sthi.q r22, -1, r0 + stlo.q r22, -8, r0 + ldx.q r22, r6, r0 + bgtu/l r5, r22, tr1 + + add r3, r4, r7 + ldlo.q r7, -8, r1 + sthi.q r22, 7, r0 + ldhi.q r7, -1, r7 + ptabs r18,tr1 + stlo.q r22, 0, r0 + or r1, r7, r1 + sthi.q r5, 15, r1 + stlo.q r5, 8, r1 + blink tr1, r63 + + .size memcpy,.-memcpy diff --git a/arch/sh/lib64/memcpy.c b/arch/sh/lib64/memcpy.c deleted file mode 100644 index fba436a92bfa2e7c5e047cd32164f03142743e8a..0000000000000000000000000000000000000000 --- a/arch/sh/lib64/memcpy.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2002 Mark Debbage (Mark.Debbage@superh.com) - * - * May be copied or modified under the terms of the GNU General Public - * License. See linux/COPYING for more information. - * - */ - -#include -#include - -// This is a simplistic optimization of memcpy to increase the -// granularity of access beyond one byte using aligned -// loads and stores. This is not an optimal implementation -// for SH-5 (especially with regard to prefetching and the cache), -// and a better version should be provided later ... - -void *memcpy(void *dest, const void *src, size_t count) -{ - char *d = (char *) dest, *s = (char *) src; - - if (count >= 32) { - int i = 8 - (((unsigned long) d) & 0x7); - - if (i != 8) - while (i-- && count--) { - *d++ = *s++; - } - - if (((((unsigned long) d) & 0x7) == 0) && - ((((unsigned long) s) & 0x7) == 0)) { - while (count >= 32) { - unsigned long long t1, t2, t3, t4; - t1 = *(unsigned long long *) (s); - t2 = *(unsigned long long *) (s + 8); - t3 = *(unsigned long long *) (s + 16); - t4 = *(unsigned long long *) (s + 24); - *(unsigned long long *) (d) = t1; - *(unsigned long long *) (d + 8) = t2; - *(unsigned long long *) (d + 16) = t3; - *(unsigned long long *) (d + 24) = t4; - d += 32; - s += 32; - count -= 32; - } - while (count >= 8) { - *(unsigned long long *) d = - *(unsigned long long *) s; - d += 8; - s += 8; - count -= 8; - } - } - - if (((((unsigned long) d) & 0x3) == 0) && - ((((unsigned long) s) & 0x3) == 0)) { - while (count >= 4) { - *(unsigned long *) d = *(unsigned long *) s; - d += 4; - s += 4; - count -= 4; - } - } - - if (((((unsigned long) d) & 0x1) == 0) && - ((((unsigned long) s) & 0x1) == 0)) { - while (count >= 2) { - *(unsigned short *) d = *(unsigned short *) s; - d += 2; - s += 2; - count -= 2; - } - } - } - - while (count--) { - *d++ = *s++; - } - - return d; -} diff --git a/arch/sh/lib64/memset.S b/arch/sh/lib64/memset.S new file mode 100644 index 0000000000000000000000000000000000000000..2d37b0488552596e5c12cce1a8568fe7893cb51d --- /dev/null +++ b/arch/sh/lib64/memset.S @@ -0,0 +1,91 @@ +/* Cloned and hacked for uClibc by Paul Mundt, December 2003 */ +/* Modified by SuperH, Inc. September 2003 */ +! +! Fast SH memset +! +! by Toshiyasu Morita (tm@netcom.com) +! +! SH5 code by J"orn Rennecke (joern.rennecke@superh.com) +! Copyright 2002 SuperH Ltd. +! + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define SHHI shlld +#define SHLO shlrd +#else +#define SHHI shlrd +#define SHLO shlld +#endif + + .section .text..SHmedia32,"ax" + .globl memset + .type memset, @function + + .align 5 + +memset: + pta/l multiquad, tr0 + andi r2, 7, r22 + ptabs r18, tr2 + mshflo.b r3,r3,r3 + add r4, r22, r23 + mperm.w r3, r63, r3 // Fill pattern now in every byte of r3 + + movi 8, r9 + bgtu/u r23, r9, tr0 // multiquad + + beqi/u r4, 0, tr2 // Return with size 0 - ensures no mem accesses + ldlo.q r2, 0, r7 + shlli r4, 2, r4 + movi -1, r8 + SHHI r8, r4, r8 + SHHI r8, r4, r8 + mcmv r7, r8, r3 + stlo.q r2, 0, r3 + blink tr2, r63 + +multiquad: + pta/l lastquad, tr0 + stlo.q r2, 0, r3 + shlri r23, 3, r24 + add r2, r4, r5 + beqi/u r24, 1, tr0 // lastquad + pta/l loop, tr1 + sub r2, r22, r25 + andi r5, -8, r20 // calculate end address and + addi r20, -7*8, r8 // loop end address; This might overflow, so we need + // to use a different test before we start the loop + bge/u r24, r9, tr1 // loop + st.q r25, 8, r3 + st.q r20, -8, r3 + shlri r24, 1, r24 + beqi/u r24, 1, tr0 // lastquad + st.q r25, 16, r3 + st.q r20, -16, r3 + beqi/u r24, 2, tr0 // lastquad + st.q r25, 24, r3 + st.q r20, -24, r3 +lastquad: + sthi.q r5, -1, r3 + blink tr2,r63 + +loop: +!!! alloco r25, 32 // QQQ comment out for short-term fix to SHUK #3895. + // QQQ commenting out is locically correct, but sub-optimal + // QQQ Sean McGoogan - 4th April 2003. + st.q r25, 8, r3 + st.q r25, 16, r3 + st.q r25, 24, r3 + st.q r25, 32, r3 + addi r25, 32, r25 + bgeu/l r8, r25, tr1 // loop + + st.q r20, -40, r3 + st.q r20, -32, r3 + st.q r20, -24, r3 + st.q r20, -16, r3 + st.q r20, -8, r3 + sthi.q r5, -1, r3 + blink tr2,r63 + + .size memset,.-memset diff --git a/arch/sh/lib64/sdivsi3.S b/arch/sh/lib64/sdivsi3.S new file mode 100644 index 0000000000000000000000000000000000000000..6a800c6a4904337a40e2bdff2618a402ae22261c --- /dev/null +++ b/arch/sh/lib64/sdivsi3.S @@ -0,0 +1,131 @@ + .global __sdivsi3 + .section .text..SHmedia32,"ax" + .align 2 + + /* inputs: r4,r5 */ + /* clobbered: r1,r18,r19,r20,r21,r25,tr0 */ + /* result in r0 */ +__sdivsi3: + ptb __div_table,tr0 + + nsb r5, r1 + shlld r5, r1, r25 /* normalize; [-2 ..1, 1..2) in s2.62 */ + shari r25, 58, r21 /* extract 5(6) bit index (s2.4 with hole -1..1) */ + /* bubble */ + gettr tr0,r20 + ldx.ub r20, r21, r19 /* u0.8 */ + shari r25, 32, r25 /* normalize to s2.30 */ + shlli r21, 1, r21 + muls.l r25, r19, r19 /* s2.38 */ + ldx.w r20, r21, r21 /* s2.14 */ + ptabs r18, tr0 + shari r19, 24, r19 /* truncate to s2.14 */ + sub r21, r19, r19 /* some 11 bit inverse in s1.14 */ + muls.l r19, r19, r21 /* u0.28 */ + sub r63, r1, r1 + addi r1, 92, r1 + muls.l r25, r21, r18 /* s2.58 */ + shlli r19, 45, r19 /* multiply by two and convert to s2.58 */ + /* bubble */ + sub r19, r18, r18 + shari r18, 28, r18 /* some 22 bit inverse in s1.30 */ + muls.l r18, r25, r0 /* s2.60 */ + muls.l r18, r4, r25 /* s32.30 */ + /* bubble */ + shari r0, 16, r19 /* s-16.44 */ + muls.l r19, r18, r19 /* s-16.74 */ + shari r25, 63, r0 + shari r4, 14, r18 /* s19.-14 */ + shari r19, 30, r19 /* s-16.44 */ + muls.l r19, r18, r19 /* s15.30 */ + xor r21, r0, r21 /* You could also use the constant 1 << 27. */ + add r21, r25, r21 + sub r21, r19, r21 + shard r21, r1, r21 + sub r21, r0, r0 + blink tr0, r63 + +/* This table has been generated by divtab.c . +Defects for bias -330: + Max defect: 6.081536e-07 at -1.000000e+00 + Min defect: 2.849516e-08 at 1.030651e+00 + Max 2nd step defect: 9.606539e-12 at -1.000000e+00 + Min 2nd step defect: 0.000000e+00 at 0.000000e+00 + Defect at 1: 1.238659e-07 + Defect at -2: 1.061708e-07 */ + + .balign 2 + .type __div_table,@object + .size __div_table,128 +/* negative division constants */ + .word -16638 + .word -17135 + .word -17737 + .word -18433 + .word -19103 + .word -19751 + .word -20583 + .word -21383 + .word -22343 + .word -23353 + .word -24407 + .word -25582 + .word -26863 + .word -28382 + .word -29965 + .word -31800 +/* negative division factors */ + .byte 66 + .byte 70 + .byte 75 + .byte 81 + .byte 87 + .byte 93 + .byte 101 + .byte 109 + .byte 119 + .byte 130 + .byte 142 + .byte 156 + .byte 172 + .byte 192 + .byte 214 + .byte 241 + .skip 16 + .global __div_table +__div_table: + .skip 16 +/* positive division factors */ + .byte 241 + .byte 214 + .byte 192 + .byte 172 + .byte 156 + .byte 142 + .byte 130 + .byte 119 + .byte 109 + .byte 101 + .byte 93 + .byte 87 + .byte 81 + .byte 75 + .byte 70 + .byte 66 +/* positive division constants */ + .word 31801 + .word 29966 + .word 28383 + .word 26864 + .word 25583 + .word 24408 + .word 23354 + .word 22344 + .word 21384 + .word 20584 + .word 19752 + .word 19104 + .word 18434 + .word 17738 + .word 17136 + .word 16639 diff --git a/arch/sh/lib64/strcpy.S b/arch/sh/lib64/strcpy.S new file mode 100644 index 0000000000000000000000000000000000000000..ea7c9c533eeab4d94aebfc8795449e8af1e99900 --- /dev/null +++ b/arch/sh/lib64/strcpy.S @@ -0,0 +1,97 @@ +/* Cloned and hacked for uClibc by Paul Mundt, December 2003 */ +/* Modified by SuperH, Inc. September 2003 */ +! Entry: arg0: destination +! arg1: source +! Exit: result: destination +! +! SH5 code Copyright 2002 SuperH Ltd. + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define SHHI shlld +#define SHLO shlrd +#else +#define SHHI shlrd +#define SHLO shlld +#endif + + .section .text..SHmedia32,"ax" + .globl strcpy + .type strcpy, @function + .align 5 + +strcpy: + + pta/l shortstring,tr1 + ldlo.q r3,0,r4 + ptabs r18,tr4 + shlli r3,3,r7 + addi r2, 8, r0 + mcmpeq.b r4,r63,r6 + SHHI r6,r7,r6 + bnei/u r6,0,tr1 // shortstring + pta/l no_lddst, tr2 + ori r3,-8,r23 + sub r2, r23, r0 + sub r3, r2, r21 + addi r21, 8, r20 + ldx.q r0, r21, r5 + pta/l loop, tr0 + ori r2,-8,r22 + mcmpeq.b r5, r63, r6 + bgt/u r22, r23, tr2 // no_lddst + + // r22 < r23 : Need to do a load from the destination. + // r22 == r23 : Doesn't actually need to load from destination, + // but still can be handled here. + ldlo.q r2, 0, r9 + movi -1, r8 + SHLO r8, r7, r8 + mcmv r4, r8, r9 + stlo.q r2, 0, r9 + beqi/l r6, 0, tr0 // loop + + add r5, r63, r4 + addi r0, 8, r0 + blink tr1, r63 // shortstring +no_lddst: + // r22 > r23: note that for r22 == r23 the sthi.q would clobber + // bytes before the destination region. + stlo.q r2, 0, r4 + SHHI r4, r7, r4 + sthi.q r0, -1, r4 + beqi/l r6, 0, tr0 // loop + + add r5, r63, r4 + addi r0, 8, r0 +shortstring: +#if __BYTE_ORDER != __LITTLE_ENDIAN + pta/l shortstring2,tr1 + byterev r4,r4 +#endif +shortstring2: + st.b r0,-8,r4 + andi r4,0xff,r5 + shlri r4,8,r4 + addi r0,1,r0 + bnei/l r5,0,tr1 + blink tr4,r63 // return + + .balign 8 +loop: + stlo.q r0, 0, r5 + ldx.q r0, r20, r4 + addi r0, 16, r0 + sthi.q r0, -9, r5 + mcmpeq.b r4, r63, r6 + bnei/u r6, 0, tr1 // shortstring + ldx.q r0, r21, r5 + stlo.q r0, -8, r4 + sthi.q r0, -1, r4 + mcmpeq.b r5, r63, r6 + beqi/l r6, 0, tr0 // loop + + add r5, r63, r4 + addi r0, 8, r0 + blink tr1, r63 // shortstring + + .size strcpy,.-strcpy diff --git a/arch/sh/lib64/strlen.S b/arch/sh/lib64/strlen.S new file mode 100644 index 0000000000000000000000000000000000000000..cbc0d912e5f35c733a7d565802e2b446c987be24 --- /dev/null +++ b/arch/sh/lib64/strlen.S @@ -0,0 +1,33 @@ +/* + * Simplistic strlen() implementation for SHmedia. + * + * Copyright (C) 2003 Paul Mundt + */ + + .section .text..SHmedia32,"ax" + .globl strlen + .type strlen,@function + + .balign 16 +strlen: + ptabs r18, tr4 + + /* + * Note: We could easily deal with the NULL case here with a simple + * sanity check, though it seems that the behavior we want is to fault + * in the event that r2 == NULL, so we don't bother. + */ +/* beqi r2, 0, tr4 */ ! Sanity check + + movi -1, r0 + pta/l loop, tr0 +loop: + ld.b r2, 0, r1 + addi r2, 1, r2 + addi r0, 1, r0 + bnei/l r1, 0, tr0 + + or r0, r63, r2 + blink tr4, r63 + + .size strlen,.-strlen diff --git a/arch/sh/lib64/udivdi3.S b/arch/sh/lib64/udivdi3.S new file mode 100644 index 0000000000000000000000000000000000000000..6895c0225b851d6a74f5c3aef55b89972f068a23 --- /dev/null +++ b/arch/sh/lib64/udivdi3.S @@ -0,0 +1,120 @@ + .section .text..SHmedia32,"ax" + .align 2 + .global __udivdi3 +__udivdi3: + shlri r3,1,r4 + nsb r4,r22 + shlld r3,r22,r6 + shlri r6,49,r5 + movi 0xffffffffffffbaf1,r21 /* .l shift count 17. */ + sub r21,r5,r1 + mmulfx.w r1,r1,r4 + mshflo.w r1,r63,r1 + sub r63,r22,r20 // r63 == 64 % 64 + mmulfx.w r5,r4,r4 + pta large_divisor,tr0 + addi r20,32,r9 + msub.w r1,r4,r1 + madd.w r1,r1,r1 + mmulfx.w r1,r1,r4 + shlri r6,32,r7 + bgt/u r9,r63,tr0 // large_divisor + mmulfx.w r5,r4,r4 + shlri r2,32+14,r19 + addi r22,-31,r0 + msub.w r1,r4,r1 + + mulu.l r1,r7,r4 + addi r1,-3,r5 + mulu.l r5,r19,r5 + sub r63,r4,r4 // Negate to make sure r1 ends up <= 1/r2 + shlri r4,2,r4 /* chop off leading %0000000000000000 001.00000000000 - or, as + the case may be, %0000000000000000 000.11111111111, still */ + muls.l r1,r4,r4 /* leaving at least one sign bit. */ + mulu.l r5,r3,r8 + mshalds.l r1,r21,r1 + shari r4,26,r4 + shlld r8,r0,r8 + add r1,r4,r1 // 31 bit unsigned reciprocal now in r1 (msb equiv. 0.5) + sub r2,r8,r2 + /* Can do second step of 64 : 32 div now, using r1 and the rest in r2. */ + + shlri r2,22,r21 + mulu.l r21,r1,r21 + shlld r5,r0,r8 + addi r20,30-22,r0 + shlrd r21,r0,r21 + mulu.l r21,r3,r5 + add r8,r21,r8 + mcmpgt.l r21,r63,r21 // See Note 1 + addi r20,30,r0 + mshfhi.l r63,r21,r21 + sub r2,r5,r2 + andc r2,r21,r2 + + /* small divisor: need a third divide step */ + mulu.l r2,r1,r7 + ptabs r18,tr0 + addi r2,1,r2 + shlrd r7,r0,r7 + mulu.l r7,r3,r5 + add r8,r7,r8 + sub r2,r3,r2 + cmpgt r2,r5,r5 + add r8,r5,r2 + /* could test r3 here to check for divide by zero. */ + blink tr0,r63 + +large_divisor: + mmulfx.w r5,r4,r4 + shlrd r2,r9,r25 + shlri r25,32,r8 + msub.w r1,r4,r1 + + mulu.l r1,r7,r4 + addi r1,-3,r5 + mulu.l r5,r8,r5 + sub r63,r4,r4 // Negate to make sure r1 ends up <= 1/r2 + shlri r4,2,r4 /* chop off leading %0000000000000000 001.00000000000 - or, as + the case may be, %0000000000000000 000.11111111111, still */ + muls.l r1,r4,r4 /* leaving at least one sign bit. */ + shlri r5,14-1,r8 + mulu.l r8,r7,r5 + mshalds.l r1,r21,r1 + shari r4,26,r4 + add r1,r4,r1 // 31 bit unsigned reciprocal now in r1 (msb equiv. 0.5) + sub r25,r5,r25 + /* Can do second step of 64 : 32 div now, using r1 and the rest in r25. */ + + shlri r25,22,r21 + mulu.l r21,r1,r21 + pta no_lo_adj,tr0 + addi r22,32,r0 + shlri r21,40,r21 + mulu.l r21,r7,r5 + add r8,r21,r8 + shlld r2,r0,r2 + sub r25,r5,r25 + bgtu/u r7,r25,tr0 // no_lo_adj + addi r8,1,r8 + sub r25,r7,r25 +no_lo_adj: + mextr4 r2,r25,r2 + + /* large_divisor: only needs a few adjustments. */ + mulu.l r8,r6,r5 + ptabs r18,tr0 + /* bubble */ + cmpgtu r5,r2,r5 + sub r8,r5,r2 + blink tr0,r63 + +/* Note 1: To shift the result of the second divide stage so that the result + always fits into 32 bits, yet we still reduce the rest sufficiently + would require a lot of instructions to do the shifts just right. Using + the full 64 bit shift result to multiply with the divisor would require + four extra instructions for the upper 32 bits (shift / mulu / shift / sub). + Fortunately, if the upper 32 bits of the shift result are nonzero, we + know that the rest after taking this partial result into account will + fit into 32 bits. So we just clear the upper 32 bits of the rest if the + upper 32 bits of the partial result are nonzero. */ diff --git a/arch/sh/lib64/udivsi3.S b/arch/sh/lib64/udivsi3.S new file mode 100644 index 0000000000000000000000000000000000000000..e68120e4b84752a737fbdc535f48f77fb8e365fa --- /dev/null +++ b/arch/sh/lib64/udivsi3.S @@ -0,0 +1,59 @@ + .global __udivsi3 + .section .text..SHmedia32,"ax" + .align 2 + +/* + inputs: r4,r5 + clobbered: r18,r19,r20,r21,r22,r25,tr0 + result in r0. + */ +__udivsi3: + addz.l r5,r63,r22 + nsb r22,r0 + shlld r22,r0,r25 + shlri r25,48,r25 + movi 0xffffffffffffbb0c,r20 /* shift count eqiv 76 */ + sub r20,r25,r21 + mmulfx.w r21,r21,r19 + mshflo.w r21,r63,r21 + ptabs r18,tr0 + mmulfx.w r25,r19,r19 + sub r20,r0,r0 + /* bubble */ + msub.w r21,r19,r19 + + /* + * It would be nice for scheduling to do this add to r21 before + * the msub.w, but we need a different value for r19 to keep + * errors under control. + */ + addi r19,-2,r21 + mulu.l r4,r21,r18 + mmulfx.w r19,r19,r19 + shlli r21,15,r21 + shlrd r18,r0,r18 + mulu.l r18,r22,r20 + mmacnfx.wl r25,r19,r21 + /* bubble */ + sub r4,r20,r25 + + mulu.l r25,r21,r19 + addi r0,14,r0 + /* bubble */ + shlrd r19,r0,r19 + mulu.l r19,r22,r20 + add r18,r19,r18 + /* bubble */ + sub.l r25,r20,r25 + + mulu.l r25,r21,r19 + addz.l r25,r63,r25 + sub r25,r22,r25 + shlrd r19,r0,r19 + mulu.l r19,r22,r20 + addi r25,1,r25 + add r18,r19,r18 + + cmpgt r25,r20,r25 + add.l r18,r25,r0 + blink tr0,r63 diff --git a/arch/sh/mm/Makefile_32 b/arch/sh/mm/Makefile_32 index f066e76da2044fb9430c80ec2481546ad963c275..cb2f3f2995914003c5f1966362be9b325df9a90f 100644 --- a/arch/sh/mm/Makefile_32 +++ b/arch/sh/mm/Makefile_32 @@ -18,6 +18,7 @@ mmu-y := tlb-nommu.o pg-nommu.o mmu-$(CONFIG_MMU) := fault_32.o tlbflush_32.o ioremap_32.o obj-y += $(mmu-y) +obj-$(CONFIG_DEBUG_FS) += asids-debugfs.o ifdef CONFIG_DEBUG_FS obj-$(CONFIG_CPU_SH4) += cache-debugfs.o diff --git a/arch/sh/mm/Makefile_64 b/arch/sh/mm/Makefile_64 index 9481d0f54efdd8a5fd6e76b86c72f12be906604f..2863ffb7006d12408e5e070621eb8f7b3af0ec4f 100644 --- a/arch/sh/mm/Makefile_64 +++ b/arch/sh/mm/Makefile_64 @@ -13,6 +13,7 @@ obj-y += cache-sh5.o endif obj-y += $(mmu-y) +obj-$(CONFIG_DEBUG_FS) += asids-debugfs.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o obj-$(CONFIG_NUMA) += numa.o diff --git a/arch/sh/mm/asids-debugfs.c b/arch/sh/mm/asids-debugfs.c new file mode 100644 index 0000000000000000000000000000000000000000..8e912a15e94f4583e1f4a8fe488b1dc45128e766 --- /dev/null +++ b/arch/sh/mm/asids-debugfs.c @@ -0,0 +1,79 @@ +/* + * debugfs ops for process ASIDs + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003 - 2008 Paul Mundt + * Copyright (C) 2003, 2004 Richard Curnow + * + * Provides a debugfs file that lists out the ASIDs currently associated + * with the processes. + * + * In the SH-5 case, if the DM.PC register is examined through the debug + * link, this shows ASID + PC. To make use of this, the PID->ASID + * relationship needs to be known. This is primarily for debugging. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include +#include +#include +#include +#include + +static int asids_seq_show(struct seq_file *file, void *iter) +{ + struct task_struct *p; + + read_lock(&tasklist_lock); + + for_each_process(p) { + int pid = p->pid; + + if (unlikely(!pid)) + continue; + + if (p->mm) + seq_printf(file, "%5d : %02lx\n", pid, + cpu_asid(smp_processor_id(), p->mm)); + else + seq_printf(file, "%5d : (none)\n", pid); + } + + read_unlock(&tasklist_lock); + + return 0; +} + +static int asids_debugfs_open(struct inode *inode, struct file *file) +{ + return single_open(file, asids_seq_show, inode->i_private); +} + +static const struct file_operations asids_debugfs_fops = { + .owner = THIS_MODULE, + .open = asids_debugfs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init asids_debugfs_init(void) +{ + struct dentry *asids_dentry; + + asids_dentry = debugfs_create_file("asids", S_IRUSR, sh_debugfs_root, + NULL, &asids_debugfs_fops); + if (!asids_dentry) + return -ENOMEM; + if (IS_ERR(asids_dentry)) + return PTR_ERR(asids_dentry); + + return 0; +} +module_init(asids_debugfs_init); + +MODULE_LICENSE("GPL v2"); diff --git a/arch/sh/mm/consistent.c b/arch/sh/mm/consistent.c index 9f8ea3ada4dbe845d6ff5dde86267471022e8afc..edcd5fbf9651398cfbdb1d7fea6bc9fdcf789bd1 100644 --- a/arch/sh/mm/consistent.c +++ b/arch/sh/mm/consistent.c @@ -42,6 +42,8 @@ void *dma_alloc_coherent(struct device *dev, size_t size, return NULL; } + split_page(pfn_to_page(virt_to_phys(ret) >> PAGE_SHIFT), order); + *dma_handle = virt_to_phys(ret); return ret_nocache; } @@ -51,10 +53,13 @@ void dma_free_coherent(struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle) { int order = get_order(size); + unsigned long pfn = dma_handle >> PAGE_SHIFT; + int k; if (!dma_release_from_coherent(dev, order, vaddr)) { WARN_ON(irqs_disabled()); /* for portability */ - free_pages((unsigned long)phys_to_virt(dma_handle), order); + for (k = 0; k < (1 << order); k++) + __free_pages(pfn_to_page(pfn + k), 0); iounmap(vaddr); } } diff --git a/arch/sh/mm/fault_32.c b/arch/sh/mm/fault_32.c index 898d477e47c171e6930832d950d85f0a3bd9a617..31a33ebdef6f8ca18d379c89cfa91fc995ce5eec 100644 --- a/arch/sh/mm/fault_32.c +++ b/arch/sh/mm/fault_32.c @@ -20,7 +20,6 @@ #include #include #include -#include /* * This routine handles page faults. It determines the address, @@ -265,17 +264,6 @@ static inline int notify_page_fault(struct pt_regs *regs, int trap) return ret; } -#ifdef CONFIG_SH_STORE_QUEUES -/* - * This is a special case for the SH-4 store queues, as pages for this - * space still need to be faulted in before it's possible to flush the - * store queue cache for writeout to the remapped region. - */ -#define P3_ADDR_MAX (P4SEG_STORE_QUE + 0x04000000) -#else -#define P3_ADDR_MAX P4SEG -#endif - /* * Called with interrupts disabled. */ @@ -293,11 +281,6 @@ asmlinkage int __kprobes __do_page_fault(struct pt_regs *regs, if (notify_page_fault(regs, lookup_exception_vector())) goto out; -#ifdef CONFIG_SH_KGDB - if (kgdb_nofault && kgdb_bus_err_hook) - kgdb_bus_err_hook(); -#endif - ret = 1; /* diff --git a/arch/sh/mm/ioremap_32.c b/arch/sh/mm/ioremap_32.c index 882a32ebc6b7c593c303a4d711cce5ae03001222..32946fba123e597046a7316f49150a1b6d3be8ea 100644 --- a/arch/sh/mm/ioremap_32.c +++ b/arch/sh/mm/ioremap_32.c @@ -116,9 +116,10 @@ EXPORT_SYMBOL(__ioremap); void __iounmap(void __iomem *addr) { unsigned long vaddr = (unsigned long __force)addr; + unsigned long seg = PXSEG(vaddr); struct vm_struct *p; - if (PXSEG(vaddr) < P3SEG || is_pci_memaddr(vaddr)) + if (seg < P3SEG || seg >= P3_ADDR_MAX || is_pci_memaddr(vaddr)) return; #ifdef CONFIG_32BIT diff --git a/arch/sh/mm/mmap.c b/arch/sh/mm/mmap.c index 8837d511710afc1bca4a6e0356d6060e2238c08a..931f4d003fa07fc66b2c4b9e14c53ac1e972c616 100644 --- a/arch/sh/mm/mmap.c +++ b/arch/sh/mm/mmap.c @@ -9,7 +9,101 @@ */ #include #include +#include +#include #include +#include + +#ifdef CONFIG_MMU +unsigned long shm_align_mask = PAGE_SIZE - 1; /* Sane caches */ +EXPORT_SYMBOL(shm_align_mask); + +/* + * To avoid cache aliases, we map the shared page with same color. + */ +#define COLOUR_ALIGN(addr, pgoff) \ + ((((addr) + shm_align_mask) & ~shm_align_mask) + \ + (((pgoff) << PAGE_SHIFT) & shm_align_mask)) + +unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, + unsigned long len, unsigned long pgoff, unsigned long flags) +{ + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + unsigned long start_addr; + int do_colour_align; + + if (flags & MAP_FIXED) { + /* We do not accept a shared mapping if it would violate + * cache aliasing constraints. + */ + if ((flags & MAP_SHARED) && (addr & shm_align_mask)) + return -EINVAL; + return addr; + } + + if (unlikely(len > TASK_SIZE)) + return -ENOMEM; + + do_colour_align = 0; + if (filp || (flags & MAP_SHARED)) + do_colour_align = 1; + + if (addr) { + if (do_colour_align) + addr = COLOUR_ALIGN(addr, pgoff); + else + addr = PAGE_ALIGN(addr); + + vma = find_vma(mm, addr); + if (TASK_SIZE - len >= addr && + (!vma || addr + len <= vma->vm_start)) + return addr; + } + + if (len > mm->cached_hole_size) { + start_addr = addr = mm->free_area_cache; + } else { + mm->cached_hole_size = 0; + start_addr = addr = TASK_UNMAPPED_BASE; + } + +full_search: + if (do_colour_align) + addr = COLOUR_ALIGN(addr, pgoff); + else + addr = PAGE_ALIGN(mm->free_area_cache); + + for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { + /* At this point: (!vma || addr < vma->vm_end). */ + if (unlikely(TASK_SIZE - len < addr)) { + /* + * Start a new search - just in case we missed + * some holes. + */ + if (start_addr != TASK_UNMAPPED_BASE) { + start_addr = addr = TASK_UNMAPPED_BASE; + mm->cached_hole_size = 0; + goto full_search; + } + return -ENOMEM; + } + if (likely(!vma || addr + len <= vma->vm_start)) { + /* + * Remember the place where we stopped the search: + */ + mm->free_area_cache = addr + len; + return addr; + } + if (addr + mm->cached_hole_size < vma->vm_start) + mm->cached_hole_size = vma->vm_start - addr; + + addr = vma->vm_end; + if (do_colour_align) + addr = COLOUR_ALIGN(addr, pgoff); + } +} +#endif /* CONFIG_MMU */ /* * You really shouldn't be using read() or write() on /dev/mem. This diff --git a/arch/sh/oprofile/Makefile b/arch/sh/oprofile/Makefile index 2efc2e79fd297019e7f207175fba437e668b7852..8e6eec91c14c902a9a9bea438fee6ac2e6c7560c 100644 --- a/arch/sh/oprofile/Makefile +++ b/arch/sh/oprofile/Makefile @@ -6,13 +6,8 @@ DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \ oprofilefs.o oprofile_stats.o \ timer_int.o ) -profdrvr-y := op_model_null.o +oprofile-y := $(DRIVER_OBJS) common.o backtrace.o -# SH7750-style performance counters exist across 7750/7750S and 7091. -profdrvr-$(CONFIG_CPU_SUBTYPE_SH7750S) := op_model_sh7750.o -profdrvr-$(CONFIG_CPU_SUBTYPE_SH7750) := op_model_sh7750.o -profdrvr-$(CONFIG_CPU_SUBTYPE_SH7091) := op_model_sh7750.o - -oprofile-y := $(DRIVER_OBJS) $(profdrvr-y) - -EXTRA_CFLAGS += -Werror +oprofile-$(CONFIG_CPU_SUBTYPE_SH7750S) += op_model_sh7750.o +oprofile-$(CONFIG_CPU_SUBTYPE_SH7750) += op_model_sh7750.o +oprofile-$(CONFIG_CPU_SUBTYPE_SH7091) += op_model_sh7750.o diff --git a/arch/sh/oprofile/backtrace.c b/arch/sh/oprofile/backtrace.c new file mode 100644 index 0000000000000000000000000000000000000000..9499a2914f89b4e10eeae491ddd1cd0a3975021f --- /dev/null +++ b/arch/sh/oprofile/backtrace.c @@ -0,0 +1,114 @@ +/* + * SH specific backtracing code for oprofile + * + * Copyright 2007 STMicroelectronics Ltd. + * + * Author: Dave Peverley + * + * Based on ARM oprofile backtrace code by Richard Purdie and in turn, i386 + * oprofile backtrace code by John Levon, David Smith + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#include +#include +#include +#include +#include +#include +#include + +/* Limit to stop backtracing too far. */ +static int backtrace_limit = 20; + +static unsigned long * +user_backtrace(unsigned long *stackaddr, struct pt_regs *regs) +{ + unsigned long buf_stack; + + /* Also check accessibility of address */ + if (!access_ok(VERIFY_READ, stackaddr, sizeof(unsigned long))) + return NULL; + + if (__copy_from_user_inatomic(&buf_stack, stackaddr, sizeof(unsigned long))) + return NULL; + + /* Quick paranoia check */ + if (buf_stack & 3) + return NULL; + + oprofile_add_trace(buf_stack); + + stackaddr++; + + return stackaddr; +} + +/* + * | | /\ Higher addresses + * | | + * --------------- stack base (address of current_thread_info) + * | thread info | + * . . + * | stack | + * --------------- saved regs->regs[15] value if valid + * . . + * --------------- struct pt_regs stored on stack (struct pt_regs *) + * | | + * . . + * | | + * --------------- ??? + * | | + * | | \/ Lower addresses + * + * Thus, &pt_regs <-> stack base restricts the valid(ish) fp values + */ +static int valid_kernel_stack(unsigned long *stackaddr, struct pt_regs *regs) +{ + unsigned long stack = (unsigned long)regs; + unsigned long stack_base = (stack & ~(THREAD_SIZE - 1)) + THREAD_SIZE; + + return ((unsigned long)stackaddr > stack) && ((unsigned long)stackaddr < stack_base); +} + +static unsigned long * +kernel_backtrace(unsigned long *stackaddr, struct pt_regs *regs) +{ + unsigned long addr; + + /* + * If not a valid kernel address, keep going till we find one + * or the SP stops being a valid address. + */ + do { + addr = *stackaddr++; + oprofile_add_trace(addr); + } while (valid_kernel_stack(stackaddr, regs)); + + return stackaddr; +} + +void sh_backtrace(struct pt_regs * const regs, unsigned int depth) +{ + unsigned long *stackaddr; + + /* + * Paranoia - clip max depth as we could get lost in the weeds. + */ + if (depth > backtrace_limit) + depth = backtrace_limit; + + stackaddr = (unsigned long *)regs->regs[15]; + if (!user_mode(regs)) { + while (depth-- && valid_kernel_stack(stackaddr, regs)) + stackaddr = kernel_backtrace(stackaddr, regs); + + return; + } + + while (depth-- && (stackaddr != NULL)) + stackaddr = user_backtrace(stackaddr, regs); +} diff --git a/arch/sh/oprofile/common.c b/arch/sh/oprofile/common.c new file mode 100644 index 0000000000000000000000000000000000000000..1d97d64cb95fa68cfece09c0d6abec4c97890c16 --- /dev/null +++ b/arch/sh/oprofile/common.c @@ -0,0 +1,150 @@ +/* + * arch/sh/oprofile/init.c + * + * Copyright (C) 2003 - 2008 Paul Mundt + * + * Based on arch/mips/oprofile/common.c: + * + * Copyright (C) 2004, 2005 Ralf Baechle + * Copyright (C) 2005 MIPS Technologies, Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include +#include +#include +#include +#include "op_impl.h" + +extern struct op_sh_model op_model_sh7750_ops __weak; +extern struct op_sh_model op_model_sh4a_ops __weak; + +static struct op_sh_model *model; + +static struct op_counter_config ctr[20]; + +extern void sh_backtrace(struct pt_regs * const regs, unsigned int depth); + +static int op_sh_setup(void) +{ + /* Pre-compute the values to stuff in the hardware registers. */ + model->reg_setup(ctr); + + /* Configure the registers on all cpus. */ + on_each_cpu(model->cpu_setup, NULL, 1); + + return 0; +} + +static int op_sh_create_files(struct super_block *sb, struct dentry *root) +{ + int i, ret = 0; + + for (i = 0; i < model->num_counters; i++) { + struct dentry *dir; + char buf[4]; + + snprintf(buf, sizeof(buf), "%d", i); + dir = oprofilefs_mkdir(sb, root, buf); + + ret |= oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled); + ret |= oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event); + ret |= oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel); + ret |= oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user); + + if (model->create_files) + ret |= model->create_files(sb, dir); + else + ret |= oprofilefs_create_ulong(sb, dir, "count", &ctr[i].count); + + /* Dummy entries */ + ret |= oprofilefs_create_ulong(sb, dir, "unit_mask", &ctr[i].unit_mask); + } + + return ret; +} + +static int op_sh_start(void) +{ + /* Enable performance monitoring for all counters. */ + on_each_cpu(model->cpu_start, NULL, 1); + + return 0; +} + +static void op_sh_stop(void) +{ + /* Disable performance monitoring for all counters. */ + on_each_cpu(model->cpu_stop, NULL, 1); +} + +int __init oprofile_arch_init(struct oprofile_operations *ops) +{ + struct op_sh_model *lmodel = NULL; + int ret; + + /* + * Always assign the backtrace op. If the counter initialization + * fails, we fall back to the timer which will still make use of + * this. + */ + ops->backtrace = sh_backtrace; + + switch (current_cpu_data.type) { + /* SH-4 types */ + case CPU_SH7750: + case CPU_SH7750S: + lmodel = &op_model_sh7750_ops; + break; + + /* SH-4A types */ + case CPU_SH7763: + case CPU_SH7770: + case CPU_SH7780: + case CPU_SH7781: + case CPU_SH7785: + case CPU_SH7723: + case CPU_SHX3: + lmodel = &op_model_sh4a_ops; + break; + + /* SH4AL-DSP types */ + case CPU_SH7343: + case CPU_SH7722: + case CPU_SH7366: + lmodel = &op_model_sh4a_ops; + break; + } + + if (!lmodel) + return -ENODEV; + if (!(current_cpu_data.flags & CPU_HAS_PERF_COUNTER)) + return -ENODEV; + + ret = lmodel->init(); + if (unlikely(ret != 0)) + return ret; + + model = lmodel; + + ops->setup = op_sh_setup; + ops->create_files = op_sh_create_files; + ops->start = op_sh_start; + ops->stop = op_sh_stop; + ops->cpu_type = lmodel->cpu_type; + + printk(KERN_INFO "oprofile: using %s performance monitoring.\n", + lmodel->cpu_type); + + return 0; +} + +void oprofile_arch_exit(void) +{ + if (model && model->exit) + model->exit(); +} diff --git a/arch/sh/oprofile/op_impl.h b/arch/sh/oprofile/op_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..4d509975eba683b28ed91cd76d23b4350aa40009 --- /dev/null +++ b/arch/sh/oprofile/op_impl.h @@ -0,0 +1,33 @@ +#ifndef __OP_IMPL_H +#define __OP_IMPL_H + +/* Per-counter configuration as set via oprofilefs. */ +struct op_counter_config { + unsigned long enabled; + unsigned long event; + + unsigned long long count; + + /* Dummy values for userspace tool compliance */ + unsigned long kernel; + unsigned long user; + unsigned long unit_mask; +}; + +/* Per-architecture configury and hooks. */ +struct op_sh_model { + void (*reg_setup)(struct op_counter_config *); + int (*create_files)(struct super_block *sb, struct dentry *dir); + void (*cpu_setup)(void *dummy); + int (*init)(void); + void (*exit)(void); + void (*cpu_start)(void *args); + void (*cpu_stop)(void *args); + char *cpu_type; + unsigned char num_counters; +}; + +/* arch/sh/oprofile/common.c */ +extern void sh_backtrace(struct pt_regs * const regs, unsigned int depth); + +#endif /* __OP_IMPL_H */ diff --git a/arch/sh/oprofile/op_model_null.c b/arch/sh/oprofile/op_model_null.c deleted file mode 100644 index a845b088edb4f2d487ccf1ddce9cc698f8d2242c..0000000000000000000000000000000000000000 --- a/arch/sh/oprofile/op_model_null.c +++ /dev/null @@ -1,23 +0,0 @@ -/* - * arch/sh/oprofile/op_model_null.c - * - * Copyright (C) 2003 Paul Mundt - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ -#include -#include -#include -#include - -int __init oprofile_arch_init(struct oprofile_operations *ops) -{ - return -ENODEV; -} - -void oprofile_arch_exit(void) -{ -} - diff --git a/arch/sh/oprofile/op_model_sh7750.c b/arch/sh/oprofile/op_model_sh7750.c index 008b3b03750aa94f78f44a601f5de0f2a5af5aea..c892c7c30c2fb530ed3cb189cba0a1306ca57ebd 100644 --- a/arch/sh/oprofile/op_model_sh7750.c +++ b/arch/sh/oprofile/op_model_sh7750.c @@ -3,7 +3,7 @@ * * OProfile support for SH7750/SH7750S Performance Counters * - * Copyright (C) 2003, 2004 Paul Mundt + * Copyright (C) 2003 - 2008 Paul Mundt * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -15,19 +15,16 @@ #include #include #include +#include #include -#include -#include +#include "op_impl.h" #define PM_CR_BASE 0xff000084 /* 16-bit */ #define PM_CTR_BASE 0xff100004 /* 32-bit */ -#define PMCR1 (PM_CR_BASE + 0x00) -#define PMCR2 (PM_CR_BASE + 0x04) -#define PMCTR1H (PM_CTR_BASE + 0x00) -#define PMCTR1L (PM_CTR_BASE + 0x04) -#define PMCTR2H (PM_CTR_BASE + 0x08) -#define PMCTR2L (PM_CTR_BASE + 0x0c) +#define PMCR(n) (PM_CR_BASE + ((n) * 0x04)) +#define PMCTRH(n) (PM_CTR_BASE + 0x00 + ((n) * 0x08)) +#define PMCTRL(n) (PM_CTR_BASE + 0x04 + ((n) * 0x08)) #define PMCR_PMM_MASK 0x0000003f @@ -36,25 +33,15 @@ #define PMCR_PMST 0x00004000 #define PMCR_PMEN 0x00008000 -#define PMCR_ENABLE (PMCR_PMST | PMCR_PMEN) +struct op_sh_model op_model_sh7750_ops; -/* - * SH7750/SH7750S have 2 perf counters - */ #define NR_CNTRS 2 -struct op_counter_config { - unsigned long enabled; - unsigned long event; - unsigned long count; - - /* Dummy values for userspace tool compliance */ - unsigned long kernel; - unsigned long user; - unsigned long unit_mask; -}; - -static struct op_counter_config ctr[NR_CNTRS]; +static struct sh7750_ppc_register_config { + unsigned int ctrl; + unsigned long cnt_hi; + unsigned long cnt_lo; +} regcache[NR_CNTRS]; /* * There are a number of events supported by each counter (33 in total). @@ -116,12 +103,8 @@ static int sh7750_timer_notify(struct pt_regs *regs) static u64 sh7750_read_counter(int counter) { - u32 hi, lo; - - hi = (counter == 0) ? ctrl_inl(PMCTR1H) : ctrl_inl(PMCTR2H); - lo = (counter == 0) ? ctrl_inl(PMCTR1L) : ctrl_inl(PMCTR2L); - - return (u64)((u64)(hi & 0xffff) << 32) | lo; + return (u64)((u64)(__raw_readl(PMCTRH(counter)) & 0xffff) << 32) | + __raw_readl(PMCTRL(counter)); } /* @@ -170,11 +153,7 @@ static ssize_t sh7750_write_count(struct file *file, const char __user *buf, */ WARN_ON(val != 0); - if (counter == 0) { - ctrl_outw(ctrl_inw(PMCR1) | PMCR_PMCLR, PMCR1); - } else { - ctrl_outw(ctrl_inw(PMCR2) | PMCR_PMCLR, PMCR2); - } + __raw_writew(__raw_readw(PMCR(counter)) | PMCR_PMCLR, PMCR(counter)); return count; } @@ -184,88 +163,93 @@ static const struct file_operations count_fops = { .write = sh7750_write_count, }; -static int sh7750_perf_counter_create_files(struct super_block *sb, struct dentry *root) +static int sh7750_ppc_create_files(struct super_block *sb, struct dentry *dir) { - int i; + return oprofilefs_create_file(sb, dir, "count", &count_fops); +} - for (i = 0; i < NR_CNTRS; i++) { - struct dentry *dir; - char buf[4]; +static void sh7750_ppc_reg_setup(struct op_counter_config *ctr) +{ + unsigned int counters = op_model_sh7750_ops.num_counters; + int i; - snprintf(buf, sizeof(buf), "%d", i); - dir = oprofilefs_mkdir(sb, root, buf); + for (i = 0; i < counters; i++) { + regcache[i].ctrl = 0; + regcache[i].cnt_hi = 0; + regcache[i].cnt_lo = 0; - oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled); - oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event); - oprofilefs_create_file(sb, dir, "count", &count_fops); + if (!ctr[i].enabled) + continue; - /* Dummy entries */ - oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel); - oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user); - oprofilefs_create_ulong(sb, dir, "unit_mask", &ctr[i].unit_mask); + regcache[i].ctrl |= ctr[i].event | PMCR_PMEN | PMCR_PMST; + regcache[i].cnt_hi = (unsigned long)((ctr->count >> 32) & 0xffff); + regcache[i].cnt_lo = (unsigned long)(ctr->count & 0xffffffff); } - - return 0; } -static int sh7750_perf_counter_start(void) +static void sh7750_ppc_cpu_setup(void *args) { - u16 pmcr; - - /* Enable counter 1 */ - if (ctr[0].enabled) { - pmcr = ctrl_inw(PMCR1); - WARN_ON(pmcr & PMCR_PMEN); - - pmcr &= ~PMCR_PMM_MASK; - pmcr |= ctr[0].event; - ctrl_outw(pmcr | PMCR_ENABLE, PMCR1); - } - - /* Enable counter 2 */ - if (ctr[1].enabled) { - pmcr = ctrl_inw(PMCR2); - WARN_ON(pmcr & PMCR_PMEN); + unsigned int counters = op_model_sh7750_ops.num_counters; + int i; - pmcr &= ~PMCR_PMM_MASK; - pmcr |= ctr[1].event; - ctrl_outw(pmcr | PMCR_ENABLE, PMCR2); + for (i = 0; i < counters; i++) { + __raw_writew(0, PMCR(i)); + __raw_writel(regcache[i].cnt_hi, PMCTRH(i)); + __raw_writel(regcache[i].cnt_lo, PMCTRL(i)); } - - return register_timer_hook(sh7750_timer_notify); } -static void sh7750_perf_counter_stop(void) +static void sh7750_ppc_cpu_start(void *args) { - ctrl_outw(ctrl_inw(PMCR1) & ~PMCR_PMEN, PMCR1); - ctrl_outw(ctrl_inw(PMCR2) & ~PMCR_PMEN, PMCR2); + unsigned int counters = op_model_sh7750_ops.num_counters; + int i; - unregister_timer_hook(sh7750_timer_notify); + for (i = 0; i < counters; i++) + __raw_writew(regcache[i].ctrl, PMCR(i)); } -static struct oprofile_operations sh7750_perf_counter_ops = { - .create_files = sh7750_perf_counter_create_files, - .start = sh7750_perf_counter_start, - .stop = sh7750_perf_counter_stop, -}; - -int __init oprofile_arch_init(struct oprofile_operations *ops) +static void sh7750_ppc_cpu_stop(void *args) { - if (!(current_cpu_data.flags & CPU_HAS_PERF_COUNTER)) - return -ENODEV; + unsigned int counters = op_model_sh7750_ops.num_counters; + int i; - ops = &sh7750_perf_counter_ops; - ops->cpu_type = "sh/sh7750"; + /* Disable the counters */ + for (i = 0; i < counters; i++) + __raw_writew(__raw_readw(PMCR(i)) & ~PMCR_PMEN, PMCR(i)); +} - printk(KERN_INFO "oprofile: using SH-4 performance monitoring.\n"); +static inline void sh7750_ppc_reset(void) +{ + unsigned int counters = op_model_sh7750_ops.num_counters; + int i; /* Clear the counters */ - ctrl_outw(ctrl_inw(PMCR1) | PMCR_PMCLR, PMCR1); - ctrl_outw(ctrl_inw(PMCR2) | PMCR_PMCLR, PMCR2); + for (i = 0; i < counters; i++) + __raw_writew(__raw_readw(PMCR(i)) | PMCR_PMCLR, PMCR(i)); +} - return 0; +static int sh7750_ppc_init(void) +{ + sh7750_ppc_reset(); + + return register_timer_hook(sh7750_timer_notify); } -void oprofile_arch_exit(void) +static void sh7750_ppc_exit(void) { + unregister_timer_hook(sh7750_timer_notify); + + sh7750_ppc_reset(); } + +struct op_sh_model op_model_sh7750_ops = { + .cpu_type = "sh/sh7750", + .num_counters = NR_CNTRS, + .reg_setup = sh7750_ppc_reg_setup, + .cpu_setup = sh7750_ppc_cpu_setup, + .cpu_start = sh7750_ppc_cpu_start, + .cpu_stop = sh7750_ppc_cpu_stop, + .init = sh7750_ppc_init, + .exit = sh7750_ppc_exit, + .create_files = sh7750_ppc_create_files, +}; diff --git a/arch/sh/tools/mach-types b/arch/sh/tools/mach-types index d0c2928d10669748c5c41136e717a914bbb0d92c..284b7e86749685cc7fe25157edcaf7e8e9bf0dcb 100644 --- a/arch/sh/tools/mach-types +++ b/arch/sh/tools/mach-types @@ -8,6 +8,7 @@ SE SH_SOLUTION_ENGINE HIGHLANDER SH_HIGHLANDER RTS7751R2D SH_RTS7751R2D +RSK SH_RSK # # List of companion chips / MFDs. @@ -46,6 +47,7 @@ R2D_1 RTS7751R2D_1 CAYMAN SH_CAYMAN SDK7780 SH_SDK7780 MIGOR SH_MIGOR +RSK7201 SH_RSK7201 RSK7203 SH_RSK7203 AP325RXA SH_AP325RXA SH7763RDP SH_SH7763RDP diff --git a/arch/sparc/include/asm/device.h b/arch/sparc/include/asm/device.h index 19790eb99cc6830820522a74c11492528ec0f567..3702e087df2c4cbcdab561f7720a2d8f23ebc543 100644 --- a/arch/sparc/include/asm/device.h +++ b/arch/sparc/include/asm/device.h @@ -20,4 +20,16 @@ struct dev_archdata { int numa_node; }; +static inline void dev_archdata_set_node(struct dev_archdata *ad, + struct device_node *np) +{ + ad->prom_node = np; +} + +static inline struct device_node * +dev_archdata_get_node(const struct dev_archdata *ad) +{ + return ad->prom_node; +} + #endif /* _ASM_SPARC_DEVICE_H */ diff --git a/arch/sparc64/kernel/idprom.c b/arch/sparc64/kernel/idprom.c index 5b45a808c621da79fcb7211796277c763bbbee5c..a62ff83337cdc16bf9e83ec0d7013de556ab1351 100644 --- a/arch/sparc64/kernel/idprom.c +++ b/arch/sparc64/kernel/idprom.c @@ -42,8 +42,5 @@ void __init idprom_init(void) idprom->id_cksum, calc_idprom_cksum(idprom)); } - printk("Ethernet address: %02x:%02x:%02x:%02x:%02x:%02x\n", - idprom->id_ethaddr[0], idprom->id_ethaddr[1], - idprom->id_ethaddr[2], idprom->id_ethaddr[3], - idprom->id_ethaddr[4], idprom->id_ethaddr[5]); + printk("Ethernet address: %pM\n", idprom->id_ethaddr); } diff --git a/arch/um/drivers/daemon_kern.c b/arch/um/drivers/daemon_kern.c index d53ff52bb40447942cff82fd93d001cfcc7200e1..b4a1522f21575bbdc1142e0c8653edf999f6c651 100644 --- a/arch/um/drivers/daemon_kern.c +++ b/arch/um/drivers/daemon_kern.c @@ -22,7 +22,7 @@ static void daemon_init(struct net_device *dev, void *data) struct daemon_data *dpri; struct daemon_init *init = data; - pri = dev->priv; + pri = netdev_priv(dev); dpri = (struct daemon_data *) pri->user; dpri->sock_type = init->sock_type; dpri->ctl_sock = init->ctl_sock; diff --git a/arch/um/drivers/mcast_kern.c b/arch/um/drivers/mcast_kern.c index 8c4378a76d6333d88d14537ae1c9a3b42b099537..ffc6416d5ed7f9af80a2490133050098fb8083aa 100644 --- a/arch/um/drivers/mcast_kern.c +++ b/arch/um/drivers/mcast_kern.c @@ -28,7 +28,7 @@ static void mcast_init(struct net_device *dev, void *data) struct mcast_data *dpri; struct mcast_init *init = data; - pri = dev->priv; + pri = netdev_priv(dev); dpri = (struct mcast_data *) pri->user; dpri->addr = init->addr; dpri->port = init->port; diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c index 8f44ebb0dec82286e85838369d8fdfd9de929ae6..e14629c87de4fb48c15943f52ffcedf7fca48821 100644 --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c @@ -161,7 +161,8 @@ void mconsole_proc(struct mc_request *req) goto out_kill; } - file = dentry_open(nd.path.dentry, nd.path.mnt, O_RDONLY); + file = dentry_open(nd.path.dentry, nd.path.mnt, O_RDONLY, + current_cred()); if (IS_ERR(file)) { mconsole_reply(req, "Failed to open file", 1, 0); goto out_kill; diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index 5b4ca8d93682cf70fe191c16c0c1180d872c8c78..fde510b664d34db07ecab00ea48d285adefd2703 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c @@ -76,7 +76,7 @@ static int update_drop_skb(int max) static int uml_net_rx(struct net_device *dev) { - struct uml_net_private *lp = dev->priv; + struct uml_net_private *lp = netdev_priv(dev); int pkt_len; struct sk_buff *skb; @@ -119,7 +119,7 @@ static void uml_dev_close(struct work_struct *work) static irqreturn_t uml_net_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; - struct uml_net_private *lp = dev->priv; + struct uml_net_private *lp = netdev_priv(dev); int err; if (!netif_running(dev)) @@ -150,7 +150,7 @@ static irqreturn_t uml_net_interrupt(int irq, void *dev_id) static int uml_net_open(struct net_device *dev) { - struct uml_net_private *lp = dev->priv; + struct uml_net_private *lp = netdev_priv(dev); int err; if (lp->fd >= 0) { @@ -195,7 +195,7 @@ static int uml_net_open(struct net_device *dev) static int uml_net_close(struct net_device *dev) { - struct uml_net_private *lp = dev->priv; + struct uml_net_private *lp = netdev_priv(dev); netif_stop_queue(dev); @@ -213,7 +213,7 @@ static int uml_net_close(struct net_device *dev) static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct uml_net_private *lp = dev->priv; + struct uml_net_private *lp = netdev_priv(dev); unsigned long flags; int len; @@ -250,7 +250,7 @@ static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev) static struct net_device_stats *uml_net_get_stats(struct net_device *dev) { - struct uml_net_private *lp = dev->priv; + struct uml_net_private *lp = netdev_priv(dev); return &lp->stats; } @@ -267,7 +267,7 @@ static void uml_net_tx_timeout(struct net_device *dev) static int uml_net_set_mac(struct net_device *dev, void *addr) { - struct uml_net_private *lp = dev->priv; + struct uml_net_private *lp = netdev_priv(dev); struct sockaddr *hwaddr = addr; spin_lock_irq(&lp->lock); @@ -368,7 +368,7 @@ static void net_device_release(struct device *dev) { struct uml_net *device = dev->driver_data; struct net_device *netdev = device->dev; - struct uml_net_private *lp = netdev->priv; + struct uml_net_private *lp = netdev_priv(netdev); if (lp->remove != NULL) (*lp->remove)(&lp->user); @@ -418,14 +418,9 @@ static void eth_configure(int n, void *init, char *mac, setup_etheraddr(mac, device->mac, dev->name); - printk(KERN_INFO "Netdevice %d ", n); - printk("(%02x:%02x:%02x:%02x:%02x:%02x) ", - device->mac[0], device->mac[1], - device->mac[2], device->mac[3], - device->mac[4], device->mac[5]); - printk(": "); + printk(KERN_INFO "Netdevice %d (%pM) : ", n, device->mac); - lp = dev->priv; + lp = netdev_priv(dev); /* This points to the transport private data. It's still clear, but we * must memset it to 0 *now*. Let's help the drivers. */ memset(lp, 0, size); @@ -735,7 +730,7 @@ static int net_remove(int n, char **error_out) return -ENODEV; dev = device->dev; - lp = dev->priv; + lp = netdev_priv(dev); if (lp->fd > 0) return -EBUSY; unregister_netdev(dev); @@ -766,7 +761,7 @@ static int uml_inetaddr_event(struct notifier_block *this, unsigned long event, if (dev->open != uml_net_open) return NOTIFY_DONE; - lp = dev->priv; + lp = netdev_priv(dev); proc = NULL; switch (event) { diff --git a/arch/um/drivers/pcap_kern.c b/arch/um/drivers/pcap_kern.c index 3a750dd39be12083935c5cdbb9633f9a3b786cfd..2860525f8ff6d56219e81dd2fe7afa8f3c627c35 100644 --- a/arch/um/drivers/pcap_kern.c +++ b/arch/um/drivers/pcap_kern.c @@ -21,7 +21,7 @@ void pcap_init(struct net_device *dev, void *data) struct pcap_data *ppri; struct pcap_init *init = data; - pri = dev->priv; + pri = netdev_priv(dev); ppri = (struct pcap_data *) pri->user; ppri->host_if = init->host_if; ppri->promisc = init->promisc; diff --git a/arch/um/drivers/slip_kern.c b/arch/um/drivers/slip_kern.c index d19faec7046e5cdb05eba59ff32c1c1beb477beb..5ec17563142e22cc6f6ff1e3ec76db23666d3ec9 100644 --- a/arch/um/drivers/slip_kern.c +++ b/arch/um/drivers/slip_kern.c @@ -19,7 +19,7 @@ static void slip_init(struct net_device *dev, void *data) struct slip_data *spri; struct slip_init *init = data; - private = dev->priv; + private = netdev_priv(dev); spri = (struct slip_data *) private->user; memset(spri->name, 0, sizeof(spri->name)); diff --git a/arch/um/drivers/slirp_kern.c b/arch/um/drivers/slirp_kern.c index d987af277db9d8f1cc943aa72ab46201e57cbb58..f15a6e7654f36fdf17af6388172d8273ebb11f71 100644 --- a/arch/um/drivers/slirp_kern.c +++ b/arch/um/drivers/slirp_kern.c @@ -22,7 +22,7 @@ void slirp_init(struct net_device *dev, void *data) struct slirp_init *init = data; int i; - private = dev->priv; + private = netdev_priv(dev); spri = (struct slirp_data *) private->user; spri->argw = init->argw; diff --git a/arch/um/drivers/vde_kern.c b/arch/um/drivers/vde_kern.c index add7e722defb3a8b331a38d11302b6e290e64d9d..1b852bffdebcf019d61c66dda7f4da77e4e1ff1f 100644 --- a/arch/um/drivers/vde_kern.c +++ b/arch/um/drivers/vde_kern.c @@ -19,7 +19,7 @@ static void vde_init(struct net_device *dev, void *data) struct uml_net_private *pri; struct vde_data *vpri; - pri = dev->priv; + pri = netdev_priv(dev); vpri = (struct vde_data *) pri->user; vpri->vde_switch = init->vde_switch; diff --git a/arch/um/os-Linux/drivers/ethertap_kern.c b/arch/um/os-Linux/drivers/ethertap_kern.c index 046a131f61046260c293e12111f30a53266084fd..7f6f9a71aae40e04db6ff38f901589e38aa54906 100644 --- a/arch/um/os-Linux/drivers/ethertap_kern.c +++ b/arch/um/os-Linux/drivers/ethertap_kern.c @@ -22,7 +22,7 @@ static void etap_init(struct net_device *dev, void *data) struct ethertap_data *epri; struct ethertap_init *init = data; - pri = dev->priv; + pri = netdev_priv(dev); epri = (struct ethertap_data *) pri->user; epri->dev_name = init->dev_name; epri->gate_addr = init->gate_addr; diff --git a/arch/um/os-Linux/drivers/tuntap_kern.c b/arch/um/os-Linux/drivers/tuntap_kern.c index 6b9e33d5de20688d639ace827c57013e76b970ff..4048800e4696a97612b3b2d282a024b3cbd86a96 100644 --- a/arch/um/os-Linux/drivers/tuntap_kern.c +++ b/arch/um/os-Linux/drivers/tuntap_kern.c @@ -21,7 +21,7 @@ static void tuntap_init(struct net_device *dev, void *data) struct tuntap_data *tpri; struct tuntap_init *init = data; - pri = dev->priv; + pri = netdev_priv(dev); tpri = (struct tuntap_data *) pri->user; tpri->dev_name = init->dev_name; tpri->fixed_config = (init->dev_name != NULL); diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index ac22bb7719f730e6b8d12b305ec9e08952a513a4..98a0ed52b5c39ec9d728d89c557353f97f986a32 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -19,6 +19,8 @@ config X86_64 config X86 def_bool y select HAVE_AOUT if X86_32 + select HAVE_READQ + select HAVE_WRITEQ select HAVE_UNSTABLE_SCHED_CLOCK select HAVE_IDE select HAVE_OPROFILE @@ -29,11 +31,14 @@ config X86 select HAVE_FTRACE_MCOUNT_RECORD select HAVE_DYNAMIC_FTRACE select HAVE_FUNCTION_TRACER + select HAVE_FUNCTION_GRAPH_TRACER + select HAVE_FUNCTION_TRACE_MCOUNT_TEST select HAVE_KVM if ((X86_32 && !X86_VOYAGER && !X86_VISWS && !X86_NUMAQ) || X86_64) select HAVE_ARCH_KGDB if !X86_VOYAGER select HAVE_ARCH_TRACEHOOK select HAVE_GENERIC_DMA_COHERENT if X86_32 select HAVE_EFFICIENT_UNALIGNED_ACCESS + select USER_STACKTRACE_SUPPORT config ARCH_DEFCONFIG string @@ -87,6 +92,10 @@ config GENERIC_IOMAP config GENERIC_BUG def_bool y depends on BUG + select GENERIC_BUG_RELATIVE_POINTERS if X86_64 + +config GENERIC_BUG_RELATIVE_POINTERS + bool config GENERIC_HWEIGHT def_bool y @@ -242,21 +251,13 @@ config X86_FIND_SMP_CONFIG def_bool y depends on X86_MPPARSE || X86_VOYAGER -if ACPI config X86_MPPARSE - def_bool y - bool "Enable MPS table" + bool "Enable MPS table" if ACPI + default y depends on X86_LOCAL_APIC help For old smp systems that do not have proper acpi support. Newer systems (esp with 64bit cpus) with acpi support, MADT and DSDT will override it -endif - -if !ACPI -config X86_MPPARSE - def_bool y - depends on X86_LOCAL_APIC -endif choice prompt "Subarchitecture Type" @@ -367,10 +368,10 @@ config X86_RDC321X as R-8610-(G). If you don't have one of these chips, you should say N here. -config SCHED_NO_NO_OMIT_FRAME_POINTER +config SCHED_OMIT_FRAME_POINTER def_bool y prompt "Single-depth WCHAN output" - depends on X86_32 + depends on X86 help Calculate simpler /proc//wchan values. If this option is disabled then wchan values will recurse back to the @@ -465,10 +466,6 @@ config X86_CYCLONE_TIMER def_bool y depends on X86_GENERICARCH -config ES7000_CLUSTERED_APIC - def_bool y - depends on SMP && X86_ES7000 && MPENTIUMIII - source "arch/x86/Kconfig.cpu" config HPET_TIMER @@ -569,7 +566,7 @@ config AMD_IOMMU # need this always selected by IOMMU for the VIA workaround config SWIOTLB - bool + def_bool y if X86_64 help Support for software bounce buffers used on x86-64 systems which don't have a hardware IOMMU (e.g. the current generation @@ -660,6 +657,30 @@ config X86_VISWS_APIC def_bool y depends on X86_32 && X86_VISWS +config X86_REROUTE_FOR_BROKEN_BOOT_IRQS + bool "Reroute for broken boot IRQs" + default n + depends on X86_IO_APIC + help + This option enables a workaround that fixes a source of + spurious interrupts. This is recommended when threaded + interrupt handling is used on systems where the generation of + superfluous "boot interrupts" cannot be disabled. + + Some chipsets generate a legacy INTx "boot IRQ" when the IRQ + entry in the chipset's IO-APIC is masked (as, e.g. the RT + kernel does during interrupt handling). On chipsets where this + boot IRQ generation cannot be disabled, this workaround keeps + the original IRQ line masked so that only the equivalent "boot + IRQ" is delivered to the CPUs. The workaround also tells the + kernel to set up the IRQ handler on the boot IRQ line. In this + way only one interrupt is delivered to the kernel. Otherwise + the spurious second interrupt may cause the kernel to bring + down (vital) interrupt lines. + + Only affects "broken" chipsets. Interrupt sharing may be + increased on these systems. + config X86_MCE bool "Machine Check Exception" depends on !X86_VOYAGER @@ -956,24 +977,37 @@ config X86_PAE config ARCH_PHYS_ADDR_T_64BIT def_bool X86_64 || X86_PAE +config DIRECT_GBPAGES + bool "Enable 1GB pages for kernel pagetables" if EMBEDDED + default y + depends on X86_64 + help + Allow the kernel linear mapping to use 1GB pages on CPUs that + support it. This can improve the kernel's performance a tiny bit by + reducing TLB pressure. If in doubt, say "Y". + # Common NUMA Features config NUMA - bool "Numa Memory Allocation and Scheduler Support (EXPERIMENTAL)" + bool "Numa Memory Allocation and Scheduler Support" depends on SMP depends on X86_64 || (X86_32 && HIGHMEM64G && (X86_NUMAQ || X86_BIGSMP || X86_SUMMIT && ACPI) && EXPERIMENTAL) default n if X86_PC default y if (X86_NUMAQ || X86_SUMMIT || X86_BIGSMP) help Enable NUMA (Non Uniform Memory Access) support. + The kernel will try to allocate memory used by a CPU on the local memory controller of the CPU and add some more NUMA awareness to the kernel. - For 32-bit this is currently highly experimental and should be only - used for kernel development. It might also cause boot failures. - For 64-bit this is recommended on all multiprocessor Opteron systems. - If the system is EM64T, you should say N unless your system is - EM64T NUMA. + For 64-bit this is recommended if the system is Intel Core i7 + (or later), AMD Opteron, or EM64T NUMA. + + For 32-bit this is only needed on (rare) 32-bit-only platforms + that support NUMA topologies, such as NUMAQ / Summit, or if you + boot a 32-bit kernel on a 64-bit NUMA platform. + + Otherwise, you should say N. comment "NUMA (Summit) requires SMP, 64GB highmem support, ACPI" depends on X86_32 && X86_SUMMIT && (!HIGHMEM64G || !ACPI) @@ -1493,6 +1527,10 @@ config ARCH_ENABLE_MEMORY_HOTPLUG def_bool y depends on X86_64 || (X86_32 && HIGHMEM) +config ARCH_ENABLE_MEMORY_HOTREMOVE + def_bool y + depends on MEMORY_HOTPLUG + config HAVE_ARCH_EARLY_PFN_TO_NID def_bool X86_64 depends on NUMA @@ -1632,13 +1670,6 @@ config APM_ALLOW_INTS many of the newer IBM Thinkpads. If you experience hangs when you suspend, try setting this to Y. Otherwise, say N. -config APM_REAL_MODE_POWER_OFF - bool "Use real mode APM BIOS call to power off" - help - Use real mode APM BIOS calls to switch off the computer. This is - a work-around for a number of buggy BIOSes. Switch this option on if - your computer crashes instead of powering off properly. - endif # APM source "arch/x86/kernel/cpu/cpufreq/Kconfig" diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu index b815664fe3700b77aa031fab7711be4128c858d1..85a78575956cb0bdf473c4694f29eb7d497a154e 100644 --- a/arch/x86/Kconfig.cpu +++ b/arch/x86/Kconfig.cpu @@ -515,6 +515,7 @@ config CPU_SUP_UMC_32 config X86_DS def_bool X86_PTRACE_BTS depends on X86_DEBUGCTLMSR + select HAVE_HW_BRANCH_TRACER config X86_PTRACE_BTS bool "Branch Trace Store" diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug index 2a3dfbd5e677b548e5e75f43da69e934b90a7eff..10d6cc3fd052fd56c6817f2736e78a113bfa1046 100644 --- a/arch/x86/Kconfig.debug +++ b/arch/x86/Kconfig.debug @@ -114,18 +114,6 @@ config DEBUG_RODATA data. This is recommended so that we can catch kernel bugs sooner. If in doubt, say "Y". -config DIRECT_GBPAGES - bool "Enable gbpages-mapped kernel pagetables" - depends on DEBUG_KERNEL && EXPERIMENTAL && X86_64 - help - Enable gigabyte pages support (if the CPU supports it). This can - improve the kernel's performance a tiny bit by reducing TLB - pressure. - - This is experimental code. - - If in doubt, say "N". - config DEBUG_RODATA_TEST bool "Testcase for the DEBUG_RODATA feature" depends on DEBUG_RODATA @@ -186,14 +174,10 @@ config IOMMU_LEAK Add a simple leak tracer to the IOMMU code. This is useful when you are debugging a buggy device driver that leaks IOMMU mappings. -config MMIOTRACE_HOOKS - bool - config MMIOTRACE bool "Memory mapped IO tracing" depends on DEBUG_KERNEL && PCI select TRACING - select MMIOTRACE_HOOKS help Mmiotrace traces Memory Mapped I/O access and is meant for debugging and reverse engineering. It is called from the ioremap @@ -307,10 +291,10 @@ config OPTIMIZE_INLINING developers have marked 'inline'. Doing so takes away freedom from gcc to do what it thinks is best, which is desirable for the gcc 3.x series of compilers. The gcc 4.x series have a rewritten inlining algorithm and - disabling this option will generate a smaller kernel there. Hopefully - this algorithm is so good that allowing gcc4 to make the decision can - become the default in the future, until then this option is there to - test gcc for this. + enabling this option will generate a smaller kernel there. Hopefully + this algorithm is so good that allowing gcc 4.x and above to make the + decision will become the default in the future. Until then this option + is there to test gcc for this. If unsure, say N. diff --git a/arch/x86/boot/video-vga.c b/arch/x86/boot/video-vga.c index b939cb476decf7d4d3089f6210c4fe3ecfb5f5be..5d4742ed4aa21dd83d968798a1c7ff92447907a1 100644 --- a/arch/x86/boot/video-vga.c +++ b/arch/x86/boot/video-vga.c @@ -34,7 +34,7 @@ static struct mode_info cga_modes[] = { { VIDEO_80x25, 80, 25, 0 }, }; -__videocard video_vga; +static __videocard video_vga; /* Set basic 80x25 mode */ static u8 vga_set_basic_mode(void) @@ -259,7 +259,7 @@ static int vga_probe(void) return mode_count[adapter]; } -__videocard video_vga = { +static __videocard video_vga = { .card_name = "VGA", .probe = vga_probe, .set_mode = vga_set_mode, diff --git a/arch/x86/boot/video.c b/arch/x86/boot/video.c index 83598b23093aa31398db2d1c9a5f89eb30733357..3bef2c1febe936bd01f1b8d7d6b7d1eb5b1f9bb6 100644 --- a/arch/x86/boot/video.c +++ b/arch/x86/boot/video.c @@ -226,7 +226,7 @@ static unsigned int mode_menu(void) #ifdef CONFIG_VIDEO_RETAIN /* Save screen content to the heap */ -struct saved_screen { +static struct saved_screen { int x, y; int curx, cury; u16 *data; diff --git a/arch/x86/configs/i386_defconfig b/arch/x86/configs/i386_defconfig index 13b8c86ae98570f67375b505e9d106374e24b574..b30a08ed8eb48b8f64f9c79cc5e62f11d63ec669 100644 --- a/arch/x86/configs/i386_defconfig +++ b/arch/x86/configs/i386_defconfig @@ -77,7 +77,7 @@ CONFIG_AUDIT=y CONFIG_AUDITSYSCALL=y CONFIG_AUDIT_TREE=y # CONFIG_IKCONFIG is not set -CONFIG_LOG_BUF_SHIFT=17 +CONFIG_LOG_BUF_SHIFT=18 CONFIG_CGROUPS=y # CONFIG_CGROUP_DEBUG is not set CONFIG_CGROUP_NS=y @@ -298,7 +298,7 @@ CONFIG_KEXEC=y CONFIG_CRASH_DUMP=y # CONFIG_KEXEC_JUMP is not set CONFIG_PHYSICAL_START=0x1000000 -CONFIG_RELOCATABLE=y +# CONFIG_RELOCATABLE is not set CONFIG_PHYSICAL_ALIGN=0x200000 CONFIG_HOTPLUG_CPU=y # CONFIG_COMPAT_VDSO is not set diff --git a/arch/x86/configs/x86_64_defconfig b/arch/x86/configs/x86_64_defconfig index f0a03d7a7d63f2f2c32f7daea043a0935021bba3..0e7dbc0a3e460e2934887c8c0d744c0515f66c6d 100644 --- a/arch/x86/configs/x86_64_defconfig +++ b/arch/x86/configs/x86_64_defconfig @@ -77,7 +77,7 @@ CONFIG_AUDIT=y CONFIG_AUDITSYSCALL=y CONFIG_AUDIT_TREE=y # CONFIG_IKCONFIG is not set -CONFIG_LOG_BUF_SHIFT=17 +CONFIG_LOG_BUF_SHIFT=18 CONFIG_CGROUPS=y # CONFIG_CGROUP_DEBUG is not set CONFIG_CGROUP_NS=y @@ -298,7 +298,7 @@ CONFIG_SCHED_HRTICK=y CONFIG_KEXEC=y CONFIG_CRASH_DUMP=y CONFIG_PHYSICAL_START=0x1000000 -CONFIG_RELOCATABLE=y +# CONFIG_RELOCATABLE is not set CONFIG_PHYSICAL_ALIGN=0x200000 CONFIG_HOTPLUG_CPU=y # CONFIG_COMPAT_VDSO is not set diff --git a/arch/x86/crypto/crc32c-intel.c b/arch/x86/crypto/crc32c-intel.c index 070afc5b6c94b404a6664a0e9ff61c714dc498ad..b9d00261703c56f45e25cf9740c412ce26c71e71 100644 --- a/arch/x86/crypto/crc32c-intel.c +++ b/arch/x86/crypto/crc32c-intel.c @@ -6,13 +6,22 @@ * Intel(R) 64 and IA-32 Architectures Software Developer's Manual * Volume 2A: Instruction Set Reference, A-M * - * Copyright (c) 2008 Austin Zhang - * Copyright (c) 2008 Kent Liu + * Copyright (C) 2008 Intel Corporation + * Authors: Austin Zhang + * Kent Liu * * 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. + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #include @@ -75,99 +84,92 @@ static u32 __pure crc32c_intel_le_hw(u32 crc, unsigned char const *p, size_t len * If your algorithm starts with ~0, then XOR with ~0 before you set * the seed. */ -static int crc32c_intel_setkey(struct crypto_ahash *hash, const u8 *key, +static int crc32c_intel_setkey(struct crypto_shash *hash, const u8 *key, unsigned int keylen) { - u32 *mctx = crypto_ahash_ctx(hash); + u32 *mctx = crypto_shash_ctx(hash); if (keylen != sizeof(u32)) { - crypto_ahash_set_flags(hash, CRYPTO_TFM_RES_BAD_KEY_LEN); + crypto_shash_set_flags(hash, CRYPTO_TFM_RES_BAD_KEY_LEN); return -EINVAL; } *mctx = le32_to_cpup((__le32 *)key); return 0; } -static int crc32c_intel_init(struct ahash_request *req) +static int crc32c_intel_init(struct shash_desc *desc) { - u32 *mctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req)); - u32 *crcp = ahash_request_ctx(req); + u32 *mctx = crypto_shash_ctx(desc->tfm); + u32 *crcp = shash_desc_ctx(desc); *crcp = *mctx; return 0; } -static int crc32c_intel_update(struct ahash_request *req) +static int crc32c_intel_update(struct shash_desc *desc, const u8 *data, + unsigned int len) { - struct crypto_hash_walk walk; - u32 *crcp = ahash_request_ctx(req); - u32 crc = *crcp; - int nbytes; - - for (nbytes = crypto_hash_walk_first(req, &walk); nbytes; - nbytes = crypto_hash_walk_done(&walk, 0)) - crc = crc32c_intel_le_hw(crc, walk.data, nbytes); + u32 *crcp = shash_desc_ctx(desc); - *crcp = crc; + *crcp = crc32c_intel_le_hw(*crcp, data, len); return 0; } -static int crc32c_intel_final(struct ahash_request *req) +static int __crc32c_intel_finup(u32 *crcp, const u8 *data, unsigned int len, + u8 *out) { - u32 *crcp = ahash_request_ctx(req); - - *(__le32 *)req->result = ~cpu_to_le32p(crcp); + *(__le32 *)out = ~cpu_to_le32(crc32c_intel_le_hw(*crcp, data, len)); return 0; } -static int crc32c_intel_digest(struct ahash_request *req) +static int crc32c_intel_finup(struct shash_desc *desc, const u8 *data, + unsigned int len, u8 *out) { - struct crypto_hash_walk walk; - u32 *mctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req)); - u32 crc = *mctx; - int nbytes; + return __crc32c_intel_finup(shash_desc_ctx(desc), data, len, out); +} - for (nbytes = crypto_hash_walk_first(req, &walk); nbytes; - nbytes = crypto_hash_walk_done(&walk, 0)) - crc = crc32c_intel_le_hw(crc, walk.data, nbytes); +static int crc32c_intel_final(struct shash_desc *desc, u8 *out) +{ + u32 *crcp = shash_desc_ctx(desc); - *(__le32 *)req->result = ~cpu_to_le32(crc); + *(__le32 *)out = ~cpu_to_le32p(crcp); return 0; } +static int crc32c_intel_digest(struct shash_desc *desc, const u8 *data, + unsigned int len, u8 *out) +{ + return __crc32c_intel_finup(crypto_shash_ctx(desc->tfm), data, len, + out); +} + static int crc32c_intel_cra_init(struct crypto_tfm *tfm) { u32 *key = crypto_tfm_ctx(tfm); *key = ~0; - tfm->crt_ahash.reqsize = sizeof(u32); - return 0; } -static struct crypto_alg alg = { - .cra_name = "crc32c", - .cra_driver_name = "crc32c-intel", - .cra_priority = 200, - .cra_flags = CRYPTO_ALG_TYPE_AHASH, - .cra_blocksize = CHKSUM_BLOCK_SIZE, - .cra_alignmask = 3, - .cra_ctxsize = sizeof(u32), - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(alg.cra_list), - .cra_init = crc32c_intel_cra_init, - .cra_type = &crypto_ahash_type, - .cra_u = { - .ahash = { - .digestsize = CHKSUM_DIGEST_SIZE, - .setkey = crc32c_intel_setkey, - .init = crc32c_intel_init, - .update = crc32c_intel_update, - .final = crc32c_intel_final, - .digest = crc32c_intel_digest, - } +static struct shash_alg alg = { + .setkey = crc32c_intel_setkey, + .init = crc32c_intel_init, + .update = crc32c_intel_update, + .final = crc32c_intel_final, + .finup = crc32c_intel_finup, + .digest = crc32c_intel_digest, + .descsize = sizeof(u32), + .digestsize = CHKSUM_DIGEST_SIZE, + .base = { + .cra_name = "crc32c", + .cra_driver_name = "crc32c-intel", + .cra_priority = 200, + .cra_blocksize = CHKSUM_BLOCK_SIZE, + .cra_ctxsize = sizeof(u32), + .cra_module = THIS_MODULE, + .cra_init = crc32c_intel_cra_init, } }; @@ -175,14 +177,14 @@ static struct crypto_alg alg = { static int __init crc32c_intel_mod_init(void) { if (cpu_has_xmm4_2) - return crypto_register_alg(&alg); + return crypto_register_shash(&alg); else return -ENODEV; } static void __exit crc32c_intel_mod_fini(void) { - crypto_unregister_alg(&alg); + crypto_unregister_shash(&alg); } module_init(crc32c_intel_mod_init); @@ -194,4 +196,3 @@ MODULE_LICENSE("GPL"); MODULE_ALIAS("crc32c"); MODULE_ALIAS("crc32c-intel"); - diff --git a/arch/x86/ia32/ia32_aout.c b/arch/x86/ia32/ia32_aout.c index 127ec3f072144b7976d19533989cd97cc41da327..2a4d073d2cf12124830ddcd2879485c5f61629b0 100644 --- a/arch/x86/ia32/ia32_aout.c +++ b/arch/x86/ia32/ia32_aout.c @@ -327,7 +327,7 @@ static int load_aout_binary(struct linux_binprm *bprm, struct pt_regs *regs) current->mm->cached_hole_size = 0; current->mm->mmap = NULL; - compute_creds(bprm); + install_exec_creds(bprm); current->flags &= ~PF_FORKNOEXEC; if (N_MAGIC(ex) == OMAGIC) { diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c index 4bc02b23674b5dfaaf91e813fb2be320dc57cd23..b195f85526e35813e08e93b2553587a37896af2f 100644 --- a/arch/x86/ia32/ia32_signal.c +++ b/arch/x86/ia32/ia32_signal.c @@ -32,6 +32,8 @@ #include #include +#include + #define DEBUG_SIG 0 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) @@ -41,7 +43,6 @@ X86_EFLAGS_ZF | X86_EFLAGS_AF | X86_EFLAGS_PF | \ X86_EFLAGS_CF) -asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); void signal_fault(struct pt_regs *regs, void __user *frame, char *where); int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from) @@ -173,47 +174,28 @@ asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr, /* * Do a signal return; undo the signal stack. */ +#define COPY(x) { \ + err |= __get_user(regs->x, &sc->x); \ +} -struct sigframe -{ - u32 pretcode; - int sig; - struct sigcontext_ia32 sc; - struct _fpstate_ia32 fpstate_unused; /* look at kernel/sigframe.h */ - unsigned int extramask[_COMPAT_NSIG_WORDS-1]; - char retcode[8]; - /* fp state follows here */ -}; - -struct rt_sigframe -{ - u32 pretcode; - int sig; - u32 pinfo; - u32 puc; - compat_siginfo_t info; - struct ucontext_ia32 uc; - char retcode[8]; - /* fp state follows here */ -}; - -#define COPY(x) { \ - unsigned int reg; \ - err |= __get_user(reg, &sc->x); \ - regs->x = reg; \ +#define COPY_SEG_CPL3(seg) { \ + unsigned short tmp; \ + err |= __get_user(tmp, &sc->seg); \ + regs->seg = tmp | 3; \ } -#define RELOAD_SEG(seg,mask) \ - { unsigned int cur; \ - unsigned short pre; \ - err |= __get_user(pre, &sc->seg); \ - savesegment(seg, cur); \ - pre |= mask; \ - if (pre != cur) loadsegment(seg, pre); } +#define RELOAD_SEG(seg) { \ + unsigned int cur, pre; \ + err |= __get_user(pre, &sc->seg); \ + savesegment(seg, cur); \ + pre |= 3; \ + if (pre != cur) \ + loadsegment(seg, pre); \ +} static int ia32_restore_sigcontext(struct pt_regs *regs, struct sigcontext_ia32 __user *sc, - unsigned int *peax) + unsigned int *pax) { unsigned int tmpflags, gs, oldgs, err = 0; void __user *buf; @@ -240,18 +222,16 @@ static int ia32_restore_sigcontext(struct pt_regs *regs, if (gs != oldgs) load_gs_index(gs); - RELOAD_SEG(fs, 3); - RELOAD_SEG(ds, 3); - RELOAD_SEG(es, 3); + RELOAD_SEG(fs); + RELOAD_SEG(ds); + RELOAD_SEG(es); COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx); COPY(dx); COPY(cx); COPY(ip); /* Don't touch extended registers */ - err |= __get_user(regs->cs, &sc->cs); - regs->cs |= 3; - err |= __get_user(regs->ss, &sc->ss); - regs->ss |= 3; + COPY_SEG_CPL3(cs); + COPY_SEG_CPL3(ss); err |= __get_user(tmpflags, &sc->flags); regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); @@ -262,15 +242,13 @@ static int ia32_restore_sigcontext(struct pt_regs *regs, buf = compat_ptr(tmp); err |= restore_i387_xstate_ia32(buf); - err |= __get_user(tmp, &sc->ax); - *peax = tmp; - + err |= __get_user(*pax, &sc->ax); return err; } asmlinkage long sys32_sigreturn(struct pt_regs *regs) { - struct sigframe __user *frame = (struct sigframe __user *)(regs->sp-8); + struct sigframe_ia32 __user *frame = (struct sigframe_ia32 __user *)(regs->sp-8); sigset_t set; unsigned int ax; @@ -300,12 +278,12 @@ asmlinkage long sys32_sigreturn(struct pt_regs *regs) asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs) { - struct rt_sigframe __user *frame; + struct rt_sigframe_ia32 __user *frame; sigset_t set; unsigned int ax; struct pt_regs tregs; - frame = (struct rt_sigframe __user *)(regs->sp - 4); + frame = (struct rt_sigframe_ia32 __user *)(regs->sp - 4); if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) goto badframe; @@ -359,20 +337,15 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc, err |= __put_user(regs->dx, &sc->dx); err |= __put_user(regs->cx, &sc->cx); err |= __put_user(regs->ax, &sc->ax); - err |= __put_user(regs->cs, &sc->cs); - err |= __put_user(regs->ss, &sc->ss); err |= __put_user(current->thread.trap_no, &sc->trapno); err |= __put_user(current->thread.error_code, &sc->err); err |= __put_user(regs->ip, &sc->ip); + err |= __put_user(regs->cs, (unsigned int __user *)&sc->cs); err |= __put_user(regs->flags, &sc->flags); err |= __put_user(regs->sp, &sc->sp_at_signal); + err |= __put_user(regs->ss, (unsigned int __user *)&sc->ss); - tmp = save_i387_xstate_ia32(fpstate); - if (tmp < 0) - err = -EFAULT; - else - err |= __put_user(ptr_to_compat(tmp ? fpstate : NULL), - &sc->fpstate); + err |= __put_user(ptr_to_compat(fpstate), &sc->fpstate); /* non-iBCS2 extensions.. */ err |= __put_user(mask, &sc->oldmask); @@ -400,7 +373,7 @@ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, } /* This is the legacy signal stack switching. */ - else if ((regs->ss & 0xffff) != __USER_DS && + else if ((regs->ss & 0xffff) != __USER32_DS && !(ka->sa.sa_flags & SA_RESTORER) && ka->sa.sa_restorer) sp = (unsigned long) ka->sa.sa_restorer; @@ -408,6 +381,8 @@ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, if (used_math()) { sp = sp - sig_xstate_ia32_size; *fpstate = (struct _fpstate_ia32 *) sp; + if (save_i387_xstate_ia32(*fpstate) < 0) + return (void __user *) -1L; } sp -= frame_size; @@ -420,7 +395,7 @@ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, int ia32_setup_frame(int sig, struct k_sigaction *ka, compat_sigset_t *set, struct pt_regs *regs) { - struct sigframe __user *frame; + struct sigframe_ia32 __user *frame; void __user *restorer; int err = 0; void __user *fpstate = NULL; @@ -430,12 +405,10 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, u16 poplmovl; u32 val; u16 int80; - u16 pad; } __attribute__((packed)) code = { 0xb858, /* popl %eax ; movl $...,%eax */ __NR_ia32_sigreturn, 0x80cd, /* int $0x80 */ - 0, }; frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); @@ -471,7 +444,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, * These are actually not used anymore, but left because some * gdb versions depend on them as a marker. */ - err |= __copy_to_user(frame->retcode, &code, 8); + err |= __put_user(*((u64 *)&code), (u64 *)frame->retcode); if (err) return -EFAULT; @@ -501,7 +474,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, compat_sigset_t *set, struct pt_regs *regs) { - struct rt_sigframe __user *frame; + struct rt_sigframe_ia32 __user *frame; void __user *restorer; int err = 0; void __user *fpstate = NULL; @@ -511,8 +484,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, u8 movl; u32 val; u16 int80; - u16 pad; - u8 pad2; + u8 pad; } __attribute__((packed)) code = { 0xb8, __NR_ia32_rt_sigreturn, @@ -559,7 +531,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, * Not actually used anymore, but left because some gdb * versions need it. */ - err |= __copy_to_user(frame->retcode, &code, 8); + err |= __put_user(*((u64 *)&code), (u64 *)frame->retcode); if (err) return -EFAULT; @@ -572,11 +544,6 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, regs->dx = (unsigned long) &frame->info; regs->cx = (unsigned long) &frame->uc; - /* Make -mregparm=3 work */ - regs->ax = sig; - regs->dx = (unsigned long) &frame->info; - regs->cx = (unsigned long) &frame->uc; - loadsegment(ds, __USER32_DS); loadsegment(es, __USER32_DS); diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h index 3b1510b4fc5741290d5660bb4c30f34bc70f6371..25caa0738af5f9d99399d3c2f36405bc62d7115b 100644 --- a/arch/x86/include/asm/apic.h +++ b/arch/x86/include/asm/apic.h @@ -193,6 +193,7 @@ extern u8 setup_APIC_eilvt_ibs(u8 vector, u8 msg_type, u8 mask); static inline void lapic_shutdown(void) { } #define local_apic_timer_c2_ok 1 static inline void init_apic_mappings(void) { } +static inline void disable_local_APIC(void) { } #endif /* !CONFIG_X86_LOCAL_APIC */ diff --git a/arch/x86/include/asm/bigsmp/apic.h b/arch/x86/include/asm/bigsmp/apic.h index 1d9543b9d35824c259a1110005866be3d1f54a4e..ce547f24a1cd30da5da6a9fc088d4a94cae2f7c8 100644 --- a/arch/x86/include/asm/bigsmp/apic.h +++ b/arch/x86/include/asm/bigsmp/apic.h @@ -24,8 +24,6 @@ static inline cpumask_t target_cpus(void) #define INT_DELIVERY_MODE (dest_Fixed) #define INT_DEST_MODE (0) /* phys delivery to target proc */ #define NO_BALANCE_IRQ (0) -#define WAKE_SECONDARY_VIA_INIT - static inline unsigned long check_apicid_used(physid_mask_t bitmap, int apicid) { diff --git a/arch/x86/include/asm/bitops.h b/arch/x86/include/asm/bitops.h index 360010322711037f80040829acceed8de6a15f42..9fa9dcdf344baeb25ccfa79db6222b5aae470ba5 100644 --- a/arch/x86/include/asm/bitops.h +++ b/arch/x86/include/asm/bitops.h @@ -168,7 +168,15 @@ static inline void __change_bit(int nr, volatile unsigned long *addr) */ static inline void change_bit(int nr, volatile unsigned long *addr) { - asm volatile(LOCK_PREFIX "btc %1,%0" : ADDR : "Ir" (nr)); + if (IS_IMMEDIATE(nr)) { + asm volatile(LOCK_PREFIX "xorb %1,%0" + : CONST_MASK_ADDR(nr, addr) + : "iq" ((u8)CONST_MASK(nr))); + } else { + asm volatile(LOCK_PREFIX "btc %1,%0" + : BITOP_ADDR(addr) + : "Ir" (nr)); + } } /** diff --git a/arch/x86/include/asm/bug.h b/arch/x86/include/asm/bug.h index 3def2065fcea73ba085fcb31ee5063e2cfc57adb..d9cf1cd156d24b5cebe5a8ed41292b6300e8c9c2 100644 --- a/arch/x86/include/asm/bug.h +++ b/arch/x86/include/asm/bug.h @@ -9,7 +9,7 @@ #ifdef CONFIG_X86_32 # define __BUG_C0 "2:\t.long 1b, %c0\n" #else -# define __BUG_C0 "2:\t.quad 1b, %c0\n" +# define __BUG_C0 "2:\t.long 1b - 2b, %c0 - 2b\n" #endif #define BUG() \ diff --git a/arch/x86/include/asm/byteorder.h b/arch/x86/include/asm/byteorder.h index e02ae2d89acf13936aad26502e485aa6ddae0b65..f110ad417df3e0121333cbb06564a492ef8be2c2 100644 --- a/arch/x86/include/asm/byteorder.h +++ b/arch/x86/include/asm/byteorder.h @@ -4,26 +4,33 @@ #include #include -#ifdef __GNUC__ +#define __LITTLE_ENDIAN -#ifdef __i386__ - -static inline __attribute_const__ __u32 ___arch__swab32(__u32 x) +static inline __attribute_const__ __u32 __arch_swab32(__u32 val) { -#ifdef CONFIG_X86_BSWAP - asm("bswap %0" : "=r" (x) : "0" (x)); -#else +#ifdef __i386__ +# ifdef CONFIG_X86_BSWAP + asm("bswap %0" : "=r" (val) : "0" (val)); +# else asm("xchgb %b0,%h0\n\t" /* swap lower bytes */ "rorl $16,%0\n\t" /* swap words */ "xchgb %b0,%h0" /* swap higher bytes */ - : "=q" (x) - : "0" (x)); + : "=q" (val) + : "0" (val)); +# endif + +#else /* __i386__ */ + asm("bswapl %0" + : "=r" (val) + : "0" (val)); #endif - return x; + return val; } +#define __arch_swab32 __arch_swab32 -static inline __attribute_const__ __u64 ___arch__swab64(__u64 val) +static inline __attribute_const__ __u64 __arch_swab64(__u64 val) { +#ifdef __i386__ union { struct { __u32 a; @@ -32,50 +39,27 @@ static inline __attribute_const__ __u64 ___arch__swab64(__u64 val) __u64 u; } v; v.u = val; -#ifdef CONFIG_X86_BSWAP +# ifdef CONFIG_X86_BSWAP asm("bswapl %0 ; bswapl %1 ; xchgl %0,%1" : "=r" (v.s.a), "=r" (v.s.b) : "0" (v.s.a), "1" (v.s.b)); -#else - v.s.a = ___arch__swab32(v.s.a); - v.s.b = ___arch__swab32(v.s.b); +# else + v.s.a = __arch_swab32(v.s.a); + v.s.b = __arch_swab32(v.s.b); asm("xchgl %0,%1" : "=r" (v.s.a), "=r" (v.s.b) : "0" (v.s.a), "1" (v.s.b)); -#endif +# endif return v.u; -} - #else /* __i386__ */ - -static inline __attribute_const__ __u64 ___arch__swab64(__u64 x) -{ asm("bswapq %0" - : "=r" (x) - : "0" (x)); - return x; -} - -static inline __attribute_const__ __u32 ___arch__swab32(__u32 x) -{ - asm("bswapl %0" - : "=r" (x) - : "0" (x)); - return x; -} - + : "=r" (val) + : "0" (val)); + return val; #endif +} +#define __arch_swab64 __arch_swab64 -/* Do not define swab16. Gcc is smart enough to recognize "C" version and - convert it into rotation or exhange. */ - -#define __arch__swab64(x) ___arch__swab64(x) -#define __arch__swab32(x) ___arch__swab32(x) - -#define __BYTEORDER_HAS_U64__ - -#endif /* __GNUC__ */ - -#include +#include #endif /* _ASM_X86_BYTEORDER_H */ diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h index cfdf8c2c5c313a0de8639577cb12a3679292637c..ea408dcba5135a04d35514e784ce7837ad90e285 100644 --- a/arch/x86/include/asm/cpufeature.h +++ b/arch/x86/include/asm/cpufeature.h @@ -80,7 +80,6 @@ #define X86_FEATURE_UP (3*32+ 9) /* smp kernel running on up */ #define X86_FEATURE_FXSAVE_LEAK (3*32+10) /* "" FXSAVE leaks FOP/FIP/FOP */ #define X86_FEATURE_ARCH_PERFMON (3*32+11) /* Intel Architectural PerfMon */ -#define X86_FEATURE_NOPL (3*32+20) /* The NOPL (0F 1F) instructions */ #define X86_FEATURE_PEBS (3*32+12) /* Precise-Event Based Sampling */ #define X86_FEATURE_BTS (3*32+13) /* Branch Trace Store */ #define X86_FEATURE_SYSCALL32 (3*32+14) /* "" syscall in ia32 userspace */ @@ -92,6 +91,8 @@ #define X86_FEATURE_NOPL (3*32+20) /* The NOPL (0F 1F) instructions */ #define X86_FEATURE_AMDC1E (3*32+21) /* AMD C1E detected */ #define X86_FEATURE_XTOPOLOGY (3*32+22) /* cpu topology enum extensions */ +#define X86_FEATURE_TSC_RELIABLE (3*32+23) /* TSC is known to be reliable */ +#define X86_FEATURE_NONSTOP_TSC (3*32+24) /* TSC does not stop in C states */ /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */ #define X86_FEATURE_XMM3 (4*32+ 0) /* "pni" SSE-3 */ @@ -117,6 +118,7 @@ #define X86_FEATURE_XSAVE (4*32+26) /* XSAVE/XRSTOR/XSETBV/XGETBV */ #define X86_FEATURE_OSXSAVE (4*32+27) /* "" XSAVE enabled in the OS */ #define X86_FEATURE_AVX (4*32+28) /* Advanced Vector Extensions */ +#define X86_FEATURE_HYPERVISOR (4*32+31) /* Running on a hypervisor */ /* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */ #define X86_FEATURE_XSTORE (5*32+ 2) /* "rng" RNG present (xstore) */ @@ -237,6 +239,7 @@ extern const char * const x86_power_flags[32]; #define cpu_has_xmm4_2 boot_cpu_has(X86_FEATURE_XMM4_2) #define cpu_has_x2apic boot_cpu_has(X86_FEATURE_X2APIC) #define cpu_has_xsave boot_cpu_has(X86_FEATURE_XSAVE) +#define cpu_has_hypervisor boot_cpu_has(X86_FEATURE_HYPERVISOR) #if defined(CONFIG_X86_INVLPG) || defined(CONFIG_X86_64) # define cpu_has_invlpg 1 diff --git a/arch/x86/include/asm/dma-mapping.h b/arch/x86/include/asm/dma-mapping.h index 097794ff6b796a2f955ddc7a8eef96a249c8b94f..dc22c0733282b9ce631250d69cbcc00e0cd46617 100644 --- a/arch/x86/include/asm/dma-mapping.h +++ b/arch/x86/include/asm/dma-mapping.h @@ -71,12 +71,10 @@ static inline struct dma_mapping_ops *get_dma_ops(struct device *dev) /* Make sure we keep the same behaviour */ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { -#ifdef CONFIG_X86_64 struct dma_mapping_ops *ops = get_dma_ops(dev); if (ops->mapping_error) return ops->mapping_error(dev, dma_addr); -#endif return (dma_addr == bad_dma_address); } diff --git a/arch/x86/include/asm/ds.h b/arch/x86/include/asm/ds.h index a95008457ea430ffbe7fdde3fc6a5fd57778ce79..a8f672ba100c541fa893c4167dffabfab1c97561 100644 --- a/arch/x86/include/asm/ds.h +++ b/arch/x86/include/asm/ds.h @@ -6,14 +6,13 @@ * precise-event based sampling (PEBS). * * It manages: - * - per-thread and per-cpu allocation of BTS and PEBS - * - buffer memory allocation (optional) - * - buffer overflow handling + * - DS and BTS hardware configuration + * - buffer overflow handling (to be done) * - buffer access * - * It assumes: - * - get_task_struct on all parameter tasks - * - current is allowed to trace parameter tasks + * It does not do: + * - security checking (is the caller allowed to trace the task) + * - buffer allocation (memory accounting) * * * Copyright (C) 2007-2008 Intel Corporation. @@ -26,11 +25,51 @@ #include #include +#include #ifdef CONFIG_X86_DS struct task_struct; +struct ds_context; +struct ds_tracer; +struct bts_tracer; +struct pebs_tracer; + +typedef void (*bts_ovfl_callback_t)(struct bts_tracer *); +typedef void (*pebs_ovfl_callback_t)(struct pebs_tracer *); + + +/* + * A list of features plus corresponding macros to talk about them in + * the ds_request function's flags parameter. + * + * We use the enum to index an array of corresponding control bits; + * we use the macro to index a flags bit-vector. + */ +enum ds_feature { + dsf_bts = 0, + dsf_bts_kernel, +#define BTS_KERNEL (1 << dsf_bts_kernel) + /* trace kernel-mode branches */ + + dsf_bts_user, +#define BTS_USER (1 << dsf_bts_user) + /* trace user-mode branches */ + + dsf_bts_overflow, + dsf_bts_max, + dsf_pebs = dsf_bts_max, + + dsf_pebs_max, + dsf_ctl_max = dsf_pebs_max, + dsf_bts_timestamps = dsf_ctl_max, +#define BTS_TIMESTAMPS (1 << dsf_bts_timestamps) + /* add timestamps into BTS trace */ + +#define BTS_USER_FLAGS (BTS_KERNEL | BTS_USER | BTS_TIMESTAMPS) +}; + /* * Request BTS or PEBS @@ -38,163 +77,169 @@ struct task_struct; * Due to alignement constraints, the actual buffer may be slightly * smaller than the requested or provided buffer. * - * Returns 0 on success; -Eerrno otherwise + * Returns a pointer to a tracer structure on success, or + * ERR_PTR(errcode) on failure. + * + * The interrupt threshold is independent from the overflow callback + * to allow users to use their own overflow interrupt handling mechanism. * * task: the task to request recording for; * NULL for per-cpu recording on the current cpu * base: the base pointer for the (non-pageable) buffer; - * NULL if buffer allocation requested - * size: the size of the requested or provided buffer + * size: the size of the provided buffer in bytes * ovfl: pointer to a function to be called on buffer overflow; * NULL if cyclic buffer requested + * th: the interrupt threshold in records from the end of the buffer; + * -1 if no interrupt threshold is requested. + * flags: a bit-mask of the above flags */ -typedef void (*ds_ovfl_callback_t)(struct task_struct *); -extern int ds_request_bts(struct task_struct *task, void *base, size_t size, - ds_ovfl_callback_t ovfl); -extern int ds_request_pebs(struct task_struct *task, void *base, size_t size, - ds_ovfl_callback_t ovfl); +extern struct bts_tracer *ds_request_bts(struct task_struct *task, + void *base, size_t size, + bts_ovfl_callback_t ovfl, + size_t th, unsigned int flags); +extern struct pebs_tracer *ds_request_pebs(struct task_struct *task, + void *base, size_t size, + pebs_ovfl_callback_t ovfl, + size_t th, unsigned int flags); /* * Release BTS or PEBS resources + * Suspend and resume BTS or PEBS tracing * - * Frees buffers allocated on ds_request. - * - * Returns 0 on success; -Eerrno otherwise - * - * task: the task to release resources for; - * NULL to release resources for the current cpu + * tracer: the tracer handle returned from ds_request_~() */ -extern int ds_release_bts(struct task_struct *task); -extern int ds_release_pebs(struct task_struct *task); +extern void ds_release_bts(struct bts_tracer *tracer); +extern void ds_suspend_bts(struct bts_tracer *tracer); +extern void ds_resume_bts(struct bts_tracer *tracer); +extern void ds_release_pebs(struct pebs_tracer *tracer); +extern void ds_suspend_pebs(struct pebs_tracer *tracer); +extern void ds_resume_pebs(struct pebs_tracer *tracer); -/* - * Return the (array) index of the write pointer. - * (assuming an array of BTS/PEBS records) - * - * Returns -Eerrno on error - * - * task: the task to access; - * NULL to access the current cpu - * pos (out): if not NULL, will hold the result - */ -extern int ds_get_bts_index(struct task_struct *task, size_t *pos); -extern int ds_get_pebs_index(struct task_struct *task, size_t *pos); /* - * Return the (array) index one record beyond the end of the array. - * (assuming an array of BTS/PEBS records) + * The raw DS buffer state as it is used for BTS and PEBS recording. * - * Returns -Eerrno on error - * - * task: the task to access; - * NULL to access the current cpu - * pos (out): if not NULL, will hold the result + * This is the low-level, arch-dependent interface for working + * directly on the raw trace data. */ -extern int ds_get_bts_end(struct task_struct *task, size_t *pos); -extern int ds_get_pebs_end(struct task_struct *task, size_t *pos); +struct ds_trace { + /* the number of bts/pebs records */ + size_t n; + /* the size of a bts/pebs record in bytes */ + size_t size; + /* pointers into the raw buffer: + - to the first entry */ + void *begin; + /* - one beyond the last entry */ + void *end; + /* - one beyond the newest entry */ + void *top; + /* - the interrupt threshold */ + void *ith; + /* flags given on ds_request() */ + unsigned int flags; +}; /* - * Provide a pointer to the BTS/PEBS record at parameter index. - * (assuming an array of BTS/PEBS records) - * - * The pointer points directly into the buffer. The user is - * responsible for copying the record. - * - * Returns the size of a single record on success; -Eerrno on error - * - * task: the task to access; - * NULL to access the current cpu - * index: the index of the requested record - * record (out): pointer to the requested record + * An arch-independent view on branch trace data. */ -extern int ds_access_bts(struct task_struct *task, - size_t index, const void **record); -extern int ds_access_pebs(struct task_struct *task, - size_t index, const void **record); +enum bts_qualifier { + bts_invalid, +#define BTS_INVALID bts_invalid + + bts_branch, +#define BTS_BRANCH bts_branch + + bts_task_arrives, +#define BTS_TASK_ARRIVES bts_task_arrives + + bts_task_departs, +#define BTS_TASK_DEPARTS bts_task_departs + + bts_qual_bit_size = 4, + bts_qual_max = (1 << bts_qual_bit_size), +}; + +struct bts_struct { + __u64 qualifier; + union { + /* BTS_BRANCH */ + struct { + __u64 from; + __u64 to; + } lbr; + /* BTS_TASK_ARRIVES or BTS_TASK_DEPARTS */ + struct { + __u64 jiffies; + pid_t pid; + } timestamp; + } variant; +}; -/* - * Write one or more BTS/PEBS records at the write pointer index and - * advance the write pointer. - * - * If size is not a multiple of the record size, trailing bytes are - * zeroed out. - * - * May result in one or more overflow notifications. - * - * If called during overflow handling, that is, with index >= - * interrupt threshold, the write will wrap around. - * - * An overflow notification is given if and when the interrupt - * threshold is reached during or after the write. - * - * Returns the number of bytes written or -Eerrno. - * - * task: the task to access; - * NULL to access the current cpu - * buffer: the buffer to write - * size: the size of the buffer - */ -extern int ds_write_bts(struct task_struct *task, - const void *buffer, size_t size); -extern int ds_write_pebs(struct task_struct *task, - const void *buffer, size_t size); /* - * Same as ds_write_bts/pebs, but omit ownership checks. + * The BTS state. * - * This is needed to have some other task than the owner of the - * BTS/PEBS buffer or the parameter task itself write into the - * respective buffer. + * This gives access to the raw DS state and adds functions to provide + * an arch-independent view of the BTS data. */ -extern int ds_unchecked_write_bts(struct task_struct *task, - const void *buffer, size_t size); -extern int ds_unchecked_write_pebs(struct task_struct *task, - const void *buffer, size_t size); +struct bts_trace { + struct ds_trace ds; + + int (*read)(struct bts_tracer *tracer, const void *at, + struct bts_struct *out); + int (*write)(struct bts_tracer *tracer, const struct bts_struct *in); +}; + /* - * Reset the write pointer of the BTS/PEBS buffer. + * The PEBS state. * - * Returns 0 on success; -Eerrno on error - * - * task: the task to access; - * NULL to access the current cpu + * This gives access to the raw DS state and the PEBS-specific counter + * reset value. */ -extern int ds_reset_bts(struct task_struct *task); -extern int ds_reset_pebs(struct task_struct *task); +struct pebs_trace { + struct ds_trace ds; + + /* the PEBS reset value */ + unsigned long long reset_value; +}; + /* - * Clear the BTS/PEBS buffer and reset the write pointer. - * The entire buffer will be zeroed out. + * Read the BTS or PEBS trace. * - * Returns 0 on success; -Eerrno on error + * Returns a view on the trace collected for the parameter tracer. + * + * The view remains valid as long as the traced task is not running or + * the tracer is suspended. + * Writes into the trace buffer are not reflected. * - * task: the task to access; - * NULL to access the current cpu + * tracer: the tracer handle returned from ds_request_~() */ -extern int ds_clear_bts(struct task_struct *task); -extern int ds_clear_pebs(struct task_struct *task); +extern const struct bts_trace *ds_read_bts(struct bts_tracer *tracer); +extern const struct pebs_trace *ds_read_pebs(struct pebs_tracer *tracer); + /* - * Provide the PEBS counter reset value. + * Reset the write pointer of the BTS/PEBS buffer. * * Returns 0 on success; -Eerrno on error * - * task: the task to access; - * NULL to access the current cpu - * value (out): the counter reset value + * tracer: the tracer handle returned from ds_request_~() */ -extern int ds_get_pebs_reset(struct task_struct *task, u64 *value); +extern int ds_reset_bts(struct bts_tracer *tracer); +extern int ds_reset_pebs(struct pebs_tracer *tracer); /* * Set the PEBS counter reset value. * * Returns 0 on success; -Eerrno on error * - * task: the task to access; - * NULL to access the current cpu + * tracer: the tracer handle returned from ds_request_pebs() * value: the new counter reset value */ -extern int ds_set_pebs_reset(struct task_struct *task, u64 value); +extern int ds_set_pebs_reset(struct pebs_tracer *tracer, u64 value); /* * Initialization @@ -202,39 +247,26 @@ extern int ds_set_pebs_reset(struct task_struct *task, u64 value); struct cpuinfo_x86; extern void __cpuinit ds_init_intel(struct cpuinfo_x86 *); - - /* - * The DS context - part of struct thread_struct. + * Context switch work */ -struct ds_context { - /* pointer to the DS configuration; goes into MSR_IA32_DS_AREA */ - unsigned char *ds; - /* the owner of the BTS and PEBS configuration, respectively */ - struct task_struct *owner[2]; - /* buffer overflow notification function for BTS and PEBS */ - ds_ovfl_callback_t callback[2]; - /* the original buffer address */ - void *buffer[2]; - /* the number of allocated pages for on-request allocated buffers */ - unsigned int pages[2]; - /* use count */ - unsigned long count; - /* a pointer to the context location inside the thread_struct - * or the per_cpu context array */ - struct ds_context **this; - /* a pointer to the task owning this context, or NULL, if the - * context is owned by a cpu */ - struct task_struct *task; -}; +extern void ds_switch_to(struct task_struct *prev, struct task_struct *next); -/* called by exit_thread() to free leftover contexts */ -extern void ds_free(struct ds_context *context); +/* + * Task clone/init and cleanup work + */ +extern void ds_copy_thread(struct task_struct *tsk, struct task_struct *father); +extern void ds_exit_thread(struct task_struct *tsk); #else /* CONFIG_X86_DS */ struct cpuinfo_x86; static inline void __cpuinit ds_init_intel(struct cpuinfo_x86 *ignored) {} +static inline void ds_switch_to(struct task_struct *prev, + struct task_struct *next) {} +static inline void ds_copy_thread(struct task_struct *tsk, + struct task_struct *father) {} +static inline void ds_exit_thread(struct task_struct *tsk) {} #endif /* CONFIG_X86_DS */ #endif /* _ASM_X86_DS_H */ diff --git a/arch/x86/include/asm/dwarf2.h b/arch/x86/include/asm/dwarf2.h index 804b6e6be9296aa5295018018404b2c9db05f6da..3afc5e87cfddbebc3e57773210ff8e89c0c232ce 100644 --- a/arch/x86/include/asm/dwarf2.h +++ b/arch/x86/include/asm/dwarf2.h @@ -6,56 +6,91 @@ #endif /* - Macros for dwarf2 CFI unwind table entries. - See "as.info" for details on these pseudo ops. Unfortunately - they are only supported in very new binutils, so define them - away for older version. + * Macros for dwarf2 CFI unwind table entries. + * See "as.info" for details on these pseudo ops. Unfortunately + * they are only supported in very new binutils, so define them + * away for older version. */ #ifdef CONFIG_AS_CFI -#define CFI_STARTPROC .cfi_startproc -#define CFI_ENDPROC .cfi_endproc -#define CFI_DEF_CFA .cfi_def_cfa -#define CFI_DEF_CFA_REGISTER .cfi_def_cfa_register -#define CFI_DEF_CFA_OFFSET .cfi_def_cfa_offset -#define CFI_ADJUST_CFA_OFFSET .cfi_adjust_cfa_offset -#define CFI_OFFSET .cfi_offset -#define CFI_REL_OFFSET .cfi_rel_offset -#define CFI_REGISTER .cfi_register -#define CFI_RESTORE .cfi_restore -#define CFI_REMEMBER_STATE .cfi_remember_state -#define CFI_RESTORE_STATE .cfi_restore_state -#define CFI_UNDEFINED .cfi_undefined +#define CFI_STARTPROC .cfi_startproc +#define CFI_ENDPROC .cfi_endproc +#define CFI_DEF_CFA .cfi_def_cfa +#define CFI_DEF_CFA_REGISTER .cfi_def_cfa_register +#define CFI_DEF_CFA_OFFSET .cfi_def_cfa_offset +#define CFI_ADJUST_CFA_OFFSET .cfi_adjust_cfa_offset +#define CFI_OFFSET .cfi_offset +#define CFI_REL_OFFSET .cfi_rel_offset +#define CFI_REGISTER .cfi_register +#define CFI_RESTORE .cfi_restore +#define CFI_REMEMBER_STATE .cfi_remember_state +#define CFI_RESTORE_STATE .cfi_restore_state +#define CFI_UNDEFINED .cfi_undefined #ifdef CONFIG_AS_CFI_SIGNAL_FRAME -#define CFI_SIGNAL_FRAME .cfi_signal_frame +#define CFI_SIGNAL_FRAME .cfi_signal_frame #else #define CFI_SIGNAL_FRAME #endif #else -/* Due to the structure of pre-exisiting code, don't use assembler line - comment character # to ignore the arguments. Instead, use a dummy macro. */ +/* + * Due to the structure of pre-exisiting code, don't use assembler line + * comment character # to ignore the arguments. Instead, use a dummy macro. + */ .macro cfi_ignore a=0, b=0, c=0, d=0 .endm -#define CFI_STARTPROC cfi_ignore -#define CFI_ENDPROC cfi_ignore -#define CFI_DEF_CFA cfi_ignore +#define CFI_STARTPROC cfi_ignore +#define CFI_ENDPROC cfi_ignore +#define CFI_DEF_CFA cfi_ignore #define CFI_DEF_CFA_REGISTER cfi_ignore #define CFI_DEF_CFA_OFFSET cfi_ignore #define CFI_ADJUST_CFA_OFFSET cfi_ignore -#define CFI_OFFSET cfi_ignore -#define CFI_REL_OFFSET cfi_ignore -#define CFI_REGISTER cfi_ignore -#define CFI_RESTORE cfi_ignore -#define CFI_REMEMBER_STATE cfi_ignore -#define CFI_RESTORE_STATE cfi_ignore -#define CFI_UNDEFINED cfi_ignore -#define CFI_SIGNAL_FRAME cfi_ignore +#define CFI_OFFSET cfi_ignore +#define CFI_REL_OFFSET cfi_ignore +#define CFI_REGISTER cfi_ignore +#define CFI_RESTORE cfi_ignore +#define CFI_REMEMBER_STATE cfi_ignore +#define CFI_RESTORE_STATE cfi_ignore +#define CFI_UNDEFINED cfi_ignore +#define CFI_SIGNAL_FRAME cfi_ignore #endif +/* + * An attempt to make CFI annotations more or less + * correct and shorter. It is implied that you know + * what you're doing if you use them. + */ +#ifdef __ASSEMBLY__ +#ifdef CONFIG_X86_64 + .macro pushq_cfi reg + pushq \reg + CFI_ADJUST_CFA_OFFSET 8 + .endm + + .macro popq_cfi reg + popq \reg + CFI_ADJUST_CFA_OFFSET -8 + .endm + + .macro movq_cfi reg offset=0 + movq %\reg, \offset(%rsp) + CFI_REL_OFFSET \reg, \offset + .endm + + .macro movq_cfi_restore offset reg + movq \offset(%rsp), %\reg + CFI_RESTORE \reg + .endm +#else /*!CONFIG_X86_64*/ + + /* 32bit defenitions are missed yet */ + +#endif /*!CONFIG_X86_64*/ +#endif /*__ASSEMBLY__*/ + #endif /* _ASM_X86_DWARF2_H */ diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h index 40ca1bea7916cc075448446887609b43e58dc670..f51a3ddde01a753c5931e4d352c165a6e3d0ebd7 100644 --- a/arch/x86/include/asm/elf.h +++ b/arch/x86/include/asm/elf.h @@ -325,7 +325,7 @@ struct linux_binprm; #define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1 extern int arch_setup_additional_pages(struct linux_binprm *bprm, - int executable_stack); + int uses_interp); extern int syscall32_setup_pages(struct linux_binprm *, int exstack); #define compat_arch_setup_additional_pages syscall32_setup_pages diff --git a/arch/x86/include/asm/emergency-restart.h b/arch/x86/include/asm/emergency-restart.h index 94826cf874557acedd7afe248daa588a0c6383dd..cc70c1c78ca47545bb7b927f878d3cb02275f142 100644 --- a/arch/x86/include/asm/emergency-restart.h +++ b/arch/x86/include/asm/emergency-restart.h @@ -8,7 +8,9 @@ enum reboot_type { BOOT_BIOS = 'b', #endif BOOT_ACPI = 'a', - BOOT_EFI = 'e' + BOOT_EFI = 'e', + BOOT_CF9 = 'p', + BOOT_CF9_COND = 'q', }; extern enum reboot_type reboot_type; diff --git a/arch/x86/include/asm/es7000/apic.h b/arch/x86/include/asm/es7000/apic.h index 380f0b4f17edfcf5c1e1440baed7231e07cdb684..e24ef876915f8833cd996c1a879b1b3ecaa54826 100644 --- a/arch/x86/include/asm/es7000/apic.h +++ b/arch/x86/include/asm/es7000/apic.h @@ -9,31 +9,27 @@ static inline int apic_id_registered(void) return (1); } -static inline cpumask_t target_cpus(void) +static inline cpumask_t target_cpus_cluster(void) { -#if defined CONFIG_ES7000_CLUSTERED_APIC return CPU_MASK_ALL; -#else +} + +static inline cpumask_t target_cpus(void) +{ return cpumask_of_cpu(smp_processor_id()); -#endif } -#if defined CONFIG_ES7000_CLUSTERED_APIC -#define APIC_DFR_VALUE (APIC_DFR_CLUSTER) -#define INT_DELIVERY_MODE (dest_LowestPrio) -#define INT_DEST_MODE (1) /* logical delivery broadcast to all procs */ -#define NO_BALANCE_IRQ (1) -#undef WAKE_SECONDARY_VIA_INIT -#define WAKE_SECONDARY_VIA_MIP -#else +#define APIC_DFR_VALUE_CLUSTER (APIC_DFR_CLUSTER) +#define INT_DELIVERY_MODE_CLUSTER (dest_LowestPrio) +#define INT_DEST_MODE_CLUSTER (1) /* logical delivery broadcast to all procs */ +#define NO_BALANCE_IRQ_CLUSTER (1) + #define APIC_DFR_VALUE (APIC_DFR_FLAT) #define INT_DELIVERY_MODE (dest_Fixed) #define INT_DEST_MODE (0) /* phys delivery to target procs */ #define NO_BALANCE_IRQ (0) #undef APIC_DEST_LOGICAL #define APIC_DEST_LOGICAL 0x0 -#define WAKE_SECONDARY_VIA_INIT -#endif static inline unsigned long check_apicid_used(physid_mask_t bitmap, int apicid) { @@ -60,6 +56,16 @@ static inline unsigned long calculate_ldr(int cpu) * an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel * document number 292116). So here it goes... */ +static inline void init_apic_ldr_cluster(void) +{ + unsigned long val; + int cpu = smp_processor_id(); + + apic_write(APIC_DFR, APIC_DFR_VALUE_CLUSTER); + val = calculate_ldr(cpu); + apic_write(APIC_LDR, val); +} + static inline void init_apic_ldr(void) { unsigned long val; @@ -70,10 +76,6 @@ static inline void init_apic_ldr(void) apic_write(APIC_LDR, val); } -#ifndef CONFIG_X86_GENERICARCH -extern void enable_apic_mode(void); -#endif - extern int apic_version [MAX_APICS]; static inline void setup_apic_routing(void) { @@ -144,7 +146,7 @@ static inline int check_phys_apicid_present(int cpu_physical_apicid) return (1); } -static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask) +static inline unsigned int cpu_mask_to_apicid_cluster(cpumask_t cpumask) { int num_bits_set; int cpus_found = 0; @@ -154,11 +156,7 @@ static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask) num_bits_set = cpus_weight(cpumask); /* Return id to all */ if (num_bits_set == NR_CPUS) -#if defined CONFIG_ES7000_CLUSTERED_APIC return 0xFF; -#else - return cpu_to_logical_apicid(0); -#endif /* * The cpus in the mask must all be on the apic cluster. If are not * on the same apicid cluster return default value of TARGET_CPUS. @@ -171,11 +169,40 @@ static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask) if (apicid_cluster(apicid) != apicid_cluster(new_apicid)){ printk ("%s: Not a valid mask!\n", __func__); -#if defined CONFIG_ES7000_CLUSTERED_APIC return 0xFF; -#else + } + apicid = new_apicid; + cpus_found++; + } + cpu++; + } + return apicid; +} + +static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask) +{ + int num_bits_set; + int cpus_found = 0; + int cpu; + int apicid; + + num_bits_set = cpus_weight(cpumask); + /* Return id to all */ + if (num_bits_set == NR_CPUS) + return cpu_to_logical_apicid(0); + /* + * The cpus in the mask must all be on the apic cluster. If are not + * on the same apicid cluster return default value of TARGET_CPUS. + */ + cpu = first_cpu(cpumask); + apicid = cpu_to_logical_apicid(cpu); + while (cpus_found < num_bits_set) { + if (cpu_isset(cpu, cpumask)) { + int new_apicid = cpu_to_logical_apicid(cpu); + if (apicid_cluster(apicid) != + apicid_cluster(new_apicid)){ + printk ("%s: Not a valid mask!\n", __func__); return cpu_to_logical_apicid(0); -#endif } apicid = new_apicid; cpus_found++; diff --git a/arch/x86/include/asm/es7000/wakecpu.h b/arch/x86/include/asm/es7000/wakecpu.h index 3984934619136119dfd7d95045d5930ab415e917..78f0daaee436333d9162013c62324dfe66bb1b9b 100644 --- a/arch/x86/include/asm/es7000/wakecpu.h +++ b/arch/x86/include/asm/es7000/wakecpu.h @@ -1,36 +1,12 @@ #ifndef __ASM_ES7000_WAKECPU_H #define __ASM_ES7000_WAKECPU_H -/* - * This file copes with machines that wakeup secondary CPUs by the - * INIT, INIT, STARTUP sequence. - */ - -#ifdef CONFIG_ES7000_CLUSTERED_APIC -#define WAKE_SECONDARY_VIA_MIP -#else -#define WAKE_SECONDARY_VIA_INIT -#endif - -#ifdef WAKE_SECONDARY_VIA_MIP -extern int es7000_start_cpu(int cpu, unsigned long eip); -static inline int -wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip) -{ - int boot_error = 0; - boot_error = es7000_start_cpu(phys_apicid, start_eip); - return boot_error; -} -#endif - -#define TRAMPOLINE_LOW phys_to_virt(0x467) -#define TRAMPOLINE_HIGH phys_to_virt(0x469) - -#define boot_cpu_apicid boot_cpu_physical_apicid +#define TRAMPOLINE_PHYS_LOW 0x467 +#define TRAMPOLINE_PHYS_HIGH 0x469 static inline void wait_for_init_deassert(atomic_t *deassert) { -#ifdef WAKE_SECONDARY_VIA_INIT +#ifndef CONFIG_ES7000_CLUSTERED_APIC while (!atomic_read(deassert)) cpu_relax(); #endif @@ -50,9 +26,12 @@ static inline void restore_NMI_vector(unsigned short *high, unsigned short *low) { } -#define inquire_remote_apic(apicid) do { \ - if (apic_verbosity >= APIC_DEBUG) \ - __inquire_remote_apic(apicid); \ - } while (0) +extern void __inquire_remote_apic(int apicid); + +static inline void inquire_remote_apic(int apicid) +{ + if (apic_verbosity >= APIC_DEBUG) + __inquire_remote_apic(apicid); +} #endif /* __ASM_MACH_WAKECPU_H */ diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h index 9e8bc29b8b17dd3739d7479af6920c3c627130cb..b55b4a7fbefd365b76813e86e71259f799bfdb59 100644 --- a/arch/x86/include/asm/ftrace.h +++ b/arch/x86/include/asm/ftrace.h @@ -1,6 +1,33 @@ #ifndef _ASM_X86_FTRACE_H #define _ASM_X86_FTRACE_H +#ifdef __ASSEMBLY__ + + .macro MCOUNT_SAVE_FRAME + /* taken from glibc */ + subq $0x38, %rsp + movq %rax, (%rsp) + movq %rcx, 8(%rsp) + movq %rdx, 16(%rsp) + movq %rsi, 24(%rsp) + movq %rdi, 32(%rsp) + movq %r8, 40(%rsp) + movq %r9, 48(%rsp) + .endm + + .macro MCOUNT_RESTORE_FRAME + movq 48(%rsp), %r9 + movq 40(%rsp), %r8 + movq 32(%rsp), %rdi + movq 24(%rsp), %rsi + movq 16(%rsp), %rdx + movq 8(%rsp), %rcx + movq (%rsp), %rax + addq $0x38, %rsp + .endm + +#endif + #ifdef CONFIG_FUNCTION_TRACER #define MCOUNT_ADDR ((long)(mcount)) #define MCOUNT_INSN_SIZE 5 /* sizeof mcount call */ @@ -17,8 +44,40 @@ static inline unsigned long ftrace_call_adjust(unsigned long addr) */ return addr - 1; } -#endif +#ifdef CONFIG_DYNAMIC_FTRACE + +struct dyn_arch_ftrace { + /* No extra data needed for x86 */ +}; + +#endif /* CONFIG_DYNAMIC_FTRACE */ +#endif /* __ASSEMBLY__ */ #endif /* CONFIG_FUNCTION_TRACER */ +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + +#ifndef __ASSEMBLY__ + +/* + * Stack of return addresses for functions + * of a thread. + * Used in struct thread_info + */ +struct ftrace_ret_stack { + unsigned long ret; + unsigned long func; + unsigned long long calltime; +}; + +/* + * Primary handler of a function return. + * It relays on ftrace_return_to_handler. + * Defined in entry_32/64.S + */ +extern void return_to_handler(void); + +#endif /* __ASSEMBLY__ */ +#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ + #endif /* _ASM_X86_FTRACE_H */ diff --git a/arch/x86/include/asm/gart.h b/arch/x86/include/asm/gart.h index 74252264433d8fa3b628afe7f91a49365d377b8a..6cfdafa409d8f436d106e4fb9f1e19374d913d55 100644 --- a/arch/x86/include/asm/gart.h +++ b/arch/x86/include/asm/gart.h @@ -29,6 +29,39 @@ extern int fix_aperture; #define AMD64_GARTCACHECTL 0x9c #define AMD64_GARTEN (1<<0) +#ifdef CONFIG_GART_IOMMU +extern int gart_iommu_aperture; +extern int gart_iommu_aperture_allowed; +extern int gart_iommu_aperture_disabled; + +extern void early_gart_iommu_check(void); +extern void gart_iommu_init(void); +extern void gart_iommu_shutdown(void); +extern void __init gart_parse_options(char *); +extern void gart_iommu_hole_init(void); + +#else +#define gart_iommu_aperture 0 +#define gart_iommu_aperture_allowed 0 +#define gart_iommu_aperture_disabled 1 + +static inline void early_gart_iommu_check(void) +{ +} +static inline void gart_iommu_init(void) +{ +} +static inline void gart_iommu_shutdown(void) +{ +} +static inline void gart_parse_options(char *options) +{ +} +static inline void gart_iommu_hole_init(void) +{ +} +#endif + extern int agp_amd64_init(void); static inline void enable_gart_translation(struct pci_dev *dev, u64 addr) diff --git a/arch/x86/include/asm/genapic_32.h b/arch/x86/include/asm/genapic_32.h index 5cbd4fcc06fd20425ce21ead1386c47d92d0b152..0ac17d33a8c7114a015ba2bb4971e3b5e381a6da 100644 --- a/arch/x86/include/asm/genapic_32.h +++ b/arch/x86/include/asm/genapic_32.h @@ -2,6 +2,7 @@ #define _ASM_X86_GENAPIC_32_H #include +#include /* * Generic APIC driver interface. @@ -65,6 +66,14 @@ struct genapic { void (*send_IPI_allbutself)(int vector); void (*send_IPI_all)(int vector); #endif + int (*wakeup_cpu)(int apicid, unsigned long start_eip); + int trampoline_phys_low; + int trampoline_phys_high; + void (*wait_for_init_deassert)(atomic_t *deassert); + void (*smp_callin_clear_local_apic)(void); + void (*store_NMI_vector)(unsigned short *high, unsigned short *low); + void (*restore_NMI_vector)(unsigned short *high, unsigned short *low); + void (*inquire_remote_apic)(int apicid); }; #define APICFUNC(x) .x = x, @@ -105,16 +114,24 @@ struct genapic { APICFUNC(get_apic_id) \ .apic_id_mask = APIC_ID_MASK, \ APICFUNC(cpu_mask_to_apicid) \ - APICFUNC(vector_allocation_domain) \ + APICFUNC(vector_allocation_domain) \ APICFUNC(acpi_madt_oem_check) \ IPIFUNC(send_IPI_mask) \ IPIFUNC(send_IPI_allbutself) \ IPIFUNC(send_IPI_all) \ APICFUNC(enable_apic_mode) \ APICFUNC(phys_pkg_id) \ + .trampoline_phys_low = TRAMPOLINE_PHYS_LOW, \ + .trampoline_phys_high = TRAMPOLINE_PHYS_HIGH, \ + APICFUNC(wait_for_init_deassert) \ + APICFUNC(smp_callin_clear_local_apic) \ + APICFUNC(store_NMI_vector) \ + APICFUNC(restore_NMI_vector) \ + APICFUNC(inquire_remote_apic) \ } extern struct genapic *genapic; +extern void es7000_update_genapic_to_cluster(void); enum uv_system_type {UV_NONE, UV_LEGACY_APIC, UV_X2APIC, UV_NON_UNIQUE_APIC}; #define get_uv_system_type() UV_NONE diff --git a/arch/x86/include/asm/genapic_64.h b/arch/x86/include/asm/genapic_64.h index 13c4e96199ea17d1e52430dac24a85f4291f50d7..2cae011668b7e09a1397e09b7fc9241f63b48d1d 100644 --- a/arch/x86/include/asm/genapic_64.h +++ b/arch/x86/include/asm/genapic_64.h @@ -32,6 +32,8 @@ struct genapic { unsigned int (*get_apic_id)(unsigned long x); unsigned long (*set_apic_id)(unsigned int id); unsigned long apic_id_mask; + /* wakeup_secondary_cpu */ + int (*wakeup_cpu)(int apicid, unsigned long start_eip); }; extern struct genapic *genapic; diff --git a/arch/x86/include/asm/hardirq_32.h b/arch/x86/include/asm/hardirq_32.h index 5ca135e72f2b0952889c395eee74d865e7fbed26..cf7954d1405fe646c6835072c6a1bf924656ac85 100644 --- a/arch/x86/include/asm/hardirq_32.h +++ b/arch/x86/include/asm/hardirq_32.h @@ -22,6 +22,8 @@ DECLARE_PER_CPU(irq_cpustat_t, irq_stat); #define __ARCH_IRQ_STAT #define __IRQ_STAT(cpu, member) (per_cpu(irq_stat, cpu).member) +#define inc_irq_stat(member) (__get_cpu_var(irq_stat).member++) + void ack_bad_irq(unsigned int irq); #include diff --git a/arch/x86/include/asm/hardirq_64.h b/arch/x86/include/asm/hardirq_64.h index 1ba381fc51d38eca1012239b6949dedd59ad9f0d..b5a6b5d56704c89330d2f88f515c5d25281e105f 100644 --- a/arch/x86/include/asm/hardirq_64.h +++ b/arch/x86/include/asm/hardirq_64.h @@ -11,6 +11,8 @@ #define __ARCH_IRQ_STAT 1 +#define inc_irq_stat(member) add_pda(member, 1) + #define local_softirq_pending() read_pda(__softirq_pending) #define __ARCH_SET_SOFTIRQ_PENDING 1 diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h index b97aecb0b61d004de95bd769deb7bbd2d59e0774..8de644b6b95992deb500f0e2325c77db87e105aa 100644 --- a/arch/x86/include/asm/hw_irq.h +++ b/arch/x86/include/asm/hw_irq.h @@ -109,9 +109,7 @@ extern asmlinkage void smp_invalidate_interrupt(struct pt_regs *); #endif #endif -#ifdef CONFIG_X86_32 -extern void (*const interrupt[NR_VECTORS])(void); -#endif +extern void (*__initconst interrupt[NR_VECTORS-FIRST_EXTERNAL_VECTOR])(void); typedef int vector_irq_t[NR_VECTORS]; DECLARE_PER_CPU(vector_irq_t, vector_irq); diff --git a/arch/x86/include/asm/hypervisor.h b/arch/x86/include/asm/hypervisor.h new file mode 100644 index 0000000000000000000000000000000000000000..369f5c5d09a176a38093c51c16abc5a602d740a8 --- /dev/null +++ b/arch/x86/include/asm/hypervisor.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2008, VMware, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +#ifndef ASM_X86__HYPERVISOR_H +#define ASM_X86__HYPERVISOR_H + +extern unsigned long get_hypervisor_tsc_freq(void); +extern void init_hypervisor(struct cpuinfo_x86 *c); + +#endif diff --git a/arch/x86/include/asm/ia32.h b/arch/x86/include/asm/ia32.h index 97989c0e534c7a8af039805dc5a04ad11ed021a5..50ca486fd88c9468fe52b4a9fb357f192fbd6ab0 100644 --- a/arch/x86/include/asm/ia32.h +++ b/arch/x86/include/asm/ia32.h @@ -129,24 +129,6 @@ typedef struct compat_siginfo { } _sifields; } compat_siginfo_t; -struct sigframe32 { - u32 pretcode; - int sig; - struct sigcontext_ia32 sc; - struct _fpstate_ia32 fpstate; - unsigned int extramask[_COMPAT_NSIG_WORDS-1]; -}; - -struct rt_sigframe32 { - u32 pretcode; - int sig; - u32 pinfo; - u32 puc; - compat_siginfo_t info; - struct ucontext_ia32 uc; - struct _fpstate_ia32 fpstate; -}; - struct ustat32 { __u32 f_tfree; compat_ino_t f_tinode; diff --git a/arch/x86/include/asm/idle.h b/arch/x86/include/asm/idle.h index 44c89c3a23e9a1f9507536b4d84f0f6b3d225c61..38d87379e270596635ff569242c54ff71ad3ce69 100644 --- a/arch/x86/include/asm/idle.h +++ b/arch/x86/include/asm/idle.h @@ -8,8 +8,13 @@ struct notifier_block; void idle_notifier_register(struct notifier_block *n); void idle_notifier_unregister(struct notifier_block *n); +#ifdef CONFIG_X86_64 void enter_idle(void); void exit_idle(void); +#else /* !CONFIG_X86_64 */ +static inline void enter_idle(void) { } +static inline void exit_idle(void) { } +#endif /* CONFIG_X86_64 */ void c1e_remove_cpu(int cpu); diff --git a/arch/x86/include/asm/io.h b/arch/x86/include/asm/io.h index ac2abc88cd95fa3e9049acc0440d65d59cd47ac1..05cfed4485fae802dc9be64f0a0feb9cf3214150 100644 --- a/arch/x86/include/asm/io.h +++ b/arch/x86/include/asm/io.h @@ -4,6 +4,7 @@ #define ARCH_HAS_IOREMAP_WC #include +#include #define build_mmio_read(name, size, type, reg, barrier) \ static inline type name(const volatile void __iomem *addr) \ @@ -45,21 +46,39 @@ build_mmio_write(__writel, "l", unsigned int, "r", ) #define mmiowb() barrier() #ifdef CONFIG_X86_64 + build_mmio_read(readq, "q", unsigned long, "=r", :"memory") -build_mmio_read(__readq, "q", unsigned long, "=r", ) build_mmio_write(writeq, "q", unsigned long, "r", :"memory") -build_mmio_write(__writeq, "q", unsigned long, "r", ) -#define readq_relaxed(a) __readq(a) -#define __raw_readq __readq -#define __raw_writeq writeq +#else + +static inline __u64 readq(const volatile void __iomem *addr) +{ + const volatile u32 __iomem *p = addr; + u32 low, high; + + low = readl(p); + high = readl(p + 1); + + return low + ((u64)high << 32); +} + +static inline void writeq(__u64 val, volatile void __iomem *addr) +{ + writel(val, addr); + writel(val >> 32, addr+4); +} -/* Let people know we have them */ -#define readq readq -#define writeq writeq #endif -extern int iommu_bio_merge; +#define readq_relaxed(a) readq(a) + +#define __raw_readq(a) readq(a) +#define __raw_writeq(val, addr) writeq(val, addr) + +/* Let people know that we have them */ +#define readq readq +#define writeq writeq #ifdef CONFIG_X86_32 # include "io_32.h" diff --git a/arch/x86/include/asm/io_64.h b/arch/x86/include/asm/io_64.h index fea325a1122f4abf66d340113a9a82787a75832f..563c16270ba6d3fee1bda648f873109b7c1d2b3f 100644 --- a/arch/x86/include/asm/io_64.h +++ b/arch/x86/include/asm/io_64.h @@ -232,8 +232,6 @@ void memset_io(volatile void __iomem *a, int b, size_t c); #define flush_write_buffers() -#define BIO_VMERGE_BOUNDARY iommu_bio_merge - /* * Convert a virtual cached pointer to an uncached pointer */ diff --git a/arch/x86/include/asm/io_apic.h b/arch/x86/include/asm/io_apic.h index 6afd9933a7dd96d96822a8ecb058cc2528ed09ac..e475e009ae5d4e60dc0e828ad96373ef91f2799a 100644 --- a/arch/x86/include/asm/io_apic.h +++ b/arch/x86/include/asm/io_apic.h @@ -156,11 +156,21 @@ extern int sis_apic_bug; /* 1 if "noapic" boot option passed */ extern int skip_ioapic_setup; +/* 1 if "noapic" boot option passed */ +extern int noioapicquirk; + +/* -1 if "noapic" boot option passed */ +extern int noioapicreroute; + /* 1 if the timer IRQ uses the '8259A Virtual Wire' mode */ extern int timer_through_8259; static inline void disable_ioapic_setup(void) { +#ifdef CONFIG_PCI + noioapicquirk = 1; + noioapicreroute = -1; +#endif skip_ioapic_setup = 1; } diff --git a/arch/x86/include/asm/iommu.h b/arch/x86/include/asm/iommu.h index 0b500c5b6446e6690846fe9d13a0a5483bef2f20..295b13193f4df09b05aad53ec09c81c601a17a9f 100644 --- a/arch/x86/include/asm/iommu.h +++ b/arch/x86/include/asm/iommu.h @@ -12,37 +12,4 @@ extern unsigned long iommu_nr_pages(unsigned long addr, unsigned long len); /* 10 seconds */ #define DMAR_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000) -#ifdef CONFIG_GART_IOMMU -extern int gart_iommu_aperture; -extern int gart_iommu_aperture_allowed; -extern int gart_iommu_aperture_disabled; - -extern void early_gart_iommu_check(void); -extern void gart_iommu_init(void); -extern void gart_iommu_shutdown(void); -extern void __init gart_parse_options(char *); -extern void gart_iommu_hole_init(void); - -#else -#define gart_iommu_aperture 0 -#define gart_iommu_aperture_allowed 0 -#define gart_iommu_aperture_disabled 1 - -static inline void early_gart_iommu_check(void) -{ -} -static inline void gart_iommu_init(void) -{ -} -static inline void gart_iommu_shutdown(void) -{ -} -static inline void gart_parse_options(char *options) -{ -} -static inline void gart_iommu_hole_init(void) -{ -} -#endif - #endif /* _ASM_X86_IOMMU_H */ diff --git a/arch/x86/include/asm/irq.h b/arch/x86/include/asm/irq.h index bae0eda954864aa62e90b6ec438b82c8785129dc..28e409fc73f3df33e4c6b2cbde5e99e0433e0fa1 100644 --- a/arch/x86/include/asm/irq.h +++ b/arch/x86/include/asm/irq.h @@ -31,10 +31,6 @@ static inline int irq_canonicalize(int irq) # endif #endif -#ifdef CONFIG_IRQBALANCE -extern int irqbalance_disable(char *str); -#endif - #ifdef CONFIG_HOTPLUG_CPU #include extern void fixup_irqs(cpumask_t map); diff --git a/arch/x86/include/asm/irq_regs_32.h b/arch/x86/include/asm/irq_regs_32.h index af2f02d27fc7a51a8e0a5c8d4470b0f9bd90330e..86afd7473457e4cff97b120cfcde5516125a1366 100644 --- a/arch/x86/include/asm/irq_regs_32.h +++ b/arch/x86/include/asm/irq_regs_32.h @@ -9,6 +9,8 @@ #include +#define ARCH_HAS_OWN_IRQ_REGS + DECLARE_PER_CPU(struct pt_regs *, irq_regs); static inline struct pt_regs *get_irq_regs(void) diff --git a/arch/x86/include/asm/kexec.h b/arch/x86/include/asm/kexec.h index a1f22771a15a2d07a88d9e071b17ebb6860631ef..c61d8b2ab8b9d8ac00e8c514ee26028fe601eb86 100644 --- a/arch/x86/include/asm/kexec.h +++ b/arch/x86/include/asm/kexec.h @@ -5,21 +5,8 @@ # define PA_CONTROL_PAGE 0 # define VA_CONTROL_PAGE 1 # define PA_PGD 2 -# define VA_PGD 3 -# define PA_PTE_0 4 -# define VA_PTE_0 5 -# define PA_PTE_1 6 -# define VA_PTE_1 7 -# define PA_SWAP_PAGE 8 -# ifdef CONFIG_X86_PAE -# define PA_PMD_0 9 -# define VA_PMD_0 10 -# define PA_PMD_1 11 -# define VA_PMD_1 12 -# define PAGES_NR 13 -# else -# define PAGES_NR 9 -# endif +# define PA_SWAP_PAGE 3 +# define PAGES_NR 4 #else # define PA_CONTROL_PAGE 0 # define VA_CONTROL_PAGE 1 @@ -170,6 +157,20 @@ relocate_kernel(unsigned long indirection_page, unsigned long start_address) ATTRIB_NORET; #endif +#ifdef CONFIG_X86_32 +#define ARCH_HAS_KIMAGE_ARCH + +struct kimage_arch { + pgd_t *pgd; +#ifdef CONFIG_X86_PAE + pmd_t *pmd0; + pmd_t *pmd1; +#endif + pte_t *pte0; + pte_t *pte1; +}; +#endif + #endif /* __ASSEMBLY__ */ #endif /* _ASM_X86_KEXEC_H */ diff --git a/arch/x86/include/asm/linkage.h b/arch/x86/include/asm/linkage.h index f61ee8f937e4b3220e58f2851c749718fd1a4e16..5d98d0b68ffc8e08e07cf829ed15103f6fc09796 100644 --- a/arch/x86/include/asm/linkage.h +++ b/arch/x86/include/asm/linkage.h @@ -57,5 +57,65 @@ #define __ALIGN_STR ".align 16,0x90" #endif +/* + * to check ENTRY_X86/END_X86 and + * KPROBE_ENTRY_X86/KPROBE_END_X86 + * unbalanced-missed-mixed appearance + */ +#define __set_entry_x86 .set ENTRY_X86_IN, 0 +#define __unset_entry_x86 .set ENTRY_X86_IN, 1 +#define __set_kprobe_x86 .set KPROBE_X86_IN, 0 +#define __unset_kprobe_x86 .set KPROBE_X86_IN, 1 + +#define __macro_err_x86 .error "ENTRY_X86/KPROBE_X86 unbalanced,missed,mixed" + +#define __check_entry_x86 \ + .ifdef ENTRY_X86_IN; \ + .ifeq ENTRY_X86_IN; \ + __macro_err_x86; \ + .abort; \ + .endif; \ + .endif + +#define __check_kprobe_x86 \ + .ifdef KPROBE_X86_IN; \ + .ifeq KPROBE_X86_IN; \ + __macro_err_x86; \ + .abort; \ + .endif; \ + .endif + +#define __check_entry_kprobe_x86 \ + __check_entry_x86; \ + __check_kprobe_x86 + +#define ENTRY_KPROBE_FINAL_X86 __check_entry_kprobe_x86 + +#define ENTRY_X86(name) \ + __check_entry_kprobe_x86; \ + __set_entry_x86; \ + .globl name; \ + __ALIGN; \ + name: + +#define END_X86(name) \ + __unset_entry_x86; \ + __check_entry_kprobe_x86; \ + .size name, .-name + +#define KPROBE_ENTRY_X86(name) \ + __check_entry_kprobe_x86; \ + __set_kprobe_x86; \ + .pushsection .kprobes.text, "ax"; \ + .globl name; \ + __ALIGN; \ + name: + +#define KPROBE_END_X86(name) \ + __unset_kprobe_x86; \ + __check_entry_kprobe_x86; \ + .size name, .-name; \ + .popsection + #endif /* _ASM_X86_LINKAGE_H */ diff --git a/arch/x86/include/asm/mach-default/mach_apic.h b/arch/x86/include/asm/mach-default/mach_apic.h index ff3a6c236c00c940d3cbc94d0895399fd25828f8..6cb3a467e0673c031c6e39b675481466a0c7531a 100644 --- a/arch/x86/include/asm/mach-default/mach_apic.h +++ b/arch/x86/include/asm/mach-default/mach_apic.h @@ -32,11 +32,13 @@ static inline cpumask_t target_cpus(void) #define vector_allocation_domain (genapic->vector_allocation_domain) #define read_apic_id() (GET_APIC_ID(apic_read(APIC_ID))) #define send_IPI_self (genapic->send_IPI_self) +#define wakeup_secondary_cpu (genapic->wakeup_cpu) extern void setup_apic_routing(void); #else #define INT_DELIVERY_MODE dest_LowestPrio #define INT_DEST_MODE 1 /* logical delivery broadcast to all procs */ #define TARGET_CPUS (target_cpus()) +#define wakeup_secondary_cpu wakeup_secondary_cpu_via_init /* * Set up the logical destination ID. * diff --git a/arch/x86/include/asm/mach-default/mach_wakecpu.h b/arch/x86/include/asm/mach-default/mach_wakecpu.h index 9d80db91e9926f040445ebffeb44cac66ce8f4d3..ceb01366014629ba1c8220dff2a95bb313a2bf30 100644 --- a/arch/x86/include/asm/mach-default/mach_wakecpu.h +++ b/arch/x86/include/asm/mach-default/mach_wakecpu.h @@ -1,17 +1,8 @@ #ifndef _ASM_X86_MACH_DEFAULT_MACH_WAKECPU_H #define _ASM_X86_MACH_DEFAULT_MACH_WAKECPU_H -/* - * This file copes with machines that wakeup secondary CPUs by the - * INIT, INIT, STARTUP sequence. - */ - -#define WAKE_SECONDARY_VIA_INIT - -#define TRAMPOLINE_LOW phys_to_virt(0x467) -#define TRAMPOLINE_HIGH phys_to_virt(0x469) - -#define boot_cpu_apicid boot_cpu_physical_apicid +#define TRAMPOLINE_PHYS_LOW (0x467) +#define TRAMPOLINE_PHYS_HIGH (0x469) static inline void wait_for_init_deassert(atomic_t *deassert) { @@ -33,9 +24,12 @@ static inline void restore_NMI_vector(unsigned short *high, unsigned short *low) { } -#define inquire_remote_apic(apicid) do { \ - if (apic_verbosity >= APIC_DEBUG) \ - __inquire_remote_apic(apicid); \ - } while (0) +extern void __inquire_remote_apic(int apicid); + +static inline void inquire_remote_apic(int apicid) +{ + if (apic_verbosity >= APIC_DEBUG) + __inquire_remote_apic(apicid); +} #endif /* _ASM_X86_MACH_DEFAULT_MACH_WAKECPU_H */ diff --git a/arch/x86/include/asm/mach-default/smpboot_hooks.h b/arch/x86/include/asm/mach-default/smpboot_hooks.h index dbab36d64d48f2b15aa6be7dea09e9feb91f869f..23bf52103b8905e662e3b9e5491b89d5b8c8c933 100644 --- a/arch/x86/include/asm/mach-default/smpboot_hooks.h +++ b/arch/x86/include/asm/mach-default/smpboot_hooks.h @@ -13,9 +13,11 @@ static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip) CMOS_WRITE(0xa, 0xf); local_flush_tlb(); pr_debug("1.\n"); - *((volatile unsigned short *) TRAMPOLINE_HIGH) = start_eip >> 4; + *((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_HIGH)) = + start_eip >> 4; pr_debug("2.\n"); - *((volatile unsigned short *) TRAMPOLINE_LOW) = start_eip & 0xf; + *((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_LOW)) = + start_eip & 0xf; pr_debug("3.\n"); } @@ -32,7 +34,7 @@ static inline void smpboot_restore_warm_reset_vector(void) */ CMOS_WRITE(0, 0xf); - *((volatile long *) phys_to_virt(0x467)) = 0; + *((volatile long *)phys_to_virt(TRAMPOLINE_PHYS_LOW)) = 0; } static inline void __init smpboot_setup_io_apic(void) diff --git a/arch/x86/include/asm/mach-generic/mach_apic.h b/arch/x86/include/asm/mach-generic/mach_apic.h index 5180bd7478fbc3d2cfc533f22e707a8099201e23..e430f47df667255e26bab25ecb123702426b6e63 100644 --- a/arch/x86/include/asm/mach-generic/mach_apic.h +++ b/arch/x86/include/asm/mach-generic/mach_apic.h @@ -27,6 +27,7 @@ #define vector_allocation_domain (genapic->vector_allocation_domain) #define enable_apic_mode (genapic->enable_apic_mode) #define phys_pkg_id (genapic->phys_pkg_id) +#define wakeup_secondary_cpu (genapic->wakeup_cpu) extern void generic_bigsmp_probe(void); diff --git a/arch/x86/include/asm/mach-generic/mach_wakecpu.h b/arch/x86/include/asm/mach-generic/mach_wakecpu.h new file mode 100644 index 0000000000000000000000000000000000000000..1ab16b168c8a80ca2e9ff69c9b309898e5868c55 --- /dev/null +++ b/arch/x86/include/asm/mach-generic/mach_wakecpu.h @@ -0,0 +1,12 @@ +#ifndef _ASM_X86_MACH_GENERIC_MACH_WAKECPU_H +#define _ASM_X86_MACH_GENERIC_MACH_WAKECPU_H + +#define TRAMPOLINE_PHYS_LOW (genapic->trampoline_phys_low) +#define TRAMPOLINE_PHYS_HIGH (genapic->trampoline_phys_high) +#define wait_for_init_deassert (genapic->wait_for_init_deassert) +#define smp_callin_clear_local_apic (genapic->smp_callin_clear_local_apic) +#define store_NMI_vector (genapic->store_NMI_vector) +#define restore_NMI_vector (genapic->restore_NMI_vector) +#define inquire_remote_apic (genapic->inquire_remote_apic) + +#endif /* _ASM_X86_MACH_GENERIC_MACH_APIC_H */ diff --git a/arch/x86/include/asm/mmu_context_32.h b/arch/x86/include/asm/mmu_context_32.h index 8e10015781fb2d6794aa0cfabae334956b365c88..7e98ce1d2c0e5ad8b2aca1c1e5d733cd839d9cc8 100644 --- a/arch/x86/include/asm/mmu_context_32.h +++ b/arch/x86/include/asm/mmu_context_32.h @@ -4,9 +4,8 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) { #ifdef CONFIG_SMP - unsigned cpu = smp_processor_id(); - if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK) - per_cpu(cpu_tlbstate, cpu).state = TLBSTATE_LAZY; + if (x86_read_percpu(cpu_tlbstate.state) == TLBSTATE_OK) + x86_write_percpu(cpu_tlbstate.state, TLBSTATE_LAZY); #endif } @@ -20,8 +19,8 @@ static inline void switch_mm(struct mm_struct *prev, /* stop flush ipis for the previous mm */ cpu_clear(cpu, prev->cpu_vm_mask); #ifdef CONFIG_SMP - per_cpu(cpu_tlbstate, cpu).state = TLBSTATE_OK; - per_cpu(cpu_tlbstate, cpu).active_mm = next; + x86_write_percpu(cpu_tlbstate.state, TLBSTATE_OK); + x86_write_percpu(cpu_tlbstate.active_mm, next); #endif cpu_set(cpu, next->cpu_vm_mask); @@ -36,8 +35,8 @@ static inline void switch_mm(struct mm_struct *prev, } #ifdef CONFIG_SMP else { - per_cpu(cpu_tlbstate, cpu).state = TLBSTATE_OK; - BUG_ON(per_cpu(cpu_tlbstate, cpu).active_mm != next); + x86_write_percpu(cpu_tlbstate.state, TLBSTATE_OK); + BUG_ON(x86_read_percpu(cpu_tlbstate.active_mm) != next); if (!cpu_test_and_set(cpu, next->cpu_vm_mask)) { /* We were in lazy tlb mode and leave_mm disabled diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index e38859d577a117e1cc1ae2cf75e278c595cfb369..cb58643947b963dcc276cbf81ab1cf92b6dd149a 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -85,7 +85,9 @@ /* AMD64 MSRs. Not complete. See the architecture manual for a more complete list. */ +#define MSR_AMD64_PATCH_LEVEL 0x0000008b #define MSR_AMD64_NB_CFG 0xc001001f +#define MSR_AMD64_PATCH_LOADER 0xc0010020 #define MSR_AMD64_IBSFETCHCTL 0xc0011030 #define MSR_AMD64_IBSFETCHLINAD 0xc0011031 #define MSR_AMD64_IBSFETCHPHYSAD 0xc0011032 diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h index c2a812ebde890e590794ea1e2d8a39d5cec49e9f..638bf6241807a9ab9c36def7541c690ccb230e07 100644 --- a/arch/x86/include/asm/msr.h +++ b/arch/x86/include/asm/msr.h @@ -22,10 +22,10 @@ static inline unsigned long long native_read_tscp(unsigned int *aux) } /* - * i386 calling convention returns 64-bit value in edx:eax, while - * x86_64 returns at rax. Also, the "A" constraint does not really - * mean rdx:rax in x86_64, so we need specialized behaviour for each - * architecture + * both i386 and x86_64 returns 64-bit value in edx:eax, but gcc's "A" + * constraint has different meanings. For i386, "A" means exactly + * edx:eax, while for x86_64 it doesn't mean rdx:rax or edx:eax. Instead, + * it means rax *or* rdx. */ #ifdef CONFIG_X86_64 #define DECLARE_ARGS(val, low, high) unsigned low, high @@ -85,7 +85,8 @@ static inline void native_write_msr(unsigned int msr, asm volatile("wrmsr" : : "c" (msr), "a"(low), "d" (high) : "memory"); } -static inline int native_write_msr_safe(unsigned int msr, +/* Can be uninlined because referenced by paravirt */ +notrace static inline int native_write_msr_safe(unsigned int msr, unsigned low, unsigned high) { int err; @@ -181,10 +182,10 @@ static inline int rdmsrl_amd_safe(unsigned msr, unsigned long long *p) } #define rdtscl(low) \ - ((low) = (u32)native_read_tsc()) + ((low) = (u32)__native_read_tsc()) #define rdtscll(val) \ - ((val) = native_read_tsc()) + ((val) = __native_read_tsc()) #define rdpmc(counter, low, high) \ do { \ diff --git a/arch/x86/include/asm/numaq/wakecpu.h b/arch/x86/include/asm/numaq/wakecpu.h index c577bda5b1c52c768047d1e664e0040356b57176..6f499df8eddbfd4246132bd570b87bfde68b4e00 100644 --- a/arch/x86/include/asm/numaq/wakecpu.h +++ b/arch/x86/include/asm/numaq/wakecpu.h @@ -3,12 +3,8 @@ /* This file copes with machines that wakeup secondary CPUs by NMIs */ -#define WAKE_SECONDARY_VIA_NMI - -#define TRAMPOLINE_LOW phys_to_virt(0x8) -#define TRAMPOLINE_HIGH phys_to_virt(0xa) - -#define boot_cpu_apicid boot_cpu_logical_apicid +#define TRAMPOLINE_PHYS_LOW (0x8) +#define TRAMPOLINE_PHYS_HIGH (0xa) /* We don't do anything here because we use NMI's to boot instead */ static inline void wait_for_init_deassert(atomic_t *deassert) @@ -27,17 +23,23 @@ static inline void smp_callin_clear_local_apic(void) static inline void store_NMI_vector(unsigned short *high, unsigned short *low) { printk("Storing NMI vector\n"); - *high = *((volatile unsigned short *) TRAMPOLINE_HIGH); - *low = *((volatile unsigned short *) TRAMPOLINE_LOW); + *high = + *((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_HIGH)); + *low = + *((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_LOW)); } static inline void restore_NMI_vector(unsigned short *high, unsigned short *low) { printk("Restoring NMI vector\n"); - *((volatile unsigned short *) TRAMPOLINE_HIGH) = *high; - *((volatile unsigned short *) TRAMPOLINE_LOW) = *low; + *((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_HIGH)) = + *high; + *((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_LOW)) = + *low; } -#define inquire_remote_apic(apicid) {} +static inline void inquire_remote_apic(int apicid) +{ +} #endif /* __ASM_NUMAQ_WAKECPU_H */ diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h index 875b38edf19383f0e1176b9a73dede0f49f42c38..647781298e7ef7cbc98b14ad75f2552b0092507f 100644 --- a/arch/x86/include/asm/pci.h +++ b/arch/x86/include/asm/pci.h @@ -19,6 +19,8 @@ struct pci_sysdata { }; extern int pci_routeirq; +extern int noioapicquirk; +extern int noioapicreroute; /* scan a bus after allocating a pci_sysdata for it */ extern struct pci_bus *pci_scan_bus_on_node(int busno, struct pci_ops *ops, diff --git a/arch/x86/include/asm/pgtable-2level.h b/arch/x86/include/asm/pgtable-2level.h index b17edfd23628953139fa58778fa7ae2d66222222..e0d199fe1d83896578421d79aac509ebd843fdf3 100644 --- a/arch/x86/include/asm/pgtable-2level.h +++ b/arch/x86/include/asm/pgtable-2level.h @@ -56,23 +56,55 @@ static inline pte_t native_ptep_get_and_clear(pte_t *xp) #define pte_none(x) (!(x).pte_low) /* - * Bits 0, 6 and 7 are taken, split up the 29 bits of offset - * into this range: + * Bits _PAGE_BIT_PRESENT, _PAGE_BIT_FILE and _PAGE_BIT_PROTNONE are taken, + * split up the 29 bits of offset into this range: */ #define PTE_FILE_MAX_BITS 29 +#define PTE_FILE_SHIFT1 (_PAGE_BIT_PRESENT + 1) +#if _PAGE_BIT_FILE < _PAGE_BIT_PROTNONE +#define PTE_FILE_SHIFT2 (_PAGE_BIT_FILE + 1) +#define PTE_FILE_SHIFT3 (_PAGE_BIT_PROTNONE + 1) +#else +#define PTE_FILE_SHIFT2 (_PAGE_BIT_PROTNONE + 1) +#define PTE_FILE_SHIFT3 (_PAGE_BIT_FILE + 1) +#endif +#define PTE_FILE_BITS1 (PTE_FILE_SHIFT2 - PTE_FILE_SHIFT1 - 1) +#define PTE_FILE_BITS2 (PTE_FILE_SHIFT3 - PTE_FILE_SHIFT2 - 1) #define pte_to_pgoff(pte) \ - ((((pte).pte_low >> 1) & 0x1f) + (((pte).pte_low >> 8) << 5)) + ((((pte).pte_low >> PTE_FILE_SHIFT1) \ + & ((1U << PTE_FILE_BITS1) - 1)) \ + + ((((pte).pte_low >> PTE_FILE_SHIFT2) \ + & ((1U << PTE_FILE_BITS2) - 1)) << PTE_FILE_BITS1) \ + + (((pte).pte_low >> PTE_FILE_SHIFT3) \ + << (PTE_FILE_BITS1 + PTE_FILE_BITS2))) #define pgoff_to_pte(off) \ - ((pte_t) { .pte_low = (((off) & 0x1f) << 1) + \ - (((off) >> 5) << 8) + _PAGE_FILE }) + ((pte_t) { .pte_low = \ + (((off) & ((1U << PTE_FILE_BITS1) - 1)) << PTE_FILE_SHIFT1) \ + + ((((off) >> PTE_FILE_BITS1) & ((1U << PTE_FILE_BITS2) - 1)) \ + << PTE_FILE_SHIFT2) \ + + (((off) >> (PTE_FILE_BITS1 + PTE_FILE_BITS2)) \ + << PTE_FILE_SHIFT3) \ + + _PAGE_FILE }) /* Encode and de-code a swap entry */ -#define __swp_type(x) (((x).val >> 1) & 0x1f) -#define __swp_offset(x) ((x).val >> 8) -#define __swp_entry(type, offset) \ - ((swp_entry_t) { ((type) << 1) | ((offset) << 8) }) +#if _PAGE_BIT_FILE < _PAGE_BIT_PROTNONE +#define SWP_TYPE_BITS (_PAGE_BIT_FILE - _PAGE_BIT_PRESENT - 1) +#define SWP_OFFSET_SHIFT (_PAGE_BIT_PROTNONE + 1) +#else +#define SWP_TYPE_BITS (_PAGE_BIT_PROTNONE - _PAGE_BIT_PRESENT - 1) +#define SWP_OFFSET_SHIFT (_PAGE_BIT_FILE + 1) +#endif + +#define MAX_SWAPFILES_CHECK() BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > SWP_TYPE_BITS) + +#define __swp_type(x) (((x).val >> (_PAGE_BIT_PRESENT + 1)) \ + & ((1U << SWP_TYPE_BITS) - 1)) +#define __swp_offset(x) ((x).val >> SWP_OFFSET_SHIFT) +#define __swp_entry(type, offset) ((swp_entry_t) { \ + ((type) << (_PAGE_BIT_PRESENT + 1)) \ + | ((offset) << SWP_OFFSET_SHIFT) }) #define __pte_to_swp_entry(pte) ((swp_entry_t) { (pte).pte_low }) #define __swp_entry_to_pte(x) ((pte_t) { .pte = (x).val }) diff --git a/arch/x86/include/asm/pgtable-3level.h b/arch/x86/include/asm/pgtable-3level.h index 52597aeadfff029e0b45aa57ee5030a15e774289..447da43cddb360a6f92a2ce98896599359546e6d 100644 --- a/arch/x86/include/asm/pgtable-3level.h +++ b/arch/x86/include/asm/pgtable-3level.h @@ -166,6 +166,7 @@ static inline int pte_none(pte_t pte) #define PTE_FILE_MAX_BITS 32 /* Encode and de-code a swap entry */ +#define MAX_SWAPFILES_CHECK() BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > 5) #define __swp_type(x) (((x).val) & 0x1f) #define __swp_offset(x) ((x).val >> 5) #define __swp_entry(type, offset) ((swp_entry_t){(type) | (offset) << 5}) diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h index c012f3b11671574150720dcaee023780cd79d905..83e69f4a37f03bafb39869169d6286210c7c95df 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h @@ -10,7 +10,6 @@ #define _PAGE_BIT_PCD 4 /* page cache disabled */ #define _PAGE_BIT_ACCESSED 5 /* was accessed (raised by CPU) */ #define _PAGE_BIT_DIRTY 6 /* was written to (raised by CPU) */ -#define _PAGE_BIT_FILE 6 #define _PAGE_BIT_PSE 7 /* 4 MB (or 2MB) page */ #define _PAGE_BIT_PAT 7 /* on 4KB pages */ #define _PAGE_BIT_GLOBAL 8 /* Global TLB entry PPro+ */ @@ -22,6 +21,12 @@ #define _PAGE_BIT_CPA_TEST _PAGE_BIT_UNUSED1 #define _PAGE_BIT_NX 63 /* No execute: only valid after cpuid check */ +/* If _PAGE_BIT_PRESENT is clear, we use these: */ +/* - if the user mapped it with PROT_NONE; pte_present gives true */ +#define _PAGE_BIT_PROTNONE _PAGE_BIT_GLOBAL +/* - set: nonlinear file mapping, saved PTE; unset:swap */ +#define _PAGE_BIT_FILE _PAGE_BIT_DIRTY + #define _PAGE_PRESENT (_AT(pteval_t, 1) << _PAGE_BIT_PRESENT) #define _PAGE_RW (_AT(pteval_t, 1) << _PAGE_BIT_RW) #define _PAGE_USER (_AT(pteval_t, 1) << _PAGE_BIT_USER) @@ -46,11 +51,8 @@ #define _PAGE_NX (_AT(pteval_t, 0)) #endif -/* If _PAGE_PRESENT is clear, we use these: */ -#define _PAGE_FILE _PAGE_DIRTY /* nonlinear file mapping, - * saved PTE; unset:swap */ -#define _PAGE_PROTNONE _PAGE_PSE /* if the user mapped it with PROT_NONE; - pte_present gives true */ +#define _PAGE_FILE (_AT(pteval_t, 1) << _PAGE_BIT_FILE) +#define _PAGE_PROTNONE (_AT(pteval_t, 1) << _PAGE_BIT_PROTNONE) #define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | \ _PAGE_ACCESSED | _PAGE_DIRTY) @@ -158,8 +160,19 @@ #define PGD_IDENT_ATTR 0x001 /* PRESENT (no other attributes) */ #endif +/* + * Macro to mark a page protection value as UC- + */ +#define pgprot_noncached(prot) \ + ((boot_cpu_data.x86 > 3) \ + ? (__pgprot(pgprot_val(prot) | _PAGE_CACHE_UC_MINUS)) \ + : (prot)) + #ifndef __ASSEMBLY__ +#define pgprot_writecombine pgprot_writecombine +extern pgprot_t pgprot_writecombine(pgprot_t prot); + /* * ZERO_PAGE is a global shared page that is always zero: used * for zero-mapped memory areas etc.. @@ -329,6 +342,9 @@ static inline pgprot_t pgprot_modify(pgprot_t oldprot, pgprot_t newprot) #define canon_pgprot(p) __pgprot(pgprot_val(p) & __supported_pte_mask) #ifndef __ASSEMBLY__ +/* Indicate that x86 has its own track and untrack pfn vma functions */ +#define __HAVE_PFNMAP_TRACKING + #define __HAVE_PHYS_MEM_ACCESS_PROT struct file; pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, diff --git a/arch/x86/include/asm/pgtable_32.h b/arch/x86/include/asm/pgtable_32.h index f9d5889b336be5eb5d9f575d22ac512be7d63f7e..72b020deb46b9352a5365410b2011e55b4c56021 100644 --- a/arch/x86/include/asm/pgtable_32.h +++ b/arch/x86/include/asm/pgtable_32.h @@ -100,15 +100,6 @@ extern unsigned long pg0[]; # include #endif -/* - * Macro to mark a page protection value as "uncacheable". - * On processors which do not support it, this is a no-op. - */ -#define pgprot_noncached(prot) \ - ((boot_cpu_data.x86 > 3) \ - ? (__pgprot(pgprot_val(prot) | _PAGE_PCD | _PAGE_PWT)) \ - : (prot)) - /* * Conversion functions: convert a page and protection to a page entry, * and a page entry and page directory to the page they refer to. diff --git a/arch/x86/include/asm/pgtable_64.h b/arch/x86/include/asm/pgtable_64.h index 545a0e042bb2d44268d7a240e97b2c14309568b9..ba09289accaa0322c70fb580a40f83677a900c9f 100644 --- a/arch/x86/include/asm/pgtable_64.h +++ b/arch/x86/include/asm/pgtable_64.h @@ -146,7 +146,7 @@ static inline void native_pgd_clear(pgd_t *pgd) #define PGDIR_MASK (~(PGDIR_SIZE - 1)) -#define MAXMEM _AC(0x00003fffffffffff, UL) +#define MAXMEM _AC(__AC(1, UL) << MAX_PHYSMEM_BITS, UL) #define VMALLOC_START _AC(0xffffc20000000000, UL) #define VMALLOC_END _AC(0xffffe1ffffffffff, UL) #define VMEMMAP_START _AC(0xffffe20000000000, UL) @@ -176,12 +176,6 @@ static inline int pmd_bad(pmd_t pmd) #define pages_to_mb(x) ((x) >> (20 - PAGE_SHIFT)) /* FIXME: is this right? */ -/* - * Macro to mark a page protection value as "uncacheable". - */ -#define pgprot_noncached(prot) \ - (__pgprot(pgprot_val((prot)) | _PAGE_PCD | _PAGE_PWT)) - /* * Conversion functions: convert a page and protection to a page entry, * and a page entry and page directory to the page they refer to. @@ -250,10 +244,22 @@ static inline int pud_large(pud_t pte) extern int direct_gbpages; /* Encode and de-code a swap entry */ -#define __swp_type(x) (((x).val >> 1) & 0x3f) -#define __swp_offset(x) ((x).val >> 8) -#define __swp_entry(type, offset) ((swp_entry_t) { ((type) << 1) | \ - ((offset) << 8) }) +#if _PAGE_BIT_FILE < _PAGE_BIT_PROTNONE +#define SWP_TYPE_BITS (_PAGE_BIT_FILE - _PAGE_BIT_PRESENT - 1) +#define SWP_OFFSET_SHIFT (_PAGE_BIT_PROTNONE + 1) +#else +#define SWP_TYPE_BITS (_PAGE_BIT_PROTNONE - _PAGE_BIT_PRESENT - 1) +#define SWP_OFFSET_SHIFT (_PAGE_BIT_FILE + 1) +#endif + +#define MAX_SWAPFILES_CHECK() BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > SWP_TYPE_BITS) + +#define __swp_type(x) (((x).val >> (_PAGE_BIT_PRESENT + 1)) \ + & ((1U << SWP_TYPE_BITS) - 1)) +#define __swp_offset(x) ((x).val >> SWP_OFFSET_SHIFT) +#define __swp_entry(type, offset) ((swp_entry_t) { \ + ((type) << (_PAGE_BIT_PRESENT + 1)) \ + | ((offset) << SWP_OFFSET_SHIFT) }) #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val((pte)) }) #define __swp_entry_to_pte(x) ((pte_t) { .pte = (x).val }) diff --git a/arch/x86/include/asm/prctl.h b/arch/x86/include/asm/prctl.h index fe681147a4f78fcd5cc0235cff57616af81e3f38..a8894647dd9aba3fd5139eb2277e39a10d17cacb 100644 --- a/arch/x86/include/asm/prctl.h +++ b/arch/x86/include/asm/prctl.h @@ -6,5 +6,8 @@ #define ARCH_GET_FS 0x1003 #define ARCH_GET_GS 0x1004 +#ifdef CONFIG_X86_64 +extern long sys_arch_prctl(int, unsigned long); +#endif /* CONFIG_X86_64 */ #endif /* _ASM_X86_PRCTL_H */ diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 5ca01e3832699b0378c36d79a4d17361a3d27b88..091cd8855f2e61707747d07c94286399619852e9 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -110,6 +110,7 @@ struct cpuinfo_x86 { /* Index into per_cpu list: */ u16 cpu_index; #endif + unsigned int x86_hyper_vendor; } __attribute__((__aligned__(SMP_CACHE_BYTES))); #define X86_VENDOR_INTEL 0 @@ -123,6 +124,9 @@ struct cpuinfo_x86 { #define X86_VENDOR_UNKNOWN 0xff +#define X86_HYPER_VENDOR_NONE 0 +#define X86_HYPER_VENDOR_VMWARE 1 + /* * capabilities of CPUs */ @@ -752,6 +756,19 @@ extern void switch_to_new_gdt(void); extern void cpu_init(void); extern void init_gdt(int cpu); +static inline unsigned long get_debugctlmsr(void) +{ + unsigned long debugctlmsr = 0; + +#ifndef CONFIG_X86_DEBUGCTLMSR + if (boot_cpu_data.x86 < 6) + return 0; +#endif + rdmsrl(MSR_IA32_DEBUGCTLMSR, debugctlmsr); + + return debugctlmsr; +} + static inline void update_debugctlmsr(unsigned long debugctlmsr) { #ifndef CONFIG_X86_DEBUGCTLMSR diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h index eefb0594b058917c7a93893f1f89a88973d8bfbc..6d34d954c22896a6b9a26bc5bd622ede33494a8b 100644 --- a/arch/x86/include/asm/ptrace.h +++ b/arch/x86/include/asm/ptrace.h @@ -6,7 +6,6 @@ #include #ifdef __KERNEL__ -#include /* the DS BTS struct is used for ptrace too */ #include #endif @@ -128,34 +127,6 @@ struct pt_regs { #endif /* !__i386__ */ -#ifdef CONFIG_X86_PTRACE_BTS -/* a branch trace record entry - * - * In order to unify the interface between various processor versions, - * we use the below data structure for all processors. - */ -enum bts_qualifier { - BTS_INVALID = 0, - BTS_BRANCH, - BTS_TASK_ARRIVES, - BTS_TASK_DEPARTS -}; - -struct bts_struct { - __u64 qualifier; - union { - /* BTS_BRANCH */ - struct { - __u64 from_ip; - __u64 to_ip; - } lbr; - /* BTS_TASK_ARRIVES or - BTS_TASK_DEPARTS */ - __u64 jiffies; - } variant; -}; -#endif /* CONFIG_X86_PTRACE_BTS */ - #ifdef __KERNEL__ #include @@ -163,13 +134,6 @@ struct bts_struct { struct cpuinfo_x86; struct task_struct; -#ifdef CONFIG_X86_PTRACE_BTS -extern void __cpuinit ptrace_bts_init_intel(struct cpuinfo_x86 *); -extern void ptrace_bts_take_timestamp(struct task_struct *, enum bts_qualifier); -#else -#define ptrace_bts_init_intel(config) do {} while (0) -#endif /* CONFIG_X86_PTRACE_BTS */ - extern unsigned long profile_pc(struct pt_regs *regs); extern unsigned long @@ -271,6 +235,13 @@ extern int do_get_thread_area(struct task_struct *p, int idx, extern int do_set_thread_area(struct task_struct *p, int idx, struct user_desc __user *info, int can_allocate); +extern void x86_ptrace_untrace(struct task_struct *); +extern void x86_ptrace_fork(struct task_struct *child, + unsigned long clone_flags); + +#define arch_ptrace_untrace(tsk) x86_ptrace_untrace(tsk) +#define arch_ptrace_fork(child, flags) x86_ptrace_fork(child, flags) + #endif /* __KERNEL__ */ #endif /* !__ASSEMBLY__ */ diff --git a/arch/x86/include/asm/reboot.h b/arch/x86/include/asm/reboot.h index df7710354f851dc957c497b30a77f4c6468c01df..562d4fd31ba89abdfba10d1069621c19608ac983 100644 --- a/arch/x86/include/asm/reboot.h +++ b/arch/x86/include/asm/reboot.h @@ -1,6 +1,8 @@ #ifndef _ASM_X86_REBOOT_H #define _ASM_X86_REBOOT_H +#include + struct pt_regs; struct machine_ops { @@ -18,4 +20,7 @@ void native_machine_crash_shutdown(struct pt_regs *regs); void native_machine_shutdown(void); void machine_real_restart(const unsigned char *code, int length); +typedef void (*nmi_shootdown_cb)(int, struct die_args*); +void nmi_shootdown_cpus(nmi_shootdown_cb callback); + #endif /* _ASM_X86_REBOOT_H */ diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h index f12d37237465df8b0a181d37685b212c0dd70cd1..4fcd53fd5f43c06c26a8e057fa4f65b5603cf89b 100644 --- a/arch/x86/include/asm/setup.h +++ b/arch/x86/include/asm/setup.h @@ -8,6 +8,10 @@ /* Interrupt control for vSMPowered x86_64 systems */ void vsmp_init(void); + +void setup_bios_corruption_check(void); + + #ifdef CONFIG_X86_VISWS extern void visws_early_detect(void); extern int is_visws_box(void); @@ -16,6 +20,8 @@ static inline void visws_early_detect(void) { } static inline int is_visws_box(void) { return 0; } #endif +extern int wakeup_secondary_cpu_via_nmi(int apicid, unsigned long start_eip); +extern int wakeup_secondary_cpu_via_init(int apicid, unsigned long start_eip); /* * Any setup quirks to be performed? */ @@ -39,6 +45,7 @@ struct x86_quirks { void (*smp_read_mpc_oem)(struct mp_config_oemtable *oemtable, unsigned short oemsize); int (*setup_ioapic_ids)(void); + int (*update_genapic)(void); }; extern struct x86_quirks *x86_quirks; diff --git a/arch/x86/include/asm/sigframe.h b/arch/x86/include/asm/sigframe.h new file mode 100644 index 0000000000000000000000000000000000000000..4e0fe26d27d341005a43f4d62608b57a1c33498b --- /dev/null +++ b/arch/x86/include/asm/sigframe.h @@ -0,0 +1,70 @@ +#ifndef _ASM_X86_SIGFRAME_H +#define _ASM_X86_SIGFRAME_H + +#include +#include +#include + +#ifdef CONFIG_X86_32 +#define sigframe_ia32 sigframe +#define rt_sigframe_ia32 rt_sigframe +#define sigcontext_ia32 sigcontext +#define _fpstate_ia32 _fpstate +#define ucontext_ia32 ucontext +#else /* !CONFIG_X86_32 */ + +#ifdef CONFIG_IA32_EMULATION +#include +#endif /* CONFIG_IA32_EMULATION */ + +#endif /* CONFIG_X86_32 */ + +#if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION) +struct sigframe_ia32 { + u32 pretcode; + int sig; + struct sigcontext_ia32 sc; + /* + * fpstate is unused. fpstate is moved/allocated after + * retcode[] below. This movement allows to have the FP state and the + * future state extensions (xsave) stay together. + * And at the same time retaining the unused fpstate, prevents changing + * the offset of extramask[] in the sigframe and thus prevent any + * legacy application accessing/modifying it. + */ + struct _fpstate_ia32 fpstate_unused; +#ifdef CONFIG_IA32_EMULATION + unsigned int extramask[_COMPAT_NSIG_WORDS-1]; +#else /* !CONFIG_IA32_EMULATION */ + unsigned long extramask[_NSIG_WORDS-1]; +#endif /* CONFIG_IA32_EMULATION */ + char retcode[8]; + /* fp state follows here */ +}; + +struct rt_sigframe_ia32 { + u32 pretcode; + int sig; + u32 pinfo; + u32 puc; +#ifdef CONFIG_IA32_EMULATION + compat_siginfo_t info; +#else /* !CONFIG_IA32_EMULATION */ + struct siginfo info; +#endif /* CONFIG_IA32_EMULATION */ + struct ucontext_ia32 uc; + char retcode[8]; + /* fp state follows here */ +}; +#endif /* defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION) */ + +#ifdef CONFIG_X86_64 +struct rt_sigframe { + char __user *pretcode; + struct ucontext uc; + struct siginfo info; + /* fp state follows here */ +}; +#endif /* CONFIG_X86_64 */ + +#endif /* _ASM_X86_SIGFRAME_H */ diff --git a/arch/x86/include/asm/signal.h b/arch/x86/include/asm/signal.h index 96ac44f275da40f24a73b5180b9e4c240d5fc8ba..7761a5d554bb2eb567024375b5bb3c083991946f 100644 --- a/arch/x86/include/asm/signal.h +++ b/arch/x86/include/asm/signal.h @@ -121,6 +121,10 @@ typedef unsigned long sigset_t; #ifndef __ASSEMBLY__ +# ifdef __KERNEL__ +extern void do_notify_resume(struct pt_regs *, void *, __u32); +# endif /* __KERNEL__ */ + #ifdef __i386__ # ifdef __KERNEL__ struct old_sigaction { @@ -141,8 +145,6 @@ struct k_sigaction { struct sigaction sa; }; -extern void do_notify_resume(struct pt_regs *, void *, __u32); - # else /* __KERNEL__ */ /* Here we must cater to libcs that poke about in kernel headers. */ diff --git a/arch/x86/include/asm/sparsemem.h b/arch/x86/include/asm/sparsemem.h index be44f7dab395ad87492e0021cbf7adb99cadb1d2..e3cc3c063ec5e77683c088fd80906de90fbf9bd2 100644 --- a/arch/x86/include/asm/sparsemem.h +++ b/arch/x86/include/asm/sparsemem.h @@ -27,7 +27,7 @@ #else /* CONFIG_X86_32 */ # define SECTION_SIZE_BITS 27 /* matt - 128 is convenient right now */ # define MAX_PHYSADDR_BITS 44 -# define MAX_PHYSMEM_BITS 44 +# define MAX_PHYSMEM_BITS 44 /* Can be max 45 bits */ #endif #endif /* CONFIG_SPARSEMEM */ diff --git a/arch/x86/include/asm/syscalls.h b/arch/x86/include/asm/syscalls.h index 87803da440100d50222d86cf7a1ac9cf00ed29ca..9c6797c3e56c1363e9f0376c7dea3f8733b81fe6 100644 --- a/arch/x86/include/asm/syscalls.h +++ b/arch/x86/include/asm/syscalls.h @@ -19,6 +19,13 @@ /* kernel/ioport.c */ asmlinkage long sys_ioperm(unsigned long, unsigned long, int); +/* kernel/ldt.c */ +asmlinkage int sys_modify_ldt(int, void __user *, unsigned long); + +/* kernel/tls.c */ +asmlinkage int sys_set_thread_area(struct user_desc __user *); +asmlinkage int sys_get_thread_area(struct user_desc __user *); + /* X86_32 only */ #ifdef CONFIG_X86_32 /* kernel/process_32.c */ @@ -33,14 +40,11 @@ asmlinkage int sys_sigaction(int, const struct old_sigaction __user *, struct old_sigaction __user *); asmlinkage int sys_sigaltstack(unsigned long); asmlinkage unsigned long sys_sigreturn(unsigned long); -asmlinkage int sys_rt_sigreturn(unsigned long); +asmlinkage int sys_rt_sigreturn(struct pt_regs); /* kernel/ioport.c */ asmlinkage long sys_iopl(unsigned long); -/* kernel/ldt.c */ -asmlinkage int sys_modify_ldt(int, void __user *, unsigned long); - /* kernel/sys_i386_32.c */ asmlinkage long sys_mmap2(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long); @@ -54,10 +58,6 @@ asmlinkage int sys_uname(struct old_utsname __user *); struct oldold_utsname; asmlinkage int sys_olduname(struct oldold_utsname __user *); -/* kernel/tls.c */ -asmlinkage int sys_set_thread_area(struct user_desc __user *); -asmlinkage int sys_get_thread_area(struct user_desc __user *); - /* kernel/vm86_32.c */ asmlinkage int sys_vm86old(struct pt_regs); asmlinkage int sys_vm86(struct pt_regs); diff --git a/arch/x86/include/asm/system.h b/arch/x86/include/asm/system.h index 2ed3f0f44ff73519a149b37c9bd658a26361c8de..8e626ea33a1a64d1565c10a0784200ef92ec9a31 100644 --- a/arch/x86/include/asm/system.h +++ b/arch/x86/include/asm/system.h @@ -17,12 +17,12 @@ # define AT_VECTOR_SIZE_ARCH 1 #endif -#ifdef CONFIG_X86_32 - struct task_struct; /* one of the stranger aspects of C forward declarations */ struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *next); +#ifdef CONFIG_X86_32 + /* * Saving eflags is important. It switches not only IOPL between tasks, * it also protects other tasks from NT leaking through sysenter etc. @@ -314,6 +314,8 @@ extern void free_init_pages(char *what, unsigned long begin, unsigned long end); void default_idle(void); +void stop_this_cpu(void *dummy); + /* * Force strict CPU ordering. * And yes, this is required on UP too when we're talking diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h index e44d379faad2b891245ef9cc2332dcaf8f8491c5..98789647baa9b8a6d1e414f9e40c95c70f704a11 100644 --- a/arch/x86/include/asm/thread_info.h +++ b/arch/x86/include/asm/thread_info.h @@ -20,11 +20,13 @@ struct task_struct; struct exec_domain; #include +#include +#include struct thread_info { struct task_struct *task; /* main task structure */ struct exec_domain *exec_domain; /* execution domain */ - unsigned long flags; /* low level flags */ + __u32 flags; /* low level flags */ __u32 status; /* thread synchronous flags */ __u32 cpu; /* current CPU */ int preempt_count; /* 0 => preemptable, @@ -91,7 +93,6 @@ struct thread_info { #define TIF_FORCED_TF 24 /* true if TF in eflags artificially */ #define TIF_DEBUGCTLMSR 25 /* uses thread_struct.debugctlmsr */ #define TIF_DS_AREA_MSR 26 /* uses thread_struct.ds_area_msr */ -#define TIF_BTS_TRACE_TS 27 /* record scheduling event timestamps */ #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) @@ -113,7 +114,6 @@ struct thread_info { #define _TIF_FORCED_TF (1 << TIF_FORCED_TF) #define _TIF_DEBUGCTLMSR (1 << TIF_DEBUGCTLMSR) #define _TIF_DS_AREA_MSR (1 << TIF_DS_AREA_MSR) -#define _TIF_BTS_TRACE_TS (1 << TIF_BTS_TRACE_TS) /* work to do in syscall_trace_enter() */ #define _TIF_WORK_SYSCALL_ENTRY \ @@ -139,8 +139,7 @@ struct thread_info { /* flags to check in __switch_to() */ #define _TIF_WORK_CTXSW \ - (_TIF_IO_BITMAP|_TIF_DEBUGCTLMSR|_TIF_DS_AREA_MSR|_TIF_BTS_TRACE_TS| \ - _TIF_NOTSC) + (_TIF_IO_BITMAP|_TIF_DEBUGCTLMSR|_TIF_DS_AREA_MSR|_TIF_NOTSC) #define _TIF_WORK_CTXSW_PREV _TIF_WORK_CTXSW #define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW|_TIF_DEBUG) diff --git a/arch/x86/include/asm/trampoline.h b/arch/x86/include/asm/trampoline.h index fa0d79facdbc4b0175db51082d1afcaad3f4a060..780ba0ab94f908da84b44d71f1740d47ac2677de 100644 --- a/arch/x86/include/asm/trampoline.h +++ b/arch/x86/include/asm/trampoline.h @@ -3,6 +3,7 @@ #ifndef __ASSEMBLY__ +#ifdef CONFIG_X86_TRAMPOLINE /* * Trampoline 80x86 program as an array. */ @@ -13,8 +14,14 @@ extern unsigned char *trampoline_base; extern unsigned long init_rsp; extern unsigned long initial_code; +#define TRAMPOLINE_SIZE roundup(trampoline_end - trampoline_data, PAGE_SIZE) #define TRAMPOLINE_BASE 0x6000 + extern unsigned long setup_trampoline(void); +extern void __init reserve_trampoline_memory(void); +#else +static inline void reserve_trampoline_memory(void) {}; +#endif /* CONFIG_X86_TRAMPOLINE */ #endif /* __ASSEMBLY__ */ diff --git a/arch/x86/include/asm/traps.h b/arch/x86/include/asm/traps.h index 45dee286e45cda98bc1fe20e79c30ccded41ff5d..2ee0a3bceedf4738cc0e65b1cda67110399550f1 100644 --- a/arch/x86/include/asm/traps.h +++ b/arch/x86/include/asm/traps.h @@ -46,6 +46,10 @@ dotraplinkage void do_coprocessor_segment_overrun(struct pt_regs *, long); dotraplinkage void do_invalid_TSS(struct pt_regs *, long); dotraplinkage void do_segment_not_present(struct pt_regs *, long); dotraplinkage void do_stack_segment(struct pt_regs *, long); +#ifdef CONFIG_X86_64 +dotraplinkage void do_double_fault(struct pt_regs *, long); +asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *); +#endif dotraplinkage void do_general_protection(struct pt_regs *, long); dotraplinkage void do_page_fault(struct pt_regs *, unsigned long); dotraplinkage void do_spurious_interrupt_bug(struct pt_regs *, long); @@ -72,10 +76,13 @@ static inline int get_si_code(unsigned long condition) extern int panic_on_unrecovered_nmi; extern int kstack_depth_to_print; -#ifdef CONFIG_X86_32 void math_error(void __user *); -unsigned long patch_espfix_desc(unsigned long, unsigned long); asmlinkage void math_emulate(long); +#ifdef CONFIG_X86_32 +unsigned long patch_espfix_desc(unsigned long, unsigned long); +#else +asmlinkage void smp_thermal_interrupt(void); +asmlinkage void mce_threshold_interrupt(void); #endif #endif /* _ASM_X86_TRAPS_H */ diff --git a/arch/x86/include/asm/tsc.h b/arch/x86/include/asm/tsc.h index 9cd83a8e40d59a3dae2978e23887d81311370ae3..38ae163cc91b00bf029d5ed5e29cd8ba96bd461b 100644 --- a/arch/x86/include/asm/tsc.h +++ b/arch/x86/include/asm/tsc.h @@ -34,8 +34,6 @@ static inline cycles_t get_cycles(void) static __always_inline cycles_t vget_cycles(void) { - cycles_t cycles; - /* * We only do VDSOs on TSC capable CPUs, so this shouldnt * access boot_cpu_data (which is not VDSO-safe): @@ -44,11 +42,7 @@ static __always_inline cycles_t vget_cycles(void) if (!cpu_has_tsc) return 0; #endif - rdtsc_barrier(); - cycles = (cycles_t)__native_read_tsc(); - rdtsc_barrier(); - - return cycles; + return (cycles_t)__native_read_tsc(); } extern void tsc_init(void); diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h index 35c54921b2e434cdd95bbd223077f2b1155d0f1f..580c3ee6c58c4d0479dbce9ea491c78049255e04 100644 --- a/arch/x86/include/asm/uaccess.h +++ b/arch/x86/include/asm/uaccess.h @@ -350,14 +350,14 @@ do { \ #define __put_user_nocheck(x, ptr, size) \ ({ \ - long __pu_err; \ + int __pu_err; \ __put_user_size((x), (ptr), (size), __pu_err, -EFAULT); \ __pu_err; \ }) #define __get_user_nocheck(x, ptr, size) \ ({ \ - long __gu_err; \ + int __gu_err; \ unsigned long __gu_val; \ __get_user_size(__gu_val, (ptr), (size), __gu_err, -EFAULT); \ (x) = (__force __typeof__(*(ptr)))__gu_val; \ diff --git a/arch/x86/include/asm/uv/bios.h b/arch/x86/include/asm/uv/bios.h index d931d3b7e6f71b394d87f5766835dd8ef892dfec..7ed17ff502b9edd76afb96fe682609a4df1afffe 100644 --- a/arch/x86/include/asm/uv/bios.h +++ b/arch/x86/include/asm/uv/bios.h @@ -32,13 +32,18 @@ enum uv_bios_cmd { UV_BIOS_COMMON, UV_BIOS_GET_SN_INFO, - UV_BIOS_FREQ_BASE + UV_BIOS_FREQ_BASE, + UV_BIOS_WATCHLIST_ALLOC, + UV_BIOS_WATCHLIST_FREE, + UV_BIOS_MEMPROTECT, + UV_BIOS_GET_PARTITION_ADDR }; /* * Status values returned from a BIOS call. */ enum { + BIOS_STATUS_MORE_PASSES = 1, BIOS_STATUS_SUCCESS = 0, BIOS_STATUS_UNIMPLEMENTED = -ENOSYS, BIOS_STATUS_EINVAL = -EINVAL, @@ -71,6 +76,21 @@ union partition_info_u { }; }; +union uv_watchlist_u { + u64 val; + struct { + u64 blade : 16, + size : 32, + filler : 16; + }; +}; + +enum uv_memprotect { + UV_MEMPROT_RESTRICT_ACCESS, + UV_MEMPROT_ALLOW_AMO, + UV_MEMPROT_ALLOW_RW +}; + /* * bios calls have 6 parameters */ @@ -80,14 +100,20 @@ extern s64 uv_bios_call_reentrant(enum uv_bios_cmd, u64, u64, u64, u64, u64); extern s64 uv_bios_get_sn_info(int, int *, long *, long *, long *); extern s64 uv_bios_freq_base(u64, u64 *); +extern int uv_bios_mq_watchlist_alloc(int, unsigned long, unsigned int, + unsigned long *); +extern int uv_bios_mq_watchlist_free(int, int); +extern s64 uv_bios_change_memprotect(u64, u64, enum uv_memprotect); +extern s64 uv_bios_reserved_page_pa(u64, u64 *, u64 *, u64 *); extern void uv_bios_init(void); +extern unsigned long sn_rtc_cycles_per_second; extern int uv_type; extern long sn_partition_id; -extern long uv_coherency_id; -extern long uv_region_size; -#define partition_coherence_id() (uv_coherency_id) +extern long sn_coherency_id; +extern long sn_region_size; +#define partition_coherence_id() (sn_coherency_id) extern struct kobject *sgi_uv_kobj; /* /sys/firmware/sgi_uv */ diff --git a/arch/x86/include/asm/uv/uv_hub.h b/arch/x86/include/asm/uv/uv_hub.h index 7a5782610b2bcb0af69d99be174d0815a6722663..777327ef05c19f0887c0b9b089a6f71135395e94 100644 --- a/arch/x86/include/asm/uv/uv_hub.h +++ b/arch/x86/include/asm/uv/uv_hub.h @@ -113,25 +113,37 @@ */ #define UV_MAX_NASID_VALUE (UV_MAX_NUMALINK_NODES * 2) +struct uv_scir_s { + struct timer_list timer; + unsigned long offset; + unsigned long last; + unsigned long idle_on; + unsigned long idle_off; + unsigned char state; + unsigned char enabled; +}; + /* * The following defines attributes of the HUB chip. These attributes are * frequently referenced and are kept in the per-cpu data areas of each cpu. * They are kept together in a struct to minimize cache misses. */ struct uv_hub_info_s { - unsigned long global_mmr_base; - unsigned long gpa_mask; - unsigned long gnode_upper; - unsigned long lowmem_remap_top; - unsigned long lowmem_remap_base; - unsigned short pnode; - unsigned short pnode_mask; - unsigned short coherency_domain_number; - unsigned short numa_blade_id; - unsigned char blade_processor_id; - unsigned char m_val; - unsigned char n_val; + unsigned long global_mmr_base; + unsigned long gpa_mask; + unsigned long gnode_upper; + unsigned long lowmem_remap_top; + unsigned long lowmem_remap_base; + unsigned short pnode; + unsigned short pnode_mask; + unsigned short coherency_domain_number; + unsigned short numa_blade_id; + unsigned char blade_processor_id; + unsigned char m_val; + unsigned char n_val; + struct uv_scir_s scir; }; + DECLARE_PER_CPU(struct uv_hub_info_s, __uv_hub_info); #define uv_hub_info (&__get_cpu_var(__uv_hub_info)) #define uv_cpu_hub_info(cpu) (&per_cpu(__uv_hub_info, cpu)) @@ -163,6 +175,30 @@ DECLARE_PER_CPU(struct uv_hub_info_s, __uv_hub_info); #define UV_APIC_PNODE_SHIFT 6 +/* Local Bus from cpu's perspective */ +#define LOCAL_BUS_BASE 0x1c00000 +#define LOCAL_BUS_SIZE (4 * 1024 * 1024) + +/* + * System Controller Interface Reg + * + * Note there are NO leds on a UV system. This register is only + * used by the system controller to monitor system-wide operation. + * There are 64 regs per node. With Nahelem cpus (2 cores per node, + * 8 cpus per core, 2 threads per cpu) there are 32 cpu threads on + * a node. + * + * The window is located at top of ACPI MMR space + */ +#define SCIR_WINDOW_COUNT 64 +#define SCIR_LOCAL_MMR_BASE (LOCAL_BUS_BASE + \ + LOCAL_BUS_SIZE - \ + SCIR_WINDOW_COUNT) + +#define SCIR_CPU_HEARTBEAT 0x01 /* timer interrupt */ +#define SCIR_CPU_ACTIVITY 0x02 /* not idle */ +#define SCIR_CPU_HB_INTERVAL (HZ) /* once per second */ + /* * Macros for converting between kernel virtual addresses, socket local physical * addresses, and UV global physical addresses. @@ -174,7 +210,7 @@ DECLARE_PER_CPU(struct uv_hub_info_s, __uv_hub_info); static inline unsigned long uv_soc_phys_ram_to_gpa(unsigned long paddr) { if (paddr < uv_hub_info->lowmem_remap_top) - paddr += uv_hub_info->lowmem_remap_base; + paddr |= uv_hub_info->lowmem_remap_base; return paddr | uv_hub_info->gnode_upper; } @@ -182,19 +218,7 @@ static inline unsigned long uv_soc_phys_ram_to_gpa(unsigned long paddr) /* socket virtual --> UV global physical address */ static inline unsigned long uv_gpa(void *v) { - return __pa(v) | uv_hub_info->gnode_upper; -} - -/* socket virtual --> UV global physical address */ -static inline void *uv_vgpa(void *v) -{ - return (void *)uv_gpa(v); -} - -/* UV global physical address --> socket virtual */ -static inline void *uv_va(unsigned long gpa) -{ - return __va(gpa & uv_hub_info->gpa_mask); + return uv_soc_phys_ram_to_gpa(__pa(v)); } /* pnode, offset --> socket virtual */ @@ -277,6 +301,16 @@ static inline void uv_write_local_mmr(unsigned long offset, unsigned long val) *uv_local_mmr_address(offset) = val; } +static inline unsigned char uv_read_local_mmr8(unsigned long offset) +{ + return *((unsigned char *)uv_local_mmr_address(offset)); +} + +static inline void uv_write_local_mmr8(unsigned long offset, unsigned char val) +{ + *((unsigned char *)uv_local_mmr_address(offset)) = val; +} + /* * Structures and definitions for converting between cpu, node, pnode, and blade * numbers. @@ -351,5 +385,20 @@ static inline int uv_num_possible_blades(void) return uv_possible_blades; } -#endif /* _ASM_X86_UV_UV_HUB_H */ +/* Update SCIR state */ +static inline void uv_set_scir_bits(unsigned char value) +{ + if (uv_hub_info->scir.state != value) { + uv_hub_info->scir.state = value; + uv_write_local_mmr8(uv_hub_info->scir.offset, value); + } +} +static inline void uv_set_cpu_scir_bits(int cpu, unsigned char value) +{ + if (uv_cpu_hub_info(cpu)->scir.state != value) { + uv_cpu_hub_info(cpu)->scir.state = value; + uv_write_local_mmr8(uv_cpu_hub_info(cpu)->scir.offset, value); + } +} +#endif /* _ASM_X86_UV_UV_HUB_H */ diff --git a/arch/x86/include/asm/vmware.h b/arch/x86/include/asm/vmware.h new file mode 100644 index 0000000000000000000000000000000000000000..c11b7e100d838278402ce2e3976d46fcc1c86b86 --- /dev/null +++ b/arch/x86/include/asm/vmware.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2008, VMware, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +#ifndef ASM_X86__VMWARE_H +#define ASM_X86__VMWARE_H + +extern unsigned long vmware_get_tsc_khz(void); +extern int vmware_platform(void); +extern void vmware_set_feature_bits(struct cpuinfo_x86 *c); + +#endif diff --git a/arch/x86/include/asm/xen/hypercall.h b/arch/x86/include/asm/xen/hypercall.h index 3f6000d95fe21f38dae31ff2dbfb8945703d91f4..5e79ca694326cdeb85886d371565ad506fe6f0af 100644 --- a/arch/x86/include/asm/xen/hypercall.h +++ b/arch/x86/include/asm/xen/hypercall.h @@ -33,8 +33,14 @@ #ifndef _ASM_X86_XEN_HYPERCALL_H #define _ASM_X86_XEN_HYPERCALL_H +#include +#include #include #include +#include + +#include +#include #include #include diff --git a/arch/x86/include/asm/xen/hypervisor.h b/arch/x86/include/asm/xen/hypervisor.h index a38d25ac87d2abdbfb6e077f304210aef43d78f8..81fbd735aec47e3edbed57a5d83eb142f3c3571e 100644 --- a/arch/x86/include/asm/xen/hypervisor.h +++ b/arch/x86/include/asm/xen/hypervisor.h @@ -33,39 +33,10 @@ #ifndef _ASM_X86_XEN_HYPERVISOR_H #define _ASM_X86_XEN_HYPERVISOR_H -#include -#include - -#include -#include - -#include -#include -#include -#if defined(__i386__) -# ifdef CONFIG_X86_PAE -# include -# else -# include -# endif -#endif -#include - /* arch/i386/kernel/setup.c */ extern struct shared_info *HYPERVISOR_shared_info; extern struct start_info *xen_start_info; -/* arch/i386/mach-xen/evtchn.c */ -/* Force a proper event-channel callback from Xen. */ -extern void force_evtchn_callback(void); - -/* Turn jiffies into Xen system time. */ -u64 jiffies_to_st(unsigned long jiffies); - - -#define MULTI_UVMFLAGS_INDEX 3 -#define MULTI_UVMDOMID_INDEX 4 - enum xen_domain_type { XEN_NATIVE, XEN_PV_DOMAIN, @@ -74,9 +45,15 @@ enum xen_domain_type { extern enum xen_domain_type xen_domain_type; +#ifdef CONFIG_XEN #define xen_domain() (xen_domain_type != XEN_NATIVE) -#define xen_pv_domain() (xen_domain_type == XEN_PV_DOMAIN) +#else +#define xen_domain() (0) +#endif + +#define xen_pv_domain() (xen_domain() && xen_domain_type == XEN_PV_DOMAIN) +#define xen_hvm_domain() (xen_domain() && xen_domain_type == XEN_HVM_DOMAIN) + #define xen_initial_domain() (xen_pv_domain() && xen_start_info->flags & SIF_INITDOMAIN) -#define xen_hvm_domain() (xen_domain_type == XEN_HVM_DOMAIN) #endif /* _ASM_X86_XEN_HYPERVISOR_H */ diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h index bc628998a1b9dc896a416d6ea0ef5293463c8a24..7ef617ef1df3ca38c1d29286a4742e770982dc67 100644 --- a/arch/x86/include/asm/xen/page.h +++ b/arch/x86/include/asm/xen/page.h @@ -1,11 +1,16 @@ #ifndef _ASM_X86_XEN_PAGE_H #define _ASM_X86_XEN_PAGE_H +#include +#include +#include #include #include +#include #include +#include #include /* Xen machine address */ diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index b62a7667828eb77574128a8ca82b1f54cee28238..88dd768eab6d34980d14aff41178115ed881045e 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -12,6 +12,7 @@ CFLAGS_REMOVE_tsc.o = -pg CFLAGS_REMOVE_rtc.o = -pg CFLAGS_REMOVE_paravirt-spinlocks.o = -pg CFLAGS_REMOVE_ftrace.o = -pg +CFLAGS_REMOVE_early_printk.o = -pg endif # @@ -23,9 +24,9 @@ CFLAGS_vsyscall_64.o := $(PROFILING) -g0 $(nostackp) CFLAGS_hpet.o := $(nostackp) CFLAGS_tsc.o := $(nostackp) -obj-y := process_$(BITS).o signal_$(BITS).o entry_$(BITS).o +obj-y := process_$(BITS).o signal.o entry_$(BITS).o obj-y += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o -obj-y += time_$(BITS).o ioport.o ldt.o +obj-y += time_$(BITS).o ioport.o ldt.o dumpstack.o obj-y += setup.o i8259.o irqinit_$(BITS).o setup_percpu.o obj-$(CONFIG_X86_VISWS) += visws_quirks.o obj-$(CONFIG_X86_32) += probe_roms_32.o @@ -65,6 +66,7 @@ obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o obj-$(CONFIG_X86_IO_APIC) += io_apic.o obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups_32.o obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o +obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o obj-$(CONFIG_KEXEC) += machine_kexec_$(BITS).o obj-$(CONFIG_KEXEC) += relocate_kernel_$(BITS).o crash.o obj-$(CONFIG_CRASH_DUMP) += crash_dump_$(BITS).o @@ -105,6 +107,8 @@ microcode-$(CONFIG_MICROCODE_INTEL) += microcode_intel.o microcode-$(CONFIG_MICROCODE_AMD) += microcode_amd.o obj-$(CONFIG_MICROCODE) += microcode.o +obj-$(CONFIG_X86_CHECK_BIOS_CORRUPTION) += check.o + ### # 64 bit specific files ifeq ($(CONFIG_X86_64),y) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 4c51a2f8fd315900071de65e6ee3bee43ea2718f..65d0b72777ea099a99ced450bec404220af6e2e2 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -1360,6 +1360,17 @@ static void __init acpi_process_madt(void) disable_acpi(); } } + + /* + * ACPI supports both logical (e.g. Hyper-Threading) and physical + * processors, where MPS only supports physical. + */ + if (acpi_lapic && acpi_ioapic) + printk(KERN_INFO "Using ACPI (MADT) for SMP configuration " + "information\n"); + else if (acpi_lapic) + printk(KERN_INFO "Using ACPI for processor (LAPIC) " + "configuration information\n"); #endif return; } diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 0a60d60ed036b264e6d4c05174dfc3b464574852..2e2da717b350bbd30cba12cfee11d06b12f6e1b8 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c index c6cc22815d35f232dd21fae7d2718a3c161b373c..c625800c55caeb411211607983ab4e7f22e3c731 100644 --- a/arch/x86/kernel/amd_iommu_init.c +++ b/arch/x86/kernel/amd_iommu_init.c @@ -28,6 +28,7 @@ #include #include #include +#include /* * definitions for the ACPI scanning code diff --git a/arch/x86/kernel/aperture_64.c b/arch/x86/kernel/aperture_64.c index 9a32b37ee2eec2f176708d7fccd5b7dadcf0e3ab..676debfc1702346939a5f17423e6a706f7e69886 100644 --- a/arch/x86/kernel/aperture_64.c +++ b/arch/x86/kernel/aperture_64.c @@ -1,8 +1,9 @@ /* * Firmware replacement code. * - * Work around broken BIOSes that don't set an aperture or only set the - * aperture in the AGP bridge. + * Work around broken BIOSes that don't set an aperture, only set the + * aperture in the AGP bridge, or set too small aperture. + * * If all fails map the aperture over some low memory. This is cheaper than * doing bounce buffering. The memory is lost. This is done at early boot * because only the bootmem allocator can allocate 32+MB. diff --git a/arch/x86/kernel/apic.c b/arch/x86/kernel/apic.c index 16f94879b52578aba3e689d7a8adcccf59ab8ecb..b5229affb95397cf8dbab2f49ab823497f8ba531 100644 --- a/arch/x86/kernel/apic.c +++ b/arch/x86/kernel/apic.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -441,6 +442,7 @@ static void lapic_timer_setup(enum clock_event_mode mode, v = apic_read(APIC_LVTT); v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR); apic_write(APIC_LVTT, v); + apic_write(APIC_TMICT, 0xffffffff); break; case CLOCK_EVT_MODE_RESUME: /* Nothing to do here */ @@ -559,13 +561,13 @@ static int __init calibrate_by_pmtimer(long deltapm, long *delta) } else { res = (((u64)deltapm) * mult) >> 22; do_div(res, 1000000); - printk(KERN_WARNING "APIC calibration not consistent " + pr_warning("APIC calibration not consistent " "with PM Timer: %ldms instead of 100ms\n", (long)res); /* Correct the lapic counter value */ res = (((u64)(*delta)) * pm_100ms); do_div(res, deltapm); - printk(KERN_INFO "APIC delta adjusted to PM-Timer: " + pr_info("APIC delta adjusted to PM-Timer: " "%lu (%ld)\n", (unsigned long)res, *delta); *delta = (long)res; } @@ -645,8 +647,7 @@ static int __init calibrate_APIC_clock(void) */ if (calibration_result < (1000000 / HZ)) { local_irq_enable(); - printk(KERN_WARNING - "APIC frequency too slow, disabling apic timer\n"); + pr_warning("APIC frequency too slow, disabling apic timer\n"); return -1; } @@ -672,13 +673,9 @@ static int __init calibrate_APIC_clock(void) while (lapic_cal_loops <= LAPIC_CAL_LOOPS) cpu_relax(); - local_irq_disable(); - /* Stop the lapic timer */ lapic_timer_setup(CLOCK_EVT_MODE_SHUTDOWN, levt); - local_irq_enable(); - /* Jiffies delta */ deltaj = lapic_cal_j2 - lapic_cal_j1; apic_printk(APIC_VERBOSE, "... jiffies delta = %lu\n", deltaj); @@ -692,8 +689,7 @@ static int __init calibrate_APIC_clock(void) local_irq_enable(); if (levt->features & CLOCK_EVT_FEAT_DUMMY) { - printk(KERN_WARNING - "APIC timer disabled due to verification failure.\n"); + pr_warning("APIC timer disabled due to verification failure.\n"); return -1; } @@ -714,7 +710,7 @@ void __init setup_boot_APIC_clock(void) * broadcast mechanism is used. On UP systems simply ignore it. */ if (disable_apic_timer) { - printk(KERN_INFO "Disabling APIC timer\n"); + pr_info("Disabling APIC timer\n"); /* No broadcast on UP ! */ if (num_possible_cpus() > 1) { lapic_clockevent.mult = 1; @@ -741,7 +737,7 @@ void __init setup_boot_APIC_clock(void) if (nmi_watchdog != NMI_IO_APIC) lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY; else - printk(KERN_WARNING "APIC timer registered as dummy," + pr_warning("APIC timer registered as dummy," " due to nmi_watchdog=%d!\n", nmi_watchdog); /* Setup the lapic or request the broadcast */ @@ -773,8 +769,7 @@ static void local_apic_timer_interrupt(void) * spurious. */ if (!evt->event_handler) { - printk(KERN_WARNING - "Spurious LAPIC timer interrupt on cpu %d\n", cpu); + pr_warning("Spurious LAPIC timer interrupt on cpu %d\n", cpu); /* Switch it off */ lapic_timer_setup(CLOCK_EVT_MODE_SHUTDOWN, evt); return; @@ -783,11 +778,7 @@ static void local_apic_timer_interrupt(void) /* * the NMI deadlock-detector uses this. */ -#ifdef CONFIG_X86_64 - add_pda(apic_timer_irqs, 1); -#else - per_cpu(irq_stat, cpu).apic_timer_irqs++; -#endif + inc_irq_stat(apic_timer_irqs); evt->event_handler(evt); } @@ -800,7 +791,7 @@ static void local_apic_timer_interrupt(void) * [ if a single-CPU system runs an SMP kernel then we call the local * interrupt as well. Thus we cannot inline the local irq ... ] */ -void smp_apic_timer_interrupt(struct pt_regs *regs) +void __irq_entry smp_apic_timer_interrupt(struct pt_regs *regs) { struct pt_regs *old_regs = set_irq_regs(regs); @@ -814,9 +805,7 @@ void smp_apic_timer_interrupt(struct pt_regs *regs) * Besides, if we don't timer interrupts ignore the global * interrupt lock, which is the WrongThing (tm) to do. */ -#ifdef CONFIG_X86_64 exit_idle(); -#endif irq_enter(); local_apic_timer_interrupt(); irq_exit(); @@ -1093,7 +1082,7 @@ static void __cpuinit lapic_setup_esr(void) unsigned int oldvalue, value, maxlvt; if (!lapic_is_integrated()) { - printk(KERN_INFO "No ESR for 82489DX.\n"); + pr_info("No ESR for 82489DX.\n"); return; } @@ -1104,7 +1093,7 @@ static void __cpuinit lapic_setup_esr(void) * ESR disabled - we can't do anything useful with the * errors anyway - mbligh */ - printk(KERN_INFO "Leaving ESR disabled.\n"); + pr_info("Leaving ESR disabled.\n"); return; } @@ -1298,7 +1287,7 @@ void check_x2apic(void) rdmsr(MSR_IA32_APICBASE, msr, msr2); if (msr & X2APIC_ENABLE) { - printk("x2apic enabled by BIOS, switching to x2apic ops\n"); + pr_info("x2apic enabled by BIOS, switching to x2apic ops\n"); x2apic_preenabled = x2apic = 1; apic_ops = &x2apic_ops; } @@ -1310,7 +1299,7 @@ void enable_x2apic(void) rdmsr(MSR_IA32_APICBASE, msr, msr2); if (!(msr & X2APIC_ENABLE)) { - printk("Enabling x2apic\n"); + pr_info("Enabling x2apic\n"); wrmsr(MSR_IA32_APICBASE, msr | X2APIC_ENABLE, 0); } } @@ -1325,9 +1314,8 @@ void __init enable_IR_x2apic(void) return; if (!x2apic_preenabled && disable_x2apic) { - printk(KERN_INFO - "Skipped enabling x2apic and Interrupt-remapping " - "because of nox2apic\n"); + pr_info("Skipped enabling x2apic and Interrupt-remapping " + "because of nox2apic\n"); return; } @@ -1335,22 +1323,19 @@ void __init enable_IR_x2apic(void) panic("Bios already enabled x2apic, can't enforce nox2apic"); if (!x2apic_preenabled && skip_ioapic_setup) { - printk(KERN_INFO - "Skipped enabling x2apic and Interrupt-remapping " - "because of skipping io-apic setup\n"); + pr_info("Skipped enabling x2apic and Interrupt-remapping " + "because of skipping io-apic setup\n"); return; } ret = dmar_table_init(); if (ret) { - printk(KERN_INFO - "dmar_table_init() failed with %d:\n", ret); + pr_info("dmar_table_init() failed with %d:\n", ret); if (x2apic_preenabled) panic("x2apic enabled by bios. But IR enabling failed"); else - printk(KERN_INFO - "Not enabling x2apic,Intr-remapping\n"); + pr_info("Not enabling x2apic,Intr-remapping\n"); return; } @@ -1359,7 +1344,7 @@ void __init enable_IR_x2apic(void) ret = save_mask_IO_APIC_setup(); if (ret) { - printk(KERN_INFO "Saving IO-APIC state failed: %d\n", ret); + pr_info("Saving IO-APIC state failed: %d\n", ret); goto end; } @@ -1394,14 +1379,11 @@ void __init enable_IR_x2apic(void) if (!ret) { if (!x2apic_preenabled) - printk(KERN_INFO - "Enabled x2apic and interrupt-remapping\n"); + pr_info("Enabled x2apic and interrupt-remapping\n"); else - printk(KERN_INFO - "Enabled Interrupt-remapping\n"); + pr_info("Enabled Interrupt-remapping\n"); } else - printk(KERN_ERR - "Failed to enable Interrupt-remapping and x2apic\n"); + pr_err("Failed to enable Interrupt-remapping and x2apic\n"); #else if (!cpu_has_x2apic) return; @@ -1410,8 +1392,8 @@ void __init enable_IR_x2apic(void) panic("x2apic enabled prior OS handover," " enable CONFIG_INTR_REMAP"); - printk(KERN_INFO "Enable CONFIG_INTR_REMAP for enabling intr-remapping " - " and x2apic\n"); + pr_info("Enable CONFIG_INTR_REMAP for enabling intr-remapping " + " and x2apic\n"); #endif return; @@ -1428,7 +1410,7 @@ void __init enable_IR_x2apic(void) static int __init detect_init_APIC(void) { if (!cpu_has_apic) { - printk(KERN_INFO "No local APIC present\n"); + pr_info("No local APIC present\n"); return -1; } @@ -1469,8 +1451,8 @@ static int __init detect_init_APIC(void) * "lapic" specified. */ if (!force_enable_local_apic) { - printk(KERN_INFO "Local APIC disabled by BIOS -- " - "you can enable it with \"lapic\"\n"); + pr_info("Local APIC disabled by BIOS -- " + "you can enable it with \"lapic\"\n"); return -1; } /* @@ -1480,8 +1462,7 @@ static int __init detect_init_APIC(void) */ rdmsr(MSR_IA32_APICBASE, l, h); if (!(l & MSR_IA32_APICBASE_ENABLE)) { - printk(KERN_INFO - "Local APIC disabled by BIOS -- reenabling.\n"); + pr_info("Local APIC disabled by BIOS -- reenabling.\n"); l &= ~MSR_IA32_APICBASE_BASE; l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE; wrmsr(MSR_IA32_APICBASE, l, h); @@ -1494,7 +1475,7 @@ static int __init detect_init_APIC(void) */ features = cpuid_edx(1); if (!(features & (1 << X86_FEATURE_APIC))) { - printk(KERN_WARNING "Could not enable APIC!\n"); + pr_warning("Could not enable APIC!\n"); return -1; } set_cpu_cap(&boot_cpu_data, X86_FEATURE_APIC); @@ -1505,14 +1486,14 @@ static int __init detect_init_APIC(void) if (l & MSR_IA32_APICBASE_ENABLE) mp_lapic_addr = l & MSR_IA32_APICBASE_BASE; - printk(KERN_INFO "Found and enabled local APIC!\n"); + pr_info("Found and enabled local APIC!\n"); apic_pm_activate(); return 0; no_apic: - printk(KERN_INFO "No local APIC present or hardware disabled\n"); + pr_info("No local APIC present or hardware disabled\n"); return -1; } #endif @@ -1588,12 +1569,12 @@ int __init APIC_init_uniprocessor(void) { #ifdef CONFIG_X86_64 if (disable_apic) { - printk(KERN_INFO "Apic disabled\n"); + pr_info("Apic disabled\n"); return -1; } if (!cpu_has_apic) { disable_apic = 1; - printk(KERN_INFO "Apic disabled by BIOS\n"); + pr_info("Apic disabled by BIOS\n"); return -1; } #else @@ -1605,8 +1586,8 @@ int __init APIC_init_uniprocessor(void) */ if (!cpu_has_apic && APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) { - printk(KERN_ERR "BIOS bug, local APIC 0x%x not detected!...\n", - boot_cpu_physical_apicid); + pr_err("BIOS bug, local APIC 0x%x not detected!...\n", + boot_cpu_physical_apicid); clear_cpu_cap(&boot_cpu_data, X86_FEATURE_APIC); return -1; } @@ -1682,9 +1663,7 @@ void smp_spurious_interrupt(struct pt_regs *regs) { u32 v; -#ifdef CONFIG_X86_64 exit_idle(); -#endif irq_enter(); /* * Check if this really is a spurious interrupt and ACK it @@ -1695,14 +1674,11 @@ void smp_spurious_interrupt(struct pt_regs *regs) if (v & (1 << (SPURIOUS_APIC_VECTOR & 0x1f))) ack_APIC_irq(); -#ifdef CONFIG_X86_64 - add_pda(irq_spurious_count, 1); -#else + inc_irq_stat(irq_spurious_count); + /* see sw-dev-man vol 3, chapter 7.4.13.5 */ - printk(KERN_INFO "spurious APIC interrupt on CPU#%d, " - "should never happen.\n", smp_processor_id()); - __get_cpu_var(irq_stat).irq_spurious_count++; -#endif + pr_info("spurious APIC interrupt on CPU#%d, " + "should never happen.\n", smp_processor_id()); irq_exit(); } @@ -1713,9 +1689,7 @@ void smp_error_interrupt(struct pt_regs *regs) { u32 v, v1; -#ifdef CONFIG_X86_64 exit_idle(); -#endif irq_enter(); /* First tickle the hardware, only then report what went on. -- REW */ v = apic_read(APIC_ESR); @@ -1724,17 +1698,18 @@ void smp_error_interrupt(struct pt_regs *regs) ack_APIC_irq(); atomic_inc(&irq_err_count); - /* Here is what the APIC error bits mean: - 0: Send CS error - 1: Receive CS error - 2: Send accept error - 3: Receive accept error - 4: Reserved - 5: Send illegal vector - 6: Received illegal vector - 7: Illegal register address - */ - printk(KERN_DEBUG "APIC error on CPU%d: %02x(%02x)\n", + /* + * Here is what the APIC error bits mean: + * 0: Send CS error + * 1: Receive CS error + * 2: Send accept error + * 3: Receive accept error + * 4: Reserved + * 5: Send illegal vector + * 6: Received illegal vector + * 7: Illegal register address + */ + pr_debug("APIC error on CPU%d: %02x(%02x)\n", smp_processor_id(), v , v1); irq_exit(); } @@ -1838,15 +1813,15 @@ void __cpuinit generic_processor_info(int apicid, int version) * Validate version */ if (version == 0x0) { - printk(KERN_WARNING "BIOS bug, APIC version is 0 for CPU#%d! " - "fixing up to 0x10. (tell your hw vendor)\n", - version); + pr_warning("BIOS bug, APIC version is 0 for CPU#%d! " + "fixing up to 0x10. (tell your hw vendor)\n", + version); version = 0x10; } apic_version[apicid] = version; if (num_processors >= NR_CPUS) { - printk(KERN_WARNING "WARNING: NR_CPUS limit of %i reached." + pr_warning("WARNING: NR_CPUS limit of %i reached." " Processor ignored.\n", NR_CPUS); return; } @@ -2209,7 +2184,7 @@ static int __init apic_set_verbosity(char *arg) else if (strcmp("verbose", arg) == 0) apic_verbosity = APIC_VERBOSE; else { - printk(KERN_WARNING "APIC Verbosity level %s not recognised" + pr_warning("APIC Verbosity level %s not recognised" " use apic=verbose or apic=debug\n", arg); return -EINVAL; } diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c index 5145a6e72bbbf7f6a4e93d85aed20c769f0883dc..3a26525a3f31a03f3490f7e17be537a6fb3e7c7e 100644 --- a/arch/x86/kernel/apm_32.c +++ b/arch/x86/kernel/apm_32.c @@ -391,11 +391,7 @@ static int power_off; #else static int power_off = 1; #endif -#ifdef CONFIG_APM_REAL_MODE_POWER_OFF -static int realmode_power_off = 1; -#else static int realmode_power_off; -#endif #ifdef CONFIG_APM_ALLOW_INTS static int allow_ints = 1; #else diff --git a/arch/x86/kernel/asm-offsets_32.c b/arch/x86/kernel/asm-offsets_32.c index 6649d09ad88f8830df49427c7d8763196eb0a0f6..ee4df08feee6b0a64b62ca639d39cffbdd0cc87a 100644 --- a/arch/x86/kernel/asm-offsets_32.c +++ b/arch/x86/kernel/asm-offsets_32.c @@ -11,7 +11,7 @@ #include #include #include -#include "sigframe.h" +#include #include #include #include diff --git a/arch/x86/kernel/asm-offsets_64.c b/arch/x86/kernel/asm-offsets_64.c index 7fcf63d22f8b28c4457b6f8e7fb2eae54b071b1f..1d41d3f1edbcaa3d39450561d25b8ef0fb801e38 100644 --- a/arch/x86/kernel/asm-offsets_64.c +++ b/arch/x86/kernel/asm-offsets_64.c @@ -20,6 +20,8 @@ #include +#include + #define __NO_STUBS 1 #undef __SYSCALL #undef _ASM_X86_UNISTD_64_H @@ -87,7 +89,7 @@ int main(void) BLANK(); #undef ENTRY DEFINE(IA32_RT_SIGFRAME_sigcontext, - offsetof (struct rt_sigframe32, uc.uc_mcontext)); + offsetof (struct rt_sigframe_ia32, uc.uc_mcontext)); BLANK(); #endif DEFINE(pbe_address, offsetof(struct pbe, address)); diff --git a/arch/x86/kernel/bios_uv.c b/arch/x86/kernel/bios_uv.c index f0dfe6f17e7eabbe41f90a8afd75c54766081fa2..2a0a2a3cac263a87edc38f12894185749a1b9dd5 100644 --- a/arch/x86/kernel/bios_uv.c +++ b/arch/x86/kernel/bios_uv.c @@ -69,10 +69,10 @@ s64 uv_bios_call_reentrant(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3, long sn_partition_id; EXPORT_SYMBOL_GPL(sn_partition_id); -long uv_coherency_id; -EXPORT_SYMBOL_GPL(uv_coherency_id); -long uv_region_size; -EXPORT_SYMBOL_GPL(uv_region_size); +long sn_coherency_id; +EXPORT_SYMBOL_GPL(sn_coherency_id); +long sn_region_size; +EXPORT_SYMBOL_GPL(sn_region_size); int uv_type; @@ -100,6 +100,56 @@ s64 uv_bios_get_sn_info(int fc, int *uvtype, long *partid, long *coher, return ret; } +int +uv_bios_mq_watchlist_alloc(int blade, unsigned long addr, unsigned int mq_size, + unsigned long *intr_mmr_offset) +{ + union uv_watchlist_u size_blade; + u64 watchlist; + s64 ret; + + size_blade.size = mq_size; + size_blade.blade = blade; + + /* + * bios returns watchlist number or negative error number. + */ + ret = (int)uv_bios_call_irqsave(UV_BIOS_WATCHLIST_ALLOC, addr, + size_blade.val, (u64)intr_mmr_offset, + (u64)&watchlist, 0); + if (ret < BIOS_STATUS_SUCCESS) + return ret; + + return watchlist; +} +EXPORT_SYMBOL_GPL(uv_bios_mq_watchlist_alloc); + +int +uv_bios_mq_watchlist_free(int blade, int watchlist_num) +{ + return (int)uv_bios_call_irqsave(UV_BIOS_WATCHLIST_FREE, + blade, watchlist_num, 0, 0, 0); +} +EXPORT_SYMBOL_GPL(uv_bios_mq_watchlist_free); + +s64 +uv_bios_change_memprotect(u64 paddr, u64 len, enum uv_memprotect perms) +{ + return uv_bios_call_irqsave(UV_BIOS_MEMPROTECT, paddr, len, + perms, 0, 0); +} +EXPORT_SYMBOL_GPL(uv_bios_change_memprotect); + +s64 +uv_bios_reserved_page_pa(u64 buf, u64 *cookie, u64 *addr, u64 *len) +{ + s64 ret; + + ret = uv_bios_call_irqsave(UV_BIOS_GET_PARTITION_ADDR, (u64)cookie, + (u64)addr, buf, (u64)len, 0); + return ret; +} +EXPORT_SYMBOL_GPL(uv_bios_reserved_page_pa); s64 uv_bios_freq_base(u64 clock_type, u64 *ticks_per_second) { diff --git a/arch/x86/kernel/check.c b/arch/x86/kernel/check.c new file mode 100644 index 0000000000000000000000000000000000000000..2ac0ab71412a59f9c9e0b025d88f0acf9e7e39ff --- /dev/null +++ b/arch/x86/kernel/check.c @@ -0,0 +1,161 @@ +#include +#include +#include +#include +#include +#include + +/* + * Some BIOSes seem to corrupt the low 64k of memory during events + * like suspend/resume and unplugging an HDMI cable. Reserve all + * remaining free memory in that area and fill it with a distinct + * pattern. + */ +#define MAX_SCAN_AREAS 8 + +static int __read_mostly memory_corruption_check = -1; + +static unsigned __read_mostly corruption_check_size = 64*1024; +static unsigned __read_mostly corruption_check_period = 60; /* seconds */ + +static struct e820entry scan_areas[MAX_SCAN_AREAS]; +static int num_scan_areas; + + +static __init int set_corruption_check(char *arg) +{ + char *end; + + memory_corruption_check = simple_strtol(arg, &end, 10); + + return (*end == 0) ? 0 : -EINVAL; +} +early_param("memory_corruption_check", set_corruption_check); + +static __init int set_corruption_check_period(char *arg) +{ + char *end; + + corruption_check_period = simple_strtoul(arg, &end, 10); + + return (*end == 0) ? 0 : -EINVAL; +} +early_param("memory_corruption_check_period", set_corruption_check_period); + +static __init int set_corruption_check_size(char *arg) +{ + char *end; + unsigned size; + + size = memparse(arg, &end); + + if (*end == '\0') + corruption_check_size = size; + + return (size == corruption_check_size) ? 0 : -EINVAL; +} +early_param("memory_corruption_check_size", set_corruption_check_size); + + +void __init setup_bios_corruption_check(void) +{ + u64 addr = PAGE_SIZE; /* assume first page is reserved anyway */ + + if (memory_corruption_check == -1) { + memory_corruption_check = +#ifdef CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK + 1 +#else + 0 +#endif + ; + } + + if (corruption_check_size == 0) + memory_corruption_check = 0; + + if (!memory_corruption_check) + return; + + corruption_check_size = round_up(corruption_check_size, PAGE_SIZE); + + while (addr < corruption_check_size && num_scan_areas < MAX_SCAN_AREAS) { + u64 size; + addr = find_e820_area_size(addr, &size, PAGE_SIZE); + + if (addr == 0) + break; + + if ((addr + size) > corruption_check_size) + size = corruption_check_size - addr; + + if (size == 0) + break; + + e820_update_range(addr, size, E820_RAM, E820_RESERVED); + scan_areas[num_scan_areas].addr = addr; + scan_areas[num_scan_areas].size = size; + num_scan_areas++; + + /* Assume we've already mapped this early memory */ + memset(__va(addr), 0, size); + + addr += size; + } + + printk(KERN_INFO "Scanning %d areas for low memory corruption\n", + num_scan_areas); + update_e820(); +} + + +void check_for_bios_corruption(void) +{ + int i; + int corruption = 0; + + if (!memory_corruption_check) + return; + + for (i = 0; i < num_scan_areas; i++) { + unsigned long *addr = __va(scan_areas[i].addr); + unsigned long size = scan_areas[i].size; + + for (; size; addr++, size -= sizeof(unsigned long)) { + if (!*addr) + continue; + printk(KERN_ERR "Corrupted low memory at %p (%lx phys) = %08lx\n", + addr, __pa(addr), *addr); + corruption = 1; + *addr = 0; + } + } + + WARN_ONCE(corruption, KERN_ERR "Memory corruption detected in low memory\n"); +} + +static void check_corruption(struct work_struct *dummy); +static DECLARE_DELAYED_WORK(bios_check_work, check_corruption); + +static void check_corruption(struct work_struct *dummy) +{ + check_for_bios_corruption(); + schedule_delayed_work(&bios_check_work, + round_jiffies_relative(corruption_check_period*HZ)); +} + +static int start_periodic_check_for_corruption(void) +{ + if (!memory_corruption_check || corruption_check_period == 0) + return 0; + + printk(KERN_INFO "Scanning for low memory corruption every %d seconds\n", + corruption_check_period); + + /* First time we run the checks right away */ + schedule_delayed_work(&bios_check_work, 0); + return 0; +} + +module_init(start_periodic_check_for_corruption); + diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile index 82ec6075c057b695cf6904a28a58fb8c60c37d7a..82db7f45e2de655430009b58fb776c11fc9b74de 100644 --- a/arch/x86/kernel/cpu/Makefile +++ b/arch/x86/kernel/cpu/Makefile @@ -2,8 +2,14 @@ # Makefile for x86-compatible CPU details and quirks # +# Don't trace early stages of a secondary CPU boot +ifdef CONFIG_FUNCTION_TRACER +CFLAGS_REMOVE_common.o = -pg +endif + obj-y := intel_cacheinfo.o addon_cpuid_features.o obj-y += proc.o capflags.o powerflags.o common.o +obj-y += vmware.o hypervisor.o obj-$(CONFIG_X86_32) += bugs.o cmpxchg.o obj-$(CONFIG_X86_64) += bugs_64.o diff --git a/arch/x86/kernel/cpu/addon_cpuid_features.c b/arch/x86/kernel/cpu/addon_cpuid_features.c index ef8f831af823a89530297919585e50c9a691e804..2cf23634b6d94d60e239d3f63cd9d4d21526b3fd 100644 --- a/arch/x86/kernel/cpu/addon_cpuid_features.c +++ b/arch/x86/kernel/cpu/addon_cpuid_features.c @@ -120,9 +120,17 @@ void __cpuinit detect_extended_topology(struct cpuinfo_x86 *c) c->cpu_core_id = phys_pkg_id(c->initial_apicid, ht_mask_width) & core_select_mask; c->phys_proc_id = phys_pkg_id(c->initial_apicid, core_plus_mask_width); + /* + * Reinit the apicid, now that we have extended initial_apicid. + */ + c->apicid = phys_pkg_id(c->initial_apicid, 0); #else c->cpu_core_id = phys_pkg_id(ht_mask_width) & core_select_mask; c->phys_proc_id = phys_pkg_id(core_plus_mask_width); + /* + * Reinit the apicid, now that we have extended initial_apicid. + */ + c->apicid = phys_pkg_id(0); #endif c->x86_max_cores = (core_level_siblings / smp_num_siblings); diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 8f1e31db2ad56d4f178881fff4d86b777349173c..7c878f6aa919182033001cdc6eaa4d1cbefc6543 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -283,9 +283,14 @@ static void __cpuinit early_init_amd(struct cpuinfo_x86 *c) { early_init_amd_mc(c); - /* c->x86_power is 8000_0007 edx. Bit 8 is constant TSC */ - if (c->x86_power & (1<<8)) + /* + * c->x86_power is 8000_0007 edx. Bit 8 is TSC runs at constant rate + * with P/T states and does not stop in deep C-states + */ + if (c->x86_power & (1 << 8)) { set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC); + set_cpu_cap(c, X86_FEATURE_NONSTOP_TSC); + } #ifdef CONFIG_X86_64 set_cpu_cap(c, X86_FEATURE_SYSCALL32); diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index b9c9ea0217a9b1fd4581f27fed692aaa6fe167ee..42e0853030cbe43275cc596c3f5896388dd30cae 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "cpu.h" @@ -703,6 +704,7 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c) detect_ht(c); #endif + init_hypervisor(c); /* * On SMP, boot_cpu_data holds the common feature set between * all CPUs; so make sure that we indicate which features are @@ -862,7 +864,7 @@ EXPORT_SYMBOL(_cpu_pda); struct desc_ptr idt_descr = { 256 * 16 - 1, (unsigned long) idt_table }; -char boot_cpu_stack[IRQSTACKSIZE] __page_aligned_bss; +static char boot_cpu_stack[IRQSTACKSIZE] __page_aligned_bss; void __cpuinit pda_init(int cpu) { @@ -903,8 +905,8 @@ void __cpuinit pda_init(int cpu) } } -char boot_exception_stacks[(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + - DEBUG_STKSZ] __page_aligned_bss; +static char boot_exception_stacks[(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + + DEBUG_STKSZ] __page_aligned_bss; extern asmlinkage void ignore_sysret(void); diff --git a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c index 8e48c5d4467df61d3652a39b06b85e7389143c54..88ea02dcb622fe5bf3ef4f2d7a28fc31bdf938e0 100644 --- a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c +++ b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -391,6 +392,7 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy, unsigned int next_perf_state = 0; /* Index into perf table */ unsigned int i; int result = 0; + struct power_trace it; dprintk("acpi_cpufreq_target %d (%d)\n", target_freq, policy->cpu); @@ -427,6 +429,8 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy, } } + trace_power_mark(&it, POWER_PSTATE, next_perf_state); + switch (data->cpu_feature) { case SYSTEM_INTEL_MSR_CAPABLE: cmd.type = SYSTEM_INTEL_MSR_CAPABLE; diff --git a/arch/x86/kernel/cpu/hypervisor.c b/arch/x86/kernel/cpu/hypervisor.c new file mode 100644 index 0000000000000000000000000000000000000000..fb5b86af0b017add1b7ed78ba869f3e5dd063a48 --- /dev/null +++ b/arch/x86/kernel/cpu/hypervisor.c @@ -0,0 +1,58 @@ +/* + * Common hypervisor code + * + * Copyright (C) 2008, VMware, Inc. + * Author : Alok N Kataria + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include +#include + +static inline void __cpuinit +detect_hypervisor_vendor(struct cpuinfo_x86 *c) +{ + if (vmware_platform()) { + c->x86_hyper_vendor = X86_HYPER_VENDOR_VMWARE; + } else { + c->x86_hyper_vendor = X86_HYPER_VENDOR_NONE; + } +} + +unsigned long get_hypervisor_tsc_freq(void) +{ + if (boot_cpu_data.x86_hyper_vendor == X86_HYPER_VENDOR_VMWARE) + return vmware_get_tsc_khz(); + return 0; +} + +static inline void __cpuinit +hypervisor_set_feature_bits(struct cpuinfo_x86 *c) +{ + if (boot_cpu_data.x86_hyper_vendor == X86_HYPER_VENDOR_VMWARE) { + vmware_set_feature_bits(c); + return; + } +} + +void __cpuinit init_hypervisor(struct cpuinfo_x86 *c) +{ + detect_hypervisor_vendor(c); + hypervisor_set_feature_bits(c); +} diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index cce0b6118d550e015a34c5e1b0f9bc60de1f8b3d..8ea6929e974c090142ed0d3744167792ce04d777 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include @@ -41,6 +40,16 @@ static void __cpuinit early_init_intel(struct cpuinfo_x86 *c) if (c->x86 == 15 && c->x86_cache_alignment == 64) c->x86_cache_alignment = 128; #endif + + /* + * c->x86_power is 8000_0007 edx. Bit 8 is TSC runs at constant rate + * with P/T states and does not stop in deep C-states + */ + if (c->x86_power & (1 << 8)) { + set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC); + set_cpu_cap(c, X86_FEATURE_NONSTOP_TSC); + } + } #ifdef CONFIG_X86_32 @@ -242,6 +251,13 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c) intel_workarounds(c); + /* + * Detect the extended topology information if available. This + * will reinitialise the initial_apicid which will be used + * in init_intel_cacheinfo() + */ + detect_extended_topology(c); + l2 = init_intel_cacheinfo(c); if (c->cpuid_level > 9) { unsigned eax = cpuid_eax(10); @@ -307,13 +323,8 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c) set_cpu_cap(c, X86_FEATURE_P4); if (c->x86 == 6) set_cpu_cap(c, X86_FEATURE_P3); - - if (cpu_has_bts) - ptrace_bts_init_intel(c); - #endif - detect_extended_topology(c); if (!cpu_has(c, X86_FEATURE_XTOPOLOGY)) { /* * let's use the legacy cpuid vector 0x1 and 0x4 for topology diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c index 3f46afbb1cf1946f52212ce96942429a9885cb04..68b5d8681cbb54597edf9021721745dbab19cb5c 100644 --- a/arch/x86/kernel/cpu/intel_cacheinfo.c +++ b/arch/x86/kernel/cpu/intel_cacheinfo.c @@ -644,20 +644,17 @@ static inline ssize_t show_shared_cpu_list(struct _cpuid4_info *leaf, char *buf) return show_shared_cpu_map_func(leaf, 1, buf); } -static ssize_t show_type(struct _cpuid4_info *this_leaf, char *buf) { - switch(this_leaf->eax.split.type) { - case CACHE_TYPE_DATA: +static ssize_t show_type(struct _cpuid4_info *this_leaf, char *buf) +{ + switch (this_leaf->eax.split.type) { + case CACHE_TYPE_DATA: return sprintf(buf, "Data\n"); - break; - case CACHE_TYPE_INST: + case CACHE_TYPE_INST: return sprintf(buf, "Instruction\n"); - break; - case CACHE_TYPE_UNIFIED: + case CACHE_TYPE_UNIFIED: return sprintf(buf, "Unified\n"); - break; - default: + default: return sprintf(buf, "Unknown\n"); - break; } } diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd_64.c b/arch/x86/kernel/cpu/mcheck/mce_amd_64.c index 5eb390a4b2e9159d980fcfcbc68f8d1d4f42c258..748c8f9e7a0527d1e6f6298852113995f033350b 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_amd_64.c +++ b/arch/x86/kernel/cpu/mcheck/mce_amd_64.c @@ -237,7 +237,7 @@ asmlinkage void mce_threshold_interrupt(void) } } out: - add_pda(irq_threshold_count, 1); + inc_irq_stat(irq_threshold_count); irq_exit(); } diff --git a/arch/x86/kernel/cpu/mcheck/mce_intel_64.c b/arch/x86/kernel/cpu/mcheck/mce_intel_64.c index c17eaf5dd6dd4ea820f5057e14f2beb861821ec1..4b48f251fd39ed540f99a2c91b6e7d66d93e1b56 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_intel_64.c +++ b/arch/x86/kernel/cpu/mcheck/mce_intel_64.c @@ -26,7 +26,7 @@ asmlinkage void smp_thermal_interrupt(void) if (therm_throt_process(msr_val & 1)) mce_log_therm_throt_event(smp_processor_id(), msr_val); - add_pda(irq_thermal_count, 1); + inc_irq_stat(irq_thermal_count); irq_exit(); } diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c index c78c04821ea18a58266b812fef480aa0b5ec0fbb..1159e269e596bc05d9b82d3ed633a434c67d1649 100644 --- a/arch/x86/kernel/cpu/mtrr/main.c +++ b/arch/x86/kernel/cpu/mtrr/main.c @@ -803,6 +803,7 @@ x86_get_mtrr_mem_range(struct res_range *range, int nr_range, } static struct res_range __initdata range[RANGE_NUM]; +static int __initdata nr_range; #ifdef CONFIG_MTRR_SANITIZER @@ -1206,39 +1207,43 @@ struct mtrr_cleanup_result { #define PSHIFT (PAGE_SHIFT - 10) static struct mtrr_cleanup_result __initdata result[NUM_RESULT]; -static struct res_range __initdata range_new[RANGE_NUM]; static unsigned long __initdata min_loss_pfn[RANGE_NUM]; -static int __init mtrr_cleanup(unsigned address_bits) +static void __init print_out_mtrr_range_state(void) { - unsigned long extra_remove_base, extra_remove_size; - unsigned long base, size, def, dummy; - mtrr_type type; - int nr_range, nr_range_new; - u64 chunk_size, gran_size; - unsigned long range_sums, range_sums_new; - int index_good; - int num_reg_good; int i; + char start_factor = 'K', size_factor = 'K'; + unsigned long start_base, size_base; + mtrr_type type; - /* extra one for all 0 */ - int num[MTRR_NUM_TYPES + 1]; + for (i = 0; i < num_var_ranges; i++) { - if (!is_cpu(INTEL) || enable_mtrr_cleanup < 1) - return 0; - rdmsr(MTRRdefType_MSR, def, dummy); - def &= 0xff; - if (def != MTRR_TYPE_UNCACHABLE) - return 0; + size_base = range_state[i].size_pfn << (PAGE_SHIFT - 10); + if (!size_base) + continue; - /* get it and store it aside */ - memset(range_state, 0, sizeof(range_state)); - for (i = 0; i < num_var_ranges; i++) { - mtrr_if->get(i, &base, &size, &type); - range_state[i].base_pfn = base; - range_state[i].size_pfn = size; - range_state[i].type = type; + size_base = to_size_factor(size_base, &size_factor), + start_base = range_state[i].base_pfn << (PAGE_SHIFT - 10); + start_base = to_size_factor(start_base, &start_factor), + type = range_state[i].type; + + printk(KERN_DEBUG "reg %d, base: %ld%cB, range: %ld%cB, type %s\n", + i, start_base, start_factor, + size_base, size_factor, + (type == MTRR_TYPE_UNCACHABLE) ? "UC" : + ((type == MTRR_TYPE_WRPROT) ? "WP" : + ((type == MTRR_TYPE_WRBACK) ? "WB" : "Other")) + ); } +} + +static int __init mtrr_need_cleanup(void) +{ + int i; + mtrr_type type; + unsigned long size; + /* extra one for all 0 */ + int num[MTRR_NUM_TYPES + 1]; /* check entries number */ memset(num, 0, sizeof(num)); @@ -1263,29 +1268,133 @@ static int __init mtrr_cleanup(unsigned address_bits) num_var_ranges - num[MTRR_NUM_TYPES]) return 0; - /* print original var MTRRs at first, for debugging: */ - printk(KERN_DEBUG "original variable MTRRs\n"); - for (i = 0; i < num_var_ranges; i++) { - char start_factor = 'K', size_factor = 'K'; - unsigned long start_base, size_base; + return 1; +} - size_base = range_state[i].size_pfn << (PAGE_SHIFT - 10); - if (!size_base) - continue; +static unsigned long __initdata range_sums; +static void __init mtrr_calc_range_state(u64 chunk_size, u64 gran_size, + unsigned long extra_remove_base, + unsigned long extra_remove_size, + int i) +{ + int num_reg; + static struct res_range range_new[RANGE_NUM]; + static int nr_range_new; + unsigned long range_sums_new; + + /* convert ranges to var ranges state */ + num_reg = x86_setup_var_mtrrs(range, nr_range, + chunk_size, gran_size); + + /* we got new setting in range_state, check it */ + memset(range_new, 0, sizeof(range_new)); + nr_range_new = x86_get_mtrr_mem_range(range_new, 0, + extra_remove_base, extra_remove_size); + range_sums_new = sum_ranges(range_new, nr_range_new); + + result[i].chunk_sizek = chunk_size >> 10; + result[i].gran_sizek = gran_size >> 10; + result[i].num_reg = num_reg; + if (range_sums < range_sums_new) { + result[i].lose_cover_sizek = + (range_sums_new - range_sums) << PSHIFT; + result[i].bad = 1; + } else + result[i].lose_cover_sizek = + (range_sums - range_sums_new) << PSHIFT; - size_base = to_size_factor(size_base, &size_factor), - start_base = range_state[i].base_pfn << (PAGE_SHIFT - 10); - start_base = to_size_factor(start_base, &start_factor), - type = range_state[i].type; + /* double check it */ + if (!result[i].bad && !result[i].lose_cover_sizek) { + if (nr_range_new != nr_range || + memcmp(range, range_new, sizeof(range))) + result[i].bad = 1; + } - printk(KERN_DEBUG "reg %d, base: %ld%cB, range: %ld%cB, type %s\n", - i, start_base, start_factor, - size_base, size_factor, - (type == MTRR_TYPE_UNCACHABLE) ? "UC" : - ((type == MTRR_TYPE_WRPROT) ? "WP" : - ((type == MTRR_TYPE_WRBACK) ? "WB" : "Other")) - ); + if (!result[i].bad && (range_sums - range_sums_new < + min_loss_pfn[num_reg])) { + min_loss_pfn[num_reg] = + range_sums - range_sums_new; } +} + +static void __init mtrr_print_out_one_result(int i) +{ + char gran_factor, chunk_factor, lose_factor; + unsigned long gran_base, chunk_base, lose_base; + + gran_base = to_size_factor(result[i].gran_sizek, &gran_factor), + chunk_base = to_size_factor(result[i].chunk_sizek, &chunk_factor), + lose_base = to_size_factor(result[i].lose_cover_sizek, &lose_factor), + printk(KERN_INFO "%sgran_size: %ld%c \tchunk_size: %ld%c \t", + result[i].bad ? "*BAD*" : " ", + gran_base, gran_factor, chunk_base, chunk_factor); + printk(KERN_CONT "num_reg: %d \tlose cover RAM: %s%ld%c\n", + result[i].num_reg, result[i].bad ? "-" : "", + lose_base, lose_factor); +} + +static int __init mtrr_search_optimal_index(void) +{ + int i; + int num_reg_good; + int index_good; + + if (nr_mtrr_spare_reg >= num_var_ranges) + nr_mtrr_spare_reg = num_var_ranges - 1; + num_reg_good = -1; + for (i = num_var_ranges - nr_mtrr_spare_reg; i > 0; i--) { + if (!min_loss_pfn[i]) + num_reg_good = i; + } + + index_good = -1; + if (num_reg_good != -1) { + for (i = 0; i < NUM_RESULT; i++) { + if (!result[i].bad && + result[i].num_reg == num_reg_good && + !result[i].lose_cover_sizek) { + index_good = i; + break; + } + } + } + + return index_good; +} + + +static int __init mtrr_cleanup(unsigned address_bits) +{ + unsigned long extra_remove_base, extra_remove_size; + unsigned long base, size, def, dummy; + mtrr_type type; + u64 chunk_size, gran_size; + int index_good; + int i; + + if (!is_cpu(INTEL) || enable_mtrr_cleanup < 1) + return 0; + rdmsr(MTRRdefType_MSR, def, dummy); + def &= 0xff; + if (def != MTRR_TYPE_UNCACHABLE) + return 0; + + /* get it and store it aside */ + memset(range_state, 0, sizeof(range_state)); + for (i = 0; i < num_var_ranges; i++) { + mtrr_if->get(i, &base, &size, &type); + range_state[i].base_pfn = base; + range_state[i].size_pfn = size; + range_state[i].type = type; + } + + /* check if we need handle it and can handle it */ + if (!mtrr_need_cleanup()) + return 0; + + /* print original var MTRRs at first, for debugging: */ + printk(KERN_DEBUG "original variable MTRRs\n"); + print_out_mtrr_range_state(); memset(range, 0, sizeof(range)); extra_remove_size = 0; @@ -1309,176 +1418,64 @@ static int __init mtrr_cleanup(unsigned address_bits) range_sums >> (20 - PAGE_SHIFT)); if (mtrr_chunk_size && mtrr_gran_size) { - int num_reg; - char gran_factor, chunk_factor, lose_factor; - unsigned long gran_base, chunk_base, lose_base; - - debug_print++; - /* convert ranges to var ranges state */ - num_reg = x86_setup_var_mtrrs(range, nr_range, mtrr_chunk_size, - mtrr_gran_size); + i = 0; + mtrr_calc_range_state(mtrr_chunk_size, mtrr_gran_size, + extra_remove_base, extra_remove_size, i); - /* we got new setting in range_state, check it */ - memset(range_new, 0, sizeof(range_new)); - nr_range_new = x86_get_mtrr_mem_range(range_new, 0, - extra_remove_base, - extra_remove_size); - range_sums_new = sum_ranges(range_new, nr_range_new); + mtrr_print_out_one_result(i); - i = 0; - result[i].chunk_sizek = mtrr_chunk_size >> 10; - result[i].gran_sizek = mtrr_gran_size >> 10; - result[i].num_reg = num_reg; - if (range_sums < range_sums_new) { - result[i].lose_cover_sizek = - (range_sums_new - range_sums) << PSHIFT; - result[i].bad = 1; - } else - result[i].lose_cover_sizek = - (range_sums - range_sums_new) << PSHIFT; - - gran_base = to_size_factor(result[i].gran_sizek, &gran_factor), - chunk_base = to_size_factor(result[i].chunk_sizek, &chunk_factor), - lose_base = to_size_factor(result[i].lose_cover_sizek, &lose_factor), - printk(KERN_INFO "%sgran_size: %ld%c \tchunk_size: %ld%c \t", - result[i].bad?"*BAD*":" ", - gran_base, gran_factor, chunk_base, chunk_factor); - printk(KERN_CONT "num_reg: %d \tlose cover RAM: %s%ld%c\n", - result[i].num_reg, result[i].bad?"-":"", - lose_base, lose_factor); if (!result[i].bad) { set_var_mtrr_all(address_bits); return 1; } printk(KERN_INFO "invalid mtrr_gran_size or mtrr_chunk_size, " "will find optimal one\n"); - debug_print--; - memset(result, 0, sizeof(result[0])); } i = 0; memset(min_loss_pfn, 0xff, sizeof(min_loss_pfn)); memset(result, 0, sizeof(result)); for (gran_size = (1ULL<<16); gran_size < (1ULL<<32); gran_size <<= 1) { - char gran_factor; - unsigned long gran_base; - - if (debug_print) - gran_base = to_size_factor(gran_size >> 10, &gran_factor); for (chunk_size = gran_size; chunk_size < (1ULL<<32); chunk_size <<= 1) { - int num_reg; - if (debug_print) { - char chunk_factor; - unsigned long chunk_base; - - chunk_base = to_size_factor(chunk_size>>10, &chunk_factor), - printk(KERN_INFO "\n"); - printk(KERN_INFO "gran_size: %ld%c chunk_size: %ld%c \n", - gran_base, gran_factor, chunk_base, chunk_factor); - } if (i >= NUM_RESULT) continue; - /* convert ranges to var ranges state */ - num_reg = x86_setup_var_mtrrs(range, nr_range, - chunk_size, gran_size); - - /* we got new setting in range_state, check it */ - memset(range_new, 0, sizeof(range_new)); - nr_range_new = x86_get_mtrr_mem_range(range_new, 0, - extra_remove_base, extra_remove_size); - range_sums_new = sum_ranges(range_new, nr_range_new); - - result[i].chunk_sizek = chunk_size >> 10; - result[i].gran_sizek = gran_size >> 10; - result[i].num_reg = num_reg; - if (range_sums < range_sums_new) { - result[i].lose_cover_sizek = - (range_sums_new - range_sums) << PSHIFT; - result[i].bad = 1; - } else - result[i].lose_cover_sizek = - (range_sums - range_sums_new) << PSHIFT; - - /* double check it */ - if (!result[i].bad && !result[i].lose_cover_sizek) { - if (nr_range_new != nr_range || - memcmp(range, range_new, sizeof(range))) - result[i].bad = 1; + mtrr_calc_range_state(chunk_size, gran_size, + extra_remove_base, extra_remove_size, i); + if (debug_print) { + mtrr_print_out_one_result(i); + printk(KERN_INFO "\n"); } - if (!result[i].bad && (range_sums - range_sums_new < - min_loss_pfn[num_reg])) { - min_loss_pfn[num_reg] = - range_sums - range_sums_new; - } i++; } } - /* print out all */ - for (i = 0; i < NUM_RESULT; i++) { - char gran_factor, chunk_factor, lose_factor; - unsigned long gran_base, chunk_base, lose_base; - - gran_base = to_size_factor(result[i].gran_sizek, &gran_factor), - chunk_base = to_size_factor(result[i].chunk_sizek, &chunk_factor), - lose_base = to_size_factor(result[i].lose_cover_sizek, &lose_factor), - printk(KERN_INFO "%sgran_size: %ld%c \tchunk_size: %ld%c \t", - result[i].bad?"*BAD*":" ", - gran_base, gran_factor, chunk_base, chunk_factor); - printk(KERN_CONT "num_reg: %d \tlose cover RAM: %s%ld%c\n", - result[i].num_reg, result[i].bad?"-":"", - lose_base, lose_factor); - } - /* try to find the optimal index */ - if (nr_mtrr_spare_reg >= num_var_ranges) - nr_mtrr_spare_reg = num_var_ranges - 1; - num_reg_good = -1; - for (i = num_var_ranges - nr_mtrr_spare_reg; i > 0; i--) { - if (!min_loss_pfn[i]) - num_reg_good = i; - } - - index_good = -1; - if (num_reg_good != -1) { - for (i = 0; i < NUM_RESULT; i++) { - if (!result[i].bad && - result[i].num_reg == num_reg_good && - !result[i].lose_cover_sizek) { - index_good = i; - break; - } - } - } + index_good = mtrr_search_optimal_index(); if (index_good != -1) { - char gran_factor, chunk_factor, lose_factor; - unsigned long gran_base, chunk_base, lose_base; - printk(KERN_INFO "Found optimal setting for mtrr clean up\n"); i = index_good; - gran_base = to_size_factor(result[i].gran_sizek, &gran_factor), - chunk_base = to_size_factor(result[i].chunk_sizek, &chunk_factor), - lose_base = to_size_factor(result[i].lose_cover_sizek, &lose_factor), - printk(KERN_INFO "gran_size: %ld%c \tchunk_size: %ld%c \t", - gran_base, gran_factor, chunk_base, chunk_factor); - printk(KERN_CONT "num_reg: %d \tlose RAM: %ld%c\n", - result[i].num_reg, lose_base, lose_factor); + mtrr_print_out_one_result(i); + /* convert ranges to var ranges state */ chunk_size = result[i].chunk_sizek; chunk_size <<= 10; gran_size = result[i].gran_sizek; gran_size <<= 10; - debug_print++; x86_setup_var_mtrrs(range, nr_range, chunk_size, gran_size); - debug_print--; set_var_mtrr_all(address_bits); + printk(KERN_DEBUG "New variable MTRRs\n"); + print_out_mtrr_range_state(); return 1; + } else { + /* print out all */ + for (i = 0; i < NUM_RESULT; i++) + mtrr_print_out_one_result(i); } printk(KERN_INFO "mtrr_cleanup: can not find optimal value\n"); @@ -1562,7 +1559,6 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn) { unsigned long i, base, size, highest_pfn = 0, def, dummy; mtrr_type type; - int nr_range; u64 total_trim_size; /* extra one for all 0 */ diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c new file mode 100644 index 0000000000000000000000000000000000000000..284c399e32346f61fe6e925b0afbf4ec7e143ca7 --- /dev/null +++ b/arch/x86/kernel/cpu/vmware.c @@ -0,0 +1,112 @@ +/* + * VMware Detection code. + * + * Copyright (C) 2008, VMware, Inc. + * Author : Alok N Kataria + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include +#include + +#define CPUID_VMWARE_INFO_LEAF 0x40000000 +#define VMWARE_HYPERVISOR_MAGIC 0x564D5868 +#define VMWARE_HYPERVISOR_PORT 0x5658 + +#define VMWARE_PORT_CMD_GETVERSION 10 +#define VMWARE_PORT_CMD_GETHZ 45 + +#define VMWARE_PORT(cmd, eax, ebx, ecx, edx) \ + __asm__("inl (%%dx)" : \ + "=a"(eax), "=c"(ecx), "=d"(edx), "=b"(ebx) : \ + "0"(VMWARE_HYPERVISOR_MAGIC), \ + "1"(VMWARE_PORT_CMD_##cmd), \ + "2"(VMWARE_HYPERVISOR_PORT), "3"(UINT_MAX) : \ + "memory"); + +static inline int __vmware_platform(void) +{ + uint32_t eax, ebx, ecx, edx; + VMWARE_PORT(GETVERSION, eax, ebx, ecx, edx); + return eax != (uint32_t)-1 && ebx == VMWARE_HYPERVISOR_MAGIC; +} + +static unsigned long __vmware_get_tsc_khz(void) +{ + uint64_t tsc_hz; + uint32_t eax, ebx, ecx, edx; + + VMWARE_PORT(GETHZ, eax, ebx, ecx, edx); + + if (ebx == UINT_MAX) + return 0; + tsc_hz = eax | (((uint64_t)ebx) << 32); + do_div(tsc_hz, 1000); + BUG_ON(tsc_hz >> 32); + return tsc_hz; +} + +/* + * While checking the dmi string infomation, just checking the product + * serial key should be enough, as this will always have a VMware + * specific string when running under VMware hypervisor. + */ +int vmware_platform(void) +{ + if (cpu_has_hypervisor) { + unsigned int eax, ebx, ecx, edx; + char hyper_vendor_id[13]; + + cpuid(CPUID_VMWARE_INFO_LEAF, &eax, &ebx, &ecx, &edx); + memcpy(hyper_vendor_id + 0, &ebx, 4); + memcpy(hyper_vendor_id + 4, &ecx, 4); + memcpy(hyper_vendor_id + 8, &edx, 4); + hyper_vendor_id[12] = '\0'; + if (!strcmp(hyper_vendor_id, "VMwareVMware")) + return 1; + } else if (dmi_available && dmi_name_in_serial("VMware") && + __vmware_platform()) + return 1; + + return 0; +} + +unsigned long vmware_get_tsc_khz(void) +{ + BUG_ON(!vmware_platform()); + return __vmware_get_tsc_khz(); +} + +/* + * VMware hypervisor takes care of exporting a reliable TSC to the guest. + * Still, due to timing difference when running on virtual cpus, the TSC can + * be marked as unstable in some cases. For example, the TSC sync check at + * bootup can fail due to a marginal offset between vcpus' TSCs (though the + * TSCs do not drift from each other). Also, the ACPI PM timer clocksource + * is not suitable as a watchdog when running on a hypervisor because the + * kernel may miss a wrap of the counter if the vcpu is descheduled for a + * long time. To skip these checks at runtime we set these capability bits, + * so that the kernel could just trust the hypervisor with providing a + * reliable virtual TSC that is suitable for timekeeping. + */ +void __cpuinit vmware_set_feature_bits(struct cpuinfo_x86 *c) +{ + set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC); + set_cpu_cap(c, X86_FEATURE_TSC_RELIABLE); +} diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c index 2685538179097a1e8e073ebf07cd49e898ef4f6e..d84a852e4cd76f4983bc617d674c7e59c0b3632d 100644 --- a/arch/x86/kernel/crash.c +++ b/arch/x86/kernel/crash.c @@ -29,34 +29,17 @@ #include -/* This keeps a track of which one is crashing cpu. */ -static int crashing_cpu; #if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC) -static atomic_t waiting_for_crash_ipi; -static int crash_nmi_callback(struct notifier_block *self, - unsigned long val, void *data) +static void kdump_nmi_callback(int cpu, struct die_args *args) { struct pt_regs *regs; #ifdef CONFIG_X86_32 struct pt_regs fixed_regs; #endif - int cpu; - if (val != DIE_NMI_IPI) - return NOTIFY_OK; - - regs = ((struct die_args *)data)->regs; - cpu = raw_smp_processor_id(); - - /* Don't do anything if this handler is invoked on crashing cpu. - * Otherwise, system will completely hang. Crashing cpu can get - * an NMI if system was initially booted with nmi_watchdog parameter. - */ - if (cpu == crashing_cpu) - return NOTIFY_STOP; - local_irq_disable(); + regs = args->regs; #ifdef CONFIG_X86_32 if (!user_mode_vm(regs)) { @@ -65,54 +48,19 @@ static int crash_nmi_callback(struct notifier_block *self, } #endif crash_save_cpu(regs, cpu); - disable_local_APIC(); - atomic_dec(&waiting_for_crash_ipi); - /* Assume hlt works */ - halt(); - for (;;) - cpu_relax(); - - return 1; -} -static void smp_send_nmi_allbutself(void) -{ - cpumask_t mask = cpu_online_map; - cpu_clear(safe_smp_processor_id(), mask); - if (!cpus_empty(mask)) - send_IPI_mask(mask, NMI_VECTOR); + disable_local_APIC(); } -static struct notifier_block crash_nmi_nb = { - .notifier_call = crash_nmi_callback, -}; - -static void nmi_shootdown_cpus(void) +static void kdump_nmi_shootdown_cpus(void) { - unsigned long msecs; - - atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); - /* Would it be better to replace the trap vector here? */ - if (register_die_notifier(&crash_nmi_nb)) - return; /* return what? */ - /* Ensure the new callback function is set before sending - * out the NMI - */ - wmb(); + nmi_shootdown_cpus(kdump_nmi_callback); - smp_send_nmi_allbutself(); - - msecs = 1000; /* Wait at most a second for the other cpus to stop */ - while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) { - mdelay(1); - msecs--; - } - - /* Leave the nmi callback set */ disable_local_APIC(); } + #else -static void nmi_shootdown_cpus(void) +static void kdump_nmi_shootdown_cpus(void) { /* There are no cpus to shootdown */ } @@ -131,9 +79,7 @@ void native_machine_crash_shutdown(struct pt_regs *regs) /* The kernel is broken so disable interrupts */ local_irq_disable(); - /* Make a note of crashing cpu. Will be used in NMI callback.*/ - crashing_cpu = safe_smp_processor_id(); - nmi_shootdown_cpus(); + kdump_nmi_shootdown_cpus(); lapic_shutdown(); #if defined(CONFIG_X86_IO_APIC) disable_IO_APIC(); diff --git a/arch/x86/kernel/ds.c b/arch/x86/kernel/ds.c index a2d1176c38ee0d59b3e47925a79d8aebdff73d20..da91701a2348cd512531716598453ece7ef8cca6 100644 --- a/arch/x86/kernel/ds.c +++ b/arch/x86/kernel/ds.c @@ -6,14 +6,13 @@ * precise-event based sampling (PEBS). * * It manages: - * - per-thread and per-cpu allocation of BTS and PEBS - * - buffer memory allocation (optional) - * - buffer overflow handling + * - DS and BTS hardware configuration + * - buffer overflow handling (to be done) * - buffer access * - * It assumes: - * - get_task_struct on all parameter tasks - * - current is allowed to trace parameter tasks + * It does not do: + * - security checking (is the caller allowed to trace the task) + * - buffer allocation (memory accounting) * * * Copyright (C) 2007-2008 Intel Corporation. @@ -28,22 +27,69 @@ #include #include #include +#include /* * The configuration for a particular DS hardware implementation. */ struct ds_configuration { - /* the size of the DS structure in bytes */ - unsigned char sizeof_ds; - /* the size of one pointer-typed field in the DS structure in bytes; - this covers the first 8 fields related to buffer management. */ + /* the name of the configuration */ + const char *name; + /* the size of one pointer-typed field in the DS structure and + in the BTS and PEBS buffers in bytes; + this covers the first 8 DS fields related to buffer management. */ unsigned char sizeof_field; /* the size of a BTS/PEBS record in bytes */ unsigned char sizeof_rec[2]; + /* a series of bit-masks to control various features indexed + * by enum ds_feature */ + unsigned long ctl[dsf_ctl_max]; }; -static struct ds_configuration ds_cfg; +static DEFINE_PER_CPU(struct ds_configuration, ds_cfg_array); +#define ds_cfg per_cpu(ds_cfg_array, smp_processor_id()) + +#define MAX_SIZEOF_DS (12 * 8) /* maximal size of a DS configuration */ +#define MAX_SIZEOF_BTS (3 * 8) /* maximal size of a BTS record */ +#define DS_ALIGNMENT (1 << 3) /* BTS and PEBS buffer alignment */ + +#define BTS_CONTROL \ + (ds_cfg.ctl[dsf_bts] | ds_cfg.ctl[dsf_bts_kernel] | ds_cfg.ctl[dsf_bts_user] |\ + ds_cfg.ctl[dsf_bts_overflow]) + + +/* + * A BTS or PEBS tracer. + * + * This holds the configuration of the tracer and serves as a handle + * to identify tracers. + */ +struct ds_tracer { + /* the DS context (partially) owned by this tracer */ + struct ds_context *context; + /* the buffer provided on ds_request() and its size in bytes */ + void *buffer; + size_t size; +}; + +struct bts_tracer { + /* the common DS part */ + struct ds_tracer ds; + /* the trace including the DS configuration */ + struct bts_trace trace; + /* buffer overflow notification function */ + bts_ovfl_callback_t ovfl; +}; + +struct pebs_tracer { + /* the common DS part */ + struct ds_tracer ds; + /* the trace including the DS configuration */ + struct pebs_trace trace; + /* buffer overflow notification function */ + pebs_ovfl_callback_t ovfl; +}; /* * Debug Store (DS) save area configuration (see Intel64 and IA32 @@ -109,32 +155,9 @@ static inline void ds_set(unsigned char *base, enum ds_qualifier qual, /* - * Locking is done only for allocating BTS or PEBS resources and for - * guarding context and buffer memory allocation. - * - * Most functions require the current task to own the ds context part - * they are going to access. All the locking is done when validating - * access to the context. + * Locking is done only for allocating BTS or PEBS resources. */ -static spinlock_t ds_lock = __SPIN_LOCK_UNLOCKED(ds_lock); - -/* - * Validate that the current task is allowed to access the BTS/PEBS - * buffer of the parameter task. - * - * Returns 0, if access is granted; -Eerrno, otherwise. - */ -static inline int ds_validate_access(struct ds_context *context, - enum ds_qualifier qual) -{ - if (!context) - return -EPERM; - - if (context->owner[qual] == current) - return 0; - - return -EPERM; -} +static DEFINE_SPINLOCK(ds_lock); /* @@ -150,27 +173,32 @@ static inline int ds_validate_access(struct ds_context *context, * >0 number of per-thread tracers * <0 number of per-cpu tracers * - * The below functions to get and put tracers and to check the - * allocation type require the ds_lock to be held by the caller. - * * Tracers essentially gives the number of ds contexts for a certain * type of allocation. */ -static long tracers; +static atomic_t tracers = ATOMIC_INIT(0); static inline void get_tracer(struct task_struct *task) { - tracers += (task ? 1 : -1); + if (task) + atomic_inc(&tracers); + else + atomic_dec(&tracers); } static inline void put_tracer(struct task_struct *task) { - tracers -= (task ? 1 : -1); + if (task) + atomic_dec(&tracers); + else + atomic_inc(&tracers); } static inline int check_tracer(struct task_struct *task) { - return (task ? (tracers >= 0) : (tracers <= 0)); + return task ? + (atomic_read(&tracers) >= 0) : + (atomic_read(&tracers) <= 0); } @@ -183,99 +211,70 @@ static inline int check_tracer(struct task_struct *task) * * Contexts are use-counted. They are allocated on first access and * deallocated when the last user puts the context. - * - * We distinguish between an allocating and a non-allocating get of a - * context: - * - the allocating get is used for requesting BTS/PEBS resources. It - * requires the caller to hold the global ds_lock. - * - the non-allocating get is used for all other cases. A - * non-existing context indicates an error. It acquires and releases - * the ds_lock itself for obtaining the context. - * - * A context and its DS configuration are allocated and deallocated - * together. A context always has a DS configuration of the - * appropriate size. - */ -static DEFINE_PER_CPU(struct ds_context *, system_context); - -#define this_system_context per_cpu(system_context, smp_processor_id()) - -/* - * Returns the pointer to the parameter task's context or to the - * system-wide context, if task is NULL. - * - * Increases the use count of the returned context, if not NULL. */ -static inline struct ds_context *ds_get_context(struct task_struct *task) -{ - struct ds_context *context; - unsigned long irq; +struct ds_context { + /* pointer to the DS configuration; goes into MSR_IA32_DS_AREA */ + unsigned char ds[MAX_SIZEOF_DS]; + /* the owner of the BTS and PEBS configuration, respectively */ + struct bts_tracer *bts_master; + struct pebs_tracer *pebs_master; + /* use count */ + unsigned long count; + /* a pointer to the context location inside the thread_struct + * or the per_cpu context array */ + struct ds_context **this; + /* a pointer to the task owning this context, or NULL, if the + * context is owned by a cpu */ + struct task_struct *task; +}; - spin_lock_irqsave(&ds_lock, irq); +static DEFINE_PER_CPU(struct ds_context *, system_context_array); - context = (task ? task->thread.ds_ctx : this_system_context); - if (context) - context->count++; +#define system_context per_cpu(system_context_array, smp_processor_id()) - spin_unlock_irqrestore(&ds_lock, irq); - - return context; -} -/* - * Same as ds_get_context, but allocates the context and it's DS - * structure, if necessary; returns NULL; if out of memory. - */ -static inline struct ds_context *ds_alloc_context(struct task_struct *task) +static inline struct ds_context *ds_get_context(struct task_struct *task) { struct ds_context **p_context = - (task ? &task->thread.ds_ctx : &this_system_context); - struct ds_context *context = *p_context; + (task ? &task->thread.ds_ctx : &system_context); + struct ds_context *context = NULL; + struct ds_context *new_context = NULL; unsigned long irq; - if (!context) { - context = kzalloc(sizeof(*context), GFP_KERNEL); - if (!context) - return NULL; - - context->ds = kzalloc(ds_cfg.sizeof_ds, GFP_KERNEL); - if (!context->ds) { - kfree(context); - return NULL; - } + /* Chances are small that we already have a context. */ + new_context = kzalloc(sizeof(*new_context), GFP_KERNEL); + if (!new_context) + return NULL; - spin_lock_irqsave(&ds_lock, irq); + spin_lock_irqsave(&ds_lock, irq); - if (*p_context) { - kfree(context->ds); - kfree(context); + context = *p_context; + if (!context) { + context = new_context; - context = *p_context; - } else { - *p_context = context; + context->this = p_context; + context->task = task; + context->count = 0; - context->this = p_context; - context->task = task; + if (task) + set_tsk_thread_flag(task, TIF_DS_AREA_MSR); - if (task) - set_tsk_thread_flag(task, TIF_DS_AREA_MSR); + if (!task || (task == current)) + wrmsrl(MSR_IA32_DS_AREA, (unsigned long)context->ds); - if (!task || (task == current)) - wrmsrl(MSR_IA32_DS_AREA, - (unsigned long)context->ds); - } - spin_unlock_irqrestore(&ds_lock, irq); + *p_context = context; } context->count++; + spin_unlock_irqrestore(&ds_lock, irq); + + if (context != new_context) + kfree(new_context); + return context; } -/* - * Decreases the use count of the parameter context, if not NULL. - * Deallocates the context, if the use count reaches zero. - */ static inline void ds_put_context(struct ds_context *context) { unsigned long irq; @@ -285,8 +284,10 @@ static inline void ds_put_context(struct ds_context *context) spin_lock_irqsave(&ds_lock, irq); - if (--context->count) - goto out; + if (--context->count) { + spin_unlock_irqrestore(&ds_lock, irq); + return; + } *(context->this) = NULL; @@ -296,135 +297,263 @@ static inline void ds_put_context(struct ds_context *context) if (!context->task || (context->task == current)) wrmsrl(MSR_IA32_DS_AREA, 0); - put_tracer(context->task); + spin_unlock_irqrestore(&ds_lock, irq); - /* free any leftover buffers from tracers that did not - * deallocate them properly. */ - kfree(context->buffer[ds_bts]); - kfree(context->buffer[ds_pebs]); - kfree(context->ds); kfree(context); - out: - spin_unlock_irqrestore(&ds_lock, irq); } /* - * Handle a buffer overflow + * Call the tracer's callback on a buffer overflow. * - * task: the task whose buffers are overflowing; - * NULL for a buffer overflow on the current cpu * context: the ds context * qual: the buffer type */ -static void ds_overflow(struct task_struct *task, struct ds_context *context, - enum ds_qualifier qual) +static void ds_overflow(struct ds_context *context, enum ds_qualifier qual) { - if (!context) - return; - - if (context->callback[qual]) - (*context->callback[qual])(task); - - /* todo: do some more overflow handling */ + switch (qual) { + case ds_bts: + if (context->bts_master && + context->bts_master->ovfl) + context->bts_master->ovfl(context->bts_master); + break; + case ds_pebs: + if (context->pebs_master && + context->pebs_master->ovfl) + context->pebs_master->ovfl(context->pebs_master); + break; + } } /* - * Allocate a non-pageable buffer of the parameter size. - * Checks the memory and the locked memory rlimit. + * Write raw data into the BTS or PEBS buffer. * - * Returns the buffer, if successful; - * NULL, if out of memory or rlimit exceeded. + * The remainder of any partially written record is zeroed out. * - * size: the requested buffer size in bytes - * pages (out): if not NULL, contains the number of pages reserved + * context: the DS context + * qual: the buffer type + * record: the data to write + * size: the size of the data */ -static inline void *ds_allocate_buffer(size_t size, unsigned int *pages) +static int ds_write(struct ds_context *context, enum ds_qualifier qual, + const void *record, size_t size) { - unsigned long rlim, vm, pgsz; - void *buffer; + int bytes_written = 0; - pgsz = PAGE_ALIGN(size) >> PAGE_SHIFT; + if (!record) + return -EINVAL; - rlim = current->signal->rlim[RLIMIT_AS].rlim_cur >> PAGE_SHIFT; - vm = current->mm->total_vm + pgsz; - if (rlim < vm) - return NULL; + while (size) { + unsigned long base, index, end, write_end, int_th; + unsigned long write_size, adj_write_size; - rlim = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur >> PAGE_SHIFT; - vm = current->mm->locked_vm + pgsz; - if (rlim < vm) - return NULL; + /* + * write as much as possible without producing an + * overflow interrupt. + * + * interrupt_threshold must either be + * - bigger than absolute_maximum or + * - point to a record between buffer_base and absolute_maximum + * + * index points to a valid record. + */ + base = ds_get(context->ds, qual, ds_buffer_base); + index = ds_get(context->ds, qual, ds_index); + end = ds_get(context->ds, qual, ds_absolute_maximum); + int_th = ds_get(context->ds, qual, ds_interrupt_threshold); - buffer = kzalloc(size, GFP_KERNEL); - if (!buffer) - return NULL; + write_end = min(end, int_th); - current->mm->total_vm += pgsz; - current->mm->locked_vm += pgsz; + /* if we are already beyond the interrupt threshold, + * we fill the entire buffer */ + if (write_end <= index) + write_end = end; - if (pages) - *pages = pgsz; + if (write_end <= index) + break; + + write_size = min((unsigned long) size, write_end - index); + memcpy((void *)index, record, write_size); - return buffer; + record = (const char *)record + write_size; + size -= write_size; + bytes_written += write_size; + + adj_write_size = write_size / ds_cfg.sizeof_rec[qual]; + adj_write_size *= ds_cfg.sizeof_rec[qual]; + + /* zero out trailing bytes */ + memset((char *)index + write_size, 0, + adj_write_size - write_size); + index += adj_write_size; + + if (index >= end) + index = base; + ds_set(context->ds, qual, ds_index, index); + + if (index >= int_th) + ds_overflow(context, qual); + } + + return bytes_written; } -static int ds_request(struct task_struct *task, void *base, size_t size, - ds_ovfl_callback_t ovfl, enum ds_qualifier qual) + +/* + * Branch Trace Store (BTS) uses the following format. Different + * architectures vary in the size of those fields. + * - source linear address + * - destination linear address + * - flags + * + * Later architectures use 64bit pointers throughout, whereas earlier + * architectures use 32bit pointers in 32bit mode. + * + * We compute the base address for the first 8 fields based on: + * - the field size stored in the DS configuration + * - the relative field position + * + * In order to store additional information in the BTS buffer, we use + * a special source address to indicate that the record requires + * special interpretation. + * + * Netburst indicated via a bit in the flags field whether the branch + * was predicted; this is ignored. + * + * We use two levels of abstraction: + * - the raw data level defined here + * - an arch-independent level defined in ds.h + */ + +enum bts_field { + bts_from, + bts_to, + bts_flags, + + bts_qual = bts_from, + bts_jiffies = bts_to, + bts_pid = bts_flags, + + bts_qual_mask = (bts_qual_max - 1), + bts_escape = ((unsigned long)-1 & ~bts_qual_mask) +}; + +static inline unsigned long bts_get(const char *base, enum bts_field field) { - struct ds_context *context; - unsigned long buffer, adj; - const unsigned long alignment = (1 << 3); - unsigned long irq; - int error = 0; + base += (ds_cfg.sizeof_field * field); + return *(unsigned long *)base; +} + +static inline void bts_set(char *base, enum bts_field field, unsigned long val) +{ + base += (ds_cfg.sizeof_field * field);; + (*(unsigned long *)base) = val; +} - if (!ds_cfg.sizeof_ds) - return -EOPNOTSUPP; - /* we require some space to do alignment adjustments below */ - if (size < (alignment + ds_cfg.sizeof_rec[qual])) +/* + * The raw BTS data is architecture dependent. + * + * For higher-level users, we give an arch-independent view. + * - ds.h defines struct bts_struct + * - bts_read translates one raw bts record into a bts_struct + * - bts_write translates one bts_struct into the raw format and + * writes it into the top of the parameter tracer's buffer. + * + * return: bytes read/written on success; -Eerrno, otherwise + */ +static int bts_read(struct bts_tracer *tracer, const void *at, + struct bts_struct *out) +{ + if (!tracer) return -EINVAL; - /* buffer overflow notification is not yet implemented */ - if (ovfl) - return -EOPNOTSUPP; + if (at < tracer->trace.ds.begin) + return -EINVAL; + if (tracer->trace.ds.end < (at + tracer->trace.ds.size)) + return -EINVAL; - context = ds_alloc_context(task); - if (!context) - return -ENOMEM; + memset(out, 0, sizeof(*out)); + if ((bts_get(at, bts_qual) & ~bts_qual_mask) == bts_escape) { + out->qualifier = (bts_get(at, bts_qual) & bts_qual_mask); + out->variant.timestamp.jiffies = bts_get(at, bts_jiffies); + out->variant.timestamp.pid = bts_get(at, bts_pid); + } else { + out->qualifier = bts_branch; + out->variant.lbr.from = bts_get(at, bts_from); + out->variant.lbr.to = bts_get(at, bts_to); + + if (!out->variant.lbr.from && !out->variant.lbr.to) + out->qualifier = bts_invalid; + } - spin_lock_irqsave(&ds_lock, irq); + return ds_cfg.sizeof_rec[ds_bts]; +} - error = -EPERM; - if (!check_tracer(task)) - goto out_unlock; +static int bts_write(struct bts_tracer *tracer, const struct bts_struct *in) +{ + unsigned char raw[MAX_SIZEOF_BTS]; - get_tracer(task); + if (!tracer) + return -EINVAL; - error = -EALREADY; - if (context->owner[qual] == current) - goto out_put_tracer; - error = -EPERM; - if (context->owner[qual] != NULL) - goto out_put_tracer; - context->owner[qual] = current; + if (MAX_SIZEOF_BTS < ds_cfg.sizeof_rec[ds_bts]) + return -EOVERFLOW; - spin_unlock_irqrestore(&ds_lock, irq); + switch (in->qualifier) { + case bts_invalid: + bts_set(raw, bts_from, 0); + bts_set(raw, bts_to, 0); + bts_set(raw, bts_flags, 0); + break; + case bts_branch: + bts_set(raw, bts_from, in->variant.lbr.from); + bts_set(raw, bts_to, in->variant.lbr.to); + bts_set(raw, bts_flags, 0); + break; + case bts_task_arrives: + case bts_task_departs: + bts_set(raw, bts_qual, (bts_escape | in->qualifier)); + bts_set(raw, bts_jiffies, in->variant.timestamp.jiffies); + bts_set(raw, bts_pid, in->variant.timestamp.pid); + break; + default: + return -EINVAL; + } + return ds_write(tracer->ds.context, ds_bts, raw, + ds_cfg.sizeof_rec[ds_bts]); +} - error = -ENOMEM; - if (!base) { - base = ds_allocate_buffer(size, &context->pages[qual]); - if (!base) - goto out_release; - context->buffer[qual] = base; - } - error = 0; +static void ds_write_config(struct ds_context *context, + struct ds_trace *cfg, enum ds_qualifier qual) +{ + unsigned char *ds = context->ds; + + ds_set(ds, qual, ds_buffer_base, (unsigned long)cfg->begin); + ds_set(ds, qual, ds_index, (unsigned long)cfg->top); + ds_set(ds, qual, ds_absolute_maximum, (unsigned long)cfg->end); + ds_set(ds, qual, ds_interrupt_threshold, (unsigned long)cfg->ith); +} + +static void ds_read_config(struct ds_context *context, + struct ds_trace *cfg, enum ds_qualifier qual) +{ + unsigned char *ds = context->ds; - context->callback[qual] = ovfl; + cfg->begin = (void *)ds_get(ds, qual, ds_buffer_base); + cfg->top = (void *)ds_get(ds, qual, ds_index); + cfg->end = (void *)ds_get(ds, qual, ds_absolute_maximum); + cfg->ith = (void *)ds_get(ds, qual, ds_interrupt_threshold); +} + +static void ds_init_ds_trace(struct ds_trace *trace, enum ds_qualifier qual, + void *base, size_t size, size_t ith, + unsigned int flags) { + unsigned long buffer, adj; /* adjust the buffer address and size to meet alignment * constraints: @@ -436,410 +565,383 @@ static int ds_request(struct task_struct *task, void *base, size_t size, */ buffer = (unsigned long)base; - adj = ALIGN(buffer, alignment) - buffer; + adj = ALIGN(buffer, DS_ALIGNMENT) - buffer; buffer += adj; size -= adj; - size /= ds_cfg.sizeof_rec[qual]; - size *= ds_cfg.sizeof_rec[qual]; - - ds_set(context->ds, qual, ds_buffer_base, buffer); - ds_set(context->ds, qual, ds_index, buffer); - ds_set(context->ds, qual, ds_absolute_maximum, buffer + size); + trace->n = size / ds_cfg.sizeof_rec[qual]; + trace->size = ds_cfg.sizeof_rec[qual]; - if (ovfl) { - /* todo: select a suitable interrupt threshold */ - } else - ds_set(context->ds, qual, - ds_interrupt_threshold, buffer + size + 1); + size = (trace->n * trace->size); - /* we keep the context until ds_release */ - return error; - - out_release: - context->owner[qual] = NULL; - ds_put_context(context); - put_tracer(task); - return error; - - out_put_tracer: - spin_unlock_irqrestore(&ds_lock, irq); - ds_put_context(context); - put_tracer(task); - return error; + trace->begin = (void *)buffer; + trace->top = trace->begin; + trace->end = (void *)(buffer + size); + /* The value for 'no threshold' is -1, which will set the + * threshold outside of the buffer, just like we want it. + */ + trace->ith = (void *)(buffer + size - ith); - out_unlock: - spin_unlock_irqrestore(&ds_lock, irq); - ds_put_context(context); - return error; + trace->flags = flags; } -int ds_request_bts(struct task_struct *task, void *base, size_t size, - ds_ovfl_callback_t ovfl) -{ - return ds_request(task, base, size, ovfl, ds_bts); -} -int ds_request_pebs(struct task_struct *task, void *base, size_t size, - ds_ovfl_callback_t ovfl) -{ - return ds_request(task, base, size, ovfl, ds_pebs); -} - -static int ds_release(struct task_struct *task, enum ds_qualifier qual) +static int ds_request(struct ds_tracer *tracer, struct ds_trace *trace, + enum ds_qualifier qual, struct task_struct *task, + void *base, size_t size, size_t th, unsigned int flags) { struct ds_context *context; int error; - context = ds_get_context(task); - error = ds_validate_access(context, qual); - if (error < 0) + error = -EINVAL; + if (!base) goto out; - kfree(context->buffer[qual]); - context->buffer[qual] = NULL; - - current->mm->total_vm -= context->pages[qual]; - current->mm->locked_vm -= context->pages[qual]; - context->pages[qual] = 0; - context->owner[qual] = NULL; - - /* - * we put the context twice: - * once for the ds_get_context - * once for the corresponding ds_request - */ - ds_put_context(context); - out: - ds_put_context(context); - return error; -} + /* we require some space to do alignment adjustments below */ + error = -EINVAL; + if (size < (DS_ALIGNMENT + ds_cfg.sizeof_rec[qual])) + goto out; -int ds_release_bts(struct task_struct *task) -{ - return ds_release(task, ds_bts); -} + if (th != (size_t)-1) { + th *= ds_cfg.sizeof_rec[qual]; -int ds_release_pebs(struct task_struct *task) -{ - return ds_release(task, ds_pebs); -} + error = -EINVAL; + if (size <= th) + goto out; + } -static int ds_get_index(struct task_struct *task, size_t *pos, - enum ds_qualifier qual) -{ - struct ds_context *context; - unsigned long base, index; - int error; + tracer->buffer = base; + tracer->size = size; + error = -ENOMEM; context = ds_get_context(task); - error = ds_validate_access(context, qual); - if (error < 0) + if (!context) goto out; + tracer->context = context; - base = ds_get(context->ds, qual, ds_buffer_base); - index = ds_get(context->ds, qual, ds_index); + ds_init_ds_trace(trace, qual, base, size, th, flags); - error = ((index - base) / ds_cfg.sizeof_rec[qual]); - if (pos) - *pos = error; + error = 0; out: - ds_put_context(context); return error; } -int ds_get_bts_index(struct task_struct *task, size_t *pos) -{ - return ds_get_index(task, pos, ds_bts); -} - -int ds_get_pebs_index(struct task_struct *task, size_t *pos) +struct bts_tracer *ds_request_bts(struct task_struct *task, + void *base, size_t size, + bts_ovfl_callback_t ovfl, size_t th, + unsigned int flags) { - return ds_get_index(task, pos, ds_pebs); -} - -static int ds_get_end(struct task_struct *task, size_t *pos, - enum ds_qualifier qual) -{ - struct ds_context *context; - unsigned long base, end; + struct bts_tracer *tracer; + unsigned long irq; int error; - context = ds_get_context(task); - error = ds_validate_access(context, qual); - if (error < 0) + error = -EOPNOTSUPP; + if (!ds_cfg.ctl[dsf_bts]) goto out; - base = ds_get(context->ds, qual, ds_buffer_base); - end = ds_get(context->ds, qual, ds_absolute_maximum); + /* buffer overflow notification is not yet implemented */ + error = -EOPNOTSUPP; + if (ovfl) + goto out; - error = ((end - base) / ds_cfg.sizeof_rec[qual]); - if (pos) - *pos = error; - out: - ds_put_context(context); - return error; -} + error = -ENOMEM; + tracer = kzalloc(sizeof(*tracer), GFP_KERNEL); + if (!tracer) + goto out; + tracer->ovfl = ovfl; -int ds_get_bts_end(struct task_struct *task, size_t *pos) -{ - return ds_get_end(task, pos, ds_bts); -} + error = ds_request(&tracer->ds, &tracer->trace.ds, + ds_bts, task, base, size, th, flags); + if (error < 0) + goto out_tracer; -int ds_get_pebs_end(struct task_struct *task, size_t *pos) -{ - return ds_get_end(task, pos, ds_pebs); -} -static int ds_access(struct task_struct *task, size_t index, - const void **record, enum ds_qualifier qual) -{ - struct ds_context *context; - unsigned long base, idx; - int error; + spin_lock_irqsave(&ds_lock, irq); - if (!record) - return -EINVAL; + error = -EPERM; + if (!check_tracer(task)) + goto out_unlock; + get_tracer(task); - context = ds_get_context(task); - error = ds_validate_access(context, qual); - if (error < 0) - goto out; + error = -EPERM; + if (tracer->ds.context->bts_master) + goto out_put_tracer; + tracer->ds.context->bts_master = tracer; - base = ds_get(context->ds, qual, ds_buffer_base); - idx = base + (index * ds_cfg.sizeof_rec[qual]); + spin_unlock_irqrestore(&ds_lock, irq); - error = -EINVAL; - if (idx > ds_get(context->ds, qual, ds_absolute_maximum)) - goto out; - *record = (const void *)idx; - error = ds_cfg.sizeof_rec[qual]; - out: - ds_put_context(context); - return error; -} + tracer->trace.read = bts_read; + tracer->trace.write = bts_write; -int ds_access_bts(struct task_struct *task, size_t index, const void **record) -{ - return ds_access(task, index, record, ds_bts); -} + ds_write_config(tracer->ds.context, &tracer->trace.ds, ds_bts); + ds_resume_bts(tracer); -int ds_access_pebs(struct task_struct *task, size_t index, const void **record) -{ - return ds_access(task, index, record, ds_pebs); + return tracer; + + out_put_tracer: + put_tracer(task); + out_unlock: + spin_unlock_irqrestore(&ds_lock, irq); + ds_put_context(tracer->ds.context); + out_tracer: + kfree(tracer); + out: + return ERR_PTR(error); } -static int ds_write(struct task_struct *task, const void *record, size_t size, - enum ds_qualifier qual, int force) +struct pebs_tracer *ds_request_pebs(struct task_struct *task, + void *base, size_t size, + pebs_ovfl_callback_t ovfl, size_t th, + unsigned int flags) { - struct ds_context *context; + struct pebs_tracer *tracer; + unsigned long irq; int error; - if (!record) - return -EINVAL; + /* buffer overflow notification is not yet implemented */ + error = -EOPNOTSUPP; + if (ovfl) + goto out; - error = -EPERM; - context = ds_get_context(task); - if (!context) + error = -ENOMEM; + tracer = kzalloc(sizeof(*tracer), GFP_KERNEL); + if (!tracer) goto out; + tracer->ovfl = ovfl; - if (!force) { - error = ds_validate_access(context, qual); - if (error < 0) - goto out; - } + error = ds_request(&tracer->ds, &tracer->trace.ds, + ds_pebs, task, base, size, th, flags); + if (error < 0) + goto out_tracer; - error = 0; - while (size) { - unsigned long base, index, end, write_end, int_th; - unsigned long write_size, adj_write_size; + spin_lock_irqsave(&ds_lock, irq); - /* - * write as much as possible without producing an - * overflow interrupt. - * - * interrupt_threshold must either be - * - bigger than absolute_maximum or - * - point to a record between buffer_base and absolute_maximum - * - * index points to a valid record. - */ - base = ds_get(context->ds, qual, ds_buffer_base); - index = ds_get(context->ds, qual, ds_index); - end = ds_get(context->ds, qual, ds_absolute_maximum); - int_th = ds_get(context->ds, qual, ds_interrupt_threshold); + error = -EPERM; + if (!check_tracer(task)) + goto out_unlock; + get_tracer(task); - write_end = min(end, int_th); + error = -EPERM; + if (tracer->ds.context->pebs_master) + goto out_put_tracer; + tracer->ds.context->pebs_master = tracer; - /* if we are already beyond the interrupt threshold, - * we fill the entire buffer */ - if (write_end <= index) - write_end = end; + spin_unlock_irqrestore(&ds_lock, irq); - if (write_end <= index) - goto out; + ds_write_config(tracer->ds.context, &tracer->trace.ds, ds_bts); + ds_resume_pebs(tracer); - write_size = min((unsigned long) size, write_end - index); - memcpy((void *)index, record, write_size); + return tracer; - record = (const char *)record + write_size; - size -= write_size; - error += write_size; + out_put_tracer: + put_tracer(task); + out_unlock: + spin_unlock_irqrestore(&ds_lock, irq); + ds_put_context(tracer->ds.context); + out_tracer: + kfree(tracer); + out: + return ERR_PTR(error); +} - adj_write_size = write_size / ds_cfg.sizeof_rec[qual]; - adj_write_size *= ds_cfg.sizeof_rec[qual]; +void ds_release_bts(struct bts_tracer *tracer) +{ + if (!tracer) + return; - /* zero out trailing bytes */ - memset((char *)index + write_size, 0, - adj_write_size - write_size); - index += adj_write_size; + ds_suspend_bts(tracer); - if (index >= end) - index = base; - ds_set(context->ds, qual, ds_index, index); + WARN_ON_ONCE(tracer->ds.context->bts_master != tracer); + tracer->ds.context->bts_master = NULL; - if (index >= int_th) - ds_overflow(task, context, qual); - } + put_tracer(tracer->ds.context->task); + ds_put_context(tracer->ds.context); - out: - ds_put_context(context); - return error; + kfree(tracer); } -int ds_write_bts(struct task_struct *task, const void *record, size_t size) +void ds_suspend_bts(struct bts_tracer *tracer) { - return ds_write(task, record, size, ds_bts, /* force = */ 0); -} + struct task_struct *task; -int ds_write_pebs(struct task_struct *task, const void *record, size_t size) -{ - return ds_write(task, record, size, ds_pebs, /* force = */ 0); -} + if (!tracer) + return; -int ds_unchecked_write_bts(struct task_struct *task, - const void *record, size_t size) -{ - return ds_write(task, record, size, ds_bts, /* force = */ 1); -} + task = tracer->ds.context->task; -int ds_unchecked_write_pebs(struct task_struct *task, - const void *record, size_t size) -{ - return ds_write(task, record, size, ds_pebs, /* force = */ 1); + if (!task || (task == current)) + update_debugctlmsr(get_debugctlmsr() & ~BTS_CONTROL); + + if (task) { + task->thread.debugctlmsr &= ~BTS_CONTROL; + + if (!task->thread.debugctlmsr) + clear_tsk_thread_flag(task, TIF_DEBUGCTLMSR); + } } -static int ds_reset_or_clear(struct task_struct *task, - enum ds_qualifier qual, int clear) +void ds_resume_bts(struct bts_tracer *tracer) { - struct ds_context *context; - unsigned long base, end; - int error; + struct task_struct *task; + unsigned long control; - context = ds_get_context(task); - error = ds_validate_access(context, qual); - if (error < 0) - goto out; + if (!tracer) + return; - base = ds_get(context->ds, qual, ds_buffer_base); - end = ds_get(context->ds, qual, ds_absolute_maximum); + task = tracer->ds.context->task; - if (clear) - memset((void *)base, 0, end - base); + control = ds_cfg.ctl[dsf_bts]; + if (!(tracer->trace.ds.flags & BTS_KERNEL)) + control |= ds_cfg.ctl[dsf_bts_kernel]; + if (!(tracer->trace.ds.flags & BTS_USER)) + control |= ds_cfg.ctl[dsf_bts_user]; - ds_set(context->ds, qual, ds_index, base); + if (task) { + task->thread.debugctlmsr |= control; + set_tsk_thread_flag(task, TIF_DEBUGCTLMSR); + } - error = 0; - out: - ds_put_context(context); - return error; + if (!task || (task == current)) + update_debugctlmsr(get_debugctlmsr() | control); } -int ds_reset_bts(struct task_struct *task) +void ds_release_pebs(struct pebs_tracer *tracer) { - return ds_reset_or_clear(task, ds_bts, /* clear = */ 0); + if (!tracer) + return; + + ds_suspend_pebs(tracer); + + WARN_ON_ONCE(tracer->ds.context->pebs_master != tracer); + tracer->ds.context->pebs_master = NULL; + + put_tracer(tracer->ds.context->task); + ds_put_context(tracer->ds.context); + + kfree(tracer); } -int ds_reset_pebs(struct task_struct *task) +void ds_suspend_pebs(struct pebs_tracer *tracer) { - return ds_reset_or_clear(task, ds_pebs, /* clear = */ 0); + } -int ds_clear_bts(struct task_struct *task) +void ds_resume_pebs(struct pebs_tracer *tracer) { - return ds_reset_or_clear(task, ds_bts, /* clear = */ 1); + } -int ds_clear_pebs(struct task_struct *task) +const struct bts_trace *ds_read_bts(struct bts_tracer *tracer) { - return ds_reset_or_clear(task, ds_pebs, /* clear = */ 1); + if (!tracer) + return NULL; + + ds_read_config(tracer->ds.context, &tracer->trace.ds, ds_bts); + return &tracer->trace; } -int ds_get_pebs_reset(struct task_struct *task, u64 *value) +const struct pebs_trace *ds_read_pebs(struct pebs_tracer *tracer) { - struct ds_context *context; - int error; + if (!tracer) + return NULL; + + ds_read_config(tracer->ds.context, &tracer->trace.ds, ds_pebs); + tracer->trace.reset_value = + *(u64 *)(tracer->ds.context->ds + (ds_cfg.sizeof_field * 8)); - if (!value) + return &tracer->trace; +} + +int ds_reset_bts(struct bts_tracer *tracer) +{ + if (!tracer) return -EINVAL; - context = ds_get_context(task); - error = ds_validate_access(context, ds_pebs); - if (error < 0) - goto out; + tracer->trace.ds.top = tracer->trace.ds.begin; - *value = *(u64 *)(context->ds + (ds_cfg.sizeof_field * 8)); + ds_set(tracer->ds.context->ds, ds_bts, ds_index, + (unsigned long)tracer->trace.ds.top); - error = 0; - out: - ds_put_context(context); - return error; + return 0; } -int ds_set_pebs_reset(struct task_struct *task, u64 value) +int ds_reset_pebs(struct pebs_tracer *tracer) { - struct ds_context *context; - int error; + if (!tracer) + return -EINVAL; - context = ds_get_context(task); - error = ds_validate_access(context, ds_pebs); - if (error < 0) - goto out; + tracer->trace.ds.top = tracer->trace.ds.begin; - *(u64 *)(context->ds + (ds_cfg.sizeof_field * 8)) = value; + ds_set(tracer->ds.context->ds, ds_bts, ds_index, + (unsigned long)tracer->trace.ds.top); - error = 0; - out: - ds_put_context(context); - return error; + return 0; +} + +int ds_set_pebs_reset(struct pebs_tracer *tracer, u64 value) +{ + if (!tracer) + return -EINVAL; + + *(u64 *)(tracer->ds.context->ds + (ds_cfg.sizeof_field * 8)) = value; + + return 0; } -static const struct ds_configuration ds_cfg_var = { - .sizeof_ds = sizeof(long) * 12, - .sizeof_field = sizeof(long), - .sizeof_rec[ds_bts] = sizeof(long) * 3, +static const struct ds_configuration ds_cfg_netburst = { + .name = "netburst", + .ctl[dsf_bts] = (1 << 2) | (1 << 3), + .ctl[dsf_bts_kernel] = (1 << 5), + .ctl[dsf_bts_user] = (1 << 6), + + .sizeof_field = sizeof(long), + .sizeof_rec[ds_bts] = sizeof(long) * 3, #ifdef __i386__ - .sizeof_rec[ds_pebs] = sizeof(long) * 10 + .sizeof_rec[ds_pebs] = sizeof(long) * 10, #else - .sizeof_rec[ds_pebs] = sizeof(long) * 18 + .sizeof_rec[ds_pebs] = sizeof(long) * 18, #endif }; -static const struct ds_configuration ds_cfg_64 = { - .sizeof_ds = 8 * 12, - .sizeof_field = 8, - .sizeof_rec[ds_bts] = 8 * 3, +static const struct ds_configuration ds_cfg_pentium_m = { + .name = "pentium m", + .ctl[dsf_bts] = (1 << 6) | (1 << 7), + + .sizeof_field = sizeof(long), + .sizeof_rec[ds_bts] = sizeof(long) * 3, #ifdef __i386__ - .sizeof_rec[ds_pebs] = 8 * 10 + .sizeof_rec[ds_pebs] = sizeof(long) * 10, #else - .sizeof_rec[ds_pebs] = 8 * 18 + .sizeof_rec[ds_pebs] = sizeof(long) * 18, #endif }; +static const struct ds_configuration ds_cfg_core2 = { + .name = "core 2", + .ctl[dsf_bts] = (1 << 6) | (1 << 7), + .ctl[dsf_bts_kernel] = (1 << 9), + .ctl[dsf_bts_user] = (1 << 10), + + .sizeof_field = 8, + .sizeof_rec[ds_bts] = 8 * 3, + .sizeof_rec[ds_pebs] = 8 * 18, +}; -static inline void +static void ds_configure(const struct ds_configuration *cfg) { + memset(&ds_cfg, 0, sizeof(ds_cfg)); ds_cfg = *cfg; + + printk(KERN_INFO "[ds] using %s configuration\n", ds_cfg.name); + + if (!cpu_has_bts) { + ds_cfg.ctl[dsf_bts] = 0; + printk(KERN_INFO "[ds] bts not available\n"); + } + if (!cpu_has_pebs) + printk(KERN_INFO "[ds] pebs not available\n"); + + WARN_ON_ONCE(MAX_SIZEOF_DS < (12 * ds_cfg.sizeof_field)); } void __cpuinit ds_init_intel(struct cpuinfo_x86 *c) @@ -847,16 +949,15 @@ void __cpuinit ds_init_intel(struct cpuinfo_x86 *c) switch (c->x86) { case 0x6: switch (c->x86_model) { + case 0 ... 0xC: + /* sorry, don't know about them */ + break; case 0xD: case 0xE: /* Pentium M */ - ds_configure(&ds_cfg_var); + ds_configure(&ds_cfg_pentium_m); break; - case 0xF: /* Core2 */ - case 0x1C: /* Atom */ - ds_configure(&ds_cfg_64); - break; - default: - /* sorry, don't know about them */ + default: /* Core2, Atom, ... */ + ds_configure(&ds_cfg_core2); break; } break; @@ -865,7 +966,7 @@ void __cpuinit ds_init_intel(struct cpuinfo_x86 *c) case 0x0: case 0x1: case 0x2: /* Netburst */ - ds_configure(&ds_cfg_var); + ds_configure(&ds_cfg_netburst); break; default: /* sorry, don't know about them */ @@ -878,12 +979,52 @@ void __cpuinit ds_init_intel(struct cpuinfo_x86 *c) } } -void ds_free(struct ds_context *context) +/* + * Change the DS configuration from tracing prev to tracing next. + */ +void ds_switch_to(struct task_struct *prev, struct task_struct *next) +{ + struct ds_context *prev_ctx = prev->thread.ds_ctx; + struct ds_context *next_ctx = next->thread.ds_ctx; + + if (prev_ctx) { + update_debugctlmsr(0); + + if (prev_ctx->bts_master && + (prev_ctx->bts_master->trace.ds.flags & BTS_TIMESTAMPS)) { + struct bts_struct ts = { + .qualifier = bts_task_departs, + .variant.timestamp.jiffies = jiffies_64, + .variant.timestamp.pid = prev->pid + }; + bts_write(prev_ctx->bts_master, &ts); + } + } + + if (next_ctx) { + if (next_ctx->bts_master && + (next_ctx->bts_master->trace.ds.flags & BTS_TIMESTAMPS)) { + struct bts_struct ts = { + .qualifier = bts_task_arrives, + .variant.timestamp.jiffies = jiffies_64, + .variant.timestamp.pid = next->pid + }; + bts_write(next_ctx->bts_master, &ts); + } + + wrmsrl(MSR_IA32_DS_AREA, (unsigned long)next_ctx->ds); + } + + update_debugctlmsr(next->thread.debugctlmsr); +} + +void ds_copy_thread(struct task_struct *tsk, struct task_struct *father) +{ + clear_tsk_thread_flag(tsk, TIF_DS_AREA_MSR); + tsk->thread.ds_ctx = NULL; +} + +void ds_exit_thread(struct task_struct *tsk) { - /* This is called when the task owning the parameter context - * is dying. There should not be any user of that context left - * to disturb us, anymore. */ - unsigned long leftovers = context->count; - while (leftovers--) - ds_put_context(context); + WARN_ON(tsk->thread.ds_ctx); } diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c new file mode 100644 index 0000000000000000000000000000000000000000..6b1f6f6f866172b41b4b64e1590bb40f2de19315 --- /dev/null +++ b/arch/x86/kernel/dumpstack.c @@ -0,0 +1,351 @@ +/* + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "dumpstack.h" + +int panic_on_unrecovered_nmi; +unsigned int code_bytes = 64; +int kstack_depth_to_print = 3 * STACKSLOTS_PER_LINE; +static int die_counter; + +void printk_address(unsigned long address, int reliable) +{ + printk(" [<%p>] %s%pS\n", (void *) address, + reliable ? "" : "? ", (void *) address); +} + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER +static void +print_ftrace_graph_addr(unsigned long addr, void *data, + const struct stacktrace_ops *ops, + struct thread_info *tinfo, int *graph) +{ + struct task_struct *task = tinfo->task; + unsigned long ret_addr; + int index = task->curr_ret_stack; + + if (addr != (unsigned long)return_to_handler) + return; + + if (!task->ret_stack || index < *graph) + return; + + index -= *graph; + ret_addr = task->ret_stack[index].ret; + + ops->address(data, ret_addr, 1); + + (*graph)++; +} +#else +static inline void +print_ftrace_graph_addr(unsigned long addr, void *data, + const struct stacktrace_ops *ops, + struct thread_info *tinfo, int *graph) +{ } +#endif + +/* + * x86-64 can have up to three kernel stacks: + * process stack + * interrupt stack + * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack + */ + +static inline int valid_stack_ptr(struct thread_info *tinfo, + void *p, unsigned int size, void *end) +{ + void *t = tinfo; + if (end) { + if (p < end && p >= (end-THREAD_SIZE)) + return 1; + else + return 0; + } + return p > t && p < t + THREAD_SIZE - size; +} + +unsigned long +print_context_stack(struct thread_info *tinfo, + unsigned long *stack, unsigned long bp, + const struct stacktrace_ops *ops, void *data, + unsigned long *end, int *graph) +{ + struct stack_frame *frame = (struct stack_frame *)bp; + + while (valid_stack_ptr(tinfo, stack, sizeof(*stack), end)) { + unsigned long addr; + + addr = *stack; + if (__kernel_text_address(addr)) { + if ((unsigned long) stack == bp + sizeof(long)) { + ops->address(data, addr, 1); + frame = frame->next_frame; + bp = (unsigned long) frame; + } else { + ops->address(data, addr, bp == 0); + } + print_ftrace_graph_addr(addr, data, ops, tinfo, graph); + } + stack++; + } + return bp; +} + + +static void +print_trace_warning_symbol(void *data, char *msg, unsigned long symbol) +{ + printk(data); + print_symbol(msg, symbol); + printk("\n"); +} + +static void print_trace_warning(void *data, char *msg) +{ + printk("%s%s\n", (char *)data, msg); +} + +static int print_trace_stack(void *data, char *name) +{ + printk("%s <%s> ", (char *)data, name); + return 0; +} + +/* + * Print one address/symbol entries per line. + */ +static void print_trace_address(void *data, unsigned long addr, int reliable) +{ + touch_nmi_watchdog(); + printk(data); + printk_address(addr, reliable); +} + +static const struct stacktrace_ops print_trace_ops = { + .warning = print_trace_warning, + .warning_symbol = print_trace_warning_symbol, + .stack = print_trace_stack, + .address = print_trace_address, +}; + +void +show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, + unsigned long *stack, unsigned long bp, char *log_lvl) +{ + printk("%sCall Trace:\n", log_lvl); + dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl); +} + +void show_trace(struct task_struct *task, struct pt_regs *regs, + unsigned long *stack, unsigned long bp) +{ + show_trace_log_lvl(task, regs, stack, bp, ""); +} + +void show_stack(struct task_struct *task, unsigned long *sp) +{ + show_stack_log_lvl(task, NULL, sp, 0, ""); +} + +/* + * The architecture-independent dump_stack generator + */ +void dump_stack(void) +{ + unsigned long bp = 0; + unsigned long stack; + +#ifdef CONFIG_FRAME_POINTER + if (!bp) + get_bp(bp); +#endif + + printk("Pid: %d, comm: %.20s %s %s %.*s\n", + current->pid, current->comm, print_tainted(), + init_utsname()->release, + (int)strcspn(init_utsname()->version, " "), + init_utsname()->version); + show_trace(NULL, NULL, &stack, bp); +} +EXPORT_SYMBOL(dump_stack); + +static raw_spinlock_t die_lock = __RAW_SPIN_LOCK_UNLOCKED; +static int die_owner = -1; +static unsigned int die_nest_count; + +unsigned __kprobes long oops_begin(void) +{ + int cpu; + unsigned long flags; + + oops_enter(); + + /* racy, but better than risking deadlock. */ + raw_local_irq_save(flags); + cpu = smp_processor_id(); + if (!__raw_spin_trylock(&die_lock)) { + if (cpu == die_owner) + /* nested oops. should stop eventually */; + else + __raw_spin_lock(&die_lock); + } + die_nest_count++; + die_owner = cpu; + console_verbose(); + bust_spinlocks(1); + return flags; +} + +void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr) +{ + if (regs && kexec_should_crash(current)) + crash_kexec(regs); + + bust_spinlocks(0); + die_owner = -1; + add_taint(TAINT_DIE); + die_nest_count--; + if (!die_nest_count) + /* Nest count reaches zero, release the lock. */ + __raw_spin_unlock(&die_lock); + raw_local_irq_restore(flags); + oops_exit(); + + if (!signr) + return; + if (in_interrupt()) + panic("Fatal exception in interrupt"); + if (panic_on_oops) + panic("Fatal exception"); + do_exit(signr); +} + +int __kprobes __die(const char *str, struct pt_regs *regs, long err) +{ +#ifdef CONFIG_X86_32 + unsigned short ss; + unsigned long sp; +#endif + printk(KERN_EMERG "%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter); +#ifdef CONFIG_PREEMPT + printk("PREEMPT "); +#endif +#ifdef CONFIG_SMP + printk("SMP "); +#endif +#ifdef CONFIG_DEBUG_PAGEALLOC + printk("DEBUG_PAGEALLOC"); +#endif + printk("\n"); + sysfs_printk_last_file(); + if (notify_die(DIE_OOPS, str, regs, err, + current->thread.trap_no, SIGSEGV) == NOTIFY_STOP) + return 1; + + show_registers(regs); +#ifdef CONFIG_X86_32 + sp = (unsigned long) (®s->sp); + savesegment(ss, ss); + if (user_mode(regs)) { + sp = regs->sp; + ss = regs->ss & 0xffff; + } + printk(KERN_EMERG "EIP: [<%08lx>] ", regs->ip); + print_symbol("%s", regs->ip); + printk(" SS:ESP %04x:%08lx\n", ss, sp); +#else + /* Executive summary in case the oops scrolled away */ + printk(KERN_ALERT "RIP "); + printk_address(regs->ip, 1); + printk(" RSP <%016lx>\n", regs->sp); +#endif + return 0; +} + +/* + * This is gone through when something in the kernel has done something bad + * and is about to be terminated: + */ +void die(const char *str, struct pt_regs *regs, long err) +{ + unsigned long flags = oops_begin(); + int sig = SIGSEGV; + + if (!user_mode_vm(regs)) + report_bug(regs->ip, regs); + + if (__die(str, regs, err)) + sig = 0; + oops_end(flags, regs, sig); +} + +void notrace __kprobes +die_nmi(char *str, struct pt_regs *regs, int do_panic) +{ + unsigned long flags; + + if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP) + return; + + /* + * We are in trouble anyway, lets at least try + * to get a message out. + */ + flags = oops_begin(); + printk(KERN_EMERG "%s", str); + printk(" on CPU%d, ip %08lx, registers:\n", + smp_processor_id(), regs->ip); + show_registers(regs); + oops_end(flags, regs, 0); + if (do_panic || panic_on_oops) + panic("Non maskable interrupt"); + nmi_exit(); + local_irq_enable(); + do_exit(SIGBUS); +} + +static int __init oops_setup(char *s) +{ + if (!s) + return -EINVAL; + if (!strcmp(s, "panic")) + panic_on_oops = 1; + return 0; +} +early_param("oops", oops_setup); + +static int __init kstack_setup(char *s) +{ + if (!s) + return -EINVAL; + kstack_depth_to_print = simple_strtoul(s, NULL, 0); + return 0; +} +early_param("kstack", kstack_setup); + +static int __init code_bytes_setup(char *s) +{ + code_bytes = simple_strtoul(s, NULL, 0); + if (code_bytes > 8192) + code_bytes = 8192; + + return 1; +} +__setup("code_bytes=", code_bytes_setup); diff --git a/arch/x86/kernel/dumpstack.h b/arch/x86/kernel/dumpstack.h new file mode 100644 index 0000000000000000000000000000000000000000..da87590b8698a7c4642ad8e46febe2bf91972599 --- /dev/null +++ b/arch/x86/kernel/dumpstack.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs + */ + +#ifndef DUMPSTACK_H +#define DUMPSTACK_H + +#ifdef CONFIG_X86_32 +#define STACKSLOTS_PER_LINE 8 +#define get_bp(bp) asm("movl %%ebp, %0" : "=r" (bp) :) +#else +#define STACKSLOTS_PER_LINE 4 +#define get_bp(bp) asm("movq %%rbp, %0" : "=r" (bp) :) +#endif + +extern unsigned long +print_context_stack(struct thread_info *tinfo, + unsigned long *stack, unsigned long bp, + const struct stacktrace_ops *ops, void *data, + unsigned long *end, int *graph); + +extern void +show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, + unsigned long *stack, unsigned long bp, char *log_lvl); + +extern void +show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, + unsigned long *sp, unsigned long bp, char *log_lvl); + +extern unsigned int code_bytes; +extern int kstack_depth_to_print; + +/* The form of the top of the frame on the stack */ +struct stack_frame { + struct stack_frame *next_frame; + unsigned long return_address; +}; +#endif diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c index b3614752197b6c6e3c0cf53c7b718dd0167fbdea..d593cd1f58dcca22925f10e2b3669435a4a25557 100644 --- a/arch/x86/kernel/dumpstack_32.c +++ b/arch/x86/kernel/dumpstack_32.c @@ -17,69 +17,14 @@ #include -#define STACKSLOTS_PER_LINE 8 -#define get_bp(bp) asm("movl %%ebp, %0" : "=r" (bp) :) - -int panic_on_unrecovered_nmi; -int kstack_depth_to_print = 3 * STACKSLOTS_PER_LINE; -static unsigned int code_bytes = 64; -static int die_counter; - -void printk_address(unsigned long address, int reliable) -{ - printk(" [<%p>] %s%pS\n", (void *) address, - reliable ? "" : "? ", (void *) address); -} - -static inline int valid_stack_ptr(struct thread_info *tinfo, - void *p, unsigned int size, void *end) -{ - void *t = tinfo; - if (end) { - if (p < end && p >= (end-THREAD_SIZE)) - return 1; - else - return 0; - } - return p > t && p < t + THREAD_SIZE - size; -} - -/* The form of the top of the frame on the stack */ -struct stack_frame { - struct stack_frame *next_frame; - unsigned long return_address; -}; - -static inline unsigned long -print_context_stack(struct thread_info *tinfo, - unsigned long *stack, unsigned long bp, - const struct stacktrace_ops *ops, void *data, - unsigned long *end) -{ - struct stack_frame *frame = (struct stack_frame *)bp; - - while (valid_stack_ptr(tinfo, stack, sizeof(*stack), end)) { - unsigned long addr; - - addr = *stack; - if (__kernel_text_address(addr)) { - if ((unsigned long) stack == bp + sizeof(long)) { - ops->address(data, addr, 1); - frame = frame->next_frame; - bp = (unsigned long) frame; - } else { - ops->address(data, addr, bp == 0); - } - } - stack++; - } - return bp; -} +#include "dumpstack.h" void dump_trace(struct task_struct *task, struct pt_regs *regs, unsigned long *stack, unsigned long bp, const struct stacktrace_ops *ops, void *data) { + int graph = 0; + if (!task) task = current; @@ -107,7 +52,8 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, context = (struct thread_info *) ((unsigned long)stack & (~(THREAD_SIZE - 1))); - bp = print_context_stack(context, stack, bp, ops, data, NULL); + bp = print_context_stack(context, stack, bp, ops, + data, NULL, &graph); stack = (unsigned long *)context->previous_esp; if (!stack) @@ -119,57 +65,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, } EXPORT_SYMBOL(dump_trace); -static void -print_trace_warning_symbol(void *data, char *msg, unsigned long symbol) -{ - printk(data); - print_symbol(msg, symbol); - printk("\n"); -} - -static void print_trace_warning(void *data, char *msg) -{ - printk("%s%s\n", (char *)data, msg); -} - -static int print_trace_stack(void *data, char *name) -{ - printk("%s <%s> ", (char *)data, name); - return 0; -} - -/* - * Print one address/symbol entries per line. - */ -static void print_trace_address(void *data, unsigned long addr, int reliable) -{ - touch_nmi_watchdog(); - printk(data); - printk_address(addr, reliable); -} - -static const struct stacktrace_ops print_trace_ops = { - .warning = print_trace_warning, - .warning_symbol = print_trace_warning_symbol, - .stack = print_trace_stack, - .address = print_trace_address, -}; - -static void -show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, - unsigned long *stack, unsigned long bp, char *log_lvl) -{ - printk("%sCall Trace:\n", log_lvl); - dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl); -} - -void show_trace(struct task_struct *task, struct pt_regs *regs, - unsigned long *stack, unsigned long bp) -{ - show_trace_log_lvl(task, regs, stack, bp, ""); -} - -static void +void show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, unsigned long *sp, unsigned long bp, char *log_lvl) { @@ -196,33 +92,6 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, show_trace_log_lvl(task, regs, sp, bp, log_lvl); } -void show_stack(struct task_struct *task, unsigned long *sp) -{ - show_stack_log_lvl(task, NULL, sp, 0, ""); -} - -/* - * The architecture-independent dump_stack generator - */ -void dump_stack(void) -{ - unsigned long bp = 0; - unsigned long stack; - -#ifdef CONFIG_FRAME_POINTER - if (!bp) - get_bp(bp); -#endif - - printk("Pid: %d, comm: %.20s %s %s %.*s\n", - current->pid, current->comm, print_tainted(), - init_utsname()->release, - (int)strcspn(init_utsname()->version, " "), - init_utsname()->version); - show_trace(NULL, NULL, &stack, bp); -} - -EXPORT_SYMBOL(dump_stack); void show_registers(struct pt_regs *regs) { @@ -283,167 +152,3 @@ int is_valid_bugaddr(unsigned long ip) return ud2 == 0x0b0f; } -static raw_spinlock_t die_lock = __RAW_SPIN_LOCK_UNLOCKED; -static int die_owner = -1; -static unsigned int die_nest_count; - -unsigned __kprobes long oops_begin(void) -{ - unsigned long flags; - - oops_enter(); - - if (die_owner != raw_smp_processor_id()) { - console_verbose(); - raw_local_irq_save(flags); - __raw_spin_lock(&die_lock); - die_owner = smp_processor_id(); - die_nest_count = 0; - bust_spinlocks(1); - } else { - raw_local_irq_save(flags); - } - die_nest_count++; - return flags; -} - -void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr) -{ - bust_spinlocks(0); - die_owner = -1; - add_taint(TAINT_DIE); - __raw_spin_unlock(&die_lock); - raw_local_irq_restore(flags); - - if (!regs) - return; - - if (kexec_should_crash(current)) - crash_kexec(regs); - if (in_interrupt()) - panic("Fatal exception in interrupt"); - if (panic_on_oops) - panic("Fatal exception"); - oops_exit(); - do_exit(signr); -} - -int __kprobes __die(const char *str, struct pt_regs *regs, long err) -{ - unsigned short ss; - unsigned long sp; - - printk(KERN_EMERG "%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter); -#ifdef CONFIG_PREEMPT - printk("PREEMPT "); -#endif -#ifdef CONFIG_SMP - printk("SMP "); -#endif -#ifdef CONFIG_DEBUG_PAGEALLOC - printk("DEBUG_PAGEALLOC"); -#endif - printk("\n"); - sysfs_printk_last_file(); - if (notify_die(DIE_OOPS, str, regs, err, - current->thread.trap_no, SIGSEGV) == NOTIFY_STOP) - return 1; - - show_registers(regs); - /* Executive summary in case the oops scrolled away */ - sp = (unsigned long) (®s->sp); - savesegment(ss, ss); - if (user_mode(regs)) { - sp = regs->sp; - ss = regs->ss & 0xffff; - } - printk(KERN_EMERG "EIP: [<%08lx>] ", regs->ip); - print_symbol("%s", regs->ip); - printk(" SS:ESP %04x:%08lx\n", ss, sp); - return 0; -} - -/* - * This is gone through when something in the kernel has done something bad - * and is about to be terminated: - */ -void die(const char *str, struct pt_regs *regs, long err) -{ - unsigned long flags = oops_begin(); - - if (die_nest_count < 3) { - report_bug(regs->ip, regs); - - if (__die(str, regs, err)) - regs = NULL; - } else { - printk(KERN_EMERG "Recursive die() failure, output suppressed\n"); - } - - oops_end(flags, regs, SIGSEGV); -} - -static DEFINE_SPINLOCK(nmi_print_lock); - -void notrace __kprobes -die_nmi(char *str, struct pt_regs *regs, int do_panic) -{ - if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP) - return; - - spin_lock(&nmi_print_lock); - /* - * We are in trouble anyway, lets at least try - * to get a message out: - */ - bust_spinlocks(1); - printk(KERN_EMERG "%s", str); - printk(" on CPU%d, ip %08lx, registers:\n", - smp_processor_id(), regs->ip); - show_registers(regs); - if (do_panic) - panic("Non maskable interrupt"); - console_silent(); - spin_unlock(&nmi_print_lock); - - /* - * If we are in kernel we are probably nested up pretty bad - * and might aswell get out now while we still can: - */ - if (!user_mode_vm(regs)) { - current->thread.trap_no = 2; - crash_kexec(regs); - } - - bust_spinlocks(0); - do_exit(SIGSEGV); -} - -static int __init oops_setup(char *s) -{ - if (!s) - return -EINVAL; - if (!strcmp(s, "panic")) - panic_on_oops = 1; - return 0; -} -early_param("oops", oops_setup); - -static int __init kstack_setup(char *s) -{ - if (!s) - return -EINVAL; - kstack_depth_to_print = simple_strtoul(s, NULL, 0); - return 0; -} -early_param("kstack", kstack_setup); - -static int __init code_bytes_setup(char *s) -{ - code_bytes = simple_strtoul(s, NULL, 0); - if (code_bytes > 8192) - code_bytes = 8192; - - return 1; -} -__setup("code_bytes=", code_bytes_setup); diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c index 96a5db7da8a747e5192f410c60fe9494e8d8e8d1..c302d070704826c44f0f4f8434383594e578cbe8 100644 --- a/arch/x86/kernel/dumpstack_64.c +++ b/arch/x86/kernel/dumpstack_64.c @@ -17,19 +17,7 @@ #include -#define STACKSLOTS_PER_LINE 4 -#define get_bp(bp) asm("movq %%rbp, %0" : "=r" (bp) :) - -int panic_on_unrecovered_nmi; -int kstack_depth_to_print = 3 * STACKSLOTS_PER_LINE; -static unsigned int code_bytes = 64; -static int die_counter; - -void printk_address(unsigned long address, int reliable) -{ - printk(" [<%p>] %s%pS\n", (void *) address, - reliable ? "" : "? ", (void *) address); -} +#include "dumpstack.h" static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, unsigned *usedp, char **idp) @@ -113,51 +101,6 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack */ -static inline int valid_stack_ptr(struct thread_info *tinfo, - void *p, unsigned int size, void *end) -{ - void *t = tinfo; - if (end) { - if (p < end && p >= (end-THREAD_SIZE)) - return 1; - else - return 0; - } - return p > t && p < t + THREAD_SIZE - size; -} - -/* The form of the top of the frame on the stack */ -struct stack_frame { - struct stack_frame *next_frame; - unsigned long return_address; -}; - -static inline unsigned long -print_context_stack(struct thread_info *tinfo, - unsigned long *stack, unsigned long bp, - const struct stacktrace_ops *ops, void *data, - unsigned long *end) -{ - struct stack_frame *frame = (struct stack_frame *)bp; - - while (valid_stack_ptr(tinfo, stack, sizeof(*stack), end)) { - unsigned long addr; - - addr = *stack; - if (__kernel_text_address(addr)) { - if ((unsigned long) stack == bp + sizeof(long)) { - ops->address(data, addr, 1); - frame = frame->next_frame; - bp = (unsigned long) frame; - } else { - ops->address(data, addr, bp == 0); - } - } - stack++; - } - return bp; -} - void dump_trace(struct task_struct *task, struct pt_regs *regs, unsigned long *stack, unsigned long bp, const struct stacktrace_ops *ops, void *data) @@ -166,6 +109,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr; unsigned used = 0; struct thread_info *tinfo; + int graph = 0; if (!task) task = current; @@ -206,7 +150,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, break; bp = print_context_stack(tinfo, stack, bp, ops, - data, estack_end); + data, estack_end, &graph); ops->stack(data, ""); /* * We link to the next stack via the @@ -225,7 +169,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, if (ops->stack(data, "IRQ") < 0) break; bp = print_context_stack(tinfo, stack, bp, - ops, data, irqstack_end); + ops, data, irqstack_end, &graph); /* * We link to the next stack (which would be * the process stack normally) the last @@ -243,62 +187,12 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, /* * This handles the process stack: */ - bp = print_context_stack(tinfo, stack, bp, ops, data, NULL); + bp = print_context_stack(tinfo, stack, bp, ops, data, NULL, &graph); put_cpu(); } EXPORT_SYMBOL(dump_trace); -static void -print_trace_warning_symbol(void *data, char *msg, unsigned long symbol) -{ - printk(data); - print_symbol(msg, symbol); - printk("\n"); -} - -static void print_trace_warning(void *data, char *msg) -{ - printk("%s%s\n", (char *)data, msg); -} - -static int print_trace_stack(void *data, char *name) -{ - printk("%s <%s> ", (char *)data, name); - return 0; -} - -/* - * Print one address/symbol entries per line. - */ -static void print_trace_address(void *data, unsigned long addr, int reliable) -{ - touch_nmi_watchdog(); - printk(data); - printk_address(addr, reliable); -} - -static const struct stacktrace_ops print_trace_ops = { - .warning = print_trace_warning, - .warning_symbol = print_trace_warning_symbol, - .stack = print_trace_stack, - .address = print_trace_address, -}; - -static void -show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, - unsigned long *stack, unsigned long bp, char *log_lvl) -{ - printk("%sCall Trace:\n", log_lvl); - dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl); -} - -void show_trace(struct task_struct *task, struct pt_regs *regs, - unsigned long *stack, unsigned long bp) -{ - show_trace_log_lvl(task, regs, stack, bp, ""); -} - -static void +void show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, unsigned long *sp, unsigned long bp, char *log_lvl) { @@ -342,33 +236,6 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, show_trace_log_lvl(task, regs, sp, bp, log_lvl); } -void show_stack(struct task_struct *task, unsigned long *sp) -{ - show_stack_log_lvl(task, NULL, sp, 0, ""); -} - -/* - * The architecture-independent dump_stack generator - */ -void dump_stack(void) -{ - unsigned long bp = 0; - unsigned long stack; - -#ifdef CONFIG_FRAME_POINTER - if (!bp) - get_bp(bp); -#endif - - printk("Pid: %d, comm: %.20s %s %s %.*s\n", - current->pid, current->comm, print_tainted(), - init_utsname()->release, - (int)strcspn(init_utsname()->version, " "), - init_utsname()->version); - show_trace(NULL, NULL, &stack, bp); -} -EXPORT_SYMBOL(dump_stack); - void show_registers(struct pt_regs *regs) { int i; @@ -429,147 +296,3 @@ int is_valid_bugaddr(unsigned long ip) return ud2 == 0x0b0f; } -static raw_spinlock_t die_lock = __RAW_SPIN_LOCK_UNLOCKED; -static int die_owner = -1; -static unsigned int die_nest_count; - -unsigned __kprobes long oops_begin(void) -{ - int cpu; - unsigned long flags; - - oops_enter(); - - /* racy, but better than risking deadlock. */ - raw_local_irq_save(flags); - cpu = smp_processor_id(); - if (!__raw_spin_trylock(&die_lock)) { - if (cpu == die_owner) - /* nested oops. should stop eventually */; - else - __raw_spin_lock(&die_lock); - } - die_nest_count++; - die_owner = cpu; - console_verbose(); - bust_spinlocks(1); - return flags; -} - -void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr) -{ - die_owner = -1; - bust_spinlocks(0); - die_nest_count--; - if (!die_nest_count) - /* Nest count reaches zero, release the lock. */ - __raw_spin_unlock(&die_lock); - raw_local_irq_restore(flags); - if (!regs) { - oops_exit(); - return; - } - if (in_interrupt()) - panic("Fatal exception in interrupt"); - if (panic_on_oops) - panic("Fatal exception"); - oops_exit(); - do_exit(signr); -} - -int __kprobes __die(const char *str, struct pt_regs *regs, long err) -{ - printk(KERN_EMERG "%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter); -#ifdef CONFIG_PREEMPT - printk("PREEMPT "); -#endif -#ifdef CONFIG_SMP - printk("SMP "); -#endif -#ifdef CONFIG_DEBUG_PAGEALLOC - printk("DEBUG_PAGEALLOC"); -#endif - printk("\n"); - sysfs_printk_last_file(); - if (notify_die(DIE_OOPS, str, regs, err, - current->thread.trap_no, SIGSEGV) == NOTIFY_STOP) - return 1; - - show_registers(regs); - add_taint(TAINT_DIE); - /* Executive summary in case the oops scrolled away */ - printk(KERN_ALERT "RIP "); - printk_address(regs->ip, 1); - printk(" RSP <%016lx>\n", regs->sp); - if (kexec_should_crash(current)) - crash_kexec(regs); - return 0; -} - -void die(const char *str, struct pt_regs *regs, long err) -{ - unsigned long flags = oops_begin(); - - if (!user_mode(regs)) - report_bug(regs->ip, regs); - - if (__die(str, regs, err)) - regs = NULL; - oops_end(flags, regs, SIGSEGV); -} - -notrace __kprobes void -die_nmi(char *str, struct pt_regs *regs, int do_panic) -{ - unsigned long flags; - - if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP) - return; - - flags = oops_begin(); - /* - * We are in trouble anyway, lets at least try - * to get a message out. - */ - printk(KERN_EMERG "%s", str); - printk(" on CPU%d, ip %08lx, registers:\n", - smp_processor_id(), regs->ip); - show_registers(regs); - if (kexec_should_crash(current)) - crash_kexec(regs); - if (do_panic || panic_on_oops) - panic("Non maskable interrupt"); - oops_end(flags, NULL, SIGBUS); - nmi_exit(); - local_irq_enable(); - do_exit(SIGBUS); -} - -static int __init oops_setup(char *s) -{ - if (!s) - return -EINVAL; - if (!strcmp(s, "panic")) - panic_on_oops = 1; - return 0; -} -early_param("oops", oops_setup); - -static int __init kstack_setup(char *s) -{ - if (!s) - return -EINVAL; - kstack_depth_to_print = simple_strtoul(s, NULL, 0); - return 0; -} -early_param("kstack", kstack_setup); - -static int __init code_bytes_setup(char *s) -{ - code_bytes = simple_strtoul(s, NULL, 0); - if (code_bytes > 8192) - code_bytes = 8192; - - return 1; -} -__setup("code_bytes=", code_bytes_setup); diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c index 7aafeb5263efbbb8de9e7aad35680d2d882a0882..65a13943e0982524877768164cf8cc0cd63688f4 100644 --- a/arch/x86/kernel/e820.c +++ b/arch/x86/kernel/e820.c @@ -677,22 +677,6 @@ struct early_res { }; static struct early_res early_res[MAX_EARLY_RES] __initdata = { { 0, PAGE_SIZE, "BIOS data page" }, /* BIOS data page */ -#if defined(CONFIG_X86_64) && defined(CONFIG_X86_TRAMPOLINE) - { TRAMPOLINE_BASE, TRAMPOLINE_BASE + 2 * PAGE_SIZE, "TRAMPOLINE" }, -#endif -#if defined(CONFIG_X86_32) && defined(CONFIG_SMP) - /* - * But first pinch a few for the stack/trampoline stuff - * FIXME: Don't need the extra page at 4K, but need to fix - * trampoline before removing it. (see the GDT stuff) - */ - { PAGE_SIZE, PAGE_SIZE + PAGE_SIZE, "EX TRAMPOLINE" }, - /* - * Has to be in very low memory so we can execute - * real-mode AP code. - */ - { TRAMPOLINE_BASE, TRAMPOLINE_BASE + PAGE_SIZE, "TRAMPOLINE" }, -#endif {} }; diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c index 1b894b72c0f5df35a1d489def584086ebb2affe5..744aa7fc49d5e875403b6ffc64c0a2cae74f9c55 100644 --- a/arch/x86/kernel/early-quirks.c +++ b/arch/x86/kernel/early-quirks.c @@ -17,6 +17,7 @@ #include #include #include +#include static void __init fix_hypertransport_config(int num, int slot, int func) { diff --git a/arch/x86/kernel/early_printk.c b/arch/x86/kernel/early_printk.c index 34ad997d3834dc773b71ae4f27e18828447d2853..23b138e31e9c2fe229c42050ab2c5e864cac4710 100644 --- a/arch/x86/kernel/early_printk.c +++ b/arch/x86/kernel/early_printk.c @@ -875,49 +875,6 @@ static struct console early_dbgp_console = { }; #endif -/* Console interface to a host file on AMD's SimNow! */ - -static int simnow_fd; - -enum { - MAGIC1 = 0xBACCD00A, - MAGIC2 = 0xCA110000, - XOPEN = 5, - XWRITE = 4, -}; - -static noinline long simnow(long cmd, long a, long b, long c) -{ - long ret; - - asm volatile("cpuid" : - "=a" (ret) : - "b" (a), "c" (b), "d" (c), "0" (MAGIC1), "D" (cmd + MAGIC2)); - return ret; -} - -static void __init simnow_init(char *str) -{ - char *fn = "klog"; - - if (*str == '=') - fn = ++str; - /* error ignored */ - simnow_fd = simnow(XOPEN, (unsigned long)fn, O_WRONLY|O_APPEND|O_CREAT, 0644); -} - -static void simnow_write(struct console *con, const char *s, unsigned n) -{ - simnow(XWRITE, simnow_fd, (unsigned long)s, n); -} - -static struct console simnow_console = { - .name = "simnow", - .write = simnow_write, - .flags = CON_PRINTBUFFER, - .index = -1, -}; - /* Direct interface for emergencies */ static struct console *early_console = &early_vga_console; static int __initdata early_console_initialized; @@ -960,10 +917,6 @@ static int __init setup_early_printk(char *buf) max_ypos = boot_params.screen_info.orig_video_lines; current_ypos = boot_params.screen_info.orig_y; early_console = &early_vga_console; - } else if (!strncmp(buf, "simnow", 6)) { - simnow_init(buf + 6); - early_console = &simnow_console; - keep_early = 1; #ifdef CONFIG_EARLY_PRINTK_DBGP } else if (!strncmp(buf, "dbgp", 4)) { if (early_dbgp_init(buf+4) < 0) diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S index 28b597ef9ca16b7992c333f10eae252ea695475c..d6f0490a7391eaeebb218337ba06c650b44b8ee8 100644 --- a/arch/x86/kernel/entry_32.S +++ b/arch/x86/kernel/entry_32.S @@ -619,28 +619,37 @@ END(syscall_badsys) 27:; /* - * Build the entry stubs and pointer table with - * some assembler magic. + * Build the entry stubs and pointer table with some assembler magic. + * We pack 7 stubs into a single 32-byte chunk, which will fit in a + * single cache line on all modern x86 implementations. */ -.section .rodata,"a" +.section .init.rodata,"a" ENTRY(interrupt) .text - + .p2align 5 + .p2align CONFIG_X86_L1_CACHE_SHIFT ENTRY(irq_entries_start) RING0_INT_FRAME -vector=0 -.rept NR_VECTORS - ALIGN - .if vector +vector=FIRST_EXTERNAL_VECTOR +.rept (NR_VECTORS-FIRST_EXTERNAL_VECTOR+6)/7 + .balign 32 + .rept 7 + .if vector < NR_VECTORS + .if vector <> FIRST_EXTERNAL_VECTOR CFI_ADJUST_CFA_OFFSET -4 - .endif -1: pushl $~(vector) + .endif +1: pushl $(~vector+0x80) /* Note: always in signed byte range */ CFI_ADJUST_CFA_OFFSET 4 - jmp common_interrupt - .previous + .if ((vector-FIRST_EXTERNAL_VECTOR)%7) <> 6 + jmp 2f + .endif + .previous .long 1b - .text + .text vector=vector+1 + .endif + .endr +2: jmp common_interrupt .endr END(irq_entries_start) @@ -652,8 +661,9 @@ END(interrupt) * the CPU automatically disables interrupts when executing an IRQ vector, * so IRQ-flags tracing has to follow that: */ - ALIGN + .p2align CONFIG_X86_L1_CACHE_SHIFT common_interrupt: + addl $-0x80,(%esp) /* Adjust vector into the [-256,-1] range */ SAVE_ALL TRACE_IRQS_OFF movl %esp,%eax @@ -678,65 +688,6 @@ ENDPROC(name) /* The include is where all of the SMP etc. interrupts come from */ #include "entry_arch.h" -KPROBE_ENTRY(page_fault) - RING0_EC_FRAME - pushl $do_page_fault - CFI_ADJUST_CFA_OFFSET 4 - ALIGN -error_code: - /* the function address is in %fs's slot on the stack */ - pushl %es - CFI_ADJUST_CFA_OFFSET 4 - /*CFI_REL_OFFSET es, 0*/ - pushl %ds - CFI_ADJUST_CFA_OFFSET 4 - /*CFI_REL_OFFSET ds, 0*/ - pushl %eax - CFI_ADJUST_CFA_OFFSET 4 - CFI_REL_OFFSET eax, 0 - pushl %ebp - CFI_ADJUST_CFA_OFFSET 4 - CFI_REL_OFFSET ebp, 0 - pushl %edi - CFI_ADJUST_CFA_OFFSET 4 - CFI_REL_OFFSET edi, 0 - pushl %esi - CFI_ADJUST_CFA_OFFSET 4 - CFI_REL_OFFSET esi, 0 - pushl %edx - CFI_ADJUST_CFA_OFFSET 4 - CFI_REL_OFFSET edx, 0 - pushl %ecx - CFI_ADJUST_CFA_OFFSET 4 - CFI_REL_OFFSET ecx, 0 - pushl %ebx - CFI_ADJUST_CFA_OFFSET 4 - CFI_REL_OFFSET ebx, 0 - cld - pushl %fs - CFI_ADJUST_CFA_OFFSET 4 - /*CFI_REL_OFFSET fs, 0*/ - movl $(__KERNEL_PERCPU), %ecx - movl %ecx, %fs - UNWIND_ESPFIX_STACK - popl %ecx - CFI_ADJUST_CFA_OFFSET -4 - /*CFI_REGISTER es, ecx*/ - movl PT_FS(%esp), %edi # get the function address - movl PT_ORIG_EAX(%esp), %edx # get the error code - movl $-1, PT_ORIG_EAX(%esp) # no syscall to restart - mov %ecx, PT_FS(%esp) - /*CFI_REL_OFFSET fs, ES*/ - movl $(__USER_DS), %ecx - movl %ecx, %ds - movl %ecx, %es - TRACE_IRQS_OFF - movl %esp,%eax # pt_regs pointer - call *%edi - jmp ret_from_exception - CFI_ENDPROC -KPROBE_END(page_fault) - ENTRY(coprocessor_error) RING0_INT_FRAME pushl $0 @@ -767,140 +718,6 @@ ENTRY(device_not_available) CFI_ENDPROC END(device_not_available) -/* - * Debug traps and NMI can happen at the one SYSENTER instruction - * that sets up the real kernel stack. Check here, since we can't - * allow the wrong stack to be used. - * - * "TSS_sysenter_sp0+12" is because the NMI/debug handler will have - * already pushed 3 words if it hits on the sysenter instruction: - * eflags, cs and eip. - * - * We just load the right stack, and push the three (known) values - * by hand onto the new stack - while updating the return eip past - * the instruction that would have done it for sysenter. - */ -#define FIX_STACK(offset, ok, label) \ - cmpw $__KERNEL_CS,4(%esp); \ - jne ok; \ -label: \ - movl TSS_sysenter_sp0+offset(%esp),%esp; \ - CFI_DEF_CFA esp, 0; \ - CFI_UNDEFINED eip; \ - pushfl; \ - CFI_ADJUST_CFA_OFFSET 4; \ - pushl $__KERNEL_CS; \ - CFI_ADJUST_CFA_OFFSET 4; \ - pushl $sysenter_past_esp; \ - CFI_ADJUST_CFA_OFFSET 4; \ - CFI_REL_OFFSET eip, 0 - -KPROBE_ENTRY(debug) - RING0_INT_FRAME - cmpl $ia32_sysenter_target,(%esp) - jne debug_stack_correct - FIX_STACK(12, debug_stack_correct, debug_esp_fix_insn) -debug_stack_correct: - pushl $-1 # mark this as an int - CFI_ADJUST_CFA_OFFSET 4 - SAVE_ALL - TRACE_IRQS_OFF - xorl %edx,%edx # error code 0 - movl %esp,%eax # pt_regs pointer - call do_debug - jmp ret_from_exception - CFI_ENDPROC -KPROBE_END(debug) - -/* - * NMI is doubly nasty. It can happen _while_ we're handling - * a debug fault, and the debug fault hasn't yet been able to - * clear up the stack. So we first check whether we got an - * NMI on the sysenter entry path, but after that we need to - * check whether we got an NMI on the debug path where the debug - * fault happened on the sysenter path. - */ -KPROBE_ENTRY(nmi) - RING0_INT_FRAME - pushl %eax - CFI_ADJUST_CFA_OFFSET 4 - movl %ss, %eax - cmpw $__ESPFIX_SS, %ax - popl %eax - CFI_ADJUST_CFA_OFFSET -4 - je nmi_espfix_stack - cmpl $ia32_sysenter_target,(%esp) - je nmi_stack_fixup - pushl %eax - CFI_ADJUST_CFA_OFFSET 4 - movl %esp,%eax - /* Do not access memory above the end of our stack page, - * it might not exist. - */ - andl $(THREAD_SIZE-1),%eax - cmpl $(THREAD_SIZE-20),%eax - popl %eax - CFI_ADJUST_CFA_OFFSET -4 - jae nmi_stack_correct - cmpl $ia32_sysenter_target,12(%esp) - je nmi_debug_stack_check -nmi_stack_correct: - /* We have a RING0_INT_FRAME here */ - pushl %eax - CFI_ADJUST_CFA_OFFSET 4 - SAVE_ALL - TRACE_IRQS_OFF - xorl %edx,%edx # zero error code - movl %esp,%eax # pt_regs pointer - call do_nmi - jmp restore_nocheck_notrace - CFI_ENDPROC - -nmi_stack_fixup: - RING0_INT_FRAME - FIX_STACK(12,nmi_stack_correct, 1) - jmp nmi_stack_correct - -nmi_debug_stack_check: - /* We have a RING0_INT_FRAME here */ - cmpw $__KERNEL_CS,16(%esp) - jne nmi_stack_correct - cmpl $debug,(%esp) - jb nmi_stack_correct - cmpl $debug_esp_fix_insn,(%esp) - ja nmi_stack_correct - FIX_STACK(24,nmi_stack_correct, 1) - jmp nmi_stack_correct - -nmi_espfix_stack: - /* We have a RING0_INT_FRAME here. - * - * create the pointer to lss back - */ - pushl %ss - CFI_ADJUST_CFA_OFFSET 4 - pushl %esp - CFI_ADJUST_CFA_OFFSET 4 - addw $4, (%esp) - /* copy the iret frame of 12 bytes */ - .rept 3 - pushl 16(%esp) - CFI_ADJUST_CFA_OFFSET 4 - .endr - pushl %eax - CFI_ADJUST_CFA_OFFSET 4 - SAVE_ALL - TRACE_IRQS_OFF - FIXUP_ESPFIX_STACK # %eax == %esp - xorl %edx,%edx # zero error code - call do_nmi - RESTORE_REGS - lss 12+4(%esp), %esp # back to espfix stack - CFI_ADJUST_CFA_OFFSET -24 - jmp irq_return - CFI_ENDPROC -KPROBE_END(nmi) - #ifdef CONFIG_PARAVIRT ENTRY(native_iret) iret @@ -916,19 +733,6 @@ ENTRY(native_irq_enable_sysexit) END(native_irq_enable_sysexit) #endif -KPROBE_ENTRY(int3) - RING0_INT_FRAME - pushl $-1 # mark this as an int - CFI_ADJUST_CFA_OFFSET 4 - SAVE_ALL - TRACE_IRQS_OFF - xorl %edx,%edx # zero error code - movl %esp,%eax # pt_regs pointer - call do_int3 - jmp ret_from_exception - CFI_ENDPROC -KPROBE_END(int3) - ENTRY(overflow) RING0_INT_FRAME pushl $0 @@ -993,14 +797,6 @@ ENTRY(stack_segment) CFI_ENDPROC END(stack_segment) -KPROBE_ENTRY(general_protection) - RING0_EC_FRAME - pushl $do_general_protection - CFI_ADJUST_CFA_OFFSET 4 - jmp error_code - CFI_ENDPROC -KPROBE_END(general_protection) - ENTRY(alignment_check) RING0_EC_FRAME pushl $do_alignment_check @@ -1051,6 +847,7 @@ ENTRY(kernel_thread_helper) push %eax CFI_ADJUST_CFA_OFFSET 4 call do_exit + ud2 # padding for call trace CFI_ENDPROC ENDPROC(kernel_thread_helper) @@ -1157,6 +954,9 @@ ENTRY(mcount) END(mcount) ENTRY(ftrace_caller) + cmpl $0, function_trace_stop + jne ftrace_stub + pushl %eax pushl %ecx pushl %edx @@ -1171,6 +971,11 @@ ftrace_call: popl %edx popl %ecx popl %eax +#ifdef CONFIG_FUNCTION_GRAPH_TRACER +.globl ftrace_graph_call +ftrace_graph_call: + jmp ftrace_stub +#endif .globl ftrace_stub ftrace_stub: @@ -1180,8 +985,18 @@ END(ftrace_caller) #else /* ! CONFIG_DYNAMIC_FTRACE */ ENTRY(mcount) + cmpl $0, function_trace_stop + jne ftrace_stub + cmpl $ftrace_stub, ftrace_trace_function jnz trace +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + cmpl $ftrace_stub, ftrace_graph_return + jnz ftrace_graph_caller + + cmpl $ftrace_graph_entry_stub, ftrace_graph_entry + jnz ftrace_graph_caller +#endif .globl ftrace_stub ftrace_stub: ret @@ -1200,13 +1015,268 @@ trace: popl %edx popl %ecx popl %eax - jmp ftrace_stub END(mcount) #endif /* CONFIG_DYNAMIC_FTRACE */ #endif /* CONFIG_FUNCTION_TRACER */ +#ifdef CONFIG_FUNCTION_GRAPH_TRACER +ENTRY(ftrace_graph_caller) + cmpl $0, function_trace_stop + jne ftrace_stub + + pushl %eax + pushl %ecx + pushl %edx + movl 0xc(%esp), %edx + lea 0x4(%ebp), %eax + subl $MCOUNT_INSN_SIZE, %edx + call prepare_ftrace_return + popl %edx + popl %ecx + popl %eax + ret +END(ftrace_graph_caller) + +.globl return_to_handler +return_to_handler: + pushl $0 + pushl %eax + pushl %ecx + pushl %edx + call ftrace_return_to_handler + movl %eax, 0xc(%esp) + popl %edx + popl %ecx + popl %eax + ret +#endif + .section .rodata,"a" #include "syscall_table_32.S" syscall_table_size=(.-sys_call_table) + +/* + * Some functions should be protected against kprobes + */ + .pushsection .kprobes.text, "ax" + +ENTRY(page_fault) + RING0_EC_FRAME + pushl $do_page_fault + CFI_ADJUST_CFA_OFFSET 4 + ALIGN +error_code: + /* the function address is in %fs's slot on the stack */ + pushl %es + CFI_ADJUST_CFA_OFFSET 4 + /*CFI_REL_OFFSET es, 0*/ + pushl %ds + CFI_ADJUST_CFA_OFFSET 4 + /*CFI_REL_OFFSET ds, 0*/ + pushl %eax + CFI_ADJUST_CFA_OFFSET 4 + CFI_REL_OFFSET eax, 0 + pushl %ebp + CFI_ADJUST_CFA_OFFSET 4 + CFI_REL_OFFSET ebp, 0 + pushl %edi + CFI_ADJUST_CFA_OFFSET 4 + CFI_REL_OFFSET edi, 0 + pushl %esi + CFI_ADJUST_CFA_OFFSET 4 + CFI_REL_OFFSET esi, 0 + pushl %edx + CFI_ADJUST_CFA_OFFSET 4 + CFI_REL_OFFSET edx, 0 + pushl %ecx + CFI_ADJUST_CFA_OFFSET 4 + CFI_REL_OFFSET ecx, 0 + pushl %ebx + CFI_ADJUST_CFA_OFFSET 4 + CFI_REL_OFFSET ebx, 0 + cld + pushl %fs + CFI_ADJUST_CFA_OFFSET 4 + /*CFI_REL_OFFSET fs, 0*/ + movl $(__KERNEL_PERCPU), %ecx + movl %ecx, %fs + UNWIND_ESPFIX_STACK + popl %ecx + CFI_ADJUST_CFA_OFFSET -4 + /*CFI_REGISTER es, ecx*/ + movl PT_FS(%esp), %edi # get the function address + movl PT_ORIG_EAX(%esp), %edx # get the error code + movl $-1, PT_ORIG_EAX(%esp) # no syscall to restart + mov %ecx, PT_FS(%esp) + /*CFI_REL_OFFSET fs, ES*/ + movl $(__USER_DS), %ecx + movl %ecx, %ds + movl %ecx, %es + TRACE_IRQS_OFF + movl %esp,%eax # pt_regs pointer + call *%edi + jmp ret_from_exception + CFI_ENDPROC +END(page_fault) + +/* + * Debug traps and NMI can happen at the one SYSENTER instruction + * that sets up the real kernel stack. Check here, since we can't + * allow the wrong stack to be used. + * + * "TSS_sysenter_sp0+12" is because the NMI/debug handler will have + * already pushed 3 words if it hits on the sysenter instruction: + * eflags, cs and eip. + * + * We just load the right stack, and push the three (known) values + * by hand onto the new stack - while updating the return eip past + * the instruction that would have done it for sysenter. + */ +#define FIX_STACK(offset, ok, label) \ + cmpw $__KERNEL_CS,4(%esp); \ + jne ok; \ +label: \ + movl TSS_sysenter_sp0+offset(%esp),%esp; \ + CFI_DEF_CFA esp, 0; \ + CFI_UNDEFINED eip; \ + pushfl; \ + CFI_ADJUST_CFA_OFFSET 4; \ + pushl $__KERNEL_CS; \ + CFI_ADJUST_CFA_OFFSET 4; \ + pushl $sysenter_past_esp; \ + CFI_ADJUST_CFA_OFFSET 4; \ + CFI_REL_OFFSET eip, 0 + +ENTRY(debug) + RING0_INT_FRAME + cmpl $ia32_sysenter_target,(%esp) + jne debug_stack_correct + FIX_STACK(12, debug_stack_correct, debug_esp_fix_insn) +debug_stack_correct: + pushl $-1 # mark this as an int + CFI_ADJUST_CFA_OFFSET 4 + SAVE_ALL + TRACE_IRQS_OFF + xorl %edx,%edx # error code 0 + movl %esp,%eax # pt_regs pointer + call do_debug + jmp ret_from_exception + CFI_ENDPROC +END(debug) + +/* + * NMI is doubly nasty. It can happen _while_ we're handling + * a debug fault, and the debug fault hasn't yet been able to + * clear up the stack. So we first check whether we got an + * NMI on the sysenter entry path, but after that we need to + * check whether we got an NMI on the debug path where the debug + * fault happened on the sysenter path. + */ +ENTRY(nmi) + RING0_INT_FRAME + pushl %eax + CFI_ADJUST_CFA_OFFSET 4 + movl %ss, %eax + cmpw $__ESPFIX_SS, %ax + popl %eax + CFI_ADJUST_CFA_OFFSET -4 + je nmi_espfix_stack + cmpl $ia32_sysenter_target,(%esp) + je nmi_stack_fixup + pushl %eax + CFI_ADJUST_CFA_OFFSET 4 + movl %esp,%eax + /* Do not access memory above the end of our stack page, + * it might not exist. + */ + andl $(THREAD_SIZE-1),%eax + cmpl $(THREAD_SIZE-20),%eax + popl %eax + CFI_ADJUST_CFA_OFFSET -4 + jae nmi_stack_correct + cmpl $ia32_sysenter_target,12(%esp) + je nmi_debug_stack_check +nmi_stack_correct: + /* We have a RING0_INT_FRAME here */ + pushl %eax + CFI_ADJUST_CFA_OFFSET 4 + SAVE_ALL + TRACE_IRQS_OFF + xorl %edx,%edx # zero error code + movl %esp,%eax # pt_regs pointer + call do_nmi + jmp restore_nocheck_notrace + CFI_ENDPROC + +nmi_stack_fixup: + RING0_INT_FRAME + FIX_STACK(12,nmi_stack_correct, 1) + jmp nmi_stack_correct + +nmi_debug_stack_check: + /* We have a RING0_INT_FRAME here */ + cmpw $__KERNEL_CS,16(%esp) + jne nmi_stack_correct + cmpl $debug,(%esp) + jb nmi_stack_correct + cmpl $debug_esp_fix_insn,(%esp) + ja nmi_stack_correct + FIX_STACK(24,nmi_stack_correct, 1) + jmp nmi_stack_correct + +nmi_espfix_stack: + /* We have a RING0_INT_FRAME here. + * + * create the pointer to lss back + */ + pushl %ss + CFI_ADJUST_CFA_OFFSET 4 + pushl %esp + CFI_ADJUST_CFA_OFFSET 4 + addw $4, (%esp) + /* copy the iret frame of 12 bytes */ + .rept 3 + pushl 16(%esp) + CFI_ADJUST_CFA_OFFSET 4 + .endr + pushl %eax + CFI_ADJUST_CFA_OFFSET 4 + SAVE_ALL + TRACE_IRQS_OFF + FIXUP_ESPFIX_STACK # %eax == %esp + xorl %edx,%edx # zero error code + call do_nmi + RESTORE_REGS + lss 12+4(%esp), %esp # back to espfix stack + CFI_ADJUST_CFA_OFFSET -24 + jmp irq_return + CFI_ENDPROC +END(nmi) + +ENTRY(int3) + RING0_INT_FRAME + pushl $-1 # mark this as an int + CFI_ADJUST_CFA_OFFSET 4 + SAVE_ALL + TRACE_IRQS_OFF + xorl %edx,%edx # zero error code + movl %esp,%eax # pt_regs pointer + call do_int3 + jmp ret_from_exception + CFI_ENDPROC +END(int3) + +ENTRY(general_protection) + RING0_EC_FRAME + pushl $do_general_protection + CFI_ADJUST_CFA_OFFSET 4 + jmp error_code + CFI_ENDPROC +END(general_protection) + +/* + * End of kprobes section + */ + .popsection diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index b86f332c96a66596f0fe076d7c0eda78ea05dbe5..e28c7a987793cbd25c628c7568fc15ca2c8c39f5 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S @@ -11,15 +11,15 @@ * * NOTE: This code handles signal-recognition, which happens every time * after an interrupt and after each system call. - * - * Normal syscalls and interrupts don't save a full stack frame, this is + * + * Normal syscalls and interrupts don't save a full stack frame, this is * only done for syscall tracing, signals or fork/exec et.al. - * - * A note on terminology: - * - top of stack: Architecture defined interrupt frame from SS to RIP - * at the top of the kernel process stack. + * + * A note on terminology: + * - top of stack: Architecture defined interrupt frame from SS to RIP + * at the top of the kernel process stack. * - partial stack frame: partially saved registers upto R11. - * - full stack frame: Like partial stack frame, but all register saved. + * - full stack frame: Like partial stack frame, but all register saved. * * Some macro usage: * - CFI macros are used to generate dwarf2 unwind information for better @@ -60,7 +60,6 @@ #define __AUDIT_ARCH_LE 0x40000000 .code64 - #ifdef CONFIG_FUNCTION_TRACER #ifdef CONFIG_DYNAMIC_FTRACE ENTRY(mcount) @@ -68,16 +67,10 @@ ENTRY(mcount) END(mcount) ENTRY(ftrace_caller) + cmpl $0, function_trace_stop + jne ftrace_stub - /* taken from glibc */ - subq $0x38, %rsp - movq %rax, (%rsp) - movq %rcx, 8(%rsp) - movq %rdx, 16(%rsp) - movq %rsi, 24(%rsp) - movq %rdi, 32(%rsp) - movq %r8, 40(%rsp) - movq %r9, 48(%rsp) + MCOUNT_SAVE_FRAME movq 0x38(%rsp), %rdi movq 8(%rbp), %rsi @@ -87,14 +80,13 @@ ENTRY(ftrace_caller) ftrace_call: call ftrace_stub - movq 48(%rsp), %r9 - movq 40(%rsp), %r8 - movq 32(%rsp), %rdi - movq 24(%rsp), %rsi - movq 16(%rsp), %rdx - movq 8(%rsp), %rcx - movq (%rsp), %rax - addq $0x38, %rsp + MCOUNT_RESTORE_FRAME + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER +.globl ftrace_graph_call +ftrace_graph_call: + jmp ftrace_stub +#endif .globl ftrace_stub ftrace_stub: @@ -103,15 +95,63 @@ END(ftrace_caller) #else /* ! CONFIG_DYNAMIC_FTRACE */ ENTRY(mcount) + cmpl $0, function_trace_stop + jne ftrace_stub + cmpq $ftrace_stub, ftrace_trace_function jnz trace + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + cmpq $ftrace_stub, ftrace_graph_return + jnz ftrace_graph_caller + + cmpq $ftrace_graph_entry_stub, ftrace_graph_entry + jnz ftrace_graph_caller +#endif + .globl ftrace_stub ftrace_stub: retq trace: - /* taken from glibc */ - subq $0x38, %rsp + MCOUNT_SAVE_FRAME + + movq 0x38(%rsp), %rdi + movq 8(%rbp), %rsi + subq $MCOUNT_INSN_SIZE, %rdi + + call *ftrace_trace_function + + MCOUNT_RESTORE_FRAME + + jmp ftrace_stub +END(mcount) +#endif /* CONFIG_DYNAMIC_FTRACE */ +#endif /* CONFIG_FUNCTION_TRACER */ + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER +ENTRY(ftrace_graph_caller) + cmpl $0, function_trace_stop + jne ftrace_stub + + MCOUNT_SAVE_FRAME + + leaq 8(%rbp), %rdi + movq 0x38(%rsp), %rsi + subq $MCOUNT_INSN_SIZE, %rsi + + call prepare_ftrace_return + + MCOUNT_RESTORE_FRAME + + retq +END(ftrace_graph_caller) + + +.globl return_to_handler +return_to_handler: + subq $80, %rsp + movq %rax, (%rsp) movq %rcx, 8(%rsp) movq %rdx, 16(%rsp) @@ -119,13 +159,14 @@ trace: movq %rdi, 32(%rsp) movq %r8, 40(%rsp) movq %r9, 48(%rsp) + movq %r10, 56(%rsp) + movq %r11, 64(%rsp) - movq 0x38(%rsp), %rdi - movq 8(%rbp), %rsi - subq $MCOUNT_INSN_SIZE, %rdi - - call *ftrace_trace_function + call ftrace_return_to_handler + movq %rax, 72(%rsp) + movq 64(%rsp), %r11 + movq 56(%rsp), %r10 movq 48(%rsp), %r9 movq 40(%rsp), %r8 movq 32(%rsp), %rdi @@ -133,16 +174,14 @@ trace: movq 16(%rsp), %rdx movq 8(%rsp), %rcx movq (%rsp), %rax - addq $0x38, %rsp + addq $72, %rsp + retq +#endif - jmp ftrace_stub -END(mcount) -#endif /* CONFIG_DYNAMIC_FTRACE */ -#endif /* CONFIG_FUNCTION_TRACER */ #ifndef CONFIG_PREEMPT #define retint_kernel retint_restore_args -#endif +#endif #ifdef CONFIG_PARAVIRT ENTRY(native_usergs_sysret64) @@ -161,29 +200,29 @@ ENTRY(native_usergs_sysret64) .endm /* - * C code is not supposed to know about undefined top of stack. Every time - * a C function with an pt_regs argument is called from the SYSCALL based + * C code is not supposed to know about undefined top of stack. Every time + * a C function with an pt_regs argument is called from the SYSCALL based * fast path FIXUP_TOP_OF_STACK is needed. * RESTORE_TOP_OF_STACK syncs the syscall state after any possible ptregs * manipulation. - */ - - /* %rsp:at FRAMEEND */ - .macro FIXUP_TOP_OF_STACK tmp - movq %gs:pda_oldrsp,\tmp - movq \tmp,RSP(%rsp) - movq $__USER_DS,SS(%rsp) - movq $__USER_CS,CS(%rsp) - movq $-1,RCX(%rsp) - movq R11(%rsp),\tmp /* get eflags */ - movq \tmp,EFLAGS(%rsp) + */ + + /* %rsp:at FRAMEEND */ + .macro FIXUP_TOP_OF_STACK tmp offset=0 + movq %gs:pda_oldrsp,\tmp + movq \tmp,RSP+\offset(%rsp) + movq $__USER_DS,SS+\offset(%rsp) + movq $__USER_CS,CS+\offset(%rsp) + movq $-1,RCX+\offset(%rsp) + movq R11+\offset(%rsp),\tmp /* get eflags */ + movq \tmp,EFLAGS+\offset(%rsp) .endm - .macro RESTORE_TOP_OF_STACK tmp,offset=0 - movq RSP-\offset(%rsp),\tmp - movq \tmp,%gs:pda_oldrsp - movq EFLAGS-\offset(%rsp),\tmp - movq \tmp,R11-\offset(%rsp) + .macro RESTORE_TOP_OF_STACK tmp offset=0 + movq RSP+\offset(%rsp),\tmp + movq \tmp,%gs:pda_oldrsp + movq EFLAGS+\offset(%rsp),\tmp + movq \tmp,R11+\offset(%rsp) .endm .macro FAKE_STACK_FRAME child_rip @@ -195,7 +234,7 @@ ENTRY(native_usergs_sysret64) pushq %rax /* rsp */ CFI_ADJUST_CFA_OFFSET 8 CFI_REL_OFFSET rsp,0 - pushq $(1<<9) /* eflags - interrupts on */ + pushq $X86_EFLAGS_IF /* eflags - interrupts on */ CFI_ADJUST_CFA_OFFSET 8 /*CFI_REL_OFFSET rflags,0*/ pushq $__KERNEL_CS /* cs */ @@ -213,62 +252,184 @@ ENTRY(native_usergs_sysret64) CFI_ADJUST_CFA_OFFSET -(6*8) .endm - .macro CFI_DEFAULT_STACK start=1 +/* + * initial frame state for interrupts (and exceptions without error code) + */ + .macro EMPTY_FRAME start=1 offset=0 .if \start - CFI_STARTPROC simple + CFI_STARTPROC simple CFI_SIGNAL_FRAME - CFI_DEF_CFA rsp,SS+8 + CFI_DEF_CFA rsp,8+\offset .else - CFI_DEF_CFA_OFFSET SS+8 + CFI_DEF_CFA_OFFSET 8+\offset .endif - CFI_REL_OFFSET r15,R15 - CFI_REL_OFFSET r14,R14 - CFI_REL_OFFSET r13,R13 - CFI_REL_OFFSET r12,R12 - CFI_REL_OFFSET rbp,RBP - CFI_REL_OFFSET rbx,RBX - CFI_REL_OFFSET r11,R11 - CFI_REL_OFFSET r10,R10 - CFI_REL_OFFSET r9,R9 - CFI_REL_OFFSET r8,R8 - CFI_REL_OFFSET rax,RAX - CFI_REL_OFFSET rcx,RCX - CFI_REL_OFFSET rdx,RDX - CFI_REL_OFFSET rsi,RSI - CFI_REL_OFFSET rdi,RDI - CFI_REL_OFFSET rip,RIP - /*CFI_REL_OFFSET cs,CS*/ - /*CFI_REL_OFFSET rflags,EFLAGS*/ - CFI_REL_OFFSET rsp,RSP - /*CFI_REL_OFFSET ss,SS*/ .endm + +/* + * initial frame state for interrupts (and exceptions without error code) + */ + .macro INTR_FRAME start=1 offset=0 + EMPTY_FRAME \start, SS+8+\offset-RIP + /*CFI_REL_OFFSET ss, SS+\offset-RIP*/ + CFI_REL_OFFSET rsp, RSP+\offset-RIP + /*CFI_REL_OFFSET rflags, EFLAGS+\offset-RIP*/ + /*CFI_REL_OFFSET cs, CS+\offset-RIP*/ + CFI_REL_OFFSET rip, RIP+\offset-RIP + .endm + +/* + * initial frame state for exceptions with error code (and interrupts + * with vector already pushed) + */ + .macro XCPT_FRAME start=1 offset=0 + INTR_FRAME \start, RIP+\offset-ORIG_RAX + /*CFI_REL_OFFSET orig_rax, ORIG_RAX-ORIG_RAX*/ + .endm + /* - * A newly forked process directly context switches into this. - */ -/* rdi: prev */ + * frame that enables calling into C. + */ + .macro PARTIAL_FRAME start=1 offset=0 + XCPT_FRAME \start, ORIG_RAX+\offset-ARGOFFSET + CFI_REL_OFFSET rdi, RDI+\offset-ARGOFFSET + CFI_REL_OFFSET rsi, RSI+\offset-ARGOFFSET + CFI_REL_OFFSET rdx, RDX+\offset-ARGOFFSET + CFI_REL_OFFSET rcx, RCX+\offset-ARGOFFSET + CFI_REL_OFFSET rax, RAX+\offset-ARGOFFSET + CFI_REL_OFFSET r8, R8+\offset-ARGOFFSET + CFI_REL_OFFSET r9, R9+\offset-ARGOFFSET + CFI_REL_OFFSET r10, R10+\offset-ARGOFFSET + CFI_REL_OFFSET r11, R11+\offset-ARGOFFSET + .endm + +/* + * frame that enables passing a complete pt_regs to a C function. + */ + .macro DEFAULT_FRAME start=1 offset=0 + PARTIAL_FRAME \start, R11+\offset-R15 + CFI_REL_OFFSET rbx, RBX+\offset + CFI_REL_OFFSET rbp, RBP+\offset + CFI_REL_OFFSET r12, R12+\offset + CFI_REL_OFFSET r13, R13+\offset + CFI_REL_OFFSET r14, R14+\offset + CFI_REL_OFFSET r15, R15+\offset + .endm + +/* save partial stack frame */ +ENTRY(save_args) + XCPT_FRAME + cld + movq_cfi rdi, RDI+16-ARGOFFSET + movq_cfi rsi, RSI+16-ARGOFFSET + movq_cfi rdx, RDX+16-ARGOFFSET + movq_cfi rcx, RCX+16-ARGOFFSET + movq_cfi rax, RAX+16-ARGOFFSET + movq_cfi r8, R8+16-ARGOFFSET + movq_cfi r9, R9+16-ARGOFFSET + movq_cfi r10, R10+16-ARGOFFSET + movq_cfi r11, R11+16-ARGOFFSET + + leaq -ARGOFFSET+16(%rsp),%rdi /* arg1 for handler */ + movq_cfi rbp, 8 /* push %rbp */ + leaq 8(%rsp), %rbp /* mov %rsp, %ebp */ + testl $3, CS(%rdi) + je 1f + SWAPGS + /* + * irqcount is used to check if a CPU is already on an interrupt stack + * or not. While this is essentially redundant with preempt_count it is + * a little cheaper to use a separate counter in the PDA (short of + * moving irq_enter into assembly, which would be too much work) + */ +1: incl %gs:pda_irqcount + jne 2f + popq_cfi %rax /* move return address... */ + mov %gs:pda_irqstackptr,%rsp + EMPTY_FRAME 0 + pushq_cfi %rax /* ... to the new stack */ + /* + * We entered an interrupt context - irqs are off: + */ +2: TRACE_IRQS_OFF + ret + CFI_ENDPROC +END(save_args) + +ENTRY(save_rest) + PARTIAL_FRAME 1 REST_SKIP+8 + movq 5*8+16(%rsp), %r11 /* save return address */ + movq_cfi rbx, RBX+16 + movq_cfi rbp, RBP+16 + movq_cfi r12, R12+16 + movq_cfi r13, R13+16 + movq_cfi r14, R14+16 + movq_cfi r15, R15+16 + movq %r11, 8(%rsp) /* return address */ + FIXUP_TOP_OF_STACK %r11, 16 + ret + CFI_ENDPROC +END(save_rest) + +/* save complete stack frame */ +ENTRY(save_paranoid) + XCPT_FRAME 1 RDI+8 + cld + movq_cfi rdi, RDI+8 + movq_cfi rsi, RSI+8 + movq_cfi rdx, RDX+8 + movq_cfi rcx, RCX+8 + movq_cfi rax, RAX+8 + movq_cfi r8, R8+8 + movq_cfi r9, R9+8 + movq_cfi r10, R10+8 + movq_cfi r11, R11+8 + movq_cfi rbx, RBX+8 + movq_cfi rbp, RBP+8 + movq_cfi r12, R12+8 + movq_cfi r13, R13+8 + movq_cfi r14, R14+8 + movq_cfi r15, R15+8 + movl $1,%ebx + movl $MSR_GS_BASE,%ecx + rdmsr + testl %edx,%edx + js 1f /* negative -> in kernel */ + SWAPGS + xorl %ebx,%ebx +1: ret + CFI_ENDPROC +END(save_paranoid) + +/* + * A newly forked process directly context switches into this address. + * + * rdi: prev task we switched from + */ ENTRY(ret_from_fork) - CFI_DEFAULT_STACK + DEFAULT_FRAME + push kernel_eflags(%rip) CFI_ADJUST_CFA_OFFSET 8 - popf # reset kernel eflags + popf # reset kernel eflags CFI_ADJUST_CFA_OFFSET -8 - call schedule_tail + + call schedule_tail # rdi: 'prev' task parameter + GET_THREAD_INFO(%rcx) - testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%rcx) - jnz rff_trace -rff_action: + + CFI_REMEMBER_STATE RESTORE_REST - testl $3,CS-ARGOFFSET(%rsp) # from kernel_thread? + + testl $3, CS-ARGOFFSET(%rsp) # from kernel_thread? je int_ret_from_sys_call - testl $_TIF_IA32,TI_flags(%rcx) + + testl $_TIF_IA32, TI_flags(%rcx) # 32-bit compat task needs IRET jnz int_ret_from_sys_call - RESTORE_TOP_OF_STACK %rdi,ARGOFFSET - jmp ret_from_sys_call -rff_trace: - movq %rsp,%rdi - call syscall_trace_leave - GET_THREAD_INFO(%rcx) - jmp rff_action + + RESTORE_TOP_OF_STACK %rdi, -ARGOFFSET + jmp ret_from_sys_call # go to the SYSRET fastpath + + CFI_RESTORE_STATE CFI_ENDPROC END(ret_from_fork) @@ -278,20 +439,20 @@ END(ret_from_fork) * SYSCALL does not save anything on the stack and does not change the * stack pointer. */ - + /* - * Register setup: + * Register setup: * rax system call number * rdi arg0 - * rcx return address for syscall/sysret, C arg3 + * rcx return address for syscall/sysret, C arg3 * rsi arg1 - * rdx arg2 + * rdx arg2 * r10 arg3 (--> moved to rcx for C) * r8 arg4 * r9 arg5 * r11 eflags for syscall/sysret, temporary for C - * r12-r15,rbp,rbx saved by C code, not touched. - * + * r12-r15,rbp,rbx saved by C code, not touched. + * * Interrupts are off on entry. * Only called from user space. * @@ -301,7 +462,7 @@ END(ret_from_fork) * When user can change the frames always force IRET. That is because * it deals with uncanonical addresses better. SYSRET has trouble * with them due to bugs in both AMD and Intel CPUs. - */ + */ ENTRY(system_call) CFI_STARTPROC simple @@ -317,7 +478,7 @@ ENTRY(system_call) */ ENTRY(system_call_after_swapgs) - movq %rsp,%gs:pda_oldrsp + movq %rsp,%gs:pda_oldrsp movq %gs:pda_kernelstack,%rsp /* * No need to follow this irqs off/on section - it's straight @@ -325,7 +486,7 @@ ENTRY(system_call_after_swapgs) */ ENABLE_INTERRUPTS(CLBR_NONE) SAVE_ARGS 8,1 - movq %rax,ORIG_RAX-ARGOFFSET(%rsp) + movq %rax,ORIG_RAX-ARGOFFSET(%rsp) movq %rcx,RIP-ARGOFFSET(%rsp) CFI_REL_OFFSET rip,RIP-ARGOFFSET GET_THREAD_INFO(%rcx) @@ -339,19 +500,19 @@ system_call_fastpath: movq %rax,RAX-ARGOFFSET(%rsp) /* * Syscall return path ending with SYSRET (fast path) - * Has incomplete stack frame and undefined top of stack. - */ + * Has incomplete stack frame and undefined top of stack. + */ ret_from_sys_call: movl $_TIF_ALLWORK_MASK,%edi /* edi: flagmask */ -sysret_check: +sysret_check: LOCKDEP_SYS_EXIT GET_THREAD_INFO(%rcx) DISABLE_INTERRUPTS(CLBR_NONE) TRACE_IRQS_OFF movl TI_flags(%rcx),%edx andl %edi,%edx - jnz sysret_careful + jnz sysret_careful CFI_REMEMBER_STATE /* * sysretq will re-enable interrupts: @@ -366,7 +527,7 @@ sysret_check: CFI_RESTORE_STATE /* Handle reschedules */ - /* edx: work, edi: workmask */ + /* edx: work, edi: workmask */ sysret_careful: bt $TIF_NEED_RESCHED,%edx jnc sysret_signal @@ -379,7 +540,7 @@ sysret_careful: CFI_ADJUST_CFA_OFFSET -8 jmp sysret_check - /* Handle a signal */ + /* Handle a signal */ sysret_signal: TRACE_IRQS_ON ENABLE_INTERRUPTS(CLBR_NONE) @@ -388,17 +549,20 @@ sysret_signal: jc sysret_audit #endif /* edx: work flags (arg3) */ - leaq do_notify_resume(%rip),%rax leaq -ARGOFFSET(%rsp),%rdi # &pt_regs -> arg1 xorl %esi,%esi # oldset -> arg2 - call ptregscall_common + SAVE_REST + FIXUP_TOP_OF_STACK %r11 + call do_notify_resume + RESTORE_TOP_OF_STACK %r11 + RESTORE_REST movl $_TIF_WORK_MASK,%edi /* Use IRET because user could have changed frame. This works because ptregscall_common has called FIXUP_TOP_OF_STACK. */ DISABLE_INTERRUPTS(CLBR_NONE) TRACE_IRQS_OFF jmp int_with_check - + badsys: movq $-ENOSYS,RAX-ARGOFFSET(%rsp) jmp ret_from_sys_call @@ -437,7 +601,7 @@ sysret_audit: #endif /* CONFIG_AUDITSYSCALL */ /* Do syscall tracing */ -tracesys: +tracesys: #ifdef CONFIG_AUDITSYSCALL testl $(_TIF_WORK_SYSCALL_ENTRY & ~_TIF_SYSCALL_AUDIT),TI_flags(%rcx) jz auditsys @@ -460,8 +624,8 @@ tracesys: call *sys_call_table(,%rax,8) movq %rax,RAX-ARGOFFSET(%rsp) /* Use IRET because user could have changed frame */ - -/* + +/* * Syscall return path ending with IRET. * Has correct top of stack, but partial stack frame. */ @@ -505,18 +669,18 @@ int_very_careful: TRACE_IRQS_ON ENABLE_INTERRUPTS(CLBR_NONE) SAVE_REST - /* Check for syscall exit trace */ + /* Check for syscall exit trace */ testl $_TIF_WORK_SYSCALL_EXIT,%edx jz int_signal pushq %rdi CFI_ADJUST_CFA_OFFSET 8 - leaq 8(%rsp),%rdi # &ptregs -> arg1 + leaq 8(%rsp),%rdi # &ptregs -> arg1 call syscall_trace_leave popq %rdi CFI_ADJUST_CFA_OFFSET -8 andl $~(_TIF_WORK_SYSCALL_EXIT|_TIF_SYSCALL_EMU),%edi jmp int_restore_rest - + int_signal: testl $_TIF_DO_NOTIFY_MASK,%edx jz 1f @@ -531,22 +695,24 @@ int_restore_rest: jmp int_with_check CFI_ENDPROC END(system_call) - -/* + +/* * Certain special system calls that need to save a complete full stack frame. - */ - + */ .macro PTREGSCALL label,func,arg - .globl \label -\label: - leaq \func(%rip),%rax - leaq -ARGOFFSET+8(%rsp),\arg /* 8 for return address */ - jmp ptregscall_common +ENTRY(\label) + PARTIAL_FRAME 1 8 /* offset 8: return address */ + subq $REST_SKIP, %rsp + CFI_ADJUST_CFA_OFFSET REST_SKIP + call save_rest + DEFAULT_FRAME 0 8 /* offset 8: return address */ + leaq 8(%rsp), \arg /* pt_regs pointer */ + call \func + jmp ptregscall_common + CFI_ENDPROC END(\label) .endm - CFI_STARTPROC - PTREGSCALL stub_clone, sys_clone, %r8 PTREGSCALL stub_fork, sys_fork, %rdi PTREGSCALL stub_vfork, sys_vfork, %rdi @@ -554,25 +720,18 @@ END(\label) PTREGSCALL stub_iopl, sys_iopl, %rsi ENTRY(ptregscall_common) - popq %r11 - CFI_ADJUST_CFA_OFFSET -8 - CFI_REGISTER rip, r11 - SAVE_REST - movq %r11, %r15 - CFI_REGISTER rip, r15 - FIXUP_TOP_OF_STACK %r11 - call *%rax - RESTORE_TOP_OF_STACK %r11 - movq %r15, %r11 - CFI_REGISTER rip, r11 - RESTORE_REST - pushq %r11 - CFI_ADJUST_CFA_OFFSET 8 - CFI_REL_OFFSET rip, 0 - ret + DEFAULT_FRAME 1 8 /* offset 8: return address */ + RESTORE_TOP_OF_STACK %r11, 8 + movq_cfi_restore R15+8, r15 + movq_cfi_restore R14+8, r14 + movq_cfi_restore R13+8, r13 + movq_cfi_restore R12+8, r12 + movq_cfi_restore RBP+8, rbp + movq_cfi_restore RBX+8, rbx + ret $REST_SKIP /* pop extended registers */ CFI_ENDPROC END(ptregscall_common) - + ENTRY(stub_execve) CFI_STARTPROC popq %r11 @@ -588,11 +747,11 @@ ENTRY(stub_execve) jmp int_ret_from_sys_call CFI_ENDPROC END(stub_execve) - + /* * sigreturn is special because it needs to restore all registers on return. * This cannot be done with SYSRET, so use the IRET return path instead. - */ + */ ENTRY(stub_rt_sigreturn) CFI_STARTPROC addq $8, %rsp @@ -608,70 +767,70 @@ ENTRY(stub_rt_sigreturn) END(stub_rt_sigreturn) /* - * initial frame state for interrupts and exceptions + * Build the entry stubs and pointer table with some assembler magic. + * We pack 7 stubs into a single 32-byte chunk, which will fit in a + * single cache line on all modern x86 implementations. */ - .macro _frame ref - CFI_STARTPROC simple - CFI_SIGNAL_FRAME - CFI_DEF_CFA rsp,SS+8-\ref - /*CFI_REL_OFFSET ss,SS-\ref*/ - CFI_REL_OFFSET rsp,RSP-\ref - /*CFI_REL_OFFSET rflags,EFLAGS-\ref*/ - /*CFI_REL_OFFSET cs,CS-\ref*/ - CFI_REL_OFFSET rip,RIP-\ref - .endm + .section .init.rodata,"a" +ENTRY(interrupt) + .text + .p2align 5 + .p2align CONFIG_X86_L1_CACHE_SHIFT +ENTRY(irq_entries_start) + INTR_FRAME +vector=FIRST_EXTERNAL_VECTOR +.rept (NR_VECTORS-FIRST_EXTERNAL_VECTOR+6)/7 + .balign 32 + .rept 7 + .if vector < NR_VECTORS + .if vector <> FIRST_EXTERNAL_VECTOR + CFI_ADJUST_CFA_OFFSET -8 + .endif +1: pushq $(~vector+0x80) /* Note: always in signed byte range */ + CFI_ADJUST_CFA_OFFSET 8 + .if ((vector-FIRST_EXTERNAL_VECTOR)%7) <> 6 + jmp 2f + .endif + .previous + .quad 1b + .text +vector=vector+1 + .endif + .endr +2: jmp common_interrupt +.endr + CFI_ENDPROC +END(irq_entries_start) -/* initial frame state for interrupts (and exceptions without error code) */ -#define INTR_FRAME _frame RIP -/* initial frame state for exceptions with error code (and interrupts with - vector already pushed) */ -#define XCPT_FRAME _frame ORIG_RAX +.previous +END(interrupt) +.previous -/* +/* * Interrupt entry/exit. * * Interrupt entry points save only callee clobbered registers in fast path. - * - * Entry runs with interrupts off. - */ + * + * Entry runs with interrupts off. + */ -/* 0(%rsp): interrupt number */ +/* 0(%rsp): ~(interrupt number) */ .macro interrupt func - cld - SAVE_ARGS - leaq -ARGOFFSET(%rsp),%rdi # arg1 for handler - pushq %rbp - /* - * Save rbp twice: One is for marking the stack frame, as usual, and the - * other, to fill pt_regs properly. This is because bx comes right - * before the last saved register in that structure, and not bp. If the - * base pointer were in the place bx is today, this would not be needed. - */ - movq %rbp, -8(%rsp) - CFI_ADJUST_CFA_OFFSET 8 - CFI_REL_OFFSET rbp, 0 - movq %rsp,%rbp - CFI_DEF_CFA_REGISTER rbp - testl $3,CS(%rdi) - je 1f - SWAPGS - /* irqcount is used to check if a CPU is already on an interrupt - stack or not. While this is essentially redundant with preempt_count - it is a little cheaper to use a separate counter in the PDA - (short of moving irq_enter into assembly, which would be too - much work) */ -1: incl %gs:pda_irqcount - cmoveq %gs:pda_irqstackptr,%rsp - push %rbp # backlink for old unwinder - /* - * We entered an interrupt context - irqs are off: - */ - TRACE_IRQS_OFF + subq $10*8, %rsp + CFI_ADJUST_CFA_OFFSET 10*8 + call save_args + PARTIAL_FRAME 0 call \func .endm -ENTRY(common_interrupt) + /* + * The interrupt stubs push (~vector+0x80) onto the stack and + * then jump to common_interrupt. + */ + .p2align CONFIG_X86_L1_CACHE_SHIFT +common_interrupt: XCPT_FRAME + addq $-0x80,(%rsp) /* Adjust vector to [-256,-1] range */ interrupt do_IRQ /* 0(%rsp): oldrsp-ARGOFFSET */ ret_from_intr: @@ -685,12 +844,12 @@ exit_intr: GET_THREAD_INFO(%rcx) testl $3,CS-ARGOFFSET(%rsp) je retint_kernel - + /* Interrupt came from user space */ /* * Has a correct top of stack, but a partial stack frame * %rcx: thread info. Interrupts off. - */ + */ retint_with_reschedule: movl $_TIF_WORK_MASK,%edi retint_check: @@ -763,20 +922,20 @@ retint_careful: pushq %rdi CFI_ADJUST_CFA_OFFSET 8 call schedule - popq %rdi + popq %rdi CFI_ADJUST_CFA_OFFSET -8 GET_THREAD_INFO(%rcx) DISABLE_INTERRUPTS(CLBR_NONE) TRACE_IRQS_OFF jmp retint_check - + retint_signal: testl $_TIF_DO_NOTIFY_MASK,%edx jz retint_swapgs TRACE_IRQS_ON ENABLE_INTERRUPTS(CLBR_NONE) SAVE_REST - movq $-1,ORIG_RAX(%rsp) + movq $-1,ORIG_RAX(%rsp) xorl %esi,%esi # oldset movq %rsp,%rdi # &pt_regs call do_notify_resume @@ -798,324 +957,211 @@ ENTRY(retint_kernel) jnc retint_restore_args call preempt_schedule_irq jmp exit_intr -#endif +#endif CFI_ENDPROC END(common_interrupt) - + /* * APIC interrupts. - */ - .macro apicinterrupt num,func + */ +.macro apicinterrupt num sym do_sym +ENTRY(\sym) INTR_FRAME pushq $~(\num) CFI_ADJUST_CFA_OFFSET 8 - interrupt \func + interrupt \do_sym jmp ret_from_intr CFI_ENDPROC - .endm - -ENTRY(thermal_interrupt) - apicinterrupt THERMAL_APIC_VECTOR,smp_thermal_interrupt -END(thermal_interrupt) - -ENTRY(threshold_interrupt) - apicinterrupt THRESHOLD_APIC_VECTOR,mce_threshold_interrupt -END(threshold_interrupt) - -#ifdef CONFIG_SMP -ENTRY(reschedule_interrupt) - apicinterrupt RESCHEDULE_VECTOR,smp_reschedule_interrupt -END(reschedule_interrupt) - - .macro INVALIDATE_ENTRY num -ENTRY(invalidate_interrupt\num) - apicinterrupt INVALIDATE_TLB_VECTOR_START+\num,smp_invalidate_interrupt -END(invalidate_interrupt\num) - .endm +END(\sym) +.endm - INVALIDATE_ENTRY 0 - INVALIDATE_ENTRY 1 - INVALIDATE_ENTRY 2 - INVALIDATE_ENTRY 3 - INVALIDATE_ENTRY 4 - INVALIDATE_ENTRY 5 - INVALIDATE_ENTRY 6 - INVALIDATE_ENTRY 7 - -ENTRY(call_function_interrupt) - apicinterrupt CALL_FUNCTION_VECTOR,smp_call_function_interrupt -END(call_function_interrupt) -ENTRY(call_function_single_interrupt) - apicinterrupt CALL_FUNCTION_SINGLE_VECTOR,smp_call_function_single_interrupt -END(call_function_single_interrupt) -ENTRY(irq_move_cleanup_interrupt) - apicinterrupt IRQ_MOVE_CLEANUP_VECTOR,smp_irq_move_cleanup_interrupt -END(irq_move_cleanup_interrupt) +#ifdef CONFIG_SMP +apicinterrupt IRQ_MOVE_CLEANUP_VECTOR \ + irq_move_cleanup_interrupt smp_irq_move_cleanup_interrupt #endif -ENTRY(apic_timer_interrupt) - apicinterrupt LOCAL_TIMER_VECTOR,smp_apic_timer_interrupt -END(apic_timer_interrupt) +apicinterrupt UV_BAU_MESSAGE \ + uv_bau_message_intr1 uv_bau_message_interrupt +apicinterrupt LOCAL_TIMER_VECTOR \ + apic_timer_interrupt smp_apic_timer_interrupt + +#ifdef CONFIG_SMP +apicinterrupt INVALIDATE_TLB_VECTOR_START+0 \ + invalidate_interrupt0 smp_invalidate_interrupt +apicinterrupt INVALIDATE_TLB_VECTOR_START+1 \ + invalidate_interrupt1 smp_invalidate_interrupt +apicinterrupt INVALIDATE_TLB_VECTOR_START+2 \ + invalidate_interrupt2 smp_invalidate_interrupt +apicinterrupt INVALIDATE_TLB_VECTOR_START+3 \ + invalidate_interrupt3 smp_invalidate_interrupt +apicinterrupt INVALIDATE_TLB_VECTOR_START+4 \ + invalidate_interrupt4 smp_invalidate_interrupt +apicinterrupt INVALIDATE_TLB_VECTOR_START+5 \ + invalidate_interrupt5 smp_invalidate_interrupt +apicinterrupt INVALIDATE_TLB_VECTOR_START+6 \ + invalidate_interrupt6 smp_invalidate_interrupt +apicinterrupt INVALIDATE_TLB_VECTOR_START+7 \ + invalidate_interrupt7 smp_invalidate_interrupt +#endif -ENTRY(uv_bau_message_intr1) - apicinterrupt 220,uv_bau_message_interrupt -END(uv_bau_message_intr1) +apicinterrupt THRESHOLD_APIC_VECTOR \ + threshold_interrupt mce_threshold_interrupt +apicinterrupt THERMAL_APIC_VECTOR \ + thermal_interrupt smp_thermal_interrupt + +#ifdef CONFIG_SMP +apicinterrupt CALL_FUNCTION_SINGLE_VECTOR \ + call_function_single_interrupt smp_call_function_single_interrupt +apicinterrupt CALL_FUNCTION_VECTOR \ + call_function_interrupt smp_call_function_interrupt +apicinterrupt RESCHEDULE_VECTOR \ + reschedule_interrupt smp_reschedule_interrupt +#endif -ENTRY(error_interrupt) - apicinterrupt ERROR_APIC_VECTOR,smp_error_interrupt -END(error_interrupt) +apicinterrupt ERROR_APIC_VECTOR \ + error_interrupt smp_error_interrupt +apicinterrupt SPURIOUS_APIC_VECTOR \ + spurious_interrupt smp_spurious_interrupt -ENTRY(spurious_interrupt) - apicinterrupt SPURIOUS_APIC_VECTOR,smp_spurious_interrupt -END(spurious_interrupt) - /* * Exception entry points. - */ - .macro zeroentry sym + */ +.macro zeroentry sym do_sym +ENTRY(\sym) INTR_FRAME PARAVIRT_ADJUST_EXCEPTION_FRAME - pushq $0 /* push error code/oldrax */ - CFI_ADJUST_CFA_OFFSET 8 - pushq %rax /* push real oldrax to the rdi slot */ - CFI_ADJUST_CFA_OFFSET 8 - CFI_REL_OFFSET rax,0 - leaq \sym(%rip),%rax - jmp error_entry + pushq_cfi $-1 /* ORIG_RAX: no syscall to restart */ + subq $15*8,%rsp + CFI_ADJUST_CFA_OFFSET 15*8 + call error_entry + DEFAULT_FRAME 0 + movq %rsp,%rdi /* pt_regs pointer */ + xorl %esi,%esi /* no error code */ + call \do_sym + jmp error_exit /* %ebx: no swapgs flag */ CFI_ENDPROC - .endm +END(\sym) +.endm - .macro errorentry sym - XCPT_FRAME +.macro paranoidzeroentry sym do_sym +ENTRY(\sym) + INTR_FRAME PARAVIRT_ADJUST_EXCEPTION_FRAME - pushq %rax + pushq $-1 /* ORIG_RAX: no syscall to restart */ CFI_ADJUST_CFA_OFFSET 8 - CFI_REL_OFFSET rax,0 - leaq \sym(%rip),%rax - jmp error_entry + subq $15*8, %rsp + call save_paranoid + TRACE_IRQS_OFF + movq %rsp,%rdi /* pt_regs pointer */ + xorl %esi,%esi /* no error code */ + call \do_sym + jmp paranoid_exit /* %ebx: no swapgs flag */ CFI_ENDPROC - .endm +END(\sym) +.endm - /* error code is on the stack already */ - /* handle NMI like exceptions that can happen everywhere */ - .macro paranoidentry sym, ist=0, irqtrace=1 - SAVE_ALL - cld - movl $1,%ebx - movl $MSR_GS_BASE,%ecx - rdmsr - testl %edx,%edx - js 1f - SWAPGS - xorl %ebx,%ebx -1: - .if \ist - movq %gs:pda_data_offset, %rbp - .endif - .if \irqtrace - TRACE_IRQS_OFF - .endif - movq %rsp,%rdi - movq ORIG_RAX(%rsp),%rsi - movq $-1,ORIG_RAX(%rsp) - .if \ist - subq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp) - .endif - call \sym - .if \ist - addq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp) - .endif - DISABLE_INTERRUPTS(CLBR_NONE) - .if \irqtrace +.macro paranoidzeroentry_ist sym do_sym ist +ENTRY(\sym) + INTR_FRAME + PARAVIRT_ADJUST_EXCEPTION_FRAME + pushq $-1 /* ORIG_RAX: no syscall to restart */ + CFI_ADJUST_CFA_OFFSET 8 + subq $15*8, %rsp + call save_paranoid TRACE_IRQS_OFF - .endif - .endm + movq %rsp,%rdi /* pt_regs pointer */ + xorl %esi,%esi /* no error code */ + movq %gs:pda_data_offset, %rbp + subq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp) + call \do_sym + addq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp) + jmp paranoid_exit /* %ebx: no swapgs flag */ + CFI_ENDPROC +END(\sym) +.endm - /* - * "Paranoid" exit path from exception stack. - * Paranoid because this is used by NMIs and cannot take - * any kernel state for granted. - * We don't do kernel preemption checks here, because only - * NMI should be common and it does not enable IRQs and - * cannot get reschedule ticks. - * - * "trace" is 0 for the NMI handler only, because irq-tracing - * is fundamentally NMI-unsafe. (we cannot change the soft and - * hard flags at once, atomically) - */ - .macro paranoidexit trace=1 - /* ebx: no swapgs flag */ -paranoid_exit\trace: - testl %ebx,%ebx /* swapgs needed? */ - jnz paranoid_restore\trace - testl $3,CS(%rsp) - jnz paranoid_userspace\trace -paranoid_swapgs\trace: - .if \trace - TRACE_IRQS_IRETQ 0 - .endif - SWAPGS_UNSAFE_STACK -paranoid_restore\trace: - RESTORE_ALL 8 - jmp irq_return -paranoid_userspace\trace: - GET_THREAD_INFO(%rcx) - movl TI_flags(%rcx),%ebx - andl $_TIF_WORK_MASK,%ebx - jz paranoid_swapgs\trace - movq %rsp,%rdi /* &pt_regs */ - call sync_regs - movq %rax,%rsp /* switch stack for scheduling */ - testl $_TIF_NEED_RESCHED,%ebx - jnz paranoid_schedule\trace - movl %ebx,%edx /* arg3: thread flags */ - .if \trace - TRACE_IRQS_ON - .endif - ENABLE_INTERRUPTS(CLBR_NONE) - xorl %esi,%esi /* arg2: oldset */ - movq %rsp,%rdi /* arg1: &pt_regs */ - call do_notify_resume - DISABLE_INTERRUPTS(CLBR_NONE) - .if \trace - TRACE_IRQS_OFF - .endif - jmp paranoid_userspace\trace -paranoid_schedule\trace: - .if \trace - TRACE_IRQS_ON - .endif - ENABLE_INTERRUPTS(CLBR_ANY) - call schedule - DISABLE_INTERRUPTS(CLBR_ANY) - .if \trace - TRACE_IRQS_OFF - .endif - jmp paranoid_userspace\trace +.macro errorentry sym do_sym +ENTRY(\sym) + XCPT_FRAME + PARAVIRT_ADJUST_EXCEPTION_FRAME + subq $15*8,%rsp + CFI_ADJUST_CFA_OFFSET 15*8 + call error_entry + DEFAULT_FRAME 0 + movq %rsp,%rdi /* pt_regs pointer */ + movq ORIG_RAX(%rsp),%rsi /* get error code */ + movq $-1,ORIG_RAX(%rsp) /* no syscall to restart */ + call \do_sym + jmp error_exit /* %ebx: no swapgs flag */ CFI_ENDPROC - .endm +END(\sym) +.endm -/* - * Exception entry point. This expects an error code/orig_rax on the stack - * and the exception handler in %rax. - */ -KPROBE_ENTRY(error_entry) - _frame RDI - CFI_REL_OFFSET rax,0 - /* rdi slot contains rax, oldrax contains error code */ - cld - subq $14*8,%rsp - CFI_ADJUST_CFA_OFFSET (14*8) - movq %rsi,13*8(%rsp) - CFI_REL_OFFSET rsi,RSI - movq 14*8(%rsp),%rsi /* load rax from rdi slot */ - CFI_REGISTER rax,rsi - movq %rdx,12*8(%rsp) - CFI_REL_OFFSET rdx,RDX - movq %rcx,11*8(%rsp) - CFI_REL_OFFSET rcx,RCX - movq %rsi,10*8(%rsp) /* store rax */ - CFI_REL_OFFSET rax,RAX - movq %r8, 9*8(%rsp) - CFI_REL_OFFSET r8,R8 - movq %r9, 8*8(%rsp) - CFI_REL_OFFSET r9,R9 - movq %r10,7*8(%rsp) - CFI_REL_OFFSET r10,R10 - movq %r11,6*8(%rsp) - CFI_REL_OFFSET r11,R11 - movq %rbx,5*8(%rsp) - CFI_REL_OFFSET rbx,RBX - movq %rbp,4*8(%rsp) - CFI_REL_OFFSET rbp,RBP - movq %r12,3*8(%rsp) - CFI_REL_OFFSET r12,R12 - movq %r13,2*8(%rsp) - CFI_REL_OFFSET r13,R13 - movq %r14,1*8(%rsp) - CFI_REL_OFFSET r14,R14 - movq %r15,(%rsp) - CFI_REL_OFFSET r15,R15 - xorl %ebx,%ebx - testl $3,CS(%rsp) - je error_kernelspace -error_swapgs: - SWAPGS -error_sti: - TRACE_IRQS_OFF - movq %rdi,RDI(%rsp) - CFI_REL_OFFSET rdi,RDI - movq %rsp,%rdi - movq ORIG_RAX(%rsp),%rsi /* get error code */ - movq $-1,ORIG_RAX(%rsp) - call *%rax - /* ebx: no swapgs flag (1: don't need swapgs, 0: need it) */ -error_exit: - movl %ebx,%eax - RESTORE_REST - DISABLE_INTERRUPTS(CLBR_NONE) + /* error code is on the stack already */ +.macro paranoiderrorentry sym do_sym +ENTRY(\sym) + XCPT_FRAME + PARAVIRT_ADJUST_EXCEPTION_FRAME + subq $15*8,%rsp + CFI_ADJUST_CFA_OFFSET 15*8 + call save_paranoid + DEFAULT_FRAME 0 TRACE_IRQS_OFF - GET_THREAD_INFO(%rcx) - testl %eax,%eax - jne retint_kernel - LOCKDEP_SYS_EXIT_IRQ - movl TI_flags(%rcx),%edx - movl $_TIF_WORK_MASK,%edi - andl %edi,%edx - jnz retint_careful - jmp retint_swapgs + movq %rsp,%rdi /* pt_regs pointer */ + movq ORIG_RAX(%rsp),%rsi /* get error code */ + movq $-1,ORIG_RAX(%rsp) /* no syscall to restart */ + call \do_sym + jmp paranoid_exit /* %ebx: no swapgs flag */ CFI_ENDPROC +END(\sym) +.endm -error_kernelspace: - incl %ebx - /* There are two places in the kernel that can potentially fault with - usergs. Handle them here. The exception handlers after - iret run with kernel gs again, so don't set the user space flag. - B stepping K8s sometimes report an truncated RIP for IRET - exceptions returning to compat mode. Check for these here too. */ - leaq irq_return(%rip),%rcx - cmpq %rcx,RIP(%rsp) - je error_swapgs - movl %ecx,%ecx /* zero extend */ - cmpq %rcx,RIP(%rsp) - je error_swapgs - cmpq $gs_change,RIP(%rsp) - je error_swapgs - jmp error_sti -KPROBE_END(error_entry) - - /* Reload gs selector with exception handling */ - /* edi: new selector */ +zeroentry divide_error do_divide_error +zeroentry overflow do_overflow +zeroentry bounds do_bounds +zeroentry invalid_op do_invalid_op +zeroentry device_not_available do_device_not_available +paranoiderrorentry double_fault do_double_fault +zeroentry coprocessor_segment_overrun do_coprocessor_segment_overrun +errorentry invalid_TSS do_invalid_TSS +errorentry segment_not_present do_segment_not_present +zeroentry spurious_interrupt_bug do_spurious_interrupt_bug +zeroentry coprocessor_error do_coprocessor_error +errorentry alignment_check do_alignment_check +zeroentry simd_coprocessor_error do_simd_coprocessor_error + + /* Reload gs selector with exception handling */ + /* edi: new selector */ ENTRY(native_load_gs_index) CFI_STARTPROC pushf CFI_ADJUST_CFA_OFFSET 8 DISABLE_INTERRUPTS(CLBR_ANY | ~(CLBR_RDI)) - SWAPGS -gs_change: - movl %edi,%gs + SWAPGS +gs_change: + movl %edi,%gs 2: mfence /* workaround */ SWAPGS - popf + popf CFI_ADJUST_CFA_OFFSET -8 - ret + ret CFI_ENDPROC -ENDPROC(native_load_gs_index) - - .section __ex_table,"a" - .align 8 - .quad gs_change,bad_gs - .previous - .section .fixup,"ax" +END(native_load_gs_index) + + .section __ex_table,"a" + .align 8 + .quad gs_change,bad_gs + .previous + .section .fixup,"ax" /* running with kernelgs */ -bad_gs: +bad_gs: SWAPGS /* switch back to user gs */ xorl %eax,%eax - movl %eax,%gs - jmp 2b - .previous - + movl %eax,%gs + jmp 2b + .previous + /* * Create a kernel thread. * @@ -1138,7 +1184,7 @@ ENTRY(kernel_thread) xorl %r8d,%r8d xorl %r9d,%r9d - + # clone now call do_fork movq %rax,RAX(%rsp) @@ -1149,15 +1195,15 @@ ENTRY(kernel_thread) * so internally to the x86_64 port you can rely on kernel_thread() * not to reschedule the child before returning, this avoids the need * of hacks for example to fork off the per-CPU idle tasks. - * [Hopefully no generic code relies on the reschedule -AK] + * [Hopefully no generic code relies on the reschedule -AK] */ RESTORE_ALL UNFAKE_STACK_FRAME ret CFI_ENDPROC -ENDPROC(kernel_thread) - -child_rip: +END(kernel_thread) + +ENTRY(child_rip) pushq $0 # fake return address CFI_STARTPROC /* @@ -1170,8 +1216,9 @@ child_rip: # exit mov %eax, %edi call do_exit + ud2 # padding for call trace CFI_ENDPROC -ENDPROC(child_rip) +END(child_rip) /* * execve(). This function needs to use IRET, not SYSRET, to set up all state properly. @@ -1191,10 +1238,10 @@ ENDPROC(child_rip) ENTRY(kernel_execve) CFI_STARTPROC FAKE_STACK_FRAME $0 - SAVE_ALL + SAVE_ALL movq %rsp,%rcx call sys_execve - movq %rax, RAX(%rsp) + movq %rax, RAX(%rsp) RESTORE_REST testq %rax,%rax je int_ret_from_sys_call @@ -1202,129 +1249,7 @@ ENTRY(kernel_execve) UNFAKE_STACK_FRAME ret CFI_ENDPROC -ENDPROC(kernel_execve) - -KPROBE_ENTRY(page_fault) - errorentry do_page_fault -KPROBE_END(page_fault) - -ENTRY(coprocessor_error) - zeroentry do_coprocessor_error -END(coprocessor_error) - -ENTRY(simd_coprocessor_error) - zeroentry do_simd_coprocessor_error -END(simd_coprocessor_error) - -ENTRY(device_not_available) - zeroentry do_device_not_available -END(device_not_available) - - /* runs on exception stack */ -KPROBE_ENTRY(debug) - INTR_FRAME - PARAVIRT_ADJUST_EXCEPTION_FRAME - pushq $0 - CFI_ADJUST_CFA_OFFSET 8 - paranoidentry do_debug, DEBUG_STACK - paranoidexit -KPROBE_END(debug) - - /* runs on exception stack */ -KPROBE_ENTRY(nmi) - INTR_FRAME - PARAVIRT_ADJUST_EXCEPTION_FRAME - pushq $-1 - CFI_ADJUST_CFA_OFFSET 8 - paranoidentry do_nmi, 0, 0 -#ifdef CONFIG_TRACE_IRQFLAGS - paranoidexit 0 -#else - jmp paranoid_exit1 - CFI_ENDPROC -#endif -KPROBE_END(nmi) - -KPROBE_ENTRY(int3) - INTR_FRAME - PARAVIRT_ADJUST_EXCEPTION_FRAME - pushq $0 - CFI_ADJUST_CFA_OFFSET 8 - paranoidentry do_int3, DEBUG_STACK - jmp paranoid_exit1 - CFI_ENDPROC -KPROBE_END(int3) - -ENTRY(overflow) - zeroentry do_overflow -END(overflow) - -ENTRY(bounds) - zeroentry do_bounds -END(bounds) - -ENTRY(invalid_op) - zeroentry do_invalid_op -END(invalid_op) - -ENTRY(coprocessor_segment_overrun) - zeroentry do_coprocessor_segment_overrun -END(coprocessor_segment_overrun) - - /* runs on exception stack */ -ENTRY(double_fault) - XCPT_FRAME - PARAVIRT_ADJUST_EXCEPTION_FRAME - paranoidentry do_double_fault - jmp paranoid_exit1 - CFI_ENDPROC -END(double_fault) - -ENTRY(invalid_TSS) - errorentry do_invalid_TSS -END(invalid_TSS) - -ENTRY(segment_not_present) - errorentry do_segment_not_present -END(segment_not_present) - - /* runs on exception stack */ -ENTRY(stack_segment) - XCPT_FRAME - PARAVIRT_ADJUST_EXCEPTION_FRAME - paranoidentry do_stack_segment - jmp paranoid_exit1 - CFI_ENDPROC -END(stack_segment) - -KPROBE_ENTRY(general_protection) - errorentry do_general_protection -KPROBE_END(general_protection) - -ENTRY(alignment_check) - errorentry do_alignment_check -END(alignment_check) - -ENTRY(divide_error) - zeroentry do_divide_error -END(divide_error) - -ENTRY(spurious_interrupt_bug) - zeroentry do_spurious_interrupt_bug -END(spurious_interrupt_bug) - -#ifdef CONFIG_X86_MCE - /* runs on exception stack */ -ENTRY(machine_check) - INTR_FRAME - PARAVIRT_ADJUST_EXCEPTION_FRAME - pushq $0 - CFI_ADJUST_CFA_OFFSET 8 - paranoidentry do_machine_check - jmp paranoid_exit1 - CFI_ENDPROC -END(machine_check) -#endif +END(kernel_execve) /* Call softirq on interrupt stack. Interrupts are off. */ ENTRY(call_softirq) @@ -1344,40 +1269,33 @@ ENTRY(call_softirq) decl %gs:pda_irqcount ret CFI_ENDPROC -ENDPROC(call_softirq) - -KPROBE_ENTRY(ignore_sysret) - CFI_STARTPROC - mov $-ENOSYS,%eax - sysret - CFI_ENDPROC -ENDPROC(ignore_sysret) +END(call_softirq) #ifdef CONFIG_XEN -ENTRY(xen_hypervisor_callback) - zeroentry xen_do_hypervisor_callback -END(xen_hypervisor_callback) +zeroentry xen_hypervisor_callback xen_do_hypervisor_callback /* -# A note on the "critical region" in our callback handler. -# We want to avoid stacking callback handlers due to events occurring -# during handling of the last event. To do this, we keep events disabled -# until we've done all processing. HOWEVER, we must enable events before -# popping the stack frame (can't be done atomically) and so it would still -# be possible to get enough handler activations to overflow the stack. -# Although unlikely, bugs of that kind are hard to track down, so we'd -# like to avoid the possibility. -# So, on entry to the handler we detect whether we interrupted an -# existing activation in its critical region -- if so, we pop the current -# activation and restart the handler using the previous one. -*/ + * A note on the "critical region" in our callback handler. + * We want to avoid stacking callback handlers due to events occurring + * during handling of the last event. To do this, we keep events disabled + * until we've done all processing. HOWEVER, we must enable events before + * popping the stack frame (can't be done atomically) and so it would still + * be possible to get enough handler activations to overflow the stack. + * Although unlikely, bugs of that kind are hard to track down, so we'd + * like to avoid the possibility. + * So, on entry to the handler we detect whether we interrupted an + * existing activation in its critical region -- if so, we pop the current + * activation and restart the handler using the previous one. + */ ENTRY(xen_do_hypervisor_callback) # do_hypervisor_callback(struct *pt_regs) CFI_STARTPROC -/* Since we don't modify %rdi, evtchn_do_upall(struct *pt_regs) will - see the correct pointer to the pt_regs */ +/* + * Since we don't modify %rdi, evtchn_do_upall(struct *pt_regs) will + * see the correct pointer to the pt_regs + */ movq %rdi, %rsp # we don't return, adjust the stack frame CFI_ENDPROC - CFI_DEFAULT_STACK + DEFAULT_FRAME 11: incl %gs:pda_irqcount movq %rsp,%rbp CFI_DEF_CFA_REGISTER rbp @@ -1392,23 +1310,26 @@ ENTRY(xen_do_hypervisor_callback) # do_hypervisor_callback(struct *pt_regs) END(do_hypervisor_callback) /* -# Hypervisor uses this for application faults while it executes. -# We get here for two reasons: -# 1. Fault while reloading DS, ES, FS or GS -# 2. Fault while executing IRET -# Category 1 we do not need to fix up as Xen has already reloaded all segment -# registers that could be reloaded and zeroed the others. -# Category 2 we fix up by killing the current process. We cannot use the -# normal Linux return path in this case because if we use the IRET hypercall -# to pop the stack frame we end up in an infinite loop of failsafe callbacks. -# We distinguish between categories by comparing each saved segment register -# with its current contents: any discrepancy means we in category 1. -*/ + * Hypervisor uses this for application faults while it executes. + * We get here for two reasons: + * 1. Fault while reloading DS, ES, FS or GS + * 2. Fault while executing IRET + * Category 1 we do not need to fix up as Xen has already reloaded all segment + * registers that could be reloaded and zeroed the others. + * Category 2 we fix up by killing the current process. We cannot use the + * normal Linux return path in this case because if we use the IRET hypercall + * to pop the stack frame we end up in an infinite loop of failsafe callbacks. + * We distinguish between categories by comparing each saved segment register + * with its current contents: any discrepancy means we in category 1. + */ ENTRY(xen_failsafe_callback) - framesz = (RIP-0x30) /* workaround buggy gas */ - _frame framesz - CFI_REL_OFFSET rcx, 0 - CFI_REL_OFFSET r11, 8 + INTR_FRAME 1 (6*8) + /*CFI_REL_OFFSET gs,GS*/ + /*CFI_REL_OFFSET fs,FS*/ + /*CFI_REL_OFFSET es,ES*/ + /*CFI_REL_OFFSET ds,DS*/ + CFI_REL_OFFSET r11,8 + CFI_REL_OFFSET rcx,0 movw %ds,%cx cmpw %cx,0x10(%rsp) CFI_REMEMBER_STATE @@ -1429,12 +1350,9 @@ ENTRY(xen_failsafe_callback) CFI_RESTORE r11 addq $0x30,%rsp CFI_ADJUST_CFA_OFFSET -0x30 - pushq $0 - CFI_ADJUST_CFA_OFFSET 8 - pushq %r11 - CFI_ADJUST_CFA_OFFSET 8 - pushq %rcx - CFI_ADJUST_CFA_OFFSET 8 + pushq_cfi $0 /* RIP */ + pushq_cfi %r11 + pushq_cfi %rcx jmp general_protection CFI_RESTORE_STATE 1: /* Segment mismatch => Category 1 (Bad segment). Retry the IRET. */ @@ -1444,11 +1362,223 @@ ENTRY(xen_failsafe_callback) CFI_RESTORE r11 addq $0x30,%rsp CFI_ADJUST_CFA_OFFSET -0x30 - pushq $0 - CFI_ADJUST_CFA_OFFSET 8 + pushq_cfi $0 SAVE_ALL jmp error_exit CFI_ENDPROC END(xen_failsafe_callback) #endif /* CONFIG_XEN */ + +/* + * Some functions should be protected against kprobes + */ + .pushsection .kprobes.text, "ax" + +paranoidzeroentry_ist debug do_debug DEBUG_STACK +paranoidzeroentry_ist int3 do_int3 DEBUG_STACK +paranoiderrorentry stack_segment do_stack_segment +errorentry general_protection do_general_protection +errorentry page_fault do_page_fault +#ifdef CONFIG_X86_MCE +paranoidzeroentry machine_check do_machine_check +#endif + + /* + * "Paranoid" exit path from exception stack. + * Paranoid because this is used by NMIs and cannot take + * any kernel state for granted. + * We don't do kernel preemption checks here, because only + * NMI should be common and it does not enable IRQs and + * cannot get reschedule ticks. + * + * "trace" is 0 for the NMI handler only, because irq-tracing + * is fundamentally NMI-unsafe. (we cannot change the soft and + * hard flags at once, atomically) + */ + + /* ebx: no swapgs flag */ +ENTRY(paranoid_exit) + INTR_FRAME + DISABLE_INTERRUPTS(CLBR_NONE) + TRACE_IRQS_OFF + testl %ebx,%ebx /* swapgs needed? */ + jnz paranoid_restore + testl $3,CS(%rsp) + jnz paranoid_userspace +paranoid_swapgs: + TRACE_IRQS_IRETQ 0 + SWAPGS_UNSAFE_STACK +paranoid_restore: + RESTORE_ALL 8 + jmp irq_return +paranoid_userspace: + GET_THREAD_INFO(%rcx) + movl TI_flags(%rcx),%ebx + andl $_TIF_WORK_MASK,%ebx + jz paranoid_swapgs + movq %rsp,%rdi /* &pt_regs */ + call sync_regs + movq %rax,%rsp /* switch stack for scheduling */ + testl $_TIF_NEED_RESCHED,%ebx + jnz paranoid_schedule + movl %ebx,%edx /* arg3: thread flags */ + TRACE_IRQS_ON + ENABLE_INTERRUPTS(CLBR_NONE) + xorl %esi,%esi /* arg2: oldset */ + movq %rsp,%rdi /* arg1: &pt_regs */ + call do_notify_resume + DISABLE_INTERRUPTS(CLBR_NONE) + TRACE_IRQS_OFF + jmp paranoid_userspace +paranoid_schedule: + TRACE_IRQS_ON + ENABLE_INTERRUPTS(CLBR_ANY) + call schedule + DISABLE_INTERRUPTS(CLBR_ANY) + TRACE_IRQS_OFF + jmp paranoid_userspace + CFI_ENDPROC +END(paranoid_exit) + +/* + * Exception entry point. This expects an error code/orig_rax on the stack. + * returns in "no swapgs flag" in %ebx. + */ +ENTRY(error_entry) + XCPT_FRAME + CFI_ADJUST_CFA_OFFSET 15*8 + /* oldrax contains error code */ + cld + movq_cfi rdi, RDI+8 + movq_cfi rsi, RSI+8 + movq_cfi rdx, RDX+8 + movq_cfi rcx, RCX+8 + movq_cfi rax, RAX+8 + movq_cfi r8, R8+8 + movq_cfi r9, R9+8 + movq_cfi r10, R10+8 + movq_cfi r11, R11+8 + movq_cfi rbx, RBX+8 + movq_cfi rbp, RBP+8 + movq_cfi r12, R12+8 + movq_cfi r13, R13+8 + movq_cfi r14, R14+8 + movq_cfi r15, R15+8 + xorl %ebx,%ebx + testl $3,CS+8(%rsp) + je error_kernelspace +error_swapgs: + SWAPGS +error_sti: + TRACE_IRQS_OFF + ret + CFI_ENDPROC + +/* + * There are two places in the kernel that can potentially fault with + * usergs. Handle them here. The exception handlers after iret run with + * kernel gs again, so don't set the user space flag. B stepping K8s + * sometimes report an truncated RIP for IRET exceptions returning to + * compat mode. Check for these here too. + */ +error_kernelspace: + incl %ebx + leaq irq_return(%rip),%rcx + cmpq %rcx,RIP+8(%rsp) + je error_swapgs + movl %ecx,%ecx /* zero extend */ + cmpq %rcx,RIP+8(%rsp) + je error_swapgs + cmpq $gs_change,RIP+8(%rsp) + je error_swapgs + jmp error_sti +END(error_entry) + + +/* ebx: no swapgs flag (1: don't need swapgs, 0: need it) */ +ENTRY(error_exit) + DEFAULT_FRAME + movl %ebx,%eax + RESTORE_REST + DISABLE_INTERRUPTS(CLBR_NONE) + TRACE_IRQS_OFF + GET_THREAD_INFO(%rcx) + testl %eax,%eax + jne retint_kernel + LOCKDEP_SYS_EXIT_IRQ + movl TI_flags(%rcx),%edx + movl $_TIF_WORK_MASK,%edi + andl %edi,%edx + jnz retint_careful + jmp retint_swapgs + CFI_ENDPROC +END(error_exit) + + + /* runs on exception stack */ +ENTRY(nmi) + INTR_FRAME + PARAVIRT_ADJUST_EXCEPTION_FRAME + pushq_cfi $-1 + subq $15*8, %rsp + CFI_ADJUST_CFA_OFFSET 15*8 + call save_paranoid + DEFAULT_FRAME 0 + /* paranoidentry do_nmi, 0; without TRACE_IRQS_OFF */ + movq %rsp,%rdi + movq $-1,%rsi + call do_nmi +#ifdef CONFIG_TRACE_IRQFLAGS + /* paranoidexit; without TRACE_IRQS_OFF */ + /* ebx: no swapgs flag */ + DISABLE_INTERRUPTS(CLBR_NONE) + testl %ebx,%ebx /* swapgs needed? */ + jnz nmi_restore + testl $3,CS(%rsp) + jnz nmi_userspace +nmi_swapgs: + SWAPGS_UNSAFE_STACK +nmi_restore: + RESTORE_ALL 8 + jmp irq_return +nmi_userspace: + GET_THREAD_INFO(%rcx) + movl TI_flags(%rcx),%ebx + andl $_TIF_WORK_MASK,%ebx + jz nmi_swapgs + movq %rsp,%rdi /* &pt_regs */ + call sync_regs + movq %rax,%rsp /* switch stack for scheduling */ + testl $_TIF_NEED_RESCHED,%ebx + jnz nmi_schedule + movl %ebx,%edx /* arg3: thread flags */ + ENABLE_INTERRUPTS(CLBR_NONE) + xorl %esi,%esi /* arg2: oldset */ + movq %rsp,%rdi /* arg1: &pt_regs */ + call do_notify_resume + DISABLE_INTERRUPTS(CLBR_NONE) + jmp nmi_userspace +nmi_schedule: + ENABLE_INTERRUPTS(CLBR_ANY) + call schedule + DISABLE_INTERRUPTS(CLBR_ANY) + jmp nmi_userspace + CFI_ENDPROC +#else + jmp paranoid_exit + CFI_ENDPROC +#endif +END(nmi) + +ENTRY(ignore_sysret) + CFI_STARTPROC + mov $-ENOSYS,%eax + sysret + CFI_ENDPROC +END(ignore_sysret) + +/* + * End of kprobes section + */ + .popsection diff --git a/arch/x86/kernel/es7000_32.c b/arch/x86/kernel/es7000_32.c index 0aa2c443d600c64dcf5b4ac440c18bb4f3d0e9d9..53699c931ad41ebdaee8594cdb17f4464fcc986f 100644 --- a/arch/x86/kernel/es7000_32.c +++ b/arch/x86/kernel/es7000_32.c @@ -38,8 +38,11 @@ #include #include #include +#include #include #include +#include +#include /* * ES7000 chipsets @@ -161,6 +164,43 @@ es7000_rename_gsi(int ioapic, int gsi) return gsi; } +static int wakeup_secondary_cpu_via_mip(int cpu, unsigned long eip) +{ + unsigned long vect = 0, psaival = 0; + + if (psai == NULL) + return -1; + + vect = ((unsigned long)__pa(eip)/0x1000) << 16; + psaival = (0x1000000 | vect | cpu); + + while (*psai & 0x1000000) + ; + + *psai = psaival; + + return 0; +} + +static void noop_wait_for_deassert(atomic_t *deassert_not_used) +{ +} + +static int __init es7000_update_genapic(void) +{ + genapic->wakeup_cpu = wakeup_secondary_cpu_via_mip; + + /* MPENTIUMIII */ + if (boot_cpu_data.x86 == 6 && + (boot_cpu_data.x86_model >= 7 || boot_cpu_data.x86_model <= 11)) { + es7000_update_genapic_to_cluster(); + genapic->wait_for_init_deassert = noop_wait_for_deassert; + genapic->wakeup_cpu = wakeup_secondary_cpu_via_mip; + } + + return 0; +} + void __init setup_unisys(void) { @@ -176,6 +216,8 @@ setup_unisys(void) else es7000_plat = ES7000_CLASSIC; ioapic_renumber_irq = es7000_rename_gsi; + + x86_quirks->update_genapic = es7000_update_genapic; } /* @@ -317,26 +359,6 @@ es7000_mip_write(struct mip_reg *mip_reg) return status; } -int -es7000_start_cpu(int cpu, unsigned long eip) -{ - unsigned long vect = 0, psaival = 0; - - if (psai == NULL) - return -1; - - vect = ((unsigned long)__pa(eip)/0x1000) << 16; - psaival = (0x1000000 | vect | cpu); - - while (*psai & 0x1000000) - ; - - *psai = psaival; - - return 0; - -} - void __init es7000_sw_apic(void) { diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index 50ea0ac8c9bf2c27a53323b93b5d473bd7e1d028..1b43086b097a8489a85adcd41a3336fb0cde4f88 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c @@ -14,14 +14,17 @@ #include #include #include +#include #include #include #include +#include #include +#include -static unsigned char ftrace_nop[MCOUNT_INSN_SIZE]; +#ifdef CONFIG_DYNAMIC_FTRACE union ftrace_code_union { char code[MCOUNT_INSN_SIZE]; @@ -31,18 +34,12 @@ union ftrace_code_union { } __attribute__((packed)); }; - static int ftrace_calc_offset(long ip, long addr) { return (int)(addr - ip); } -unsigned char *ftrace_nop_replace(void) -{ - return ftrace_nop; -} - -unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) +static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) { static union ftrace_code_union calc; @@ -56,7 +53,142 @@ unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) return calc.code; } -int +/* + * Modifying code must take extra care. On an SMP machine, if + * the code being modified is also being executed on another CPU + * that CPU will have undefined results and possibly take a GPF. + * We use kstop_machine to stop other CPUS from exectuing code. + * But this does not stop NMIs from happening. We still need + * to protect against that. We separate out the modification of + * the code to take care of this. + * + * Two buffers are added: An IP buffer and a "code" buffer. + * + * 1) Put the instruction pointer into the IP buffer + * and the new code into the "code" buffer. + * 2) Set a flag that says we are modifying code + * 3) Wait for any running NMIs to finish. + * 4) Write the code + * 5) clear the flag. + * 6) Wait for any running NMIs to finish. + * + * If an NMI is executed, the first thing it does is to call + * "ftrace_nmi_enter". This will check if the flag is set to write + * and if it is, it will write what is in the IP and "code" buffers. + * + * The trick is, it does not matter if everyone is writing the same + * content to the code location. Also, if a CPU is executing code + * it is OK to write to that code location if the contents being written + * are the same as what exists. + */ + +static atomic_t in_nmi = ATOMIC_INIT(0); +static int mod_code_status; /* holds return value of text write */ +static int mod_code_write; /* set when NMI should do the write */ +static void *mod_code_ip; /* holds the IP to write to */ +static void *mod_code_newcode; /* holds the text to write to the IP */ + +static unsigned nmi_wait_count; +static atomic_t nmi_update_count = ATOMIC_INIT(0); + +int ftrace_arch_read_dyn_info(char *buf, int size) +{ + int r; + + r = snprintf(buf, size, "%u %u", + nmi_wait_count, + atomic_read(&nmi_update_count)); + return r; +} + +static void ftrace_mod_code(void) +{ + /* + * Yes, more than one CPU process can be writing to mod_code_status. + * (and the code itself) + * But if one were to fail, then they all should, and if one were + * to succeed, then they all should. + */ + mod_code_status = probe_kernel_write(mod_code_ip, mod_code_newcode, + MCOUNT_INSN_SIZE); +} + +void ftrace_nmi_enter(void) +{ + atomic_inc(&in_nmi); + /* Must have in_nmi seen before reading write flag */ + smp_mb(); + if (mod_code_write) { + ftrace_mod_code(); + atomic_inc(&nmi_update_count); + } +} + +void ftrace_nmi_exit(void) +{ + /* Finish all executions before clearing in_nmi */ + smp_wmb(); + atomic_dec(&in_nmi); +} + +static void wait_for_nmi(void) +{ + int waited = 0; + + while (atomic_read(&in_nmi)) { + waited = 1; + cpu_relax(); + } + + if (waited) + nmi_wait_count++; +} + +static int +do_ftrace_mod_code(unsigned long ip, void *new_code) +{ + mod_code_ip = (void *)ip; + mod_code_newcode = new_code; + + /* The buffers need to be visible before we let NMIs write them */ + smp_wmb(); + + mod_code_write = 1; + + /* Make sure write bit is visible before we wait on NMIs */ + smp_mb(); + + wait_for_nmi(); + + /* Make sure all running NMIs have finished before we write the code */ + smp_mb(); + + ftrace_mod_code(); + + /* Make sure the write happens before clearing the bit */ + smp_wmb(); + + mod_code_write = 0; + + /* make sure NMIs see the cleared bit */ + smp_mb(); + + wait_for_nmi(); + + return mod_code_status; +} + + + + +static unsigned char ftrace_nop[MCOUNT_INSN_SIZE]; + +static unsigned char *ftrace_nop_replace(void) +{ + return ftrace_nop; +} + +static int ftrace_modify_code(unsigned long ip, unsigned char *old_code, unsigned char *new_code) { @@ -81,7 +213,7 @@ ftrace_modify_code(unsigned long ip, unsigned char *old_code, return -EINVAL; /* replace the text with the new text */ - if (probe_kernel_write((void *)ip, new_code, MCOUNT_INSN_SIZE)) + if (do_ftrace_mod_code(ip, new_code)) return -EPERM; sync_core(); @@ -89,6 +221,29 @@ ftrace_modify_code(unsigned long ip, unsigned char *old_code, return 0; } +int ftrace_make_nop(struct module *mod, + struct dyn_ftrace *rec, unsigned long addr) +{ + unsigned char *new, *old; + unsigned long ip = rec->ip; + + old = ftrace_call_replace(ip, addr); + new = ftrace_nop_replace(); + + return ftrace_modify_code(rec->ip, old, new); +} + +int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) +{ + unsigned char *new, *old; + unsigned long ip = rec->ip; + + old = ftrace_nop_replace(); + new = ftrace_call_replace(ip, addr); + + return ftrace_modify_code(rec->ip, old, new); +} + int ftrace_update_ftrace_func(ftrace_func_t func) { unsigned long ip = (unsigned long)(&ftrace_call); @@ -165,3 +320,218 @@ int __init ftrace_dyn_arch_init(void *data) return 0; } +#endif + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + +#ifdef CONFIG_DYNAMIC_FTRACE +extern void ftrace_graph_call(void); + +static int ftrace_mod_jmp(unsigned long ip, + int old_offset, int new_offset) +{ + unsigned char code[MCOUNT_INSN_SIZE]; + + if (probe_kernel_read(code, (void *)ip, MCOUNT_INSN_SIZE)) + return -EFAULT; + + if (code[0] != 0xe9 || old_offset != *(int *)(&code[1])) + return -EINVAL; + + *(int *)(&code[1]) = new_offset; + + if (do_ftrace_mod_code(ip, &code)) + return -EPERM; + + return 0; +} + +int ftrace_enable_ftrace_graph_caller(void) +{ + unsigned long ip = (unsigned long)(&ftrace_graph_call); + int old_offset, new_offset; + + old_offset = (unsigned long)(&ftrace_stub) - (ip + MCOUNT_INSN_SIZE); + new_offset = (unsigned long)(&ftrace_graph_caller) - (ip + MCOUNT_INSN_SIZE); + + return ftrace_mod_jmp(ip, old_offset, new_offset); +} + +int ftrace_disable_ftrace_graph_caller(void) +{ + unsigned long ip = (unsigned long)(&ftrace_graph_call); + int old_offset, new_offset; + + old_offset = (unsigned long)(&ftrace_graph_caller) - (ip + MCOUNT_INSN_SIZE); + new_offset = (unsigned long)(&ftrace_stub) - (ip + MCOUNT_INSN_SIZE); + + return ftrace_mod_jmp(ip, old_offset, new_offset); +} + +#else /* CONFIG_DYNAMIC_FTRACE */ + +/* + * These functions are picked from those used on + * this page for dynamic ftrace. They have been + * simplified to ignore all traces in NMI context. + */ +static atomic_t in_nmi; + +void ftrace_nmi_enter(void) +{ + atomic_inc(&in_nmi); +} + +void ftrace_nmi_exit(void) +{ + atomic_dec(&in_nmi); +} + +#endif /* !CONFIG_DYNAMIC_FTRACE */ + +/* Add a function return address to the trace stack on thread info.*/ +static int push_return_trace(unsigned long ret, unsigned long long time, + unsigned long func, int *depth) +{ + int index; + + if (!current->ret_stack) + return -EBUSY; + + /* The return trace stack is full */ + if (current->curr_ret_stack == FTRACE_RETFUNC_DEPTH - 1) { + atomic_inc(¤t->trace_overrun); + return -EBUSY; + } + + index = ++current->curr_ret_stack; + barrier(); + current->ret_stack[index].ret = ret; + current->ret_stack[index].func = func; + current->ret_stack[index].calltime = time; + *depth = index; + + return 0; +} + +/* Retrieve a function return address to the trace stack on thread info.*/ +static void pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret) +{ + int index; + + index = current->curr_ret_stack; + + if (unlikely(index < 0)) { + ftrace_graph_stop(); + WARN_ON(1); + /* Might as well panic, otherwise we have no where to go */ + *ret = (unsigned long)panic; + return; + } + + *ret = current->ret_stack[index].ret; + trace->func = current->ret_stack[index].func; + trace->calltime = current->ret_stack[index].calltime; + trace->overrun = atomic_read(¤t->trace_overrun); + trace->depth = index; + barrier(); + current->curr_ret_stack--; + +} + +/* + * Send the trace to the ring-buffer. + * @return the original return address. + */ +unsigned long ftrace_return_to_handler(void) +{ + struct ftrace_graph_ret trace; + unsigned long ret; + + pop_return_trace(&trace, &ret); + trace.rettime = cpu_clock(raw_smp_processor_id()); + ftrace_graph_return(&trace); + + if (unlikely(!ret)) { + ftrace_graph_stop(); + WARN_ON(1); + /* Might as well panic. What else to do? */ + ret = (unsigned long)panic; + } + + return ret; +} + +/* + * Hook the return address and push it in the stack of return addrs + * in current thread info. + */ +void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr) +{ + unsigned long old; + unsigned long long calltime; + int faulted; + struct ftrace_graph_ent trace; + unsigned long return_hooker = (unsigned long) + &return_to_handler; + + /* Nmi's are currently unsupported */ + if (unlikely(atomic_read(&in_nmi))) + return; + + if (unlikely(atomic_read(¤t->tracing_graph_pause))) + return; + + /* + * Protect against fault, even if it shouldn't + * happen. This tool is too much intrusive to + * ignore such a protection. + */ + asm volatile( + "1: " _ASM_MOV " (%[parent_old]), %[old]\n" + "2: " _ASM_MOV " %[return_hooker], (%[parent_replaced])\n" + " movl $0, %[faulted]\n" + + ".section .fixup, \"ax\"\n" + "3: movl $1, %[faulted]\n" + ".previous\n" + + _ASM_EXTABLE(1b, 3b) + _ASM_EXTABLE(2b, 3b) + + : [parent_replaced] "=r" (parent), [old] "=r" (old), + [faulted] "=r" (faulted) + : [parent_old] "0" (parent), [return_hooker] "r" (return_hooker) + : "memory" + ); + + if (unlikely(faulted)) { + ftrace_graph_stop(); + WARN_ON(1); + return; + } + + if (unlikely(!__kernel_text_address(old))) { + ftrace_graph_stop(); + *parent = old; + WARN_ON(1); + return; + } + + calltime = cpu_clock(raw_smp_processor_id()); + + if (push_return_trace(old, calltime, + self_addr, &trace.depth) == -EBUSY) { + *parent = old; + return; + } + + trace.func = self_addr; + + /* Only trace if the calling function expects to */ + if (!ftrace_graph_entry(&trace)) { + current->curr_ret_stack--; + *parent = old; + } +} +#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ diff --git a/arch/x86/kernel/genapic_64.c b/arch/x86/kernel/genapic_64.c index 6c9bfc9e1e95cbc5f8aa2273bd06f9eb75c2ca11..2bced78b0b8e85d6317c729c9554919cac2eb67b 100644 --- a/arch/x86/kernel/genapic_64.c +++ b/arch/x86/kernel/genapic_64.c @@ -21,6 +21,7 @@ #include #include #include +#include extern struct genapic apic_flat; extern struct genapic apic_physflat; @@ -53,6 +54,9 @@ void __init setup_apic_routing(void) genapic = &apic_physflat; printk(KERN_INFO "Setting APIC routing to %s\n", genapic->name); } + + if (x86_quirks->update_genapic) + x86_quirks->update_genapic(); } /* Same for both flat and physical. */ diff --git a/arch/x86/kernel/genx2apic_uv_x.c b/arch/x86/kernel/genx2apic_uv_x.c index 2c7dbdb98278316a6fd7228e9a7b2eaf76f58562..dece17289731b951c4189bd5f66db0a919f91197 100644 --- a/arch/x86/kernel/genx2apic_uv_x.c +++ b/arch/x86/kernel/genx2apic_uv_x.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -17,6 +18,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -355,6 +359,103 @@ static __init void uv_rtc_init(void) sn_rtc_cycles_per_second = ticks_per_sec; } +/* + * percpu heartbeat timer + */ +static void uv_heartbeat(unsigned long ignored) +{ + struct timer_list *timer = &uv_hub_info->scir.timer; + unsigned char bits = uv_hub_info->scir.state; + + /* flip heartbeat bit */ + bits ^= SCIR_CPU_HEARTBEAT; + + /* is this cpu idle? */ + if (idle_cpu(raw_smp_processor_id())) + bits &= ~SCIR_CPU_ACTIVITY; + else + bits |= SCIR_CPU_ACTIVITY; + + /* update system controller interface reg */ + uv_set_scir_bits(bits); + + /* enable next timer period */ + mod_timer(timer, jiffies + SCIR_CPU_HB_INTERVAL); +} + +static void __cpuinit uv_heartbeat_enable(int cpu) +{ + if (!uv_cpu_hub_info(cpu)->scir.enabled) { + struct timer_list *timer = &uv_cpu_hub_info(cpu)->scir.timer; + + uv_set_cpu_scir_bits(cpu, SCIR_CPU_HEARTBEAT|SCIR_CPU_ACTIVITY); + setup_timer(timer, uv_heartbeat, cpu); + timer->expires = jiffies + SCIR_CPU_HB_INTERVAL; + add_timer_on(timer, cpu); + uv_cpu_hub_info(cpu)->scir.enabled = 1; + } + + /* check boot cpu */ + if (!uv_cpu_hub_info(0)->scir.enabled) + uv_heartbeat_enable(0); +} + +#ifdef CONFIG_HOTPLUG_CPU +static void __cpuinit uv_heartbeat_disable(int cpu) +{ + if (uv_cpu_hub_info(cpu)->scir.enabled) { + uv_cpu_hub_info(cpu)->scir.enabled = 0; + del_timer(&uv_cpu_hub_info(cpu)->scir.timer); + } + uv_set_cpu_scir_bits(cpu, 0xff); +} + +/* + * cpu hotplug notifier + */ +static __cpuinit int uv_scir_cpu_notify(struct notifier_block *self, + unsigned long action, void *hcpu) +{ + long cpu = (long)hcpu; + + switch (action) { + case CPU_ONLINE: + uv_heartbeat_enable(cpu); + break; + case CPU_DOWN_PREPARE: + uv_heartbeat_disable(cpu); + break; + default: + break; + } + return NOTIFY_OK; +} + +static __init void uv_scir_register_cpu_notifier(void) +{ + hotcpu_notifier(uv_scir_cpu_notify, 0); +} + +#else /* !CONFIG_HOTPLUG_CPU */ + +static __init void uv_scir_register_cpu_notifier(void) +{ +} + +static __init int uv_init_heartbeat(void) +{ + int cpu; + + if (is_uv_system()) + for_each_online_cpu(cpu) + uv_heartbeat_enable(cpu); + return 0; +} + +late_initcall(uv_init_heartbeat); + +#endif /* !CONFIG_HOTPLUG_CPU */ + /* * Called on each cpu to initialize the per_cpu UV data area. * ZZZ hotplug not supported yet @@ -428,7 +529,7 @@ void __init uv_system_init(void) uv_bios_init(); uv_bios_get_sn_info(0, &uv_type, &sn_partition_id, - &uv_coherency_id, &uv_region_size); + &sn_coherency_id, &sn_region_size); uv_rtc_init(); for_each_present_cpu(cpu) { @@ -439,8 +540,7 @@ void __init uv_system_init(void) uv_blade_info[blade].nr_possible_cpus++; uv_cpu_hub_info(cpu)->lowmem_remap_base = lowmem_redir_base; - uv_cpu_hub_info(cpu)->lowmem_remap_top = - lowmem_redir_base + lowmem_redir_size; + uv_cpu_hub_info(cpu)->lowmem_remap_top = lowmem_redir_size; uv_cpu_hub_info(cpu)->m_val = m_val; uv_cpu_hub_info(cpu)->n_val = m_val; uv_cpu_hub_info(cpu)->numa_blade_id = blade; @@ -450,7 +550,8 @@ void __init uv_system_init(void) uv_cpu_hub_info(cpu)->gpa_mask = (1 << (m_val + n_val)) - 1; uv_cpu_hub_info(cpu)->gnode_upper = gnode_upper; uv_cpu_hub_info(cpu)->global_mmr_base = mmr_base; - uv_cpu_hub_info(cpu)->coherency_domain_number = uv_coherency_id; + uv_cpu_hub_info(cpu)->coherency_domain_number = sn_coherency_id; + uv_cpu_hub_info(cpu)->scir.offset = SCIR_LOCAL_MMR_BASE + lcpu; uv_node_to_blade[nid] = blade; uv_cpu_to_blade[cpu] = blade; max_pnode = max(pnode, max_pnode); @@ -467,4 +568,6 @@ void __init uv_system_init(void) map_mmioh_high(max_pnode); uv_cpu_init(); + uv_scir_register_cpu_notifier(); + proc_mkdir("sgi_uv", NULL); } diff --git a/arch/x86/kernel/head.c b/arch/x86/kernel/head.c index 1dcb0f13897e9b6d4773111e1bc8300713efe0e8..3e66bd364a9db3cf8f3fb624f96eeb7075364d78 100644 --- a/arch/x86/kernel/head.c +++ b/arch/x86/kernel/head.c @@ -35,7 +35,6 @@ void __init reserve_ebda_region(void) /* start of EBDA area */ ebda_addr = get_bios_ebda(); - printk(KERN_INFO "BIOS EBDA/lowmem at: %08x/%08x\n", ebda_addr, lowmem); /* Fixup: bios puts an EBDA in the top 64K segment */ /* of conventional memory, but does not adjust lowmem. */ diff --git a/arch/x86/kernel/head32.c b/arch/x86/kernel/head32.c index fa1d25dd83e3fa18cc2a445841c61e1e1b8b571c..ac108d1fe182a44abcd0da75f18aae5fde32e1c0 100644 --- a/arch/x86/kernel/head32.c +++ b/arch/x86/kernel/head32.c @@ -12,9 +12,12 @@ #include #include #include +#include void __init i386_start_kernel(void) { + reserve_trampoline_memory(); + reserve_early(__pa_symbol(&_text), __pa_symbol(&_end), "TEXT DATA BSS"); #ifdef CONFIG_BLK_DEV_INITRD diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c index d16084f90649181e6e944e104118f7ec5de6a0e3..388e05a5fc17ec05dc68fc881c169608390538b5 100644 --- a/arch/x86/kernel/head64.c +++ b/arch/x86/kernel/head64.c @@ -24,6 +24,7 @@ #include #include #include +#include /* boot cpu pda */ static struct x8664_pda _boot_cpu_pda __read_mostly; @@ -120,6 +121,8 @@ void __init x86_64_start_reservations(char *real_mode_data) { copy_bootdata(__va(real_mode_data)); + reserve_trampoline_memory(); + reserve_early(__pa_symbol(&_text), __pa_symbol(&_end), "TEXT DATA BSS"); #ifdef CONFIG_BLK_DEV_INITRD diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index 067d8de913f612d45018090a1fae4e5cc920462f..3f0a3edf0a573a2f5f2d1051b32285ebffcdbb36 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c @@ -33,7 +33,9 @@ * HPET address is set in acpi/boot.c, when an ACPI entry exists */ unsigned long hpet_address; -unsigned long hpet_num_timers; +#ifdef CONFIG_PCI_MSI +static unsigned long hpet_num_timers; +#endif static void __iomem *hpet_virt_address; struct hpet_dev { diff --git a/arch/x86/kernel/init_task.c b/arch/x86/kernel/init_task.c index a4f93b4120c155c20889947942d7bdb5c286908d..d39918076bb48a4b70e5b911736f84ec817fd420 100644 --- a/arch/x86/kernel/init_task.c +++ b/arch/x86/kernel/init_task.c @@ -14,7 +14,6 @@ static struct fs_struct init_fs = INIT_FS; static struct signal_struct init_signals = INIT_SIGNALS(init_signals); static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); struct mm_struct init_mm = INIT_MM(init_mm); -EXPORT_UNUSED_SYMBOL(init_mm); /* will be removed in 2.6.26 */ /* * Initial thread structure. diff --git a/arch/x86/kernel/io_apic.c b/arch/x86/kernel/io_apic.c index 9043251210fba4dc32ea7db009a1db6196216453..679e7bbbbcd6b07230a2e7fdbd2ebe38e04f0563 100644 --- a/arch/x86/kernel/io_apic.c +++ b/arch/x86/kernel/io_apic.c @@ -2216,10 +2216,9 @@ static void set_ir_ioapic_affinity_irq(unsigned int irq, cpumask_t mask) asmlinkage void smp_irq_move_cleanup_interrupt(void) { unsigned vector, me; + ack_APIC_irq(); -#ifdef CONFIG_X86_64 exit_idle(); -#endif irq_enter(); me = smp_processor_id(); diff --git a/arch/x86/kernel/irq_64.c b/arch/x86/kernel/irq_64.c index 60eb84eb77a0a34232be8aafbe8a7d1e040f454f..1df869e5bd0b935fc12e5a65b254eeb985df3f6f 100644 --- a/arch/x86/kernel/irq_64.c +++ b/arch/x86/kernel/irq_64.c @@ -13,12 +13,12 @@ #include #include #include +#include #include #include #include #include -#ifdef CONFIG_DEBUG_STACKOVERFLOW /* * Probabilistic stack overflow check: * @@ -28,26 +28,25 @@ */ static inline void stack_overflow_check(struct pt_regs *regs) { +#ifdef CONFIG_DEBUG_STACKOVERFLOW u64 curbase = (u64)task_stack_page(current); - static unsigned long warned = -60*HZ; - - if (regs->sp >= curbase && regs->sp <= curbase + THREAD_SIZE && - regs->sp < curbase + sizeof(struct thread_info) + 128 && - time_after(jiffies, warned + 60*HZ)) { - printk("do_IRQ: %s near stack overflow (cur:%Lx,sp:%lx)\n", - current->comm, curbase, regs->sp); - show_stack(NULL,NULL); - warned = jiffies; - } -} + + WARN_ONCE(regs->sp >= curbase && + regs->sp <= curbase + THREAD_SIZE && + regs->sp < curbase + sizeof(struct thread_info) + + sizeof(struct pt_regs) + 128, + + "do_IRQ: %s near stack overflow (cur:%Lx,sp:%lx)\n", + current->comm, curbase, regs->sp); #endif +} /* * do_IRQ handles all normal device IRQ's (the special * SMP cross-CPU interrupts have their own specific * handlers). */ -asmlinkage unsigned int do_IRQ(struct pt_regs *regs) +asmlinkage unsigned int __irq_entry do_IRQ(struct pt_regs *regs) { struct pt_regs *old_regs = set_irq_regs(regs); struct irq_desc *desc; @@ -60,9 +59,7 @@ asmlinkage unsigned int do_IRQ(struct pt_regs *regs) irq_enter(); irq = __get_cpu_var(vector_irq)[vector]; -#ifdef CONFIG_DEBUG_STACKOVERFLOW stack_overflow_check(regs); -#endif desc = irq_to_desc(irq); if (likely(desc)) diff --git a/arch/x86/kernel/irqinit_32.c b/arch/x86/kernel/irqinit_32.c index 845aa9803e804edd7cdc6ef5bb61e2db72f1a911..607db63044a5e6f2ea383f71378a6a79ce85797b 100644 --- a/arch/x86/kernel/irqinit_32.c +++ b/arch/x86/kernel/irqinit_32.c @@ -129,7 +129,7 @@ void __init native_init_IRQ(void) for (i = FIRST_EXTERNAL_VECTOR; i < NR_VECTORS; i++) { /* SYSCALL_VECTOR was reserved in trap_init. */ if (i != SYSCALL_VECTOR) - set_intr_gate(i, interrupt[i]); + set_intr_gate(i, interrupt[i-FIRST_EXTERNAL_VECTOR]); } diff --git a/arch/x86/kernel/irqinit_64.c b/arch/x86/kernel/irqinit_64.c index ff0235391285a6dc388e1d175f04a6425972d90f..8670b3ce626e7ee6bf0d379c610959a699d79aef 100644 --- a/arch/x86/kernel/irqinit_64.c +++ b/arch/x86/kernel/irqinit_64.c @@ -23,41 +23,6 @@ #include #include -/* - * Common place to define all x86 IRQ vectors - * - * This builds up the IRQ handler stubs using some ugly macros in irq.h - * - * These macros create the low-level assembly IRQ routines that save - * register context and call do_IRQ(). do_IRQ() then does all the - * operations that are needed to keep the AT (or SMP IOAPIC) - * interrupt-controller happy. - */ - -#define IRQ_NAME2(nr) nr##_interrupt(void) -#define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr) - -/* - * SMP has a few special interrupts for IPI messages - */ - -#define BUILD_IRQ(nr) \ - asmlinkage void IRQ_NAME(nr); \ - asm("\n.text\n.p2align\n" \ - "IRQ" #nr "_interrupt:\n\t" \ - "push $~(" #nr ") ; " \ - "jmp common_interrupt\n" \ - ".previous"); - -#define BI(x,y) \ - BUILD_IRQ(x##y) - -#define BUILD_16_IRQS(x) \ - BI(x,0) BI(x,1) BI(x,2) BI(x,3) \ - BI(x,4) BI(x,5) BI(x,6) BI(x,7) \ - BI(x,8) BI(x,9) BI(x,a) BI(x,b) \ - BI(x,c) BI(x,d) BI(x,e) BI(x,f) - /* * ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts: * (these are usually mapped to vectors 0x30-0x3f) @@ -73,37 +38,6 @@ * * (these are usually mapped into the 0x30-0xff vector range) */ - BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3) -BUILD_16_IRQS(0x4) BUILD_16_IRQS(0x5) BUILD_16_IRQS(0x6) BUILD_16_IRQS(0x7) -BUILD_16_IRQS(0x8) BUILD_16_IRQS(0x9) BUILD_16_IRQS(0xa) BUILD_16_IRQS(0xb) -BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd) BUILD_16_IRQS(0xe) BUILD_16_IRQS(0xf) - -#undef BUILD_16_IRQS -#undef BI - - -#define IRQ(x,y) \ - IRQ##x##y##_interrupt - -#define IRQLIST_16(x) \ - IRQ(x,0), IRQ(x,1), IRQ(x,2), IRQ(x,3), \ - IRQ(x,4), IRQ(x,5), IRQ(x,6), IRQ(x,7), \ - IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \ - IRQ(x,c), IRQ(x,d), IRQ(x,e), IRQ(x,f) - -/* for the irq vectors */ -static void (*__initdata interrupt[NR_VECTORS - FIRST_EXTERNAL_VECTOR])(void) = { - IRQLIST_16(0x2), IRQLIST_16(0x3), - IRQLIST_16(0x4), IRQLIST_16(0x5), IRQLIST_16(0x6), IRQLIST_16(0x7), - IRQLIST_16(0x8), IRQLIST_16(0x9), IRQLIST_16(0xa), IRQLIST_16(0xb), - IRQLIST_16(0xc), IRQLIST_16(0xd), IRQLIST_16(0xe), IRQLIST_16(0xf) -}; - -#undef IRQ -#undef IRQLIST_16 - - - /* * IRQ2 is cascade interrupt to second interrupt controller diff --git a/arch/x86/kernel/machine_kexec_32.c b/arch/x86/kernel/machine_kexec_32.c index 7a385746509a2a625991447e8554a20b4d992c54..37f420018a41c806bf57048d50163d0d28c640aa 100644 --- a/arch/x86/kernel/machine_kexec_32.c +++ b/arch/x86/kernel/machine_kexec_32.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -25,15 +26,6 @@ #include #include -#define PAGE_ALIGNED __attribute__ ((__aligned__(PAGE_SIZE))) -static u32 kexec_pgd[1024] PAGE_ALIGNED; -#ifdef CONFIG_X86_PAE -static u32 kexec_pmd0[1024] PAGE_ALIGNED; -static u32 kexec_pmd1[1024] PAGE_ALIGNED; -#endif -static u32 kexec_pte0[1024] PAGE_ALIGNED; -static u32 kexec_pte1[1024] PAGE_ALIGNED; - static void set_idt(void *newidt, __u16 limit) { struct desc_ptr curidt; @@ -76,6 +68,76 @@ static void load_segments(void) #undef __STR } +static void machine_kexec_free_page_tables(struct kimage *image) +{ + free_page((unsigned long)image->arch.pgd); +#ifdef CONFIG_X86_PAE + free_page((unsigned long)image->arch.pmd0); + free_page((unsigned long)image->arch.pmd1); +#endif + free_page((unsigned long)image->arch.pte0); + free_page((unsigned long)image->arch.pte1); +} + +static int machine_kexec_alloc_page_tables(struct kimage *image) +{ + image->arch.pgd = (pgd_t *)get_zeroed_page(GFP_KERNEL); +#ifdef CONFIG_X86_PAE + image->arch.pmd0 = (pmd_t *)get_zeroed_page(GFP_KERNEL); + image->arch.pmd1 = (pmd_t *)get_zeroed_page(GFP_KERNEL); +#endif + image->arch.pte0 = (pte_t *)get_zeroed_page(GFP_KERNEL); + image->arch.pte1 = (pte_t *)get_zeroed_page(GFP_KERNEL); + if (!image->arch.pgd || +#ifdef CONFIG_X86_PAE + !image->arch.pmd0 || !image->arch.pmd1 || +#endif + !image->arch.pte0 || !image->arch.pte1) { + machine_kexec_free_page_tables(image); + return -ENOMEM; + } + return 0; +} + +static void machine_kexec_page_table_set_one( + pgd_t *pgd, pmd_t *pmd, pte_t *pte, + unsigned long vaddr, unsigned long paddr) +{ + pud_t *pud; + + pgd += pgd_index(vaddr); +#ifdef CONFIG_X86_PAE + if (!(pgd_val(*pgd) & _PAGE_PRESENT)) + set_pgd(pgd, __pgd(__pa(pmd) | _PAGE_PRESENT)); +#endif + pud = pud_offset(pgd, vaddr); + pmd = pmd_offset(pud, vaddr); + if (!(pmd_val(*pmd) & _PAGE_PRESENT)) + set_pmd(pmd, __pmd(__pa(pte) | _PAGE_TABLE)); + pte = pte_offset_kernel(pmd, vaddr); + set_pte(pte, pfn_pte(paddr >> PAGE_SHIFT, PAGE_KERNEL_EXEC)); +} + +static void machine_kexec_prepare_page_tables(struct kimage *image) +{ + void *control_page; + pmd_t *pmd = 0; + + control_page = page_address(image->control_code_page); +#ifdef CONFIG_X86_PAE + pmd = image->arch.pmd0; +#endif + machine_kexec_page_table_set_one( + image->arch.pgd, pmd, image->arch.pte0, + (unsigned long)control_page, __pa(control_page)); +#ifdef CONFIG_X86_PAE + pmd = image->arch.pmd1; +#endif + machine_kexec_page_table_set_one( + image->arch.pgd, pmd, image->arch.pte1, + __pa(control_page), __pa(control_page)); +} + /* * A architecture hook called to validate the * proposed image and prepare the control pages @@ -87,12 +149,20 @@ static void load_segments(void) * reboot code buffer to allow us to avoid allocations * later. * - * Make control page executable. + * - Make control page executable. + * - Allocate page tables + * - Setup page tables */ int machine_kexec_prepare(struct kimage *image) { + int error; + if (nx_enabled) set_pages_x(image->control_code_page, 1); + error = machine_kexec_alloc_page_tables(image); + if (error) + return error; + machine_kexec_prepare_page_tables(image); return 0; } @@ -104,6 +174,7 @@ void machine_kexec_cleanup(struct kimage *image) { if (nx_enabled) set_pages_nx(image->control_code_page, 1); + machine_kexec_free_page_tables(image); } /* @@ -150,18 +221,7 @@ void machine_kexec(struct kimage *image) relocate_kernel_ptr = control_page; page_list[PA_CONTROL_PAGE] = __pa(control_page); page_list[VA_CONTROL_PAGE] = (unsigned long)control_page; - page_list[PA_PGD] = __pa(kexec_pgd); - page_list[VA_PGD] = (unsigned long)kexec_pgd; -#ifdef CONFIG_X86_PAE - page_list[PA_PMD_0] = __pa(kexec_pmd0); - page_list[VA_PMD_0] = (unsigned long)kexec_pmd0; - page_list[PA_PMD_1] = __pa(kexec_pmd1); - page_list[VA_PMD_1] = (unsigned long)kexec_pmd1; -#endif - page_list[PA_PTE_0] = __pa(kexec_pte0); - page_list[VA_PTE_0] = (unsigned long)kexec_pte0; - page_list[PA_PTE_1] = __pa(kexec_pte1); - page_list[VA_PTE_1] = (unsigned long)kexec_pte1; + page_list[PA_PGD] = __pa(image->arch.pgd); if (image->type == KEXEC_TYPE_DEFAULT) page_list[PA_SWAP_PAGE] = (page_to_pfn(image->swap_page) diff --git a/arch/x86/kernel/microcode_amd.c b/arch/x86/kernel/microcode_amd.c index 5f8e5d75a254621799bff0138430fd2344b918a7..c25fdb38229212cb5e5ad79f527770bb9063153e 100644 --- a/arch/x86/kernel/microcode_amd.c +++ b/arch/x86/kernel/microcode_amd.c @@ -10,7 +10,7 @@ * This driver allows to upgrade microcode on AMD * family 0x10 and 0x11 processors. * - * Licensed unter the terms of the GNU General Public + * Licensed under the terms of the GNU General Public * License version 2. See file COPYING for details. */ @@ -32,9 +32,9 @@ #include #include #include +#include #include -#include #include #include @@ -47,43 +47,38 @@ MODULE_LICENSE("GPL v2"); #define UCODE_UCODE_TYPE 0x00000001 struct equiv_cpu_entry { - unsigned int installed_cpu; - unsigned int fixed_errata_mask; - unsigned int fixed_errata_compare; - unsigned int equiv_cpu; -}; + u32 installed_cpu; + u32 fixed_errata_mask; + u32 fixed_errata_compare; + u16 equiv_cpu; + u16 res; +} __attribute__((packed)); struct microcode_header_amd { - unsigned int data_code; - unsigned int patch_id; - unsigned char mc_patch_data_id[2]; - unsigned char mc_patch_data_len; - unsigned char init_flag; - unsigned int mc_patch_data_checksum; - unsigned int nb_dev_id; - unsigned int sb_dev_id; - unsigned char processor_rev_id[2]; - unsigned char nb_rev_id; - unsigned char sb_rev_id; - unsigned char bios_api_rev; - unsigned char reserved1[3]; - unsigned int match_reg[8]; -}; + u32 data_code; + u32 patch_id; + u16 mc_patch_data_id; + u8 mc_patch_data_len; + u8 init_flag; + u32 mc_patch_data_checksum; + u32 nb_dev_id; + u32 sb_dev_id; + u16 processor_rev_id; + u8 nb_rev_id; + u8 sb_rev_id; + u8 bios_api_rev; + u8 reserved1[3]; + u32 match_reg[8]; +} __attribute__((packed)); struct microcode_amd { struct microcode_header_amd hdr; unsigned int mpb[0]; }; -#define UCODE_MAX_SIZE (2048) -#define DEFAULT_UCODE_DATASIZE (896) -#define MC_HEADER_SIZE (sizeof(struct microcode_header_amd)) -#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE) -#define DWSIZE (sizeof(u32)) -/* For now we support a fixed ucode total size only */ -#define get_totalsize(mc) \ - ((((struct microcode_amd *)mc)->hdr.mc_patch_data_len * 28) \ - + MC_HEADER_SIZE) +#define UCODE_MAX_SIZE 2048 +#define UCODE_CONTAINER_SECTION_HDR 8 +#define UCODE_CONTAINER_HEADER_SIZE 12 /* serialize access to the physical write */ static DEFINE_SPINLOCK(microcode_update_lock); @@ -93,31 +88,24 @@ static struct equiv_cpu_entry *equiv_cpu_table; static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig) { struct cpuinfo_x86 *c = &cpu_data(cpu); + u32 dummy; memset(csig, 0, sizeof(*csig)); - if (c->x86_vendor != X86_VENDOR_AMD || c->x86 < 0x10) { - printk(KERN_ERR "microcode: CPU%d not a capable AMD processor\n", - cpu); + printk(KERN_WARNING "microcode: CPU%d: AMD CPU family 0x%x not " + "supported\n", cpu, c->x86); return -1; } - - asm volatile("movl %1, %%ecx; rdmsr" - : "=a" (csig->rev) - : "i" (0x0000008B) : "ecx"); - - printk(KERN_INFO "microcode: collect_cpu_info_amd : patch_id=0x%x\n", - csig->rev); - + rdmsr(MSR_AMD64_PATCH_LEVEL, csig->rev, dummy); + printk(KERN_INFO "microcode: CPU%d: patch_level=0x%x\n", cpu, csig->rev); return 0; } static int get_matching_microcode(int cpu, void *mc, int rev) { struct microcode_header_amd *mc_header = mc; - struct pci_dev *nb_pci_dev, *sb_pci_dev; unsigned int current_cpu_id; - unsigned int equiv_cpu_id = 0x00; + u16 equiv_cpu_id = 0; unsigned int i = 0; BUG_ON(equiv_cpu_table == NULL); @@ -132,57 +120,25 @@ static int get_matching_microcode(int cpu, void *mc, int rev) } if (!equiv_cpu_id) { - printk(KERN_ERR "microcode: CPU%d cpu_id " - "not found in equivalent cpu table \n", cpu); + printk(KERN_WARNING "microcode: CPU%d: cpu revision " + "not listed in equivalent cpu table\n", cpu); return 0; } - if ((mc_header->processor_rev_id[0]) != (equiv_cpu_id & 0xff)) { - printk(KERN_ERR - "microcode: CPU%d patch does not match " - "(patch is %x, cpu extended is %x) \n", - cpu, mc_header->processor_rev_id[0], - (equiv_cpu_id & 0xff)); + if (mc_header->processor_rev_id != equiv_cpu_id) { + printk(KERN_ERR "microcode: CPU%d: patch mismatch " + "(processor_rev_id: %x, equiv_cpu_id: %x)\n", + cpu, mc_header->processor_rev_id, equiv_cpu_id); return 0; } - if ((mc_header->processor_rev_id[1]) != ((equiv_cpu_id >> 16) & 0xff)) { - printk(KERN_ERR "microcode: CPU%d patch does not match " - "(patch is %x, cpu base id is %x) \n", - cpu, mc_header->processor_rev_id[1], - ((equiv_cpu_id >> 16) & 0xff)); - + /* ucode might be chipset specific -- currently we don't support this */ + if (mc_header->nb_dev_id || mc_header->sb_dev_id) { + printk(KERN_ERR "microcode: CPU%d: loading of chipset " + "specific code not yet supported\n", cpu); return 0; } - /* ucode may be northbridge specific */ - if (mc_header->nb_dev_id) { - nb_pci_dev = pci_get_device(PCI_VENDOR_ID_AMD, - (mc_header->nb_dev_id & 0xff), - NULL); - if ((!nb_pci_dev) || - (mc_header->nb_rev_id != nb_pci_dev->revision)) { - printk(KERN_ERR "microcode: CPU%d NB mismatch \n", cpu); - pci_dev_put(nb_pci_dev); - return 0; - } - pci_dev_put(nb_pci_dev); - } - - /* ucode may be southbridge specific */ - if (mc_header->sb_dev_id) { - sb_pci_dev = pci_get_device(PCI_VENDOR_ID_AMD, - (mc_header->sb_dev_id & 0xff), - NULL); - if ((!sb_pci_dev) || - (mc_header->sb_rev_id != sb_pci_dev->revision)) { - printk(KERN_ERR "microcode: CPU%d SB mismatch \n", cpu); - pci_dev_put(sb_pci_dev); - return 0; - } - pci_dev_put(sb_pci_dev); - } - if (mc_header->patch_id <= rev) return 0; @@ -192,12 +148,10 @@ static int get_matching_microcode(int cpu, void *mc, int rev) static void apply_microcode_amd(int cpu) { unsigned long flags; - unsigned int eax, edx; - unsigned int rev; + u32 rev, dummy; int cpu_num = raw_smp_processor_id(); struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; struct microcode_amd *mc_amd = uci->mc; - unsigned long addr; /* We should bind the task to the CPU */ BUG_ON(cpu_num != cpu); @@ -206,42 +160,34 @@ static void apply_microcode_amd(int cpu) return; spin_lock_irqsave(µcode_update_lock, flags); - - addr = (unsigned long)&mc_amd->hdr.data_code; - edx = (unsigned int)(((unsigned long)upper_32_bits(addr))); - eax = (unsigned int)(((unsigned long)lower_32_bits(addr))); - - asm volatile("movl %0, %%ecx; wrmsr" : - : "i" (0xc0010020), "a" (eax), "d" (edx) : "ecx"); - + wrmsrl(MSR_AMD64_PATCH_LOADER, (u64)(long)&mc_amd->hdr.data_code); /* get patch id after patching */ - asm volatile("movl %1, %%ecx; rdmsr" - : "=a" (rev) - : "i" (0x0000008B) : "ecx"); - + rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); spin_unlock_irqrestore(µcode_update_lock, flags); /* check current patch id and patch's id for match */ if (rev != mc_amd->hdr.patch_id) { - printk(KERN_ERR "microcode: CPU%d update from revision " - "0x%x to 0x%x failed\n", cpu_num, - mc_amd->hdr.patch_id, rev); + printk(KERN_ERR "microcode: CPU%d: update failed " + "(for patch_level=0x%x)\n", cpu, mc_amd->hdr.patch_id); return; } - printk(KERN_INFO "microcode: CPU%d updated from revision " - "0x%x to 0x%x \n", - cpu_num, uci->cpu_sig.rev, mc_amd->hdr.patch_id); + printk(KERN_INFO "microcode: CPU%d: updated (new patch_level=0x%x)\n", + cpu, rev); uci->cpu_sig.rev = rev; } -static void * get_next_ucode(u8 *buf, unsigned int size, - int (*get_ucode_data)(void *, const void *, size_t), - unsigned int *mc_size) +static int get_ucode_data(void *to, const u8 *from, size_t n) +{ + memcpy(to, from, n); + return 0; +} + +static void *get_next_ucode(const u8 *buf, unsigned int size, + unsigned int *mc_size) { unsigned int total_size; -#define UCODE_CONTAINER_SECTION_HDR 8 u8 section_hdr[UCODE_CONTAINER_SECTION_HDR]; void *mc; @@ -249,39 +195,37 @@ static void * get_next_ucode(u8 *buf, unsigned int size, return NULL; if (section_hdr[0] != UCODE_UCODE_TYPE) { - printk(KERN_ERR "microcode: error! " - "Wrong microcode payload type field\n"); + printk(KERN_ERR "microcode: error: invalid type field in " + "container file section header\n"); return NULL; } total_size = (unsigned long) (section_hdr[4] + (section_hdr[5] << 8)); - printk(KERN_INFO "microcode: size %u, total_size %u\n", - size, total_size); + printk(KERN_DEBUG "microcode: size %u, total_size %u\n", + size, total_size); if (total_size > size || total_size > UCODE_MAX_SIZE) { - printk(KERN_ERR "microcode: error! Bad data in microcode data file\n"); + printk(KERN_ERR "microcode: error: size mismatch\n"); return NULL; } mc = vmalloc(UCODE_MAX_SIZE); if (mc) { memset(mc, 0, UCODE_MAX_SIZE); - if (get_ucode_data(mc, buf + UCODE_CONTAINER_SECTION_HDR, total_size)) { + if (get_ucode_data(mc, buf + UCODE_CONTAINER_SECTION_HDR, + total_size)) { vfree(mc); mc = NULL; } else *mc_size = total_size + UCODE_CONTAINER_SECTION_HDR; } -#undef UCODE_CONTAINER_SECTION_HDR return mc; } -static int install_equiv_cpu_table(u8 *buf, - int (*get_ucode_data)(void *, const void *, size_t)) +static int install_equiv_cpu_table(const u8 *buf) { -#define UCODE_CONTAINER_HEADER_SIZE 12 u8 *container_hdr[UCODE_CONTAINER_HEADER_SIZE]; unsigned int *buf_pos = (unsigned int *)container_hdr; unsigned long size; @@ -292,14 +236,15 @@ static int install_equiv_cpu_table(u8 *buf, size = buf_pos[2]; if (buf_pos[1] != UCODE_EQUIV_CPU_TABLE_TYPE || !size) { - printk(KERN_ERR "microcode: error! " - "Wrong microcode equivalnet cpu table\n"); + printk(KERN_ERR "microcode: error: invalid type field in " + "container file section header\n"); return 0; } equiv_cpu_table = (struct equiv_cpu_entry *) vmalloc(size); if (!equiv_cpu_table) { - printk(KERN_ERR "microcode: error, can't allocate memory for equiv CPU table\n"); + printk(KERN_ERR "microcode: failed to allocate " + "equivalent CPU table\n"); return 0; } @@ -310,7 +255,6 @@ static int install_equiv_cpu_table(u8 *buf, } return size + UCODE_CONTAINER_HEADER_SIZE; /* add header length */ -#undef UCODE_CONTAINER_HEADER_SIZE } static void free_equiv_cpu_table(void) @@ -321,18 +265,20 @@ static void free_equiv_cpu_table(void) } } -static int generic_load_microcode(int cpu, void *data, size_t size, - int (*get_ucode_data)(void *, const void *, size_t)) +static int generic_load_microcode(int cpu, const u8 *data, size_t size) { struct ucode_cpu_info *uci = ucode_cpu_info + cpu; - u8 *ucode_ptr = data, *new_mc = NULL, *mc; + const u8 *ucode_ptr = data; + void *new_mc = NULL; + void *mc; int new_rev = uci->cpu_sig.rev; unsigned int leftover; unsigned long offset; - offset = install_equiv_cpu_table(ucode_ptr, get_ucode_data); + offset = install_equiv_cpu_table(ucode_ptr); if (!offset) { - printk(KERN_ERR "microcode: installing equivalent cpu table failed\n"); + printk(KERN_ERR "microcode: failed to create " + "equivalent cpu table\n"); return -EINVAL; } @@ -343,7 +289,7 @@ static int generic_load_microcode(int cpu, void *data, size_t size, unsigned int uninitialized_var(mc_size); struct microcode_header_amd *mc_header; - mc = get_next_ucode(ucode_ptr, leftover, get_ucode_data, &mc_size); + mc = get_next_ucode(ucode_ptr, leftover, &mc_size); if (!mc) break; @@ -353,7 +299,7 @@ static int generic_load_microcode(int cpu, void *data, size_t size, vfree(new_mc); new_rev = mc_header->patch_id; new_mc = mc; - } else + } else vfree(mc); ucode_ptr += mc_size; @@ -365,9 +311,9 @@ static int generic_load_microcode(int cpu, void *data, size_t size, if (uci->mc) vfree(uci->mc); uci->mc = new_mc; - pr_debug("microcode: CPU%d found a matching microcode update with" - " version 0x%x (current=0x%x)\n", - cpu, new_rev, uci->cpu_sig.rev); + pr_debug("microcode: CPU%d found a matching microcode " + "update with version 0x%x (current=0x%x)\n", + cpu, new_rev, uci->cpu_sig.rev); } else vfree(new_mc); } @@ -377,12 +323,6 @@ static int generic_load_microcode(int cpu, void *data, size_t size, return (int)leftover; } -static int get_ucode_fw(void *to, const void *from, size_t n) -{ - memcpy(to, from, n); - return 0; -} - static int request_microcode_fw(int cpu, struct device *device) { const char *fw_name = "amd-ucode/microcode_amd.bin"; @@ -394,12 +334,11 @@ static int request_microcode_fw(int cpu, struct device *device) ret = request_firmware(&firmware, fw_name, device); if (ret) { - printk(KERN_ERR "microcode: ucode data file %s load failed\n", fw_name); + printk(KERN_ERR "microcode: failed to load file %s\n", fw_name); return ret; } - ret = generic_load_microcode(cpu, (void*)firmware->data, firmware->size, - &get_ucode_fw); + ret = generic_load_microcode(cpu, firmware->data, firmware->size); release_firmware(firmware); @@ -408,8 +347,8 @@ static int request_microcode_fw(int cpu, struct device *device) static int request_microcode_user(int cpu, const void __user *buf, size_t size) { - printk(KERN_WARNING "microcode: AMD microcode update via /dev/cpu/microcode" - "is not supported\n"); + printk(KERN_INFO "microcode: AMD microcode update via " + "/dev/cpu/microcode not supported\n"); return -1; } @@ -433,3 +372,4 @@ struct microcode_ops * __init init_amd_microcode(void) { return µcode_amd_ops; } + diff --git a/arch/x86/kernel/microcode_core.c b/arch/x86/kernel/microcode_core.c index c4b5b24e0217c585cbb8d0f8011a8b6c87229a6f..c9b721ba968c8f779a253919b2c7c046542ea974 100644 --- a/arch/x86/kernel/microcode_core.c +++ b/arch/x86/kernel/microcode_core.c @@ -99,7 +99,7 @@ MODULE_LICENSE("GPL"); #define MICROCODE_VERSION "2.00" -struct microcode_ops *microcode_ops; +static struct microcode_ops *microcode_ops; /* no concurrent ->write()s are allowed on /dev/cpu/microcode */ static DEFINE_MUTEX(microcode_mutex); @@ -203,7 +203,7 @@ MODULE_ALIAS_MISCDEV(MICROCODE_MINOR); #endif /* fake device for request_firmware */ -struct platform_device *microcode_pdev; +static struct platform_device *microcode_pdev; static ssize_t reload_store(struct sys_device *dev, struct sysdev_attribute *attr, @@ -328,7 +328,7 @@ static int microcode_resume_cpu(int cpu) return 0; } -void microcode_update_cpu(int cpu) +static void microcode_update_cpu(int cpu) { struct ucode_cpu_info *uci = ucode_cpu_info + cpu; int err = 0; diff --git a/arch/x86/kernel/microcode_intel.c b/arch/x86/kernel/microcode_intel.c index a8e62792d171c6c63645582441b3d9482fffcbac..b7f4c929e61505d368ac02de9e63e9a917472ca8 100644 --- a/arch/x86/kernel/microcode_intel.c +++ b/arch/x86/kernel/microcode_intel.c @@ -471,7 +471,7 @@ static void microcode_fini_cpu(int cpu) uci->mc = NULL; } -struct microcode_ops microcode_intel_ops = { +static struct microcode_ops microcode_intel_ops = { .request_microcode_user = request_microcode_user, .request_microcode_fw = request_microcode_fw, .collect_cpu_info = collect_cpu_info, diff --git a/arch/x86/kernel/mpparse.c b/arch/x86/kernel/mpparse.c index 0f4c1fd5a1f434259afd90480b5af527b326b855..45e3b69808ba6722bcc9617cdd0c883cab1a8ee2 100644 --- a/arch/x86/kernel/mpparse.c +++ b/arch/x86/kernel/mpparse.c @@ -586,26 +586,23 @@ static void __init __get_smp_config(unsigned int early) { struct intel_mp_floating *mpf = mpf_found; - if (x86_quirks->mach_get_smp_config) { - if (x86_quirks->mach_get_smp_config(early)) - return; - } + if (!mpf) + return; + if (acpi_lapic && early) return; + /* - * ACPI supports both logical (e.g. Hyper-Threading) and physical - * processors, where MPS only supports physical. + * MPS doesn't support hyperthreading, aka only have + * thread 0 apic id in MPS table */ - if (acpi_lapic && acpi_ioapic) { - printk(KERN_INFO "Using ACPI (MADT) for SMP configuration " - "information\n"); + if (acpi_lapic && acpi_ioapic) return; - } else if (acpi_lapic) - printk(KERN_INFO "Using ACPI for processor (LAPIC) " - "configuration information\n"); - if (!mpf) - return; + if (x86_quirks->mach_get_smp_config) { + if (x86_quirks->mach_get_smp_config(early)) + return; + } printk(KERN_INFO "Intel MultiProcessor Specification v1.%d\n", mpf->mpf_specification); diff --git a/arch/x86/kernel/nmi.c b/arch/x86/kernel/nmi.c index 2c97f07f1c2cb76a705e4e421c018837588f1b6c..8bd1bf9622a7cf1062f33e039c37a2167e5f2918 100644 --- a/arch/x86/kernel/nmi.c +++ b/arch/x86/kernel/nmi.c @@ -131,6 +131,11 @@ static void report_broken_nmi(int cpu, int *prev_nmi_count) atomic_dec(&nmi_active); } +static void __acpi_nmi_disable(void *__unused) +{ + apic_write(APIC_LVT0, APIC_DM_NMI | APIC_LVT_MASKED); +} + int __init check_nmi_watchdog(void) { unsigned int *prev_nmi_count; @@ -179,8 +184,12 @@ int __init check_nmi_watchdog(void) kfree(prev_nmi_count); return 0; error: - if (nmi_watchdog == NMI_IO_APIC && !timer_through_8259) - disable_8259A_irq(0); + if (nmi_watchdog == NMI_IO_APIC) { + if (!timer_through_8259) + disable_8259A_irq(0); + on_each_cpu(__acpi_nmi_disable, NULL, 1); + } + #ifdef CONFIG_X86_32 timer_ack = 0; #endif @@ -199,12 +208,17 @@ static int __init setup_nmi_watchdog(char *str) ++str; } - get_option(&str, &nmi); - - if (nmi >= NMI_INVALID) - return 0; + if (!strncmp(str, "lapic", 5)) + nmi_watchdog = NMI_LOCAL_APIC; + else if (!strncmp(str, "ioapic", 6)) + nmi_watchdog = NMI_IO_APIC; + else { + get_option(&str, &nmi); + if (nmi >= NMI_INVALID) + return 0; + nmi_watchdog = nmi; + } - nmi_watchdog = nmi; return 1; } __setup("nmi_watchdog=", setup_nmi_watchdog); @@ -285,11 +299,6 @@ void acpi_nmi_enable(void) on_each_cpu(__acpi_nmi_enable, NULL, 1); } -static void __acpi_nmi_disable(void *__unused) -{ - apic_write(APIC_LVT0, APIC_DM_NMI | APIC_LVT_MASKED); -} - /* * Disable timer based NMIs on all CPUs: */ @@ -340,6 +349,8 @@ void stop_apic_nmi_watchdog(void *unused) return; if (nmi_watchdog == NMI_LOCAL_APIC) lapic_watchdog_stop(); + else + __acpi_nmi_disable(NULL); __get_cpu_var(wd_enabled) = 0; atomic_dec(&nmi_active); } @@ -465,6 +476,24 @@ nmi_watchdog_tick(struct pt_regs *regs, unsigned reason) #ifdef CONFIG_SYSCTL +static void enable_ioapic_nmi_watchdog_single(void *unused) +{ + __get_cpu_var(wd_enabled) = 1; + atomic_inc(&nmi_active); + __acpi_nmi_enable(NULL); +} + +static void enable_ioapic_nmi_watchdog(void) +{ + on_each_cpu(enable_ioapic_nmi_watchdog_single, NULL, 1); + touch_nmi_watchdog(); +} + +static void disable_ioapic_nmi_watchdog(void) +{ + on_each_cpu(stop_apic_nmi_watchdog, NULL, 1); +} + static int __init setup_unknown_nmi_panic(char *str) { unknown_nmi_panic = 1; @@ -507,6 +536,11 @@ int proc_nmi_enabled(struct ctl_table *table, int write, struct file *file, enable_lapic_nmi_watchdog(); else disable_lapic_nmi_watchdog(); + } else if (nmi_watchdog == NMI_IO_APIC) { + if (nmi_watchdog_enabled) + enable_ioapic_nmi_watchdog(); + else + disable_ioapic_nmi_watchdog(); } else { printk(KERN_WARNING "NMI watchdog doesn't know what hardware to touch\n"); diff --git a/arch/x86/kernel/numaq_32.c b/arch/x86/kernel/numaq_32.c index 4caff39078e0d386a0f1d2783fbc7e081582d9a9..0deea37a53cf5613477a17d304a03f8bf254325f 100644 --- a/arch/x86/kernel/numaq_32.c +++ b/arch/x86/kernel/numaq_32.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include @@ -235,6 +235,13 @@ static int __init numaq_setup_ioapic_ids(void) return 1; } +static int __init numaq_update_genapic(void) +{ + genapic->wakeup_cpu = wakeup_secondary_cpu_via_nmi; + + return 0; +} + static struct x86_quirks numaq_x86_quirks __initdata = { .arch_pre_time_init = numaq_pre_time_init, .arch_time_init = NULL, @@ -250,6 +257,7 @@ static struct x86_quirks numaq_x86_quirks __initdata = { .mpc_oem_pci_bus = mpc_oem_pci_bus, .smp_read_mpc_oem = smp_read_mpc_oem, .setup_ioapic_ids = numaq_setup_ioapic_ids, + .update_genapic = numaq_update_genapic, }; void numaq_mps_oem_check(struct mp_config_table *mpc, char *oem, diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index 192624820217f9eeeb64ee39ada5ad57a76a0df5..7a3dfceb90e47a341295ca3f1201c232b5beb814 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -30,11 +31,6 @@ int no_iommu __read_mostly; /* Set this to 1 if there is a HW IOMMU in the system */ int iommu_detected __read_mostly = 0; -/* This tells the BIO block layer to assume merging. Default to off - because we cannot guarantee merging later. */ -int iommu_bio_merge __read_mostly = 0; -EXPORT_SYMBOL(iommu_bio_merge); - dma_addr_t bad_dma_address __read_mostly = 0; EXPORT_SYMBOL(bad_dma_address); @@ -188,7 +184,6 @@ static __init int iommu_setup(char *p) } if (!strncmp(p, "biomerge", 8)) { - iommu_bio_merge = 4096; iommu_merge = 1; force_iommu = 1; } @@ -300,8 +295,8 @@ fs_initcall(pci_iommu_init); static __devinit void via_no_dac(struct pci_dev *dev) { if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI && forbid_dac == 0) { - printk(KERN_INFO "PCI: VIA PCI bridge detected." - "Disabling DAC.\n"); + printk(KERN_INFO + "PCI: VIA PCI bridge detected. Disabling DAC.\n"); forbid_dac = 1; } } diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index c622772744d86fcb0dcd3e6c46a6de5323508c40..e68bb9e30864e50e764ce2581484f53aef0bfdda 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -1,13 +1,16 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include +#include unsigned long idle_halt; EXPORT_SYMBOL(idle_halt); @@ -100,6 +103,9 @@ static inline int hlt_use_halt(void) void default_idle(void) { if (hlt_use_halt()) { + struct power_trace it; + + trace_power_start(&it, POWER_CSTATE, 1); current_thread_info()->status &= ~TS_POLLING; /* * TS_POLLING-cleared state must be visible before we @@ -112,6 +118,7 @@ void default_idle(void) else local_irq_enable(); current_thread_info()->status |= TS_POLLING; + trace_power_end(&it); } else { local_irq_enable(); /* loop is done by the caller */ @@ -122,6 +129,21 @@ void default_idle(void) EXPORT_SYMBOL(default_idle); #endif +void stop_this_cpu(void *dummy) +{ + local_irq_disable(); + /* + * Remove this CPU: + */ + cpu_clear(smp_processor_id(), cpu_online_map); + disable_local_APIC(); + + for (;;) { + if (hlt_works(smp_processor_id())) + halt(); + } +} + static void do_nothing(void *unused) { } @@ -154,24 +176,31 @@ EXPORT_SYMBOL_GPL(cpu_idle_wait); */ void mwait_idle_with_hints(unsigned long ax, unsigned long cx) { + struct power_trace it; + + trace_power_start(&it, POWER_CSTATE, (ax>>4)+1); if (!need_resched()) { __monitor((void *)¤t_thread_info()->flags, 0, 0); smp_mb(); if (!need_resched()) __mwait(ax, cx); } + trace_power_end(&it); } /* Default MONITOR/MWAIT with no hints, used for default C1 state */ static void mwait_idle(void) { + struct power_trace it; if (!need_resched()) { + trace_power_start(&it, POWER_CSTATE, 1); __monitor((void *)¤t_thread_info()->flags, 0, 0); smp_mb(); if (!need_resched()) __sti_mwait(0, 0); else local_irq_enable(); + trace_power_end(&it); } else local_irq_enable(); } @@ -183,9 +212,13 @@ static void mwait_idle(void) */ static void poll_idle(void) { + struct power_trace it; + + trace_power_start(&it, POWER_CSTATE, 0); local_irq_enable(); while (!need_resched()) cpu_relax(); + trace_power_end(&it); } /* @@ -270,7 +303,7 @@ static void c1e_idle(void) rdmsr(MSR_K8_INT_PENDING_MSG, lo, hi); if (lo & K8_INTP_C1E_ACTIVE_MASK) { c1e_detected = 1; - if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC)) + if (!boot_cpu_has(X86_FEATURE_NONSTOP_TSC)) mark_tsc_unstable("TSC halt in AMD C1E"); printk(KERN_INFO "System has AMD C1E enabled\n"); set_cpu_cap(&boot_cpu_data, X86_FEATURE_AMDC1E); diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index 0a1302fe6d45307ffa880ed9e355050a194518af..3ba155d24884dd812790ff0e5aef8bb6767100d0 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -59,6 +60,7 @@ #include #include #include +#include asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); @@ -250,14 +252,8 @@ void exit_thread(void) tss->x86_tss.io_bitmap_base = INVALID_IO_BITMAP_OFFSET; put_cpu(); } -#ifdef CONFIG_X86_DS - /* Free any DS contexts that have not been properly released. */ - if (unlikely(current->thread.ds_ctx)) { - /* we clear debugctl to make sure DS is not used. */ - update_debugctlmsr(0); - ds_free(current->thread.ds_ctx); - } -#endif /* CONFIG_X86_DS */ + + ds_exit_thread(current); } void flush_thread(void) @@ -339,6 +335,12 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, kfree(p->thread.io_bitmap_ptr); p->thread.io_bitmap_max = 0; } + + ds_copy_thread(p, current); + + clear_tsk_thread_flag(p, TIF_DEBUGCTLMSR); + p->thread.debugctlmsr = 0; + return err; } @@ -419,48 +421,19 @@ int set_tsc_mode(unsigned int val) return 0; } -#ifdef CONFIG_X86_DS -static int update_debugctl(struct thread_struct *prev, - struct thread_struct *next, unsigned long debugctl) -{ - unsigned long ds_prev = 0; - unsigned long ds_next = 0; - - if (prev->ds_ctx) - ds_prev = (unsigned long)prev->ds_ctx->ds; - if (next->ds_ctx) - ds_next = (unsigned long)next->ds_ctx->ds; - - if (ds_next != ds_prev) { - /* we clear debugctl to make sure DS - * is not in use when we change it */ - debugctl = 0; - update_debugctlmsr(0); - wrmsr(MSR_IA32_DS_AREA, ds_next, 0); - } - return debugctl; -} -#else -static int update_debugctl(struct thread_struct *prev, - struct thread_struct *next, unsigned long debugctl) -{ - return debugctl; -} -#endif /* CONFIG_X86_DS */ - static noinline void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p, struct tss_struct *tss) { struct thread_struct *prev, *next; - unsigned long debugctl; prev = &prev_p->thread; next = &next_p->thread; - debugctl = update_debugctl(prev, next, prev->debugctlmsr); - - if (next->debugctlmsr != debugctl) + if (test_tsk_thread_flag(next_p, TIF_DS_AREA_MSR) || + test_tsk_thread_flag(prev_p, TIF_DS_AREA_MSR)) + ds_switch_to(prev_p, next_p); + else if (next->debugctlmsr != prev->debugctlmsr) update_debugctlmsr(next->debugctlmsr); if (test_tsk_thread_flag(next_p, TIF_DEBUG)) { @@ -482,15 +455,6 @@ __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p, hard_enable_TSC(); } -#ifdef CONFIG_X86_PTRACE_BTS - if (test_tsk_thread_flag(prev_p, TIF_BTS_TRACE_TS)) - ptrace_bts_take_timestamp(prev_p, BTS_TASK_DEPARTS); - - if (test_tsk_thread_flag(next_p, TIF_BTS_TRACE_TS)) - ptrace_bts_take_timestamp(next_p, BTS_TASK_ARRIVES); -#endif /* CONFIG_X86_PTRACE_BTS */ - - if (!test_tsk_thread_flag(next_p, TIF_IO_BITMAP)) { /* * Disable the bitmap via an invalid offset. We still cache @@ -548,7 +512,8 @@ __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p, * the task-switch, and shows up in ret_from_fork in entry.S, * for example. */ -struct task_struct * __switch_to(struct task_struct *prev_p, struct task_struct *next_p) +__notrace_funcgraph struct task_struct * +__switch_to(struct task_struct *prev_p, struct task_struct *next_p) { struct thread_struct *prev = &prev_p->thread, *next = &next_p->thread; diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index c958120fb1b6f549f853a79a26864abeb38ceb24..416fb9282f4fc73b666586d1964ca277f14f44cc 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -52,6 +53,7 @@ #include #include #include +#include asmlinkage extern void ret_from_fork(void); @@ -235,14 +237,8 @@ void exit_thread(void) t->io_bitmap_max = 0; put_cpu(); } -#ifdef CONFIG_X86_DS - /* Free any DS contexts that have not been properly released. */ - if (unlikely(t->ds_ctx)) { - /* we clear debugctl to make sure DS is not used. */ - update_debugctlmsr(0); - ds_free(t->ds_ctx); - } -#endif /* CONFIG_X86_DS */ + + ds_exit_thread(current); } void flush_thread(void) @@ -372,6 +368,12 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, if (err) goto out; } + + ds_copy_thread(p, me); + + clear_tsk_thread_flag(p, TIF_DEBUGCTLMSR); + p->thread.debugctlmsr = 0; + err = 0; out: if (err && p->thread.io_bitmap_ptr) { @@ -470,35 +472,14 @@ static inline void __switch_to_xtra(struct task_struct *prev_p, struct tss_struct *tss) { struct thread_struct *prev, *next; - unsigned long debugctl; prev = &prev_p->thread, next = &next_p->thread; - debugctl = prev->debugctlmsr; - -#ifdef CONFIG_X86_DS - { - unsigned long ds_prev = 0, ds_next = 0; - - if (prev->ds_ctx) - ds_prev = (unsigned long)prev->ds_ctx->ds; - if (next->ds_ctx) - ds_next = (unsigned long)next->ds_ctx->ds; - - if (ds_next != ds_prev) { - /* - * We clear debugctl to make sure DS - * is not in use when we change it: - */ - debugctl = 0; - update_debugctlmsr(0); - wrmsrl(MSR_IA32_DS_AREA, ds_next); - } - } -#endif /* CONFIG_X86_DS */ - - if (next->debugctlmsr != debugctl) + if (test_tsk_thread_flag(next_p, TIF_DS_AREA_MSR) || + test_tsk_thread_flag(prev_p, TIF_DS_AREA_MSR)) + ds_switch_to(prev_p, next_p); + else if (next->debugctlmsr != prev->debugctlmsr) update_debugctlmsr(next->debugctlmsr); if (test_tsk_thread_flag(next_p, TIF_DEBUG)) { @@ -533,14 +514,6 @@ static inline void __switch_to_xtra(struct task_struct *prev_p, */ memset(tss->io_bitmap, 0xff, prev->io_bitmap_max); } - -#ifdef CONFIG_X86_PTRACE_BTS - if (test_tsk_thread_flag(prev_p, TIF_BTS_TRACE_TS)) - ptrace_bts_take_timestamp(prev_p, BTS_TASK_DEPARTS); - - if (test_tsk_thread_flag(next_p, TIF_BTS_TRACE_TS)) - ptrace_bts_take_timestamp(next_p, BTS_TASK_ARRIVES); -#endif /* CONFIG_X86_PTRACE_BTS */ } /* @@ -551,8 +524,9 @@ static inline void __switch_to_xtra(struct task_struct *prev_p, * - could test fs/gs bitsliced * * Kprobes not supported here. Set the probe on schedule instead. + * Function graph tracer not supported too. */ -struct task_struct * +__notrace_funcgraph struct task_struct * __switch_to(struct task_struct *prev_p, struct task_struct *next_p) { struct thread_struct *prev = &prev_p->thread; diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 0a6d8c12e10dc7742c2e33dd29475874cb9f2b50..0a5df5f82fb9579b1be4e824aa499ac561d9ba10 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c @@ -581,158 +581,91 @@ static int ioperm_get(struct task_struct *target, } #ifdef CONFIG_X86_PTRACE_BTS -/* - * The configuration for a particular BTS hardware implementation. - */ -struct bts_configuration { - /* the size of a BTS record in bytes; at most BTS_MAX_RECORD_SIZE */ - unsigned char sizeof_bts; - /* the size of a field in the BTS record in bytes */ - unsigned char sizeof_field; - /* a bitmask to enable/disable BTS in DEBUGCTL MSR */ - unsigned long debugctl_mask; -}; -static struct bts_configuration bts_cfg; - -#define BTS_MAX_RECORD_SIZE (8 * 3) - - -/* - * Branch Trace Store (BTS) uses the following format. Different - * architectures vary in the size of those fields. - * - source linear address - * - destination linear address - * - flags - * - * Later architectures use 64bit pointers throughout, whereas earlier - * architectures use 32bit pointers in 32bit mode. - * - * We compute the base address for the first 8 fields based on: - * - the field size stored in the DS configuration - * - the relative field position - * - * In order to store additional information in the BTS buffer, we use - * a special source address to indicate that the record requires - * special interpretation. - * - * Netburst indicated via a bit in the flags field whether the branch - * was predicted; this is ignored. - */ - -enum bts_field { - bts_from = 0, - bts_to, - bts_flags, - - bts_escape = (unsigned long)-1, - bts_qual = bts_to, - bts_jiffies = bts_flags -}; - -static inline unsigned long bts_get(const char *base, enum bts_field field) -{ - base += (bts_cfg.sizeof_field * field); - return *(unsigned long *)base; -} - -static inline void bts_set(char *base, enum bts_field field, unsigned long val) -{ - base += (bts_cfg.sizeof_field * field);; - (*(unsigned long *)base) = val; -} - -/* - * Translate a BTS record from the raw format into the bts_struct format - * - * out (out): bts_struct interpretation - * raw: raw BTS record - */ -static void ptrace_bts_translate_record(struct bts_struct *out, const void *raw) -{ - memset(out, 0, sizeof(*out)); - if (bts_get(raw, bts_from) == bts_escape) { - out->qualifier = bts_get(raw, bts_qual); - out->variant.jiffies = bts_get(raw, bts_jiffies); - } else { - out->qualifier = BTS_BRANCH; - out->variant.lbr.from_ip = bts_get(raw, bts_from); - out->variant.lbr.to_ip = bts_get(raw, bts_to); - } -} - static int ptrace_bts_read_record(struct task_struct *child, size_t index, struct bts_struct __user *out) { - struct bts_struct ret; - const void *bts_record; - size_t bts_index, bts_end; + const struct bts_trace *trace; + struct bts_struct bts; + const unsigned char *at; int error; - error = ds_get_bts_end(child, &bts_end); - if (error < 0) - return error; - - if (bts_end <= index) - return -EINVAL; + trace = ds_read_bts(child->bts); + if (!trace) + return -EPERM; - error = ds_get_bts_index(child, &bts_index); - if (error < 0) - return error; + at = trace->ds.top - ((index + 1) * trace->ds.size); + if ((void *)at < trace->ds.begin) + at += (trace->ds.n * trace->ds.size); - /* translate the ptrace bts index into the ds bts index */ - bts_index += bts_end - (index + 1); - if (bts_end <= bts_index) - bts_index -= bts_end; + if (!trace->read) + return -EOPNOTSUPP; - error = ds_access_bts(child, bts_index, &bts_record); + error = trace->read(child->bts, at, &bts); if (error < 0) return error; - ptrace_bts_translate_record(&ret, bts_record); - - if (copy_to_user(out, &ret, sizeof(ret))) + if (copy_to_user(out, &bts, sizeof(bts))) return -EFAULT; - return sizeof(ret); + return sizeof(bts); } static int ptrace_bts_drain(struct task_struct *child, long size, struct bts_struct __user *out) { - struct bts_struct ret; - const unsigned char *raw; - size_t end, i; - int error; + const struct bts_trace *trace; + const unsigned char *at; + int error, drained = 0; - error = ds_get_bts_index(child, &end); - if (error < 0) - return error; + trace = ds_read_bts(child->bts); + if (!trace) + return -EPERM; - if (size < (end * sizeof(struct bts_struct))) + if (!trace->read) + return -EOPNOTSUPP; + + if (size < (trace->ds.top - trace->ds.begin)) return -EIO; - error = ds_access_bts(child, 0, (const void **)&raw); - if (error < 0) - return error; + for (at = trace->ds.begin; (void *)at < trace->ds.top; + out++, drained++, at += trace->ds.size) { + struct bts_struct bts; + int error; - for (i = 0; i < end; i++, out++, raw += bts_cfg.sizeof_bts) { - ptrace_bts_translate_record(&ret, raw); + error = trace->read(child->bts, at, &bts); + if (error < 0) + return error; - if (copy_to_user(out, &ret, sizeof(ret))) + if (copy_to_user(out, &bts, sizeof(bts))) return -EFAULT; } - error = ds_clear_bts(child); + memset(trace->ds.begin, 0, trace->ds.n * trace->ds.size); + + error = ds_reset_bts(child->bts); if (error < 0) return error; - return end; + return drained; } -static void ptrace_bts_ovfl(struct task_struct *child) +static int ptrace_bts_allocate_buffer(struct task_struct *child, size_t size) { - send_sig(child->thread.bts_ovfl_signal, child, 0); + child->bts_buffer = alloc_locked_buffer(size); + if (!child->bts_buffer) + return -ENOMEM; + + child->bts_size = size; + + return 0; +} + +static void ptrace_bts_free_buffer(struct task_struct *child) +{ + free_locked_buffer(child->bts_buffer, child->bts_size); + child->bts_buffer = NULL; + child->bts_size = 0; } static int ptrace_bts_config(struct task_struct *child, @@ -740,114 +673,86 @@ static int ptrace_bts_config(struct task_struct *child, const struct ptrace_bts_config __user *ucfg) { struct ptrace_bts_config cfg; - int error = 0; - - error = -EOPNOTSUPP; - if (!bts_cfg.sizeof_bts) - goto errout; + unsigned int flags = 0; - error = -EIO; if (cfg_size < sizeof(cfg)) - goto errout; + return -EIO; - error = -EFAULT; if (copy_from_user(&cfg, ucfg, sizeof(cfg))) - goto errout; + return -EFAULT; - error = -EINVAL; - if ((cfg.flags & PTRACE_BTS_O_SIGNAL) && - !(cfg.flags & PTRACE_BTS_O_ALLOC)) - goto errout; + if (child->bts) { + ds_release_bts(child->bts); + child->bts = NULL; + } - if (cfg.flags & PTRACE_BTS_O_ALLOC) { - ds_ovfl_callback_t ovfl = NULL; - unsigned int sig = 0; + if (cfg.flags & PTRACE_BTS_O_SIGNAL) { + if (!cfg.signal) + return -EINVAL; - /* we ignore the error in case we were not tracing child */ - (void)ds_release_bts(child); + return -EOPNOTSUPP; - if (cfg.flags & PTRACE_BTS_O_SIGNAL) { - if (!cfg.signal) - goto errout; + child->thread.bts_ovfl_signal = cfg.signal; + } - sig = cfg.signal; - ovfl = ptrace_bts_ovfl; - } + if ((cfg.flags & PTRACE_BTS_O_ALLOC) && + (cfg.size != child->bts_size)) { + int error; - error = ds_request_bts(child, /* base = */ NULL, cfg.size, ovfl); - if (error < 0) - goto errout; + ptrace_bts_free_buffer(child); - child->thread.bts_ovfl_signal = sig; + error = ptrace_bts_allocate_buffer(child, cfg.size); + if (error < 0) + return error; } - error = -EINVAL; - if (!child->thread.ds_ctx && cfg.flags) - goto errout; - if (cfg.flags & PTRACE_BTS_O_TRACE) - child->thread.debugctlmsr |= bts_cfg.debugctl_mask; - else - child->thread.debugctlmsr &= ~bts_cfg.debugctl_mask; + flags |= BTS_USER; if (cfg.flags & PTRACE_BTS_O_SCHED) - set_tsk_thread_flag(child, TIF_BTS_TRACE_TS); - else - clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS); + flags |= BTS_TIMESTAMPS; - error = sizeof(cfg); + child->bts = ds_request_bts(child, child->bts_buffer, child->bts_size, + /* ovfl = */ NULL, /* th = */ (size_t)-1, + flags); + if (IS_ERR(child->bts)) { + int error = PTR_ERR(child->bts); -out: - if (child->thread.debugctlmsr) - set_tsk_thread_flag(child, TIF_DEBUGCTLMSR); - else - clear_tsk_thread_flag(child, TIF_DEBUGCTLMSR); + ptrace_bts_free_buffer(child); + child->bts = NULL; - return error; + return error; + } -errout: - child->thread.debugctlmsr &= ~bts_cfg.debugctl_mask; - clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS); - goto out; + return sizeof(cfg); } static int ptrace_bts_status(struct task_struct *child, long cfg_size, struct ptrace_bts_config __user *ucfg) { + const struct bts_trace *trace; struct ptrace_bts_config cfg; - size_t end; - const void *base, *max; - int error; if (cfg_size < sizeof(cfg)) return -EIO; - error = ds_get_bts_end(child, &end); - if (error < 0) - return error; - - error = ds_access_bts(child, /* index = */ 0, &base); - if (error < 0) - return error; - - error = ds_access_bts(child, /* index = */ end, &max); - if (error < 0) - return error; + trace = ds_read_bts(child->bts); + if (!trace) + return -EPERM; memset(&cfg, 0, sizeof(cfg)); - cfg.size = (max - base); + cfg.size = trace->ds.end - trace->ds.begin; cfg.signal = child->thread.bts_ovfl_signal; cfg.bts_size = sizeof(struct bts_struct); if (cfg.signal) cfg.flags |= PTRACE_BTS_O_SIGNAL; - if (test_tsk_thread_flag(child, TIF_DEBUGCTLMSR) && - child->thread.debugctlmsr & bts_cfg.debugctl_mask) + if (trace->ds.flags & BTS_USER) cfg.flags |= PTRACE_BTS_O_TRACE; - if (test_tsk_thread_flag(child, TIF_BTS_TRACE_TS)) + if (trace->ds.flags & BTS_TIMESTAMPS) cfg.flags |= PTRACE_BTS_O_SCHED; if (copy_to_user(ucfg, &cfg, sizeof(cfg))) @@ -856,110 +761,77 @@ static int ptrace_bts_status(struct task_struct *child, return sizeof(cfg); } -static int ptrace_bts_write_record(struct task_struct *child, - const struct bts_struct *in) +static int ptrace_bts_clear(struct task_struct *child) { - unsigned char bts_record[BTS_MAX_RECORD_SIZE]; + const struct bts_trace *trace; - BUG_ON(BTS_MAX_RECORD_SIZE < bts_cfg.sizeof_bts); + trace = ds_read_bts(child->bts); + if (!trace) + return -EPERM; - memset(bts_record, 0, bts_cfg.sizeof_bts); - switch (in->qualifier) { - case BTS_INVALID: - break; + memset(trace->ds.begin, 0, trace->ds.n * trace->ds.size); - case BTS_BRANCH: - bts_set(bts_record, bts_from, in->variant.lbr.from_ip); - bts_set(bts_record, bts_to, in->variant.lbr.to_ip); - break; + return ds_reset_bts(child->bts); +} - case BTS_TASK_ARRIVES: - case BTS_TASK_DEPARTS: - bts_set(bts_record, bts_from, bts_escape); - bts_set(bts_record, bts_qual, in->qualifier); - bts_set(bts_record, bts_jiffies, in->variant.jiffies); - break; +static int ptrace_bts_size(struct task_struct *child) +{ + const struct bts_trace *trace; - default: - return -EINVAL; - } + trace = ds_read_bts(child->bts); + if (!trace) + return -EPERM; - /* The writing task will be the switched-to task on a context - * switch. It needs to write into the switched-from task's BTS - * buffer. */ - return ds_unchecked_write_bts(child, bts_record, bts_cfg.sizeof_bts); + return (trace->ds.top - trace->ds.begin) / trace->ds.size; } -void ptrace_bts_take_timestamp(struct task_struct *tsk, - enum bts_qualifier qualifier) +static void ptrace_bts_fork(struct task_struct *tsk) { - struct bts_struct rec = { - .qualifier = qualifier, - .variant.jiffies = jiffies_64 - }; - - ptrace_bts_write_record(tsk, &rec); + tsk->bts = NULL; + tsk->bts_buffer = NULL; + tsk->bts_size = 0; + tsk->thread.bts_ovfl_signal = 0; } -static const struct bts_configuration bts_cfg_netburst = { - .sizeof_bts = sizeof(long) * 3, - .sizeof_field = sizeof(long), - .debugctl_mask = (1<<2)|(1<<3)|(1<<5) -}; +static void ptrace_bts_untrace(struct task_struct *child) +{ + if (unlikely(child->bts)) { + ds_release_bts(child->bts); + child->bts = NULL; + + /* We cannot update total_vm and locked_vm since + child's mm is already gone. But we can reclaim the + memory. */ + kfree(child->bts_buffer); + child->bts_buffer = NULL; + child->bts_size = 0; + } +} -static const struct bts_configuration bts_cfg_pentium_m = { - .sizeof_bts = sizeof(long) * 3, - .sizeof_field = sizeof(long), - .debugctl_mask = (1<<6)|(1<<7) -}; +static void ptrace_bts_detach(struct task_struct *child) +{ + if (unlikely(child->bts)) { + ds_release_bts(child->bts); + child->bts = NULL; -static const struct bts_configuration bts_cfg_core2 = { - .sizeof_bts = 8 * 3, - .sizeof_field = 8, - .debugctl_mask = (1<<6)|(1<<7)|(1<<9) -}; + ptrace_bts_free_buffer(child); + } +} +#else +static inline void ptrace_bts_fork(struct task_struct *tsk) {} +static inline void ptrace_bts_detach(struct task_struct *child) {} +static inline void ptrace_bts_untrace(struct task_struct *child) {} +#endif /* CONFIG_X86_PTRACE_BTS */ -static inline void bts_configure(const struct bts_configuration *cfg) +void x86_ptrace_fork(struct task_struct *child, unsigned long clone_flags) { - bts_cfg = *cfg; + ptrace_bts_fork(child); } -void __cpuinit ptrace_bts_init_intel(struct cpuinfo_x86 *c) +void x86_ptrace_untrace(struct task_struct *child) { - switch (c->x86) { - case 0x6: - switch (c->x86_model) { - case 0xD: - case 0xE: /* Pentium M */ - bts_configure(&bts_cfg_pentium_m); - break; - case 0xF: /* Core2 */ - case 0x1C: /* Atom */ - bts_configure(&bts_cfg_core2); - break; - default: - /* sorry, don't know about them */ - break; - } - break; - case 0xF: - switch (c->x86_model) { - case 0x0: - case 0x1: - case 0x2: /* Netburst */ - bts_configure(&bts_cfg_netburst); - break; - default: - /* sorry, don't know about them */ - break; - } - break; - default: - /* sorry, don't know about them */ - break; - } + ptrace_bts_untrace(child); } -#endif /* CONFIG_X86_PTRACE_BTS */ /* * Called by kernel/ptrace.c when detaching.. @@ -972,15 +844,7 @@ void ptrace_disable(struct task_struct *child) #ifdef TIF_SYSCALL_EMU clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); #endif -#ifdef CONFIG_X86_PTRACE_BTS - (void)ds_release_bts(child); - - child->thread.debugctlmsr &= ~bts_cfg.debugctl_mask; - if (!child->thread.debugctlmsr) - clear_tsk_thread_flag(child, TIF_DEBUGCTLMSR); - - clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS); -#endif /* CONFIG_X86_PTRACE_BTS */ + ptrace_bts_detach(child); } #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION @@ -1112,7 +976,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) break; case PTRACE_BTS_SIZE: - ret = ds_get_bts_index(child, /* pos = */ NULL); + ret = ptrace_bts_size(child); break; case PTRACE_BTS_GET: @@ -1121,7 +985,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) break; case PTRACE_BTS_CLEAR: - ret = ds_clear_bts(child); + ret = ptrace_bts_clear(child); break; case PTRACE_BTS_DRAIN: @@ -1384,6 +1248,14 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, case PTRACE_GET_THREAD_AREA: case PTRACE_SET_THREAD_AREA: +#ifdef CONFIG_X86_PTRACE_BTS + case PTRACE_BTS_CONFIG: + case PTRACE_BTS_STATUS: + case PTRACE_BTS_SIZE: + case PTRACE_BTS_GET: + case PTRACE_BTS_CLEAR: + case PTRACE_BTS_DRAIN: +#endif /* CONFIG_X86_PTRACE_BTS */ return arch_ptrace(child, request, addr, data); default: diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index cc5a2545dd41c0ce42b96eafffe85230773162e4..61f718df6eec1fe74dffaa2cb3b110b1deaeb70b 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -21,6 +21,9 @@ # include #endif +#include + + /* * Power off function, if any */ @@ -36,7 +39,10 @@ int reboot_force; static int reboot_cpu = -1; #endif -/* reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] +/* This is set by the PCI code if either type 1 or type 2 PCI is detected */ +bool port_cf9_safe = false; + +/* reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | p[ci] warm Don't set the cold reboot flag cold Set the cold reboot flag bios Reboot by jumping through the BIOS (only for X86_32) @@ -45,6 +51,7 @@ static int reboot_cpu = -1; kbd Use the keyboard controller. cold reset (default) acpi Use the RESET_REG in the FADT efi Use efi reset_system runtime service + pci Use the so-called "PCI reset register", CF9 force Avoid anything that could hang. */ static int __init reboot_setup(char *str) @@ -79,6 +86,7 @@ static int __init reboot_setup(char *str) case 'k': case 't': case 'e': + case 'p': reboot_type = *str; break; @@ -404,12 +412,27 @@ static void native_machine_emergency_restart(void) reboot_type = BOOT_KBD; break; - case BOOT_EFI: if (efi_enabled) - efi.reset_system(reboot_mode ? EFI_RESET_WARM : EFI_RESET_COLD, + efi.reset_system(reboot_mode ? + EFI_RESET_WARM : + EFI_RESET_COLD, EFI_SUCCESS, 0, NULL); + reboot_type = BOOT_KBD; + break; + case BOOT_CF9: + port_cf9_safe = true; + /* fall through */ + + case BOOT_CF9_COND: + if (port_cf9_safe) { + u8 cf9 = inb(0xcf9) & ~6; + outb(cf9|2, 0xcf9); /* Request hard reset */ + udelay(50); + outb(cf9|6, 0xcf9); /* Actually do the reset */ + udelay(50); + } reboot_type = BOOT_KBD; break; } @@ -470,6 +493,11 @@ static void native_machine_restart(char *__unused) static void native_machine_halt(void) { + /* stop other cpus and apics */ + machine_shutdown(); + + /* stop this cpu */ + stop_this_cpu(NULL); } static void native_machine_power_off(void) @@ -523,3 +551,95 @@ void machine_crash_shutdown(struct pt_regs *regs) machine_ops.crash_shutdown(regs); } #endif + + +#if defined(CONFIG_SMP) + +/* This keeps a track of which one is crashing cpu. */ +static int crashing_cpu; +static nmi_shootdown_cb shootdown_callback; + +static atomic_t waiting_for_crash_ipi; + +static int crash_nmi_callback(struct notifier_block *self, + unsigned long val, void *data) +{ + int cpu; + + if (val != DIE_NMI_IPI) + return NOTIFY_OK; + + cpu = raw_smp_processor_id(); + + /* Don't do anything if this handler is invoked on crashing cpu. + * Otherwise, system will completely hang. Crashing cpu can get + * an NMI if system was initially booted with nmi_watchdog parameter. + */ + if (cpu == crashing_cpu) + return NOTIFY_STOP; + local_irq_disable(); + + shootdown_callback(cpu, (struct die_args *)data); + + atomic_dec(&waiting_for_crash_ipi); + /* Assume hlt works */ + halt(); + for (;;) + cpu_relax(); + + return 1; +} + +static void smp_send_nmi_allbutself(void) +{ + cpumask_t mask = cpu_online_map; + cpu_clear(safe_smp_processor_id(), mask); + if (!cpus_empty(mask)) + send_IPI_mask(mask, NMI_VECTOR); +} + +static struct notifier_block crash_nmi_nb = { + .notifier_call = crash_nmi_callback, +}; + +/* Halt all other CPUs, calling the specified function on each of them + * + * This function can be used to halt all other CPUs on crash + * or emergency reboot time. The function passed as parameter + * will be called inside a NMI handler on all CPUs. + */ +void nmi_shootdown_cpus(nmi_shootdown_cb callback) +{ + unsigned long msecs; + local_irq_disable(); + + /* Make a note of crashing cpu. Will be used in NMI callback.*/ + crashing_cpu = safe_smp_processor_id(); + + shootdown_callback = callback; + + atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); + /* Would it be better to replace the trap vector here? */ + if (register_die_notifier(&crash_nmi_nb)) + return; /* return what? */ + /* Ensure the new callback function is set before sending + * out the NMI + */ + wmb(); + + smp_send_nmi_allbutself(); + + msecs = 1000; /* Wait at most a second for the other cpus to stop */ + while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) { + mdelay(1); + msecs--; + } + + /* Leave the nmi callback set */ +} +#else /* !CONFIG_SMP */ +void nmi_shootdown_cpus(nmi_shootdown_cb callback) +{ + /* No other CPUs to shoot down */ +} +#endif diff --git a/arch/x86/kernel/relocate_kernel_32.S b/arch/x86/kernel/relocate_kernel_32.S index 6f50664b2ba50564dfbf10c017f52bcc247a9af8..a160f31197256680c32b835b7c32d62e9dbd184b 100644 --- a/arch/x86/kernel/relocate_kernel_32.S +++ b/arch/x86/kernel/relocate_kernel_32.S @@ -10,15 +10,12 @@ #include #include #include -#include /* * Must be relocatable PIC code callable as a C function */ #define PTR(x) (x << 2) -#define PAGE_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY) -#define PAE_PGD_ATTR (_PAGE_PRESENT) /* control_page + KEXEC_CONTROL_CODE_MAX_SIZE * ~ control_page + PAGE_SIZE are used as data storage and stack for @@ -39,7 +36,6 @@ #define CP_PA_BACKUP_PAGES_MAP DATA(0x1c) .text - .align PAGE_SIZE .globl relocate_kernel relocate_kernel: /* Save the CPU context, used for jumping back */ @@ -60,117 +56,6 @@ relocate_kernel: movl %cr4, %eax movl %eax, CR4(%edi) -#ifdef CONFIG_X86_PAE - /* map the control page at its virtual address */ - - movl PTR(VA_PGD)(%ebp), %edi - movl PTR(VA_CONTROL_PAGE)(%ebp), %eax - andl $0xc0000000, %eax - shrl $27, %eax - addl %edi, %eax - - movl PTR(PA_PMD_0)(%ebp), %edx - orl $PAE_PGD_ATTR, %edx - movl %edx, (%eax) - - movl PTR(VA_PMD_0)(%ebp), %edi - movl PTR(VA_CONTROL_PAGE)(%ebp), %eax - andl $0x3fe00000, %eax - shrl $18, %eax - addl %edi, %eax - - movl PTR(PA_PTE_0)(%ebp), %edx - orl $PAGE_ATTR, %edx - movl %edx, (%eax) - - movl PTR(VA_PTE_0)(%ebp), %edi - movl PTR(VA_CONTROL_PAGE)(%ebp), %eax - andl $0x001ff000, %eax - shrl $9, %eax - addl %edi, %eax - - movl PTR(PA_CONTROL_PAGE)(%ebp), %edx - orl $PAGE_ATTR, %edx - movl %edx, (%eax) - - /* identity map the control page at its physical address */ - - movl PTR(VA_PGD)(%ebp), %edi - movl PTR(PA_CONTROL_PAGE)(%ebp), %eax - andl $0xc0000000, %eax - shrl $27, %eax - addl %edi, %eax - - movl PTR(PA_PMD_1)(%ebp), %edx - orl $PAE_PGD_ATTR, %edx - movl %edx, (%eax) - - movl PTR(VA_PMD_1)(%ebp), %edi - movl PTR(PA_CONTROL_PAGE)(%ebp), %eax - andl $0x3fe00000, %eax - shrl $18, %eax - addl %edi, %eax - - movl PTR(PA_PTE_1)(%ebp), %edx - orl $PAGE_ATTR, %edx - movl %edx, (%eax) - - movl PTR(VA_PTE_1)(%ebp), %edi - movl PTR(PA_CONTROL_PAGE)(%ebp), %eax - andl $0x001ff000, %eax - shrl $9, %eax - addl %edi, %eax - - movl PTR(PA_CONTROL_PAGE)(%ebp), %edx - orl $PAGE_ATTR, %edx - movl %edx, (%eax) -#else - /* map the control page at its virtual address */ - - movl PTR(VA_PGD)(%ebp), %edi - movl PTR(VA_CONTROL_PAGE)(%ebp), %eax - andl $0xffc00000, %eax - shrl $20, %eax - addl %edi, %eax - - movl PTR(PA_PTE_0)(%ebp), %edx - orl $PAGE_ATTR, %edx - movl %edx, (%eax) - - movl PTR(VA_PTE_0)(%ebp), %edi - movl PTR(VA_CONTROL_PAGE)(%ebp), %eax - andl $0x003ff000, %eax - shrl $10, %eax - addl %edi, %eax - - movl PTR(PA_CONTROL_PAGE)(%ebp), %edx - orl $PAGE_ATTR, %edx - movl %edx, (%eax) - - /* identity map the control page at its physical address */ - - movl PTR(VA_PGD)(%ebp), %edi - movl PTR(PA_CONTROL_PAGE)(%ebp), %eax - andl $0xffc00000, %eax - shrl $20, %eax - addl %edi, %eax - - movl PTR(PA_PTE_1)(%ebp), %edx - orl $PAGE_ATTR, %edx - movl %edx, (%eax) - - movl PTR(VA_PTE_1)(%ebp), %edi - movl PTR(PA_CONTROL_PAGE)(%ebp), %eax - andl $0x003ff000, %eax - shrl $10, %eax - addl %edi, %eax - - movl PTR(PA_CONTROL_PAGE)(%ebp), %edx - orl $PAGE_ATTR, %edx - movl %edx, (%eax) -#endif - -relocate_new_kernel: /* read the arguments and say goodbye to the stack */ movl 20+4(%esp), %ebx /* page_list */ movl 20+8(%esp), %ebp /* list of pages */ diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index bdec76e5559433d77366b85535f0563451614501..08e02e8453c9a147d838daab9c21421708d22350 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -93,11 +93,13 @@ #include #include #include +#include #include #include #include #include +#include #include #include @@ -448,6 +450,7 @@ static void __init reserve_early_setup_data(void) * @size: Size of the crashkernel memory to reserve. * Returns the base address on success, and -1ULL on failure. */ +static unsigned long long __init find_and_reserve_crashkernel(unsigned long long size) { const unsigned long long alignment = 16<<20; /* 16M */ @@ -583,161 +586,24 @@ static int __init setup_elfcorehdr(char *arg) early_param("elfcorehdr", setup_elfcorehdr); #endif -static struct x86_quirks default_x86_quirks __initdata; - -struct x86_quirks *x86_quirks __initdata = &default_x86_quirks; - -/* - * Some BIOSes seem to corrupt the low 64k of memory during events - * like suspend/resume and unplugging an HDMI cable. Reserve all - * remaining free memory in that area and fill it with a distinct - * pattern. - */ -#ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION -#define MAX_SCAN_AREAS 8 - -static int __read_mostly memory_corruption_check = -1; - -static unsigned __read_mostly corruption_check_size = 64*1024; -static unsigned __read_mostly corruption_check_period = 60; /* seconds */ - -static struct e820entry scan_areas[MAX_SCAN_AREAS]; -static int num_scan_areas; - - -static int set_corruption_check(char *arg) -{ - char *end; - - memory_corruption_check = simple_strtol(arg, &end, 10); - - return (*end == 0) ? 0 : -EINVAL; -} -early_param("memory_corruption_check", set_corruption_check); - -static int set_corruption_check_period(char *arg) -{ - char *end; - - corruption_check_period = simple_strtoul(arg, &end, 10); - - return (*end == 0) ? 0 : -EINVAL; -} -early_param("memory_corruption_check_period", set_corruption_check_period); - -static int set_corruption_check_size(char *arg) +static int __init default_update_genapic(void) { - char *end; - unsigned size; - - size = memparse(arg, &end); - - if (*end == '\0') - corruption_check_size = size; - - return (size == corruption_check_size) ? 0 : -EINVAL; -} -early_param("memory_corruption_check_size", set_corruption_check_size); - - -static void __init setup_bios_corruption_check(void) -{ - u64 addr = PAGE_SIZE; /* assume first page is reserved anyway */ - - if (memory_corruption_check == -1) { - memory_corruption_check = -#ifdef CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK - 1 -#else - 0 +#ifdef CONFIG_X86_SMP +# if defined(CONFIG_X86_GENERICARCH) || defined(CONFIG_X86_64) + genapic->wakeup_cpu = wakeup_secondary_cpu_via_init; +# endif #endif - ; - } - - if (corruption_check_size == 0) - memory_corruption_check = 0; - - if (!memory_corruption_check) - return; - - corruption_check_size = round_up(corruption_check_size, PAGE_SIZE); - while(addr < corruption_check_size && num_scan_areas < MAX_SCAN_AREAS) { - u64 size; - addr = find_e820_area_size(addr, &size, PAGE_SIZE); - - if (addr == 0) - break; - - if ((addr + size) > corruption_check_size) - size = corruption_check_size - addr; - - if (size == 0) - break; - - e820_update_range(addr, size, E820_RAM, E820_RESERVED); - scan_areas[num_scan_areas].addr = addr; - scan_areas[num_scan_areas].size = size; - num_scan_areas++; - - /* Assume we've already mapped this early memory */ - memset(__va(addr), 0, size); - - addr += size; - } - - printk(KERN_INFO "Scanning %d areas for low memory corruption\n", - num_scan_areas); - update_e820(); -} - -static struct timer_list periodic_check_timer; - -void check_for_bios_corruption(void) -{ - int i; - int corruption = 0; - - if (!memory_corruption_check) - return; - - for(i = 0; i < num_scan_areas; i++) { - unsigned long *addr = __va(scan_areas[i].addr); - unsigned long size = scan_areas[i].size; - - for(; size; addr++, size -= sizeof(unsigned long)) { - if (!*addr) - continue; - printk(KERN_ERR "Corrupted low memory at %p (%lx phys) = %08lx\n", - addr, __pa(addr), *addr); - corruption = 1; - *addr = 0; - } - } - - WARN(corruption, KERN_ERR "Memory corruption detected in low memory\n"); -} - -static void periodic_check_for_corruption(unsigned long data) -{ - check_for_bios_corruption(); - mod_timer(&periodic_check_timer, round_jiffies(jiffies + corruption_check_period*HZ)); + return 0; } -void start_periodic_check_for_corruption(void) -{ - if (!memory_corruption_check || corruption_check_period == 0) - return; - - printk(KERN_INFO "Scanning for low memory corruption every %d seconds\n", - corruption_check_period); +static struct x86_quirks default_x86_quirks __initdata = { + .update_genapic = default_update_genapic, +}; - init_timer(&periodic_check_timer); - periodic_check_timer.function = &periodic_check_for_corruption; - periodic_check_for_corruption(0); -} -#endif +struct x86_quirks *x86_quirks __initdata = &default_x86_quirks; +#ifdef CONFIG_X86_RESERVE_LOW_64K static int __init dmi_low_memory_corruption(const struct dmi_system_id *d) { printk(KERN_NOTICE @@ -749,6 +615,7 @@ static int __init dmi_low_memory_corruption(const struct dmi_system_id *d) return 0; } +#endif /* List of systems that have known low memory corruption BIOS problems */ static struct dmi_system_id __initdata bad_bios_dmi_table[] = { @@ -907,6 +774,12 @@ void __init setup_arch(char **cmdline_p) dmi_check_system(bad_bios_dmi_table); + /* + * VMware detection requires dmi to be available, so this + * needs to be done after dmi_scan_machine, for the BP. + */ + init_hypervisor(&boot_cpu_data); + #ifdef CONFIG_X86_32 probe_roms(); #endif diff --git a/arch/x86/kernel/sigframe.h b/arch/x86/kernel/sigframe.h deleted file mode 100644 index cc673aa55ce4d8fb7eeb82e8cd21a773ca8f6213..0000000000000000000000000000000000000000 --- a/arch/x86/kernel/sigframe.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifdef CONFIG_X86_32 -struct sigframe { - char __user *pretcode; - int sig; - struct sigcontext sc; - /* - * fpstate is unused. fpstate is moved/allocated after - * retcode[] below. This movement allows to have the FP state and the - * future state extensions (xsave) stay together. - * And at the same time retaining the unused fpstate, prevents changing - * the offset of extramask[] in the sigframe and thus prevent any - * legacy application accessing/modifying it. - */ - struct _fpstate fpstate_unused; - unsigned long extramask[_NSIG_WORDS-1]; - char retcode[8]; - /* fp state follows here */ -}; - -struct rt_sigframe { - char __user *pretcode; - int sig; - struct siginfo __user *pinfo; - void __user *puc; - struct siginfo info; - struct ucontext uc; - char retcode[8]; - /* fp state follows here */ -}; -#else -struct rt_sigframe { - char __user *pretcode; - struct ucontext uc; - struct siginfo info; - /* fp state follows here */ -}; - -int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, - sigset_t *set, struct pt_regs *regs); -int ia32_setup_frame(int sig, struct k_sigaction *ka, - sigset_t *set, struct pt_regs *regs); -#endif diff --git a/arch/x86/kernel/signal_32.c b/arch/x86/kernel/signal.c similarity index 73% rename from arch/x86/kernel/signal_32.c rename to arch/x86/kernel/signal.c index d6dd057d0f2210784023ee1c591ed4f660e837e2..89bb7668041d63067c1a2b3fd1210ab9ccfcb49d 100644 --- a/arch/x86/kernel/signal_32.c +++ b/arch/x86/kernel/signal.c @@ -1,36 +1,41 @@ /* * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright (C) 2000, 2001, 2002 Andi Kleen SuSE Labs * * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson * 2000-06-20 Pentium III FXSR, SSE support by Gareth Hughes + * 2000-2002 x86-64 support by Andi Kleen */ -#include -#include -#include -#include +#include +#include +#include #include -#include #include -#include -#include #include -#include #include +#include #include -#include -#include -#include +#include +#include +#include +#include #include #include -#include #include #include + +#ifdef CONFIG_X86_64 +#include +#include +#include +#endif /* CONFIG_X86_64 */ + #include #include -#include "sigframe.h" +#include #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) @@ -45,74 +50,6 @@ # define FIX_EFLAGS __FIX_EFLAGS #endif -/* - * Atomically swap in the new signal mask, and wait for a signal. - */ -asmlinkage int -sys_sigsuspend(int history0, int history1, old_sigset_t mask) -{ - mask &= _BLOCKABLE; - spin_lock_irq(¤t->sighand->siglock); - current->saved_sigmask = current->blocked; - siginitset(¤t->blocked, mask); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - current->state = TASK_INTERRUPTIBLE; - schedule(); - set_restore_sigmask(); - - return -ERESTARTNOHAND; -} - -asmlinkage int -sys_sigaction(int sig, const struct old_sigaction __user *act, - struct old_sigaction __user *oact) -{ - struct k_sigaction new_ka, old_ka; - int ret; - - if (act) { - old_sigset_t mask; - - if (!access_ok(VERIFY_READ, act, sizeof(*act)) || - __get_user(new_ka.sa.sa_handler, &act->sa_handler) || - __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) - return -EFAULT; - - __get_user(new_ka.sa.sa_flags, &act->sa_flags); - __get_user(mask, &act->sa_mask); - siginitset(&new_ka.sa.sa_mask, mask); - } - - ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); - - if (!ret && oact) { - if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || - __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || - __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) - return -EFAULT; - - __put_user(old_ka.sa.sa_flags, &oact->sa_flags); - __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); - } - - return ret; -} - -asmlinkage int sys_sigaltstack(unsigned long bx) -{ - /* - * This is needed to make gcc realize it doesn't own the - * "struct pt_regs" - */ - struct pt_regs *regs = (struct pt_regs *)&bx; - const stack_t __user *uss = (const stack_t __user *)bx; - stack_t __user *uoss = (stack_t __user *)regs->cx; - - return do_sigaltstack(uss, uoss, regs->sp); -} - #define COPY(x) { \ err |= __get_user(regs->x, &sc->x); \ } @@ -123,7 +60,7 @@ asmlinkage int sys_sigaltstack(unsigned long bx) regs->seg = tmp; \ } -#define COPY_SEG_STRICT(seg) { \ +#define COPY_SEG_CPL3(seg) { \ unsigned short tmp; \ err |= __get_user(tmp, &sc->seg); \ regs->seg = tmp | 3; \ @@ -135,9 +72,6 @@ asmlinkage int sys_sigaltstack(unsigned long bx) loadsegment(seg, tmp); \ } -/* - * Do a signal return; undo the signal stack. - */ static int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, unsigned long *pax) @@ -149,14 +83,36 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; +#ifdef CONFIG_X86_32 GET_SEG(gs); COPY_SEG(fs); COPY_SEG(es); COPY_SEG(ds); +#endif /* CONFIG_X86_32 */ + COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx); COPY(dx); COPY(cx); COPY(ip); - COPY_SEG_STRICT(cs); - COPY_SEG_STRICT(ss); + +#ifdef CONFIG_X86_64 + COPY(r8); + COPY(r9); + COPY(r10); + COPY(r11); + COPY(r12); + COPY(r13); + COPY(r14); + COPY(r15); +#endif /* CONFIG_X86_64 */ + +#ifdef CONFIG_X86_32 + COPY_SEG_CPL3(cs); + COPY_SEG_CPL3(ss); +#else /* !CONFIG_X86_32 */ + /* Kernel saves and restores only the CS segment register on signals, + * which is the bare minimum needed to allow mixed 32/64-bit code. + * App's signal handler can save/restore other segments if needed. */ + COPY_SEG_CPL3(cs); +#endif /* CONFIG_X86_32 */ err |= __get_user(tmpflags, &sc->flags); regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); @@ -169,102 +125,24 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, return err; } -asmlinkage unsigned long sys_sigreturn(unsigned long __unused) -{ - struct sigframe __user *frame; - struct pt_regs *regs; - unsigned long ax; - sigset_t set; - - regs = (struct pt_regs *) &__unused; - frame = (struct sigframe __user *)(regs->sp - 8); - - if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) - goto badframe; - if (__get_user(set.sig[0], &frame->sc.oldmask) || (_NSIG_WORDS > 1 - && __copy_from_user(&set.sig[1], &frame->extramask, - sizeof(frame->extramask)))) - goto badframe; - - sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - if (restore_sigcontext(regs, &frame->sc, &ax)) - goto badframe; - return ax; - -badframe: - if (show_unhandled_signals && printk_ratelimit()) { - printk("%s%s[%d] bad frame in sigreturn frame:" - "%p ip:%lx sp:%lx oeax:%lx", - task_pid_nr(current) > 1 ? KERN_INFO : KERN_EMERG, - current->comm, task_pid_nr(current), frame, regs->ip, - regs->sp, regs->orig_ax); - print_vma_addr(" in ", regs->ip); - printk(KERN_CONT "\n"); - } - - force_sig(SIGSEGV, current); - - return 0; -} - -static long do_rt_sigreturn(struct pt_regs *regs) -{ - struct rt_sigframe __user *frame; - unsigned long ax; - sigset_t set; - - frame = (struct rt_sigframe __user *)(regs->sp - sizeof(long)); - if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) - goto badframe; - if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) - goto badframe; - - sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax)) - goto badframe; - - if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT) - goto badframe; - - return ax; - -badframe: - signal_fault(regs, frame, "rt_sigreturn"); - return 0; -} - -asmlinkage int sys_rt_sigreturn(unsigned long __unused) -{ - struct pt_regs *regs = (struct pt_regs *)&__unused; - - return do_rt_sigreturn(regs); -} - -/* - * Set up a signal frame. - */ static int setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate, struct pt_regs *regs, unsigned long mask) { - int tmp, err = 0; + int err = 0; - err |= __put_user(regs->fs, (unsigned int __user *)&sc->fs); - savesegment(gs, tmp); - err |= __put_user(tmp, (unsigned int __user *)&sc->gs); +#ifdef CONFIG_X86_32 + { + unsigned int tmp; + savesegment(gs, tmp); + err |= __put_user(tmp, (unsigned int __user *)&sc->gs); + } + err |= __put_user(regs->fs, (unsigned int __user *)&sc->fs); err |= __put_user(regs->es, (unsigned int __user *)&sc->es); err |= __put_user(regs->ds, (unsigned int __user *)&sc->ds); +#endif /* CONFIG_X86_32 */ + err |= __put_user(regs->di, &sc->di); err |= __put_user(regs->si, &sc->si); err |= __put_user(regs->bp, &sc->bp); @@ -273,19 +151,33 @@ setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate, err |= __put_user(regs->dx, &sc->dx); err |= __put_user(regs->cx, &sc->cx); err |= __put_user(regs->ax, &sc->ax); +#ifdef CONFIG_X86_64 + err |= __put_user(regs->r8, &sc->r8); + err |= __put_user(regs->r9, &sc->r9); + err |= __put_user(regs->r10, &sc->r10); + err |= __put_user(regs->r11, &sc->r11); + err |= __put_user(regs->r12, &sc->r12); + err |= __put_user(regs->r13, &sc->r13); + err |= __put_user(regs->r14, &sc->r14); + err |= __put_user(regs->r15, &sc->r15); +#endif /* CONFIG_X86_64 */ + err |= __put_user(current->thread.trap_no, &sc->trapno); err |= __put_user(current->thread.error_code, &sc->err); err |= __put_user(regs->ip, &sc->ip); +#ifdef CONFIG_X86_32 err |= __put_user(regs->cs, (unsigned int __user *)&sc->cs); err |= __put_user(regs->flags, &sc->flags); err |= __put_user(regs->sp, &sc->sp_at_signal); err |= __put_user(regs->ss, (unsigned int __user *)&sc->ss); +#else /* !CONFIG_X86_32 */ + err |= __put_user(regs->flags, &sc->flags); + err |= __put_user(regs->cs, &sc->cs); + err |= __put_user(0, &sc->gs); + err |= __put_user(0, &sc->fs); +#endif /* CONFIG_X86_32 */ - tmp = save_i387_xstate(fpstate); - if (tmp < 0) - err = 1; - else - err |= __put_user(tmp ? fpstate : NULL, &sc->fpstate); + err |= __put_user(fpstate, &sc->fpstate); /* non-iBCS2 extensions.. */ err |= __put_user(mask, &sc->oldmask); @@ -294,6 +186,32 @@ setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate, return err; } +/* + * Set up a signal frame. + */ +#ifdef CONFIG_X86_32 +static const struct { + u16 poplmovl; + u32 val; + u16 int80; +} __attribute__((packed)) retcode = { + 0xb858, /* popl %eax; movl $..., %eax */ + __NR_sigreturn, + 0x80cd, /* int $0x80 */ +}; + +static const struct { + u8 movl; + u32 val; + u16 int80; + u8 pad; +} __attribute__((packed)) rt_retcode = { + 0xb8, /* movl $..., %eax */ + __NR_rt_sigreturn, + 0x80cd, /* int $0x80 */ + 0 +}; + /* * Determine which stack to use.. */ @@ -328,6 +246,8 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, if (used_math()) { sp = sp - sig_xstate_size; *fpstate = (struct _fpstate *) sp; + if (save_i387_xstate(*fpstate) < 0) + return (void __user *)-1L; } sp -= frame_size; @@ -383,9 +303,7 @@ __setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, * reasons and because gdb uses it as a signature to notice * signal handler stack frames. */ - err |= __put_user(0xb858, (short __user *)(frame->retcode+0)); - err |= __put_user(__NR_sigreturn, (int __user *)(frame->retcode+2)); - err |= __put_user(0x80cd, (short __user *)(frame->retcode+6)); + err |= __put_user(*((u64 *)&retcode), (u64 *)frame->retcode); if (err) return -EFAULT; @@ -454,9 +372,7 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, * reasons and because gdb uses it as a signature to notice * signal handler stack frames. */ - err |= __put_user(0xb8, (char __user *)(frame->retcode+0)); - err |= __put_user(__NR_rt_sigreturn, (int __user *)(frame->retcode+1)); - err |= __put_user(0x80cd, (short __user *)(frame->retcode+5)); + err |= __put_user(*((u64 *)&rt_retcode), (u64 *)frame->retcode); if (err) return -EFAULT; @@ -475,23 +391,293 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, return 0; } +#else /* !CONFIG_X86_32 */ +/* + * Determine which stack to use.. + */ +static void __user * +get_stack(struct k_sigaction *ka, unsigned long sp, unsigned long size) +{ + /* Default to using normal stack - redzone*/ + sp -= 128; + + /* This is the X/Open sanctioned signal stack switching. */ + if (ka->sa.sa_flags & SA_ONSTACK) { + if (sas_ss_flags(sp) == 0) + sp = current->sas_ss_sp + current->sas_ss_size; + } + + return (void __user *)round_down(sp - size, 64); +} + +static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *set, struct pt_regs *regs) +{ + struct rt_sigframe __user *frame; + void __user *fp = NULL; + int err = 0; + struct task_struct *me = current; + + if (used_math()) { + fp = get_stack(ka, regs->sp, sig_xstate_size); + frame = (void __user *)round_down( + (unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8; + + if (save_i387_xstate(fp) < 0) + return -EFAULT; + } else + frame = get_stack(ka, regs->sp, sizeof(struct rt_sigframe)) - 8; + + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) + return -EFAULT; + + if (ka->sa.sa_flags & SA_SIGINFO) { + if (copy_siginfo_to_user(&frame->info, info)) + return -EFAULT; + } + + /* Create the ucontext. */ + if (cpu_has_xsave) + err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags); + else + err |= __put_user(0, &frame->uc.uc_flags); + err |= __put_user(0, &frame->uc.uc_link); + err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp); + err |= __put_user(sas_ss_flags(regs->sp), + &frame->uc.uc_stack.ss_flags); + err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size); + err |= setup_sigcontext(&frame->uc.uc_mcontext, fp, regs, set->sig[0]); + err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); + + /* Set up to return from userspace. If provided, use a stub + already in userspace. */ + /* x86-64 should always use SA_RESTORER. */ + if (ka->sa.sa_flags & SA_RESTORER) { + err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); + } else { + /* could use a vstub here */ + return -EFAULT; + } + + if (err) + return -EFAULT; + + /* Set up registers for signal handler */ + regs->di = sig; + /* In case the signal handler was declared without prototypes */ + regs->ax = 0; + + /* This also works for non SA_SIGINFO handlers because they expect the + next argument after the signal number on the stack. */ + regs->si = (unsigned long)&frame->info; + regs->dx = (unsigned long)&frame->uc; + regs->ip = (unsigned long) ka->sa.sa_handler; + + regs->sp = (unsigned long)frame; + + /* Set up the CS register to run signal handlers in 64-bit mode, + even if the handler happens to be interrupting 32-bit code. */ + regs->cs = __USER_CS; + + return 0; +} +#endif /* CONFIG_X86_32 */ + +#ifdef CONFIG_X86_32 +/* + * Atomically swap in the new signal mask, and wait for a signal. + */ +asmlinkage int +sys_sigsuspend(int history0, int history1, old_sigset_t mask) +{ + mask &= _BLOCKABLE; + spin_lock_irq(¤t->sighand->siglock); + current->saved_sigmask = current->blocked; + siginitset(¤t->blocked, mask); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + current->state = TASK_INTERRUPTIBLE; + schedule(); + set_restore_sigmask(); + + return -ERESTARTNOHAND; +} + +asmlinkage int +sys_sigaction(int sig, const struct old_sigaction __user *act, + struct old_sigaction __user *oact) +{ + struct k_sigaction new_ka, old_ka; + int ret; + + if (act) { + old_sigset_t mask; + + if (!access_ok(VERIFY_READ, act, sizeof(*act)) || + __get_user(new_ka.sa.sa_handler, &act->sa_handler) || + __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) + return -EFAULT; + + __get_user(new_ka.sa.sa_flags, &act->sa_flags); + __get_user(mask, &act->sa_mask); + siginitset(&new_ka.sa.sa_mask, mask); + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || + __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || + __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) + return -EFAULT; + + __put_user(old_ka.sa.sa_flags, &oact->sa_flags); + __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); + } + + return ret; +} +#endif /* CONFIG_X86_32 */ + +#ifdef CONFIG_X86_32 +asmlinkage int sys_sigaltstack(unsigned long bx) +{ + /* + * This is needed to make gcc realize it doesn't own the + * "struct pt_regs" + */ + struct pt_regs *regs = (struct pt_regs *)&bx; + const stack_t __user *uss = (const stack_t __user *)bx; + stack_t __user *uoss = (stack_t __user *)regs->cx; + + return do_sigaltstack(uss, uoss, regs->sp); +} +#else /* !CONFIG_X86_32 */ +asmlinkage long +sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, + struct pt_regs *regs) +{ + return do_sigaltstack(uss, uoss, regs->sp); +} +#endif /* CONFIG_X86_32 */ + +/* + * Do a signal return; undo the signal stack. + */ +#ifdef CONFIG_X86_32 +asmlinkage unsigned long sys_sigreturn(unsigned long __unused) +{ + struct sigframe __user *frame; + struct pt_regs *regs; + unsigned long ax; + sigset_t set; + + regs = (struct pt_regs *) &__unused; + frame = (struct sigframe __user *)(regs->sp - 8); + + if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + if (__get_user(set.sig[0], &frame->sc.oldmask) || (_NSIG_WORDS > 1 + && __copy_from_user(&set.sig[1], &frame->extramask, + sizeof(frame->extramask)))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sighand->siglock); + current->blocked = set; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + if (restore_sigcontext(regs, &frame->sc, &ax)) + goto badframe; + return ax; + +badframe: + signal_fault(regs, frame, "sigreturn"); + + return 0; +} +#endif /* CONFIG_X86_32 */ + +static long do_rt_sigreturn(struct pt_regs *regs) +{ + struct rt_sigframe __user *frame; + unsigned long ax; + sigset_t set; + + frame = (struct rt_sigframe __user *)(regs->sp - sizeof(long)); + if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sighand->siglock); + current->blocked = set; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax)) + goto badframe; + + if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT) + goto badframe; + + return ax; + +badframe: + signal_fault(regs, frame, "rt_sigreturn"); + return 0; +} + +#ifdef CONFIG_X86_32 +asmlinkage int sys_rt_sigreturn(struct pt_regs regs) +{ + return do_rt_sigreturn(®s); +} +#else /* !CONFIG_X86_32 */ +asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) +{ + return do_rt_sigreturn(regs); +} +#endif /* CONFIG_X86_32 */ /* * OK, we're invoking a handler: */ static int signr_convert(int sig) { +#ifdef CONFIG_X86_32 struct thread_info *info = current_thread_info(); if (info->exec_domain && info->exec_domain->signal_invmap && sig < 32) return info->exec_domain->signal_invmap[sig]; +#endif /* CONFIG_X86_32 */ return sig; } +#ifdef CONFIG_X86_32 + #define is_ia32 1 #define ia32_setup_frame __setup_frame #define ia32_setup_rt_frame __setup_rt_frame +#else /* !CONFIG_X86_32 */ + +#ifdef CONFIG_IA32_EMULATION +#define is_ia32 test_thread_flag(TIF_IA32) +#else /* !CONFIG_IA32_EMULATION */ +#define is_ia32 0 +#endif /* CONFIG_IA32_EMULATION */ + +int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *set, struct pt_regs *regs); +int ia32_setup_frame(int sig, struct k_sigaction *ka, + sigset_t *set, struct pt_regs *regs); + +#endif /* CONFIG_X86_32 */ + static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs *regs) @@ -592,7 +778,13 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, return 0; } +#ifdef CONFIG_X86_32 #define NR_restart_syscall __NR_restart_syscall +#else /* !CONFIG_X86_32 */ +#define NR_restart_syscall \ + test_thread_flag(TIF_IA32) ? __NR_ia32_restart_syscall : __NR_restart_syscall +#endif /* CONFIG_X86_32 */ + /* * Note that 'init' is a special process: it doesn't get signals it doesn't * want to handle. Thus you cannot kill init even with a SIGKILL even by @@ -704,8 +896,9 @@ void signal_fault(struct pt_regs *regs, void __user *frame, char *where) struct task_struct *me = current; if (show_unhandled_signals && printk_ratelimit()) { - printk(KERN_INFO + printk("%s" "%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx", + task_pid_nr(current) > 1 ? KERN_INFO : KERN_EMERG, me->comm, me->pid, where, frame, regs->ip, regs->sp, regs->orig_ax); print_vma_addr(" in ", regs->ip); diff --git a/arch/x86/kernel/signal_64.c b/arch/x86/kernel/signal_64.c deleted file mode 100644 index a5c9627f4db9df635a01373edbaeff215d9c52ae..0000000000000000000000000000000000000000 --- a/arch/x86/kernel/signal_64.c +++ /dev/null @@ -1,516 +0,0 @@ -/* - * Copyright (C) 1991, 1992 Linus Torvalds - * Copyright (C) 2000, 2001, 2002 Andi Kleen SuSE Labs - * - * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson - * 2000-06-20 Pentium III FXSR, SSE support by Gareth Hughes - * 2000-2002 x86-64 support by Andi Kleen - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include "sigframe.h" - -#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) - -#define __FIX_EFLAGS (X86_EFLAGS_AC | X86_EFLAGS_OF | \ - X86_EFLAGS_DF | X86_EFLAGS_TF | X86_EFLAGS_SF | \ - X86_EFLAGS_ZF | X86_EFLAGS_AF | X86_EFLAGS_PF | \ - X86_EFLAGS_CF) - -#ifdef CONFIG_X86_32 -# define FIX_EFLAGS (__FIX_EFLAGS | X86_EFLAGS_RF) -#else -# define FIX_EFLAGS __FIX_EFLAGS -#endif - -asmlinkage long -sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, - struct pt_regs *regs) -{ - return do_sigaltstack(uss, uoss, regs->sp); -} - -#define COPY(x) { \ - err |= __get_user(regs->x, &sc->x); \ -} - -#define COPY_SEG_STRICT(seg) { \ - unsigned short tmp; \ - err |= __get_user(tmp, &sc->seg); \ - regs->seg = tmp | 3; \ -} - -/* - * Do a signal return; undo the signal stack. - */ -static int -restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, - unsigned long *pax) -{ - void __user *buf; - unsigned int tmpflags; - unsigned int err = 0; - - /* Always make any pending restarted system calls return -EINTR */ - current_thread_info()->restart_block.fn = do_no_restart_syscall; - - COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx); - COPY(dx); COPY(cx); COPY(ip); - COPY(r8); - COPY(r9); - COPY(r10); - COPY(r11); - COPY(r12); - COPY(r13); - COPY(r14); - COPY(r15); - - /* Kernel saves and restores only the CS segment register on signals, - * which is the bare minimum needed to allow mixed 32/64-bit code. - * App's signal handler can save/restore other segments if needed. */ - COPY_SEG_STRICT(cs); - - err |= __get_user(tmpflags, &sc->flags); - regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); - regs->orig_ax = -1; /* disable syscall checks */ - - err |= __get_user(buf, &sc->fpstate); - err |= restore_i387_xstate(buf); - - err |= __get_user(*pax, &sc->ax); - return err; -} - -static long do_rt_sigreturn(struct pt_regs *regs) -{ - struct rt_sigframe __user *frame; - unsigned long ax; - sigset_t set; - - frame = (struct rt_sigframe __user *)(regs->sp - sizeof(long)); - if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) - goto badframe; - if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) - goto badframe; - - sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax)) - goto badframe; - - if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT) - goto badframe; - - return ax; - -badframe: - signal_fault(regs, frame, "rt_sigreturn"); - return 0; -} - -asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) -{ - return do_rt_sigreturn(regs); -} - -/* - * Set up a signal frame. - */ - -static inline int -setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, - unsigned long mask, struct task_struct *me) -{ - int err = 0; - - err |= __put_user(regs->cs, &sc->cs); - err |= __put_user(0, &sc->gs); - err |= __put_user(0, &sc->fs); - - err |= __put_user(regs->di, &sc->di); - err |= __put_user(regs->si, &sc->si); - err |= __put_user(regs->bp, &sc->bp); - err |= __put_user(regs->sp, &sc->sp); - err |= __put_user(regs->bx, &sc->bx); - err |= __put_user(regs->dx, &sc->dx); - err |= __put_user(regs->cx, &sc->cx); - err |= __put_user(regs->ax, &sc->ax); - err |= __put_user(regs->r8, &sc->r8); - err |= __put_user(regs->r9, &sc->r9); - err |= __put_user(regs->r10, &sc->r10); - err |= __put_user(regs->r11, &sc->r11); - err |= __put_user(regs->r12, &sc->r12); - err |= __put_user(regs->r13, &sc->r13); - err |= __put_user(regs->r14, &sc->r14); - err |= __put_user(regs->r15, &sc->r15); - err |= __put_user(me->thread.trap_no, &sc->trapno); - err |= __put_user(me->thread.error_code, &sc->err); - err |= __put_user(regs->ip, &sc->ip); - err |= __put_user(regs->flags, &sc->flags); - err |= __put_user(mask, &sc->oldmask); - err |= __put_user(me->thread.cr2, &sc->cr2); - - return err; -} - -/* - * Determine which stack to use.. - */ - -static void __user * -get_stack(struct k_sigaction *ka, struct pt_regs *regs, unsigned long size) -{ - unsigned long sp; - - /* Default to using normal stack - redzone*/ - sp = regs->sp - 128; - - /* This is the X/Open sanctioned signal stack switching. */ - if (ka->sa.sa_flags & SA_ONSTACK) { - if (sas_ss_flags(sp) == 0) - sp = current->sas_ss_sp + current->sas_ss_size; - } - - return (void __user *)round_down(sp - size, 64); -} - -static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, - sigset_t *set, struct pt_regs *regs) -{ - struct rt_sigframe __user *frame; - void __user *fp = NULL; - int err = 0; - struct task_struct *me = current; - - if (used_math()) { - fp = get_stack(ka, regs, sig_xstate_size); - frame = (void __user *)round_down( - (unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8; - - if (save_i387_xstate(fp) < 0) - return -EFAULT; - } else - frame = get_stack(ka, regs, sizeof(struct rt_sigframe)) - 8; - - if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) - return -EFAULT; - - if (ka->sa.sa_flags & SA_SIGINFO) { - if (copy_siginfo_to_user(&frame->info, info)) - return -EFAULT; - } - - /* Create the ucontext. */ - if (cpu_has_xsave) - err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags); - else - err |= __put_user(0, &frame->uc.uc_flags); - err |= __put_user(0, &frame->uc.uc_link); - err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp); - err |= __put_user(sas_ss_flags(regs->sp), - &frame->uc.uc_stack.ss_flags); - err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size); - err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0], me); - err |= __put_user(fp, &frame->uc.uc_mcontext.fpstate); - if (sizeof(*set) == 16) { - __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]); - __put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]); - } else - err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); - - /* Set up to return from userspace. If provided, use a stub - already in userspace. */ - /* x86-64 should always use SA_RESTORER. */ - if (ka->sa.sa_flags & SA_RESTORER) { - err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); - } else { - /* could use a vstub here */ - return -EFAULT; - } - - if (err) - return -EFAULT; - - /* Set up registers for signal handler */ - regs->di = sig; - /* In case the signal handler was declared without prototypes */ - regs->ax = 0; - - /* This also works for non SA_SIGINFO handlers because they expect the - next argument after the signal number on the stack. */ - regs->si = (unsigned long)&frame->info; - regs->dx = (unsigned long)&frame->uc; - regs->ip = (unsigned long) ka->sa.sa_handler; - - regs->sp = (unsigned long)frame; - - /* Set up the CS register to run signal handlers in 64-bit mode, - even if the handler happens to be interrupting 32-bit code. */ - regs->cs = __USER_CS; - - return 0; -} - -/* - * OK, we're invoking a handler - */ -static int signr_convert(int sig) -{ - return sig; -} - -#ifdef CONFIG_IA32_EMULATION -#define is_ia32 test_thread_flag(TIF_IA32) -#else -#define is_ia32 0 -#endif - -static int -setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, - sigset_t *set, struct pt_regs *regs) -{ - int usig = signr_convert(sig); - int ret; - - /* Set up the stack frame */ - if (is_ia32) { - if (ka->sa.sa_flags & SA_SIGINFO) - ret = ia32_setup_rt_frame(usig, ka, info, set, regs); - else - ret = ia32_setup_frame(usig, ka, set, regs); - } else - ret = __setup_rt_frame(sig, ka, info, set, regs); - - if (ret) { - force_sigsegv(sig, current); - return -EFAULT; - } - - return ret; -} - -static int -handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, - sigset_t *oldset, struct pt_regs *regs) -{ - int ret; - - /* Are we from a system call? */ - if (syscall_get_nr(current, regs) >= 0) { - /* If so, check system call restarting.. */ - switch (syscall_get_error(current, regs)) { - case -ERESTART_RESTARTBLOCK: - case -ERESTARTNOHAND: - regs->ax = -EINTR; - break; - - case -ERESTARTSYS: - if (!(ka->sa.sa_flags & SA_RESTART)) { - regs->ax = -EINTR; - break; - } - /* fallthrough */ - case -ERESTARTNOINTR: - regs->ax = regs->orig_ax; - regs->ip -= 2; - break; - } - } - - /* - * If TF is set due to a debugger (TIF_FORCED_TF), clear the TF - * flag so that register information in the sigcontext is correct. - */ - if (unlikely(regs->flags & X86_EFLAGS_TF) && - likely(test_and_clear_thread_flag(TIF_FORCED_TF))) - regs->flags &= ~X86_EFLAGS_TF; - - ret = setup_rt_frame(sig, ka, info, oldset, regs); - - if (ret) - return ret; - -#ifdef CONFIG_X86_64 - /* - * This has nothing to do with segment registers, - * despite the name. This magic affects uaccess.h - * macros' behavior. Reset it to the normal setting. - */ - set_fs(USER_DS); -#endif - - /* - * Clear the direction flag as per the ABI for function entry. - */ - regs->flags &= ~X86_EFLAGS_DF; - - /* - * Clear TF when entering the signal handler, but - * notify any tracer that was single-stepping it. - * The tracer may want to single-step inside the - * handler too. - */ - regs->flags &= ~X86_EFLAGS_TF; - - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); - if (!(ka->sa.sa_flags & SA_NODEFER)) - sigaddset(¤t->blocked, sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - tracehook_signal_handler(sig, info, ka, regs, - test_thread_flag(TIF_SINGLESTEP)); - - return 0; -} - -#define NR_restart_syscall \ - test_thread_flag(TIF_IA32) ? __NR_ia32_restart_syscall : __NR_restart_syscall -/* - * Note that 'init' is a special process: it doesn't get signals it doesn't - * want to handle. Thus you cannot kill init even with a SIGKILL even by - * mistake. - */ -static void do_signal(struct pt_regs *regs) -{ - struct k_sigaction ka; - siginfo_t info; - int signr; - sigset_t *oldset; - - /* - * We want the common case to go fast, which is why we may in certain - * cases get here from kernel mode. Just return without doing anything - * if so. - * X86_32: vm86 regs switched out by assembly code before reaching - * here, so testing against kernel CS suffices. - */ - if (!user_mode(regs)) - return; - - if (current_thread_info()->status & TS_RESTORE_SIGMASK) - oldset = ¤t->saved_sigmask; - else - oldset = ¤t->blocked; - - signr = get_signal_to_deliver(&info, &ka, regs, NULL); - if (signr > 0) { - /* - * Re-enable any watchpoints before delivering the - * signal to user space. The processor register will - * have been cleared if the watchpoint triggered - * inside the kernel. - */ - if (current->thread.debugreg7) - set_debugreg(current->thread.debugreg7, 7); - - /* Whee! Actually deliver the signal. */ - if (handle_signal(signr, &info, &ka, oldset, regs) == 0) { - /* - * A signal was successfully delivered; the saved - * sigmask will have been stored in the signal frame, - * and will be restored by sigreturn, so we can simply - * clear the TS_RESTORE_SIGMASK flag. - */ - current_thread_info()->status &= ~TS_RESTORE_SIGMASK; - } - return; - } - - /* Did we come from a system call? */ - if (syscall_get_nr(current, regs) >= 0) { - /* Restart the system call - no handlers present */ - switch (syscall_get_error(current, regs)) { - case -ERESTARTNOHAND: - case -ERESTARTSYS: - case -ERESTARTNOINTR: - regs->ax = regs->orig_ax; - regs->ip -= 2; - break; - - case -ERESTART_RESTARTBLOCK: - regs->ax = NR_restart_syscall; - regs->ip -= 2; - break; - } - } - - /* - * If there's no signal to deliver, we just put the saved sigmask - * back. - */ - if (current_thread_info()->status & TS_RESTORE_SIGMASK) { - current_thread_info()->status &= ~TS_RESTORE_SIGMASK; - sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); - } -} - -/* - * notification of userspace execution resumption - * - triggered by the TIF_WORK_MASK flags - */ -void -do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) -{ -#if defined(CONFIG_X86_64) && defined(CONFIG_X86_MCE) - /* notify userspace of pending MCEs */ - if (thread_info_flags & _TIF_MCE_NOTIFY) - mce_notify_user(); -#endif /* CONFIG_X86_64 && CONFIG_X86_MCE */ - - /* deal with pending signal delivery */ - if (thread_info_flags & _TIF_SIGPENDING) - do_signal(regs); - - if (thread_info_flags & _TIF_NOTIFY_RESUME) { - clear_thread_flag(TIF_NOTIFY_RESUME); - tracehook_notify_resume(regs); - } - -#ifdef CONFIG_X86_32 - clear_thread_flag(TIF_IRET); -#endif /* CONFIG_X86_32 */ -} - -void signal_fault(struct pt_regs *regs, void __user *frame, char *where) -{ - struct task_struct *me = current; - - if (show_unhandled_signals && printk_ratelimit()) { - printk(KERN_INFO - "%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx", - me->comm, me->pid, where, frame, - regs->ip, regs->sp, regs->orig_ax); - print_vma_addr(" in ", regs->ip); - printk(KERN_CONT "\n"); - } - - force_sig(SIGSEGV, me); -} diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c index 18f9b19f5f8f5d46582b64501d83d11cb4376eb6..7e558db362c1870f19013da9879f8cea1542e472 100644 --- a/arch/x86/kernel/smp.c +++ b/arch/x86/kernel/smp.c @@ -140,19 +140,6 @@ void native_send_call_func_ipi(cpumask_t mask) send_IPI_mask(mask, CALL_FUNCTION_VECTOR); } -static void stop_this_cpu(void *dummy) -{ - local_irq_disable(); - /* - * Remove this CPU: - */ - cpu_clear(smp_processor_id(), cpu_online_map); - disable_local_APIC(); - if (hlt_works(smp_processor_id())) - for (;;) halt(); - for (;;); -} - /* * this function calls the 'stop' function on all other CPUs in the system. */ @@ -178,11 +165,7 @@ static void native_smp_send_stop(void) void smp_reschedule_interrupt(struct pt_regs *regs) { ack_APIC_irq(); -#ifdef CONFIG_X86_32 - __get_cpu_var(irq_stat).irq_resched_count++; -#else - add_pda(irq_resched_count, 1); -#endif + inc_irq_stat(irq_resched_count); } void smp_call_function_interrupt(struct pt_regs *regs) @@ -190,11 +173,7 @@ void smp_call_function_interrupt(struct pt_regs *regs) ack_APIC_irq(); irq_enter(); generic_smp_call_function_interrupt(); -#ifdef CONFIG_X86_32 - __get_cpu_var(irq_stat).irq_call_count++; -#else - add_pda(irq_call_count, 1); -#endif + inc_irq_stat(irq_call_count); irq_exit(); } @@ -203,11 +182,7 @@ void smp_call_function_single_interrupt(struct pt_regs *regs) ack_APIC_irq(); irq_enter(); generic_smp_call_function_single_interrupt(); -#ifdef CONFIG_X86_32 - __get_cpu_var(irq_stat).irq_call_count++; -#else - add_pda(irq_call_count, 1); -#endif + inc_irq_stat(irq_call_count); irq_exit(); } diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index f71f96fc9e62ea8e4f027a78cb3aafcd96fdbf99..f8500c969442875e4db94cf9ca3d68e1c3777fbf 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -62,6 +62,7 @@ #include #include #include +#include #include #include @@ -287,7 +288,7 @@ static int __cpuinitdata unsafe_smp; /* * Activate a secondary processor. */ -static void __cpuinit start_secondary(void *unused) +notrace static void __cpuinit start_secondary(void *unused) { /* * Don't put *anything* before cpu_init(), SMP booting is too @@ -534,7 +535,7 @@ static void impress_friends(void) pr_debug("Before bogocount - setting activated=1.\n"); } -static inline void __inquire_remote_apic(int apicid) +void __inquire_remote_apic(int apicid) { unsigned i, regs[] = { APIC_ID >> 4, APIC_LVR >> 4, APIC_SPIV >> 4 }; char *names[] = { "ID", "VERSION", "SPIV" }; @@ -573,14 +574,13 @@ static inline void __inquire_remote_apic(int apicid) } } -#ifdef WAKE_SECONDARY_VIA_NMI /* * Poke the other CPU in the eye via NMI to wake it up. Remember that the normal * INIT, INIT, STARTUP sequence will reset the chip hard for us, and this * won't ... remember to clear down the APIC, etc later. */ -static int __devinit -wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip) +int __devinit +wakeup_secondary_cpu_via_nmi(int logical_apicid, unsigned long start_eip) { unsigned long send_status, accept_status = 0; int maxlvt; @@ -597,7 +597,7 @@ wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip) * Give the other CPU some time to accept the IPI. */ udelay(200); - if (APIC_INTEGRATED(apic_version[phys_apicid])) { + if (APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) { maxlvt = lapic_get_maxlvt(); if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */ apic_write(APIC_ESR, 0); @@ -612,11 +612,9 @@ wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip) return (send_status | accept_status); } -#endif /* WAKE_SECONDARY_VIA_NMI */ -#ifdef WAKE_SECONDARY_VIA_INIT -static int __devinit -wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip) +int __devinit +wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip) { unsigned long send_status, accept_status = 0; int maxlvt, num_starts, j; @@ -735,7 +733,6 @@ wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip) return (send_status | accept_status); } -#endif /* WAKE_SECONDARY_VIA_INIT */ struct create_idle { struct work_struct work; @@ -1084,8 +1081,10 @@ static int __init smp_sanity_check(unsigned max_cpus) #endif if (!physid_isset(hard_smp_processor_id(), phys_cpu_present_map)) { - printk(KERN_WARNING "weird, boot CPU (#%d) not listed" - "by the BIOS.\n", hard_smp_processor_id()); + printk(KERN_WARNING + "weird, boot CPU (#%d) not listed by the BIOS.\n", + hard_smp_processor_id()); + physid_set(hard_smp_processor_id(), phys_cpu_present_map); } diff --git a/arch/x86/kernel/stacktrace.c b/arch/x86/kernel/stacktrace.c index a03e7f6d90c35af5f4638f6394e4a39f6e2e4020..10786af95545ea37654bcf7125d7a880edc03540 100644 --- a/arch/x86/kernel/stacktrace.c +++ b/arch/x86/kernel/stacktrace.c @@ -6,6 +6,7 @@ #include #include #include +#include #include static void save_stack_warning(void *data, char *msg) @@ -83,3 +84,66 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) trace->entries[trace->nr_entries++] = ULONG_MAX; } EXPORT_SYMBOL_GPL(save_stack_trace_tsk); + +/* Userspace stacktrace - based on kernel/trace/trace_sysprof.c */ + +struct stack_frame { + const void __user *next_fp; + unsigned long ret_addr; +}; + +static int copy_stack_frame(const void __user *fp, struct stack_frame *frame) +{ + int ret; + + if (!access_ok(VERIFY_READ, fp, sizeof(*frame))) + return 0; + + ret = 1; + pagefault_disable(); + if (__copy_from_user_inatomic(frame, fp, sizeof(*frame))) + ret = 0; + pagefault_enable(); + + return ret; +} + +static inline void __save_stack_trace_user(struct stack_trace *trace) +{ + const struct pt_regs *regs = task_pt_regs(current); + const void __user *fp = (const void __user *)regs->bp; + + if (trace->nr_entries < trace->max_entries) + trace->entries[trace->nr_entries++] = regs->ip; + + while (trace->nr_entries < trace->max_entries) { + struct stack_frame frame; + + frame.next_fp = NULL; + frame.ret_addr = 0; + if (!copy_stack_frame(fp, &frame)) + break; + if ((unsigned long)fp < regs->sp) + break; + if (frame.ret_addr) { + trace->entries[trace->nr_entries++] = + frame.ret_addr; + } + if (fp == frame.next_fp) + break; + fp = frame.next_fp; + } +} + +void save_stack_trace_user(struct stack_trace *trace) +{ + /* + * Trace user stack if we are not a kernel thread + */ + if (current->mm) { + __save_stack_trace_user(trace); + } + if (trace->nr_entries < trace->max_entries) + trace->entries[trace->nr_entries++] = ULONG_MAX; +} + diff --git a/arch/x86/kernel/time_32.c b/arch/x86/kernel/time_32.c index 77b400f06ea2335fa770fb3273ce5cd7e5820c18..65309e4cb1c0844480efdf3b18e50c46602bc56f 100644 --- a/arch/x86/kernel/time_32.c +++ b/arch/x86/kernel/time_32.c @@ -75,7 +75,7 @@ EXPORT_SYMBOL(profile_pc); irqreturn_t timer_interrupt(int irq, void *dev_id) { /* Keep nmi watchdog up to date */ - per_cpu(irq_stat, smp_processor_id()).irq0_irqs++; + inc_irq_stat(irq0_irqs); #ifdef CONFIG_X86_IO_APIC if (timer_ack) { diff --git a/arch/x86/kernel/time_64.c b/arch/x86/kernel/time_64.c index cb19d650c21643599aa1423a57b64a85ee26afe8..891e7a7c4334086b1949444944236c241147e930 100644 --- a/arch/x86/kernel/time_64.c +++ b/arch/x86/kernel/time_64.c @@ -49,9 +49,9 @@ unsigned long profile_pc(struct pt_regs *regs) } EXPORT_SYMBOL(profile_pc); -irqreturn_t timer_interrupt(int irq, void *dev_id) +static irqreturn_t timer_interrupt(int irq, void *dev_id) { - add_pda(irq0_irqs, 1); + inc_irq_stat(irq0_irqs); global_clock_event->event_handler(global_clock_event); @@ -80,6 +80,8 @@ unsigned long __init calibrate_cpu(void) break; no_ctr_free = (i == 4); if (no_ctr_free) { + WARN(1, KERN_WARNING "Warning: AMD perfctrs busy ... " + "cpu_khz value may be incorrect.\n"); i = 3; rdmsrl(MSR_K7_EVNTSEL3, evntsel3); wrmsrl(MSR_K7_EVNTSEL3, 0); diff --git a/arch/x86/kernel/tlb_32.c b/arch/x86/kernel/tlb_32.c index f4049f3513b6b5e01e71523a5490fbedd5db9992..8da059f949be9527e1ce7919bfff54550a65c714 100644 --- a/arch/x86/kernel/tlb_32.c +++ b/arch/x86/kernel/tlb_32.c @@ -34,9 +34,8 @@ static DEFINE_SPINLOCK(tlbstate_lock); */ void leave_mm(int cpu) { - if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK) - BUG(); - cpu_clear(cpu, per_cpu(cpu_tlbstate, cpu).active_mm->cpu_vm_mask); + BUG_ON(x86_read_percpu(cpu_tlbstate.state) == TLBSTATE_OK); + cpu_clear(cpu, x86_read_percpu(cpu_tlbstate.active_mm)->cpu_vm_mask); load_cr3(swapper_pg_dir); } EXPORT_SYMBOL_GPL(leave_mm); @@ -104,8 +103,8 @@ void smp_invalidate_interrupt(struct pt_regs *regs) * BUG(); */ - if (flush_mm == per_cpu(cpu_tlbstate, cpu).active_mm) { - if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK) { + if (flush_mm == x86_read_percpu(cpu_tlbstate.active_mm)) { + if (x86_read_percpu(cpu_tlbstate.state) == TLBSTATE_OK) { if (flush_va == TLB_FLUSH_ALL) local_flush_tlb(); else @@ -119,7 +118,7 @@ void smp_invalidate_interrupt(struct pt_regs *regs) smp_mb__after_clear_bit(); out: put_cpu_no_resched(); - __get_cpu_var(irq_stat).irq_tlb_count++; + inc_irq_stat(irq_tlb_count); } void native_flush_tlb_others(const cpumask_t *cpumaskp, struct mm_struct *mm, @@ -238,7 +237,7 @@ static void do_flush_tlb_all(void *info) unsigned long cpu = smp_processor_id(); __flush_tlb_all(); - if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_LAZY) + if (x86_read_percpu(cpu_tlbstate.state) == TLBSTATE_LAZY) leave_mm(cpu); } diff --git a/arch/x86/kernel/tlb_64.c b/arch/x86/kernel/tlb_64.c index 8f919ca69494d62541453202b27f4ec13903d2f8..29887d7081a9572557e5ae30f630f8c2a3ab3321 100644 --- a/arch/x86/kernel/tlb_64.c +++ b/arch/x86/kernel/tlb_64.c @@ -154,7 +154,7 @@ asmlinkage void smp_invalidate_interrupt(struct pt_regs *regs) out: ack_APIC_irq(); cpu_clear(cpu, f->flush_cpumask); - add_pda(irq_tlb_count, 1); + inc_irq_stat(irq_tlb_count); } void native_flush_tlb_others(const cpumask_t *cpumaskp, struct mm_struct *mm, diff --git a/arch/x86/kernel/tlb_uv.c b/arch/x86/kernel/tlb_uv.c index 04431f34fd16f24946bb66b4eedf69ed7e51cf6f..6a00e5faaa74375d5b709488a0b9c371c3fe5c79 100644 --- a/arch/x86/kernel/tlb_uv.c +++ b/arch/x86/kernel/tlb_uv.c @@ -566,14 +566,10 @@ static int __init uv_ptc_init(void) if (!is_uv_system()) return 0; - if (!proc_mkdir("sgi_uv", NULL)) - return -EINVAL; - proc_uv_ptc = create_proc_entry(UV_PTC_BASENAME, 0444, NULL); if (!proc_uv_ptc) { printk(KERN_ERR "unable to create %s proc entry\n", UV_PTC_BASENAME); - remove_proc_entry("sgi_uv", NULL); return -EINVAL; } proc_uv_ptc->proc_fops = &proc_uv_ptc_operations; diff --git a/arch/x86/kernel/trampoline.c b/arch/x86/kernel/trampoline.c index 1106fac6024d412fae02df4780464ecd2f9abf4b..808031a5ba19a62bee01b404a812d57409b60b7d 100644 --- a/arch/x86/kernel/trampoline.c +++ b/arch/x86/kernel/trampoline.c @@ -1,10 +1,26 @@ #include #include +#include /* ready for x86_64 and x86 */ unsigned char *trampoline_base = __va(TRAMPOLINE_BASE); +void __init reserve_trampoline_memory(void) +{ +#ifdef CONFIG_X86_32 + /* + * But first pinch a few for the stack/trampoline stuff + * FIXME: Don't need the extra page at 4K, but need to fix + * trampoline before removing it. (see the GDT stuff) + */ + reserve_early(PAGE_SIZE, PAGE_SIZE + PAGE_SIZE, "EX TRAMPOLINE"); +#endif + /* Has to be in very low memory so we can execute real-mode AP code. */ + reserve_early(TRAMPOLINE_BASE, TRAMPOLINE_BASE + TRAMPOLINE_SIZE, + "TRAMPOLINE"); +} + /* * Currently trivial. Write the real->protected mode * bootstrap into the page concerned. The caller @@ -12,7 +28,6 @@ unsigned char *trampoline_base = __va(TRAMPOLINE_BASE); */ unsigned long setup_trampoline(void) { - memcpy(trampoline_base, trampoline_data, - trampoline_end - trampoline_data); + memcpy(trampoline_base, trampoline_data, TRAMPOLINE_SIZE); return virt_to_phys(trampoline_base); } diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 04d242ab0161967985bcb7f9e24f9fe54fb9f33f..141907ab6e2260adaa2f20cbcdc6747751184c64 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -481,11 +481,7 @@ do_nmi(struct pt_regs *regs, long error_code) { nmi_enter(); -#ifdef CONFIG_X86_32 - { int cpu; cpu = smp_processor_id(); ++nmi_count(cpu); } -#else - add_pda(__nmi_count, 1); -#endif + inc_irq_stat(__nmi_count); if (!ignore_nmis) default_do_nmi(regs); @@ -664,7 +660,7 @@ void math_error(void __user *ip) { struct task_struct *task; siginfo_t info; - unsigned short cwd, swd; + unsigned short cwd, swd, err; /* * Save the info for the exception handler and clear the error. @@ -675,7 +671,6 @@ void math_error(void __user *ip) task->thread.error_code = 0; info.si_signo = SIGFPE; info.si_errno = 0; - info.si_code = __SI_FAULT; info.si_addr = ip; /* * (~cwd & swd) will mask out exceptions that are not set to unmasked @@ -689,34 +684,31 @@ void math_error(void __user *ip) */ cwd = get_fpu_cwd(task); swd = get_fpu_swd(task); - switch (swd & ~cwd & 0x3f) { - case 0x000: /* No unmasked exception */ + + err = swd & ~cwd & 0x3f; + #ifdef CONFIG_X86_32 + if (!err) return; #endif - default: /* Multiple exceptions */ - break; - case 0x001: /* Invalid Op */ + + if (err & 0x001) { /* Invalid op */ /* * swd & 0x240 == 0x040: Stack Underflow * swd & 0x240 == 0x240: Stack Overflow * User must clear the SF bit (0x40) if set */ info.si_code = FPE_FLTINV; - break; - case 0x002: /* Denormalize */ - case 0x010: /* Underflow */ - info.si_code = FPE_FLTUND; - break; - case 0x004: /* Zero Divide */ + } else if (err & 0x004) { /* Divide by Zero */ info.si_code = FPE_FLTDIV; - break; - case 0x008: /* Overflow */ + } else if (err & 0x008) { /* Overflow */ info.si_code = FPE_FLTOVF; - break; - case 0x020: /* Precision */ + } else if (err & 0x012) { /* Denormal, Underflow */ + info.si_code = FPE_FLTUND; + } else if (err & 0x020) { /* Precision */ info.si_code = FPE_FLTRES; - break; + } else { + info.si_code = __SI_FAULT|SI_KERNEL; /* WTF? */ } force_sig_info(SIGFPE, &info, task); } diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index 424093b157d363dcad0bb58b8ed08636a9e0b61e..599e58168631e22e5ff69e15c365273bd2f9b03c 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -15,6 +15,7 @@ #include #include #include +#include unsigned int cpu_khz; /* TSC clocks / usec, not used here */ EXPORT_SYMBOL(cpu_khz); @@ -31,6 +32,7 @@ static int tsc_unstable; erroneous rdtsc usage on !cpu_has_tsc processors */ static int tsc_disabled = -1; +static int tsc_clocksource_reliable; /* * Scheduler clock - returns current time in nanosec units. */ @@ -98,6 +100,15 @@ int __init notsc_setup(char *str) __setup("notsc", notsc_setup); +static int __init tsc_setup(char *str) +{ + if (!strcmp(str, "reliable")) + tsc_clocksource_reliable = 1; + return 1; +} + +__setup("tsc=", tsc_setup); + #define MAX_RETRIES 5 #define SMI_TRESHOLD 50000 @@ -352,9 +363,15 @@ unsigned long native_calibrate_tsc(void) { u64 tsc1, tsc2, delta, ref1, ref2; unsigned long tsc_pit_min = ULONG_MAX, tsc_ref_min = ULONG_MAX; - unsigned long flags, latch, ms, fast_calibrate; + unsigned long flags, latch, ms, fast_calibrate, tsc_khz; int hpet = is_hpet_enabled(), i, loopmin; + tsc_khz = get_hypervisor_tsc_freq(); + if (tsc_khz) { + printk(KERN_INFO "TSC: Frequency read from the hypervisor\n"); + return tsc_khz; + } + local_irq_save(flags); fast_calibrate = quick_pit_calibrate(); local_irq_restore(flags); @@ -731,24 +748,21 @@ static struct dmi_system_id __initdata bad_tsc_dmi_table[] = { {} }; -/* - * Geode_LX - the OLPC CPU has a possibly a very reliable TSC - */ +static void __init check_system_tsc_reliable(void) +{ #ifdef CONFIG_MGEODE_LX -/* RTSC counts during suspend */ + /* RTSC counts during suspend */ #define RTSC_SUSP 0x100 - -static void __init check_geode_tsc_reliable(void) -{ unsigned long res_low, res_high; rdmsr_safe(MSR_GEODE_BUSCONT_CONF0, &res_low, &res_high); + /* Geode_LX - the OLPC CPU has a possibly a very reliable TSC */ if (res_low & RTSC_SUSP) - clocksource_tsc.flags &= ~CLOCK_SOURCE_MUST_VERIFY; -} -#else -static inline void check_geode_tsc_reliable(void) { } + tsc_clocksource_reliable = 1; #endif + if (boot_cpu_has(X86_FEATURE_TSC_RELIABLE)) + tsc_clocksource_reliable = 1; +} /* * Make an educated guess if the TSC is trustworthy and synchronized @@ -783,6 +797,8 @@ static void __init init_tsc_clocksource(void) { clocksource_tsc.mult = clocksource_khz2mult(tsc_khz, clocksource_tsc.shift); + if (tsc_clocksource_reliable) + clocksource_tsc.flags &= ~CLOCK_SOURCE_MUST_VERIFY; /* lower the rating if we already know its unstable: */ if (check_tsc_unstable()) { clocksource_tsc.rating = 0; @@ -843,7 +859,7 @@ void __init tsc_init(void) if (unsynchronized_tsc()) mark_tsc_unstable("TSCs unsynchronized"); - check_geode_tsc_reliable(); + check_system_tsc_reliable(); init_tsc_clocksource(); } diff --git a/arch/x86/kernel/tsc_sync.c b/arch/x86/kernel/tsc_sync.c index 1c0dfbca87c18a05beb42cebaa8e9ffed6d508a1..bf36328f6ef9289c4b1a1a7d0ffd9c67878f3f32 100644 --- a/arch/x86/kernel/tsc_sync.c +++ b/arch/x86/kernel/tsc_sync.c @@ -112,6 +112,12 @@ void __cpuinit check_tsc_sync_source(int cpu) if (unsynchronized_tsc()) return; + if (boot_cpu_has(X86_FEATURE_TSC_RELIABLE)) { + printk(KERN_INFO + "Skipping synchronization checks as TSC is reliable.\n"); + return; + } + printk(KERN_INFO "checking TSC synchronization [CPU#%d -> CPU#%d]:", smp_processor_id(), cpu); @@ -165,7 +171,7 @@ void __cpuinit check_tsc_sync_target(void) { int cpus = 2; - if (unsynchronized_tsc()) + if (unsynchronized_tsc() || boot_cpu_has(X86_FEATURE_TSC_RELIABLE)) return; /* diff --git a/arch/x86/kernel/vmi_32.c b/arch/x86/kernel/vmi_32.c index 22fd6577156a9ac81453792185e3cc0a317d96d2..23206ba16874ce5d6ace3d046ee35e95e721427c 100644 --- a/arch/x86/kernel/vmi_32.c +++ b/arch/x86/kernel/vmi_32.c @@ -266,109 +266,6 @@ static void vmi_nop(void) { } -#ifdef CONFIG_DEBUG_PAGE_TYPE - -#ifdef CONFIG_X86_PAE -#define MAX_BOOT_PTS (2048+4+1) -#else -#define MAX_BOOT_PTS (1024+1) -#endif - -/* - * During boot, mem_map is not yet available in paging_init, so stash - * all the boot page allocations here. - */ -static struct { - u32 pfn; - int type; -} boot_page_allocations[MAX_BOOT_PTS]; -static int num_boot_page_allocations; -static int boot_allocations_applied; - -void vmi_apply_boot_page_allocations(void) -{ - int i; - BUG_ON(!mem_map); - for (i = 0; i < num_boot_page_allocations; i++) { - struct page *page = pfn_to_page(boot_page_allocations[i].pfn); - page->type = boot_page_allocations[i].type; - page->type = boot_page_allocations[i].type & - ~(VMI_PAGE_ZEROED | VMI_PAGE_CLONE); - } - boot_allocations_applied = 1; -} - -static void record_page_type(u32 pfn, int type) -{ - BUG_ON(num_boot_page_allocations >= MAX_BOOT_PTS); - boot_page_allocations[num_boot_page_allocations].pfn = pfn; - boot_page_allocations[num_boot_page_allocations].type = type; - num_boot_page_allocations++; -} - -static void check_zeroed_page(u32 pfn, int type, struct page *page) -{ - u32 *ptr; - int i; - int limit = PAGE_SIZE / sizeof(int); - - if (page_address(page)) - ptr = (u32 *)page_address(page); - else - ptr = (u32 *)__va(pfn << PAGE_SHIFT); - /* - * When cloning the root in non-PAE mode, only the userspace - * pdes need to be zeroed. - */ - if (type & VMI_PAGE_CLONE) - limit = KERNEL_PGD_BOUNDARY; - for (i = 0; i < limit; i++) - BUG_ON(ptr[i]); -} - -/* - * We stash the page type into struct page so we can verify the page - * types are used properly. - */ -static void vmi_set_page_type(u32 pfn, int type) -{ - /* PAE can have multiple roots per page - don't track */ - if (PTRS_PER_PMD > 1 && (type & VMI_PAGE_PDP)) - return; - - if (boot_allocations_applied) { - struct page *page = pfn_to_page(pfn); - if (type != VMI_PAGE_NORMAL) - BUG_ON(page->type); - else - BUG_ON(page->type == VMI_PAGE_NORMAL); - page->type = type & ~(VMI_PAGE_ZEROED | VMI_PAGE_CLONE); - if (type & VMI_PAGE_ZEROED) - check_zeroed_page(pfn, type, page); - } else { - record_page_type(pfn, type); - } -} - -static void vmi_check_page_type(u32 pfn, int type) -{ - /* PAE can have multiple roots per page - skip checks */ - if (PTRS_PER_PMD > 1 && (type & VMI_PAGE_PDP)) - return; - - type &= ~(VMI_PAGE_ZEROED | VMI_PAGE_CLONE); - if (boot_allocations_applied) { - struct page *page = pfn_to_page(pfn); - BUG_ON((page->type ^ type) & VMI_PAGE_PAE); - BUG_ON(type == VMI_PAGE_NORMAL && page->type); - BUG_ON((type & page->type) == 0); - } -} -#else -#define vmi_set_page_type(p,t) do { } while (0) -#define vmi_check_page_type(p,t) do { } while (0) -#endif - #ifdef CONFIG_HIGHPTE static void *vmi_kmap_atomic_pte(struct page *page, enum km_type type) { @@ -395,7 +292,6 @@ static void *vmi_kmap_atomic_pte(struct page *page, enum km_type type) static void vmi_allocate_pte(struct mm_struct *mm, unsigned long pfn) { - vmi_set_page_type(pfn, VMI_PAGE_L1); vmi_ops.allocate_page(pfn, VMI_PAGE_L1, 0, 0, 0); } @@ -406,27 +302,22 @@ static void vmi_allocate_pmd(struct mm_struct *mm, unsigned long pfn) * It is called only for swapper_pg_dir, which already has * data on it. */ - vmi_set_page_type(pfn, VMI_PAGE_L2); vmi_ops.allocate_page(pfn, VMI_PAGE_L2, 0, 0, 0); } static void vmi_allocate_pmd_clone(unsigned long pfn, unsigned long clonepfn, unsigned long start, unsigned long count) { - vmi_set_page_type(pfn, VMI_PAGE_L2 | VMI_PAGE_CLONE); - vmi_check_page_type(clonepfn, VMI_PAGE_L2); vmi_ops.allocate_page(pfn, VMI_PAGE_L2 | VMI_PAGE_CLONE, clonepfn, start, count); } static void vmi_release_pte(unsigned long pfn) { vmi_ops.release_page(pfn, VMI_PAGE_L1); - vmi_set_page_type(pfn, VMI_PAGE_NORMAL); } static void vmi_release_pmd(unsigned long pfn) { vmi_ops.release_page(pfn, VMI_PAGE_L2); - vmi_set_page_type(pfn, VMI_PAGE_NORMAL); } /* @@ -450,26 +341,22 @@ static void vmi_release_pmd(unsigned long pfn) static void vmi_update_pte(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { - vmi_check_page_type(__pa(ptep) >> PAGE_SHIFT, VMI_PAGE_PTE); vmi_ops.update_pte(ptep, vmi_flags_addr(mm, addr, VMI_PAGE_PT, 0)); } static void vmi_update_pte_defer(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { - vmi_check_page_type(__pa(ptep) >> PAGE_SHIFT, VMI_PAGE_PTE); vmi_ops.update_pte(ptep, vmi_flags_addr_defer(mm, addr, VMI_PAGE_PT, 0)); } static void vmi_set_pte(pte_t *ptep, pte_t pte) { /* XXX because of set_pmd_pte, this can be called on PT or PD layers */ - vmi_check_page_type(__pa(ptep) >> PAGE_SHIFT, VMI_PAGE_PTE | VMI_PAGE_PD); vmi_ops.set_pte(pte, ptep, VMI_PAGE_PT); } static void vmi_set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte) { - vmi_check_page_type(__pa(ptep) >> PAGE_SHIFT, VMI_PAGE_PTE); vmi_ops.set_pte(pte, ptep, vmi_flags_addr(mm, addr, VMI_PAGE_PT, 0)); } @@ -477,10 +364,8 @@ static void vmi_set_pmd(pmd_t *pmdp, pmd_t pmdval) { #ifdef CONFIG_X86_PAE const pte_t pte = { .pte = pmdval.pmd }; - vmi_check_page_type(__pa(pmdp) >> PAGE_SHIFT, VMI_PAGE_PMD); #else const pte_t pte = { pmdval.pud.pgd.pgd }; - vmi_check_page_type(__pa(pmdp) >> PAGE_SHIFT, VMI_PAGE_PGD); #endif vmi_ops.set_pte(pte, (pte_t *)pmdp, VMI_PAGE_PD); } @@ -502,7 +387,6 @@ static void vmi_set_pte_atomic(pte_t *ptep, pte_t pteval) static void vmi_set_pte_present(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte) { - vmi_check_page_type(__pa(ptep) >> PAGE_SHIFT, VMI_PAGE_PTE); vmi_ops.set_pte(pte, ptep, vmi_flags_addr_defer(mm, addr, VMI_PAGE_PT, 1)); } @@ -510,21 +394,18 @@ static void vmi_set_pud(pud_t *pudp, pud_t pudval) { /* Um, eww */ const pte_t pte = { .pte = pudval.pgd.pgd }; - vmi_check_page_type(__pa(pudp) >> PAGE_SHIFT, VMI_PAGE_PGD); vmi_ops.set_pte(pte, (pte_t *)pudp, VMI_PAGE_PDP); } static void vmi_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { const pte_t pte = { .pte = 0 }; - vmi_check_page_type(__pa(ptep) >> PAGE_SHIFT, VMI_PAGE_PTE); vmi_ops.set_pte(pte, ptep, vmi_flags_addr(mm, addr, VMI_PAGE_PT, 0)); } static void vmi_pmd_clear(pmd_t *pmd) { const pte_t pte = { .pte = 0 }; - vmi_check_page_type(__pa(pmd) >> PAGE_SHIFT, VMI_PAGE_PMD); vmi_ops.set_pte(pte, (pte_t *)pmd, VMI_PAGE_PD); } #endif diff --git a/arch/x86/kernel/vmlinux_32.lds.S b/arch/x86/kernel/vmlinux_32.lds.S index a9b8560adbc22ebe37cfde9abcb7c46237fca3db..82c67559dde7858f6bd5a433e38e595dc0cec7cf 100644 --- a/arch/x86/kernel/vmlinux_32.lds.S +++ b/arch/x86/kernel/vmlinux_32.lds.S @@ -44,6 +44,7 @@ SECTIONS SCHED_TEXT LOCK_TEXT KPROBES_TEXT + IRQENTRY_TEXT *(.fixup) *(.gnu.warning) _etext = .; /* End of text section */ diff --git a/arch/x86/kernel/vmlinux_64.lds.S b/arch/x86/kernel/vmlinux_64.lds.S index 46e05447405b43855f46602f493847b75efa252a..1a614c0e6befcb5893dcb50dbc9cefac16907645 100644 --- a/arch/x86/kernel/vmlinux_64.lds.S +++ b/arch/x86/kernel/vmlinux_64.lds.S @@ -35,6 +35,7 @@ SECTIONS SCHED_TEXT LOCK_TEXT KPROBES_TEXT + IRQENTRY_TEXT *(.fixup) *(.gnu.warning) _etext = .; /* End of text section */ diff --git a/arch/x86/kernel/vsyscall_64.c b/arch/x86/kernel/vsyscall_64.c index 0b8b6690a86d184959703177b9cb6011bfd605ca..44153afc9067558cef387ba3237ffcf439ca3800 100644 --- a/arch/x86/kernel/vsyscall_64.c +++ b/arch/x86/kernel/vsyscall_64.c @@ -17,6 +17,9 @@ * want per guest time just set the kernel.vsyscall64 sysctl to 0. */ +/* Disable profiling for userspace code: */ +#define DISABLE_BRANCH_PROFILING + #include #include #include @@ -128,7 +131,16 @@ static __always_inline void do_vgettimeofday(struct timeval * tv) gettimeofday(tv,NULL); return; } + + /* + * Surround the RDTSC by barriers, to make sure it's not + * speculated to outside the seqlock critical section and + * does not cause time warps: + */ + rdtsc_barrier(); now = vread(); + rdtsc_barrier(); + base = __vsyscall_gtod_data.clock.cycle_last; mask = __vsyscall_gtod_data.clock.mask; mult = __vsyscall_gtod_data.clock.mult; diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c index a5d8e1ace1cf700922d1b7268401e4a4feed52c2..50a779264bb18fabcf21e3434f58a7963b1c691d 100644 --- a/arch/x86/lguest/boot.c +++ b/arch/x86/lguest/boot.c @@ -590,7 +590,8 @@ static void __init lguest_init_IRQ(void) * a straightforward 1 to 1 mapping, so force that here. */ __get_cpu_var(vector_irq)[vector] = i; if (vector != SYSCALL_VECTOR) { - set_intr_gate(vector, interrupt[vector]); + set_intr_gate(vector, + interrupt[vector-FIRST_EXTERNAL_VECTOR]); set_irq_chip_and_handler_name(i, &lguest_irq_controller, handle_level_irq, "level"); diff --git a/arch/x86/mach-generic/bigsmp.c b/arch/x86/mach-generic/bigsmp.c index 3c3b471ea496225e5a53029b92cfd5eeee658e43..3624a364b7f37ad8f7105956c15f4e1385dd66e8 100644 --- a/arch/x86/mach-generic/bigsmp.c +++ b/arch/x86/mach-generic/bigsmp.c @@ -17,6 +17,7 @@ #include #include #include +#include static int dmi_bigsmp; /* can be set by dmi scanners */ diff --git a/arch/x86/mach-generic/default.c b/arch/x86/mach-generic/default.c index 9e835a11a13a7cba9c16f2de4e5db0e54d9ecbc5..e63a4a76d8cdd2a966aec1299d941b5e5fb7196b 100644 --- a/arch/x86/mach-generic/default.c +++ b/arch/x86/mach-generic/default.c @@ -16,6 +16,7 @@ #include #include #include +#include /* should be called last. */ static int probe_default(void) diff --git a/arch/x86/mach-generic/es7000.c b/arch/x86/mach-generic/es7000.c index 28459cab3ddb5fdae0d560e5f766b141412e00bb..7b4e6d0d169001480eebb37c8b4bc3a32d1c6333 100644 --- a/arch/x86/mach-generic/es7000.c +++ b/arch/x86/mach-generic/es7000.c @@ -16,7 +16,19 @@ #include #include #include -#include +#include + +void __init es7000_update_genapic_to_cluster(void) +{ + genapic->target_cpus = target_cpus_cluster; + genapic->int_delivery_mode = INT_DELIVERY_MODE_CLUSTER; + genapic->int_dest_mode = INT_DEST_MODE_CLUSTER; + genapic->no_balance_irq = NO_BALANCE_IRQ_CLUSTER; + + genapic->init_apic_ldr = init_apic_ldr_cluster; + + genapic->cpu_mask_to_apicid = cpu_mask_to_apicid_cluster; +} static int probe_es7000(void) { diff --git a/arch/x86/mach-generic/probe.c b/arch/x86/mach-generic/probe.c index 5a7e4619e1c47589fc6745d5843c7ef743170318..c346d9d0226f313129917b091e4a4e94bcde6105 100644 --- a/arch/x86/mach-generic/probe.c +++ b/arch/x86/mach-generic/probe.c @@ -15,6 +15,7 @@ #include #include #include +#include extern struct genapic apic_numaq; extern struct genapic apic_summit; @@ -57,6 +58,9 @@ static int __init parse_apic(char *arg) } } + if (x86_quirks->update_genapic) + x86_quirks->update_genapic(); + /* Parsed again by __setup for debug/verbose */ return 0; } @@ -72,12 +76,15 @@ void __init generic_bigsmp_probe(void) * - we find more than 8 CPUs in acpi LAPIC listing with xAPIC support */ - if (!cmdline_apic && genapic == &apic_default) + if (!cmdline_apic && genapic == &apic_default) { if (apic_bigsmp.probe()) { genapic = &apic_bigsmp; + if (x86_quirks->update_genapic) + x86_quirks->update_genapic(); printk(KERN_INFO "Overriding APIC driver with %s\n", genapic->name); } + } #endif } @@ -94,6 +101,9 @@ void __init generic_apic_probe(void) /* Not visible without early console */ if (!apic_probe[i]) panic("Didn't find an APIC driver"); + + if (x86_quirks->update_genapic) + x86_quirks->update_genapic(); } printk(KERN_INFO "Using APIC driver %s\n", genapic->name); } @@ -108,6 +118,8 @@ int __init mps_oem_check(struct mp_config_table *mpc, char *oem, if (apic_probe[i]->mps_oem_check(mpc, oem, productid)) { if (!cmdline_apic) { genapic = apic_probe[i]; + if (x86_quirks->update_genapic) + x86_quirks->update_genapic(); printk(KERN_INFO "Switched to APIC driver `%s'.\n", genapic->name); } @@ -124,6 +136,8 @@ int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id) if (apic_probe[i]->acpi_madt_oem_check(oem_id, oem_table_id)) { if (!cmdline_apic) { genapic = apic_probe[i]; + if (x86_quirks->update_genapic) + x86_quirks->update_genapic(); printk(KERN_INFO "Switched to APIC driver `%s'.\n", genapic->name); } diff --git a/arch/x86/mach-generic/summit.c b/arch/x86/mach-generic/summit.c index 6272b5e69da62b28f660105d9a8788e4944432b3..2c6d234e0009ccd5b2ca50db816f599a5cd133b3 100644 --- a/arch/x86/mach-generic/summit.c +++ b/arch/x86/mach-generic/summit.c @@ -16,6 +16,7 @@ #include #include #include +#include static int probe_summit(void) { diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile index fea4565ff576b9f52f76d9286ece00ed52a4f141..d8cc96a2738f739a9f5dba76f77ee8c9a0885e6a 100644 --- a/arch/x86/mm/Makefile +++ b/arch/x86/mm/Makefile @@ -8,9 +8,8 @@ obj-$(CONFIG_X86_PTDUMP) += dump_pagetables.o obj-$(CONFIG_HIGHMEM) += highmem_32.o -obj-$(CONFIG_MMIOTRACE_HOOKS) += kmmio.o obj-$(CONFIG_MMIOTRACE) += mmiotrace.o -mmiotrace-y := pf_in.o mmio-mod.o +mmiotrace-y := kmmio.o pf_in.o mmio-mod.o obj-$(CONFIG_MMIOTRACE_TEST) += testmmiotrace.o obj-$(CONFIG_NUMA) += numa_$(BITS).o diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 31e8730fa2463214f36c2f6b3df9d0f75f6be346..57ec8c86a8776700729f682fc8a9b60b6a3482cd 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -53,7 +53,7 @@ static inline int kmmio_fault(struct pt_regs *regs, unsigned long addr) { -#ifdef CONFIG_MMIOTRACE_HOOKS +#ifdef CONFIG_MMIOTRACE if (unlikely(is_kmmio_active())) if (kmmio_handler(regs, addr) == 1) return -1; @@ -393,7 +393,7 @@ static void show_fault_oops(struct pt_regs *regs, unsigned long error_code, if (pte && pte_present(*pte) && !pte_exec(*pte)) printk(KERN_CRIT "kernel tried to execute " "NX-protected page - exploit attempt? " - "(uid: %d)\n", current->uid); + "(uid: %d)\n", current_uid()); } #endif @@ -413,6 +413,7 @@ static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs, unsigned long error_code) { unsigned long flags = oops_begin(); + int sig = SIGKILL; struct task_struct *tsk; printk(KERN_ALERT "%s: Corrupted page table at address %lx\n", @@ -423,8 +424,8 @@ static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs, tsk->thread.trap_no = 14; tsk->thread.error_code = error_code; if (__die("Bad pagetable", regs, error_code)) - regs = NULL; - oops_end(flags, regs, SIGKILL); + sig = 0; + oops_end(flags, regs, sig); } #endif @@ -590,6 +591,7 @@ void __kprobes do_page_fault(struct pt_regs *regs, unsigned long error_code) int fault; #ifdef CONFIG_X86_64 unsigned long flags; + int sig; #endif tsk = current; @@ -849,11 +851,12 @@ void __kprobes do_page_fault(struct pt_regs *regs, unsigned long error_code) bust_spinlocks(0); do_exit(SIGKILL); #else + sig = SIGKILL; if (__die("Oops", regs, error_code)) - regs = NULL; + sig = 0; /* Executive summary in case the body of the oops scrolled away */ printk(KERN_EMERG "CR2: %016lx\n", address); - oops_end(flags, regs, SIGKILL); + oops_end(flags, regs, sig); #endif /* diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c index c483f424207938cc16ff3a2eb6b92eee5175e6b5..800e1d94c1b5580e627ddb0a2ef81cfd10d031cd 100644 --- a/arch/x86/mm/init_32.c +++ b/arch/x86/mm/init_32.c @@ -67,7 +67,7 @@ static unsigned long __meminitdata table_top; static int __initdata after_init_bootmem; -static __init void *alloc_low_page(unsigned long *phys) +static __init void *alloc_low_page(void) { unsigned long pfn = table_end++; void *adr; @@ -77,7 +77,6 @@ static __init void *alloc_low_page(unsigned long *phys) adr = __va(pfn * PAGE_SIZE); memset(adr, 0, PAGE_SIZE); - *phys = pfn * PAGE_SIZE; return adr; } @@ -92,16 +91,17 @@ static pmd_t * __init one_md_table_init(pgd_t *pgd) pmd_t *pmd_table; #ifdef CONFIG_X86_PAE - unsigned long phys; if (!(pgd_val(*pgd) & _PAGE_PRESENT)) { if (after_init_bootmem) pmd_table = (pmd_t *)alloc_bootmem_low_pages(PAGE_SIZE); else - pmd_table = (pmd_t *)alloc_low_page(&phys); + pmd_table = (pmd_t *)alloc_low_page(); paravirt_alloc_pmd(&init_mm, __pa(pmd_table) >> PAGE_SHIFT); set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT)); pud = pud_offset(pgd, 0); BUG_ON(pmd_table != pmd_offset(pud, 0)); + + return pmd_table; } #endif pud = pud_offset(pgd, 0); @@ -126,10 +126,8 @@ static pte_t * __init one_page_table_init(pmd_t *pmd) if (!page_table) page_table = (pte_t *)alloc_bootmem_low_pages(PAGE_SIZE); - } else { - unsigned long phys; - page_table = (pte_t *)alloc_low_page(&phys); - } + } else + page_table = (pte_t *)alloc_low_page(); paravirt_alloc_pte(&init_mm, __pa(page_table) >> PAGE_SHIFT); set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE)); @@ -969,8 +967,6 @@ void __init mem_init(void) int codesize, reservedpages, datasize, initsize; int tmp; - start_periodic_check_for_corruption(); - #ifdef CONFIG_FLATMEM BUG_ON(!mem_map); #endif @@ -1040,11 +1036,25 @@ void __init mem_init(void) (unsigned long)&_text, (unsigned long)&_etext, ((unsigned long)&_etext - (unsigned long)&_text) >> 10); + /* + * Check boundaries twice: Some fundamental inconsistencies can + * be detected at build time already. + */ +#define __FIXADDR_TOP (-PAGE_SIZE) +#ifdef CONFIG_HIGHMEM + BUILD_BUG_ON(PKMAP_BASE + LAST_PKMAP*PAGE_SIZE > FIXADDR_START); + BUILD_BUG_ON(VMALLOC_END > PKMAP_BASE); +#endif +#define high_memory (-128UL << 20) + BUILD_BUG_ON(VMALLOC_START >= VMALLOC_END); +#undef high_memory +#undef __FIXADDR_TOP + #ifdef CONFIG_HIGHMEM BUG_ON(PKMAP_BASE + LAST_PKMAP*PAGE_SIZE > FIXADDR_START); BUG_ON(VMALLOC_END > PKMAP_BASE); #endif - BUG_ON(VMALLOC_START > VMALLOC_END); + BUG_ON(VMALLOC_START >= VMALLOC_END); BUG_ON((unsigned long)high_memory > VMALLOC_START); if (boot_cpu_data.wp_works_ok < 0) diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index 9db01db6e3cdf4cb0e11444d49e4d598be280b55..9f7a0d24d42a93b47e36d3ce40c70876f5d09e16 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -902,8 +902,6 @@ void __init mem_init(void) long codesize, reservedpages, datasize, initsize; unsigned long absent_pages; - start_periodic_check_for_corruption(); - pci_iommu_alloc(); /* clear_bss() already clear the empty_zero_page */ diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c index d4c4307ff3e049f1454c3629fb2989f63395ae68..bd85d42819e1eadad218a266cdade7e00bf7659a 100644 --- a/arch/x86/mm/ioremap.c +++ b/arch/x86/mm/ioremap.c @@ -223,7 +223,8 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr, * Check if the request spans more than any BAR in the iomem resource * tree. */ - WARN_ON(iomem_map_sanity_check(phys_addr, size)); + WARN_ONCE(iomem_map_sanity_check(phys_addr, size), + KERN_INFO "Info: mapping multiple BARs. Your kernel is fine."); /* * Don't allow anybody to remap normal RAM that we're using.. diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c index eb1bf000d12e9b1aa1769284e263d43593095183..85cbd3cd3723698ed51707d01fa75d8000f81477 100644 --- a/arch/x86/mm/pat.c +++ b/arch/x86/mm/pat.c @@ -596,6 +596,242 @@ void unmap_devmem(unsigned long pfn, unsigned long size, pgprot_t vma_prot) free_memtype(addr, addr + size); } +/* + * Internal interface to reserve a range of physical memory with prot. + * Reserved non RAM regions only and after successful reserve_memtype, + * this func also keeps identity mapping (if any) in sync with this new prot. + */ +static int reserve_pfn_range(u64 paddr, unsigned long size, pgprot_t vma_prot) +{ + int is_ram = 0; + int id_sz, ret; + unsigned long flags; + unsigned long want_flags = (pgprot_val(vma_prot) & _PAGE_CACHE_MASK); + + is_ram = pagerange_is_ram(paddr, paddr + size); + + if (is_ram != 0) { + /* + * For mapping RAM pages, drivers need to call + * set_memory_[uc|wc|wb] directly, for reserve and free, before + * setting up the PTE. + */ + WARN_ON_ONCE(1); + return 0; + } + + ret = reserve_memtype(paddr, paddr + size, want_flags, &flags); + if (ret) + return ret; + + if (flags != want_flags) { + free_memtype(paddr, paddr + size); + printk(KERN_ERR + "%s:%d map pfn expected mapping type %s for %Lx-%Lx, got %s\n", + current->comm, current->pid, + cattr_name(want_flags), + (unsigned long long)paddr, + (unsigned long long)(paddr + size), + cattr_name(flags)); + return -EINVAL; + } + + /* Need to keep identity mapping in sync */ + if (paddr >= __pa(high_memory)) + return 0; + + id_sz = (__pa(high_memory) < paddr + size) ? + __pa(high_memory) - paddr : + size; + + if (ioremap_change_attr((unsigned long)__va(paddr), id_sz, flags) < 0) { + free_memtype(paddr, paddr + size); + printk(KERN_ERR + "%s:%d reserve_pfn_range ioremap_change_attr failed %s " + "for %Lx-%Lx\n", + current->comm, current->pid, + cattr_name(flags), + (unsigned long long)paddr, + (unsigned long long)(paddr + size)); + return -EINVAL; + } + return 0; +} + +/* + * Internal interface to free a range of physical memory. + * Frees non RAM regions only. + */ +static void free_pfn_range(u64 paddr, unsigned long size) +{ + int is_ram; + + is_ram = pagerange_is_ram(paddr, paddr + size); + if (is_ram == 0) + free_memtype(paddr, paddr + size); +} + +/* + * track_pfn_vma_copy is called when vma that is covering the pfnmap gets + * copied through copy_page_range(). + * + * If the vma has a linear pfn mapping for the entire range, we get the prot + * from pte and reserve the entire vma range with single reserve_pfn_range call. + * Otherwise, we reserve the entire vma range, my ging through the PTEs page + * by page to get physical address and protection. + */ +int track_pfn_vma_copy(struct vm_area_struct *vma) +{ + int retval = 0; + unsigned long i, j; + resource_size_t paddr; + unsigned long prot; + unsigned long vma_start = vma->vm_start; + unsigned long vma_end = vma->vm_end; + unsigned long vma_size = vma_end - vma_start; + + if (!pat_enabled) + return 0; + + if (is_linear_pfn_mapping(vma)) { + /* + * reserve the whole chunk covered by vma. We need the + * starting address and protection from pte. + */ + if (follow_phys(vma, vma_start, 0, &prot, &paddr)) { + WARN_ON_ONCE(1); + return -EINVAL; + } + return reserve_pfn_range(paddr, vma_size, __pgprot(prot)); + } + + /* reserve entire vma page by page, using pfn and prot from pte */ + for (i = 0; i < vma_size; i += PAGE_SIZE) { + if (follow_phys(vma, vma_start + i, 0, &prot, &paddr)) + continue; + + retval = reserve_pfn_range(paddr, PAGE_SIZE, __pgprot(prot)); + if (retval) + goto cleanup_ret; + } + return 0; + +cleanup_ret: + /* Reserve error: Cleanup partial reservation and return error */ + for (j = 0; j < i; j += PAGE_SIZE) { + if (follow_phys(vma, vma_start + j, 0, &prot, &paddr)) + continue; + + free_pfn_range(paddr, PAGE_SIZE); + } + + return retval; +} + +/* + * track_pfn_vma_new is called when a _new_ pfn mapping is being established + * for physical range indicated by pfn and size. + * + * prot is passed in as a parameter for the new mapping. If the vma has a + * linear pfn mapping for the entire range reserve the entire vma range with + * single reserve_pfn_range call. + * Otherwise, we look t the pfn and size and reserve only the specified range + * page by page. + * + * Note that this function can be called with caller trying to map only a + * subrange/page inside the vma. + */ +int track_pfn_vma_new(struct vm_area_struct *vma, pgprot_t prot, + unsigned long pfn, unsigned long size) +{ + int retval = 0; + unsigned long i, j; + resource_size_t base_paddr; + resource_size_t paddr; + unsigned long vma_start = vma->vm_start; + unsigned long vma_end = vma->vm_end; + unsigned long vma_size = vma_end - vma_start; + + if (!pat_enabled) + return 0; + + if (is_linear_pfn_mapping(vma)) { + /* reserve the whole chunk starting from vm_pgoff */ + paddr = (resource_size_t)vma->vm_pgoff << PAGE_SHIFT; + return reserve_pfn_range(paddr, vma_size, prot); + } + + /* reserve page by page using pfn and size */ + base_paddr = (resource_size_t)pfn << PAGE_SHIFT; + for (i = 0; i < size; i += PAGE_SIZE) { + paddr = base_paddr + i; + retval = reserve_pfn_range(paddr, PAGE_SIZE, prot); + if (retval) + goto cleanup_ret; + } + return 0; + +cleanup_ret: + /* Reserve error: Cleanup partial reservation and return error */ + for (j = 0; j < i; j += PAGE_SIZE) { + paddr = base_paddr + j; + free_pfn_range(paddr, PAGE_SIZE); + } + + return retval; +} + +/* + * untrack_pfn_vma is called while unmapping a pfnmap for a region. + * untrack can be called for a specific region indicated by pfn and size or + * can be for the entire vma (in which case size can be zero). + */ +void untrack_pfn_vma(struct vm_area_struct *vma, unsigned long pfn, + unsigned long size) +{ + unsigned long i; + resource_size_t paddr; + unsigned long prot; + unsigned long vma_start = vma->vm_start; + unsigned long vma_end = vma->vm_end; + unsigned long vma_size = vma_end - vma_start; + + if (!pat_enabled) + return; + + if (is_linear_pfn_mapping(vma)) { + /* free the whole chunk starting from vm_pgoff */ + paddr = (resource_size_t)vma->vm_pgoff << PAGE_SHIFT; + free_pfn_range(paddr, vma_size); + return; + } + + if (size != 0 && size != vma_size) { + /* free page by page, using pfn and size */ + paddr = (resource_size_t)pfn << PAGE_SHIFT; + for (i = 0; i < size; i += PAGE_SIZE) { + paddr = paddr + i; + free_pfn_range(paddr, PAGE_SIZE); + } + } else { + /* free entire vma, page by page, using the pfn from pte */ + for (i = 0; i < vma_size; i += PAGE_SIZE) { + if (follow_phys(vma, vma_start + i, 0, &prot, &paddr)) + continue; + + free_pfn_range(paddr, PAGE_SIZE); + } + } +} + +pgprot_t pgprot_writecombine(pgprot_t prot) +{ + if (pat_enabled) + return __pgprot(pgprot_val(prot) | _PAGE_CACHE_WC); + else + return pgprot_noncached(prot); +} + #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_X86_PAT) /* get Nth element of the linked list */ diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c index b67732bbb85a3a562063c36e579ee769ccdf86c1..bb1a01f089e29c817432907a820ca7a06f727347 100644 --- a/arch/x86/pci/common.c +++ b/arch/x86/pci/common.c @@ -23,6 +23,12 @@ unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 | unsigned int pci_early_dump_regs; static int pci_bf_sort; int pci_routeirq; +int noioapicquirk; +#ifdef CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS +int noioapicreroute = 0; +#else +int noioapicreroute = 1; +#endif int pcibios_last_bus = -1; unsigned long pirq_table_addr; struct pci_bus *pci_root_bus; @@ -519,6 +525,17 @@ char * __devinit pcibios_setup(char *str) } else if (!strcmp(str, "skip_isa_align")) { pci_probe |= PCI_CAN_SKIP_ISA_ALIGN; return NULL; + } else if (!strcmp(str, "noioapicquirk")) { + noioapicquirk = 1; + return NULL; + } else if (!strcmp(str, "ioapicreroute")) { + if (noioapicreroute != -1) + noioapicreroute = 0; + return NULL; + } else if (!strcmp(str, "noioapicreroute")) { + if (noioapicreroute != -1) + noioapicreroute = 1; + return NULL; } return str; } diff --git a/arch/x86/pci/direct.c b/arch/x86/pci/direct.c index 9915293500fb69ebdae0b8d80b69155f180f1274..9a5af6c8fbe9fc445fdca3358b90666c9ecae7bb 100644 --- a/arch/x86/pci/direct.c +++ b/arch/x86/pci/direct.c @@ -173,7 +173,7 @@ static int pci_conf2_write(unsigned int seg, unsigned int bus, #undef PCI_CONF2_ADDRESS -static struct pci_raw_ops pci_direct_conf2 = { +struct pci_raw_ops pci_direct_conf2 = { .read = pci_conf2_read, .write = pci_conf2_write, }; @@ -289,6 +289,7 @@ int __init pci_direct_probe(void) if (pci_check_type1()) { raw_pci_ops = &pci_direct_conf1; + port_cf9_safe = true; return 1; } release_resource(region); @@ -305,6 +306,7 @@ int __init pci_direct_probe(void) if (pci_check_type2()) { raw_pci_ops = &pci_direct_conf2; + port_cf9_safe = true; return 2; } diff --git a/arch/x86/pci/pci.h b/arch/x86/pci/pci.h index 15b9cf6be729c0c7cddee3ff54d1ce9809f32d58..1959018aac025ea3a38048973e6cc7a107396684 100644 --- a/arch/x86/pci/pci.h +++ b/arch/x86/pci/pci.h @@ -96,6 +96,7 @@ extern struct pci_raw_ops *raw_pci_ops; extern struct pci_raw_ops *raw_pci_ext_ops; extern struct pci_raw_ops pci_direct_conf1; +extern bool port_cf9_safe; /* arch_initcall level */ extern int pci_direct_probe(void); diff --git a/arch/x86/scripts/strip-symbols b/arch/x86/scripts/strip-symbols new file mode 100644 index 0000000000000000000000000000000000000000..a2f1ccb827c7437e853a7f258b2119e29840bef0 --- /dev/null +++ b/arch/x86/scripts/strip-symbols @@ -0,0 +1 @@ +__cpu_vendor_dev_X86_VENDOR_* diff --git a/arch/x86/vdso/vclock_gettime.c b/arch/x86/vdso/vclock_gettime.c index 1ef0f90813d626ed6be436b93d3d5b6550dbb392..d9d35824c56f30e56266445cdf9ed5877f94bf52 100644 --- a/arch/x86/vdso/vclock_gettime.c +++ b/arch/x86/vdso/vclock_gettime.c @@ -9,6 +9,9 @@ * Also alternative() doesn't work. */ +/* Disable profiling for userspace code: */ +#define DISABLE_BRANCH_PROFILING + #include #include #include diff --git a/arch/x86/vdso/vdso32-setup.c b/arch/x86/vdso/vdso32-setup.c index 513f330c58326b2126e6cfe4c78214eaa77226e8..1241f118ab561b181b5dd9634f5c80d7783de493 100644 --- a/arch/x86/vdso/vdso32-setup.c +++ b/arch/x86/vdso/vdso32-setup.c @@ -310,7 +310,7 @@ int __init sysenter_setup(void) } /* Setup a VMA at program startup for the vsyscall page */ -int arch_setup_additional_pages(struct linux_binprm *bprm, int exstack) +int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) { struct mm_struct *mm = current->mm; unsigned long addr; diff --git a/arch/x86/vdso/vma.c b/arch/x86/vdso/vma.c index 257ba4a10abf0740ee908d2ff1369c77d7d31b50..9c98cc6ba9783ce1c1caac812341924e43ae98aa 100644 --- a/arch/x86/vdso/vma.c +++ b/arch/x86/vdso/vma.c @@ -98,7 +98,7 @@ static unsigned long vdso_addr(unsigned long start, unsigned len) /* Setup a VMA at program startup for the vsyscall page. Not called for compat tasks */ -int arch_setup_additional_pages(struct linux_binprm *bprm, int exstack) +int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) { struct mm_struct *mm = current->mm; unsigned long addr; diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 5e4686d70f629de22f81adc96b658ab06216be24..bea215230b20cdf4fc41ac5fd4e060dcbaec4ec1 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -793,7 +794,7 @@ static int xen_write_msr_safe(unsigned int msr, unsigned low, unsigned high) ret = 0; - switch(msr) { + switch (msr) { #ifdef CONFIG_X86_64 unsigned which; u64 base; @@ -1453,7 +1454,7 @@ static __init void xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn) ident_pte = 0; pfn = 0; - for(pmdidx = 0; pmdidx < PTRS_PER_PMD && pfn < max_pfn; pmdidx++) { + for (pmdidx = 0; pmdidx < PTRS_PER_PMD && pfn < max_pfn; pmdidx++) { pte_t *pte_page; /* Reuse or allocate a page of ptes */ @@ -1471,7 +1472,7 @@ static __init void xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn) } /* Install mappings */ - for(pteidx = 0; pteidx < PTRS_PER_PTE; pteidx++, pfn++) { + for (pteidx = 0; pteidx < PTRS_PER_PTE; pteidx++, pfn++) { pte_t pte; if (pfn > max_pfn_mapped) @@ -1485,7 +1486,7 @@ static __init void xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn) } } - for(pteidx = 0; pteidx < ident_pte; pteidx += PTRS_PER_PTE) + for (pteidx = 0; pteidx < ident_pte; pteidx += PTRS_PER_PTE) set_page_prot(&level1_ident_pgt[pteidx], PAGE_KERNEL_RO); set_page_prot(pmd, PAGE_KERNEL_RO); @@ -1499,7 +1500,7 @@ static void convert_pfn_mfn(void *v) /* All levels are converted the same way, so just treat them as ptes. */ - for(i = 0; i < PTRS_PER_PTE; i++) + for (i = 0; i < PTRS_PER_PTE; i++) pte[i] = xen_make_pte(pte[i].pte); } @@ -1514,7 +1515,8 @@ static void convert_pfn_mfn(void *v) * of the physical mapping once some sort of allocator has been set * up. */ -static __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pfn) +static __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd, + unsigned long max_pfn) { pud_t *l3; pmd_t *l2; @@ -1577,7 +1579,8 @@ static __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pf #else /* !CONFIG_X86_64 */ static pmd_t level2_kernel_pgt[PTRS_PER_PMD] __page_aligned_bss; -static __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pfn) +static __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd, + unsigned long max_pfn) { pmd_t *kernel_pmd; diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index 636ef4caa52d3dee2a24fc3b1913fe23b8ab34db..773d68d3e9128eba414a31ae3fa3dbc989033d72 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c @@ -154,13 +154,13 @@ void xen_setup_mfn_list_list(void) { unsigned pfn, idx; - for(pfn = 0; pfn < MAX_DOMAIN_PAGES; pfn += P2M_ENTRIES_PER_PAGE) { + for (pfn = 0; pfn < MAX_DOMAIN_PAGES; pfn += P2M_ENTRIES_PER_PAGE) { unsigned topidx = p2m_top_index(pfn); p2m_top_mfn[topidx] = virt_to_mfn(p2m_top[topidx]); } - for(idx = 0; idx < ARRAY_SIZE(p2m_top_mfn_list); idx++) { + for (idx = 0; idx < ARRAY_SIZE(p2m_top_mfn_list); idx++) { unsigned topidx = idx * P2M_ENTRIES_PER_PAGE; p2m_top_mfn_list[idx] = virt_to_mfn(&p2m_top_mfn[topidx]); } @@ -179,7 +179,7 @@ void __init xen_build_dynamic_phys_to_machine(void) unsigned long max_pfn = min(MAX_DOMAIN_PAGES, xen_start_info->nr_pages); unsigned pfn; - for(pfn = 0; pfn < max_pfn; pfn += P2M_ENTRIES_PER_PAGE) { + for (pfn = 0; pfn < max_pfn; pfn += P2M_ENTRIES_PER_PAGE) { unsigned topidx = p2m_top_index(pfn); p2m_top[topidx] = &mfn_list[pfn]; @@ -207,7 +207,7 @@ static void alloc_p2m(unsigned long **pp, unsigned long *mfnp) p = (void *)__get_free_page(GFP_KERNEL | __GFP_NOFAIL); BUG_ON(p == NULL); - for(i = 0; i < P2M_ENTRIES_PER_PAGE; i++) + for (i = 0; i < P2M_ENTRIES_PER_PAGE; i++) p[i] = INVALID_P2M_ENTRY; if (cmpxchg(pp, p2m_missing, p) != p2m_missing) @@ -407,7 +407,8 @@ void xen_set_pte_at(struct mm_struct *mm, unsigned long addr, preempt_enable(); } -pte_t xen_ptep_modify_prot_start(struct mm_struct *mm, unsigned long addr, pte_t *ptep) +pte_t xen_ptep_modify_prot_start(struct mm_struct *mm, + unsigned long addr, pte_t *ptep) { /* Just return the pte as-is. We preserve the bits on commit */ return *ptep; @@ -878,7 +879,8 @@ static void __xen_pgd_pin(struct mm_struct *mm, pgd_t *pgd) if (user_pgd) { xen_pin_page(mm, virt_to_page(user_pgd), PT_PGD); - xen_do_pin(MMUEXT_PIN_L4_TABLE, PFN_DOWN(__pa(user_pgd))); + xen_do_pin(MMUEXT_PIN_L4_TABLE, + PFN_DOWN(__pa(user_pgd))); } } #else /* CONFIG_X86_32 */ @@ -993,7 +995,8 @@ static void __xen_pgd_unpin(struct mm_struct *mm, pgd_t *pgd) pgd_t *user_pgd = xen_get_user_pgd(pgd); if (user_pgd) { - xen_do_pin(MMUEXT_UNPIN_TABLE, PFN_DOWN(__pa(user_pgd))); + xen_do_pin(MMUEXT_UNPIN_TABLE, + PFN_DOWN(__pa(user_pgd))); xen_unpin_page(mm, virt_to_page(user_pgd), PT_PGD); } } diff --git a/arch/x86/xen/multicalls.c b/arch/x86/xen/multicalls.c index 8ea8a0d0b0deeff69a438a5ad4fc0552d250d68f..c738644b543502d6577ee07b42c25f6e52493131 100644 --- a/arch/x86/xen/multicalls.c +++ b/arch/x86/xen/multicalls.c @@ -154,7 +154,7 @@ void xen_mc_flush(void) ret, smp_processor_id()); dump_stack(); for (i = 0; i < b->mcidx; i++) { - printk(" call %2d/%d: op=%lu arg=[%lx] result=%ld\n", + printk(KERN_DEBUG " call %2d/%d: op=%lu arg=[%lx] result=%ld\n", i+1, b->mcidx, b->debug[i].op, b->debug[i].args[0], diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c index d679010838883195da63cfa7a7bbef7cfa71fe03..15c6c68db6a25f4941d25e8fc35857a3d518dc5d 100644 --- a/arch/x86/xen/setup.c +++ b/arch/x86/xen/setup.c @@ -28,6 +28,9 @@ /* These are code, but not functions. Defined in entry.S */ extern const char xen_hypervisor_callback[]; extern const char xen_failsafe_callback[]; +extern void xen_sysenter_target(void); +extern void xen_syscall_target(void); +extern void xen_syscall32_target(void); /** @@ -110,7 +113,6 @@ static __cpuinit int register_callback(unsigned type, const void *func) void __cpuinit xen_enable_sysenter(void) { - extern void xen_sysenter_target(void); int ret; unsigned sysenter_feature; @@ -132,8 +134,6 @@ void __cpuinit xen_enable_syscall(void) { #ifdef CONFIG_X86_64 int ret; - extern void xen_syscall_target(void); - extern void xen_syscall32_target(void); ret = register_callback(CALLBACKTYPE_syscall, xen_syscall_target); if (ret != 0) { @@ -160,7 +160,8 @@ void __init xen_arch_setup(void) HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_writable_pagetables); if (!xen_feature(XENFEAT_auto_translated_physmap)) - HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_pae_extended_cr3); + HYPERVISOR_vm_assist(VMASST_CMD_enable, + VMASST_TYPE_pae_extended_cr3); if (register_callback(CALLBACKTYPE_event, xen_hypervisor_callback) || register_callback(CALLBACKTYPE_failsafe, xen_failsafe_callback)) diff --git a/arch/xtensa/platforms/iss/network.c b/arch/xtensa/platforms/iss/network.c index 11a20adc140999b96b5b76f844c9e8fedd00c9f0..64f057d89e7302f929e535d9ca3bbcea7867d91d 100644 --- a/arch/xtensa/platforms/iss/network.c +++ b/arch/xtensa/platforms/iss/network.c @@ -365,7 +365,7 @@ static int tuntap_probe(struct iss_net_private *lp, int index, char *init) static int iss_net_rx(struct net_device *dev) { - struct iss_net_private *lp = dev->priv; + struct iss_net_private *lp = netdev_priv(dev); int pkt_len; struct sk_buff *skb; @@ -456,7 +456,7 @@ static void iss_net_timer(unsigned long priv) static int iss_net_open(struct net_device *dev) { - struct iss_net_private *lp = dev->priv; + struct iss_net_private *lp = netdev_priv(dev); char addr[sizeof "255.255.255.255\0"]; int err; @@ -496,7 +496,7 @@ static int iss_net_open(struct net_device *dev) static int iss_net_close(struct net_device *dev) { - struct iss_net_private *lp = dev->priv; + struct iss_net_private *lp = netdev_priv(dev); printk("iss_net_close!\n"); netif_stop_queue(dev); spin_lock(&lp->lock); @@ -515,7 +515,7 @@ printk("iss_net_close!\n"); static int iss_net_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct iss_net_private *lp = dev->priv; + struct iss_net_private *lp = netdev_priv(dev); unsigned long flags; int len; @@ -551,7 +551,7 @@ static int iss_net_start_xmit(struct sk_buff *skb, struct net_device *dev) static struct net_device_stats *iss_net_get_stats(struct net_device *dev) { - struct iss_net_private *lp = dev->priv; + struct iss_net_private *lp = netdev_priv(dev); return &lp->stats; } @@ -578,7 +578,7 @@ static void iss_net_tx_timeout(struct net_device *dev) static int iss_net_set_mac(struct net_device *dev, void *addr) { #if 0 - struct iss_net_private *lp = dev->priv; + struct iss_net_private *lp = netdev_priv(dev); struct sockaddr *hwaddr = addr; spin_lock(&lp->lock); @@ -592,7 +592,7 @@ static int iss_net_set_mac(struct net_device *dev, void *addr) static int iss_net_change_mtu(struct net_device *dev, int new_mtu) { #if 0 - struct iss_net_private *lp = dev->priv; + struct iss_net_private *lp = netdev_priv(dev); int err = 0; spin_lock(&lp->lock); @@ -636,7 +636,7 @@ static int iss_net_configure(int index, char *init) /* Initialize private element. */ - lp = dev->priv; + lp = netdev_priv(dev); *lp = ((struct iss_net_private) { .device_list = LIST_HEAD_INIT(lp->device_list), .opened_list = LIST_HEAD_INIT(lp->opened_list), @@ -660,10 +660,7 @@ static int iss_net_configure(int index, char *init) printk(KERN_INFO "Netdevice %d ", index); if (lp->have_mac) - printk("(%02x:%02x:%02x:%02x:%02x:%02x) ", - lp->mac[0], lp->mac[1], - lp->mac[2], lp->mac[3], - lp->mac[4], lp->mac[5]); + printk("(%pM) ", lp->mac); printk(": "); /* sysfs register */ diff --git a/block/Kconfig b/block/Kconfig index 1ab7c15c8d7a58bc2df639a759a0b719bb2c25da..290b219fad9c5a1b825d495c8ea427bda7b04c5c 100644 --- a/block/Kconfig +++ b/block/Kconfig @@ -47,6 +47,7 @@ config BLK_DEV_IO_TRACE depends on SYSFS select RELAY select DEBUG_FS + select TRACEPOINTS help Say Y here if you want to be able to trace the block layer actions on a given queue. Tracing allows you to see any traffic happening diff --git a/block/blk-core.c b/block/blk-core.c index c36aa98fafa3e4ed94adcf3e462945d59b0c1fcd..561e8a1b43a4a526e405905c69cf8f0e15a4df27 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -28,9 +28,23 @@ #include #include #include +#include #include "blk.h" +DEFINE_TRACE(block_plug); +DEFINE_TRACE(block_unplug_io); +DEFINE_TRACE(block_unplug_timer); +DEFINE_TRACE(block_getrq); +DEFINE_TRACE(block_sleeprq); +DEFINE_TRACE(block_rq_requeue); +DEFINE_TRACE(block_bio_backmerge); +DEFINE_TRACE(block_bio_frontmerge); +DEFINE_TRACE(block_bio_queue); +DEFINE_TRACE(block_rq_complete); +DEFINE_TRACE(block_remap); /* Also used in drivers/md/dm.c */ +EXPORT_TRACEPOINT_SYMBOL_GPL(block_remap); + static int __make_request(struct request_queue *q, struct bio *bio); /* @@ -205,7 +219,7 @@ void blk_plug_device(struct request_queue *q) if (!queue_flag_test_and_set(QUEUE_FLAG_PLUGGED, q)) { mod_timer(&q->unplug_timer, jiffies + q->unplug_delay); - blk_add_trace_generic(q, NULL, 0, BLK_TA_PLUG); + trace_block_plug(q); } } EXPORT_SYMBOL(blk_plug_device); @@ -292,9 +306,7 @@ void blk_unplug_work(struct work_struct *work) struct request_queue *q = container_of(work, struct request_queue, unplug_work); - blk_add_trace_pdu_int(q, BLK_TA_UNPLUG_IO, NULL, - q->rq.count[READ] + q->rq.count[WRITE]); - + trace_block_unplug_io(q); q->unplug_fn(q); } @@ -302,9 +314,7 @@ void blk_unplug_timeout(unsigned long data) { struct request_queue *q = (struct request_queue *)data; - blk_add_trace_pdu_int(q, BLK_TA_UNPLUG_TIMER, NULL, - q->rq.count[READ] + q->rq.count[WRITE]); - + trace_block_unplug_timer(q); kblockd_schedule_work(q, &q->unplug_work); } @@ -314,9 +324,7 @@ void blk_unplug(struct request_queue *q) * devices don't necessarily have an ->unplug_fn defined */ if (q->unplug_fn) { - blk_add_trace_pdu_int(q, BLK_TA_UNPLUG_IO, NULL, - q->rq.count[READ] + q->rq.count[WRITE]); - + trace_block_unplug_io(q); q->unplug_fn(q); } } @@ -822,7 +830,7 @@ static struct request *get_request(struct request_queue *q, int rw_flags, if (ioc_batching(q, ioc)) ioc->nr_batch_requests--; - blk_add_trace_generic(q, bio, rw, BLK_TA_GETRQ); + trace_block_getrq(q, bio, rw); out: return rq; } @@ -848,7 +856,7 @@ static struct request *get_request_wait(struct request_queue *q, int rw_flags, prepare_to_wait_exclusive(&rl->wait[rw], &wait, TASK_UNINTERRUPTIBLE); - blk_add_trace_generic(q, bio, rw, BLK_TA_SLEEPRQ); + trace_block_sleeprq(q, bio, rw); __generic_unplug_device(q); spin_unlock_irq(q->queue_lock); @@ -928,7 +936,7 @@ void blk_requeue_request(struct request_queue *q, struct request *rq) { blk_delete_timer(rq); blk_clear_rq_complete(rq); - blk_add_trace_rq(q, rq, BLK_TA_REQUEUE); + trace_block_rq_requeue(q, rq); if (blk_rq_tagged(rq)) blk_queue_end_tag(q, rq); @@ -1167,7 +1175,7 @@ static int __make_request(struct request_queue *q, struct bio *bio) if (!ll_back_merge_fn(q, req, bio)) break; - blk_add_trace_bio(q, bio, BLK_TA_BACKMERGE); + trace_block_bio_backmerge(q, bio); req->biotail->bi_next = bio; req->biotail = bio; @@ -1186,7 +1194,7 @@ static int __make_request(struct request_queue *q, struct bio *bio) if (!ll_front_merge_fn(q, req, bio)) break; - blk_add_trace_bio(q, bio, BLK_TA_FRONTMERGE); + trace_block_bio_frontmerge(q, bio); bio->bi_next = req->bio; req->bio = bio; @@ -1269,7 +1277,7 @@ static inline void blk_partition_remap(struct bio *bio) bio->bi_sector += p->start_sect; bio->bi_bdev = bdev->bd_contains; - blk_add_trace_remap(bdev_get_queue(bio->bi_bdev), bio, + trace_block_remap(bdev_get_queue(bio->bi_bdev), bio, bdev->bd_dev, bio->bi_sector, bio->bi_sector - p->start_sect); } @@ -1441,10 +1449,10 @@ static inline void __generic_make_request(struct bio *bio) goto end_io; if (old_sector != -1) - blk_add_trace_remap(q, bio, old_dev, bio->bi_sector, + trace_block_remap(q, bio, old_dev, bio->bi_sector, old_sector); - blk_add_trace_bio(q, bio, BLK_TA_QUEUE); + trace_block_bio_queue(q, bio); old_sector = bio->bi_sector; old_dev = bio->bi_bdev->bd_dev; @@ -1678,7 +1686,7 @@ static int __end_that_request_first(struct request *req, int error, int total_bytes, bio_nbytes, next_idx = 0; struct bio *bio; - blk_add_trace_rq(req->q, req, BLK_TA_COMPLETE); + trace_block_rq_complete(req->q, req); /* * for a REQ_TYPE_BLOCK_PC request, we want to carry any eventual diff --git a/block/blktrace.c b/block/blktrace.c index 85049a7e7a179a97c283eb4ebe6c1fe7285f80cf..b0a2cae886dbdc4dde9a2efa99345ea2462a54b0 100644 --- a/block/blktrace.c +++ b/block/blktrace.c @@ -23,10 +23,18 @@ #include #include #include +#include #include static unsigned int blktrace_seq __read_mostly = 1; +/* Global reference count of probes */ +static DEFINE_MUTEX(blk_probe_mutex); +static atomic_t blk_probes_ref = ATOMIC_INIT(0); + +static int blk_register_tracepoints(void); +static void blk_unregister_tracepoints(void); + /* * Send out a notify message. */ @@ -119,7 +127,7 @@ static u32 ddir_act[2] __read_mostly = { BLK_TC_ACT(BLK_TC_READ), BLK_TC_ACT(BLK * The worker for the various blk_add_trace*() types. Fills out a * blk_io_trace structure and places it in a per-cpu subbuffer. */ -void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes, +static void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes, int rw, u32 what, int error, int pdu_len, void *pdu_data) { struct task_struct *tsk = current; @@ -177,8 +185,6 @@ void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes, local_irq_restore(flags); } -EXPORT_SYMBOL_GPL(__blk_add_trace); - static struct dentry *blk_tree_root; static DEFINE_MUTEX(blk_tree_mutex); static unsigned int root_users; @@ -237,6 +243,10 @@ static void blk_trace_cleanup(struct blk_trace *bt) free_percpu(bt->sequence); free_percpu(bt->msg_data); kfree(bt); + mutex_lock(&blk_probe_mutex); + if (atomic_dec_and_test(&blk_probes_ref)) + blk_unregister_tracepoints(); + mutex_unlock(&blk_probe_mutex); } int blk_trace_remove(struct request_queue *q) @@ -428,6 +438,14 @@ int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev, bt->pid = buts->pid; bt->trace_state = Blktrace_setup; + mutex_lock(&blk_probe_mutex); + if (atomic_add_return(1, &blk_probes_ref) == 1) { + ret = blk_register_tracepoints(); + if (ret) + goto probe_err; + } + mutex_unlock(&blk_probe_mutex); + ret = -EBUSY; old_bt = xchg(&q->blk_trace, bt); if (old_bt) { @@ -436,6 +454,9 @@ int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev, } return 0; +probe_err: + atomic_dec(&blk_probes_ref); + mutex_unlock(&blk_probe_mutex); err: if (dir) blk_remove_tree(dir); @@ -562,3 +583,308 @@ void blk_trace_shutdown(struct request_queue *q) blk_trace_remove(q); } } + +/* + * blktrace probes + */ + +/** + * blk_add_trace_rq - Add a trace for a request oriented action + * @q: queue the io is for + * @rq: the source request + * @what: the action + * + * Description: + * Records an action against a request. Will log the bio offset + size. + * + **/ +static void blk_add_trace_rq(struct request_queue *q, struct request *rq, + u32 what) +{ + struct blk_trace *bt = q->blk_trace; + int rw = rq->cmd_flags & 0x03; + + if (likely(!bt)) + return; + + if (blk_discard_rq(rq)) + rw |= (1 << BIO_RW_DISCARD); + + if (blk_pc_request(rq)) { + what |= BLK_TC_ACT(BLK_TC_PC); + __blk_add_trace(bt, 0, rq->data_len, rw, what, rq->errors, + sizeof(rq->cmd), rq->cmd); + } else { + what |= BLK_TC_ACT(BLK_TC_FS); + __blk_add_trace(bt, rq->hard_sector, rq->hard_nr_sectors << 9, + rw, what, rq->errors, 0, NULL); + } +} + +static void blk_add_trace_rq_abort(struct request_queue *q, struct request *rq) +{ + blk_add_trace_rq(q, rq, BLK_TA_ABORT); +} + +static void blk_add_trace_rq_insert(struct request_queue *q, struct request *rq) +{ + blk_add_trace_rq(q, rq, BLK_TA_INSERT); +} + +static void blk_add_trace_rq_issue(struct request_queue *q, struct request *rq) +{ + blk_add_trace_rq(q, rq, BLK_TA_ISSUE); +} + +static void blk_add_trace_rq_requeue(struct request_queue *q, struct request *rq) +{ + blk_add_trace_rq(q, rq, BLK_TA_REQUEUE); +} + +static void blk_add_trace_rq_complete(struct request_queue *q, struct request *rq) +{ + blk_add_trace_rq(q, rq, BLK_TA_COMPLETE); +} + +/** + * blk_add_trace_bio - Add a trace for a bio oriented action + * @q: queue the io is for + * @bio: the source bio + * @what: the action + * + * Description: + * Records an action against a bio. Will log the bio offset + size. + * + **/ +static void blk_add_trace_bio(struct request_queue *q, struct bio *bio, + u32 what) +{ + struct blk_trace *bt = q->blk_trace; + + if (likely(!bt)) + return; + + __blk_add_trace(bt, bio->bi_sector, bio->bi_size, bio->bi_rw, what, + !bio_flagged(bio, BIO_UPTODATE), 0, NULL); +} + +static void blk_add_trace_bio_bounce(struct request_queue *q, struct bio *bio) +{ + blk_add_trace_bio(q, bio, BLK_TA_BOUNCE); +} + +static void blk_add_trace_bio_complete(struct request_queue *q, struct bio *bio) +{ + blk_add_trace_bio(q, bio, BLK_TA_COMPLETE); +} + +static void blk_add_trace_bio_backmerge(struct request_queue *q, struct bio *bio) +{ + blk_add_trace_bio(q, bio, BLK_TA_BACKMERGE); +} + +static void blk_add_trace_bio_frontmerge(struct request_queue *q, struct bio *bio) +{ + blk_add_trace_bio(q, bio, BLK_TA_FRONTMERGE); +} + +static void blk_add_trace_bio_queue(struct request_queue *q, struct bio *bio) +{ + blk_add_trace_bio(q, bio, BLK_TA_QUEUE); +} + +static void blk_add_trace_getrq(struct request_queue *q, struct bio *bio, int rw) +{ + if (bio) + blk_add_trace_bio(q, bio, BLK_TA_GETRQ); + else { + struct blk_trace *bt = q->blk_trace; + + if (bt) + __blk_add_trace(bt, 0, 0, rw, BLK_TA_GETRQ, 0, 0, NULL); + } +} + + +static void blk_add_trace_sleeprq(struct request_queue *q, struct bio *bio, int rw) +{ + if (bio) + blk_add_trace_bio(q, bio, BLK_TA_SLEEPRQ); + else { + struct blk_trace *bt = q->blk_trace; + + if (bt) + __blk_add_trace(bt, 0, 0, rw, BLK_TA_SLEEPRQ, 0, 0, NULL); + } +} + +static void blk_add_trace_plug(struct request_queue *q) +{ + struct blk_trace *bt = q->blk_trace; + + if (bt) + __blk_add_trace(bt, 0, 0, 0, BLK_TA_PLUG, 0, 0, NULL); +} + +static void blk_add_trace_unplug_io(struct request_queue *q) +{ + struct blk_trace *bt = q->blk_trace; + + if (bt) { + unsigned int pdu = q->rq.count[READ] + q->rq.count[WRITE]; + __be64 rpdu = cpu_to_be64(pdu); + + __blk_add_trace(bt, 0, 0, 0, BLK_TA_UNPLUG_IO, 0, + sizeof(rpdu), &rpdu); + } +} + +static void blk_add_trace_unplug_timer(struct request_queue *q) +{ + struct blk_trace *bt = q->blk_trace; + + if (bt) { + unsigned int pdu = q->rq.count[READ] + q->rq.count[WRITE]; + __be64 rpdu = cpu_to_be64(pdu); + + __blk_add_trace(bt, 0, 0, 0, BLK_TA_UNPLUG_TIMER, 0, + sizeof(rpdu), &rpdu); + } +} + +static void blk_add_trace_split(struct request_queue *q, struct bio *bio, + unsigned int pdu) +{ + struct blk_trace *bt = q->blk_trace; + + if (bt) { + __be64 rpdu = cpu_to_be64(pdu); + + __blk_add_trace(bt, bio->bi_sector, bio->bi_size, bio->bi_rw, + BLK_TA_SPLIT, !bio_flagged(bio, BIO_UPTODATE), + sizeof(rpdu), &rpdu); + } +} + +/** + * blk_add_trace_remap - Add a trace for a remap operation + * @q: queue the io is for + * @bio: the source bio + * @dev: target device + * @from: source sector + * @to: target sector + * + * Description: + * Device mapper or raid target sometimes need to split a bio because + * it spans a stripe (or similar). Add a trace for that action. + * + **/ +static void blk_add_trace_remap(struct request_queue *q, struct bio *bio, + dev_t dev, sector_t from, sector_t to) +{ + struct blk_trace *bt = q->blk_trace; + struct blk_io_trace_remap r; + + if (likely(!bt)) + return; + + r.device = cpu_to_be32(dev); + r.device_from = cpu_to_be32(bio->bi_bdev->bd_dev); + r.sector = cpu_to_be64(to); + + __blk_add_trace(bt, from, bio->bi_size, bio->bi_rw, BLK_TA_REMAP, + !bio_flagged(bio, BIO_UPTODATE), sizeof(r), &r); +} + +/** + * blk_add_driver_data - Add binary message with driver-specific data + * @q: queue the io is for + * @rq: io request + * @data: driver-specific data + * @len: length of driver-specific data + * + * Description: + * Some drivers might want to write driver-specific data per request. + * + **/ +void blk_add_driver_data(struct request_queue *q, + struct request *rq, + void *data, size_t len) +{ + struct blk_trace *bt = q->blk_trace; + + if (likely(!bt)) + return; + + if (blk_pc_request(rq)) + __blk_add_trace(bt, 0, rq->data_len, 0, BLK_TA_DRV_DATA, + rq->errors, len, data); + else + __blk_add_trace(bt, rq->hard_sector, rq->hard_nr_sectors << 9, + 0, BLK_TA_DRV_DATA, rq->errors, len, data); +} +EXPORT_SYMBOL_GPL(blk_add_driver_data); + +static int blk_register_tracepoints(void) +{ + int ret; + + ret = register_trace_block_rq_abort(blk_add_trace_rq_abort); + WARN_ON(ret); + ret = register_trace_block_rq_insert(blk_add_trace_rq_insert); + WARN_ON(ret); + ret = register_trace_block_rq_issue(blk_add_trace_rq_issue); + WARN_ON(ret); + ret = register_trace_block_rq_requeue(blk_add_trace_rq_requeue); + WARN_ON(ret); + ret = register_trace_block_rq_complete(blk_add_trace_rq_complete); + WARN_ON(ret); + ret = register_trace_block_bio_bounce(blk_add_trace_bio_bounce); + WARN_ON(ret); + ret = register_trace_block_bio_complete(blk_add_trace_bio_complete); + WARN_ON(ret); + ret = register_trace_block_bio_backmerge(blk_add_trace_bio_backmerge); + WARN_ON(ret); + ret = register_trace_block_bio_frontmerge(blk_add_trace_bio_frontmerge); + WARN_ON(ret); + ret = register_trace_block_bio_queue(blk_add_trace_bio_queue); + WARN_ON(ret); + ret = register_trace_block_getrq(blk_add_trace_getrq); + WARN_ON(ret); + ret = register_trace_block_sleeprq(blk_add_trace_sleeprq); + WARN_ON(ret); + ret = register_trace_block_plug(blk_add_trace_plug); + WARN_ON(ret); + ret = register_trace_block_unplug_timer(blk_add_trace_unplug_timer); + WARN_ON(ret); + ret = register_trace_block_unplug_io(blk_add_trace_unplug_io); + WARN_ON(ret); + ret = register_trace_block_split(blk_add_trace_split); + WARN_ON(ret); + ret = register_trace_block_remap(blk_add_trace_remap); + WARN_ON(ret); + return 0; +} + +static void blk_unregister_tracepoints(void) +{ + unregister_trace_block_remap(blk_add_trace_remap); + unregister_trace_block_split(blk_add_trace_split); + unregister_trace_block_unplug_io(blk_add_trace_unplug_io); + unregister_trace_block_unplug_timer(blk_add_trace_unplug_timer); + unregister_trace_block_plug(blk_add_trace_plug); + unregister_trace_block_sleeprq(blk_add_trace_sleeprq); + unregister_trace_block_getrq(blk_add_trace_getrq); + unregister_trace_block_bio_queue(blk_add_trace_bio_queue); + unregister_trace_block_bio_frontmerge(blk_add_trace_bio_frontmerge); + unregister_trace_block_bio_backmerge(blk_add_trace_bio_backmerge); + unregister_trace_block_bio_complete(blk_add_trace_bio_complete); + unregister_trace_block_bio_bounce(blk_add_trace_bio_bounce); + unregister_trace_block_rq_complete(blk_add_trace_rq_complete); + unregister_trace_block_rq_requeue(blk_add_trace_rq_requeue); + unregister_trace_block_rq_issue(blk_add_trace_rq_issue); + unregister_trace_block_rq_insert(blk_add_trace_rq_insert); + unregister_trace_block_rq_abort(blk_add_trace_rq_abort); + + tracepoint_synchronize_unregister(); +} diff --git a/block/elevator.c b/block/elevator.c index a6951f76ba0c3fa3e9a0c9f8ff58a108e63dc85c..86836dd179c05476078719869a0481777e999bc1 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -41,6 +42,8 @@ static DEFINE_SPINLOCK(elv_list_lock); static LIST_HEAD(elv_list); +DEFINE_TRACE(block_rq_abort); + /* * Merge hash stuff. */ @@ -52,6 +55,9 @@ static const int elv_hash_shift = 6; #define rq_hash_key(rq) ((rq)->sector + (rq)->nr_sectors) #define ELV_ON_HASH(rq) (!hlist_unhashed(&(rq)->hash)) +DEFINE_TRACE(block_rq_insert); +DEFINE_TRACE(block_rq_issue); + /* * Query io scheduler to see if the current process issuing bio may be * merged with rq. @@ -586,7 +592,7 @@ void elv_insert(struct request_queue *q, struct request *rq, int where) unsigned ordseq; int unplug_it = 1; - blk_add_trace_rq(q, rq, BLK_TA_INSERT); + trace_block_rq_insert(q, rq); rq->q = q; @@ -772,7 +778,7 @@ struct request *elv_next_request(struct request_queue *q) * not be passed by new incoming requests */ rq->cmd_flags |= REQ_STARTED; - blk_add_trace_rq(q, rq, BLK_TA_ISSUE); + trace_block_rq_issue(q, rq); } if (!q->boundary_rq || q->boundary_rq == rq) { @@ -914,7 +920,7 @@ void elv_abort_queue(struct request_queue *q) while (!list_empty(&q->queue_head)) { rq = list_entry_rq(q->queue_head.next); rq->cmd_flags |= REQ_QUIET; - blk_add_trace_rq(q, rq, BLK_TA_ABORT); + trace_block_rq_abort(q, rq); __blk_end_request(rq, -EIO, blk_rq_bytes(rq)); } } diff --git a/crypto/Kconfig b/crypto/Kconfig index dc20a34ba5efaf9922cf225f1ec18a962b5f1024..8dde4fcf99c947b7c292be0a775b102e43260879 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -102,6 +102,7 @@ config CRYPTO_NULL tristate "Null algorithms" select CRYPTO_ALGAPI select CRYPTO_BLKCIPHER + select CRYPTO_HASH help These are 'Null' algorithms, used by IPsec, which do nothing. @@ -256,12 +257,10 @@ comment "Digest" config CRYPTO_CRC32C tristate "CRC32c CRC algorithm" select CRYPTO_HASH - select LIBCRC32C help Castagnoli, et al Cyclic Redundancy-Check Algorithm. Used by iSCSI for header and data digests and by others. - See Castagnoli93. This implementation uses lib/libcrc32c. - Module will be crc32c. + See Castagnoli93. Module will be crc32c. config CRYPTO_CRC32C_INTEL tristate "CRC32c INTEL hardware acceleration" @@ -277,19 +276,19 @@ config CRYPTO_CRC32C_INTEL config CRYPTO_MD4 tristate "MD4 digest algorithm" - select CRYPTO_ALGAPI + select CRYPTO_HASH help MD4 message digest algorithm (RFC1320). config CRYPTO_MD5 tristate "MD5 digest algorithm" - select CRYPTO_ALGAPI + select CRYPTO_HASH help MD5 message digest algorithm (RFC1321). config CRYPTO_MICHAEL_MIC tristate "Michael MIC keyed digest algorithm" - select CRYPTO_ALGAPI + select CRYPTO_HASH help Michael MIC is used for message integrity protection in TKIP (IEEE 802.11i). This algorithm is required for TKIP, but it @@ -298,7 +297,7 @@ config CRYPTO_MICHAEL_MIC config CRYPTO_RMD128 tristate "RIPEMD-128 digest algorithm" - select CRYPTO_ALGAPI + select CRYPTO_HASH help RIPEMD-128 (ISO/IEC 10118-3:2004). @@ -311,7 +310,7 @@ config CRYPTO_RMD128 config CRYPTO_RMD160 tristate "RIPEMD-160 digest algorithm" - select CRYPTO_ALGAPI + select CRYPTO_HASH help RIPEMD-160 (ISO/IEC 10118-3:2004). @@ -328,7 +327,7 @@ config CRYPTO_RMD160 config CRYPTO_RMD256 tristate "RIPEMD-256 digest algorithm" - select CRYPTO_ALGAPI + select CRYPTO_HASH help RIPEMD-256 is an optional extension of RIPEMD-128 with a 256 bit hash. It is intended for applications that require @@ -340,7 +339,7 @@ config CRYPTO_RMD256 config CRYPTO_RMD320 tristate "RIPEMD-320 digest algorithm" - select CRYPTO_ALGAPI + select CRYPTO_HASH help RIPEMD-320 is an optional extension of RIPEMD-160 with a 320 bit hash. It is intended for applications that require @@ -352,13 +351,13 @@ config CRYPTO_RMD320 config CRYPTO_SHA1 tristate "SHA1 digest algorithm" - select CRYPTO_ALGAPI + select CRYPTO_HASH help SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2). config CRYPTO_SHA256 tristate "SHA224 and SHA256 digest algorithm" - select CRYPTO_ALGAPI + select CRYPTO_HASH help SHA256 secure hash standard (DFIPS 180-2). @@ -370,7 +369,7 @@ config CRYPTO_SHA256 config CRYPTO_SHA512 tristate "SHA384 and SHA512 digest algorithms" - select CRYPTO_ALGAPI + select CRYPTO_HASH help SHA512 secure hash standard (DFIPS 180-2). @@ -382,7 +381,7 @@ config CRYPTO_SHA512 config CRYPTO_TGR192 tristate "Tiger digest algorithms" - select CRYPTO_ALGAPI + select CRYPTO_HASH help Tiger hash algorithm 192, 160 and 128-bit hashes @@ -395,7 +394,7 @@ config CRYPTO_TGR192 config CRYPTO_WP512 tristate "Whirlpool digest algorithms" - select CRYPTO_ALGAPI + select CRYPTO_HASH help Whirlpool hash algorithm 512, 384 and 256-bit hashes diff --git a/crypto/Makefile b/crypto/Makefile index cd4a4ed078ff1252642dba2fc87093fa97eedb18..46b08bf2035fdfd5e404953aa2b5f8740efa4c82 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_CRYPTO_SEQIV) += seqiv.o crypto_hash-objs := hash.o crypto_hash-objs += ahash.o +crypto_hash-objs += shash.o obj-$(CONFIG_CRYPTO_HASH2) += crypto_hash.o cryptomgr-objs := algboss.o testmgr.o diff --git a/crypto/aes_generic.c b/crypto/aes_generic.c index 136dc98d8a03f9f7d8d1a259a123c10dc03d4f4c..b8b66ec3883b74d8ea2b7b41f1298a4b01a32ca8 100644 --- a/crypto/aes_generic.c +++ b/crypto/aes_generic.c @@ -60,102 +60,1068 @@ static inline u8 byte(const u32 x, const unsigned n) return x >> (n << 3); } -static u8 pow_tab[256] __initdata; -static u8 log_tab[256] __initdata; -static u8 sbx_tab[256] __initdata; -static u8 isb_tab[256] __initdata; -static u32 rco_tab[10]; - -u32 crypto_ft_tab[4][256]; -u32 crypto_fl_tab[4][256]; -u32 crypto_it_tab[4][256]; -u32 crypto_il_tab[4][256]; - -EXPORT_SYMBOL_GPL(crypto_ft_tab); -EXPORT_SYMBOL_GPL(crypto_fl_tab); -EXPORT_SYMBOL_GPL(crypto_it_tab); -EXPORT_SYMBOL_GPL(crypto_il_tab); - -static inline u8 __init f_mult(u8 a, u8 b) -{ - u8 aa = log_tab[a], cc = aa + log_tab[b]; - - return pow_tab[cc + (cc < aa ? 1 : 0)]; -} - -#define ff_mult(a, b) (a && b ? f_mult(a, b) : 0) - -static void __init gen_tabs(void) -{ - u32 i, t; - u8 p, q; - - /* - * log and power tables for GF(2**8) finite field with - * 0x011b as modular polynomial - the simplest primitive - * root is 0x03, used here to generate the tables - */ - - for (i = 0, p = 1; i < 256; ++i) { - pow_tab[i] = (u8) p; - log_tab[p] = (u8) i; - - p ^= (p << 1) ^ (p & 0x80 ? 0x01b : 0); +static const u32 rco_tab[10] = { 1, 2, 4, 8, 16, 32, 64, 128, 27, 54 }; + +const u32 crypto_ft_tab[4][256] = { + { + 0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, + 0x0df2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, + 0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56, + 0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec, + 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa, + 0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb, + 0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, + 0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b, + 0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c, + 0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83, + 0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9, + 0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a, + 0x0c040408, 0x52c7c795, 0x65232346, 0x5ec3c39d, + 0x28181830, 0xa1969637, 0x0f05050a, 0xb59a9a2f, + 0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df, + 0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, + 0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34, + 0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b, + 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d, + 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413, + 0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1, + 0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, + 0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972, + 0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85, + 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed, + 0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, + 0xcf45458a, 0x10f9f9e9, 0x06020204, 0x817f7ffe, + 0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b, + 0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05, + 0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1, + 0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, + 0x30101020, 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf, + 0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3, + 0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e, + 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a, + 0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, + 0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3, + 0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b, + 0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428, + 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad, + 0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, + 0xdb494992, 0x0a06060c, 0x6c242448, 0xe45c5cb8, + 0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4, + 0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2, + 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda, + 0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, + 0xb46c6cd8, 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf, + 0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810, + 0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c, + 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697, + 0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, + 0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, + 0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc, + 0xd8484890, 0x05030306, 0x01f6f6f7, 0x120e0e1c, + 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969, + 0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, + 0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122, + 0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433, + 0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9, + 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5, + 0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, + 0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0, + 0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e, + 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c, + }, { + 0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d, + 0xf2f2ff0d, 0x6b6bd6bd, 0x6f6fdeb1, 0xc5c59154, + 0x30306050, 0x01010203, 0x6767cea9, 0x2b2b567d, + 0xfefee719, 0xd7d7b562, 0xabab4de6, 0x7676ec9a, + 0xcaca8f45, 0x82821f9d, 0xc9c98940, 0x7d7dfa87, + 0xfafaef15, 0x5959b2eb, 0x47478ec9, 0xf0f0fb0b, + 0xadad41ec, 0xd4d4b367, 0xa2a25ffd, 0xafaf45ea, + 0x9c9c23bf, 0xa4a453f7, 0x7272e496, 0xc0c09b5b, + 0xb7b775c2, 0xfdfde11c, 0x93933dae, 0x26264c6a, + 0x36366c5a, 0x3f3f7e41, 0xf7f7f502, 0xcccc834f, + 0x3434685c, 0xa5a551f4, 0xe5e5d134, 0xf1f1f908, + 0x7171e293, 0xd8d8ab73, 0x31316253, 0x15152a3f, + 0x0404080c, 0xc7c79552, 0x23234665, 0xc3c39d5e, + 0x18183028, 0x969637a1, 0x05050a0f, 0x9a9a2fb5, + 0x07070e09, 0x12122436, 0x80801b9b, 0xe2e2df3d, + 0xebebcd26, 0x27274e69, 0xb2b27fcd, 0x7575ea9f, + 0x0909121b, 0x83831d9e, 0x2c2c5874, 0x1a1a342e, + 0x1b1b362d, 0x6e6edcb2, 0x5a5ab4ee, 0xa0a05bfb, + 0x5252a4f6, 0x3b3b764d, 0xd6d6b761, 0xb3b37dce, + 0x2929527b, 0xe3e3dd3e, 0x2f2f5e71, 0x84841397, + 0x5353a6f5, 0xd1d1b968, 0x00000000, 0xededc12c, + 0x20204060, 0xfcfce31f, 0xb1b179c8, 0x5b5bb6ed, + 0x6a6ad4be, 0xcbcb8d46, 0xbebe67d9, 0x3939724b, + 0x4a4a94de, 0x4c4c98d4, 0x5858b0e8, 0xcfcf854a, + 0xd0d0bb6b, 0xefefc52a, 0xaaaa4fe5, 0xfbfbed16, + 0x434386c5, 0x4d4d9ad7, 0x33336655, 0x85851194, + 0x45458acf, 0xf9f9e910, 0x02020406, 0x7f7ffe81, + 0x5050a0f0, 0x3c3c7844, 0x9f9f25ba, 0xa8a84be3, + 0x5151a2f3, 0xa3a35dfe, 0x404080c0, 0x8f8f058a, + 0x92923fad, 0x9d9d21bc, 0x38387048, 0xf5f5f104, + 0xbcbc63df, 0xb6b677c1, 0xdadaaf75, 0x21214263, + 0x10102030, 0xffffe51a, 0xf3f3fd0e, 0xd2d2bf6d, + 0xcdcd814c, 0x0c0c1814, 0x13132635, 0xececc32f, + 0x5f5fbee1, 0x979735a2, 0x444488cc, 0x17172e39, + 0xc4c49357, 0xa7a755f2, 0x7e7efc82, 0x3d3d7a47, + 0x6464c8ac, 0x5d5dbae7, 0x1919322b, 0x7373e695, + 0x6060c0a0, 0x81811998, 0x4f4f9ed1, 0xdcdca37f, + 0x22224466, 0x2a2a547e, 0x90903bab, 0x88880b83, + 0x46468cca, 0xeeeec729, 0xb8b86bd3, 0x1414283c, + 0xdedea779, 0x5e5ebce2, 0x0b0b161d, 0xdbdbad76, + 0xe0e0db3b, 0x32326456, 0x3a3a744e, 0x0a0a141e, + 0x494992db, 0x06060c0a, 0x2424486c, 0x5c5cb8e4, + 0xc2c29f5d, 0xd3d3bd6e, 0xacac43ef, 0x6262c4a6, + 0x919139a8, 0x959531a4, 0xe4e4d337, 0x7979f28b, + 0xe7e7d532, 0xc8c88b43, 0x37376e59, 0x6d6ddab7, + 0x8d8d018c, 0xd5d5b164, 0x4e4e9cd2, 0xa9a949e0, + 0x6c6cd8b4, 0x5656acfa, 0xf4f4f307, 0xeaeacf25, + 0x6565caaf, 0x7a7af48e, 0xaeae47e9, 0x08081018, + 0xbaba6fd5, 0x7878f088, 0x25254a6f, 0x2e2e5c72, + 0x1c1c3824, 0xa6a657f1, 0xb4b473c7, 0xc6c69751, + 0xe8e8cb23, 0xdddda17c, 0x7474e89c, 0x1f1f3e21, + 0x4b4b96dd, 0xbdbd61dc, 0x8b8b0d86, 0x8a8a0f85, + 0x7070e090, 0x3e3e7c42, 0xb5b571c4, 0x6666ccaa, + 0x484890d8, 0x03030605, 0xf6f6f701, 0x0e0e1c12, + 0x6161c2a3, 0x35356a5f, 0x5757aef9, 0xb9b969d0, + 0x86861791, 0xc1c19958, 0x1d1d3a27, 0x9e9e27b9, + 0xe1e1d938, 0xf8f8eb13, 0x98982bb3, 0x11112233, + 0x6969d2bb, 0xd9d9a970, 0x8e8e0789, 0x949433a7, + 0x9b9b2db6, 0x1e1e3c22, 0x87871592, 0xe9e9c920, + 0xcece8749, 0x5555aaff, 0x28285078, 0xdfdfa57a, + 0x8c8c038f, 0xa1a159f8, 0x89890980, 0x0d0d1a17, + 0xbfbf65da, 0xe6e6d731, 0x424284c6, 0x6868d0b8, + 0x414182c3, 0x999929b0, 0x2d2d5a77, 0x0f0f1e11, + 0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6, 0x16162c3a, + }, { + 0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b, + 0xf2ff0df2, 0x6bd6bd6b, 0x6fdeb16f, 0xc59154c5, + 0x30605030, 0x01020301, 0x67cea967, 0x2b567d2b, + 0xfee719fe, 0xd7b562d7, 0xab4de6ab, 0x76ec9a76, + 0xca8f45ca, 0x821f9d82, 0xc98940c9, 0x7dfa877d, + 0xfaef15fa, 0x59b2eb59, 0x478ec947, 0xf0fb0bf0, + 0xad41ecad, 0xd4b367d4, 0xa25ffda2, 0xaf45eaaf, + 0x9c23bf9c, 0xa453f7a4, 0x72e49672, 0xc09b5bc0, + 0xb775c2b7, 0xfde11cfd, 0x933dae93, 0x264c6a26, + 0x366c5a36, 0x3f7e413f, 0xf7f502f7, 0xcc834fcc, + 0x34685c34, 0xa551f4a5, 0xe5d134e5, 0xf1f908f1, + 0x71e29371, 0xd8ab73d8, 0x31625331, 0x152a3f15, + 0x04080c04, 0xc79552c7, 0x23466523, 0xc39d5ec3, + 0x18302818, 0x9637a196, 0x050a0f05, 0x9a2fb59a, + 0x070e0907, 0x12243612, 0x801b9b80, 0xe2df3de2, + 0xebcd26eb, 0x274e6927, 0xb27fcdb2, 0x75ea9f75, + 0x09121b09, 0x831d9e83, 0x2c58742c, 0x1a342e1a, + 0x1b362d1b, 0x6edcb26e, 0x5ab4ee5a, 0xa05bfba0, + 0x52a4f652, 0x3b764d3b, 0xd6b761d6, 0xb37dceb3, + 0x29527b29, 0xe3dd3ee3, 0x2f5e712f, 0x84139784, + 0x53a6f553, 0xd1b968d1, 0x00000000, 0xedc12ced, + 0x20406020, 0xfce31ffc, 0xb179c8b1, 0x5bb6ed5b, + 0x6ad4be6a, 0xcb8d46cb, 0xbe67d9be, 0x39724b39, + 0x4a94de4a, 0x4c98d44c, 0x58b0e858, 0xcf854acf, + 0xd0bb6bd0, 0xefc52aef, 0xaa4fe5aa, 0xfbed16fb, + 0x4386c543, 0x4d9ad74d, 0x33665533, 0x85119485, + 0x458acf45, 0xf9e910f9, 0x02040602, 0x7ffe817f, + 0x50a0f050, 0x3c78443c, 0x9f25ba9f, 0xa84be3a8, + 0x51a2f351, 0xa35dfea3, 0x4080c040, 0x8f058a8f, + 0x923fad92, 0x9d21bc9d, 0x38704838, 0xf5f104f5, + 0xbc63dfbc, 0xb677c1b6, 0xdaaf75da, 0x21426321, + 0x10203010, 0xffe51aff, 0xf3fd0ef3, 0xd2bf6dd2, + 0xcd814ccd, 0x0c18140c, 0x13263513, 0xecc32fec, + 0x5fbee15f, 0x9735a297, 0x4488cc44, 0x172e3917, + 0xc49357c4, 0xa755f2a7, 0x7efc827e, 0x3d7a473d, + 0x64c8ac64, 0x5dbae75d, 0x19322b19, 0x73e69573, + 0x60c0a060, 0x81199881, 0x4f9ed14f, 0xdca37fdc, + 0x22446622, 0x2a547e2a, 0x903bab90, 0x880b8388, + 0x468cca46, 0xeec729ee, 0xb86bd3b8, 0x14283c14, + 0xdea779de, 0x5ebce25e, 0x0b161d0b, 0xdbad76db, + 0xe0db3be0, 0x32645632, 0x3a744e3a, 0x0a141e0a, + 0x4992db49, 0x060c0a06, 0x24486c24, 0x5cb8e45c, + 0xc29f5dc2, 0xd3bd6ed3, 0xac43efac, 0x62c4a662, + 0x9139a891, 0x9531a495, 0xe4d337e4, 0x79f28b79, + 0xe7d532e7, 0xc88b43c8, 0x376e5937, 0x6ddab76d, + 0x8d018c8d, 0xd5b164d5, 0x4e9cd24e, 0xa949e0a9, + 0x6cd8b46c, 0x56acfa56, 0xf4f307f4, 0xeacf25ea, + 0x65caaf65, 0x7af48e7a, 0xae47e9ae, 0x08101808, + 0xba6fd5ba, 0x78f08878, 0x254a6f25, 0x2e5c722e, + 0x1c38241c, 0xa657f1a6, 0xb473c7b4, 0xc69751c6, + 0xe8cb23e8, 0xdda17cdd, 0x74e89c74, 0x1f3e211f, + 0x4b96dd4b, 0xbd61dcbd, 0x8b0d868b, 0x8a0f858a, + 0x70e09070, 0x3e7c423e, 0xb571c4b5, 0x66ccaa66, + 0x4890d848, 0x03060503, 0xf6f701f6, 0x0e1c120e, + 0x61c2a361, 0x356a5f35, 0x57aef957, 0xb969d0b9, + 0x86179186, 0xc19958c1, 0x1d3a271d, 0x9e27b99e, + 0xe1d938e1, 0xf8eb13f8, 0x982bb398, 0x11223311, + 0x69d2bb69, 0xd9a970d9, 0x8e07898e, 0x9433a794, + 0x9b2db69b, 0x1e3c221e, 0x87159287, 0xe9c920e9, + 0xce8749ce, 0x55aaff55, 0x28507828, 0xdfa57adf, + 0x8c038f8c, 0xa159f8a1, 0x89098089, 0x0d1a170d, + 0xbf65dabf, 0xe6d731e6, 0x4284c642, 0x68d0b868, + 0x4182c341, 0x9929b099, 0x2d5a772d, 0x0f1e110f, + 0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb, 0x162c3a16, + }, { + 0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b, + 0xff0df2f2, 0xd6bd6b6b, 0xdeb16f6f, 0x9154c5c5, + 0x60503030, 0x02030101, 0xcea96767, 0x567d2b2b, + 0xe719fefe, 0xb562d7d7, 0x4de6abab, 0xec9a7676, + 0x8f45caca, 0x1f9d8282, 0x8940c9c9, 0xfa877d7d, + 0xef15fafa, 0xb2eb5959, 0x8ec94747, 0xfb0bf0f0, + 0x41ecadad, 0xb367d4d4, 0x5ffda2a2, 0x45eaafaf, + 0x23bf9c9c, 0x53f7a4a4, 0xe4967272, 0x9b5bc0c0, + 0x75c2b7b7, 0xe11cfdfd, 0x3dae9393, 0x4c6a2626, + 0x6c5a3636, 0x7e413f3f, 0xf502f7f7, 0x834fcccc, + 0x685c3434, 0x51f4a5a5, 0xd134e5e5, 0xf908f1f1, + 0xe2937171, 0xab73d8d8, 0x62533131, 0x2a3f1515, + 0x080c0404, 0x9552c7c7, 0x46652323, 0x9d5ec3c3, + 0x30281818, 0x37a19696, 0x0a0f0505, 0x2fb59a9a, + 0x0e090707, 0x24361212, 0x1b9b8080, 0xdf3de2e2, + 0xcd26ebeb, 0x4e692727, 0x7fcdb2b2, 0xea9f7575, + 0x121b0909, 0x1d9e8383, 0x58742c2c, 0x342e1a1a, + 0x362d1b1b, 0xdcb26e6e, 0xb4ee5a5a, 0x5bfba0a0, + 0xa4f65252, 0x764d3b3b, 0xb761d6d6, 0x7dceb3b3, + 0x527b2929, 0xdd3ee3e3, 0x5e712f2f, 0x13978484, + 0xa6f55353, 0xb968d1d1, 0x00000000, 0xc12ceded, + 0x40602020, 0xe31ffcfc, 0x79c8b1b1, 0xb6ed5b5b, + 0xd4be6a6a, 0x8d46cbcb, 0x67d9bebe, 0x724b3939, + 0x94de4a4a, 0x98d44c4c, 0xb0e85858, 0x854acfcf, + 0xbb6bd0d0, 0xc52aefef, 0x4fe5aaaa, 0xed16fbfb, + 0x86c54343, 0x9ad74d4d, 0x66553333, 0x11948585, + 0x8acf4545, 0xe910f9f9, 0x04060202, 0xfe817f7f, + 0xa0f05050, 0x78443c3c, 0x25ba9f9f, 0x4be3a8a8, + 0xa2f35151, 0x5dfea3a3, 0x80c04040, 0x058a8f8f, + 0x3fad9292, 0x21bc9d9d, 0x70483838, 0xf104f5f5, + 0x63dfbcbc, 0x77c1b6b6, 0xaf75dada, 0x42632121, + 0x20301010, 0xe51affff, 0xfd0ef3f3, 0xbf6dd2d2, + 0x814ccdcd, 0x18140c0c, 0x26351313, 0xc32fecec, + 0xbee15f5f, 0x35a29797, 0x88cc4444, 0x2e391717, + 0x9357c4c4, 0x55f2a7a7, 0xfc827e7e, 0x7a473d3d, + 0xc8ac6464, 0xbae75d5d, 0x322b1919, 0xe6957373, + 0xc0a06060, 0x19988181, 0x9ed14f4f, 0xa37fdcdc, + 0x44662222, 0x547e2a2a, 0x3bab9090, 0x0b838888, + 0x8cca4646, 0xc729eeee, 0x6bd3b8b8, 0x283c1414, + 0xa779dede, 0xbce25e5e, 0x161d0b0b, 0xad76dbdb, + 0xdb3be0e0, 0x64563232, 0x744e3a3a, 0x141e0a0a, + 0x92db4949, 0x0c0a0606, 0x486c2424, 0xb8e45c5c, + 0x9f5dc2c2, 0xbd6ed3d3, 0x43efacac, 0xc4a66262, + 0x39a89191, 0x31a49595, 0xd337e4e4, 0xf28b7979, + 0xd532e7e7, 0x8b43c8c8, 0x6e593737, 0xdab76d6d, + 0x018c8d8d, 0xb164d5d5, 0x9cd24e4e, 0x49e0a9a9, + 0xd8b46c6c, 0xacfa5656, 0xf307f4f4, 0xcf25eaea, + 0xcaaf6565, 0xf48e7a7a, 0x47e9aeae, 0x10180808, + 0x6fd5baba, 0xf0887878, 0x4a6f2525, 0x5c722e2e, + 0x38241c1c, 0x57f1a6a6, 0x73c7b4b4, 0x9751c6c6, + 0xcb23e8e8, 0xa17cdddd, 0xe89c7474, 0x3e211f1f, + 0x96dd4b4b, 0x61dcbdbd, 0x0d868b8b, 0x0f858a8a, + 0xe0907070, 0x7c423e3e, 0x71c4b5b5, 0xccaa6666, + 0x90d84848, 0x06050303, 0xf701f6f6, 0x1c120e0e, + 0xc2a36161, 0x6a5f3535, 0xaef95757, 0x69d0b9b9, + 0x17918686, 0x9958c1c1, 0x3a271d1d, 0x27b99e9e, + 0xd938e1e1, 0xeb13f8f8, 0x2bb39898, 0x22331111, + 0xd2bb6969, 0xa970d9d9, 0x07898e8e, 0x33a79494, + 0x2db69b9b, 0x3c221e1e, 0x15928787, 0xc920e9e9, + 0x8749cece, 0xaaff5555, 0x50782828, 0xa57adfdf, + 0x038f8c8c, 0x59f8a1a1, 0x09808989, 0x1a170d0d, + 0x65dabfbf, 0xd731e6e6, 0x84c64242, 0xd0b86868, + 0x82c34141, 0x29b09999, 0x5a772d2d, 0x1e110f0f, + 0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb, 0x2c3a1616, } +}; - log_tab[1] = 0; - - for (i = 0, p = 1; i < 10; ++i) { - rco_tab[i] = p; - - p = (p << 1) ^ (p & 0x80 ? 0x01b : 0); +const u32 crypto_fl_tab[4][256] = { + { + 0x00000063, 0x0000007c, 0x00000077, 0x0000007b, + 0x000000f2, 0x0000006b, 0x0000006f, 0x000000c5, + 0x00000030, 0x00000001, 0x00000067, 0x0000002b, + 0x000000fe, 0x000000d7, 0x000000ab, 0x00000076, + 0x000000ca, 0x00000082, 0x000000c9, 0x0000007d, + 0x000000fa, 0x00000059, 0x00000047, 0x000000f0, + 0x000000ad, 0x000000d4, 0x000000a2, 0x000000af, + 0x0000009c, 0x000000a4, 0x00000072, 0x000000c0, + 0x000000b7, 0x000000fd, 0x00000093, 0x00000026, + 0x00000036, 0x0000003f, 0x000000f7, 0x000000cc, + 0x00000034, 0x000000a5, 0x000000e5, 0x000000f1, + 0x00000071, 0x000000d8, 0x00000031, 0x00000015, + 0x00000004, 0x000000c7, 0x00000023, 0x000000c3, + 0x00000018, 0x00000096, 0x00000005, 0x0000009a, + 0x00000007, 0x00000012, 0x00000080, 0x000000e2, + 0x000000eb, 0x00000027, 0x000000b2, 0x00000075, + 0x00000009, 0x00000083, 0x0000002c, 0x0000001a, + 0x0000001b, 0x0000006e, 0x0000005a, 0x000000a0, + 0x00000052, 0x0000003b, 0x000000d6, 0x000000b3, + 0x00000029, 0x000000e3, 0x0000002f, 0x00000084, + 0x00000053, 0x000000d1, 0x00000000, 0x000000ed, + 0x00000020, 0x000000fc, 0x000000b1, 0x0000005b, + 0x0000006a, 0x000000cb, 0x000000be, 0x00000039, + 0x0000004a, 0x0000004c, 0x00000058, 0x000000cf, + 0x000000d0, 0x000000ef, 0x000000aa, 0x000000fb, + 0x00000043, 0x0000004d, 0x00000033, 0x00000085, + 0x00000045, 0x000000f9, 0x00000002, 0x0000007f, + 0x00000050, 0x0000003c, 0x0000009f, 0x000000a8, + 0x00000051, 0x000000a3, 0x00000040, 0x0000008f, + 0x00000092, 0x0000009d, 0x00000038, 0x000000f5, + 0x000000bc, 0x000000b6, 0x000000da, 0x00000021, + 0x00000010, 0x000000ff, 0x000000f3, 0x000000d2, + 0x000000cd, 0x0000000c, 0x00000013, 0x000000ec, + 0x0000005f, 0x00000097, 0x00000044, 0x00000017, + 0x000000c4, 0x000000a7, 0x0000007e, 0x0000003d, + 0x00000064, 0x0000005d, 0x00000019, 0x00000073, + 0x00000060, 0x00000081, 0x0000004f, 0x000000dc, + 0x00000022, 0x0000002a, 0x00000090, 0x00000088, + 0x00000046, 0x000000ee, 0x000000b8, 0x00000014, + 0x000000de, 0x0000005e, 0x0000000b, 0x000000db, + 0x000000e0, 0x00000032, 0x0000003a, 0x0000000a, + 0x00000049, 0x00000006, 0x00000024, 0x0000005c, + 0x000000c2, 0x000000d3, 0x000000ac, 0x00000062, + 0x00000091, 0x00000095, 0x000000e4, 0x00000079, + 0x000000e7, 0x000000c8, 0x00000037, 0x0000006d, + 0x0000008d, 0x000000d5, 0x0000004e, 0x000000a9, + 0x0000006c, 0x00000056, 0x000000f4, 0x000000ea, + 0x00000065, 0x0000007a, 0x000000ae, 0x00000008, + 0x000000ba, 0x00000078, 0x00000025, 0x0000002e, + 0x0000001c, 0x000000a6, 0x000000b4, 0x000000c6, + 0x000000e8, 0x000000dd, 0x00000074, 0x0000001f, + 0x0000004b, 0x000000bd, 0x0000008b, 0x0000008a, + 0x00000070, 0x0000003e, 0x000000b5, 0x00000066, + 0x00000048, 0x00000003, 0x000000f6, 0x0000000e, + 0x00000061, 0x00000035, 0x00000057, 0x000000b9, + 0x00000086, 0x000000c1, 0x0000001d, 0x0000009e, + 0x000000e1, 0x000000f8, 0x00000098, 0x00000011, + 0x00000069, 0x000000d9, 0x0000008e, 0x00000094, + 0x0000009b, 0x0000001e, 0x00000087, 0x000000e9, + 0x000000ce, 0x00000055, 0x00000028, 0x000000df, + 0x0000008c, 0x000000a1, 0x00000089, 0x0000000d, + 0x000000bf, 0x000000e6, 0x00000042, 0x00000068, + 0x00000041, 0x00000099, 0x0000002d, 0x0000000f, + 0x000000b0, 0x00000054, 0x000000bb, 0x00000016, + }, { + 0x00006300, 0x00007c00, 0x00007700, 0x00007b00, + 0x0000f200, 0x00006b00, 0x00006f00, 0x0000c500, + 0x00003000, 0x00000100, 0x00006700, 0x00002b00, + 0x0000fe00, 0x0000d700, 0x0000ab00, 0x00007600, + 0x0000ca00, 0x00008200, 0x0000c900, 0x00007d00, + 0x0000fa00, 0x00005900, 0x00004700, 0x0000f000, + 0x0000ad00, 0x0000d400, 0x0000a200, 0x0000af00, + 0x00009c00, 0x0000a400, 0x00007200, 0x0000c000, + 0x0000b700, 0x0000fd00, 0x00009300, 0x00002600, + 0x00003600, 0x00003f00, 0x0000f700, 0x0000cc00, + 0x00003400, 0x0000a500, 0x0000e500, 0x0000f100, + 0x00007100, 0x0000d800, 0x00003100, 0x00001500, + 0x00000400, 0x0000c700, 0x00002300, 0x0000c300, + 0x00001800, 0x00009600, 0x00000500, 0x00009a00, + 0x00000700, 0x00001200, 0x00008000, 0x0000e200, + 0x0000eb00, 0x00002700, 0x0000b200, 0x00007500, + 0x00000900, 0x00008300, 0x00002c00, 0x00001a00, + 0x00001b00, 0x00006e00, 0x00005a00, 0x0000a000, + 0x00005200, 0x00003b00, 0x0000d600, 0x0000b300, + 0x00002900, 0x0000e300, 0x00002f00, 0x00008400, + 0x00005300, 0x0000d100, 0x00000000, 0x0000ed00, + 0x00002000, 0x0000fc00, 0x0000b100, 0x00005b00, + 0x00006a00, 0x0000cb00, 0x0000be00, 0x00003900, + 0x00004a00, 0x00004c00, 0x00005800, 0x0000cf00, + 0x0000d000, 0x0000ef00, 0x0000aa00, 0x0000fb00, + 0x00004300, 0x00004d00, 0x00003300, 0x00008500, + 0x00004500, 0x0000f900, 0x00000200, 0x00007f00, + 0x00005000, 0x00003c00, 0x00009f00, 0x0000a800, + 0x00005100, 0x0000a300, 0x00004000, 0x00008f00, + 0x00009200, 0x00009d00, 0x00003800, 0x0000f500, + 0x0000bc00, 0x0000b600, 0x0000da00, 0x00002100, + 0x00001000, 0x0000ff00, 0x0000f300, 0x0000d200, + 0x0000cd00, 0x00000c00, 0x00001300, 0x0000ec00, + 0x00005f00, 0x00009700, 0x00004400, 0x00001700, + 0x0000c400, 0x0000a700, 0x00007e00, 0x00003d00, + 0x00006400, 0x00005d00, 0x00001900, 0x00007300, + 0x00006000, 0x00008100, 0x00004f00, 0x0000dc00, + 0x00002200, 0x00002a00, 0x00009000, 0x00008800, + 0x00004600, 0x0000ee00, 0x0000b800, 0x00001400, + 0x0000de00, 0x00005e00, 0x00000b00, 0x0000db00, + 0x0000e000, 0x00003200, 0x00003a00, 0x00000a00, + 0x00004900, 0x00000600, 0x00002400, 0x00005c00, + 0x0000c200, 0x0000d300, 0x0000ac00, 0x00006200, + 0x00009100, 0x00009500, 0x0000e400, 0x00007900, + 0x0000e700, 0x0000c800, 0x00003700, 0x00006d00, + 0x00008d00, 0x0000d500, 0x00004e00, 0x0000a900, + 0x00006c00, 0x00005600, 0x0000f400, 0x0000ea00, + 0x00006500, 0x00007a00, 0x0000ae00, 0x00000800, + 0x0000ba00, 0x00007800, 0x00002500, 0x00002e00, + 0x00001c00, 0x0000a600, 0x0000b400, 0x0000c600, + 0x0000e800, 0x0000dd00, 0x00007400, 0x00001f00, + 0x00004b00, 0x0000bd00, 0x00008b00, 0x00008a00, + 0x00007000, 0x00003e00, 0x0000b500, 0x00006600, + 0x00004800, 0x00000300, 0x0000f600, 0x00000e00, + 0x00006100, 0x00003500, 0x00005700, 0x0000b900, + 0x00008600, 0x0000c100, 0x00001d00, 0x00009e00, + 0x0000e100, 0x0000f800, 0x00009800, 0x00001100, + 0x00006900, 0x0000d900, 0x00008e00, 0x00009400, + 0x00009b00, 0x00001e00, 0x00008700, 0x0000e900, + 0x0000ce00, 0x00005500, 0x00002800, 0x0000df00, + 0x00008c00, 0x0000a100, 0x00008900, 0x00000d00, + 0x0000bf00, 0x0000e600, 0x00004200, 0x00006800, + 0x00004100, 0x00009900, 0x00002d00, 0x00000f00, + 0x0000b000, 0x00005400, 0x0000bb00, 0x00001600, + }, { + 0x00630000, 0x007c0000, 0x00770000, 0x007b0000, + 0x00f20000, 0x006b0000, 0x006f0000, 0x00c50000, + 0x00300000, 0x00010000, 0x00670000, 0x002b0000, + 0x00fe0000, 0x00d70000, 0x00ab0000, 0x00760000, + 0x00ca0000, 0x00820000, 0x00c90000, 0x007d0000, + 0x00fa0000, 0x00590000, 0x00470000, 0x00f00000, + 0x00ad0000, 0x00d40000, 0x00a20000, 0x00af0000, + 0x009c0000, 0x00a40000, 0x00720000, 0x00c00000, + 0x00b70000, 0x00fd0000, 0x00930000, 0x00260000, + 0x00360000, 0x003f0000, 0x00f70000, 0x00cc0000, + 0x00340000, 0x00a50000, 0x00e50000, 0x00f10000, + 0x00710000, 0x00d80000, 0x00310000, 0x00150000, + 0x00040000, 0x00c70000, 0x00230000, 0x00c30000, + 0x00180000, 0x00960000, 0x00050000, 0x009a0000, + 0x00070000, 0x00120000, 0x00800000, 0x00e20000, + 0x00eb0000, 0x00270000, 0x00b20000, 0x00750000, + 0x00090000, 0x00830000, 0x002c0000, 0x001a0000, + 0x001b0000, 0x006e0000, 0x005a0000, 0x00a00000, + 0x00520000, 0x003b0000, 0x00d60000, 0x00b30000, + 0x00290000, 0x00e30000, 0x002f0000, 0x00840000, + 0x00530000, 0x00d10000, 0x00000000, 0x00ed0000, + 0x00200000, 0x00fc0000, 0x00b10000, 0x005b0000, + 0x006a0000, 0x00cb0000, 0x00be0000, 0x00390000, + 0x004a0000, 0x004c0000, 0x00580000, 0x00cf0000, + 0x00d00000, 0x00ef0000, 0x00aa0000, 0x00fb0000, + 0x00430000, 0x004d0000, 0x00330000, 0x00850000, + 0x00450000, 0x00f90000, 0x00020000, 0x007f0000, + 0x00500000, 0x003c0000, 0x009f0000, 0x00a80000, + 0x00510000, 0x00a30000, 0x00400000, 0x008f0000, + 0x00920000, 0x009d0000, 0x00380000, 0x00f50000, + 0x00bc0000, 0x00b60000, 0x00da0000, 0x00210000, + 0x00100000, 0x00ff0000, 0x00f30000, 0x00d20000, + 0x00cd0000, 0x000c0000, 0x00130000, 0x00ec0000, + 0x005f0000, 0x00970000, 0x00440000, 0x00170000, + 0x00c40000, 0x00a70000, 0x007e0000, 0x003d0000, + 0x00640000, 0x005d0000, 0x00190000, 0x00730000, + 0x00600000, 0x00810000, 0x004f0000, 0x00dc0000, + 0x00220000, 0x002a0000, 0x00900000, 0x00880000, + 0x00460000, 0x00ee0000, 0x00b80000, 0x00140000, + 0x00de0000, 0x005e0000, 0x000b0000, 0x00db0000, + 0x00e00000, 0x00320000, 0x003a0000, 0x000a0000, + 0x00490000, 0x00060000, 0x00240000, 0x005c0000, + 0x00c20000, 0x00d30000, 0x00ac0000, 0x00620000, + 0x00910000, 0x00950000, 0x00e40000, 0x00790000, + 0x00e70000, 0x00c80000, 0x00370000, 0x006d0000, + 0x008d0000, 0x00d50000, 0x004e0000, 0x00a90000, + 0x006c0000, 0x00560000, 0x00f40000, 0x00ea0000, + 0x00650000, 0x007a0000, 0x00ae0000, 0x00080000, + 0x00ba0000, 0x00780000, 0x00250000, 0x002e0000, + 0x001c0000, 0x00a60000, 0x00b40000, 0x00c60000, + 0x00e80000, 0x00dd0000, 0x00740000, 0x001f0000, + 0x004b0000, 0x00bd0000, 0x008b0000, 0x008a0000, + 0x00700000, 0x003e0000, 0x00b50000, 0x00660000, + 0x00480000, 0x00030000, 0x00f60000, 0x000e0000, + 0x00610000, 0x00350000, 0x00570000, 0x00b90000, + 0x00860000, 0x00c10000, 0x001d0000, 0x009e0000, + 0x00e10000, 0x00f80000, 0x00980000, 0x00110000, + 0x00690000, 0x00d90000, 0x008e0000, 0x00940000, + 0x009b0000, 0x001e0000, 0x00870000, 0x00e90000, + 0x00ce0000, 0x00550000, 0x00280000, 0x00df0000, + 0x008c0000, 0x00a10000, 0x00890000, 0x000d0000, + 0x00bf0000, 0x00e60000, 0x00420000, 0x00680000, + 0x00410000, 0x00990000, 0x002d0000, 0x000f0000, + 0x00b00000, 0x00540000, 0x00bb0000, 0x00160000, + }, { + 0x63000000, 0x7c000000, 0x77000000, 0x7b000000, + 0xf2000000, 0x6b000000, 0x6f000000, 0xc5000000, + 0x30000000, 0x01000000, 0x67000000, 0x2b000000, + 0xfe000000, 0xd7000000, 0xab000000, 0x76000000, + 0xca000000, 0x82000000, 0xc9000000, 0x7d000000, + 0xfa000000, 0x59000000, 0x47000000, 0xf0000000, + 0xad000000, 0xd4000000, 0xa2000000, 0xaf000000, + 0x9c000000, 0xa4000000, 0x72000000, 0xc0000000, + 0xb7000000, 0xfd000000, 0x93000000, 0x26000000, + 0x36000000, 0x3f000000, 0xf7000000, 0xcc000000, + 0x34000000, 0xa5000000, 0xe5000000, 0xf1000000, + 0x71000000, 0xd8000000, 0x31000000, 0x15000000, + 0x04000000, 0xc7000000, 0x23000000, 0xc3000000, + 0x18000000, 0x96000000, 0x05000000, 0x9a000000, + 0x07000000, 0x12000000, 0x80000000, 0xe2000000, + 0xeb000000, 0x27000000, 0xb2000000, 0x75000000, + 0x09000000, 0x83000000, 0x2c000000, 0x1a000000, + 0x1b000000, 0x6e000000, 0x5a000000, 0xa0000000, + 0x52000000, 0x3b000000, 0xd6000000, 0xb3000000, + 0x29000000, 0xe3000000, 0x2f000000, 0x84000000, + 0x53000000, 0xd1000000, 0x00000000, 0xed000000, + 0x20000000, 0xfc000000, 0xb1000000, 0x5b000000, + 0x6a000000, 0xcb000000, 0xbe000000, 0x39000000, + 0x4a000000, 0x4c000000, 0x58000000, 0xcf000000, + 0xd0000000, 0xef000000, 0xaa000000, 0xfb000000, + 0x43000000, 0x4d000000, 0x33000000, 0x85000000, + 0x45000000, 0xf9000000, 0x02000000, 0x7f000000, + 0x50000000, 0x3c000000, 0x9f000000, 0xa8000000, + 0x51000000, 0xa3000000, 0x40000000, 0x8f000000, + 0x92000000, 0x9d000000, 0x38000000, 0xf5000000, + 0xbc000000, 0xb6000000, 0xda000000, 0x21000000, + 0x10000000, 0xff000000, 0xf3000000, 0xd2000000, + 0xcd000000, 0x0c000000, 0x13000000, 0xec000000, + 0x5f000000, 0x97000000, 0x44000000, 0x17000000, + 0xc4000000, 0xa7000000, 0x7e000000, 0x3d000000, + 0x64000000, 0x5d000000, 0x19000000, 0x73000000, + 0x60000000, 0x81000000, 0x4f000000, 0xdc000000, + 0x22000000, 0x2a000000, 0x90000000, 0x88000000, + 0x46000000, 0xee000000, 0xb8000000, 0x14000000, + 0xde000000, 0x5e000000, 0x0b000000, 0xdb000000, + 0xe0000000, 0x32000000, 0x3a000000, 0x0a000000, + 0x49000000, 0x06000000, 0x24000000, 0x5c000000, + 0xc2000000, 0xd3000000, 0xac000000, 0x62000000, + 0x91000000, 0x95000000, 0xe4000000, 0x79000000, + 0xe7000000, 0xc8000000, 0x37000000, 0x6d000000, + 0x8d000000, 0xd5000000, 0x4e000000, 0xa9000000, + 0x6c000000, 0x56000000, 0xf4000000, 0xea000000, + 0x65000000, 0x7a000000, 0xae000000, 0x08000000, + 0xba000000, 0x78000000, 0x25000000, 0x2e000000, + 0x1c000000, 0xa6000000, 0xb4000000, 0xc6000000, + 0xe8000000, 0xdd000000, 0x74000000, 0x1f000000, + 0x4b000000, 0xbd000000, 0x8b000000, 0x8a000000, + 0x70000000, 0x3e000000, 0xb5000000, 0x66000000, + 0x48000000, 0x03000000, 0xf6000000, 0x0e000000, + 0x61000000, 0x35000000, 0x57000000, 0xb9000000, + 0x86000000, 0xc1000000, 0x1d000000, 0x9e000000, + 0xe1000000, 0xf8000000, 0x98000000, 0x11000000, + 0x69000000, 0xd9000000, 0x8e000000, 0x94000000, + 0x9b000000, 0x1e000000, 0x87000000, 0xe9000000, + 0xce000000, 0x55000000, 0x28000000, 0xdf000000, + 0x8c000000, 0xa1000000, 0x89000000, 0x0d000000, + 0xbf000000, 0xe6000000, 0x42000000, 0x68000000, + 0x41000000, 0x99000000, 0x2d000000, 0x0f000000, + 0xb0000000, 0x54000000, 0xbb000000, 0x16000000, } +}; - for (i = 0; i < 256; ++i) { - p = (i ? pow_tab[255 - log_tab[i]] : 0); - q = ((p >> 7) | (p << 1)) ^ ((p >> 6) | (p << 2)); - p ^= 0x63 ^ q ^ ((q >> 6) | (q << 2)); - sbx_tab[i] = p; - isb_tab[p] = (u8) i; +const u32 crypto_it_tab[4][256] = { + { + 0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, + 0xcb6bab3b, 0xf1459d1f, 0xab58faac, 0x9303e34b, + 0x55fa3020, 0xf66d76ad, 0x9176cc88, 0x254c02f5, + 0xfcd7e54f, 0xd7cb2ac5, 0x80443526, 0x8fa362b5, + 0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d, + 0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b, + 0xe75f8f03, 0x959c9215, 0xeb7a6dbf, 0xda595295, + 0x2d83bed4, 0xd3217458, 0x2969e049, 0x44c8c98e, + 0x6a89c275, 0x78798ef4, 0x6b3e5899, 0xdd71b927, + 0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d, + 0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362, + 0xe07764b1, 0x84ae6bbb, 0x1ca081fe, 0x942b08f9, + 0x58684870, 0x19fd458f, 0x876cde94, 0xb7f87b52, + 0x23d373ab, 0xe2024b72, 0x578f1fe3, 0x2aab5566, + 0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3, + 0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed, + 0x2b1ccf8a, 0x92b479a7, 0xf0f207f3, 0xa1e2694e, + 0xcdf4da65, 0xd5be0506, 0x1f6234d1, 0x8afea6c4, + 0x9d532e34, 0xa055f3a2, 0x32e18a05, 0x75ebf6a4, + 0x39ec830b, 0xaaef6040, 0x069f715e, 0x51106ebd, + 0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d, + 0xb58d5491, 0x055dc471, 0x6fd40604, 0xff155060, + 0x24fb9819, 0x97e9bdd6, 0xcc434089, 0x779ed967, + 0xbd42e8b0, 0x888b8907, 0x385b19e7, 0xdbeec879, + 0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000, + 0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c, + 0xfbff0efd, 0x5638850f, 0x1ed5ae3d, 0x27392d36, + 0x64d90f0a, 0x21a65c68, 0xd1545b9b, 0x3a2e3624, + 0xb1670a0c, 0x0fe75793, 0xd296eeb4, 0x9e919b1b, + 0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c, + 0x0aba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12, + 0x0b0d090e, 0xadc78bf2, 0xb9a8b62d, 0xc8a91e14, + 0x8519f157, 0x4c0775af, 0xbbdd99ee, 0xfd607fa3, + 0x9f2601f7, 0xbcf5725c, 0xc53b6644, 0x347efb5b, + 0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8, + 0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684, + 0x7d244a85, 0xf83dbbd2, 0x1132f9ae, 0x6da129c7, + 0x4b2f9e1d, 0xf330b2dc, 0xec52860d, 0xd0e3c177, + 0x6c16b32b, 0x99b970a9, 0xfa489411, 0x2264e947, + 0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322, + 0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498, + 0xcf81f5a6, 0x28de7aa5, 0x268eb7da, 0xa4bfad3f, + 0xe49d3a2c, 0x0d927850, 0x9bcc5f6a, 0x62467e54, + 0xc2138df6, 0xe8b8d890, 0x5ef7392e, 0xf5afc382, + 0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf, + 0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb, + 0x097826cd, 0xf418596e, 0x01b79aec, 0xa89a4f83, + 0x656e95e6, 0x7ee6ffaa, 0x08cfbc21, 0xe6e815ef, + 0xd99be7ba, 0xce366f4a, 0xd4099fea, 0xd67cb029, + 0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235, + 0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733, + 0x4a9804f1, 0xf7daec41, 0x0e50cd7f, 0x2ff69117, + 0x8dd64d76, 0x4db0ef43, 0x544daacc, 0xdf0496e4, + 0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1, 0x7f516546, + 0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb, + 0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d, + 0x8c61d79a, 0x7a0ca137, 0x8e14f859, 0x893c13eb, + 0xee27a9ce, 0x35c961b7, 0xede51ce1, 0x3cb1477a, + 0x59dfd29c, 0x3f73f255, 0x79ce1418, 0xbf37c773, + 0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478, + 0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2, + 0x72c31d16, 0x0c25e2bc, 0x8b493c28, 0x41950dff, + 0x7101a839, 0xdeb30c08, 0x9ce4b4d8, 0x90c15664, + 0x6184cb7b, 0x70b632d5, 0x745c6c48, 0x4257b8d0, + }, { + 0xa7f45150, 0x65417e53, 0xa4171ac3, 0x5e273a96, + 0x6bab3bcb, 0x459d1ff1, 0x58faacab, 0x03e34b93, + 0xfa302055, 0x6d76adf6, 0x76cc8891, 0x4c02f525, + 0xd7e54ffc, 0xcb2ac5d7, 0x44352680, 0xa362b58f, + 0x5ab1de49, 0x1bba2567, 0x0eea4598, 0xc0fe5de1, + 0x752fc302, 0xf04c8112, 0x97468da3, 0xf9d36bc6, + 0x5f8f03e7, 0x9c921595, 0x7a6dbfeb, 0x595295da, + 0x83bed42d, 0x217458d3, 0x69e04929, 0xc8c98e44, + 0x89c2756a, 0x798ef478, 0x3e58996b, 0x71b927dd, + 0x4fe1beb6, 0xad88f017, 0xac20c966, 0x3ace7db4, + 0x4adf6318, 0x311ae582, 0x33519760, 0x7f536245, + 0x7764b1e0, 0xae6bbb84, 0xa081fe1c, 0x2b08f994, + 0x68487058, 0xfd458f19, 0x6cde9487, 0xf87b52b7, + 0xd373ab23, 0x024b72e2, 0x8f1fe357, 0xab55662a, + 0x28ebb207, 0xc2b52f03, 0x7bc5869a, 0x0837d3a5, + 0x872830f2, 0xa5bf23b2, 0x6a0302ba, 0x8216ed5c, + 0x1ccf8a2b, 0xb479a792, 0xf207f3f0, 0xe2694ea1, + 0xf4da65cd, 0xbe0506d5, 0x6234d11f, 0xfea6c48a, + 0x532e349d, 0x55f3a2a0, 0xe18a0532, 0xebf6a475, + 0xec830b39, 0xef6040aa, 0x9f715e06, 0x106ebd51, + 0x8a213ef9, 0x06dd963d, 0x053eddae, 0xbde64d46, + 0x8d5491b5, 0x5dc47105, 0xd406046f, 0x155060ff, + 0xfb981924, 0xe9bdd697, 0x434089cc, 0x9ed96777, + 0x42e8b0bd, 0x8b890788, 0x5b19e738, 0xeec879db, + 0x0a7ca147, 0x0f427ce9, 0x1e84f8c9, 0x00000000, + 0x86800983, 0xed2b3248, 0x70111eac, 0x725a6c4e, + 0xff0efdfb, 0x38850f56, 0xd5ae3d1e, 0x392d3627, + 0xd90f0a64, 0xa65c6821, 0x545b9bd1, 0x2e36243a, + 0x670a0cb1, 0xe757930f, 0x96eeb4d2, 0x919b1b9e, + 0xc5c0804f, 0x20dc61a2, 0x4b775a69, 0x1a121c16, + 0xba93e20a, 0x2aa0c0e5, 0xe0223c43, 0x171b121d, + 0x0d090e0b, 0xc78bf2ad, 0xa8b62db9, 0xa91e14c8, + 0x19f15785, 0x0775af4c, 0xdd99eebb, 0x607fa3fd, + 0x2601f79f, 0xf5725cbc, 0x3b6644c5, 0x7efb5b34, + 0x29438b76, 0xc623cbdc, 0xfcedb668, 0xf1e4b863, + 0xdc31d7ca, 0x85634210, 0x22971340, 0x11c68420, + 0x244a857d, 0x3dbbd2f8, 0x32f9ae11, 0xa129c76d, + 0x2f9e1d4b, 0x30b2dcf3, 0x52860dec, 0xe3c177d0, + 0x16b32b6c, 0xb970a999, 0x489411fa, 0x64e94722, + 0x8cfca8c4, 0x3ff0a01a, 0x2c7d56d8, 0x903322ef, + 0x4e4987c7, 0xd138d9c1, 0xa2ca8cfe, 0x0bd49836, + 0x81f5a6cf, 0xde7aa528, 0x8eb7da26, 0xbfad3fa4, + 0x9d3a2ce4, 0x9278500d, 0xcc5f6a9b, 0x467e5462, + 0x138df6c2, 0xb8d890e8, 0xf7392e5e, 0xafc382f5, + 0x805d9fbe, 0x93d0697c, 0x2dd56fa9, 0x1225cfb3, + 0x99acc83b, 0x7d1810a7, 0x639ce86e, 0xbb3bdb7b, + 0x7826cd09, 0x18596ef4, 0xb79aec01, 0x9a4f83a8, + 0x6e95e665, 0xe6ffaa7e, 0xcfbc2108, 0xe815efe6, + 0x9be7bad9, 0x366f4ace, 0x099fead4, 0x7cb029d6, + 0xb2a431af, 0x233f2a31, 0x94a5c630, 0x66a235c0, + 0xbc4e7437, 0xca82fca6, 0xd090e0b0, 0xd8a73315, + 0x9804f14a, 0xdaec41f7, 0x50cd7f0e, 0xf691172f, + 0xd64d768d, 0xb0ef434d, 0x4daacc54, 0x0496e4df, + 0xb5d19ee3, 0x886a4c1b, 0x1f2cc1b8, 0x5165467f, + 0xea5e9d04, 0x358c015d, 0x7487fa73, 0x410bfb2e, + 0x1d67b35a, 0xd2db9252, 0x5610e933, 0x47d66d13, + 0x61d79a8c, 0x0ca1377a, 0x14f8598e, 0x3c13eb89, + 0x27a9ceee, 0xc961b735, 0xe51ce1ed, 0xb1477a3c, + 0xdfd29c59, 0x73f2553f, 0xce141879, 0x37c773bf, + 0xcdf753ea, 0xaafd5f5b, 0x6f3ddf14, 0xdb447886, + 0xf3afca81, 0xc468b93e, 0x3424382c, 0x40a3c25f, + 0xc31d1672, 0x25e2bc0c, 0x493c288b, 0x950dff41, + 0x01a83971, 0xb30c08de, 0xe4b4d89c, 0xc1566490, + 0x84cb7b61, 0xb632d570, 0x5c6c4874, 0x57b8d042, + }, { + 0xf45150a7, 0x417e5365, 0x171ac3a4, 0x273a965e, + 0xab3bcb6b, 0x9d1ff145, 0xfaacab58, 0xe34b9303, + 0x302055fa, 0x76adf66d, 0xcc889176, 0x02f5254c, + 0xe54ffcd7, 0x2ac5d7cb, 0x35268044, 0x62b58fa3, + 0xb1de495a, 0xba25671b, 0xea45980e, 0xfe5de1c0, + 0x2fc30275, 0x4c8112f0, 0x468da397, 0xd36bc6f9, + 0x8f03e75f, 0x9215959c, 0x6dbfeb7a, 0x5295da59, + 0xbed42d83, 0x7458d321, 0xe0492969, 0xc98e44c8, + 0xc2756a89, 0x8ef47879, 0x58996b3e, 0xb927dd71, + 0xe1beb64f, 0x88f017ad, 0x20c966ac, 0xce7db43a, + 0xdf63184a, 0x1ae58231, 0x51976033, 0x5362457f, + 0x64b1e077, 0x6bbb84ae, 0x81fe1ca0, 0x08f9942b, + 0x48705868, 0x458f19fd, 0xde94876c, 0x7b52b7f8, + 0x73ab23d3, 0x4b72e202, 0x1fe3578f, 0x55662aab, + 0xebb20728, 0xb52f03c2, 0xc5869a7b, 0x37d3a508, + 0x2830f287, 0xbf23b2a5, 0x0302ba6a, 0x16ed5c82, + 0xcf8a2b1c, 0x79a792b4, 0x07f3f0f2, 0x694ea1e2, + 0xda65cdf4, 0x0506d5be, 0x34d11f62, 0xa6c48afe, + 0x2e349d53, 0xf3a2a055, 0x8a0532e1, 0xf6a475eb, + 0x830b39ec, 0x6040aaef, 0x715e069f, 0x6ebd5110, + 0x213ef98a, 0xdd963d06, 0x3eddae05, 0xe64d46bd, + 0x5491b58d, 0xc471055d, 0x06046fd4, 0x5060ff15, + 0x981924fb, 0xbdd697e9, 0x4089cc43, 0xd967779e, + 0xe8b0bd42, 0x8907888b, 0x19e7385b, 0xc879dbee, + 0x7ca1470a, 0x427ce90f, 0x84f8c91e, 0x00000000, + 0x80098386, 0x2b3248ed, 0x111eac70, 0x5a6c4e72, + 0x0efdfbff, 0x850f5638, 0xae3d1ed5, 0x2d362739, + 0x0f0a64d9, 0x5c6821a6, 0x5b9bd154, 0x36243a2e, + 0x0a0cb167, 0x57930fe7, 0xeeb4d296, 0x9b1b9e91, + 0xc0804fc5, 0xdc61a220, 0x775a694b, 0x121c161a, + 0x93e20aba, 0xa0c0e52a, 0x223c43e0, 0x1b121d17, + 0x090e0b0d, 0x8bf2adc7, 0xb62db9a8, 0x1e14c8a9, + 0xf1578519, 0x75af4c07, 0x99eebbdd, 0x7fa3fd60, + 0x01f79f26, 0x725cbcf5, 0x6644c53b, 0xfb5b347e, + 0x438b7629, 0x23cbdcc6, 0xedb668fc, 0xe4b863f1, + 0x31d7cadc, 0x63421085, 0x97134022, 0xc6842011, + 0x4a857d24, 0xbbd2f83d, 0xf9ae1132, 0x29c76da1, + 0x9e1d4b2f, 0xb2dcf330, 0x860dec52, 0xc177d0e3, + 0xb32b6c16, 0x70a999b9, 0x9411fa48, 0xe9472264, + 0xfca8c48c, 0xf0a01a3f, 0x7d56d82c, 0x3322ef90, + 0x4987c74e, 0x38d9c1d1, 0xca8cfea2, 0xd498360b, + 0xf5a6cf81, 0x7aa528de, 0xb7da268e, 0xad3fa4bf, + 0x3a2ce49d, 0x78500d92, 0x5f6a9bcc, 0x7e546246, + 0x8df6c213, 0xd890e8b8, 0x392e5ef7, 0xc382f5af, + 0x5d9fbe80, 0xd0697c93, 0xd56fa92d, 0x25cfb312, + 0xacc83b99, 0x1810a77d, 0x9ce86e63, 0x3bdb7bbb, + 0x26cd0978, 0x596ef418, 0x9aec01b7, 0x4f83a89a, + 0x95e6656e, 0xffaa7ee6, 0xbc2108cf, 0x15efe6e8, + 0xe7bad99b, 0x6f4ace36, 0x9fead409, 0xb029d67c, + 0xa431afb2, 0x3f2a3123, 0xa5c63094, 0xa235c066, + 0x4e7437bc, 0x82fca6ca, 0x90e0b0d0, 0xa73315d8, + 0x04f14a98, 0xec41f7da, 0xcd7f0e50, 0x91172ff6, + 0x4d768dd6, 0xef434db0, 0xaacc544d, 0x96e4df04, + 0xd19ee3b5, 0x6a4c1b88, 0x2cc1b81f, 0x65467f51, + 0x5e9d04ea, 0x8c015d35, 0x87fa7374, 0x0bfb2e41, + 0x67b35a1d, 0xdb9252d2, 0x10e93356, 0xd66d1347, + 0xd79a8c61, 0xa1377a0c, 0xf8598e14, 0x13eb893c, + 0xa9ceee27, 0x61b735c9, 0x1ce1ede5, 0x477a3cb1, + 0xd29c59df, 0xf2553f73, 0x141879ce, 0xc773bf37, + 0xf753eacd, 0xfd5f5baa, 0x3ddf146f, 0x447886db, + 0xafca81f3, 0x68b93ec4, 0x24382c34, 0xa3c25f40, + 0x1d1672c3, 0xe2bc0c25, 0x3c288b49, 0x0dff4195, + 0xa8397101, 0x0c08deb3, 0xb4d89ce4, 0x566490c1, + 0xcb7b6184, 0x32d570b6, 0x6c48745c, 0xb8d04257, + }, { + 0x5150a7f4, 0x7e536541, 0x1ac3a417, 0x3a965e27, + 0x3bcb6bab, 0x1ff1459d, 0xacab58fa, 0x4b9303e3, + 0x2055fa30, 0xadf66d76, 0x889176cc, 0xf5254c02, + 0x4ffcd7e5, 0xc5d7cb2a, 0x26804435, 0xb58fa362, + 0xde495ab1, 0x25671bba, 0x45980eea, 0x5de1c0fe, + 0xc302752f, 0x8112f04c, 0x8da39746, 0x6bc6f9d3, + 0x03e75f8f, 0x15959c92, 0xbfeb7a6d, 0x95da5952, + 0xd42d83be, 0x58d32174, 0x492969e0, 0x8e44c8c9, + 0x756a89c2, 0xf478798e, 0x996b3e58, 0x27dd71b9, + 0xbeb64fe1, 0xf017ad88, 0xc966ac20, 0x7db43ace, + 0x63184adf, 0xe582311a, 0x97603351, 0x62457f53, + 0xb1e07764, 0xbb84ae6b, 0xfe1ca081, 0xf9942b08, + 0x70586848, 0x8f19fd45, 0x94876cde, 0x52b7f87b, + 0xab23d373, 0x72e2024b, 0xe3578f1f, 0x662aab55, + 0xb20728eb, 0x2f03c2b5, 0x869a7bc5, 0xd3a50837, + 0x30f28728, 0x23b2a5bf, 0x02ba6a03, 0xed5c8216, + 0x8a2b1ccf, 0xa792b479, 0xf3f0f207, 0x4ea1e269, + 0x65cdf4da, 0x06d5be05, 0xd11f6234, 0xc48afea6, + 0x349d532e, 0xa2a055f3, 0x0532e18a, 0xa475ebf6, + 0x0b39ec83, 0x40aaef60, 0x5e069f71, 0xbd51106e, + 0x3ef98a21, 0x963d06dd, 0xddae053e, 0x4d46bde6, + 0x91b58d54, 0x71055dc4, 0x046fd406, 0x60ff1550, + 0x1924fb98, 0xd697e9bd, 0x89cc4340, 0x67779ed9, + 0xb0bd42e8, 0x07888b89, 0xe7385b19, 0x79dbeec8, + 0xa1470a7c, 0x7ce90f42, 0xf8c91e84, 0x00000000, + 0x09838680, 0x3248ed2b, 0x1eac7011, 0x6c4e725a, + 0xfdfbff0e, 0x0f563885, 0x3d1ed5ae, 0x3627392d, + 0x0a64d90f, 0x6821a65c, 0x9bd1545b, 0x243a2e36, + 0x0cb1670a, 0x930fe757, 0xb4d296ee, 0x1b9e919b, + 0x804fc5c0, 0x61a220dc, 0x5a694b77, 0x1c161a12, + 0xe20aba93, 0xc0e52aa0, 0x3c43e022, 0x121d171b, + 0x0e0b0d09, 0xf2adc78b, 0x2db9a8b6, 0x14c8a91e, + 0x578519f1, 0xaf4c0775, 0xeebbdd99, 0xa3fd607f, + 0xf79f2601, 0x5cbcf572, 0x44c53b66, 0x5b347efb, + 0x8b762943, 0xcbdcc623, 0xb668fced, 0xb863f1e4, + 0xd7cadc31, 0x42108563, 0x13402297, 0x842011c6, + 0x857d244a, 0xd2f83dbb, 0xae1132f9, 0xc76da129, + 0x1d4b2f9e, 0xdcf330b2, 0x0dec5286, 0x77d0e3c1, + 0x2b6c16b3, 0xa999b970, 0x11fa4894, 0x472264e9, + 0xa8c48cfc, 0xa01a3ff0, 0x56d82c7d, 0x22ef9033, + 0x87c74e49, 0xd9c1d138, 0x8cfea2ca, 0x98360bd4, + 0xa6cf81f5, 0xa528de7a, 0xda268eb7, 0x3fa4bfad, + 0x2ce49d3a, 0x500d9278, 0x6a9bcc5f, 0x5462467e, + 0xf6c2138d, 0x90e8b8d8, 0x2e5ef739, 0x82f5afc3, + 0x9fbe805d, 0x697c93d0, 0x6fa92dd5, 0xcfb31225, + 0xc83b99ac, 0x10a77d18, 0xe86e639c, 0xdb7bbb3b, + 0xcd097826, 0x6ef41859, 0xec01b79a, 0x83a89a4f, + 0xe6656e95, 0xaa7ee6ff, 0x2108cfbc, 0xefe6e815, + 0xbad99be7, 0x4ace366f, 0xead4099f, 0x29d67cb0, + 0x31afb2a4, 0x2a31233f, 0xc63094a5, 0x35c066a2, + 0x7437bc4e, 0xfca6ca82, 0xe0b0d090, 0x3315d8a7, + 0xf14a9804, 0x41f7daec, 0x7f0e50cd, 0x172ff691, + 0x768dd64d, 0x434db0ef, 0xcc544daa, 0xe4df0496, + 0x9ee3b5d1, 0x4c1b886a, 0xc1b81f2c, 0x467f5165, + 0x9d04ea5e, 0x015d358c, 0xfa737487, 0xfb2e410b, + 0xb35a1d67, 0x9252d2db, 0xe9335610, 0x6d1347d6, + 0x9a8c61d7, 0x377a0ca1, 0x598e14f8, 0xeb893c13, + 0xceee27a9, 0xb735c961, 0xe1ede51c, 0x7a3cb147, + 0x9c59dfd2, 0x553f73f2, 0x1879ce14, 0x73bf37c7, + 0x53eacdf7, 0x5f5baafd, 0xdf146f3d, 0x7886db44, + 0xca81f3af, 0xb93ec468, 0x382c3424, 0xc25f40a3, + 0x1672c31d, 0xbc0c25e2, 0x288b493c, 0xff41950d, + 0x397101a8, 0x08deb30c, 0xd89ce4b4, 0x6490c156, + 0x7b6184cb, 0xd570b632, 0x48745c6c, 0xd04257b8, } +}; - for (i = 0; i < 256; ++i) { - p = sbx_tab[i]; - - t = p; - crypto_fl_tab[0][i] = t; - crypto_fl_tab[1][i] = rol32(t, 8); - crypto_fl_tab[2][i] = rol32(t, 16); - crypto_fl_tab[3][i] = rol32(t, 24); - - t = ((u32) ff_mult(2, p)) | - ((u32) p << 8) | - ((u32) p << 16) | ((u32) ff_mult(3, p) << 24); - - crypto_ft_tab[0][i] = t; - crypto_ft_tab[1][i] = rol32(t, 8); - crypto_ft_tab[2][i] = rol32(t, 16); - crypto_ft_tab[3][i] = rol32(t, 24); - - p = isb_tab[i]; - - t = p; - crypto_il_tab[0][i] = t; - crypto_il_tab[1][i] = rol32(t, 8); - crypto_il_tab[2][i] = rol32(t, 16); - crypto_il_tab[3][i] = rol32(t, 24); - - t = ((u32) ff_mult(14, p)) | - ((u32) ff_mult(9, p) << 8) | - ((u32) ff_mult(13, p) << 16) | - ((u32) ff_mult(11, p) << 24); - - crypto_it_tab[0][i] = t; - crypto_it_tab[1][i] = rol32(t, 8); - crypto_it_tab[2][i] = rol32(t, 16); - crypto_it_tab[3][i] = rol32(t, 24); +const u32 crypto_il_tab[4][256] = { + { + 0x00000052, 0x00000009, 0x0000006a, 0x000000d5, + 0x00000030, 0x00000036, 0x000000a5, 0x00000038, + 0x000000bf, 0x00000040, 0x000000a3, 0x0000009e, + 0x00000081, 0x000000f3, 0x000000d7, 0x000000fb, + 0x0000007c, 0x000000e3, 0x00000039, 0x00000082, + 0x0000009b, 0x0000002f, 0x000000ff, 0x00000087, + 0x00000034, 0x0000008e, 0x00000043, 0x00000044, + 0x000000c4, 0x000000de, 0x000000e9, 0x000000cb, + 0x00000054, 0x0000007b, 0x00000094, 0x00000032, + 0x000000a6, 0x000000c2, 0x00000023, 0x0000003d, + 0x000000ee, 0x0000004c, 0x00000095, 0x0000000b, + 0x00000042, 0x000000fa, 0x000000c3, 0x0000004e, + 0x00000008, 0x0000002e, 0x000000a1, 0x00000066, + 0x00000028, 0x000000d9, 0x00000024, 0x000000b2, + 0x00000076, 0x0000005b, 0x000000a2, 0x00000049, + 0x0000006d, 0x0000008b, 0x000000d1, 0x00000025, + 0x00000072, 0x000000f8, 0x000000f6, 0x00000064, + 0x00000086, 0x00000068, 0x00000098, 0x00000016, + 0x000000d4, 0x000000a4, 0x0000005c, 0x000000cc, + 0x0000005d, 0x00000065, 0x000000b6, 0x00000092, + 0x0000006c, 0x00000070, 0x00000048, 0x00000050, + 0x000000fd, 0x000000ed, 0x000000b9, 0x000000da, + 0x0000005e, 0x00000015, 0x00000046, 0x00000057, + 0x000000a7, 0x0000008d, 0x0000009d, 0x00000084, + 0x00000090, 0x000000d8, 0x000000ab, 0x00000000, + 0x0000008c, 0x000000bc, 0x000000d3, 0x0000000a, + 0x000000f7, 0x000000e4, 0x00000058, 0x00000005, + 0x000000b8, 0x000000b3, 0x00000045, 0x00000006, + 0x000000d0, 0x0000002c, 0x0000001e, 0x0000008f, + 0x000000ca, 0x0000003f, 0x0000000f, 0x00000002, + 0x000000c1, 0x000000af, 0x000000bd, 0x00000003, + 0x00000001, 0x00000013, 0x0000008a, 0x0000006b, + 0x0000003a, 0x00000091, 0x00000011, 0x00000041, + 0x0000004f, 0x00000067, 0x000000dc, 0x000000ea, + 0x00000097, 0x000000f2, 0x000000cf, 0x000000ce, + 0x000000f0, 0x000000b4, 0x000000e6, 0x00000073, + 0x00000096, 0x000000ac, 0x00000074, 0x00000022, + 0x000000e7, 0x000000ad, 0x00000035, 0x00000085, + 0x000000e2, 0x000000f9, 0x00000037, 0x000000e8, + 0x0000001c, 0x00000075, 0x000000df, 0x0000006e, + 0x00000047, 0x000000f1, 0x0000001a, 0x00000071, + 0x0000001d, 0x00000029, 0x000000c5, 0x00000089, + 0x0000006f, 0x000000b7, 0x00000062, 0x0000000e, + 0x000000aa, 0x00000018, 0x000000be, 0x0000001b, + 0x000000fc, 0x00000056, 0x0000003e, 0x0000004b, + 0x000000c6, 0x000000d2, 0x00000079, 0x00000020, + 0x0000009a, 0x000000db, 0x000000c0, 0x000000fe, + 0x00000078, 0x000000cd, 0x0000005a, 0x000000f4, + 0x0000001f, 0x000000dd, 0x000000a8, 0x00000033, + 0x00000088, 0x00000007, 0x000000c7, 0x00000031, + 0x000000b1, 0x00000012, 0x00000010, 0x00000059, + 0x00000027, 0x00000080, 0x000000ec, 0x0000005f, + 0x00000060, 0x00000051, 0x0000007f, 0x000000a9, + 0x00000019, 0x000000b5, 0x0000004a, 0x0000000d, + 0x0000002d, 0x000000e5, 0x0000007a, 0x0000009f, + 0x00000093, 0x000000c9, 0x0000009c, 0x000000ef, + 0x000000a0, 0x000000e0, 0x0000003b, 0x0000004d, + 0x000000ae, 0x0000002a, 0x000000f5, 0x000000b0, + 0x000000c8, 0x000000eb, 0x000000bb, 0x0000003c, + 0x00000083, 0x00000053, 0x00000099, 0x00000061, + 0x00000017, 0x0000002b, 0x00000004, 0x0000007e, + 0x000000ba, 0x00000077, 0x000000d6, 0x00000026, + 0x000000e1, 0x00000069, 0x00000014, 0x00000063, + 0x00000055, 0x00000021, 0x0000000c, 0x0000007d, + }, { + 0x00005200, 0x00000900, 0x00006a00, 0x0000d500, + 0x00003000, 0x00003600, 0x0000a500, 0x00003800, + 0x0000bf00, 0x00004000, 0x0000a300, 0x00009e00, + 0x00008100, 0x0000f300, 0x0000d700, 0x0000fb00, + 0x00007c00, 0x0000e300, 0x00003900, 0x00008200, + 0x00009b00, 0x00002f00, 0x0000ff00, 0x00008700, + 0x00003400, 0x00008e00, 0x00004300, 0x00004400, + 0x0000c400, 0x0000de00, 0x0000e900, 0x0000cb00, + 0x00005400, 0x00007b00, 0x00009400, 0x00003200, + 0x0000a600, 0x0000c200, 0x00002300, 0x00003d00, + 0x0000ee00, 0x00004c00, 0x00009500, 0x00000b00, + 0x00004200, 0x0000fa00, 0x0000c300, 0x00004e00, + 0x00000800, 0x00002e00, 0x0000a100, 0x00006600, + 0x00002800, 0x0000d900, 0x00002400, 0x0000b200, + 0x00007600, 0x00005b00, 0x0000a200, 0x00004900, + 0x00006d00, 0x00008b00, 0x0000d100, 0x00002500, + 0x00007200, 0x0000f800, 0x0000f600, 0x00006400, + 0x00008600, 0x00006800, 0x00009800, 0x00001600, + 0x0000d400, 0x0000a400, 0x00005c00, 0x0000cc00, + 0x00005d00, 0x00006500, 0x0000b600, 0x00009200, + 0x00006c00, 0x00007000, 0x00004800, 0x00005000, + 0x0000fd00, 0x0000ed00, 0x0000b900, 0x0000da00, + 0x00005e00, 0x00001500, 0x00004600, 0x00005700, + 0x0000a700, 0x00008d00, 0x00009d00, 0x00008400, + 0x00009000, 0x0000d800, 0x0000ab00, 0x00000000, + 0x00008c00, 0x0000bc00, 0x0000d300, 0x00000a00, + 0x0000f700, 0x0000e400, 0x00005800, 0x00000500, + 0x0000b800, 0x0000b300, 0x00004500, 0x00000600, + 0x0000d000, 0x00002c00, 0x00001e00, 0x00008f00, + 0x0000ca00, 0x00003f00, 0x00000f00, 0x00000200, + 0x0000c100, 0x0000af00, 0x0000bd00, 0x00000300, + 0x00000100, 0x00001300, 0x00008a00, 0x00006b00, + 0x00003a00, 0x00009100, 0x00001100, 0x00004100, + 0x00004f00, 0x00006700, 0x0000dc00, 0x0000ea00, + 0x00009700, 0x0000f200, 0x0000cf00, 0x0000ce00, + 0x0000f000, 0x0000b400, 0x0000e600, 0x00007300, + 0x00009600, 0x0000ac00, 0x00007400, 0x00002200, + 0x0000e700, 0x0000ad00, 0x00003500, 0x00008500, + 0x0000e200, 0x0000f900, 0x00003700, 0x0000e800, + 0x00001c00, 0x00007500, 0x0000df00, 0x00006e00, + 0x00004700, 0x0000f100, 0x00001a00, 0x00007100, + 0x00001d00, 0x00002900, 0x0000c500, 0x00008900, + 0x00006f00, 0x0000b700, 0x00006200, 0x00000e00, + 0x0000aa00, 0x00001800, 0x0000be00, 0x00001b00, + 0x0000fc00, 0x00005600, 0x00003e00, 0x00004b00, + 0x0000c600, 0x0000d200, 0x00007900, 0x00002000, + 0x00009a00, 0x0000db00, 0x0000c000, 0x0000fe00, + 0x00007800, 0x0000cd00, 0x00005a00, 0x0000f400, + 0x00001f00, 0x0000dd00, 0x0000a800, 0x00003300, + 0x00008800, 0x00000700, 0x0000c700, 0x00003100, + 0x0000b100, 0x00001200, 0x00001000, 0x00005900, + 0x00002700, 0x00008000, 0x0000ec00, 0x00005f00, + 0x00006000, 0x00005100, 0x00007f00, 0x0000a900, + 0x00001900, 0x0000b500, 0x00004a00, 0x00000d00, + 0x00002d00, 0x0000e500, 0x00007a00, 0x00009f00, + 0x00009300, 0x0000c900, 0x00009c00, 0x0000ef00, + 0x0000a000, 0x0000e000, 0x00003b00, 0x00004d00, + 0x0000ae00, 0x00002a00, 0x0000f500, 0x0000b000, + 0x0000c800, 0x0000eb00, 0x0000bb00, 0x00003c00, + 0x00008300, 0x00005300, 0x00009900, 0x00006100, + 0x00001700, 0x00002b00, 0x00000400, 0x00007e00, + 0x0000ba00, 0x00007700, 0x0000d600, 0x00002600, + 0x0000e100, 0x00006900, 0x00001400, 0x00006300, + 0x00005500, 0x00002100, 0x00000c00, 0x00007d00, + }, { + 0x00520000, 0x00090000, 0x006a0000, 0x00d50000, + 0x00300000, 0x00360000, 0x00a50000, 0x00380000, + 0x00bf0000, 0x00400000, 0x00a30000, 0x009e0000, + 0x00810000, 0x00f30000, 0x00d70000, 0x00fb0000, + 0x007c0000, 0x00e30000, 0x00390000, 0x00820000, + 0x009b0000, 0x002f0000, 0x00ff0000, 0x00870000, + 0x00340000, 0x008e0000, 0x00430000, 0x00440000, + 0x00c40000, 0x00de0000, 0x00e90000, 0x00cb0000, + 0x00540000, 0x007b0000, 0x00940000, 0x00320000, + 0x00a60000, 0x00c20000, 0x00230000, 0x003d0000, + 0x00ee0000, 0x004c0000, 0x00950000, 0x000b0000, + 0x00420000, 0x00fa0000, 0x00c30000, 0x004e0000, + 0x00080000, 0x002e0000, 0x00a10000, 0x00660000, + 0x00280000, 0x00d90000, 0x00240000, 0x00b20000, + 0x00760000, 0x005b0000, 0x00a20000, 0x00490000, + 0x006d0000, 0x008b0000, 0x00d10000, 0x00250000, + 0x00720000, 0x00f80000, 0x00f60000, 0x00640000, + 0x00860000, 0x00680000, 0x00980000, 0x00160000, + 0x00d40000, 0x00a40000, 0x005c0000, 0x00cc0000, + 0x005d0000, 0x00650000, 0x00b60000, 0x00920000, + 0x006c0000, 0x00700000, 0x00480000, 0x00500000, + 0x00fd0000, 0x00ed0000, 0x00b90000, 0x00da0000, + 0x005e0000, 0x00150000, 0x00460000, 0x00570000, + 0x00a70000, 0x008d0000, 0x009d0000, 0x00840000, + 0x00900000, 0x00d80000, 0x00ab0000, 0x00000000, + 0x008c0000, 0x00bc0000, 0x00d30000, 0x000a0000, + 0x00f70000, 0x00e40000, 0x00580000, 0x00050000, + 0x00b80000, 0x00b30000, 0x00450000, 0x00060000, + 0x00d00000, 0x002c0000, 0x001e0000, 0x008f0000, + 0x00ca0000, 0x003f0000, 0x000f0000, 0x00020000, + 0x00c10000, 0x00af0000, 0x00bd0000, 0x00030000, + 0x00010000, 0x00130000, 0x008a0000, 0x006b0000, + 0x003a0000, 0x00910000, 0x00110000, 0x00410000, + 0x004f0000, 0x00670000, 0x00dc0000, 0x00ea0000, + 0x00970000, 0x00f20000, 0x00cf0000, 0x00ce0000, + 0x00f00000, 0x00b40000, 0x00e60000, 0x00730000, + 0x00960000, 0x00ac0000, 0x00740000, 0x00220000, + 0x00e70000, 0x00ad0000, 0x00350000, 0x00850000, + 0x00e20000, 0x00f90000, 0x00370000, 0x00e80000, + 0x001c0000, 0x00750000, 0x00df0000, 0x006e0000, + 0x00470000, 0x00f10000, 0x001a0000, 0x00710000, + 0x001d0000, 0x00290000, 0x00c50000, 0x00890000, + 0x006f0000, 0x00b70000, 0x00620000, 0x000e0000, + 0x00aa0000, 0x00180000, 0x00be0000, 0x001b0000, + 0x00fc0000, 0x00560000, 0x003e0000, 0x004b0000, + 0x00c60000, 0x00d20000, 0x00790000, 0x00200000, + 0x009a0000, 0x00db0000, 0x00c00000, 0x00fe0000, + 0x00780000, 0x00cd0000, 0x005a0000, 0x00f40000, + 0x001f0000, 0x00dd0000, 0x00a80000, 0x00330000, + 0x00880000, 0x00070000, 0x00c70000, 0x00310000, + 0x00b10000, 0x00120000, 0x00100000, 0x00590000, + 0x00270000, 0x00800000, 0x00ec0000, 0x005f0000, + 0x00600000, 0x00510000, 0x007f0000, 0x00a90000, + 0x00190000, 0x00b50000, 0x004a0000, 0x000d0000, + 0x002d0000, 0x00e50000, 0x007a0000, 0x009f0000, + 0x00930000, 0x00c90000, 0x009c0000, 0x00ef0000, + 0x00a00000, 0x00e00000, 0x003b0000, 0x004d0000, + 0x00ae0000, 0x002a0000, 0x00f50000, 0x00b00000, + 0x00c80000, 0x00eb0000, 0x00bb0000, 0x003c0000, + 0x00830000, 0x00530000, 0x00990000, 0x00610000, + 0x00170000, 0x002b0000, 0x00040000, 0x007e0000, + 0x00ba0000, 0x00770000, 0x00d60000, 0x00260000, + 0x00e10000, 0x00690000, 0x00140000, 0x00630000, + 0x00550000, 0x00210000, 0x000c0000, 0x007d0000, + }, { + 0x52000000, 0x09000000, 0x6a000000, 0xd5000000, + 0x30000000, 0x36000000, 0xa5000000, 0x38000000, + 0xbf000000, 0x40000000, 0xa3000000, 0x9e000000, + 0x81000000, 0xf3000000, 0xd7000000, 0xfb000000, + 0x7c000000, 0xe3000000, 0x39000000, 0x82000000, + 0x9b000000, 0x2f000000, 0xff000000, 0x87000000, + 0x34000000, 0x8e000000, 0x43000000, 0x44000000, + 0xc4000000, 0xde000000, 0xe9000000, 0xcb000000, + 0x54000000, 0x7b000000, 0x94000000, 0x32000000, + 0xa6000000, 0xc2000000, 0x23000000, 0x3d000000, + 0xee000000, 0x4c000000, 0x95000000, 0x0b000000, + 0x42000000, 0xfa000000, 0xc3000000, 0x4e000000, + 0x08000000, 0x2e000000, 0xa1000000, 0x66000000, + 0x28000000, 0xd9000000, 0x24000000, 0xb2000000, + 0x76000000, 0x5b000000, 0xa2000000, 0x49000000, + 0x6d000000, 0x8b000000, 0xd1000000, 0x25000000, + 0x72000000, 0xf8000000, 0xf6000000, 0x64000000, + 0x86000000, 0x68000000, 0x98000000, 0x16000000, + 0xd4000000, 0xa4000000, 0x5c000000, 0xcc000000, + 0x5d000000, 0x65000000, 0xb6000000, 0x92000000, + 0x6c000000, 0x70000000, 0x48000000, 0x50000000, + 0xfd000000, 0xed000000, 0xb9000000, 0xda000000, + 0x5e000000, 0x15000000, 0x46000000, 0x57000000, + 0xa7000000, 0x8d000000, 0x9d000000, 0x84000000, + 0x90000000, 0xd8000000, 0xab000000, 0x00000000, + 0x8c000000, 0xbc000000, 0xd3000000, 0x0a000000, + 0xf7000000, 0xe4000000, 0x58000000, 0x05000000, + 0xb8000000, 0xb3000000, 0x45000000, 0x06000000, + 0xd0000000, 0x2c000000, 0x1e000000, 0x8f000000, + 0xca000000, 0x3f000000, 0x0f000000, 0x02000000, + 0xc1000000, 0xaf000000, 0xbd000000, 0x03000000, + 0x01000000, 0x13000000, 0x8a000000, 0x6b000000, + 0x3a000000, 0x91000000, 0x11000000, 0x41000000, + 0x4f000000, 0x67000000, 0xdc000000, 0xea000000, + 0x97000000, 0xf2000000, 0xcf000000, 0xce000000, + 0xf0000000, 0xb4000000, 0xe6000000, 0x73000000, + 0x96000000, 0xac000000, 0x74000000, 0x22000000, + 0xe7000000, 0xad000000, 0x35000000, 0x85000000, + 0xe2000000, 0xf9000000, 0x37000000, 0xe8000000, + 0x1c000000, 0x75000000, 0xdf000000, 0x6e000000, + 0x47000000, 0xf1000000, 0x1a000000, 0x71000000, + 0x1d000000, 0x29000000, 0xc5000000, 0x89000000, + 0x6f000000, 0xb7000000, 0x62000000, 0x0e000000, + 0xaa000000, 0x18000000, 0xbe000000, 0x1b000000, + 0xfc000000, 0x56000000, 0x3e000000, 0x4b000000, + 0xc6000000, 0xd2000000, 0x79000000, 0x20000000, + 0x9a000000, 0xdb000000, 0xc0000000, 0xfe000000, + 0x78000000, 0xcd000000, 0x5a000000, 0xf4000000, + 0x1f000000, 0xdd000000, 0xa8000000, 0x33000000, + 0x88000000, 0x07000000, 0xc7000000, 0x31000000, + 0xb1000000, 0x12000000, 0x10000000, 0x59000000, + 0x27000000, 0x80000000, 0xec000000, 0x5f000000, + 0x60000000, 0x51000000, 0x7f000000, 0xa9000000, + 0x19000000, 0xb5000000, 0x4a000000, 0x0d000000, + 0x2d000000, 0xe5000000, 0x7a000000, 0x9f000000, + 0x93000000, 0xc9000000, 0x9c000000, 0xef000000, + 0xa0000000, 0xe0000000, 0x3b000000, 0x4d000000, + 0xae000000, 0x2a000000, 0xf5000000, 0xb0000000, + 0xc8000000, 0xeb000000, 0xbb000000, 0x3c000000, + 0x83000000, 0x53000000, 0x99000000, 0x61000000, + 0x17000000, 0x2b000000, 0x04000000, 0x7e000000, + 0xba000000, 0x77000000, 0xd6000000, 0x26000000, + 0xe1000000, 0x69000000, 0x14000000, 0x63000000, + 0x55000000, 0x21000000, 0x0c000000, 0x7d000000, } -} +}; + +EXPORT_SYMBOL_GPL(crypto_ft_tab); +EXPORT_SYMBOL_GPL(crypto_fl_tab); +EXPORT_SYMBOL_GPL(crypto_it_tab); +EXPORT_SYMBOL_GPL(crypto_il_tab); /* initialise the key schedule from the user supplied key */ @@ -491,7 +1457,6 @@ static struct crypto_alg aes_alg = { static int __init aes_init(void) { - gen_tabs(); return crypto_register_alg(&aes_alg); } diff --git a/crypto/ahash.c b/crypto/ahash.c index 27128f2c687a62494b8d20b60191c916376aca4a..ba5292d69ebd206cdbf9961e130cf089dc584dd2 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c @@ -112,6 +112,22 @@ int crypto_hash_walk_first(struct ahash_request *req, } EXPORT_SYMBOL_GPL(crypto_hash_walk_first); +int crypto_hash_walk_first_compat(struct hash_desc *hdesc, + struct crypto_hash_walk *walk, + struct scatterlist *sg, unsigned int len) +{ + walk->total = len; + + if (!walk->total) + return 0; + + walk->alignmask = crypto_hash_alignmask(hdesc->tfm); + walk->sg = sg; + walk->flags = hdesc->flags; + + return hash_walk_new_entry(walk); +} + static int ahash_setkey_unaligned(struct crypto_ahash *tfm, const u8 *key, unsigned int keylen) { @@ -146,6 +162,26 @@ static int ahash_setkey(struct crypto_ahash *tfm, const u8 *key, return ahash->setkey(tfm, key, keylen); } +static int ahash_nosetkey(struct crypto_ahash *tfm, const u8 *key, + unsigned int keylen) +{ + return -ENOSYS; +} + +int crypto_ahash_import(struct ahash_request *req, const u8 *in) +{ + struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); + struct ahash_alg *alg = crypto_ahash_alg(tfm); + + memcpy(ahash_request_ctx(req), in, crypto_ahash_reqsize(tfm)); + + if (alg->reinit) + alg->reinit(req); + + return 0; +} +EXPORT_SYMBOL_GPL(crypto_ahash_import); + static unsigned int crypto_ahash_ctxsize(struct crypto_alg *alg, u32 type, u32 mask) { @@ -164,7 +200,7 @@ static int crypto_init_ahash_ops(struct crypto_tfm *tfm, u32 type, u32 mask) crt->update = alg->update; crt->final = alg->final; crt->digest = alg->digest; - crt->setkey = ahash_setkey; + crt->setkey = alg->setkey ? ahash_setkey : ahash_nosetkey; crt->digestsize = alg->digestsize; return 0; diff --git a/crypto/ansi_cprng.c b/crypto/ansi_cprng.c index 72db0fd763cca01ed6ed17f35a494fa7744a0b47..0fac8ffc2fb7ef5dc6d39cca05d0292b584bb472 100644 --- a/crypto/ansi_cprng.c +++ b/crypto/ansi_cprng.c @@ -161,7 +161,7 @@ static int _get_more_prng_bytes(struct prng_context *ctx) /* * Now update our DT value */ - for (i = 0; i < DEFAULT_BLK_SZ; i++) { + for (i = DEFAULT_BLK_SZ - 1; i >= 0; i--) { ctx->DT[i] += 1; if (ctx->DT[i] != 0) break; @@ -223,9 +223,10 @@ static int get_prng_bytes(char *buf, size_t nbytes, struct prng_context *ctx) } /* - * Copy up to the next whole block size + * Copy any data less than an entire block */ if (byte_count < DEFAULT_BLK_SZ) { +empty_rbuf: for (; ctx->rand_data_valid < DEFAULT_BLK_SZ; ctx->rand_data_valid++) { *ptr = ctx->rand_data[ctx->rand_data_valid]; @@ -240,18 +241,22 @@ static int get_prng_bytes(char *buf, size_t nbytes, struct prng_context *ctx) * Now copy whole blocks */ for (; byte_count >= DEFAULT_BLK_SZ; byte_count -= DEFAULT_BLK_SZ) { - if (_get_more_prng_bytes(ctx) < 0) { - memset(buf, 0, nbytes); - err = -EINVAL; - goto done; + if (ctx->rand_data_valid == DEFAULT_BLK_SZ) { + if (_get_more_prng_bytes(ctx) < 0) { + memset(buf, 0, nbytes); + err = -EINVAL; + goto done; + } } + if (ctx->rand_data_valid > 0) + goto empty_rbuf; memcpy(ptr, ctx->rand_data, DEFAULT_BLK_SZ); ctx->rand_data_valid += DEFAULT_BLK_SZ; ptr += DEFAULT_BLK_SZ; } /* - * Now copy any extra partial data + * Now go back and get any remaining partial block */ if (byte_count) goto remainder; @@ -349,15 +354,25 @@ static int cprng_get_random(struct crypto_rng *tfm, u8 *rdata, return get_prng_bytes(rdata, dlen, prng); } +/* + * This is the cprng_registered reset method the seed value is + * interpreted as the tuple { V KEY DT} + * V and KEY are required during reset, and DT is optional, detected + * as being present by testing the length of the seed + */ static int cprng_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen) { struct prng_context *prng = crypto_rng_ctx(tfm); - u8 *key = seed + DEFAULT_PRNG_KSZ; + u8 *key = seed + DEFAULT_BLK_SZ; + u8 *dt = NULL; if (slen < DEFAULT_PRNG_KSZ + DEFAULT_BLK_SZ) return -EINVAL; - reset_prng_context(prng, key, DEFAULT_PRNG_KSZ, seed, NULL); + if (slen >= (2 * DEFAULT_BLK_SZ + DEFAULT_PRNG_KSZ)) + dt = key + DEFAULT_PRNG_KSZ; + + reset_prng_context(prng, key, DEFAULT_PRNG_KSZ, seed, dt); if (prng->flags & PRNG_NEED_RESET) return -EINVAL; @@ -379,7 +394,7 @@ static struct crypto_alg rng_alg = { .rng = { .rng_make_random = cprng_get_random, .rng_reset = cprng_reset, - .seedsize = DEFAULT_PRNG_KSZ + DEFAULT_BLK_SZ, + .seedsize = DEFAULT_PRNG_KSZ + 2*DEFAULT_BLK_SZ, } } }; diff --git a/crypto/api.c b/crypto/api.c index 0444d242e9854dbc1a63a61a37ecc37b94c52df7..9975a7bd246c21d4d7e3152249ffefdb38812ee5 100644 --- a/crypto/api.c +++ b/crypto/api.c @@ -300,8 +300,8 @@ static void crypto_exit_ops(struct crypto_tfm *tfm) const struct crypto_type *type = tfm->__crt_alg->cra_type; if (type) { - if (type->exit) - type->exit(tfm); + if (tfm->exit) + tfm->exit(tfm); return; } @@ -379,17 +379,16 @@ struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 type, if (err) goto out_free_tfm; - if (alg->cra_init && (err = alg->cra_init(tfm))) { - if (err == -EAGAIN) - crypto_shoot_alg(alg); + if (!tfm->exit && alg->cra_init && (err = alg->cra_init(tfm))) goto cra_init_failed; - } goto out; cra_init_failed: crypto_exit_ops(tfm); out_free_tfm: + if (err == -EAGAIN) + crypto_shoot_alg(alg); kfree(tfm); out_err: tfm = ERR_PTR(err); @@ -404,6 +403,9 @@ EXPORT_SYMBOL_GPL(__crypto_alloc_tfm); * @type: Type of algorithm * @mask: Mask for type comparison * + * This function should not be used by new algorithm types. + * Plesae use crypto_alloc_tfm instead. + * * crypto_alloc_base() will first attempt to locate an already loaded * algorithm. If that fails and the kernel supports dynamically loadable * modules, it will then attempt to load a module of the same name or @@ -450,6 +452,111 @@ struct crypto_tfm *crypto_alloc_base(const char *alg_name, u32 type, u32 mask) return ERR_PTR(err); } EXPORT_SYMBOL_GPL(crypto_alloc_base); + +struct crypto_tfm *crypto_create_tfm(struct crypto_alg *alg, + const struct crypto_type *frontend) +{ + char *mem; + struct crypto_tfm *tfm = NULL; + unsigned int tfmsize; + unsigned int total; + int err = -ENOMEM; + + tfmsize = frontend->tfmsize; + total = tfmsize + sizeof(*tfm) + frontend->extsize(alg, frontend); + + mem = kzalloc(total, GFP_KERNEL); + if (mem == NULL) + goto out_err; + + tfm = (struct crypto_tfm *)(mem + tfmsize); + tfm->__crt_alg = alg; + + err = frontend->init_tfm(tfm, frontend); + if (err) + goto out_free_tfm; + + if (!tfm->exit && alg->cra_init && (err = alg->cra_init(tfm))) + goto cra_init_failed; + + goto out; + +cra_init_failed: + crypto_exit_ops(tfm); +out_free_tfm: + if (err == -EAGAIN) + crypto_shoot_alg(alg); + kfree(mem); +out_err: + tfm = ERR_PTR(err); +out: + return tfm; +} +EXPORT_SYMBOL_GPL(crypto_create_tfm); + +/* + * crypto_alloc_tfm - Locate algorithm and allocate transform + * @alg_name: Name of algorithm + * @frontend: Frontend algorithm type + * @type: Type of algorithm + * @mask: Mask for type comparison + * + * crypto_alloc_tfm() will first attempt to locate an already loaded + * algorithm. If that fails and the kernel supports dynamically loadable + * modules, it will then attempt to load a module of the same name or + * alias. If that fails it will send a query to any loaded crypto manager + * to construct an algorithm on the fly. A refcount is grabbed on the + * algorithm which is then associated with the new transform. + * + * The returned transform is of a non-determinate type. Most people + * should use one of the more specific allocation functions such as + * crypto_alloc_blkcipher. + * + * In case of error the return value is an error pointer. + */ +struct crypto_tfm *crypto_alloc_tfm(const char *alg_name, + const struct crypto_type *frontend, + u32 type, u32 mask) +{ + struct crypto_alg *(*lookup)(const char *name, u32 type, u32 mask); + struct crypto_tfm *tfm; + int err; + + type &= frontend->maskclear; + mask &= frontend->maskclear; + type |= frontend->type; + mask |= frontend->maskset; + + lookup = frontend->lookup ?: crypto_alg_mod_lookup; + + for (;;) { + struct crypto_alg *alg; + + alg = lookup(alg_name, type, mask); + if (IS_ERR(alg)) { + err = PTR_ERR(alg); + goto err; + } + + tfm = crypto_create_tfm(alg, frontend); + if (!IS_ERR(tfm)) + return tfm; + + crypto_mod_put(alg); + err = PTR_ERR(tfm); + +err: + if (err != -EAGAIN) + break; + if (signal_pending(current)) { + err = -EINTR; + break; + } + } + + return ERR_PTR(err); +} +EXPORT_SYMBOL_GPL(crypto_alloc_tfm); /* * crypto_free_tfm - Free crypto transform @@ -469,7 +576,7 @@ void crypto_free_tfm(struct crypto_tfm *tfm) alg = tfm->__crt_alg; size = sizeof(*tfm) + alg->cra_ctxsize; - if (alg->cra_exit) + if (!tfm->exit && alg->cra_exit) alg->cra_exit(tfm); crypto_exit_ops(tfm); crypto_mod_put(alg); diff --git a/crypto/authenc.c b/crypto/authenc.c index fd9f06c63d76efc223a6f025dcab10b19ceba84c..40b6e9ec9e3a0a2069b5f972226918dc33625294 100644 --- a/crypto/authenc.c +++ b/crypto/authenc.c @@ -11,6 +11,7 @@ */ #include +#include #include #include #include @@ -431,6 +432,8 @@ static struct crypto_instance *crypto_authenc_alloc(struct rtattr **tb) inst->alg.cra_aead.ivsize = enc->cra_ablkcipher.ivsize; inst->alg.cra_aead.maxauthsize = auth->cra_type == &crypto_hash_type ? auth->cra_hash.digestsize : + auth->cra_type ? + __crypto_shash_alg(auth)->digestsize : auth->cra_digest.dia_digestsize; inst->alg.cra_ctxsize = sizeof(struct crypto_authenc_ctx); diff --git a/crypto/camellia.c b/crypto/camellia.c index 493fee7e0a8b46bbd9933d92681e0a7c16d0ab81..964635d163f4767a9ff7a47c271fb1f5bd3a6c59 100644 --- a/crypto/camellia.c +++ b/crypto/camellia.c @@ -35,6 +35,8 @@ #include #include #include +#include +#include static const u32 camellia_sp1110[256] = { 0x70707000,0x82828200,0x2c2c2c00,0xececec00, @@ -335,20 +337,6 @@ static const u32 camellia_sp4404[256] = { /* * macros */ -#define GETU32(v, pt) \ - do { \ - /* latest breed of gcc is clever enough to use move */ \ - memcpy(&(v), (pt), 4); \ - (v) = be32_to_cpu(v); \ - } while(0) - -/* rotation right shift 1byte */ -#define ROR8(x) (((x) >> 8) + ((x) << 24)) -/* rotation left shift 1bit */ -#define ROL1(x) (((x) << 1) + ((x) >> 31)) -/* rotation left shift 1byte */ -#define ROL8(x) (((x) << 8) + ((x) >> 24)) - #define ROLDQ(ll, lr, rl, rr, w0, w1, bits) \ do { \ w0 = ll; \ @@ -383,7 +371,7 @@ static const u32 camellia_sp4404[256] = { ^ camellia_sp3033[(u8)(il >> 8)] \ ^ camellia_sp4404[(u8)(il )]; \ yl ^= yr; \ - yr = ROR8(yr); \ + yr = ror32(yr, 8); \ yr ^= yl; \ } while(0) @@ -405,7 +393,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max) subL[7] ^= subL[1]; subR[7] ^= subR[1]; subL[1] ^= subR[1] & ~subR[9]; dw = subL[1] & subL[9], - subR[1] ^= ROL1(dw); /* modified for FLinv(kl2) */ + subR[1] ^= rol32(dw, 1); /* modified for FLinv(kl2) */ /* round 8 */ subL[11] ^= subL[1]; subR[11] ^= subR[1]; /* round 10 */ @@ -414,7 +402,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max) subL[15] ^= subL[1]; subR[15] ^= subR[1]; subL[1] ^= subR[1] & ~subR[17]; dw = subL[1] & subL[17], - subR[1] ^= ROL1(dw); /* modified for FLinv(kl4) */ + subR[1] ^= rol32(dw, 1); /* modified for FLinv(kl4) */ /* round 14 */ subL[19] ^= subL[1]; subR[19] ^= subR[1]; /* round 16 */ @@ -430,7 +418,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max) } else { subL[1] ^= subR[1] & ~subR[25]; dw = subL[1] & subL[25], - subR[1] ^= ROL1(dw); /* modified for FLinv(kl6) */ + subR[1] ^= rol32(dw, 1); /* modified for FLinv(kl6) */ /* round 20 */ subL[27] ^= subL[1]; subR[27] ^= subR[1]; /* round 22 */ @@ -450,7 +438,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max) subL[26] ^= kw4l; subR[26] ^= kw4r; kw4l ^= kw4r & ~subR[24]; dw = kw4l & subL[24], - kw4r ^= ROL1(dw); /* modified for FL(kl5) */ + kw4r ^= rol32(dw, 1); /* modified for FL(kl5) */ } /* round 17 */ subL[22] ^= kw4l; subR[22] ^= kw4r; @@ -460,7 +448,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max) subL[18] ^= kw4l; subR[18] ^= kw4r; kw4l ^= kw4r & ~subR[16]; dw = kw4l & subL[16], - kw4r ^= ROL1(dw); /* modified for FL(kl3) */ + kw4r ^= rol32(dw, 1); /* modified for FL(kl3) */ /* round 11 */ subL[14] ^= kw4l; subR[14] ^= kw4r; /* round 9 */ @@ -469,7 +457,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max) subL[10] ^= kw4l; subR[10] ^= kw4r; kw4l ^= kw4r & ~subR[8]; dw = kw4l & subL[8], - kw4r ^= ROL1(dw); /* modified for FL(kl1) */ + kw4r ^= rol32(dw, 1); /* modified for FL(kl1) */ /* round 5 */ subL[6] ^= kw4l; subR[6] ^= kw4r; /* round 3 */ @@ -494,7 +482,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max) SUBKEY_R(6) = subR[5] ^ subR[7]; tl = subL[10] ^ (subR[10] & ~subR[8]); dw = tl & subL[8], /* FL(kl1) */ - tr = subR[10] ^ ROL1(dw); + tr = subR[10] ^ rol32(dw, 1); SUBKEY_L(7) = subL[6] ^ tl; /* round 6 */ SUBKEY_R(7) = subR[6] ^ tr; SUBKEY_L(8) = subL[8]; /* FL(kl1) */ @@ -503,7 +491,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max) SUBKEY_R(9) = subR[9]; tl = subL[7] ^ (subR[7] & ~subR[9]); dw = tl & subL[9], /* FLinv(kl2) */ - tr = subR[7] ^ ROL1(dw); + tr = subR[7] ^ rol32(dw, 1); SUBKEY_L(10) = tl ^ subL[11]; /* round 7 */ SUBKEY_R(10) = tr ^ subR[11]; SUBKEY_L(11) = subL[10] ^ subL[12]; /* round 8 */ @@ -516,7 +504,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max) SUBKEY_R(14) = subR[13] ^ subR[15]; tl = subL[18] ^ (subR[18] & ~subR[16]); dw = tl & subL[16], /* FL(kl3) */ - tr = subR[18] ^ ROL1(dw); + tr = subR[18] ^ rol32(dw, 1); SUBKEY_L(15) = subL[14] ^ tl; /* round 12 */ SUBKEY_R(15) = subR[14] ^ tr; SUBKEY_L(16) = subL[16]; /* FL(kl3) */ @@ -525,7 +513,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max) SUBKEY_R(17) = subR[17]; tl = subL[15] ^ (subR[15] & ~subR[17]); dw = tl & subL[17], /* FLinv(kl4) */ - tr = subR[15] ^ ROL1(dw); + tr = subR[15] ^ rol32(dw, 1); SUBKEY_L(18) = tl ^ subL[19]; /* round 13 */ SUBKEY_R(18) = tr ^ subR[19]; SUBKEY_L(19) = subL[18] ^ subL[20]; /* round 14 */ @@ -544,7 +532,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max) } else { tl = subL[26] ^ (subR[26] & ~subR[24]); dw = tl & subL[24], /* FL(kl5) */ - tr = subR[26] ^ ROL1(dw); + tr = subR[26] ^ rol32(dw, 1); SUBKEY_L(23) = subL[22] ^ tl; /* round 18 */ SUBKEY_R(23) = subR[22] ^ tr; SUBKEY_L(24) = subL[24]; /* FL(kl5) */ @@ -553,7 +541,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max) SUBKEY_R(25) = subR[25]; tl = subL[23] ^ (subR[23] & ~subR[25]); dw = tl & subL[25], /* FLinv(kl6) */ - tr = subR[23] ^ ROL1(dw); + tr = subR[23] ^ rol32(dw, 1); SUBKEY_L(26) = tl ^ subL[27]; /* round 19 */ SUBKEY_R(26) = tr ^ subR[27]; SUBKEY_L(27) = subL[26] ^ subL[28]; /* round 20 */ @@ -573,17 +561,17 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max) /* apply the inverse of the last half of P-function */ i = 2; do { - dw = SUBKEY_L(i + 0) ^ SUBKEY_R(i + 0); dw = ROL8(dw);/* round 1 */ + dw = SUBKEY_L(i + 0) ^ SUBKEY_R(i + 0); dw = rol32(dw, 8);/* round 1 */ SUBKEY_R(i + 0) = SUBKEY_L(i + 0) ^ dw; SUBKEY_L(i + 0) = dw; - dw = SUBKEY_L(i + 1) ^ SUBKEY_R(i + 1); dw = ROL8(dw);/* round 2 */ + dw = SUBKEY_L(i + 1) ^ SUBKEY_R(i + 1); dw = rol32(dw, 8);/* round 2 */ SUBKEY_R(i + 1) = SUBKEY_L(i + 1) ^ dw; SUBKEY_L(i + 1) = dw; - dw = SUBKEY_L(i + 2) ^ SUBKEY_R(i + 2); dw = ROL8(dw);/* round 3 */ + dw = SUBKEY_L(i + 2) ^ SUBKEY_R(i + 2); dw = rol32(dw, 8);/* round 3 */ SUBKEY_R(i + 2) = SUBKEY_L(i + 2) ^ dw; SUBKEY_L(i + 2) = dw; - dw = SUBKEY_L(i + 3) ^ SUBKEY_R(i + 3); dw = ROL8(dw);/* round 4 */ + dw = SUBKEY_L(i + 3) ^ SUBKEY_R(i + 3); dw = rol32(dw, 8);/* round 4 */ SUBKEY_R(i + 3) = SUBKEY_L(i + 3) ^ dw; SUBKEY_L(i + 3) = dw; - dw = SUBKEY_L(i + 4) ^ SUBKEY_R(i + 4); dw = ROL8(dw);/* round 5 */ + dw = SUBKEY_L(i + 4) ^ SUBKEY_R(i + 4); dw = rol32(dw, 8);/* round 5 */ SUBKEY_R(i + 4) = SUBKEY_L(i + 4) ^ dw; SUBKEY_L(i + 4) = dw; - dw = SUBKEY_L(i + 5) ^ SUBKEY_R(i + 5); dw = ROL8(dw);/* round 6 */ + dw = SUBKEY_L(i + 5) ^ SUBKEY_R(i + 5); dw = rol32(dw, 8);/* round 6 */ SUBKEY_R(i + 5) = SUBKEY_L(i + 5) ^ dw; SUBKEY_L(i + 5) = dw; i += 8; } while (i < max); @@ -599,10 +587,10 @@ static void camellia_setup128(const unsigned char *key, u32 *subkey) /** * k == kll || klr || krl || krr (|| is concatenation) */ - GETU32(kll, key ); - GETU32(klr, key + 4); - GETU32(krl, key + 8); - GETU32(krr, key + 12); + kll = get_unaligned_be32(key); + klr = get_unaligned_be32(key + 4); + krl = get_unaligned_be32(key + 8); + krr = get_unaligned_be32(key + 12); /* generate KL dependent subkeys */ /* kw1 */ @@ -707,14 +695,14 @@ static void camellia_setup256(const unsigned char *key, u32 *subkey) * key = (kll || klr || krl || krr || krll || krlr || krrl || krrr) * (|| is concatenation) */ - GETU32(kll, key ); - GETU32(klr, key + 4); - GETU32(krl, key + 8); - GETU32(krr, key + 12); - GETU32(krll, key + 16); - GETU32(krlr, key + 20); - GETU32(krrl, key + 24); - GETU32(krrr, key + 28); + kll = get_unaligned_be32(key); + klr = get_unaligned_be32(key + 4); + krl = get_unaligned_be32(key + 8); + krr = get_unaligned_be32(key + 12); + krll = get_unaligned_be32(key + 16); + krlr = get_unaligned_be32(key + 20); + krrl = get_unaligned_be32(key + 24); + krrr = get_unaligned_be32(key + 28); /* generate KL dependent subkeys */ /* kw1 */ @@ -870,13 +858,13 @@ static void camellia_setup192(const unsigned char *key, u32 *subkey) t0 &= ll; \ t2 |= rr; \ rl ^= t2; \ - lr ^= ROL1(t0); \ + lr ^= rol32(t0, 1); \ t3 = krl; \ t1 = klr; \ t3 &= rl; \ t1 |= lr; \ ll ^= t1; \ - rr ^= ROL1(t3); \ + rr ^= rol32(t3, 1); \ } while(0) #define CAMELLIA_ROUNDSM(xl, xr, kl, kr, yl, yr, il, ir) \ @@ -892,7 +880,7 @@ static void camellia_setup192(const unsigned char *key, u32 *subkey) il ^= kl; \ ir ^= il ^ kr; \ yl ^= ir; \ - yr ^= ROR8(il) ^ ir; \ + yr ^= ror32(il, 8) ^ ir; \ } while(0) /* max = 24: 128bit encrypt, max = 32: 256bit encrypt */ diff --git a/crypto/crc32c.c b/crypto/crc32c.c index a882d9e4e63e741fd90ec2d6183cee337c841c54..973bc2cfab2ec00b8571894bc7ceb35541670cad 100644 --- a/crypto/crc32c.c +++ b/crypto/crc32c.c @@ -3,8 +3,29 @@ * * CRC32C chksum * - * This module file is a wrapper to invoke the lib/crc32c routines. + *@Article{castagnoli-crc, + * author = { Guy Castagnoli and Stefan Braeuer and Martin Herrman}, + * title = {{Optimization of Cyclic Redundancy-Check Codes with 24 + * and 32 Parity Bits}}, + * journal = IEEE Transactions on Communication, + * year = {1993}, + * volume = {41}, + * number = {6}, + * pages = {}, + * month = {June}, + *} + * Used by the iSCSI driver, possibly others, and derived from the + * the iscsi-crc.c module of the linux-iscsi driver at + * http://linux-iscsi.sourceforge.net. * + * Following the example of lib/crc32, this function is intended to be + * flexible and useful for all users. Modules that currently have their + * own crc32c, but hopefully may be able to use this one are: + * net/sctp (please add all your doco to here if you change to + * use this one!) + * + * + * Copyright (c) 2004 Cisco Systems, Inc. * Copyright (c) 2008 Herbert Xu * * This program is free software; you can redistribute it and/or modify it @@ -18,208 +39,217 @@ #include #include #include -#include #include #define CHKSUM_BLOCK_SIZE 1 #define CHKSUM_DIGEST_SIZE 4 struct chksum_ctx { - u32 crc; u32 key; }; +struct chksum_desc_ctx { + u32 crc; +}; + /* - * Steps through buffer one byte at at time, calculates reflected - * crc using table. + * This is the CRC-32C table + * Generated with: + * width = 32 bits + * poly = 0x1EDC6F41 + * reflect input bytes = true + * reflect output bytes = true */ -static void chksum_init(struct crypto_tfm *tfm) -{ - struct chksum_ctx *mctx = crypto_tfm_ctx(tfm); - - mctx->crc = mctx->key; -} +static const u32 crc32c_table[256] = { + 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L, + 0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL, + 0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL, + 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L, + 0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL, + 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L, + 0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L, + 0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL, + 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL, + 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L, + 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L, + 0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL, + 0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L, + 0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL, + 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL, + 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L, + 0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L, + 0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L, + 0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L, + 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L, + 0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L, + 0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L, + 0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L, + 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L, + 0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L, + 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L, + 0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L, + 0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L, + 0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L, + 0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L, + 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L, + 0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L, + 0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL, + 0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L, + 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L, + 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL, + 0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L, + 0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL, + 0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL, + 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L, + 0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L, + 0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL, + 0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL, + 0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L, + 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL, + 0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L, + 0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L, + 0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL, + 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L, + 0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL, + 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL, + 0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L, + 0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL, + 0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L, + 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L, + 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL, + 0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL, + 0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L, + 0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L, + 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL, + 0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L, + 0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL, + 0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL, + 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L +}; /* - * Setting the seed allows arbitrary accumulators and flexible XOR policy - * If your algorithm starts with ~0, then XOR with ~0 before you set - * the seed. + * Steps through buffer one byte at at time, calculates reflected + * crc using table. */ -static int chksum_setkey(struct crypto_tfm *tfm, const u8 *key, - unsigned int keylen) -{ - struct chksum_ctx *mctx = crypto_tfm_ctx(tfm); - if (keylen != sizeof(mctx->crc)) { - tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; - return -EINVAL; - } - mctx->key = le32_to_cpu(*(__le32 *)key); - return 0; -} - -static void chksum_update(struct crypto_tfm *tfm, const u8 *data, - unsigned int length) +static u32 crc32c(u32 crc, const u8 *data, unsigned int length) { - struct chksum_ctx *mctx = crypto_tfm_ctx(tfm); + while (length--) + crc = crc32c_table[(crc ^ *data++) & 0xFFL] ^ (crc >> 8); - mctx->crc = crc32c(mctx->crc, data, length); + return crc; } -static void chksum_final(struct crypto_tfm *tfm, u8 *out) -{ - struct chksum_ctx *mctx = crypto_tfm_ctx(tfm); - - *(__le32 *)out = ~cpu_to_le32(mctx->crc); -} +/* + * Steps through buffer one byte at at time, calculates reflected + * crc using table. + */ -static int crc32c_cra_init_old(struct crypto_tfm *tfm) +static int chksum_init(struct shash_desc *desc) { - struct chksum_ctx *mctx = crypto_tfm_ctx(tfm); + struct chksum_ctx *mctx = crypto_shash_ctx(desc->tfm); + struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); + + ctx->crc = mctx->key; - mctx->key = ~0; return 0; } -static struct crypto_alg old_alg = { - .cra_name = "crc32c", - .cra_flags = CRYPTO_ALG_TYPE_DIGEST, - .cra_blocksize = CHKSUM_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct chksum_ctx), - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(old_alg.cra_list), - .cra_init = crc32c_cra_init_old, - .cra_u = { - .digest = { - .dia_digestsize= CHKSUM_DIGEST_SIZE, - .dia_setkey = chksum_setkey, - .dia_init = chksum_init, - .dia_update = chksum_update, - .dia_final = chksum_final - } - } -}; - /* * Setting the seed allows arbitrary accumulators and flexible XOR policy * If your algorithm starts with ~0, then XOR with ~0 before you set * the seed. */ -static int crc32c_setkey(struct crypto_ahash *hash, const u8 *key, +static int chksum_setkey(struct crypto_shash *tfm, const u8 *key, unsigned int keylen) { - u32 *mctx = crypto_ahash_ctx(hash); + struct chksum_ctx *mctx = crypto_shash_ctx(tfm); - if (keylen != sizeof(u32)) { - crypto_ahash_set_flags(hash, CRYPTO_TFM_RES_BAD_KEY_LEN); + if (keylen != sizeof(mctx->key)) { + crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); return -EINVAL; } - *mctx = le32_to_cpup((__le32 *)key); + mctx->key = le32_to_cpu(*(__le32 *)key); return 0; } -static int crc32c_init(struct ahash_request *req) +static int chksum_update(struct shash_desc *desc, const u8 *data, + unsigned int length) { - u32 *mctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req)); - u32 *crcp = ahash_request_ctx(req); + struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); - *crcp = *mctx; + ctx->crc = crc32c(ctx->crc, data, length); return 0; } -static int crc32c_update(struct ahash_request *req) +static int chksum_final(struct shash_desc *desc, u8 *out) { - struct crypto_hash_walk walk; - u32 *crcp = ahash_request_ctx(req); - u32 crc = *crcp; - int nbytes; - - for (nbytes = crypto_hash_walk_first(req, &walk); nbytes; - nbytes = crypto_hash_walk_done(&walk, 0)) - crc = crc32c(crc, walk.data, nbytes); + struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); - *crcp = crc; + *(__le32 *)out = ~cpu_to_le32p(&ctx->crc); return 0; } -static int crc32c_final(struct ahash_request *req) +static int __chksum_finup(u32 *crcp, const u8 *data, unsigned int len, u8 *out) { - u32 *crcp = ahash_request_ctx(req); - - *(__le32 *)req->result = ~cpu_to_le32p(crcp); + *(__le32 *)out = ~cpu_to_le32(crc32c(*crcp, data, len)); return 0; } -static int crc32c_digest(struct ahash_request *req) +static int chksum_finup(struct shash_desc *desc, const u8 *data, + unsigned int len, u8 *out) { - struct crypto_hash_walk walk; - u32 *mctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req)); - u32 crc = *mctx; - int nbytes; + struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); - for (nbytes = crypto_hash_walk_first(req, &walk); nbytes; - nbytes = crypto_hash_walk_done(&walk, 0)) - crc = crc32c(crc, walk.data, nbytes); - - *(__le32 *)req->result = ~cpu_to_le32(crc); - return 0; + return __chksum_finup(&ctx->crc, data, len, out); } -static int crc32c_cra_init(struct crypto_tfm *tfm) +static int chksum_digest(struct shash_desc *desc, const u8 *data, + unsigned int length, u8 *out) { - u32 *key = crypto_tfm_ctx(tfm); + struct chksum_ctx *mctx = crypto_shash_ctx(desc->tfm); - *key = ~0; + return __chksum_finup(&mctx->key, data, length, out); +} - tfm->crt_ahash.reqsize = sizeof(u32); +static int crc32c_cra_init(struct crypto_tfm *tfm) +{ + struct chksum_ctx *mctx = crypto_tfm_ctx(tfm); + mctx->key = ~0; return 0; } -static struct crypto_alg alg = { - .cra_name = "crc32c", - .cra_driver_name = "crc32c-generic", - .cra_priority = 100, - .cra_flags = CRYPTO_ALG_TYPE_AHASH, - .cra_blocksize = CHKSUM_BLOCK_SIZE, - .cra_alignmask = 3, - .cra_ctxsize = sizeof(u32), - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(alg.cra_list), - .cra_init = crc32c_cra_init, - .cra_type = &crypto_ahash_type, - .cra_u = { - .ahash = { - .digestsize = CHKSUM_DIGEST_SIZE, - .setkey = crc32c_setkey, - .init = crc32c_init, - .update = crc32c_update, - .final = crc32c_final, - .digest = crc32c_digest, - } +static struct shash_alg alg = { + .digestsize = CHKSUM_DIGEST_SIZE, + .setkey = chksum_setkey, + .init = chksum_init, + .update = chksum_update, + .final = chksum_final, + .finup = chksum_finup, + .digest = chksum_digest, + .descsize = sizeof(struct chksum_desc_ctx), + .base = { + .cra_name = "crc32c", + .cra_driver_name = "crc32c-generic", + .cra_priority = 100, + .cra_blocksize = CHKSUM_BLOCK_SIZE, + .cra_alignmask = 3, + .cra_ctxsize = sizeof(struct chksum_ctx), + .cra_module = THIS_MODULE, + .cra_init = crc32c_cra_init, } }; static int __init crc32c_mod_init(void) { - int err; - - err = crypto_register_alg(&old_alg); - if (err) - return err; - - err = crypto_register_alg(&alg); - if (err) - crypto_unregister_alg(&old_alg); - - return err; + return crypto_register_shash(&alg); } static void __exit crc32c_mod_fini(void) { - crypto_unregister_alg(&alg); - crypto_unregister_alg(&old_alg); + crypto_unregister_shash(&alg); } module_init(crc32c_mod_init); diff --git a/crypto/crypto_null.c b/crypto/crypto_null.c index 1f7d53013a228b4a459470d86ebfc0bb17998239..cb71c9122bc0d794f5a531765fbda14a1187bcda 100644 --- a/crypto/crypto_null.c +++ b/crypto/crypto_null.c @@ -17,6 +17,7 @@ * */ +#include #include #include #include @@ -38,15 +39,31 @@ static int null_compress(struct crypto_tfm *tfm, const u8 *src, return 0; } -static void null_init(struct crypto_tfm *tfm) -{ } +static int null_init(struct shash_desc *desc) +{ + return 0; +} -static void null_update(struct crypto_tfm *tfm, const u8 *data, - unsigned int len) -{ } +static int null_update(struct shash_desc *desc, const u8 *data, + unsigned int len) +{ + return 0; +} -static void null_final(struct crypto_tfm *tfm, u8 *out) -{ } +static int null_final(struct shash_desc *desc, u8 *out) +{ + return 0; +} + +static int null_digest(struct shash_desc *desc, const u8 *data, + unsigned int len, u8 *out) +{ + return 0; +} + +static int null_hash_setkey(struct crypto_shash *tfm, const u8 *key, + unsigned int keylen) +{ return 0; } static int null_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) @@ -89,19 +106,20 @@ static struct crypto_alg compress_null = { .coa_decompress = null_compress } } }; -static struct crypto_alg digest_null = { - .cra_name = "digest_null", - .cra_flags = CRYPTO_ALG_TYPE_DIGEST, - .cra_blocksize = NULL_BLOCK_SIZE, - .cra_ctxsize = 0, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(digest_null.cra_list), - .cra_u = { .digest = { - .dia_digestsize = NULL_DIGEST_SIZE, - .dia_setkey = null_setkey, - .dia_init = null_init, - .dia_update = null_update, - .dia_final = null_final } } +static struct shash_alg digest_null = { + .digestsize = NULL_DIGEST_SIZE, + .setkey = null_hash_setkey, + .init = null_init, + .update = null_update, + .finup = null_digest, + .digest = null_digest, + .final = null_final, + .base = { + .cra_name = "digest_null", + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = NULL_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } }; static struct crypto_alg cipher_null = { @@ -154,7 +172,7 @@ static int __init crypto_null_mod_init(void) if (ret < 0) goto out_unregister_cipher; - ret = crypto_register_alg(&digest_null); + ret = crypto_register_shash(&digest_null); if (ret < 0) goto out_unregister_skcipher; @@ -166,7 +184,7 @@ static int __init crypto_null_mod_init(void) return ret; out_unregister_digest: - crypto_unregister_alg(&digest_null); + crypto_unregister_shash(&digest_null); out_unregister_skcipher: crypto_unregister_alg(&skcipher_null); out_unregister_cipher: @@ -177,7 +195,7 @@ static int __init crypto_null_mod_init(void) static void __exit crypto_null_mod_fini(void) { crypto_unregister_alg(&compress_null); - crypto_unregister_alg(&digest_null); + crypto_unregister_shash(&digest_null); crypto_unregister_alg(&skcipher_null); crypto_unregister_alg(&cipher_null); } diff --git a/crypto/des_generic.c b/crypto/des_generic.c index 5d0e4580f998c23650eb24ba73135cd5af68a01e..5bd3ee345a64d8e60604a32097818a3a3d369a46 100644 --- a/crypto/des_generic.c +++ b/crypto/des_generic.c @@ -868,9 +868,10 @@ static int des3_ede_setkey(struct crypto_tfm *tfm, const u8 *key, u32 *flags = &tfm->crt_flags; if (unlikely(!((K[0] ^ K[2]) | (K[1] ^ K[3])) || - !((K[2] ^ K[4]) | (K[3] ^ K[5])))) + !((K[2] ^ K[4]) | (K[3] ^ K[5]))) && + (*flags & CRYPTO_TFM_REQ_WEAK_KEY)) { - *flags |= CRYPTO_TFM_RES_BAD_KEY_SCHED; + *flags |= CRYPTO_TFM_RES_WEAK_KEY; return -EINVAL; } diff --git a/crypto/fcrypt.c b/crypto/fcrypt.c index 1302f4cae337489f5a7aafaa39a36e1fab56bdca..b82d61f4e26c487c8b9f1a8838621040e25fdd5b 100644 --- a/crypto/fcrypt.c +++ b/crypto/fcrypt.c @@ -73,7 +73,7 @@ do { \ * /afs/transarc.com/public/afsps/afs.rel31b.export-src/rxkad/sboxes.h */ #undef Z -#define Z(x) __constant_cpu_to_be32(x << 3) +#define Z(x) cpu_to_be32(x << 3) static const __be32 sbox0[256] = { Z(0xea), Z(0x7f), Z(0xb2), Z(0x64), Z(0x9d), Z(0xb0), Z(0xd9), Z(0x11), Z(0xcd), Z(0x86), Z(0x86), Z(0x91), Z(0x0a), Z(0xb2), Z(0x93), Z(0x06), @@ -110,7 +110,7 @@ static const __be32 sbox0[256] = { }; #undef Z -#define Z(x) __constant_cpu_to_be32((x << 27) | (x >> 5)) +#define Z(x) cpu_to_be32((x << 27) | (x >> 5)) static const __be32 sbox1[256] = { Z(0x77), Z(0x14), Z(0xa6), Z(0xfe), Z(0xb2), Z(0x5e), Z(0x8c), Z(0x3e), Z(0x67), Z(0x6c), Z(0xa1), Z(0x0d), Z(0xc2), Z(0xa2), Z(0xc1), Z(0x85), @@ -147,7 +147,7 @@ static const __be32 sbox1[256] = { }; #undef Z -#define Z(x) __constant_cpu_to_be32(x << 11) +#define Z(x) cpu_to_be32(x << 11) static const __be32 sbox2[256] = { Z(0xf0), Z(0x37), Z(0x24), Z(0x53), Z(0x2a), Z(0x03), Z(0x83), Z(0x86), Z(0xd1), Z(0xec), Z(0x50), Z(0xf0), Z(0x42), Z(0x78), Z(0x2f), Z(0x6d), @@ -184,7 +184,7 @@ static const __be32 sbox2[256] = { }; #undef Z -#define Z(x) __constant_cpu_to_be32(x << 19) +#define Z(x) cpu_to_be32(x << 19) static const __be32 sbox3[256] = { Z(0xa9), Z(0x2a), Z(0x48), Z(0x51), Z(0x84), Z(0x7e), Z(0x49), Z(0xe2), Z(0xb5), Z(0xb7), Z(0x42), Z(0x33), Z(0x7d), Z(0x5d), Z(0xa6), Z(0x12), diff --git a/crypto/hmac.c b/crypto/hmac.c index 7ff2d6a8c7d0b5c58b753140cd579e332e385819..0ad39c3749639e227bef876664ce3ff7ed147c2c 100644 --- a/crypto/hmac.c +++ b/crypto/hmac.c @@ -16,7 +16,7 @@ * */ -#include +#include #include #include #include @@ -238,9 +238,11 @@ static struct crypto_instance *hmac_alloc(struct rtattr **tb) return ERR_CAST(alg); inst = ERR_PTR(-EINVAL); - ds = (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) == - CRYPTO_ALG_TYPE_HASH ? alg->cra_hash.digestsize : - alg->cra_digest.dia_digestsize; + ds = alg->cra_type == &crypto_hash_type ? + alg->cra_hash.digestsize : + alg->cra_type ? + __crypto_shash_alg(alg)->digestsize : + alg->cra_digest.dia_digestsize; if (ds > alg->cra_blocksize) goto out_put_alg; diff --git a/crypto/internal.h b/crypto/internal.h index 8ef72d76092e40227000c3126688f254ffed6978..3c19a27a7563cd628513a777a59121a24caadf85 100644 --- a/crypto/internal.h +++ b/crypto/internal.h @@ -109,6 +109,8 @@ void crypto_alg_tested(const char *name, int err); void crypto_shoot_alg(struct crypto_alg *alg); struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 type, u32 mask); +struct crypto_tfm *crypto_create_tfm(struct crypto_alg *alg, + const struct crypto_type *frontend); int crypto_register_instance(struct crypto_template *tmpl, struct crypto_instance *inst); diff --git a/crypto/md4.c b/crypto/md4.c index 3c19aa0750fdd2f19f135aec5f958a8b55c18d5a..7fca1f59a4f5253baff7a13db7d1fcab9cc9371e 100644 --- a/crypto/md4.c +++ b/crypto/md4.c @@ -20,8 +20,8 @@ * (at your option) any later version. * */ +#include #include -#include #include #include #include @@ -58,7 +58,7 @@ static inline u32 H(u32 x, u32 y, u32 z) { return x ^ y ^ z; } - + #define ROUND1(a,b,c,d,k,s) (a = lshift(a + F(b,c,d) + k, s)) #define ROUND2(a,b,c,d,k,s) (a = lshift(a + G(b,c,d) + k + (u32)0x5A827999,s)) #define ROUND3(a,b,c,d,k,s) (a = lshift(a + H(b,c,d) + k + (u32)0x6ED9EBA1,s)) @@ -148,24 +148,26 @@ static void md4_transform(u32 *hash, u32 const *in) static inline void md4_transform_helper(struct md4_ctx *ctx) { - le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(u32)); + le32_to_cpu_array(ctx->block, ARRAY_SIZE(ctx->block)); md4_transform(ctx->hash, ctx->block); } -static void md4_init(struct crypto_tfm *tfm) +static int md4_init(struct shash_desc *desc) { - struct md4_ctx *mctx = crypto_tfm_ctx(tfm); + struct md4_ctx *mctx = shash_desc_ctx(desc); mctx->hash[0] = 0x67452301; mctx->hash[1] = 0xefcdab89; mctx->hash[2] = 0x98badcfe; mctx->hash[3] = 0x10325476; mctx->byte_count = 0; + + return 0; } -static void md4_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len) +static int md4_update(struct shash_desc *desc, const u8 *data, unsigned int len) { - struct md4_ctx *mctx = crypto_tfm_ctx(tfm); + struct md4_ctx *mctx = shash_desc_ctx(desc); const u32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f); mctx->byte_count += len; @@ -173,7 +175,7 @@ static void md4_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len) if (avail > len) { memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), data, len); - return; + return 0; } memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), @@ -191,11 +193,13 @@ static void md4_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len) } memcpy(mctx->block, data, len); + + return 0; } -static void md4_final(struct crypto_tfm *tfm, u8 *out) +static int md4_final(struct shash_desc *desc, u8 *out) { - struct md4_ctx *mctx = crypto_tfm_ctx(tfm); + struct md4_ctx *mctx = shash_desc_ctx(desc); const unsigned int offset = mctx->byte_count & 0x3f; char *p = (char *)mctx->block + offset; int padding = 56 - (offset + 1); @@ -214,33 +218,35 @@ static void md4_final(struct crypto_tfm *tfm, u8 *out) le32_to_cpu_array(mctx->block, (sizeof(mctx->block) - sizeof(u64)) / sizeof(u32)); md4_transform(mctx->hash, mctx->block); - cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(u32)); + cpu_to_le32_array(mctx->hash, ARRAY_SIZE(mctx->hash)); memcpy(out, mctx->hash, sizeof(mctx->hash)); memset(mctx, 0, sizeof(*mctx)); + + return 0; } -static struct crypto_alg alg = { - .cra_name = "md4", - .cra_flags = CRYPTO_ALG_TYPE_DIGEST, - .cra_blocksize = MD4_HMAC_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct md4_ctx), - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(alg.cra_list), - .cra_u = { .digest = { - .dia_digestsize = MD4_DIGEST_SIZE, - .dia_init = md4_init, - .dia_update = md4_update, - .dia_final = md4_final } } +static struct shash_alg alg = { + .digestsize = MD4_DIGEST_SIZE, + .init = md4_init, + .update = md4_update, + .final = md4_final, + .descsize = sizeof(struct md4_ctx), + .base = { + .cra_name = "md4", + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = MD4_HMAC_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } }; static int __init md4_mod_init(void) { - return crypto_register_alg(&alg); + return crypto_register_shash(&alg); } static void __exit md4_mod_fini(void) { - crypto_unregister_alg(&alg); + crypto_unregister_shash(&alg); } module_init(md4_mod_init); diff --git a/crypto/md5.c b/crypto/md5.c index 39268f3d2f1d249cdcabec3d8fe58315bee10725..83eb52961750115b6332869a4e19fa7b852d39cb 100644 --- a/crypto/md5.c +++ b/crypto/md5.c @@ -15,10 +15,10 @@ * any later version. * */ +#include #include #include #include -#include #include #include @@ -147,20 +147,22 @@ static inline void md5_transform_helper(struct md5_ctx *ctx) md5_transform(ctx->hash, ctx->block); } -static void md5_init(struct crypto_tfm *tfm) +static int md5_init(struct shash_desc *desc) { - struct md5_ctx *mctx = crypto_tfm_ctx(tfm); + struct md5_ctx *mctx = shash_desc_ctx(desc); mctx->hash[0] = 0x67452301; mctx->hash[1] = 0xefcdab89; mctx->hash[2] = 0x98badcfe; mctx->hash[3] = 0x10325476; mctx->byte_count = 0; + + return 0; } -static void md5_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len) +static int md5_update(struct shash_desc *desc, const u8 *data, unsigned int len) { - struct md5_ctx *mctx = crypto_tfm_ctx(tfm); + struct md5_ctx *mctx = shash_desc_ctx(desc); const u32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f); mctx->byte_count += len; @@ -168,7 +170,7 @@ static void md5_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len) if (avail > len) { memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), data, len); - return; + return 0; } memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), @@ -186,11 +188,13 @@ static void md5_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len) } memcpy(mctx->block, data, len); + + return 0; } -static void md5_final(struct crypto_tfm *tfm, u8 *out) +static int md5_final(struct shash_desc *desc, u8 *out) { - struct md5_ctx *mctx = crypto_tfm_ctx(tfm); + struct md5_ctx *mctx = shash_desc_ctx(desc); const unsigned int offset = mctx->byte_count & 0x3f; char *p = (char *)mctx->block + offset; int padding = 56 - (offset + 1); @@ -212,30 +216,32 @@ static void md5_final(struct crypto_tfm *tfm, u8 *out) cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(u32)); memcpy(out, mctx->hash, sizeof(mctx->hash)); memset(mctx, 0, sizeof(*mctx)); + + return 0; } -static struct crypto_alg alg = { - .cra_name = "md5", - .cra_flags = CRYPTO_ALG_TYPE_DIGEST, - .cra_blocksize = MD5_HMAC_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct md5_ctx), - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(alg.cra_list), - .cra_u = { .digest = { - .dia_digestsize = MD5_DIGEST_SIZE, - .dia_init = md5_init, - .dia_update = md5_update, - .dia_final = md5_final } } +static struct shash_alg alg = { + .digestsize = MD5_DIGEST_SIZE, + .init = md5_init, + .update = md5_update, + .final = md5_final, + .descsize = sizeof(struct md5_ctx), + .base = { + .cra_name = "md5", + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = MD5_HMAC_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } }; static int __init md5_mod_init(void) { - return crypto_register_alg(&alg); + return crypto_register_shash(&alg); } static void __exit md5_mod_fini(void) { - crypto_unregister_alg(&alg); + crypto_unregister_shash(&alg); } module_init(md5_mod_init); diff --git a/crypto/michael_mic.c b/crypto/michael_mic.c index 9e917b8011b11e1b712bf769bf8c7bdab4a79a6e..079b761bc70d125b241da7d13d30d7cef8b43846 100644 --- a/crypto/michael_mic.c +++ b/crypto/michael_mic.c @@ -9,23 +9,25 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - +#include #include #include #include #include -#include #include struct michael_mic_ctx { + u32 l, r; +}; + +struct michael_mic_desc_ctx { u8 pending[4]; size_t pending_len; u32 l, r; }; - static inline u32 xswap(u32 val) { return ((val & 0x00ff00ff) << 8) | ((val & 0xff00ff00) >> 8); @@ -45,17 +47,22 @@ do { \ } while (0) -static void michael_init(struct crypto_tfm *tfm) +static int michael_init(struct shash_desc *desc) { - struct michael_mic_ctx *mctx = crypto_tfm_ctx(tfm); + struct michael_mic_desc_ctx *mctx = shash_desc_ctx(desc); + struct michael_mic_ctx *ctx = crypto_shash_ctx(desc->tfm); mctx->pending_len = 0; + mctx->l = ctx->l; + mctx->r = ctx->r; + + return 0; } -static void michael_update(struct crypto_tfm *tfm, const u8 *data, +static int michael_update(struct shash_desc *desc, const u8 *data, unsigned int len) { - struct michael_mic_ctx *mctx = crypto_tfm_ctx(tfm); + struct michael_mic_desc_ctx *mctx = shash_desc_ctx(desc); const __le32 *src; if (mctx->pending_len) { @@ -68,7 +75,7 @@ static void michael_update(struct crypto_tfm *tfm, const u8 *data, len -= flen; if (mctx->pending_len < 4) - return; + return 0; src = (const __le32 *)mctx->pending; mctx->l ^= le32_to_cpup(src); @@ -88,12 +95,14 @@ static void michael_update(struct crypto_tfm *tfm, const u8 *data, mctx->pending_len = len; memcpy(mctx->pending, src, len); } + + return 0; } -static void michael_final(struct crypto_tfm *tfm, u8 *out) +static int michael_final(struct shash_desc *desc, u8 *out) { - struct michael_mic_ctx *mctx = crypto_tfm_ctx(tfm); + struct michael_mic_desc_ctx *mctx = shash_desc_ctx(desc); u8 *data = mctx->pending; __le32 *dst = (__le32 *)out; @@ -119,17 +128,20 @@ static void michael_final(struct crypto_tfm *tfm, u8 *out) dst[0] = cpu_to_le32(mctx->l); dst[1] = cpu_to_le32(mctx->r); + + return 0; } -static int michael_setkey(struct crypto_tfm *tfm, const u8 *key, +static int michael_setkey(struct crypto_shash *tfm, const u8 *key, unsigned int keylen) { - struct michael_mic_ctx *mctx = crypto_tfm_ctx(tfm); + struct michael_mic_ctx *mctx = crypto_shash_ctx(tfm); + const __le32 *data = (const __le32 *)key; if (keylen != 8) { - tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); return -EINVAL; } @@ -138,33 +150,31 @@ static int michael_setkey(struct crypto_tfm *tfm, const u8 *key, return 0; } - -static struct crypto_alg michael_mic_alg = { - .cra_name = "michael_mic", - .cra_flags = CRYPTO_ALG_TYPE_DIGEST, - .cra_blocksize = 8, - .cra_ctxsize = sizeof(struct michael_mic_ctx), - .cra_module = THIS_MODULE, - .cra_alignmask = 3, - .cra_list = LIST_HEAD_INIT(michael_mic_alg.cra_list), - .cra_u = { .digest = { - .dia_digestsize = 8, - .dia_init = michael_init, - .dia_update = michael_update, - .dia_final = michael_final, - .dia_setkey = michael_setkey } } +static struct shash_alg alg = { + .digestsize = 8, + .setkey = michael_setkey, + .init = michael_init, + .update = michael_update, + .final = michael_final, + .descsize = sizeof(struct michael_mic_desc_ctx), + .base = { + .cra_name = "michael_mic", + .cra_blocksize = 8, + .cra_alignmask = 3, + .cra_ctxsize = sizeof(struct michael_mic_ctx), + .cra_module = THIS_MODULE, + } }; - static int __init michael_mic_init(void) { - return crypto_register_alg(&michael_mic_alg); + return crypto_register_shash(&alg); } static void __exit michael_mic_exit(void) { - crypto_unregister_alg(&michael_mic_alg); + crypto_unregister_shash(&alg); } diff --git a/crypto/proc.c b/crypto/proc.c index 37a13d05636d4beaaea521d4538aa711e8bbb627..5dc07e442fca00f73359b53cb44669d4250bafc2 100644 --- a/crypto/proc.c +++ b/crypto/proc.c @@ -94,6 +94,17 @@ static int c_show(struct seq_file *m, void *p) seq_printf(m, "selftest : %s\n", (alg->cra_flags & CRYPTO_ALG_TESTED) ? "passed" : "unknown"); + + if (alg->cra_flags & CRYPTO_ALG_LARVAL) { + seq_printf(m, "type : larval\n"); + seq_printf(m, "flags : 0x%x\n", alg->cra_flags); + goto out; + } + + if (alg->cra_type && alg->cra_type->show) { + alg->cra_type->show(m, alg); + goto out; + } switch (alg->cra_flags & (CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_LARVAL)) { case CRYPTO_ALG_TYPE_CIPHER: @@ -115,16 +126,11 @@ static int c_show(struct seq_file *m, void *p) seq_printf(m, "type : compression\n"); break; default: - if (alg->cra_flags & CRYPTO_ALG_LARVAL) { - seq_printf(m, "type : larval\n"); - seq_printf(m, "flags : 0x%x\n", alg->cra_flags); - } else if (alg->cra_type && alg->cra_type->show) - alg->cra_type->show(m, alg); - else - seq_printf(m, "type : unknown\n"); + seq_printf(m, "type : unknown\n"); break; } +out: seq_putc(m, '\n'); return 0; } diff --git a/crypto/rmd128.c b/crypto/rmd128.c index 5de6fa2a76fbe489f4868341ce595971733e3a91..1ceb6735aa5386f5507fbd0c9e5cc19a66feb7b5 100644 --- a/crypto/rmd128.c +++ b/crypto/rmd128.c @@ -13,11 +13,10 @@ * any later version. * */ +#include #include #include #include -#include -#include #include #include @@ -218,9 +217,9 @@ static void rmd128_transform(u32 *state, const __le32 *in) return; } -static void rmd128_init(struct crypto_tfm *tfm) +static int rmd128_init(struct shash_desc *desc) { - struct rmd128_ctx *rctx = crypto_tfm_ctx(tfm); + struct rmd128_ctx *rctx = shash_desc_ctx(desc); rctx->byte_count = 0; @@ -230,12 +229,14 @@ static void rmd128_init(struct crypto_tfm *tfm) rctx->state[3] = RMD_H3; memset(rctx->buffer, 0, sizeof(rctx->buffer)); + + return 0; } -static void rmd128_update(struct crypto_tfm *tfm, const u8 *data, - unsigned int len) +static int rmd128_update(struct shash_desc *desc, const u8 *data, + unsigned int len) { - struct rmd128_ctx *rctx = crypto_tfm_ctx(tfm); + struct rmd128_ctx *rctx = shash_desc_ctx(desc); const u32 avail = sizeof(rctx->buffer) - (rctx->byte_count & 0x3f); rctx->byte_count += len; @@ -244,7 +245,7 @@ static void rmd128_update(struct crypto_tfm *tfm, const u8 *data, if (avail > len) { memcpy((char *)rctx->buffer + (sizeof(rctx->buffer) - avail), data, len); - return; + goto out; } memcpy((char *)rctx->buffer + (sizeof(rctx->buffer) - avail), @@ -262,12 +263,15 @@ static void rmd128_update(struct crypto_tfm *tfm, const u8 *data, } memcpy(rctx->buffer, data, len); + +out: + return 0; } /* Add padding and return the message digest. */ -static void rmd128_final(struct crypto_tfm *tfm, u8 *out) +static int rmd128_final(struct shash_desc *desc, u8 *out) { - struct rmd128_ctx *rctx = crypto_tfm_ctx(tfm); + struct rmd128_ctx *rctx = shash_desc_ctx(desc); u32 i, index, padlen; __le64 bits; __le32 *dst = (__le32 *)out; @@ -278,10 +282,10 @@ static void rmd128_final(struct crypto_tfm *tfm, u8 *out) /* Pad out to 56 mod 64 */ index = rctx->byte_count & 0x3f; padlen = (index < 56) ? (56 - index) : ((64+56) - index); - rmd128_update(tfm, padding, padlen); + rmd128_update(desc, padding, padlen); /* Append length */ - rmd128_update(tfm, (const u8 *)&bits, sizeof(bits)); + rmd128_update(desc, (const u8 *)&bits, sizeof(bits)); /* Store state in digest */ for (i = 0; i < 4; i++) @@ -289,31 +293,32 @@ static void rmd128_final(struct crypto_tfm *tfm, u8 *out) /* Wipe context */ memset(rctx, 0, sizeof(*rctx)); + + return 0; } -static struct crypto_alg alg = { - .cra_name = "rmd128", - .cra_driver_name = "rmd128", - .cra_flags = CRYPTO_ALG_TYPE_DIGEST, - .cra_blocksize = RMD128_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct rmd128_ctx), - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(alg.cra_list), - .cra_u = { .digest = { - .dia_digestsize = RMD128_DIGEST_SIZE, - .dia_init = rmd128_init, - .dia_update = rmd128_update, - .dia_final = rmd128_final } } +static struct shash_alg alg = { + .digestsize = RMD128_DIGEST_SIZE, + .init = rmd128_init, + .update = rmd128_update, + .final = rmd128_final, + .descsize = sizeof(struct rmd128_ctx), + .base = { + .cra_name = "rmd128", + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = RMD128_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } }; static int __init rmd128_mod_init(void) { - return crypto_register_alg(&alg); + return crypto_register_shash(&alg); } static void __exit rmd128_mod_fini(void) { - crypto_unregister_alg(&alg); + crypto_unregister_shash(&alg); } module_init(rmd128_mod_init); @@ -321,5 +326,3 @@ module_exit(rmd128_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("RIPEMD-128 Message Digest"); - -MODULE_ALIAS("rmd128"); diff --git a/crypto/rmd160.c b/crypto/rmd160.c index f001ec775e1fcd6d22a39fc453b953cccc851ec6..472261fc913fb43918c0074fc72023190e31acff 100644 --- a/crypto/rmd160.c +++ b/crypto/rmd160.c @@ -13,11 +13,10 @@ * any later version. * */ +#include #include #include #include -#include -#include #include #include @@ -261,9 +260,9 @@ static void rmd160_transform(u32 *state, const __le32 *in) return; } -static void rmd160_init(struct crypto_tfm *tfm) +static int rmd160_init(struct shash_desc *desc) { - struct rmd160_ctx *rctx = crypto_tfm_ctx(tfm); + struct rmd160_ctx *rctx = shash_desc_ctx(desc); rctx->byte_count = 0; @@ -274,12 +273,14 @@ static void rmd160_init(struct crypto_tfm *tfm) rctx->state[4] = RMD_H4; memset(rctx->buffer, 0, sizeof(rctx->buffer)); + + return 0; } -static void rmd160_update(struct crypto_tfm *tfm, const u8 *data, - unsigned int len) +static int rmd160_update(struct shash_desc *desc, const u8 *data, + unsigned int len) { - struct rmd160_ctx *rctx = crypto_tfm_ctx(tfm); + struct rmd160_ctx *rctx = shash_desc_ctx(desc); const u32 avail = sizeof(rctx->buffer) - (rctx->byte_count & 0x3f); rctx->byte_count += len; @@ -288,7 +289,7 @@ static void rmd160_update(struct crypto_tfm *tfm, const u8 *data, if (avail > len) { memcpy((char *)rctx->buffer + (sizeof(rctx->buffer) - avail), data, len); - return; + goto out; } memcpy((char *)rctx->buffer + (sizeof(rctx->buffer) - avail), @@ -306,12 +307,15 @@ static void rmd160_update(struct crypto_tfm *tfm, const u8 *data, } memcpy(rctx->buffer, data, len); + +out: + return 0; } /* Add padding and return the message digest. */ -static void rmd160_final(struct crypto_tfm *tfm, u8 *out) +static int rmd160_final(struct shash_desc *desc, u8 *out) { - struct rmd160_ctx *rctx = crypto_tfm_ctx(tfm); + struct rmd160_ctx *rctx = shash_desc_ctx(desc); u32 i, index, padlen; __le64 bits; __le32 *dst = (__le32 *)out; @@ -322,10 +326,10 @@ static void rmd160_final(struct crypto_tfm *tfm, u8 *out) /* Pad out to 56 mod 64 */ index = rctx->byte_count & 0x3f; padlen = (index < 56) ? (56 - index) : ((64+56) - index); - rmd160_update(tfm, padding, padlen); + rmd160_update(desc, padding, padlen); /* Append length */ - rmd160_update(tfm, (const u8 *)&bits, sizeof(bits)); + rmd160_update(desc, (const u8 *)&bits, sizeof(bits)); /* Store state in digest */ for (i = 0; i < 5; i++) @@ -333,31 +337,32 @@ static void rmd160_final(struct crypto_tfm *tfm, u8 *out) /* Wipe context */ memset(rctx, 0, sizeof(*rctx)); + + return 0; } -static struct crypto_alg alg = { - .cra_name = "rmd160", - .cra_driver_name = "rmd160", - .cra_flags = CRYPTO_ALG_TYPE_DIGEST, - .cra_blocksize = RMD160_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct rmd160_ctx), - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(alg.cra_list), - .cra_u = { .digest = { - .dia_digestsize = RMD160_DIGEST_SIZE, - .dia_init = rmd160_init, - .dia_update = rmd160_update, - .dia_final = rmd160_final } } +static struct shash_alg alg = { + .digestsize = RMD160_DIGEST_SIZE, + .init = rmd160_init, + .update = rmd160_update, + .final = rmd160_final, + .descsize = sizeof(struct rmd160_ctx), + .base = { + .cra_name = "rmd160", + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = RMD160_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } }; static int __init rmd160_mod_init(void) { - return crypto_register_alg(&alg); + return crypto_register_shash(&alg); } static void __exit rmd160_mod_fini(void) { - crypto_unregister_alg(&alg); + crypto_unregister_shash(&alg); } module_init(rmd160_mod_init); @@ -365,5 +370,3 @@ module_exit(rmd160_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("RIPEMD-160 Message Digest"); - -MODULE_ALIAS("rmd160"); diff --git a/crypto/rmd256.c b/crypto/rmd256.c index e3de5b4cb47f99bb46fea596426f869b770b68b0..72eafa8d2e7bdcb3e403eadeca3a58f6cc298ad0 100644 --- a/crypto/rmd256.c +++ b/crypto/rmd256.c @@ -13,11 +13,10 @@ * any later version. * */ +#include #include #include #include -#include -#include #include #include @@ -233,9 +232,9 @@ static void rmd256_transform(u32 *state, const __le32 *in) return; } -static void rmd256_init(struct crypto_tfm *tfm) +static int rmd256_init(struct shash_desc *desc) { - struct rmd256_ctx *rctx = crypto_tfm_ctx(tfm); + struct rmd256_ctx *rctx = shash_desc_ctx(desc); rctx->byte_count = 0; @@ -249,12 +248,14 @@ static void rmd256_init(struct crypto_tfm *tfm) rctx->state[7] = RMD_H8; memset(rctx->buffer, 0, sizeof(rctx->buffer)); + + return 0; } -static void rmd256_update(struct crypto_tfm *tfm, const u8 *data, - unsigned int len) +static int rmd256_update(struct shash_desc *desc, const u8 *data, + unsigned int len) { - struct rmd256_ctx *rctx = crypto_tfm_ctx(tfm); + struct rmd256_ctx *rctx = shash_desc_ctx(desc); const u32 avail = sizeof(rctx->buffer) - (rctx->byte_count & 0x3f); rctx->byte_count += len; @@ -263,7 +264,7 @@ static void rmd256_update(struct crypto_tfm *tfm, const u8 *data, if (avail > len) { memcpy((char *)rctx->buffer + (sizeof(rctx->buffer) - avail), data, len); - return; + goto out; } memcpy((char *)rctx->buffer + (sizeof(rctx->buffer) - avail), @@ -281,12 +282,15 @@ static void rmd256_update(struct crypto_tfm *tfm, const u8 *data, } memcpy(rctx->buffer, data, len); + +out: + return 0; } /* Add padding and return the message digest. */ -static void rmd256_final(struct crypto_tfm *tfm, u8 *out) +static int rmd256_final(struct shash_desc *desc, u8 *out) { - struct rmd256_ctx *rctx = crypto_tfm_ctx(tfm); + struct rmd256_ctx *rctx = shash_desc_ctx(desc); u32 i, index, padlen; __le64 bits; __le32 *dst = (__le32 *)out; @@ -297,10 +301,10 @@ static void rmd256_final(struct crypto_tfm *tfm, u8 *out) /* Pad out to 56 mod 64 */ index = rctx->byte_count & 0x3f; padlen = (index < 56) ? (56 - index) : ((64+56) - index); - rmd256_update(tfm, padding, padlen); + rmd256_update(desc, padding, padlen); /* Append length */ - rmd256_update(tfm, (const u8 *)&bits, sizeof(bits)); + rmd256_update(desc, (const u8 *)&bits, sizeof(bits)); /* Store state in digest */ for (i = 0; i < 8; i++) @@ -308,31 +312,32 @@ static void rmd256_final(struct crypto_tfm *tfm, u8 *out) /* Wipe context */ memset(rctx, 0, sizeof(*rctx)); + + return 0; } -static struct crypto_alg alg = { - .cra_name = "rmd256", - .cra_driver_name = "rmd256", - .cra_flags = CRYPTO_ALG_TYPE_DIGEST, - .cra_blocksize = RMD256_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct rmd256_ctx), - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(alg.cra_list), - .cra_u = { .digest = { - .dia_digestsize = RMD256_DIGEST_SIZE, - .dia_init = rmd256_init, - .dia_update = rmd256_update, - .dia_final = rmd256_final } } +static struct shash_alg alg = { + .digestsize = RMD256_DIGEST_SIZE, + .init = rmd256_init, + .update = rmd256_update, + .final = rmd256_final, + .descsize = sizeof(struct rmd256_ctx), + .base = { + .cra_name = "rmd256", + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = RMD256_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } }; static int __init rmd256_mod_init(void) { - return crypto_register_alg(&alg); + return crypto_register_shash(&alg); } static void __exit rmd256_mod_fini(void) { - crypto_unregister_alg(&alg); + crypto_unregister_shash(&alg); } module_init(rmd256_mod_init); @@ -340,5 +345,3 @@ module_exit(rmd256_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("RIPEMD-256 Message Digest"); - -MODULE_ALIAS("rmd256"); diff --git a/crypto/rmd320.c b/crypto/rmd320.c index b143d66e42c8095c3742589f06106dfe8b65b793..86becaba2f05bbd714121242110b28338c5da3f2 100644 --- a/crypto/rmd320.c +++ b/crypto/rmd320.c @@ -13,11 +13,10 @@ * any later version. * */ +#include #include #include #include -#include -#include #include #include @@ -280,9 +279,9 @@ static void rmd320_transform(u32 *state, const __le32 *in) return; } -static void rmd320_init(struct crypto_tfm *tfm) +static int rmd320_init(struct shash_desc *desc) { - struct rmd320_ctx *rctx = crypto_tfm_ctx(tfm); + struct rmd320_ctx *rctx = shash_desc_ctx(desc); rctx->byte_count = 0; @@ -298,12 +297,14 @@ static void rmd320_init(struct crypto_tfm *tfm) rctx->state[9] = RMD_H9; memset(rctx->buffer, 0, sizeof(rctx->buffer)); + + return 0; } -static void rmd320_update(struct crypto_tfm *tfm, const u8 *data, - unsigned int len) +static int rmd320_update(struct shash_desc *desc, const u8 *data, + unsigned int len) { - struct rmd320_ctx *rctx = crypto_tfm_ctx(tfm); + struct rmd320_ctx *rctx = shash_desc_ctx(desc); const u32 avail = sizeof(rctx->buffer) - (rctx->byte_count & 0x3f); rctx->byte_count += len; @@ -312,7 +313,7 @@ static void rmd320_update(struct crypto_tfm *tfm, const u8 *data, if (avail > len) { memcpy((char *)rctx->buffer + (sizeof(rctx->buffer) - avail), data, len); - return; + goto out; } memcpy((char *)rctx->buffer + (sizeof(rctx->buffer) - avail), @@ -330,12 +331,15 @@ static void rmd320_update(struct crypto_tfm *tfm, const u8 *data, } memcpy(rctx->buffer, data, len); + +out: + return 0; } /* Add padding and return the message digest. */ -static void rmd320_final(struct crypto_tfm *tfm, u8 *out) +static int rmd320_final(struct shash_desc *desc, u8 *out) { - struct rmd320_ctx *rctx = crypto_tfm_ctx(tfm); + struct rmd320_ctx *rctx = shash_desc_ctx(desc); u32 i, index, padlen; __le64 bits; __le32 *dst = (__le32 *)out; @@ -346,10 +350,10 @@ static void rmd320_final(struct crypto_tfm *tfm, u8 *out) /* Pad out to 56 mod 64 */ index = rctx->byte_count & 0x3f; padlen = (index < 56) ? (56 - index) : ((64+56) - index); - rmd320_update(tfm, padding, padlen); + rmd320_update(desc, padding, padlen); /* Append length */ - rmd320_update(tfm, (const u8 *)&bits, sizeof(bits)); + rmd320_update(desc, (const u8 *)&bits, sizeof(bits)); /* Store state in digest */ for (i = 0; i < 10; i++) @@ -357,31 +361,32 @@ static void rmd320_final(struct crypto_tfm *tfm, u8 *out) /* Wipe context */ memset(rctx, 0, sizeof(*rctx)); + + return 0; } -static struct crypto_alg alg = { - .cra_name = "rmd320", - .cra_driver_name = "rmd320", - .cra_flags = CRYPTO_ALG_TYPE_DIGEST, - .cra_blocksize = RMD320_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct rmd320_ctx), - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(alg.cra_list), - .cra_u = { .digest = { - .dia_digestsize = RMD320_DIGEST_SIZE, - .dia_init = rmd320_init, - .dia_update = rmd320_update, - .dia_final = rmd320_final } } +static struct shash_alg alg = { + .digestsize = RMD320_DIGEST_SIZE, + .init = rmd320_init, + .update = rmd320_update, + .final = rmd320_final, + .descsize = sizeof(struct rmd320_ctx), + .base = { + .cra_name = "rmd320", + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = RMD320_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } }; static int __init rmd320_mod_init(void) { - return crypto_register_alg(&alg); + return crypto_register_shash(&alg); } static void __exit rmd320_mod_fini(void) { - crypto_unregister_alg(&alg); + crypto_unregister_shash(&alg); } module_init(rmd320_mod_init); @@ -389,5 +394,3 @@ module_exit(rmd320_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("RIPEMD-320 Message Digest"); - -MODULE_ALIAS("rmd320"); diff --git a/crypto/salsa20_generic.c b/crypto/salsa20_generic.c index b07d55981741578b951b8accbe6cf2b47c771f95..eac10c11685cd436472d9262347922b88165b50d 100644 --- a/crypto/salsa20_generic.c +++ b/crypto/salsa20_generic.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -42,10 +43,6 @@ D. J. Bernstein Public domain. */ -#define ROTATE(v,n) (((v) << (n)) | ((v) >> (32 - (n)))) -#define XOR(v,w) ((v) ^ (w)) -#define PLUS(v,w) (((v) + (w))) -#define PLUSONE(v) (PLUS((v),1)) #define U32TO8_LITTLE(p, v) \ { (p)[0] = (v >> 0) & 0xff; (p)[1] = (v >> 8) & 0xff; \ (p)[2] = (v >> 16) & 0xff; (p)[3] = (v >> 24) & 0xff; } @@ -65,41 +62,41 @@ static void salsa20_wordtobyte(u8 output[64], const u32 input[16]) memcpy(x, input, sizeof(x)); for (i = 20; i > 0; i -= 2) { - x[ 4] = XOR(x[ 4],ROTATE(PLUS(x[ 0],x[12]), 7)); - x[ 8] = XOR(x[ 8],ROTATE(PLUS(x[ 4],x[ 0]), 9)); - x[12] = XOR(x[12],ROTATE(PLUS(x[ 8],x[ 4]),13)); - x[ 0] = XOR(x[ 0],ROTATE(PLUS(x[12],x[ 8]),18)); - x[ 9] = XOR(x[ 9],ROTATE(PLUS(x[ 5],x[ 1]), 7)); - x[13] = XOR(x[13],ROTATE(PLUS(x[ 9],x[ 5]), 9)); - x[ 1] = XOR(x[ 1],ROTATE(PLUS(x[13],x[ 9]),13)); - x[ 5] = XOR(x[ 5],ROTATE(PLUS(x[ 1],x[13]),18)); - x[14] = XOR(x[14],ROTATE(PLUS(x[10],x[ 6]), 7)); - x[ 2] = XOR(x[ 2],ROTATE(PLUS(x[14],x[10]), 9)); - x[ 6] = XOR(x[ 6],ROTATE(PLUS(x[ 2],x[14]),13)); - x[10] = XOR(x[10],ROTATE(PLUS(x[ 6],x[ 2]),18)); - x[ 3] = XOR(x[ 3],ROTATE(PLUS(x[15],x[11]), 7)); - x[ 7] = XOR(x[ 7],ROTATE(PLUS(x[ 3],x[15]), 9)); - x[11] = XOR(x[11],ROTATE(PLUS(x[ 7],x[ 3]),13)); - x[15] = XOR(x[15],ROTATE(PLUS(x[11],x[ 7]),18)); - x[ 1] = XOR(x[ 1],ROTATE(PLUS(x[ 0],x[ 3]), 7)); - x[ 2] = XOR(x[ 2],ROTATE(PLUS(x[ 1],x[ 0]), 9)); - x[ 3] = XOR(x[ 3],ROTATE(PLUS(x[ 2],x[ 1]),13)); - x[ 0] = XOR(x[ 0],ROTATE(PLUS(x[ 3],x[ 2]),18)); - x[ 6] = XOR(x[ 6],ROTATE(PLUS(x[ 5],x[ 4]), 7)); - x[ 7] = XOR(x[ 7],ROTATE(PLUS(x[ 6],x[ 5]), 9)); - x[ 4] = XOR(x[ 4],ROTATE(PLUS(x[ 7],x[ 6]),13)); - x[ 5] = XOR(x[ 5],ROTATE(PLUS(x[ 4],x[ 7]),18)); - x[11] = XOR(x[11],ROTATE(PLUS(x[10],x[ 9]), 7)); - x[ 8] = XOR(x[ 8],ROTATE(PLUS(x[11],x[10]), 9)); - x[ 9] = XOR(x[ 9],ROTATE(PLUS(x[ 8],x[11]),13)); - x[10] = XOR(x[10],ROTATE(PLUS(x[ 9],x[ 8]),18)); - x[12] = XOR(x[12],ROTATE(PLUS(x[15],x[14]), 7)); - x[13] = XOR(x[13],ROTATE(PLUS(x[12],x[15]), 9)); - x[14] = XOR(x[14],ROTATE(PLUS(x[13],x[12]),13)); - x[15] = XOR(x[15],ROTATE(PLUS(x[14],x[13]),18)); + x[ 4] ^= rol32((x[ 0] + x[12]), 7); + x[ 8] ^= rol32((x[ 4] + x[ 0]), 9); + x[12] ^= rol32((x[ 8] + x[ 4]), 13); + x[ 0] ^= rol32((x[12] + x[ 8]), 18); + x[ 9] ^= rol32((x[ 5] + x[ 1]), 7); + x[13] ^= rol32((x[ 9] + x[ 5]), 9); + x[ 1] ^= rol32((x[13] + x[ 9]), 13); + x[ 5] ^= rol32((x[ 1] + x[13]), 18); + x[14] ^= rol32((x[10] + x[ 6]), 7); + x[ 2] ^= rol32((x[14] + x[10]), 9); + x[ 6] ^= rol32((x[ 2] + x[14]), 13); + x[10] ^= rol32((x[ 6] + x[ 2]), 18); + x[ 3] ^= rol32((x[15] + x[11]), 7); + x[ 7] ^= rol32((x[ 3] + x[15]), 9); + x[11] ^= rol32((x[ 7] + x[ 3]), 13); + x[15] ^= rol32((x[11] + x[ 7]), 18); + x[ 1] ^= rol32((x[ 0] + x[ 3]), 7); + x[ 2] ^= rol32((x[ 1] + x[ 0]), 9); + x[ 3] ^= rol32((x[ 2] + x[ 1]), 13); + x[ 0] ^= rol32((x[ 3] + x[ 2]), 18); + x[ 6] ^= rol32((x[ 5] + x[ 4]), 7); + x[ 7] ^= rol32((x[ 6] + x[ 5]), 9); + x[ 4] ^= rol32((x[ 7] + x[ 6]), 13); + x[ 5] ^= rol32((x[ 4] + x[ 7]), 18); + x[11] ^= rol32((x[10] + x[ 9]), 7); + x[ 8] ^= rol32((x[11] + x[10]), 9); + x[ 9] ^= rol32((x[ 8] + x[11]), 13); + x[10] ^= rol32((x[ 9] + x[ 8]), 18); + x[12] ^= rol32((x[15] + x[14]), 7); + x[13] ^= rol32((x[12] + x[15]), 9); + x[14] ^= rol32((x[13] + x[12]), 13); + x[15] ^= rol32((x[14] + x[13]), 18); } for (i = 0; i < 16; ++i) - x[i] = PLUS(x[i],input[i]); + x[i] += input[i]; for (i = 0; i < 16; ++i) U32TO8_LITTLE(output + 4 * i,x[i]); } @@ -150,9 +147,9 @@ static void salsa20_encrypt_bytes(struct salsa20_ctx *ctx, u8 *dst, while (bytes) { salsa20_wordtobyte(buf, ctx->input); - ctx->input[8] = PLUSONE(ctx->input[8]); + ctx->input[8]++; if (!ctx->input[8]) - ctx->input[9] = PLUSONE(ctx->input[9]); + ctx->input[9]++; if (bytes <= 64) { crypto_xor(dst, buf, bytes); diff --git a/crypto/sha1_generic.c b/crypto/sha1_generic.c index c7c6899e1fca8efb0ce9af81c42747f180203ed7..9efef20454cba0281c9e08c9ec02da4eae0e3665 100644 --- a/crypto/sha1_generic.c +++ b/crypto/sha1_generic.c @@ -16,10 +16,10 @@ * any later version. * */ +#include #include #include #include -#include #include #include #include @@ -31,9 +31,10 @@ struct sha1_ctx { u8 buffer[64]; }; -static void sha1_init(struct crypto_tfm *tfm) +static int sha1_init(struct shash_desc *desc) { - struct sha1_ctx *sctx = crypto_tfm_ctx(tfm); + struct sha1_ctx *sctx = shash_desc_ctx(desc); + static const struct sha1_ctx initstate = { 0, { SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4 }, @@ -41,12 +42,14 @@ static void sha1_init(struct crypto_tfm *tfm) }; *sctx = initstate; + + return 0; } -static void sha1_update(struct crypto_tfm *tfm, const u8 *data, +static int sha1_update(struct shash_desc *desc, const u8 *data, unsigned int len) { - struct sha1_ctx *sctx = crypto_tfm_ctx(tfm); + struct sha1_ctx *sctx = shash_desc_ctx(desc); unsigned int partial, done; const u8 *src; @@ -74,13 +77,15 @@ static void sha1_update(struct crypto_tfm *tfm, const u8 *data, partial = 0; } memcpy(sctx->buffer + partial, src, len - done); + + return 0; } /* Add padding and return the message digest. */ -static void sha1_final(struct crypto_tfm *tfm, u8 *out) +static int sha1_final(struct shash_desc *desc, u8 *out) { - struct sha1_ctx *sctx = crypto_tfm_ctx(tfm); + struct sha1_ctx *sctx = shash_desc_ctx(desc); __be32 *dst = (__be32 *)out; u32 i, index, padlen; __be64 bits; @@ -91,10 +96,10 @@ static void sha1_final(struct crypto_tfm *tfm, u8 *out) /* Pad out to 56 mod 64 */ index = sctx->count & 0x3f; padlen = (index < 56) ? (56 - index) : ((64+56) - index); - sha1_update(tfm, padding, padlen); + sha1_update(desc, padding, padlen); /* Append length */ - sha1_update(tfm, (const u8 *)&bits, sizeof(bits)); + sha1_update(desc, (const u8 *)&bits, sizeof(bits)); /* Store state in digest */ for (i = 0; i < 5; i++) @@ -102,32 +107,33 @@ static void sha1_final(struct crypto_tfm *tfm, u8 *out) /* Wipe context */ memset(sctx, 0, sizeof *sctx); + + return 0; } -static struct crypto_alg alg = { - .cra_name = "sha1", - .cra_driver_name= "sha1-generic", - .cra_flags = CRYPTO_ALG_TYPE_DIGEST, - .cra_blocksize = SHA1_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct sha1_ctx), - .cra_module = THIS_MODULE, - .cra_alignmask = 3, - .cra_list = LIST_HEAD_INIT(alg.cra_list), - .cra_u = { .digest = { - .dia_digestsize = SHA1_DIGEST_SIZE, - .dia_init = sha1_init, - .dia_update = sha1_update, - .dia_final = sha1_final } } +static struct shash_alg alg = { + .digestsize = SHA1_DIGEST_SIZE, + .init = sha1_init, + .update = sha1_update, + .final = sha1_final, + .descsize = sizeof(struct sha1_ctx), + .base = { + .cra_name = "sha1", + .cra_driver_name= "sha1-generic", + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = SHA1_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } }; static int __init sha1_generic_mod_init(void) { - return crypto_register_alg(&alg); + return crypto_register_shash(&alg); } static void __exit sha1_generic_mod_fini(void) { - crypto_unregister_alg(&alg); + crypto_unregister_shash(&alg); } module_init(sha1_generic_mod_init); diff --git a/crypto/sha256_generic.c b/crypto/sha256_generic.c index 5a8dd47558e566752d9d3cbd02231fd981be0a4e..caa3542e6ce8943a2b5ed5f9a0f0aaded9a486cc 100644 --- a/crypto/sha256_generic.c +++ b/crypto/sha256_generic.c @@ -17,10 +17,10 @@ * any later version. * */ +#include #include #include #include -#include #include #include #include @@ -69,7 +69,7 @@ static void sha256_transform(u32 *state, const u8 *input) /* now blend */ for (i = 16; i < 64; i++) BLEND_OP(i, W); - + /* load the state into our registers */ a=state[0]; b=state[1]; c=state[2]; d=state[3]; e=state[4]; f=state[5]; g=state[6]; h=state[7]; @@ -220,9 +220,9 @@ static void sha256_transform(u32 *state, const u8 *input) } -static void sha224_init(struct crypto_tfm *tfm) +static int sha224_init(struct shash_desc *desc) { - struct sha256_ctx *sctx = crypto_tfm_ctx(tfm); + struct sha256_ctx *sctx = shash_desc_ctx(desc); sctx->state[0] = SHA224_H0; sctx->state[1] = SHA224_H1; sctx->state[2] = SHA224_H2; @@ -233,11 +233,13 @@ static void sha224_init(struct crypto_tfm *tfm) sctx->state[7] = SHA224_H7; sctx->count[0] = 0; sctx->count[1] = 0; + + return 0; } -static void sha256_init(struct crypto_tfm *tfm) +static int sha256_init(struct shash_desc *desc) { - struct sha256_ctx *sctx = crypto_tfm_ctx(tfm); + struct sha256_ctx *sctx = shash_desc_ctx(desc); sctx->state[0] = SHA256_H0; sctx->state[1] = SHA256_H1; sctx->state[2] = SHA256_H2; @@ -247,12 +249,14 @@ static void sha256_init(struct crypto_tfm *tfm) sctx->state[6] = SHA256_H6; sctx->state[7] = SHA256_H7; sctx->count[0] = sctx->count[1] = 0; + + return 0; } -static void sha256_update(struct crypto_tfm *tfm, const u8 *data, +static int sha256_update(struct shash_desc *desc, const u8 *data, unsigned int len) { - struct sha256_ctx *sctx = crypto_tfm_ctx(tfm); + struct sha256_ctx *sctx = shash_desc_ctx(desc); unsigned int i, index, part_len; /* Compute number of bytes mod 128 */ @@ -277,14 +281,16 @@ static void sha256_update(struct crypto_tfm *tfm, const u8 *data, } else { i = 0; } - + /* Buffer remaining input */ memcpy(&sctx->buf[index], &data[i], len-i); + + return 0; } -static void sha256_final(struct crypto_tfm *tfm, u8 *out) +static int sha256_final(struct shash_desc *desc, u8 *out) { - struct sha256_ctx *sctx = crypto_tfm_ctx(tfm); + struct sha256_ctx *sctx = shash_desc_ctx(desc); __be32 *dst = (__be32 *)out; __be32 bits[2]; unsigned int index, pad_len; @@ -298,10 +304,10 @@ static void sha256_final(struct crypto_tfm *tfm, u8 *out) /* Pad out to 56 mod 64. */ index = (sctx->count[0] >> 3) & 0x3f; pad_len = (index < 56) ? (56 - index) : ((64+56) - index); - sha256_update(tfm, padding, pad_len); + sha256_update(desc, padding, pad_len); /* Append length (before padding) */ - sha256_update(tfm, (const u8 *)bits, sizeof(bits)); + sha256_update(desc, (const u8 *)bits, sizeof(bits)); /* Store state in digest */ for (i = 0; i < 8; i++) @@ -309,71 +315,73 @@ static void sha256_final(struct crypto_tfm *tfm, u8 *out) /* Zeroize sensitive information. */ memset(sctx, 0, sizeof(*sctx)); + + return 0; } -static void sha224_final(struct crypto_tfm *tfm, u8 *hash) +static int sha224_final(struct shash_desc *desc, u8 *hash) { u8 D[SHA256_DIGEST_SIZE]; - sha256_final(tfm, D); + sha256_final(desc, D); memcpy(hash, D, SHA224_DIGEST_SIZE); memset(D, 0, SHA256_DIGEST_SIZE); + + return 0; } -static struct crypto_alg sha256 = { - .cra_name = "sha256", - .cra_driver_name= "sha256-generic", - .cra_flags = CRYPTO_ALG_TYPE_DIGEST, - .cra_blocksize = SHA256_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct sha256_ctx), - .cra_module = THIS_MODULE, - .cra_alignmask = 3, - .cra_list = LIST_HEAD_INIT(sha256.cra_list), - .cra_u = { .digest = { - .dia_digestsize = SHA256_DIGEST_SIZE, - .dia_init = sha256_init, - .dia_update = sha256_update, - .dia_final = sha256_final } } +static struct shash_alg sha256 = { + .digestsize = SHA256_DIGEST_SIZE, + .init = sha256_init, + .update = sha256_update, + .final = sha256_final, + .descsize = sizeof(struct sha256_ctx), + .base = { + .cra_name = "sha256", + .cra_driver_name= "sha256-generic", + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = SHA256_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } }; -static struct crypto_alg sha224 = { - .cra_name = "sha224", - .cra_driver_name = "sha224-generic", - .cra_flags = CRYPTO_ALG_TYPE_DIGEST, - .cra_blocksize = SHA224_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct sha256_ctx), - .cra_module = THIS_MODULE, - .cra_alignmask = 3, - .cra_list = LIST_HEAD_INIT(sha224.cra_list), - .cra_u = { .digest = { - .dia_digestsize = SHA224_DIGEST_SIZE, - .dia_init = sha224_init, - .dia_update = sha256_update, - .dia_final = sha224_final } } +static struct shash_alg sha224 = { + .digestsize = SHA224_DIGEST_SIZE, + .init = sha224_init, + .update = sha256_update, + .final = sha224_final, + .descsize = sizeof(struct sha256_ctx), + .base = { + .cra_name = "sha224", + .cra_driver_name= "sha224-generic", + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = SHA224_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } }; static int __init sha256_generic_mod_init(void) { int ret = 0; - ret = crypto_register_alg(&sha224); + ret = crypto_register_shash(&sha224); if (ret < 0) return ret; - ret = crypto_register_alg(&sha256); + ret = crypto_register_shash(&sha256); if (ret < 0) - crypto_unregister_alg(&sha224); + crypto_unregister_shash(&sha224); return ret; } static void __exit sha256_generic_mod_fini(void) { - crypto_unregister_alg(&sha224); - crypto_unregister_alg(&sha256); + crypto_unregister_shash(&sha224); + crypto_unregister_shash(&sha256); } module_init(sha256_generic_mod_init); diff --git a/crypto/sha512_generic.c b/crypto/sha512_generic.c index bc3686138aebb2a5bd58a373e3aa7f24a71f6510..3bea38d12242d03e97d0159e3b6a6c5527559094 100644 --- a/crypto/sha512_generic.c +++ b/crypto/sha512_generic.c @@ -10,7 +10,7 @@ * later version. * */ - +#include #include #include #include @@ -18,16 +18,17 @@ #include #include #include - +#include #include struct sha512_ctx { u64 state[8]; u32 count[4]; u8 buf[128]; - u64 W[80]; }; +static DEFINE_PER_CPU(u64[80], msg_schedule); + static inline u64 Ch(u64 x, u64 y, u64 z) { return z ^ (x & (y ^ z)); @@ -89,11 +90,12 @@ static inline void BLEND_OP(int I, u64 *W) } static void -sha512_transform(u64 *state, u64 *W, const u8 *input) +sha512_transform(u64 *state, const u8 *input) { u64 a, b, c, d, e, f, g, h, t1, t2; int i; + u64 *W = get_cpu_var(msg_schedule); /* load the input */ for (i = 0; i < 16; i++) @@ -132,12 +134,14 @@ sha512_transform(u64 *state, u64 *W, const u8 *input) /* erase our data */ a = b = c = d = e = f = g = h = t1 = t2 = 0; + memset(W, 0, sizeof(__get_cpu_var(msg_schedule))); + put_cpu_var(msg_schedule); } -static void -sha512_init(struct crypto_tfm *tfm) +static int +sha512_init(struct shash_desc *desc) { - struct sha512_ctx *sctx = crypto_tfm_ctx(tfm); + struct sha512_ctx *sctx = shash_desc_ctx(desc); sctx->state[0] = SHA512_H0; sctx->state[1] = SHA512_H1; sctx->state[2] = SHA512_H2; @@ -147,12 +151,14 @@ sha512_init(struct crypto_tfm *tfm) sctx->state[6] = SHA512_H6; sctx->state[7] = SHA512_H7; sctx->count[0] = sctx->count[1] = sctx->count[2] = sctx->count[3] = 0; + + return 0; } -static void -sha384_init(struct crypto_tfm *tfm) +static int +sha384_init(struct shash_desc *desc) { - struct sha512_ctx *sctx = crypto_tfm_ctx(tfm); + struct sha512_ctx *sctx = shash_desc_ctx(desc); sctx->state[0] = SHA384_H0; sctx->state[1] = SHA384_H1; sctx->state[2] = SHA384_H2; @@ -162,12 +168,14 @@ sha384_init(struct crypto_tfm *tfm) sctx->state[6] = SHA384_H6; sctx->state[7] = SHA384_H7; sctx->count[0] = sctx->count[1] = sctx->count[2] = sctx->count[3] = 0; + + return 0; } -static void -sha512_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len) +static int +sha512_update(struct shash_desc *desc, const u8 *data, unsigned int len) { - struct sha512_ctx *sctx = crypto_tfm_ctx(tfm); + struct sha512_ctx *sctx = shash_desc_ctx(desc); unsigned int i, index, part_len; @@ -187,10 +195,10 @@ sha512_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len) /* Transform as many times as possible. */ if (len >= part_len) { memcpy(&sctx->buf[index], data, part_len); - sha512_transform(sctx->state, sctx->W, sctx->buf); + sha512_transform(sctx->state, sctx->buf); for (i = part_len; i + 127 < len; i+=128) - sha512_transform(sctx->state, sctx->W, &data[i]); + sha512_transform(sctx->state, &data[i]); index = 0; } else { @@ -200,14 +208,13 @@ sha512_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len) /* Buffer remaining input */ memcpy(&sctx->buf[index], &data[i], len - i); - /* erase our data */ - memset(sctx->W, 0, sizeof(sctx->W)); + return 0; } -static void -sha512_final(struct crypto_tfm *tfm, u8 *hash) +static int +sha512_final(struct shash_desc *desc, u8 *hash) { - struct sha512_ctx *sctx = crypto_tfm_ctx(tfm); + struct sha512_ctx *sctx = shash_desc_ctx(desc); static u8 padding[128] = { 0x80, }; __be64 *dst = (__be64 *)hash; __be32 bits[4]; @@ -223,10 +230,10 @@ sha512_final(struct crypto_tfm *tfm, u8 *hash) /* Pad out to 112 mod 128. */ index = (sctx->count[0] >> 3) & 0x7f; pad_len = (index < 112) ? (112 - index) : ((128+112) - index); - sha512_update(tfm, padding, pad_len); + sha512_update(desc, padding, pad_len); /* Append length (before padding) */ - sha512_update(tfm, (const u8 *)bits, sizeof(bits)); + sha512_update(desc, (const u8 *)bits, sizeof(bits)); /* Store state in digest */ for (i = 0; i < 8; i++) @@ -234,66 +241,66 @@ sha512_final(struct crypto_tfm *tfm, u8 *hash) /* Zeroize sensitive information. */ memset(sctx, 0, sizeof(struct sha512_ctx)); + + return 0; } -static void sha384_final(struct crypto_tfm *tfm, u8 *hash) +static int sha384_final(struct shash_desc *desc, u8 *hash) { - u8 D[64]; + u8 D[64]; + + sha512_final(desc, D); - sha512_final(tfm, D); + memcpy(hash, D, 48); + memset(D, 0, 64); - memcpy(hash, D, 48); - memset(D, 0, 64); + return 0; } -static struct crypto_alg sha512 = { - .cra_name = "sha512", - .cra_flags = CRYPTO_ALG_TYPE_DIGEST, - .cra_blocksize = SHA512_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct sha512_ctx), - .cra_module = THIS_MODULE, - .cra_alignmask = 3, - .cra_list = LIST_HEAD_INIT(sha512.cra_list), - .cra_u = { .digest = { - .dia_digestsize = SHA512_DIGEST_SIZE, - .dia_init = sha512_init, - .dia_update = sha512_update, - .dia_final = sha512_final } - } +static struct shash_alg sha512 = { + .digestsize = SHA512_DIGEST_SIZE, + .init = sha512_init, + .update = sha512_update, + .final = sha512_final, + .descsize = sizeof(struct sha512_ctx), + .base = { + .cra_name = "sha512", + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = SHA512_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } }; -static struct crypto_alg sha384 = { - .cra_name = "sha384", - .cra_flags = CRYPTO_ALG_TYPE_DIGEST, - .cra_blocksize = SHA384_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct sha512_ctx), - .cra_alignmask = 3, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(sha384.cra_list), - .cra_u = { .digest = { - .dia_digestsize = SHA384_DIGEST_SIZE, - .dia_init = sha384_init, - .dia_update = sha512_update, - .dia_final = sha384_final } - } +static struct shash_alg sha384 = { + .digestsize = SHA384_DIGEST_SIZE, + .init = sha384_init, + .update = sha512_update, + .final = sha384_final, + .descsize = sizeof(struct sha512_ctx), + .base = { + .cra_name = "sha384", + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = SHA384_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } }; static int __init sha512_generic_mod_init(void) { int ret = 0; - if ((ret = crypto_register_alg(&sha384)) < 0) + if ((ret = crypto_register_shash(&sha384)) < 0) goto out; - if ((ret = crypto_register_alg(&sha512)) < 0) - crypto_unregister_alg(&sha384); + if ((ret = crypto_register_shash(&sha512)) < 0) + crypto_unregister_shash(&sha384); out: return ret; } static void __exit sha512_generic_mod_fini(void) { - crypto_unregister_alg(&sha384); - crypto_unregister_alg(&sha512); + crypto_unregister_shash(&sha384); + crypto_unregister_shash(&sha512); } module_init(sha512_generic_mod_init); diff --git a/crypto/shash.c b/crypto/shash.c new file mode 100644 index 0000000000000000000000000000000000000000..c9df367332ffd1f122b1d675bcb434b936848bc4 --- /dev/null +++ b/crypto/shash.c @@ -0,0 +1,508 @@ +/* + * Synchronous Cryptographic Hash operations. + * + * Copyright (c) 2008 Herbert Xu + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +static const struct crypto_type crypto_shash_type; + +static inline struct crypto_shash *__crypto_shash_cast(struct crypto_tfm *tfm) +{ + return container_of(tfm, struct crypto_shash, base); +} + +#include "internal.h" + +static int shash_setkey_unaligned(struct crypto_shash *tfm, const u8 *key, + unsigned int keylen) +{ + struct shash_alg *shash = crypto_shash_alg(tfm); + unsigned long alignmask = crypto_shash_alignmask(tfm); + unsigned long absize; + u8 *buffer, *alignbuffer; + int err; + + absize = keylen + (alignmask & ~(CRYPTO_MINALIGN - 1)); + buffer = kmalloc(absize, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); + memcpy(alignbuffer, key, keylen); + err = shash->setkey(tfm, alignbuffer, keylen); + memset(alignbuffer, 0, keylen); + kfree(buffer); + return err; +} + +int crypto_shash_setkey(struct crypto_shash *tfm, const u8 *key, + unsigned int keylen) +{ + struct shash_alg *shash = crypto_shash_alg(tfm); + unsigned long alignmask = crypto_shash_alignmask(tfm); + + if (!shash->setkey) + return -ENOSYS; + + if ((unsigned long)key & alignmask) + return shash_setkey_unaligned(tfm, key, keylen); + + return shash->setkey(tfm, key, keylen); +} +EXPORT_SYMBOL_GPL(crypto_shash_setkey); + +static inline unsigned int shash_align_buffer_size(unsigned len, + unsigned long mask) +{ + return len + (mask & ~(__alignof__(u8 __attribute__ ((aligned))) - 1)); +} + +static int shash_update_unaligned(struct shash_desc *desc, const u8 *data, + unsigned int len) +{ + struct crypto_shash *tfm = desc->tfm; + struct shash_alg *shash = crypto_shash_alg(tfm); + unsigned long alignmask = crypto_shash_alignmask(tfm); + unsigned int unaligned_len = alignmask + 1 - + ((unsigned long)data & alignmask); + u8 buf[shash_align_buffer_size(unaligned_len, alignmask)] + __attribute__ ((aligned)); + + memcpy(buf, data, unaligned_len); + + return shash->update(desc, buf, unaligned_len) ?: + shash->update(desc, data + unaligned_len, len - unaligned_len); +} + +int crypto_shash_update(struct shash_desc *desc, const u8 *data, + unsigned int len) +{ + struct crypto_shash *tfm = desc->tfm; + struct shash_alg *shash = crypto_shash_alg(tfm); + unsigned long alignmask = crypto_shash_alignmask(tfm); + + if ((unsigned long)data & alignmask) + return shash_update_unaligned(desc, data, len); + + return shash->update(desc, data, len); +} +EXPORT_SYMBOL_GPL(crypto_shash_update); + +static int shash_final_unaligned(struct shash_desc *desc, u8 *out) +{ + struct crypto_shash *tfm = desc->tfm; + unsigned long alignmask = crypto_shash_alignmask(tfm); + struct shash_alg *shash = crypto_shash_alg(tfm); + unsigned int ds = crypto_shash_digestsize(tfm); + u8 buf[shash_align_buffer_size(ds, alignmask)] + __attribute__ ((aligned)); + int err; + + err = shash->final(desc, buf); + memcpy(out, buf, ds); + return err; +} + +int crypto_shash_final(struct shash_desc *desc, u8 *out) +{ + struct crypto_shash *tfm = desc->tfm; + struct shash_alg *shash = crypto_shash_alg(tfm); + unsigned long alignmask = crypto_shash_alignmask(tfm); + + if ((unsigned long)out & alignmask) + return shash_final_unaligned(desc, out); + + return shash->final(desc, out); +} +EXPORT_SYMBOL_GPL(crypto_shash_final); + +static int shash_finup_unaligned(struct shash_desc *desc, const u8 *data, + unsigned int len, u8 *out) +{ + return crypto_shash_update(desc, data, len) ?: + crypto_shash_final(desc, out); +} + +int crypto_shash_finup(struct shash_desc *desc, const u8 *data, + unsigned int len, u8 *out) +{ + struct crypto_shash *tfm = desc->tfm; + struct shash_alg *shash = crypto_shash_alg(tfm); + unsigned long alignmask = crypto_shash_alignmask(tfm); + + if (((unsigned long)data | (unsigned long)out) & alignmask || + !shash->finup) + return shash_finup_unaligned(desc, data, len, out); + + return shash->finup(desc, data, len, out); +} +EXPORT_SYMBOL_GPL(crypto_shash_finup); + +static int shash_digest_unaligned(struct shash_desc *desc, const u8 *data, + unsigned int len, u8 *out) +{ + return crypto_shash_init(desc) ?: + crypto_shash_update(desc, data, len) ?: + crypto_shash_final(desc, out); +} + +int crypto_shash_digest(struct shash_desc *desc, const u8 *data, + unsigned int len, u8 *out) +{ + struct crypto_shash *tfm = desc->tfm; + struct shash_alg *shash = crypto_shash_alg(tfm); + unsigned long alignmask = crypto_shash_alignmask(tfm); + + if (((unsigned long)data | (unsigned long)out) & alignmask || + !shash->digest) + return shash_digest_unaligned(desc, data, len, out); + + return shash->digest(desc, data, len, out); +} +EXPORT_SYMBOL_GPL(crypto_shash_digest); + +int crypto_shash_import(struct shash_desc *desc, const u8 *in) +{ + struct crypto_shash *tfm = desc->tfm; + struct shash_alg *alg = crypto_shash_alg(tfm); + + memcpy(shash_desc_ctx(desc), in, crypto_shash_descsize(tfm)); + + if (alg->reinit) + alg->reinit(desc); + + return 0; +} +EXPORT_SYMBOL_GPL(crypto_shash_import); + +static int shash_async_setkey(struct crypto_ahash *tfm, const u8 *key, + unsigned int keylen) +{ + struct crypto_shash **ctx = crypto_ahash_ctx(tfm); + + return crypto_shash_setkey(*ctx, key, keylen); +} + +static int shash_async_init(struct ahash_request *req) +{ + struct crypto_shash **ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req)); + struct shash_desc *desc = ahash_request_ctx(req); + + desc->tfm = *ctx; + desc->flags = req->base.flags; + + return crypto_shash_init(desc); +} + +static int shash_async_update(struct ahash_request *req) +{ + struct shash_desc *desc = ahash_request_ctx(req); + struct crypto_hash_walk walk; + int nbytes; + + for (nbytes = crypto_hash_walk_first(req, &walk); nbytes > 0; + nbytes = crypto_hash_walk_done(&walk, nbytes)) + nbytes = crypto_shash_update(desc, walk.data, nbytes); + + return nbytes; +} + +static int shash_async_final(struct ahash_request *req) +{ + return crypto_shash_final(ahash_request_ctx(req), req->result); +} + +static int shash_async_digest(struct ahash_request *req) +{ + struct scatterlist *sg = req->src; + unsigned int offset = sg->offset; + unsigned int nbytes = req->nbytes; + int err; + + if (nbytes < min(sg->length, ((unsigned int)(PAGE_SIZE)) - offset)) { + struct crypto_shash **ctx = + crypto_ahash_ctx(crypto_ahash_reqtfm(req)); + struct shash_desc *desc = ahash_request_ctx(req); + void *data; + + desc->tfm = *ctx; + desc->flags = req->base.flags; + + data = crypto_kmap(sg_page(sg), 0); + err = crypto_shash_digest(desc, data + offset, nbytes, + req->result); + crypto_kunmap(data, 0); + crypto_yield(desc->flags); + goto out; + } + + err = shash_async_init(req); + if (err) + goto out; + + err = shash_async_update(req); + if (err) + goto out; + + err = shash_async_final(req); + +out: + return err; +} + +static void crypto_exit_shash_ops_async(struct crypto_tfm *tfm) +{ + struct crypto_shash **ctx = crypto_tfm_ctx(tfm); + + crypto_free_shash(*ctx); +} + +static int crypto_init_shash_ops_async(struct crypto_tfm *tfm) +{ + struct crypto_alg *calg = tfm->__crt_alg; + struct shash_alg *alg = __crypto_shash_alg(calg); + struct ahash_tfm *crt = &tfm->crt_ahash; + struct crypto_shash **ctx = crypto_tfm_ctx(tfm); + struct crypto_shash *shash; + + if (!crypto_mod_get(calg)) + return -EAGAIN; + + shash = __crypto_shash_cast(crypto_create_tfm( + calg, &crypto_shash_type)); + if (IS_ERR(shash)) { + crypto_mod_put(calg); + return PTR_ERR(shash); + } + + *ctx = shash; + tfm->exit = crypto_exit_shash_ops_async; + + crt->init = shash_async_init; + crt->update = shash_async_update; + crt->final = shash_async_final; + crt->digest = shash_async_digest; + crt->setkey = shash_async_setkey; + + crt->digestsize = alg->digestsize; + crt->reqsize = sizeof(struct shash_desc) + crypto_shash_descsize(shash); + + return 0; +} + +static int shash_compat_setkey(struct crypto_hash *tfm, const u8 *key, + unsigned int keylen) +{ + struct shash_desc *desc = crypto_hash_ctx(tfm); + + return crypto_shash_setkey(desc->tfm, key, keylen); +} + +static int shash_compat_init(struct hash_desc *hdesc) +{ + struct shash_desc *desc = crypto_hash_ctx(hdesc->tfm); + + desc->flags = hdesc->flags; + + return crypto_shash_init(desc); +} + +static int shash_compat_update(struct hash_desc *hdesc, struct scatterlist *sg, + unsigned int len) +{ + struct shash_desc *desc = crypto_hash_ctx(hdesc->tfm); + struct crypto_hash_walk walk; + int nbytes; + + for (nbytes = crypto_hash_walk_first_compat(hdesc, &walk, sg, len); + nbytes > 0; nbytes = crypto_hash_walk_done(&walk, nbytes)) + nbytes = crypto_shash_update(desc, walk.data, nbytes); + + return nbytes; +} + +static int shash_compat_final(struct hash_desc *hdesc, u8 *out) +{ + return crypto_shash_final(crypto_hash_ctx(hdesc->tfm), out); +} + +static int shash_compat_digest(struct hash_desc *hdesc, struct scatterlist *sg, + unsigned int nbytes, u8 *out) +{ + unsigned int offset = sg->offset; + int err; + + if (nbytes < min(sg->length, ((unsigned int)(PAGE_SIZE)) - offset)) { + struct shash_desc *desc = crypto_hash_ctx(hdesc->tfm); + void *data; + + desc->flags = hdesc->flags; + + data = crypto_kmap(sg_page(sg), 0); + err = crypto_shash_digest(desc, data + offset, nbytes, out); + crypto_kunmap(data, 0); + crypto_yield(desc->flags); + goto out; + } + + err = shash_compat_init(hdesc); + if (err) + goto out; + + err = shash_compat_update(hdesc, sg, nbytes); + if (err) + goto out; + + err = shash_compat_final(hdesc, out); + +out: + return err; +} + +static void crypto_exit_shash_ops_compat(struct crypto_tfm *tfm) +{ + struct shash_desc *desc= crypto_tfm_ctx(tfm); + + crypto_free_shash(desc->tfm); +} + +static int crypto_init_shash_ops_compat(struct crypto_tfm *tfm) +{ + struct hash_tfm *crt = &tfm->crt_hash; + struct crypto_alg *calg = tfm->__crt_alg; + struct shash_alg *alg = __crypto_shash_alg(calg); + struct shash_desc *desc = crypto_tfm_ctx(tfm); + struct crypto_shash *shash; + + shash = __crypto_shash_cast(crypto_create_tfm( + calg, &crypto_shash_type)); + if (IS_ERR(shash)) + return PTR_ERR(shash); + + desc->tfm = shash; + tfm->exit = crypto_exit_shash_ops_compat; + + crt->init = shash_compat_init; + crt->update = shash_compat_update; + crt->final = shash_compat_final; + crt->digest = shash_compat_digest; + crt->setkey = shash_compat_setkey; + + crt->digestsize = alg->digestsize; + + return 0; +} + +static int crypto_init_shash_ops(struct crypto_tfm *tfm, u32 type, u32 mask) +{ + switch (mask & CRYPTO_ALG_TYPE_MASK) { + case CRYPTO_ALG_TYPE_HASH_MASK: + return crypto_init_shash_ops_compat(tfm); + case CRYPTO_ALG_TYPE_AHASH_MASK: + return crypto_init_shash_ops_async(tfm); + } + + return -EINVAL; +} + +static unsigned int crypto_shash_ctxsize(struct crypto_alg *alg, u32 type, + u32 mask) +{ + struct shash_alg *salg = __crypto_shash_alg(alg); + + switch (mask & CRYPTO_ALG_TYPE_MASK) { + case CRYPTO_ALG_TYPE_HASH_MASK: + return sizeof(struct shash_desc) + salg->descsize; + case CRYPTO_ALG_TYPE_AHASH_MASK: + return sizeof(struct crypto_shash *); + } + + return 0; +} + +static int crypto_shash_init_tfm(struct crypto_tfm *tfm, + const struct crypto_type *frontend) +{ + if (frontend->type != CRYPTO_ALG_TYPE_SHASH) + return -EINVAL; + return 0; +} + +static unsigned int crypto_shash_extsize(struct crypto_alg *alg, + const struct crypto_type *frontend) +{ + return alg->cra_ctxsize; +} + +static void crypto_shash_show(struct seq_file *m, struct crypto_alg *alg) + __attribute__ ((unused)); +static void crypto_shash_show(struct seq_file *m, struct crypto_alg *alg) +{ + struct shash_alg *salg = __crypto_shash_alg(alg); + + seq_printf(m, "type : shash\n"); + seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); + seq_printf(m, "digestsize : %u\n", salg->digestsize); + seq_printf(m, "descsize : %u\n", salg->descsize); +} + +static const struct crypto_type crypto_shash_type = { + .ctxsize = crypto_shash_ctxsize, + .extsize = crypto_shash_extsize, + .init = crypto_init_shash_ops, + .init_tfm = crypto_shash_init_tfm, +#ifdef CONFIG_PROC_FS + .show = crypto_shash_show, +#endif + .maskclear = ~CRYPTO_ALG_TYPE_MASK, + .maskset = CRYPTO_ALG_TYPE_MASK, + .type = CRYPTO_ALG_TYPE_SHASH, + .tfmsize = offsetof(struct crypto_shash, base), +}; + +struct crypto_shash *crypto_alloc_shash(const char *alg_name, u32 type, + u32 mask) +{ + return __crypto_shash_cast( + crypto_alloc_tfm(alg_name, &crypto_shash_type, type, mask)); +} +EXPORT_SYMBOL_GPL(crypto_alloc_shash); + +int crypto_register_shash(struct shash_alg *alg) +{ + struct crypto_alg *base = &alg->base; + + if (alg->digestsize > PAGE_SIZE / 8 || + alg->descsize > PAGE_SIZE / 8) + return -EINVAL; + + base->cra_type = &crypto_shash_type; + base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; + base->cra_flags |= CRYPTO_ALG_TYPE_SHASH; + + return crypto_register_alg(base); +} +EXPORT_SYMBOL_GPL(crypto_register_shash); + +int crypto_unregister_shash(struct shash_alg *alg) +{ + return crypto_unregister_alg(&alg->base); +} +EXPORT_SYMBOL_GPL(crypto_unregister_shash); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Synchronous cryptographic hash type"); diff --git a/crypto/testmgr.c b/crypto/testmgr.c index b828c6cf1b1d2d7179cfaaac3f0a3aa2e79f8749..a75f11ffb957257d15d67b7eecf55c666466b0f5 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -843,6 +843,14 @@ static int test_comp(struct crypto_comp *tfm, struct comp_testvec *ctemplate, goto out; } + if (dlen != ctemplate[i].outlen) { + printk(KERN_ERR "alg: comp: Compression test %d " + "failed for %s: output len = %d\n", i + 1, algo, + dlen); + ret = -EINVAL; + goto out; + } + if (memcmp(result, ctemplate[i].output, dlen)) { printk(KERN_ERR "alg: comp: Compression test %d " "failed for %s\n", i + 1, algo); @@ -853,7 +861,7 @@ static int test_comp(struct crypto_comp *tfm, struct comp_testvec *ctemplate, } for (i = 0; i < dtcount; i++) { - int ilen, ret, dlen = COMP_BUF_SIZE; + int ilen, dlen = COMP_BUF_SIZE; memset(result, 0, sizeof (result)); @@ -867,6 +875,14 @@ static int test_comp(struct crypto_comp *tfm, struct comp_testvec *ctemplate, goto out; } + if (dlen != dtemplate[i].outlen) { + printk(KERN_ERR "alg: comp: Decompression test %d " + "failed for %s: output len = %d\n", i + 1, algo, + dlen); + ret = -EINVAL; + goto out; + } + if (memcmp(result, dtemplate[i].output, dlen)) { printk(KERN_ERR "alg: comp: Decompression test %d " "failed for %s\n", i + 1, algo); @@ -1010,6 +1026,55 @@ static int alg_test_hash(const struct alg_test_desc *desc, const char *driver, return err; } +static int alg_test_crc32c(const struct alg_test_desc *desc, + const char *driver, u32 type, u32 mask) +{ + struct crypto_shash *tfm; + u32 val; + int err; + + err = alg_test_hash(desc, driver, type, mask); + if (err) + goto out; + + tfm = crypto_alloc_shash(driver, type, mask); + if (IS_ERR(tfm)) { + printk(KERN_ERR "alg: crc32c: Failed to load transform for %s: " + "%ld\n", driver, PTR_ERR(tfm)); + err = PTR_ERR(tfm); + goto out; + } + + do { + struct { + struct shash_desc shash; + char ctx[crypto_shash_descsize(tfm)]; + } sdesc; + + sdesc.shash.tfm = tfm; + sdesc.shash.flags = 0; + + *(u32 *)sdesc.ctx = le32_to_cpu(420553207); + err = crypto_shash_final(&sdesc.shash, (u8 *)&val); + if (err) { + printk(KERN_ERR "alg: crc32c: Operation failed for " + "%s: %d\n", driver, err); + break; + } + + if (val != ~420553207) { + printk(KERN_ERR "alg: crc32c: Test failed for %s: " + "%d\n", driver, val); + err = -EINVAL; + } + } while (0); + + crypto_free_shash(tfm); + +out: + return err; +} + /* Please keep this list sorted by algorithm name. */ static const struct alg_test_desc alg_test_descs[] = { { @@ -1134,7 +1199,7 @@ static const struct alg_test_desc alg_test_descs[] = { } }, { .alg = "crc32c", - .test = alg_test_hash, + .test = alg_test_crc32c, .suite = { .hash = { .vecs = crc32c_tv_template, @@ -1801,6 +1866,7 @@ static int alg_find_test(const char *alg) int alg_test(const char *driver, const char *alg, u32 type, u32 mask) { int i; + int rc; if ((type & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_CIPHER) { char nalg[CRYPTO_MAX_ALG_NAME]; @@ -1820,8 +1886,12 @@ int alg_test(const char *driver, const char *alg, u32 type, u32 mask) if (i < 0) goto notest; - return alg_test_descs[i].test(alg_test_descs + i, driver, + rc = alg_test_descs[i].test(alg_test_descs + i, driver, type, mask); + if (fips_enabled && rc) + panic("%s: %s alg self test failed in fips mode!\n", driver, alg); + + return rc; notest: printk(KERN_INFO "alg: No test for %s (%s)\n", alg, driver); diff --git a/crypto/testmgr.h b/crypto/testmgr.h index dee94d9ecfba5e3724d37ebc844bd1219aba587d..132953e144d34bcb0766f4eebfce32107c7a489b 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -8349,7 +8349,7 @@ struct comp_testvec { /* * Deflate test vectors (null-terminated strings). - * Params: winbits=11, Z_DEFAULT_COMPRESSION, MAX_MEM_LEVEL. + * Params: winbits=-11, Z_DEFAULT_COMPRESSION, MAX_MEM_LEVEL. */ #define DEFLATE_COMP_TEST_VECTORS 2 #define DEFLATE_DECOMP_TEST_VECTORS 2 diff --git a/crypto/tgr192.c b/crypto/tgr192.c index a92414f24bebd2e5a65a40491d98501757971f83..cbca4f208c9f40017c8ff69c27c52f34862904fd 100644 --- a/crypto/tgr192.c +++ b/crypto/tgr192.c @@ -21,11 +21,11 @@ * (at your option) any later version. * */ +#include #include #include #include #include -#include #include #define TGR192_DIGEST_SIZE 24 @@ -495,24 +495,26 @@ static void tgr192_transform(struct tgr192_ctx *tctx, const u8 * data) tctx->c = c; } -static void tgr192_init(struct crypto_tfm *tfm) +static int tgr192_init(struct shash_desc *desc) { - struct tgr192_ctx *tctx = crypto_tfm_ctx(tfm); + struct tgr192_ctx *tctx = shash_desc_ctx(desc); tctx->a = 0x0123456789abcdefULL; tctx->b = 0xfedcba9876543210ULL; tctx->c = 0xf096a5b4c3b2e187ULL; tctx->nblocks = 0; tctx->count = 0; + + return 0; } /* Update the message digest with the contents * of INBUF with length INLEN. */ -static void tgr192_update(struct crypto_tfm *tfm, const u8 *inbuf, +static int tgr192_update(struct shash_desc *desc, const u8 *inbuf, unsigned int len) { - struct tgr192_ctx *tctx = crypto_tfm_ctx(tfm); + struct tgr192_ctx *tctx = shash_desc_ctx(desc); if (tctx->count == 64) { /* flush the buffer */ tgr192_transform(tctx, tctx->hash); @@ -520,15 +522,15 @@ static void tgr192_update(struct crypto_tfm *tfm, const u8 *inbuf, tctx->nblocks++; } if (!inbuf) { - return; + return 0; } if (tctx->count) { for (; len && tctx->count < 64; len--) { tctx->hash[tctx->count++] = *inbuf++; } - tgr192_update(tfm, NULL, 0); + tgr192_update(desc, NULL, 0); if (!len) { - return; + return 0; } } @@ -543,20 +545,22 @@ static void tgr192_update(struct crypto_tfm *tfm, const u8 *inbuf, for (; len && tctx->count < 64; len--) { tctx->hash[tctx->count++] = *inbuf++; } + + return 0; } /* The routine terminates the computation */ -static void tgr192_final(struct crypto_tfm *tfm, u8 * out) +static int tgr192_final(struct shash_desc *desc, u8 * out) { - struct tgr192_ctx *tctx = crypto_tfm_ctx(tfm); + struct tgr192_ctx *tctx = shash_desc_ctx(desc); __be64 *dst = (__be64 *)out; __be64 *be64p; __le32 *le32p; u32 t, msb, lsb; - tgr192_update(tfm, NULL, 0); /* flush */ ; + tgr192_update(desc, NULL, 0); /* flush */ ; msb = 0; t = tctx->nblocks; @@ -584,7 +588,7 @@ static void tgr192_final(struct crypto_tfm *tfm, u8 * out) while (tctx->count < 64) { tctx->hash[tctx->count++] = 0; } - tgr192_update(tfm, NULL, 0); /* flush */ ; + tgr192_update(desc, NULL, 0); /* flush */ ; memset(tctx->hash, 0, 56); /* fill next block with zeroes */ } /* append the 64 bit count */ @@ -598,91 +602,94 @@ static void tgr192_final(struct crypto_tfm *tfm, u8 * out) dst[0] = be64p[0] = cpu_to_be64(tctx->a); dst[1] = be64p[1] = cpu_to_be64(tctx->b); dst[2] = be64p[2] = cpu_to_be64(tctx->c); + + return 0; } -static void tgr160_final(struct crypto_tfm *tfm, u8 * out) +static int tgr160_final(struct shash_desc *desc, u8 * out) { u8 D[64]; - tgr192_final(tfm, D); + tgr192_final(desc, D); memcpy(out, D, TGR160_DIGEST_SIZE); memset(D, 0, TGR192_DIGEST_SIZE); + + return 0; } -static void tgr128_final(struct crypto_tfm *tfm, u8 * out) +static int tgr128_final(struct shash_desc *desc, u8 * out) { u8 D[64]; - tgr192_final(tfm, D); + tgr192_final(desc, D); memcpy(out, D, TGR128_DIGEST_SIZE); memset(D, 0, TGR192_DIGEST_SIZE); + + return 0; } -static struct crypto_alg tgr192 = { - .cra_name = "tgr192", - .cra_flags = CRYPTO_ALG_TYPE_DIGEST, - .cra_blocksize = TGR192_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct tgr192_ctx), - .cra_module = THIS_MODULE, - .cra_alignmask = 7, - .cra_list = LIST_HEAD_INIT(tgr192.cra_list), - .cra_u = {.digest = { - .dia_digestsize = TGR192_DIGEST_SIZE, - .dia_init = tgr192_init, - .dia_update = tgr192_update, - .dia_final = tgr192_final}} +static struct shash_alg tgr192 = { + .digestsize = TGR192_DIGEST_SIZE, + .init = tgr192_init, + .update = tgr192_update, + .final = tgr192_final, + .descsize = sizeof(struct tgr192_ctx), + .base = { + .cra_name = "tgr192", + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = TGR192_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } }; -static struct crypto_alg tgr160 = { - .cra_name = "tgr160", - .cra_flags = CRYPTO_ALG_TYPE_DIGEST, - .cra_blocksize = TGR192_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct tgr192_ctx), - .cra_module = THIS_MODULE, - .cra_alignmask = 7, - .cra_list = LIST_HEAD_INIT(tgr160.cra_list), - .cra_u = {.digest = { - .dia_digestsize = TGR160_DIGEST_SIZE, - .dia_init = tgr192_init, - .dia_update = tgr192_update, - .dia_final = tgr160_final}} +static struct shash_alg tgr160 = { + .digestsize = TGR160_DIGEST_SIZE, + .init = tgr192_init, + .update = tgr192_update, + .final = tgr160_final, + .descsize = sizeof(struct tgr192_ctx), + .base = { + .cra_name = "tgr160", + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = TGR192_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } }; -static struct crypto_alg tgr128 = { - .cra_name = "tgr128", - .cra_flags = CRYPTO_ALG_TYPE_DIGEST, - .cra_blocksize = TGR192_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct tgr192_ctx), - .cra_module = THIS_MODULE, - .cra_alignmask = 7, - .cra_list = LIST_HEAD_INIT(tgr128.cra_list), - .cra_u = {.digest = { - .dia_digestsize = TGR128_DIGEST_SIZE, - .dia_init = tgr192_init, - .dia_update = tgr192_update, - .dia_final = tgr128_final}} +static struct shash_alg tgr128 = { + .digestsize = TGR128_DIGEST_SIZE, + .init = tgr192_init, + .update = tgr192_update, + .final = tgr128_final, + .descsize = sizeof(struct tgr192_ctx), + .base = { + .cra_name = "tgr128", + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = TGR192_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } }; static int __init tgr192_mod_init(void) { int ret = 0; - ret = crypto_register_alg(&tgr192); + ret = crypto_register_shash(&tgr192); if (ret < 0) { goto out; } - ret = crypto_register_alg(&tgr160); + ret = crypto_register_shash(&tgr160); if (ret < 0) { - crypto_unregister_alg(&tgr192); + crypto_unregister_shash(&tgr192); goto out; } - ret = crypto_register_alg(&tgr128); + ret = crypto_register_shash(&tgr128); if (ret < 0) { - crypto_unregister_alg(&tgr192); - crypto_unregister_alg(&tgr160); + crypto_unregister_shash(&tgr192); + crypto_unregister_shash(&tgr160); } out: return ret; @@ -690,9 +697,9 @@ static int __init tgr192_mod_init(void) static void __exit tgr192_mod_fini(void) { - crypto_unregister_alg(&tgr192); - crypto_unregister_alg(&tgr160); - crypto_unregister_alg(&tgr128); + crypto_unregister_shash(&tgr192); + crypto_unregister_shash(&tgr160); + crypto_unregister_shash(&tgr128); } MODULE_ALIAS("tgr160"); diff --git a/crypto/wp512.c b/crypto/wp512.c index bff28560d66d8de4ce54c7c40f9fba604ecee29d..723427273687011b3c4e8fd995e1ec8d1f6546d8 100644 --- a/crypto/wp512.c +++ b/crypto/wp512.c @@ -19,11 +19,11 @@ * (at your option) any later version. * */ +#include #include #include #include #include -#include #include #define WP512_DIGEST_SIZE 64 @@ -980,8 +980,8 @@ static void wp512_process_buffer(struct wp512_ctx *wctx) { } -static void wp512_init(struct crypto_tfm *tfm) { - struct wp512_ctx *wctx = crypto_tfm_ctx(tfm); +static int wp512_init(struct shash_desc *desc) { + struct wp512_ctx *wctx = shash_desc_ctx(desc); int i; memset(wctx->bitLength, 0, 32); @@ -990,12 +990,14 @@ static void wp512_init(struct crypto_tfm *tfm) { for (i = 0; i < 8; i++) { wctx->hash[i] = 0L; } + + return 0; } -static void wp512_update(struct crypto_tfm *tfm, const u8 *source, +static int wp512_update(struct shash_desc *desc, const u8 *source, unsigned int len) { - struct wp512_ctx *wctx = crypto_tfm_ctx(tfm); + struct wp512_ctx *wctx = shash_desc_ctx(desc); int sourcePos = 0; unsigned int bits_len = len * 8; // convert to number of bits int sourceGap = (8 - ((int)bits_len & 7)) & 7; @@ -1051,11 +1053,12 @@ static void wp512_update(struct crypto_tfm *tfm, const u8 *source, wctx->bufferBits = bufferBits; wctx->bufferPos = bufferPos; + return 0; } -static void wp512_final(struct crypto_tfm *tfm, u8 *out) +static int wp512_final(struct shash_desc *desc, u8 *out) { - struct wp512_ctx *wctx = crypto_tfm_ctx(tfm); + struct wp512_ctx *wctx = shash_desc_ctx(desc); int i; u8 *buffer = wctx->buffer; u8 *bitLength = wctx->bitLength; @@ -1084,89 +1087,95 @@ static void wp512_final(struct crypto_tfm *tfm, u8 *out) digest[i] = cpu_to_be64(wctx->hash[i]); wctx->bufferBits = bufferBits; wctx->bufferPos = bufferPos; + + return 0; } -static void wp384_final(struct crypto_tfm *tfm, u8 *out) +static int wp384_final(struct shash_desc *desc, u8 *out) { u8 D[64]; - wp512_final(tfm, D); + wp512_final(desc, D); memcpy (out, D, WP384_DIGEST_SIZE); memset (D, 0, WP512_DIGEST_SIZE); + + return 0; } -static void wp256_final(struct crypto_tfm *tfm, u8 *out) +static int wp256_final(struct shash_desc *desc, u8 *out) { u8 D[64]; - wp512_final(tfm, D); + wp512_final(desc, D); memcpy (out, D, WP256_DIGEST_SIZE); memset (D, 0, WP512_DIGEST_SIZE); + + return 0; } -static struct crypto_alg wp512 = { - .cra_name = "wp512", - .cra_flags = CRYPTO_ALG_TYPE_DIGEST, - .cra_blocksize = WP512_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct wp512_ctx), - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(wp512.cra_list), - .cra_u = { .digest = { - .dia_digestsize = WP512_DIGEST_SIZE, - .dia_init = wp512_init, - .dia_update = wp512_update, - .dia_final = wp512_final } } +static struct shash_alg wp512 = { + .digestsize = WP512_DIGEST_SIZE, + .init = wp512_init, + .update = wp512_update, + .final = wp512_final, + .descsize = sizeof(struct wp512_ctx), + .base = { + .cra_name = "wp512", + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = WP512_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } }; -static struct crypto_alg wp384 = { - .cra_name = "wp384", - .cra_flags = CRYPTO_ALG_TYPE_DIGEST, - .cra_blocksize = WP512_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct wp512_ctx), - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(wp384.cra_list), - .cra_u = { .digest = { - .dia_digestsize = WP384_DIGEST_SIZE, - .dia_init = wp512_init, - .dia_update = wp512_update, - .dia_final = wp384_final } } +static struct shash_alg wp384 = { + .digestsize = WP384_DIGEST_SIZE, + .init = wp512_init, + .update = wp512_update, + .final = wp384_final, + .descsize = sizeof(struct wp512_ctx), + .base = { + .cra_name = "wp384", + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = WP512_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } }; -static struct crypto_alg wp256 = { - .cra_name = "wp256", - .cra_flags = CRYPTO_ALG_TYPE_DIGEST, - .cra_blocksize = WP512_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct wp512_ctx), - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(wp256.cra_list), - .cra_u = { .digest = { - .dia_digestsize = WP256_DIGEST_SIZE, - .dia_init = wp512_init, - .dia_update = wp512_update, - .dia_final = wp256_final } } +static struct shash_alg wp256 = { + .digestsize = WP256_DIGEST_SIZE, + .init = wp512_init, + .update = wp512_update, + .final = wp256_final, + .descsize = sizeof(struct wp512_ctx), + .base = { + .cra_name = "wp256", + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = WP512_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } }; static int __init wp512_mod_init(void) { int ret = 0; - ret = crypto_register_alg(&wp512); + ret = crypto_register_shash(&wp512); if (ret < 0) goto out; - ret = crypto_register_alg(&wp384); + ret = crypto_register_shash(&wp384); if (ret < 0) { - crypto_unregister_alg(&wp512); + crypto_unregister_shash(&wp512); goto out; } - ret = crypto_register_alg(&wp256); + ret = crypto_register_shash(&wp256); if (ret < 0) { - crypto_unregister_alg(&wp512); - crypto_unregister_alg(&wp384); + crypto_unregister_shash(&wp512); + crypto_unregister_shash(&wp384); } out: return ret; @@ -1174,9 +1183,9 @@ static int __init wp512_mod_init(void) static void __exit wp512_mod_fini(void) { - crypto_unregister_alg(&wp512); - crypto_unregister_alg(&wp384); - crypto_unregister_alg(&wp256); + crypto_unregister_shash(&wp512); + crypto_unregister_shash(&wp384); + crypto_unregister_shash(&wp256); } MODULE_ALIAS("wp384"); diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 7edf6d913c1318fded1fd4cf6a448b2f799a0849..765fd1c56cd66bc445ab5228f562177b9eb469e1 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -688,14 +688,6 @@ void __init acpi_early_init(void) if (acpi_disabled) return; - /* - * ACPI CA initializes acpi_dbg_level to non-zero, which means - * we get debug output merely by turning on CONFIG_ACPI_DEBUG. - * Turn it off so we don't get output unless the user specifies - * acpi.debug_level. - */ - acpi_dbg_level = 0; - printk(KERN_INFO PREFIX "Core revision %08x\n", ACPI_CA_VERSION); /* enable workarounds, unless strict ACPI spec. compliance */ diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index 11acaee14d66ddb1752f9432107f46bf0fc1b146..bf79d83bdfbbbade9a942a297e90b0223eef5946 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -384,6 +384,27 @@ acpi_pci_free_irq(struct acpi_prt_entry *entry, return irq; } +#ifdef CONFIG_X86_IO_APIC +extern int noioapicquirk; + +static int bridge_has_boot_interrupt_variant(struct pci_bus *bus) +{ + struct pci_bus *bus_it; + + for (bus_it = bus ; bus_it ; bus_it = bus_it->parent) { + if (!bus_it->self) + return 0; + + printk(KERN_INFO "vendor=%04x device=%04x\n", bus_it->self->vendor, + bus_it->self->device); + + if (bus_it->self->irq_reroute_variant) + return bus_it->self->irq_reroute_variant; + } + return 0; +} +#endif /* CONFIG_X86_IO_APIC */ + /* * acpi_pci_irq_lookup * success: return IRQ >= 0 @@ -413,6 +434,41 @@ acpi_pci_irq_lookup(struct pci_bus *bus, } ret = func(entry, triggering, polarity, link); + +#ifdef CONFIG_X86_IO_APIC + /* + * Some chipsets (e.g. intel 6700PXH) generate a legacy INTx when the + * IRQ entry in the chipset's IO-APIC is masked (as, e.g. the RT kernel + * does during interrupt handling). When this INTx generation cannot be + * disabled, we reroute these interrupts to their legacy equivalent to + * get rid of spurious interrupts. + */ + if (!noioapicquirk) { + switch (bridge_has_boot_interrupt_variant(bus)) { + case 0: + /* no rerouting necessary */ + break; + + case INTEL_IRQ_REROUTE_VARIANT: + /* + * Remap according to INTx routing table in 6700PXH + * specs, intel order number 302628-002, section + * 2.15.2. Other chipsets (80332, ...) have the same + * mapping and are handled here as well. + */ + printk(KERN_INFO "pci irq %d -> rerouted to legacy " + "irq %d\n", ret, (ret % 4) + 16); + ret = (ret % 4) + 16; + break; + + default: + printk(KERN_INFO "not rerouting irq %d to legacy irq: " + "unknown mapping\n", ret); + break; + } + } +#endif /* CONFIG_X86_IO_APIC */ + return ret; } diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 5f8d746a9b8198e516321ccdaaa8c5a1486b39b7..38aca048e9515a6f0be0b36f6db9475cbaa889b3 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -374,15 +374,15 @@ static int tsc_halts_in_c(int state) { switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: + case X86_VENDOR_INTEL: /* * AMD Fam10h TSC will tick in all * C/P/S0/S1 states when this bit is set. */ - if (boot_cpu_has(X86_FEATURE_CONSTANT_TSC)) + if (boot_cpu_has(X86_FEATURE_NONSTOP_TSC)) return 0; + /*FALL THROUGH*/ - case X86_VENDOR_INTEL: - /* Several cases known where TSC halts in C2 too */ default: return state > ACPI_STATE_C1; } diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c index 670551b95e56e44fecfc075d9cbd5255a2aebc55..17ed5ac840f7be1d65c37acb967a29e4e9bc4965 100644 --- a/drivers/acpi/utilities/utglobal.c +++ b/drivers/acpi/utilities/utglobal.c @@ -64,7 +64,7 @@ u32 acpi_dbg_level = ACPI_DEBUG_DEFAULT; /* Debug switch - layer (component) mask */ -u32 acpi_dbg_layer = ACPI_COMPONENT_DEFAULT | ACPI_ALL_DRIVERS; +u32 acpi_dbg_layer = 0; u32 acpi_gbl_nesting_level = 0; /* Debugger globals */ diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 421b7c71e72db447a7c3b09abe183908399ac34a..1a7be96d627b3224eaf5bf34ec8da4059ef61f6d 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -456,7 +456,8 @@ config PATA_MARVELL config PATA_MPC52xx tristate "Freescale MPC52xx SoC internal IDE" - depends on PPC_MPC52xx + depends on PPC_MPC52xx && PPC_BESTCOMM + select PPC_BESTCOMM_ATA help This option enables support for integrated IDE controller of the Freescale MPC52xx SoC. diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c index a9e827356d0681bfd4c64bf8bf6e02bb32513318..50ae6d13078aeb122dfe0595d57ebd865a857e04 100644 --- a/drivers/ata/pata_mpc52xx.c +++ b/drivers/ata/pata_mpc52xx.c @@ -6,6 +6,9 @@ * Copyright (C) 2006 Sylvain Munaut * Copyright (C) 2003 Mipsys - Benjamin Herrenschmidt * + * UDMA support based on patches by Freescale (Bernard Kuhn, John Rigby), + * Domen Puncer and Tim Yamin. + * * This file is licensed under the terms of the GNU General Public License * version 2. This program is licensed "as is" without any warranty of any * kind, whether express or implied. @@ -17,28 +20,46 @@ #include #include #include +#include -#include +#include #include #include +#include +#include +#include #define DRV_NAME "mpc52xx_ata" -#define DRV_VERSION "0.1.2" - /* Private structures used by the driver */ struct mpc52xx_ata_timings { u32 pio1; u32 pio2; + u32 mdma1; + u32 mdma2; + u32 udma1; + u32 udma2; + u32 udma3; + u32 udma4; + u32 udma5; + int using_udma; }; struct mpc52xx_ata_priv { unsigned int ipb_period; - struct mpc52xx_ata __iomem * ata_regs; + struct mpc52xx_ata __iomem *ata_regs; + phys_addr_t ata_regs_pa; int ata_irq; struct mpc52xx_ata_timings timings[2]; int csel; + + /* DMA */ + struct bcom_task *dmatsk; + const struct udmaspec *udmaspec; + const struct mdmaspec *mdmaspec; + int mpc52xx_ata_dma_last_write; + int waiting_for_dma; }; @@ -53,6 +74,107 @@ static const int ataspec_ta[5] = { 35, 35, 35, 35, 35}; #define CALC_CLKCYC(c,v) ((((v)+(c)-1)/(c))) +/* ======================================================================== */ + +/* ATAPI-4 MDMA specs (in clocks) */ +struct mdmaspec { + u32 t0M; + u32 td; + u32 th; + u32 tj; + u32 tkw; + u32 tm; + u32 tn; +}; + +static const struct mdmaspec mdmaspec66[3] = { + { .t0M = 32, .td = 15, .th = 2, .tj = 2, .tkw = 15, .tm = 4, .tn = 1 }, + { .t0M = 10, .td = 6, .th = 1, .tj = 1, .tkw = 4, .tm = 2, .tn = 1 }, + { .t0M = 8, .td = 5, .th = 1, .tj = 1, .tkw = 2, .tm = 2, .tn = 1 }, +}; + +static const struct mdmaspec mdmaspec132[3] = { + { .t0M = 64, .td = 29, .th = 3, .tj = 3, .tkw = 29, .tm = 7, .tn = 2 }, + { .t0M = 20, .td = 11, .th = 2, .tj = 1, .tkw = 7, .tm = 4, .tn = 1 }, + { .t0M = 16, .td = 10, .th = 2, .tj = 1, .tkw = 4, .tm = 4, .tn = 1 }, +}; + +/* ATAPI-4 UDMA specs (in clocks) */ +struct udmaspec { + u32 tcyc; + u32 t2cyc; + u32 tds; + u32 tdh; + u32 tdvs; + u32 tdvh; + u32 tfs; + u32 tli; + u32 tmli; + u32 taz; + u32 tzah; + u32 tenv; + u32 tsr; + u32 trfs; + u32 trp; + u32 tack; + u32 tss; +}; + +static const struct udmaspec udmaspec66[6] = { + { .tcyc = 8, .t2cyc = 16, .tds = 1, .tdh = 1, .tdvs = 5, .tdvh = 1, + .tfs = 16, .tli = 10, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2, + .tsr = 3, .trfs = 5, .trp = 11, .tack = 2, .tss = 4, + }, + { .tcyc = 5, .t2cyc = 11, .tds = 1, .tdh = 1, .tdvs = 4, .tdvh = 1, + .tfs = 14, .tli = 10, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2, + .tsr = 2, .trfs = 5, .trp = 9, .tack = 2, .tss = 4, + }, + { .tcyc = 4, .t2cyc = 8, .tds = 1, .tdh = 1, .tdvs = 3, .tdvh = 1, + .tfs = 12, .tli = 10, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2, + .tsr = 2, .trfs = 4, .trp = 7, .tack = 2, .tss = 4, + }, + { .tcyc = 3, .t2cyc = 6, .tds = 1, .tdh = 1, .tdvs = 2, .tdvh = 1, + .tfs = 9, .tli = 7, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2, + .tsr = 2, .trfs = 4, .trp = 7, .tack = 2, .tss = 4, + }, + { .tcyc = 2, .t2cyc = 4, .tds = 1, .tdh = 1, .tdvs = 1, .tdvh = 1, + .tfs = 8, .tli = 8, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2, + .tsr = 2, .trfs = 4, .trp = 7, .tack = 2, .tss = 4, + }, + { .tcyc = 2, .t2cyc = 2, .tds = 1, .tdh = 1, .tdvs = 1, .tdvh = 1, + .tfs = 6, .tli = 5, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2, + .tsr = 2, .trfs = 4, .trp = 6, .tack = 2, .tss = 4, + }, +}; + +static const struct udmaspec udmaspec132[6] = { + { .tcyc = 15, .t2cyc = 31, .tds = 2, .tdh = 1, .tdvs = 10, .tdvh = 1, + .tfs = 30, .tli = 20, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3, + .tsr = 7, .trfs = 10, .trp = 22, .tack = 3, .tss = 7, + }, + { .tcyc = 10, .t2cyc = 21, .tds = 2, .tdh = 1, .tdvs = 7, .tdvh = 1, + .tfs = 27, .tli = 20, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3, + .tsr = 4, .trfs = 10, .trp = 17, .tack = 3, .tss = 7, + }, + { .tcyc = 6, .t2cyc = 12, .tds = 1, .tdh = 1, .tdvs = 5, .tdvh = 1, + .tfs = 23, .tli = 20, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3, + .tsr = 3, .trfs = 8, .trp = 14, .tack = 3, .tss = 7, + }, + { .tcyc = 7, .t2cyc = 12, .tds = 1, .tdh = 1, .tdvs = 3, .tdvh = 1, + .tfs = 15, .tli = 13, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3, + .tsr = 3, .trfs = 8, .trp = 14, .tack = 3, .tss = 7, + }, + { .tcyc = 2, .t2cyc = 5, .tds = 0, .tdh = 0, .tdvs = 1, .tdvh = 1, + .tfs = 16, .tli = 14, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2, + .tsr = 2, .trfs = 7, .trp = 13, .tack = 2, .tss = 6, + }, + { .tcyc = 3, .t2cyc = 6, .tds = 1, .tdh = 1, .tdvs = 1, .tdvh = 1, + .tfs = 12, .tli = 10, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3, + .tsr = 3, .trfs = 7, .trp = 12, .tack = 3, .tss = 7, + }, +}; + +/* ======================================================================== */ /* Bit definitions inside the registers */ #define MPC52xx_ATA_HOSTCONF_SMR 0x80000000UL /* State machine reset */ @@ -66,6 +188,7 @@ static const int ataspec_ta[5] = { 35, 35, 35, 35, 35}; #define MPC52xx_ATA_HOSTSTAT_WERR 0x01000000UL /* Write Error */ #define MPC52xx_ATA_FIFOSTAT_EMPTY 0x01 /* FIFO Empty */ +#define MPC52xx_ATA_FIFOSTAT_ERROR 0x40 /* FIFO Error */ #define MPC52xx_ATA_DMAMODE_WRITE 0x01 /* Write DMA */ #define MPC52xx_ATA_DMAMODE_READ 0x02 /* Read DMA */ @@ -75,6 +198,8 @@ static const int ataspec_ta[5] = { 35, 35, 35, 35, 35}; #define MPC52xx_ATA_DMAMODE_FR 0x20 /* FIFO Reset */ #define MPC52xx_ATA_DMAMODE_HUT 0x40 /* Host UDMA burst terminate */ +#define MAX_DMA_BUFFERS 128 +#define MAX_DMA_BUFFER_SIZE 0x20000u /* Structure of the hardware registers */ struct mpc52xx_ata { @@ -140,7 +265,6 @@ struct mpc52xx_ata { /* MPC52xx low level hw control */ - static int mpc52xx_ata_compute_pio_timings(struct mpc52xx_ata_priv *priv, int dev, int pio) { @@ -148,7 +272,7 @@ mpc52xx_ata_compute_pio_timings(struct mpc52xx_ata_priv *priv, int dev, int pio) unsigned int ipb_period = priv->ipb_period; unsigned int t0, t1, t2_8, t2_16, t2i, t4, ta; - if ((pio<0) || (pio>4)) + if ((pio < 0) || (pio > 4)) return -EINVAL; t0 = CALC_CLKCYC(ipb_period, 1000 * ataspec_t0[pio]); @@ -165,6 +289,43 @@ mpc52xx_ata_compute_pio_timings(struct mpc52xx_ata_priv *priv, int dev, int pio) return 0; } +static int +mpc52xx_ata_compute_mdma_timings(struct mpc52xx_ata_priv *priv, int dev, + int speed) +{ + struct mpc52xx_ata_timings *t = &priv->timings[dev]; + const struct mdmaspec *s = &priv->mdmaspec[speed]; + + if (speed < 0 || speed > 2) + return -EINVAL; + + t->mdma1 = (s->t0M << 24) | (s->td << 16) | (s->tkw << 8) | (s->tm); + t->mdma2 = (s->th << 24) | (s->tj << 16) | (s->tn << 8); + t->using_udma = 0; + + return 0; +} + +static int +mpc52xx_ata_compute_udma_timings(struct mpc52xx_ata_priv *priv, int dev, + int speed) +{ + struct mpc52xx_ata_timings *t = &priv->timings[dev]; + const struct udmaspec *s = &priv->udmaspec[speed]; + + if (speed < 0 || speed > 2) + return -EINVAL; + + t->udma1 = (s->t2cyc << 24) | (s->tcyc << 16) | (s->tds << 8) | s->tdh; + t->udma2 = (s->tdvs << 24) | (s->tdvh << 16) | (s->tfs << 8) | s->tli; + t->udma3 = (s->tmli << 24) | (s->taz << 16) | (s->tenv << 8) | s->tsr; + t->udma4 = (s->tss << 24) | (s->trfs << 16) | (s->trp << 8) | s->tack; + t->udma5 = (s->tzah << 24); + t->using_udma = 1; + + return 0; +} + static void mpc52xx_ata_apply_timings(struct mpc52xx_ata_priv *priv, int device) { @@ -173,14 +334,13 @@ mpc52xx_ata_apply_timings(struct mpc52xx_ata_priv *priv, int device) out_be32(®s->pio1, timing->pio1); out_be32(®s->pio2, timing->pio2); - out_be32(®s->mdma1, 0); - out_be32(®s->mdma2, 0); - out_be32(®s->udma1, 0); - out_be32(®s->udma2, 0); - out_be32(®s->udma3, 0); - out_be32(®s->udma4, 0); - out_be32(®s->udma5, 0); - + out_be32(®s->mdma1, timing->mdma1); + out_be32(®s->mdma2, timing->mdma2); + out_be32(®s->udma1, timing->udma1); + out_be32(®s->udma2, timing->udma2); + out_be32(®s->udma3, timing->udma3); + out_be32(®s->udma4, timing->udma4); + out_be32(®s->udma5, timing->udma5); priv->csel = device; } @@ -208,7 +368,7 @@ mpc52xx_ata_hw_init(struct mpc52xx_ata_priv *priv) /* Set the time slot to 1us */ tslot = CALC_CLKCYC(priv->ipb_period, 1000000); - out_be32(®s->share_cnt, tslot << 16 ); + out_be32(®s->share_cnt, tslot << 16); /* Init timings to PIO0 */ memset(priv->timings, 0x00, 2*sizeof(struct mpc52xx_ata_timings)); @@ -237,13 +397,37 @@ mpc52xx_ata_set_piomode(struct ata_port *ap, struct ata_device *adev) rv = mpc52xx_ata_compute_pio_timings(priv, adev->devno, pio); if (rv) { - printk(KERN_ERR DRV_NAME - ": Trying to select invalid PIO mode %d\n", pio); + dev_err(ap->dev, "error: invalid PIO mode: %d\n", pio); + return; + } + + mpc52xx_ata_apply_timings(priv, adev->devno); +} + +static void +mpc52xx_ata_set_dmamode(struct ata_port *ap, struct ata_device *adev) +{ + struct mpc52xx_ata_priv *priv = ap->host->private_data; + int rv; + + if (adev->dma_mode >= XFER_UDMA_0) { + int dma = adev->dma_mode - XFER_UDMA_0; + rv = mpc52xx_ata_compute_udma_timings(priv, adev->devno, dma); + } else { + int dma = adev->dma_mode - XFER_MW_DMA_0; + rv = mpc52xx_ata_compute_mdma_timings(priv, adev->devno, dma); + } + + if (rv) { + dev_alert(ap->dev, + "Trying to select invalid DMA mode %d\n", + adev->dma_mode); return; } mpc52xx_ata_apply_timings(priv, adev->devno); } + static void mpc52xx_ata_dev_select(struct ata_port *ap, unsigned int device) { @@ -252,7 +436,173 @@ mpc52xx_ata_dev_select(struct ata_port *ap, unsigned int device) if (device != priv->csel) mpc52xx_ata_apply_timings(priv, device); - ata_sff_dev_select(ap,device); + ata_sff_dev_select(ap, device); +} + +static int +mpc52xx_ata_build_dmatable(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct mpc52xx_ata_priv *priv = ap->host->private_data; + struct bcom_ata_bd *bd; + unsigned int read = !(qc->tf.flags & ATA_TFLAG_WRITE), si; + struct scatterlist *sg; + int count = 0; + + if (read) + bcom_ata_rx_prepare(priv->dmatsk); + else + bcom_ata_tx_prepare(priv->dmatsk); + + for_each_sg(qc->sg, sg, qc->n_elem, si) { + dma_addr_t cur_addr = sg_dma_address(sg); + u32 cur_len = sg_dma_len(sg); + + while (cur_len) { + unsigned int tc = min(cur_len, MAX_DMA_BUFFER_SIZE); + bd = (struct bcom_ata_bd *) + bcom_prepare_next_buffer(priv->dmatsk); + + if (read) { + bd->status = tc; + bd->src_pa = (__force u32) priv->ata_regs_pa + + offsetof(struct mpc52xx_ata, fifo_data); + bd->dst_pa = (__force u32) cur_addr; + } else { + bd->status = tc; + bd->src_pa = (__force u32) cur_addr; + bd->dst_pa = (__force u32) priv->ata_regs_pa + + offsetof(struct mpc52xx_ata, fifo_data); + } + + bcom_submit_next_buffer(priv->dmatsk, NULL); + + cur_addr += tc; + cur_len -= tc; + count++; + + if (count > MAX_DMA_BUFFERS) { + dev_alert(ap->dev, "dma table" + "too small\n"); + goto use_pio_instead; + } + } + } + return 1; + + use_pio_instead: + bcom_ata_reset_bd(priv->dmatsk); + return 0; +} + +static void +mpc52xx_bmdma_setup(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct mpc52xx_ata_priv *priv = ap->host->private_data; + struct mpc52xx_ata __iomem *regs = priv->ata_regs; + + unsigned int read = !(qc->tf.flags & ATA_TFLAG_WRITE); + u8 dma_mode; + + if (!mpc52xx_ata_build_dmatable(qc)) + dev_alert(ap->dev, "%s: %i, return 1?\n", + __func__, __LINE__); + + /* Check FIFO is OK... */ + if (in_8(&priv->ata_regs->fifo_status) & MPC52xx_ATA_FIFOSTAT_ERROR) + dev_alert(ap->dev, "%s: FIFO error detected: 0x%02x!\n", + __func__, in_8(&priv->ata_regs->fifo_status)); + + if (read) { + dma_mode = MPC52xx_ATA_DMAMODE_IE | MPC52xx_ATA_DMAMODE_READ | + MPC52xx_ATA_DMAMODE_FE; + + /* Setup FIFO if direction changed */ + if (priv->mpc52xx_ata_dma_last_write != 0) { + priv->mpc52xx_ata_dma_last_write = 0; + + /* Configure FIFO with granularity to 7 */ + out_8(®s->fifo_control, 7); + out_be16(®s->fifo_alarm, 128); + + /* Set FIFO Reset bit (FR) */ + out_8(®s->dma_mode, MPC52xx_ATA_DMAMODE_FR); + } + } else { + dma_mode = MPC52xx_ATA_DMAMODE_IE | MPC52xx_ATA_DMAMODE_WRITE; + + /* Setup FIFO if direction changed */ + if (priv->mpc52xx_ata_dma_last_write != 1) { + priv->mpc52xx_ata_dma_last_write = 1; + + /* Configure FIFO with granularity to 4 */ + out_8(®s->fifo_control, 4); + out_be16(®s->fifo_alarm, 128); + } + } + + if (priv->timings[qc->dev->devno].using_udma) + dma_mode |= MPC52xx_ATA_DMAMODE_UDMA; + + out_8(®s->dma_mode, dma_mode); + priv->waiting_for_dma = ATA_DMA_ACTIVE; + + ata_wait_idle(ap); + ap->ops->sff_exec_command(ap, &qc->tf); +} + +static void +mpc52xx_bmdma_start(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct mpc52xx_ata_priv *priv = ap->host->private_data; + + bcom_set_task_auto_start(priv->dmatsk->tasknum, priv->dmatsk->tasknum); + bcom_enable(priv->dmatsk); +} + +static void +mpc52xx_bmdma_stop(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct mpc52xx_ata_priv *priv = ap->host->private_data; + + bcom_disable(priv->dmatsk); + bcom_ata_reset_bd(priv->dmatsk); + priv->waiting_for_dma = 0; + + /* Check FIFO is OK... */ + if (in_8(&priv->ata_regs->fifo_status) & MPC52xx_ATA_FIFOSTAT_ERROR) + dev_alert(ap->dev, "%s: FIFO error detected: 0x%02x!\n", + __func__, in_8(&priv->ata_regs->fifo_status)); +} + +static u8 +mpc52xx_bmdma_status(struct ata_port *ap) +{ + struct mpc52xx_ata_priv *priv = ap->host->private_data; + + /* Check FIFO is OK... */ + if (in_8(&priv->ata_regs->fifo_status) & MPC52xx_ATA_FIFOSTAT_ERROR) { + dev_alert(ap->dev, "%s: FIFO error detected: 0x%02x!\n", + __func__, in_8(&priv->ata_regs->fifo_status)); + return priv->waiting_for_dma | ATA_DMA_ERR; + } + + return priv->waiting_for_dma; +} + +static irqreturn_t +mpc52xx_ata_task_irq(int irq, void *vpriv) +{ + struct mpc52xx_ata_priv *priv = vpriv; + while (bcom_buffer_done(priv->dmatsk)) + bcom_retrieve_buffer(priv->dmatsk, NULL, NULL); + + priv->waiting_for_dma |= ATA_DMA_INTR; + + return IRQ_HANDLED; } static struct scsi_host_template mpc52xx_ata_sht = { @@ -262,14 +612,18 @@ static struct scsi_host_template mpc52xx_ata_sht = { static struct ata_port_operations mpc52xx_ata_port_ops = { .inherits = &ata_sff_port_ops, .sff_dev_select = mpc52xx_ata_dev_select, - .cable_detect = ata_cable_40wire, .set_piomode = mpc52xx_ata_set_piomode, - .post_internal_cmd = ATA_OP_NULL, + .set_dmamode = mpc52xx_ata_set_dmamode, + .bmdma_setup = mpc52xx_bmdma_setup, + .bmdma_start = mpc52xx_bmdma_start, + .bmdma_stop = mpc52xx_bmdma_stop, + .bmdma_status = mpc52xx_bmdma_status, + .qc_prep = ata_noop_qc_prep, }; static int __devinit mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv, - unsigned long raw_ata_regs) + unsigned long raw_ata_regs, int mwdma_mask, int udma_mask) { struct ata_host *host; struct ata_port *ap; @@ -281,9 +635,9 @@ mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv, ap = host->ports[0]; ap->flags |= ATA_FLAG_SLAVE_POSS; - ap->pio_mask = 0x1f; /* Up to PIO4 */ - ap->mwdma_mask = 0x00; /* No MWDMA */ - ap->udma_mask = 0x00; /* No UDMA */ + ap->pio_mask = ATA_PIO4; + ap->mwdma_mask = mwdma_mask; + ap->udma_mask = udma_mask; ap->ops = &mpc52xx_ata_port_ops; host->private_data = priv; @@ -330,89 +684,139 @@ mpc52xx_ata_probe(struct of_device *op, const struct of_device_id *match) { unsigned int ipb_freq; struct resource res_mem; - int ata_irq; + int ata_irq = 0; struct mpc52xx_ata __iomem *ata_regs; - struct mpc52xx_ata_priv *priv; - int rv; + struct mpc52xx_ata_priv *priv = NULL; + int rv, ret, task_irq = 0; + int mwdma_mask = 0, udma_mask = 0; + const __be32 *prop; + int proplen; + struct bcom_task *dmatsk = NULL; /* Get ipb frequency */ ipb_freq = mpc52xx_find_ipb_freq(op->node); if (!ipb_freq) { - printk(KERN_ERR DRV_NAME ": " - "Unable to find IPB Bus frequency\n" ); + dev_err(&op->dev, "could not determine IPB bus frequency\n"); return -ENODEV; } - /* Get IRQ and register */ + /* Get device base address from device tree, request the region + * and ioremap it. */ rv = of_address_to_resource(op->node, 0, &res_mem); if (rv) { - printk(KERN_ERR DRV_NAME ": " - "Error while parsing device node resource\n" ); + dev_err(&op->dev, "could not determine device base address\n"); return rv; } - ata_irq = irq_of_parse_and_map(op->node, 0); - if (ata_irq == NO_IRQ) { - printk(KERN_ERR DRV_NAME ": " - "Error while mapping the irq\n"); - return -EINVAL; - } - - /* Request mem region */ if (!devm_request_mem_region(&op->dev, res_mem.start, - sizeof(struct mpc52xx_ata), DRV_NAME)) { - printk(KERN_ERR DRV_NAME ": " - "Error while requesting mem region\n"); - rv = -EBUSY; - goto err; + sizeof(*ata_regs), DRV_NAME)) { + dev_err(&op->dev, "error requesting register region\n"); + return -EBUSY; } - /* Remap registers */ - ata_regs = devm_ioremap(&op->dev, res_mem.start, - sizeof(struct mpc52xx_ata)); + ata_regs = devm_ioremap(&op->dev, res_mem.start, sizeof(*ata_regs)); if (!ata_regs) { - printk(KERN_ERR DRV_NAME ": " - "Error while mapping register set\n"); + dev_err(&op->dev, "error mapping device registers\n"); rv = -ENOMEM; goto err; } + /* + * By default, all DMA modes are disabled for the MPC5200. Some + * boards don't have the required signals routed to make DMA work. + * Also, the MPC5200B has a silicon bug that causes data corruption + * with UDMA if it is used at the same time as the LocalPlus bus. + * + * Instead of trying to guess what modes are usable, check the + * ATA device tree node to find out what DMA modes work on the board. + * UDMA/MWDMA modes can also be forced by adding "libata.force=" + * to the kernel boot parameters. + * + * The MPC5200 ATA controller supports MWDMA modes 0, 1 and 2 and + * UDMA modes 0, 1 and 2. + */ + prop = of_get_property(op->node, "mwdma-mode", &proplen); + if ((prop) && (proplen >= 4)) + mwdma_mask = 0x7 & ((1 << (*prop + 1)) - 1); + prop = of_get_property(op->node, "udma-mode", &proplen); + if ((prop) && (proplen >= 4)) + udma_mask = 0x7 & ((1 << (*prop + 1)) - 1); + + ata_irq = irq_of_parse_and_map(op->node, 0); + if (ata_irq == NO_IRQ) { + dev_err(&op->dev, "error mapping irq\n"); + return -EINVAL; + } + /* Prepare our private structure */ - priv = devm_kzalloc(&op->dev, sizeof(struct mpc52xx_ata_priv), - GFP_ATOMIC); + priv = devm_kzalloc(&op->dev, sizeof(*priv), GFP_ATOMIC); if (!priv) { - printk(KERN_ERR DRV_NAME ": " - "Error while allocating private structure\n"); + dev_err(&op->dev, "error allocating private structure\n"); rv = -ENOMEM; goto err; } priv->ipb_period = 1000000000 / (ipb_freq / 1000); priv->ata_regs = ata_regs; + priv->ata_regs_pa = res_mem.start; priv->ata_irq = ata_irq; priv->csel = -1; + priv->mpc52xx_ata_dma_last_write = -1; + + if (ipb_freq/1000000 == 66) { + priv->mdmaspec = mdmaspec66; + priv->udmaspec = udmaspec66; + } else { + priv->mdmaspec = mdmaspec132; + priv->udmaspec = udmaspec132; + } + + /* Allocate a BestComm task for DMA */ + dmatsk = bcom_ata_init(MAX_DMA_BUFFERS, MAX_DMA_BUFFER_SIZE); + if (!dmatsk) { + dev_err(&op->dev, "bestcomm initialization failed\n"); + rv = -ENOMEM; + goto err; + } + + task_irq = bcom_get_task_irq(dmatsk); + ret = request_irq(task_irq, &mpc52xx_ata_task_irq, IRQF_DISABLED, + "ATA task", priv); + if (ret) { + dev_err(&op->dev, "error requesting DMA IRQ\n"); + goto err; + } + priv->dmatsk = dmatsk; /* Init the hw */ rv = mpc52xx_ata_hw_init(priv); if (rv) { - printk(KERN_ERR DRV_NAME ": Error during HW init\n"); + dev_err(&op->dev, "error initializing hardware\n"); goto err; } /* Register ourselves to libata */ - rv = mpc52xx_ata_init_one(&op->dev, priv, res_mem.start); + rv = mpc52xx_ata_init_one(&op->dev, priv, res_mem.start, + mwdma_mask, udma_mask); if (rv) { - printk(KERN_ERR DRV_NAME ": " - "Error while registering to ATA layer\n"); - return rv; + dev_err(&op->dev, "error registering with ATA layer\n"); + goto err; } - /* Done */ return 0; - /* Error path */ -err: - irq_dispose_mapping(ata_irq); + err: + devm_release_mem_region(&op->dev, res_mem.start, sizeof(*ata_regs)); + if (ata_irq) + irq_dispose_mapping(ata_irq); + if (task_irq) + irq_dispose_mapping(task_irq); + if (dmatsk) + bcom_ata_release(dmatsk); + if (ata_regs) + devm_iounmap(&op->dev, ata_regs); + if (priv) + devm_kfree(&op->dev, priv); return rv; } @@ -420,10 +824,23 @@ static int mpc52xx_ata_remove(struct of_device *op) { struct mpc52xx_ata_priv *priv; + int task_irq; + /* Deregister the ATA interface */ priv = mpc52xx_ata_remove_one(&op->dev); + + /* Clean up DMA */ + task_irq = bcom_get_task_irq(priv->dmatsk); + irq_dispose_mapping(task_irq); + bcom_ata_release(priv->dmatsk); irq_dispose_mapping(priv->ata_irq); + /* Clear up IO allocations */ + devm_iounmap(&op->dev, priv->ata_regs); + devm_release_mem_region(&op->dev, priv->ata_regs_pa, + sizeof(*priv->ata_regs)); + devm_kfree(&op->dev, priv); + return 0; } @@ -447,7 +864,7 @@ mpc52xx_ata_resume(struct of_device *op) rv = mpc52xx_ata_hw_init(priv); if (rv) { - printk(KERN_ERR DRV_NAME ": Error during HW init\n"); + dev_err(host->dev, "error initializing hardware\n"); return rv; } @@ -507,5 +924,4 @@ MODULE_AUTHOR("Sylvain Munaut "); MODULE_DESCRIPTION("Freescale MPC52xx IDE/ATA libata driver"); MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(of, mpc52xx_ata_of_match); -MODULE_VERSION(DRV_VERSION); diff --git a/drivers/atm/Kconfig b/drivers/atm/Kconfig index f197a193633aebd3f1f8964c34cbf4c9bffd72b3..191b85e857e0a3f0ef9055c27dd2408812ad1268 100644 --- a/drivers/atm/Kconfig +++ b/drivers/atm/Kconfig @@ -391,4 +391,10 @@ config ATM_HE_USE_SUNI Support for the S/UNI-Ultra and S/UNI-622 found in the ForeRunner HE cards. This driver provides carrier detection some statistics. +config ATM_SOLOS + tristate "Solos ADSL2+ PCI Multiport card driver" + depends on PCI + help + Support for the Solos multiport ADSL2+ card. + endif # ATM diff --git a/drivers/atm/Makefile b/drivers/atm/Makefile index 0bfb31748ecf8495185888789e5009945bc9051f..62c3cc1075ae9239349652d53c114d404e282347 100644 --- a/drivers/atm/Makefile +++ b/drivers/atm/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_ATM_IA) += iphase.o suni.o obj-$(CONFIG_ATM_FORE200E) += fore_200e.o obj-$(CONFIG_ATM_ENI) += eni.o suni.o obj-$(CONFIG_ATM_IDT77252) += idt77252.o +obj-$(CONFIG_ATM_SOLOS) += solos-pci.o ifeq ($(CONFIG_ATM_NICSTAR_USE_SUNI),y) obj-$(CONFIG_ATM_NICSTAR) += suni.o diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c new file mode 100644 index 0000000000000000000000000000000000000000..72fc0f799a64e55d81365dba9dd78acca1e86f1d --- /dev/null +++ b/drivers/atm/solos-pci.c @@ -0,0 +1,790 @@ +/* + * Driver for the Solos PCI ADSL2+ card, designed to support Linux by + * Traverse Technologies -- http://www.traverse.com.au/ + * Xrio Limited -- http://www.xrio.com/ + * + * + * Copyright © 2008 Traverse Technologies + * Copyright © 2008 Intel Corporation + * + * Authors: Nathan Williams + * David Woodhouse + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define DEBUG +#define VERBOSE_DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define VERSION "0.04" +#define PTAG "solos-pci" + +#define CONFIG_RAM_SIZE 128 +#define FLAGS_ADDR 0x7C +#define IRQ_EN_ADDR 0x78 +#define FPGA_VER 0x74 +#define IRQ_CLEAR 0x70 +#define BUG_FLAG 0x6C + +#define DATA_RAM_SIZE 32768 +#define BUF_SIZE 4096 + +#define RX_BUF(card, nr) ((card->buffers) + (nr)*BUF_SIZE*2) +#define TX_BUF(card, nr) ((card->buffers) + (nr)*BUF_SIZE*2 + BUF_SIZE) + +static int debug = 0; +static int atmdebug = 0; + +struct pkt_hdr { + __le16 size; + __le16 vpi; + __le16 vci; + __le16 type; +}; + +#define PKT_DATA 0 +#define PKT_COMMAND 1 +#define PKT_POPEN 3 +#define PKT_PCLOSE 4 + +struct solos_card { + void __iomem *config_regs; + void __iomem *buffers; + int nr_ports; + struct pci_dev *dev; + struct atm_dev *atmdev[4]; + struct tasklet_struct tlet; + spinlock_t tx_lock; + spinlock_t tx_queue_lock; + spinlock_t cli_queue_lock; + struct sk_buff_head tx_queue[4]; + struct sk_buff_head cli_queue[4]; +}; + +#define SOLOS_CHAN(atmdev) ((int)(unsigned long)(atmdev)->phy_data) + +MODULE_AUTHOR("Traverse Technologies "); +MODULE_DESCRIPTION("Solos PCI driver"); +MODULE_VERSION(VERSION); +MODULE_LICENSE("GPL"); +MODULE_PARM_DESC(debug, "Enable Loopback"); +MODULE_PARM_DESC(atmdebug, "Print ATM data"); +module_param(debug, int, 0444); +module_param(atmdebug, int, 0444); + +static int opens; + +static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb, + struct atm_vcc *vcc); +static int fpga_tx(struct solos_card *); +static irqreturn_t solos_irq(int irq, void *dev_id); +static struct atm_vcc* find_vcc(struct atm_dev *dev, short vpi, int vci); +static int list_vccs(int vci); +static int atm_init(struct solos_card *); +static void atm_remove(struct solos_card *); +static int send_command(struct solos_card *card, int dev, const char *buf, size_t size); +static void solos_bh(unsigned long); +static int print_buffer(struct sk_buff *buf); + +static inline void solos_pop(struct atm_vcc *vcc, struct sk_buff *skb) +{ + if (vcc->pop) + vcc->pop(vcc, skb); + else + dev_kfree_skb_any(skb); +} + +static ssize_t console_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct atm_dev *atmdev = container_of(dev, struct atm_dev, class_dev); + struct solos_card *card = atmdev->dev_data; + struct sk_buff *skb; + + spin_lock(&card->cli_queue_lock); + skb = skb_dequeue(&card->cli_queue[SOLOS_CHAN(atmdev)]); + spin_unlock(&card->cli_queue_lock); + if(skb == NULL) + return sprintf(buf, "No data.\n"); + + memcpy(buf, skb->data, skb->len); + dev_dbg(&card->dev->dev, "len: %d\n", skb->len); + + kfree_skb(skb); + return skb->len; +} + +static int send_command(struct solos_card *card, int dev, const char *buf, size_t size) +{ + struct sk_buff *skb; + struct pkt_hdr *header; + +// dev_dbg(&card->dev->dev, "size: %d\n", size); + + if (size > (BUF_SIZE - sizeof(*header))) { + dev_dbg(&card->dev->dev, "Command is too big. Dropping request\n"); + return 0; + } + skb = alloc_skb(size + sizeof(*header), GFP_ATOMIC); + if (!skb) { + dev_warn(&card->dev->dev, "Failed to allocate sk_buff in send_command()\n"); + return 0; + } + + header = (void *)skb_put(skb, sizeof(*header)); + + header->size = cpu_to_le16(size); + header->vpi = cpu_to_le16(0); + header->vci = cpu_to_le16(0); + header->type = cpu_to_le16(PKT_COMMAND); + + memcpy(skb_put(skb, size), buf, size); + + fpga_queue(card, dev, skb, NULL); + + return 0; +} + +static ssize_t console_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct atm_dev *atmdev = container_of(dev, struct atm_dev, class_dev); + struct solos_card *card = atmdev->dev_data; + int err; + + err = send_command(card, SOLOS_CHAN(atmdev), buf, count); + + return err?:count; +} + +static DEVICE_ATTR(console, 0644, console_show, console_store); + +static irqreturn_t solos_irq(int irq, void *dev_id) +{ + struct solos_card *card = dev_id; + int handled = 1; + + //ACK IRQ + iowrite32(0, card->config_regs + IRQ_CLEAR); + //Disable IRQs from FPGA + iowrite32(0, card->config_regs + IRQ_EN_ADDR); + + /* If we only do it when the device is open, we lose console + messages */ + if (1 || opens) + tasklet_schedule(&card->tlet); + + //Enable IRQs from FPGA + iowrite32(1, card->config_regs + IRQ_EN_ADDR); + return IRQ_RETVAL(handled); +} + +void solos_bh(unsigned long card_arg) +{ + struct solos_card *card = (void *)card_arg; + int port; + uint32_t card_flags; + uint32_t tx_mask; + uint32_t rx_done = 0; + + card_flags = ioread32(card->config_regs + FLAGS_ADDR); + + /* The TX bits are set if the channel is busy; clear if not. We want to + invoke fpga_tx() unless _all_ the bits for active channels are set */ + tx_mask = (1 << card->nr_ports) - 1; + if ((card_flags & tx_mask) != tx_mask) + fpga_tx(card); + + for (port = 0; port < card->nr_ports; port++) { + if (card_flags & (0x10 << port)) { + struct pkt_hdr header; + struct sk_buff *skb; + struct atm_vcc *vcc; + int size; + + rx_done |= 0x10 << port; + + memcpy_fromio(&header, RX_BUF(card, port), sizeof(header)); + + size = le16_to_cpu(header.size); + + skb = alloc_skb(size, GFP_ATOMIC); + if (!skb) { + if (net_ratelimit()) + dev_warn(&card->dev->dev, "Failed to allocate sk_buff for RX\n"); + continue; + } + + memcpy_fromio(skb_put(skb, size), + RX_BUF(card, port) + sizeof(header), + size); + + if (atmdebug) { + dev_info(&card->dev->dev, "Received: device %d\n", port); + dev_info(&card->dev->dev, "size: %d VPI: %d VCI: %d\n", + size, le16_to_cpu(header.vpi), + le16_to_cpu(header.vci)); + print_buffer(skb); + } + + switch (le16_to_cpu(header.type)) { + case PKT_DATA: + vcc = find_vcc(card->atmdev[port], le16_to_cpu(header.vpi), + le16_to_cpu(header.vci)); + if (!vcc) { + if (net_ratelimit()) + dev_warn(&card->dev->dev, "Received packet for unknown VCI.VPI %d.%d on port %d\n", + le16_to_cpu(header.vci), le16_to_cpu(header.vpi), + port); + continue; + } + atm_charge(vcc, skb->truesize); + vcc->push(vcc, skb); + atomic_inc(&vcc->stats->rx); + break; + + case PKT_COMMAND: + default: /* FIXME: Not really, surely? */ + spin_lock(&card->cli_queue_lock); + if (skb_queue_len(&card->cli_queue[port]) > 10) { + if (net_ratelimit()) + dev_warn(&card->dev->dev, "Dropping console response on port %d\n", + port); + } else + skb_queue_tail(&card->cli_queue[port], skb); + spin_unlock(&card->cli_queue_lock); + break; + } + } + } + if (rx_done) + iowrite32(rx_done, card->config_regs + FLAGS_ADDR); + + return; +} + +static struct atm_vcc *find_vcc(struct atm_dev *dev, short vpi, int vci) +{ + struct hlist_head *head; + struct atm_vcc *vcc = NULL; + struct hlist_node *node; + struct sock *s; + + read_lock(&vcc_sklist_lock); + head = &vcc_hash[vci & (VCC_HTABLE_SIZE -1)]; + sk_for_each(s, node, head) { + vcc = atm_sk(s); + if (vcc->dev == dev && vcc->vci == vci && + vcc->vpi == vpi && vcc->qos.rxtp.traffic_class != ATM_NONE) + goto out; + } + vcc = NULL; + out: + read_unlock(&vcc_sklist_lock); + return vcc; +} + +static int list_vccs(int vci) +{ + struct hlist_head *head; + struct atm_vcc *vcc; + struct hlist_node *node; + struct sock *s; + int num_found = 0; + int i; + + read_lock(&vcc_sklist_lock); + if (vci != 0){ + head = &vcc_hash[vci & (VCC_HTABLE_SIZE -1)]; + sk_for_each(s, node, head) { + num_found ++; + vcc = atm_sk(s); + printk(KERN_DEBUG "Device: %d Vpi: %d Vci: %d\n", + vcc->dev->number, + vcc->vpi, + vcc->vci); + } + } else { + for(i=0; i<32; i++){ + head = &vcc_hash[i]; + sk_for_each(s, node, head) { + num_found ++; + vcc = atm_sk(s); + printk(KERN_DEBUG "Device: %d Vpi: %d Vci: %d\n", + vcc->dev->number, + vcc->vpi, + vcc->vci); + } + } + } + read_unlock(&vcc_sklist_lock); + return num_found; +} + + +static int popen(struct atm_vcc *vcc) +{ + struct solos_card *card = vcc->dev->dev_data; + struct sk_buff *skb; + struct pkt_hdr *header; + + skb = alloc_skb(sizeof(*header), GFP_ATOMIC); + if (!skb && net_ratelimit()) { + dev_warn(&card->dev->dev, "Failed to allocate sk_buff in popen()\n"); + return -ENOMEM; + } + header = (void *)skb_put(skb, sizeof(*header)); + + header->size = cpu_to_le16(sizeof(*header)); + header->vpi = cpu_to_le16(vcc->vpi); + header->vci = cpu_to_le16(vcc->vci); + header->type = cpu_to_le16(PKT_POPEN); + + fpga_queue(card, SOLOS_CHAN(vcc->dev), skb, NULL); + +// dev_dbg(&card->dev->dev, "Open for vpi %d and vci %d on interface %d\n", vcc->vpi, vcc->vci, SOLOS_CHAN(vcc->dev)); + set_bit(ATM_VF_ADDR, &vcc->flags); // accept the vpi / vci + set_bit(ATM_VF_READY, &vcc->flags); + list_vccs(0); + + if (!opens) + iowrite32(1, card->config_regs + IRQ_EN_ADDR); + + opens++; //count open PVCs + + return 0; +} + +static void pclose(struct atm_vcc *vcc) +{ + struct solos_card *card = vcc->dev->dev_data; + struct sk_buff *skb; + struct pkt_hdr *header; + + skb = alloc_skb(sizeof(*header), GFP_ATOMIC); + if (!skb) { + dev_warn(&card->dev->dev, "Failed to allocate sk_buff in pclose()\n"); + return; + } + header = (void *)skb_put(skb, sizeof(*header)); + + header->size = cpu_to_le16(sizeof(*header)); + header->vpi = cpu_to_le16(vcc->vpi); + header->vci = cpu_to_le16(vcc->vci); + header->type = cpu_to_le16(PKT_PCLOSE); + + fpga_queue(card, SOLOS_CHAN(vcc->dev), skb, NULL); + +// dev_dbg(&card->dev->dev, "Close for vpi %d and vci %d on interface %d\n", vcc->vpi, vcc->vci, SOLOS_CHAN(vcc->dev)); + if (!--opens) + iowrite32(0, card->config_regs + IRQ_EN_ADDR); + + clear_bit(ATM_VF_ADDR, &vcc->flags); + clear_bit(ATM_VF_READY, &vcc->flags); + + return; +} + +static int print_buffer(struct sk_buff *buf) +{ + int len,i; + char msg[500]; + char item[10]; + + len = buf->len; + for (i = 0; i < len; i++){ + if(i % 8 == 0) + sprintf(msg, "%02X: ", i); + + sprintf(item,"%02X ",*(buf->data + i)); + strcat(msg, item); + if(i % 8 == 7) { + sprintf(item, "\n"); + strcat(msg, item); + printk(KERN_DEBUG "%s", msg); + } + } + if (i % 8 != 0) { + sprintf(item, "\n"); + strcat(msg, item); + printk(KERN_DEBUG "%s", msg); + } + printk(KERN_DEBUG "\n"); + + return 0; +} + +static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb, + struct atm_vcc *vcc) +{ + int old_len; + + *(void **)skb->cb = vcc; + + spin_lock(&card->tx_queue_lock); + old_len = skb_queue_len(&card->tx_queue[port]); + skb_queue_tail(&card->tx_queue[port], skb); + spin_unlock(&card->tx_queue_lock); + + /* If TX might need to be started, do so */ + if (!old_len) + fpga_tx(card); +} + +static int fpga_tx(struct solos_card *card) +{ + uint32_t tx_pending; + uint32_t tx_started = 0; + struct sk_buff *skb; + struct atm_vcc *vcc; + unsigned char port; + unsigned long flags; + + spin_lock_irqsave(&card->tx_lock, flags); + + tx_pending = ioread32(card->config_regs + FLAGS_ADDR); + + dev_vdbg(&card->dev->dev, "TX Flags are %X\n", tx_pending); + + for (port = 0; port < card->nr_ports; port++) { + if (!(tx_pending & (1 << port))) { + + spin_lock(&card->tx_queue_lock); + skb = skb_dequeue(&card->tx_queue[port]); + spin_unlock(&card->tx_queue_lock); + + if (!skb) + continue; + + if (atmdebug) { + dev_info(&card->dev->dev, "Transmitted: port %d\n", + port); + print_buffer(skb); + } + memcpy_toio(TX_BUF(card, port), skb->data, skb->len); + + vcc = *(void **)skb->cb; + + if (vcc) { + atomic_inc(&vcc->stats->tx); + solos_pop(vcc, skb); + } else + dev_kfree_skb_irq(skb); + + tx_started |= 1 << port; //Set TX full flag + } + } + if (tx_started) + iowrite32(tx_started, card->config_regs + FLAGS_ADDR); + + spin_unlock_irqrestore(&card->tx_lock, flags); + return 0; +} + +static int psend(struct atm_vcc *vcc, struct sk_buff *skb) +{ + struct solos_card *card = vcc->dev->dev_data; + struct sk_buff *skb2 = NULL; + struct pkt_hdr *header; + + //dev_dbg(&card->dev->dev, "psend called.\n"); + //dev_dbg(&card->dev->dev, "dev,vpi,vci = %d,%d,%d\n",SOLOS_CHAN(vcc->dev),vcc->vpi,vcc->vci); + + if (debug) { + skb2 = atm_alloc_charge(vcc, skb->len, GFP_ATOMIC); + if (skb2) { + memcpy(skb2->data, skb->data, skb->len); + skb_put(skb2, skb->len); + vcc->push(vcc, skb2); + atomic_inc(&vcc->stats->rx); + } + atomic_inc(&vcc->stats->tx); + solos_pop(vcc, skb); + return 0; + } + + if (skb->len > (BUF_SIZE - sizeof(*header))) { + dev_warn(&card->dev->dev, "Length of PDU is too large. Dropping PDU.\n"); + solos_pop(vcc, skb); + return 0; + } + + if (!skb_clone_writable(skb, sizeof(*header))) { + int expand_by = 0; + int ret; + + if (skb_headroom(skb) < sizeof(*header)) + expand_by = sizeof(*header) - skb_headroom(skb); + + ret = pskb_expand_head(skb, expand_by, 0, GFP_ATOMIC); + if (ret) { + solos_pop(vcc, skb); + return ret; + } + } + + header = (void *)skb_push(skb, sizeof(*header)); + + header->size = cpu_to_le16(skb->len); + header->vpi = cpu_to_le16(vcc->vpi); + header->vci = cpu_to_le16(vcc->vci); + header->type = cpu_to_le16(PKT_DATA); + + fpga_queue(card, SOLOS_CHAN(vcc->dev), skb, vcc); + + return 0; +} + +static struct atmdev_ops fpga_ops = { + .open = popen, + .close = pclose, + .ioctl = NULL, + .getsockopt = NULL, + .setsockopt = NULL, + .send = psend, + .send_oam = NULL, + .phy_put = NULL, + .phy_get = NULL, + .change_qos = NULL, + .proc_read = NULL, + .owner = THIS_MODULE +}; + +static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + int err, i; + uint16_t fpga_ver; + uint8_t major_ver, minor_ver; + uint32_t data32; + struct solos_card *card; + + if (debug) + return 0; + + card = kzalloc(sizeof(*card), GFP_KERNEL); + if (!card) + return -ENOMEM; + + card->dev = dev; + + err = pci_enable_device(dev); + if (err) { + dev_warn(&dev->dev, "Failed to enable PCI device\n"); + goto out; + } + + err = pci_request_regions(dev, "solos"); + if (err) { + dev_warn(&dev->dev, "Failed to request regions\n"); + goto out; + } + + card->config_regs = pci_iomap(dev, 0, CONFIG_RAM_SIZE); + if (!card->config_regs) { + dev_warn(&dev->dev, "Failed to ioremap config registers\n"); + goto out_release_regions; + } + card->buffers = pci_iomap(dev, 1, DATA_RAM_SIZE); + if (!card->buffers) { + dev_warn(&dev->dev, "Failed to ioremap data buffers\n"); + goto out_unmap_config; + } + +// for(i=0;i<64 ;i+=4){ +// data32=ioread32(card->buffers + i); +// dev_dbg(&card->dev->dev, "%08lX\n",(unsigned long)data32); +// } + + //Fill Config Mem with zeros + for(i = 0; i < 128; i += 4) + iowrite32(0, card->config_regs + i); + + //Set RX empty flags + iowrite32(0xF0, card->config_regs + FLAGS_ADDR); + + data32 = ioread32(card->config_regs + FPGA_VER); + fpga_ver = (data32 & 0x0000FFFF); + major_ver = ((data32 & 0xFF000000) >> 24); + minor_ver = ((data32 & 0x00FF0000) >> 16); + dev_info(&dev->dev, "Solos FPGA Version %d.%02d svn-%d\n", + major_ver, minor_ver, fpga_ver); + + card->nr_ports = 2; /* FIXME: Detect daughterboard */ + + err = atm_init(card); + if (err) + goto out_unmap_both; + + pci_set_drvdata(dev, card); + tasklet_init(&card->tlet, solos_bh, (unsigned long)card); + spin_lock_init(&card->tx_lock); + spin_lock_init(&card->tx_queue_lock); + spin_lock_init(&card->cli_queue_lock); +/* + // Set Loopback mode + data32 = 0x00010000; + iowrite32(data32,card->config_regs + FLAGS_ADDR); +*/ +/* + // Fill Buffers with zeros + for (i = 0; i < BUF_SIZE * 8; i += 4) + iowrite32(0, card->buffers + i); +*/ +/* + for(i = 0; i < (BUF_SIZE * 1); i += 4) + iowrite32(0x12345678, card->buffers + i + (0*BUF_SIZE)); + for(i = 0; i < (BUF_SIZE * 1); i += 4) + iowrite32(0xabcdef98, card->buffers + i + (1*BUF_SIZE)); + + // Read Config Memory + printk(KERN_DEBUG "Reading Config MEM\n"); + i = 0; + for(i = 0; i < 16; i++) { + data32=ioread32(card->buffers + i*(BUF_SIZE/2)); + printk(KERN_ALERT "Addr: %lX Data: %08lX\n", + (unsigned long)(addr_start + i*(BUF_SIZE/2)), + (unsigned long)data32); + } +*/ + //dev_dbg(&card->dev->dev, "Requesting IRQ: %d\n",dev->irq); + err = request_irq(dev->irq, solos_irq, IRQF_DISABLED|IRQF_SHARED, + "solos-pci", card); + if (err) + dev_dbg(&card->dev->dev, "Failed to request interrupt IRQ: %d\n", dev->irq); + + // Enable IRQs + iowrite32(1, card->config_regs + IRQ_EN_ADDR); + + return 0; + + out_unmap_both: + pci_iounmap(dev, card->config_regs); + out_unmap_config: + pci_iounmap(dev, card->buffers); + out_release_regions: + pci_release_regions(dev); + out: + return err; +} + +static int atm_init(struct solos_card *card) +{ + int i; + + opens = 0; + + for (i = 0; i < card->nr_ports; i++) { + skb_queue_head_init(&card->tx_queue[i]); + skb_queue_head_init(&card->cli_queue[i]); + + card->atmdev[i] = atm_dev_register("solos-pci", &fpga_ops, -1, NULL); + if (!card->atmdev[i]) { + dev_err(&card->dev->dev, "Could not register ATM device %d\n", i); + atm_remove(card); + return -ENODEV; + } + if (device_create_file(&card->atmdev[i]->class_dev, &dev_attr_console)) + dev_err(&card->dev->dev, "Could not register console for ATM device %d\n", i); + + dev_info(&card->dev->dev, "Registered ATM device %d\n", card->atmdev[i]->number); + + card->atmdev[i]->ci_range.vpi_bits = 8; + card->atmdev[i]->ci_range.vci_bits = 16; + card->atmdev[i]->dev_data = card; + card->atmdev[i]->phy_data = (void *)(unsigned long)i; + } + return 0; +} + +static void atm_remove(struct solos_card *card) +{ + int i; + + for (i = 0; i < card->nr_ports; i++) { + if (card->atmdev[i]) { + dev_info(&card->dev->dev, "Unregistering ATM device %d\n", card->atmdev[i]->number); + atm_dev_deregister(card->atmdev[i]); + } + } +} + +static void fpga_remove(struct pci_dev *dev) +{ + struct solos_card *card = pci_get_drvdata(dev); + + if (debug) + return; + + atm_remove(card); + + dev_vdbg(&dev->dev, "Freeing IRQ\n"); + // Disable IRQs from FPGA + iowrite32(0, card->config_regs + IRQ_EN_ADDR); + free_irq(dev->irq, card); + tasklet_kill(&card->tlet); + + // iowrite32(0x01,pciregs); + dev_vdbg(&dev->dev, "Unmapping PCI resource\n"); + pci_iounmap(dev, card->buffers); + pci_iounmap(dev, card->config_regs); + + dev_vdbg(&dev->dev, "Releasing PCI Region\n"); + pci_release_regions(dev); + pci_disable_device(dev); + + pci_set_drvdata(dev, NULL); + kfree(card); +// dev_dbg(&card->dev->dev, "fpga_remove\n"); + return; +} + +static struct pci_device_id fpga_pci_tbl[] __devinitdata = { + { 0x10ee, 0x0300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci,fpga_pci_tbl); + +static struct pci_driver fpga_driver = { + .name = "solos", + .id_table = fpga_pci_tbl, + .probe = fpga_probe, + .remove = fpga_remove, +}; + + +static int __init solos_pci_init(void) +{ + printk(KERN_INFO "Solos PCI Driver Version %s\n", VERSION); + return pci_register_driver(&fpga_driver); +} + +static void __exit solos_pci_exit(void) +{ + pci_unregister_driver(&fpga_driver); + printk(KERN_INFO "Solos PCI Driver %s Unloaded\n", VERSION); +} + +module_init(solos_pci_init); +module_exit(solos_pci_exit); diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h index 93f3690396a5176de5cec3fb3151ef9e1670299d..c237527b1aa59880b272a13bc8d0a17d6206ca2a 100644 --- a/drivers/block/aoe/aoe.h +++ b/drivers/block/aoe/aoe.h @@ -200,4 +200,3 @@ void aoenet_xmit(struct sk_buff_head *); int is_aoe_netif(struct net_device *ifp); int set_aoe_iflist(const char __user *str, size_t size); -unsigned long long mac_addr(char addr[6]); diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index 1747dd272cd476bd1c14b03be0ee0c8f5faf17dd..2307a271bdc99e91b5c410083383a0595c4c08d0 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -37,7 +37,7 @@ static ssize_t aoedisk_show_mac(struct device *dev, if (t == NULL) return snprintf(page, PAGE_SIZE, "none\n"); - return snprintf(page, PAGE_SIZE, "%012llx\n", mac_addr(t->addr)); + return snprintf(page, PAGE_SIZE, "%pm\n", t->addr); } static ssize_t aoedisk_show_netif(struct device *dev, struct device_attribute *attr, char *page) diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 71ff78c9e4d6c24a3d752cc35956645aa752eb34..45c5a33daf498d623e9749bd75e8f4bf94a9e49e 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -349,11 +349,9 @@ resend(struct aoedev *d, struct aoetgt *t, struct frame *f) ah = (struct aoe_atahdr *) (h+1); snprintf(buf, sizeof buf, - "%15s e%ld.%d oldtag=%08x@%08lx newtag=%08x " - "s=%012llx d=%012llx nout=%d\n", + "%15s e%ld.%d oldtag=%08x@%08lx newtag=%08x s=%pm d=%pm nout=%d\n", "retransmit", d->aoemajor, d->aoeminor, f->tag, jiffies, n, - mac_addr(h->src), - mac_addr(h->dst), t->nout); + h->src, h->dst, t->nout); aoechr_error(buf); f->tag = n; @@ -544,10 +542,10 @@ rexmit_timer(ulong vp) printk(KERN_INFO "aoe: e%ld.%d: " "too many lost jumbo on " - "%s:%012llx - " + "%s:%pm - " "falling back to %d frames.\n", d->aoemajor, d->aoeminor, - ifp->nd->name, mac_addr(t->addr), + ifp->nd->name, t->addr, DEFAULTBCNT); ifp->maxbcnt = 0; } @@ -672,8 +670,8 @@ ataid_complete(struct aoedev *d, struct aoetgt *t, unsigned char *id) if (d->ssize != ssize) printk(KERN_INFO - "aoe: %012llx e%ld.%d v%04x has %llu sectors\n", - mac_addr(t->addr), + "aoe: %pm e%ld.%d v%04x has %llu sectors\n", + t->addr, d->aoemajor, d->aoeminor, d->fw_ver, (long long)ssize); d->ssize = ssize; @@ -775,8 +773,8 @@ aoecmd_ata_rsp(struct sk_buff *skb) n = get_unaligned_be32(&hin->tag); t = gettgt(d, hin->src); if (t == NULL) { - printk(KERN_INFO "aoe: can't find target e%ld.%d:%012llx\n", - d->aoemajor, d->aoeminor, mac_addr(hin->src)); + printk(KERN_INFO "aoe: can't find target e%ld.%d:%pm\n", + d->aoemajor, d->aoeminor, hin->src); spin_unlock_irqrestore(&d->lock, flags); return; } @@ -1036,10 +1034,10 @@ aoecmd_cfg_rsp(struct sk_buff *skb) n = n ? n * 512 : DEFAULTBCNT; if (n != ifp->maxbcnt) { printk(KERN_INFO - "aoe: e%ld.%d: setting %d%s%s:%012llx\n", + "aoe: e%ld.%d: setting %d%s%s:%pm\n", d->aoemajor, d->aoeminor, n, " byte data frames on ", ifp->nd->name, - mac_addr(t->addr)); + t->addr); ifp->maxbcnt = n; } } diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c index 9157d64270cb041ba8b92bc462913439b12018e0..30de5b1c647e80b05007a22f1a4e0b79a38dcad4 100644 --- a/drivers/block/aoe/aoenet.c +++ b/drivers/block/aoe/aoenet.c @@ -83,17 +83,6 @@ set_aoe_iflist(const char __user *user_str, size_t size) return 0; } -unsigned long long -mac_addr(char addr[6]) -{ - __be64 n = 0; - char *p = (char *) &n; - - memcpy(p + 2, addr, 6); /* (sizeof addr != 6) */ - - return (unsigned long long) __be64_to_cpu(n); -} - void aoenet_xmit(struct sk_buff_head *queue) { diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 5c4ee70d5cf319311deab818996928af5f2736f6..fb06ed6592121fe8dbdfa79da727f2a6eac921f5 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -936,8 +936,10 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info) { int err; struct loop_func_table *xfer; + uid_t uid = current_uid(); - if (lo->lo_encrypt_key_size && lo->lo_key_owner != current->uid && + if (lo->lo_encrypt_key_size && + lo->lo_key_owner != uid && !capable(CAP_SYS_ADMIN)) return -EPERM; if (lo->lo_state != Lo_bound) @@ -992,7 +994,7 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info) if (info->lo_encrypt_key_size) { memcpy(lo->lo_encrypt_key, info->lo_encrypt_key, info->lo_encrypt_key_size); - lo->lo_key_owner = current->uid; + lo->lo_key_owner = uid; } return 0; diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 7cb4029a5375a774ed9c0cc888284d37330b1b17..1164837bb781470730768c37f466a17f091095d3 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -2,26 +2,6 @@ menu "Bluetooth device drivers" depends on BT -config BT_HCIUSB - tristate "HCI USB driver (old version)" - depends on USB && BT_HCIBTUSB=n - help - Bluetooth HCI USB driver. - This driver is required if you want to use Bluetooth devices with - USB interface. - - Say Y here to compile support for Bluetooth USB devices into the - kernel or say M to compile it as module (hci_usb). - -config BT_HCIUSB_SCO - bool "SCO (voice) support" - depends on BT_HCIUSB - help - This option enables the SCO support in the HCI USB driver. You need this - to transmit voice data with your Bluetooth USB device. - - Say Y here to compile support for SCO over HCI USB. - config BT_HCIBTUSB tristate "HCI USB driver" depends on USB diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile index 77444afbf107281de422a950d1e0a4ac63469cc0..16930f93d1ca4db6ffaf08df3e2f5fb4132ea076 100644 --- a/drivers/bluetooth/Makefile +++ b/drivers/bluetooth/Makefile @@ -2,7 +2,6 @@ # Makefile for the Linux Bluetooth HCI device drivers. # -obj-$(CONFIG_BT_HCIUSB) += hci_usb.o obj-$(CONFIG_BT_HCIVHCI) += hci_vhci.o obj-$(CONFIG_BT_HCIUART) += hci_uart.o obj-$(CONFIG_BT_HCIBCM203X) += bcm203x.o diff --git a/drivers/bluetooth/bcm203x.c b/drivers/bluetooth/bcm203x.c index ee40201c7278ad94aadf43ac220c1cedfd67c49e..eafd4af0746e7bb2a6004e48604cf86e6ab1c109 100644 --- a/drivers/bluetooth/bcm203x.c +++ b/drivers/bluetooth/bcm203x.c @@ -37,11 +37,6 @@ #include -#ifndef CONFIG_BT_HCIBCM203X_DEBUG -#undef BT_DBG -#define BT_DBG(D...) -#endif - #define VERSION "1.2" static struct usb_device_id bcm203x_table[] = { @@ -199,7 +194,7 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id return -EIO; } - BT_DBG("minidrv data %p size %d", firmware->data, firmware->size); + BT_DBG("minidrv data %p size %zu", firmware->data, firmware->size); size = max_t(uint, firmware->size, 4096); @@ -227,7 +222,7 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id return -EIO; } - BT_DBG("firmware data %p size %d", firmware->data, firmware->size); + BT_DBG("firmware data %p size %zu", firmware->data, firmware->size); data->fw_data = kmalloc(firmware->size, GFP_KERNEL); if (!data->fw_data) { diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c index 90a0946346303c4d654afd215bfbcda2c9e66f1b..d3f14bee0f1939fcb1ff0261e6018b0f99e1689e 100644 --- a/drivers/bluetooth/bfusb.c +++ b/drivers/bluetooth/bfusb.c @@ -38,11 +38,6 @@ #include #include -#ifndef CONFIG_BT_HCIBFUSB_DEBUG -#undef BT_DBG -#define BT_DBG(D...) -#endif - #define VERSION "1.2" static struct usb_driver bfusb_driver; @@ -221,7 +216,7 @@ static int bfusb_rx_submit(struct bfusb_data *data, struct urb *urb) struct sk_buff *skb; int err, pipe, size = HCI_MAX_FRAME_SIZE + 32; - BT_DBG("bfusb %p urb %p", bfusb, urb); + BT_DBG("bfusb %p urb %p", data, urb); if (!urb && !(urb = usb_alloc_urb(0, GFP_ATOMIC))) return -ENOMEM; @@ -354,7 +349,7 @@ static void bfusb_rx_complete(struct urb *urb) int count = urb->actual_length; int err, hdr, len; - BT_DBG("bfusb %p urb %p skb %p len %d", bfusb, urb, skb, skb->len); + BT_DBG("bfusb %p urb %p skb %p len %d", data, urb, skb, skb->len); read_lock(&data->lock); @@ -691,7 +686,7 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i goto error; } - BT_DBG("firmware data %p size %d", firmware->data, firmware->size); + BT_DBG("firmware data %p size %zu", firmware->data, firmware->size); if (bfusb_load_firmware(data, firmware->data, firmware->size) < 0) { BT_ERR("Firmware loading failed"); diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c index b936d8ce2728836c2ba3c214a2cf93960886187f..c115285867c3010495b74da4b7eccfd910e518cb 100644 --- a/drivers/bluetooth/bpa10x.c +++ b/drivers/bluetooth/bpa10x.c @@ -35,11 +35,6 @@ #include #include -#ifndef CONFIG_BT_HCIBPA10X_DEBUG -#undef BT_DBG -#define BT_DBG(D...) -#endif - #define VERSION "0.10" static struct usb_device_id bpa10x_table[] = { @@ -489,6 +484,8 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id * hdev->owner = THIS_MODULE; + set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); + err = hci_register_dev(hdev); if (err < 0) { hci_free_dev(hdev); diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index b3e4d07a4ac2b75bd73a1caf3c91be36c8124a62..ff195c23082587e03a957043cb48dd009984d745 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -502,15 +502,15 @@ static int bt3c_load_firmware(bt3c_info_t *info, const unsigned char *firmware, memset(b, 0, sizeof(b)); memcpy(b, ptr + 2, 2); - size = simple_strtol(b, NULL, 16); + size = simple_strtoul(b, NULL, 16); memset(b, 0, sizeof(b)); memcpy(b, ptr + 4, 8); - addr = simple_strtol(b, NULL, 16); + addr = simple_strtoul(b, NULL, 16); memset(b, 0, sizeof(b)); memcpy(b, ptr + (size * 2) + 2, 2); - fcs = simple_strtol(b, NULL, 16); + fcs = simple_strtoul(b, NULL, 16); memset(b, 0, sizeof(b)); for (tmp = 0, i = 0; i < size; i++) { @@ -530,7 +530,7 @@ static int bt3c_load_firmware(bt3c_info_t *info, const unsigned char *firmware, memset(b, 0, sizeof(b)); for (i = 0; i < (size - 4) / 2; i++) { memcpy(b, ptr + (i * 4) + 12, 4); - tmp = simple_strtol(b, NULL, 16); + tmp = simple_strtoul(b, NULL, 16); bt3c_put(iobase, tmp); } } diff --git a/drivers/bluetooth/btsdio.c b/drivers/bluetooth/btsdio.c index cda6c7cc944b1470a00ab1bafc8942236417b30a..7e298275c8f663b45fc04f57e5499c9f372b62d5 100644 --- a/drivers/bluetooth/btsdio.c +++ b/drivers/bluetooth/btsdio.c @@ -37,11 +37,6 @@ #include #include -#ifndef CONFIG_BT_HCIBTSDIO_DEBUG -#undef BT_DBG -#define BT_DBG(D...) -#endif - #define VERSION "0.1" static const struct sdio_device_id btsdio_table[] = { @@ -91,6 +86,7 @@ static int btsdio_tx_packet(struct btsdio_data *data, struct sk_buff *skb) err = sdio_writesb(data->func, REG_TDAT, skb->data, skb->len); if (err < 0) { + skb_pull(skb, 4); sdio_writeb(data->func, 0x01, REG_PC_WRT, NULL); return err; } diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index af472e05273296e664e8ddcb7fa443f4bc0e60e8..b5fbda6d490a4a142e5a11936b3e14260a09d3de 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -35,31 +35,25 @@ #include #include -//#define CONFIG_BT_HCIBTUSB_DEBUG -#ifndef CONFIG_BT_HCIBTUSB_DEBUG -#undef BT_DBG -#define BT_DBG(D...) -#endif - -#define VERSION "0.3" +#define VERSION "0.4" static int ignore_dga; static int ignore_csr; static int ignore_sniffer; static int disable_scofix; static int force_scofix; -static int reset; + +static int reset = 1; static struct usb_driver btusb_driver; #define BTUSB_IGNORE 0x01 -#define BTUSB_RESET 0x02 -#define BTUSB_DIGIANSWER 0x04 -#define BTUSB_CSR 0x08 -#define BTUSB_SNIFFER 0x10 -#define BTUSB_BCM92035 0x20 -#define BTUSB_BROKEN_ISOC 0x40 -#define BTUSB_WRONG_SCO_MTU 0x80 +#define BTUSB_DIGIANSWER 0x02 +#define BTUSB_CSR 0x04 +#define BTUSB_SNIFFER 0x08 +#define BTUSB_BCM92035 0x10 +#define BTUSB_BROKEN_ISOC 0x20 +#define BTUSB_WRONG_SCO_MTU 0x40 static struct usb_device_id btusb_table[] = { /* Generic Bluetooth USB device */ @@ -79,7 +73,7 @@ static struct usb_device_id btusb_table[] = { { USB_DEVICE(0x0bdb, 0x1002) }, /* Canyon CN-BTU1 with HID interfaces */ - { USB_DEVICE(0x0c10, 0x0000), .driver_info = BTUSB_RESET }, + { USB_DEVICE(0x0c10, 0x0000) }, { } /* Terminating entry */ }; @@ -94,52 +88,37 @@ static struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x0a5c, 0x2033), .driver_info = BTUSB_IGNORE }, /* Broadcom BCM2035 */ - { USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU }, - { USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU }, + { USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU }, + { USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU }, + { USB_DEVICE(0x0a5c, 0x2009), .driver_info = BTUSB_BCM92035 }, /* Broadcom BCM2045 */ - { USB_DEVICE(0x0a5c, 0x2039), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU }, - { USB_DEVICE(0x0a5c, 0x2101), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU }, - - /* Broadcom BCM2046 */ - { USB_DEVICE(0x0a5c, 0x2146), .driver_info = BTUSB_RESET }, - { USB_DEVICE(0x0a5c, 0x2151), .driver_info = BTUSB_RESET }, - - /* Apple MacBook Pro with Broadcom chip */ - { USB_DEVICE(0x05ac, 0x820f), .driver_info = BTUSB_RESET }, + { USB_DEVICE(0x0a5c, 0x2039), .driver_info = BTUSB_WRONG_SCO_MTU }, + { USB_DEVICE(0x0a5c, 0x2101), .driver_info = BTUSB_WRONG_SCO_MTU }, /* IBM/Lenovo ThinkPad with Broadcom chip */ - { USB_DEVICE(0x0a5c, 0x201e), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU }, - { USB_DEVICE(0x0a5c, 0x2110), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU }, - - /* Targus ACB10US */ - { USB_DEVICE(0x0a5c, 0x2100), .driver_info = BTUSB_RESET }, - { USB_DEVICE(0x0a5c, 0x2154), .driver_info = BTUSB_RESET }, - - /* ANYCOM Bluetooth USB-200 and USB-250 */ - { USB_DEVICE(0x0a5c, 0x2111), .driver_info = BTUSB_RESET }, + { USB_DEVICE(0x0a5c, 0x201e), .driver_info = BTUSB_WRONG_SCO_MTU }, + { USB_DEVICE(0x0a5c, 0x2110), .driver_info = BTUSB_WRONG_SCO_MTU }, /* HP laptop with Broadcom chip */ - { USB_DEVICE(0x03f0, 0x171d), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU }, + { USB_DEVICE(0x03f0, 0x171d), .driver_info = BTUSB_WRONG_SCO_MTU }, /* Dell laptop with Broadcom chip */ - { USB_DEVICE(0x413c, 0x8126), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU }, + { USB_DEVICE(0x413c, 0x8126), .driver_info = BTUSB_WRONG_SCO_MTU }, - /* Dell Wireless 370 */ - { USB_DEVICE(0x413c, 0x8156), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU }, + /* Dell Wireless 370 and 410 devices */ + { USB_DEVICE(0x413c, 0x8152), .driver_info = BTUSB_WRONG_SCO_MTU }, + { USB_DEVICE(0x413c, 0x8156), .driver_info = BTUSB_WRONG_SCO_MTU }, - /* Dell Wireless 410 */ - { USB_DEVICE(0x413c, 0x8152), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU }, + /* Belkin F8T012 and F8T013 devices */ + { USB_DEVICE(0x050d, 0x0012), .driver_info = BTUSB_WRONG_SCO_MTU }, + { USB_DEVICE(0x050d, 0x0013), .driver_info = BTUSB_WRONG_SCO_MTU }, - /* Microsoft Wireless Transceiver for Bluetooth 2.0 */ - { USB_DEVICE(0x045e, 0x009c), .driver_info = BTUSB_RESET }, + /* Asus WL-BTD202 device */ + { USB_DEVICE(0x0b05, 0x1715), .driver_info = BTUSB_WRONG_SCO_MTU }, /* Kensington Bluetooth USB adapter */ - { USB_DEVICE(0x047d, 0x105d), .driver_info = BTUSB_RESET }, - { USB_DEVICE(0x047d, 0x105e), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU }, - - /* ISSC Bluetooth Adapter v3.1 */ - { USB_DEVICE(0x1131, 0x1001), .driver_info = BTUSB_RESET }, + { USB_DEVICE(0x047d, 0x105e), .driver_info = BTUSB_WRONG_SCO_MTU }, /* RTX Telecom based adapters with buggy SCO support */ { USB_DEVICE(0x0400, 0x0807), .driver_info = BTUSB_BROKEN_ISOC }, @@ -148,13 +127,6 @@ static struct usb_device_id blacklist_table[] = { /* CONWISE Technology based adapters with buggy SCO support */ { USB_DEVICE(0x0e5e, 0x6622), .driver_info = BTUSB_BROKEN_ISOC }, - /* Belkin F8T012 and F8T013 devices */ - { USB_DEVICE(0x050d, 0x0012), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU }, - { USB_DEVICE(0x050d, 0x0013), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU }, - - /* Belkin F8T016 device */ - { USB_DEVICE(0x050d, 0x016a), .driver_info = BTUSB_RESET }, - /* Digianswer devices */ { USB_DEVICE(0x08fd, 0x0001), .driver_info = BTUSB_DIGIANSWER }, { USB_DEVICE(0x08fd, 0x0002), .driver_info = BTUSB_IGNORE }, @@ -197,7 +169,10 @@ struct btusb_data { struct usb_endpoint_descriptor *isoc_tx_ep; struct usb_endpoint_descriptor *isoc_rx_ep; + __u8 cmdreq_type; + int isoc_altsetting; + int suspend_count; }; static void btusb_intr_complete(struct urb *urb) @@ -236,7 +211,7 @@ static void btusb_intr_complete(struct urb *urb) } } -static int btusb_submit_intr_urb(struct hci_dev *hdev) +static int btusb_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags) { struct btusb_data *data = hdev->driver_data; struct urb *urb; @@ -249,13 +224,13 @@ static int btusb_submit_intr_urb(struct hci_dev *hdev) if (!data->intr_ep) return -ENODEV; - urb = usb_alloc_urb(0, GFP_ATOMIC); + urb = usb_alloc_urb(0, mem_flags); if (!urb) return -ENOMEM; size = le16_to_cpu(data->intr_ep->wMaxPacketSize); - buf = kmalloc(size, GFP_ATOMIC); + buf = kmalloc(size, mem_flags); if (!buf) { usb_free_urb(urb); return -ENOMEM; @@ -271,7 +246,7 @@ static int btusb_submit_intr_urb(struct hci_dev *hdev) usb_anchor_urb(urb, &data->intr_anchor); - err = usb_submit_urb(urb, GFP_ATOMIC); + err = usb_submit_urb(urb, mem_flags); if (err < 0) { BT_ERR("%s urb %p submission failed (%d)", hdev->name, urb, -err); @@ -319,7 +294,7 @@ static void btusb_bulk_complete(struct urb *urb) } } -static int btusb_submit_bulk_urb(struct hci_dev *hdev) +static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags) { struct btusb_data *data = hdev->driver_data; struct urb *urb; @@ -332,13 +307,13 @@ static int btusb_submit_bulk_urb(struct hci_dev *hdev) if (!data->bulk_rx_ep) return -ENODEV; - urb = usb_alloc_urb(0, GFP_KERNEL); + urb = usb_alloc_urb(0, mem_flags); if (!urb) return -ENOMEM; size = le16_to_cpu(data->bulk_rx_ep->wMaxPacketSize); - buf = kmalloc(size, GFP_KERNEL); + buf = kmalloc(size, mem_flags); if (!buf) { usb_free_urb(urb); return -ENOMEM; @@ -353,7 +328,7 @@ static int btusb_submit_bulk_urb(struct hci_dev *hdev) usb_anchor_urb(urb, &data->bulk_anchor); - err = usb_submit_urb(urb, GFP_KERNEL); + err = usb_submit_urb(urb, mem_flags); if (err < 0) { BT_ERR("%s urb %p submission failed (%d)", hdev->name, urb, -err); @@ -430,7 +405,7 @@ static void inline __fill_isoc_descriptor(struct urb *urb, int len, int mtu) urb->number_of_packets = i; } -static int btusb_submit_isoc_urb(struct hci_dev *hdev) +static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags) { struct btusb_data *data = hdev->driver_data; struct urb *urb; @@ -443,14 +418,14 @@ static int btusb_submit_isoc_urb(struct hci_dev *hdev) if (!data->isoc_rx_ep) return -ENODEV; - urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_KERNEL); + urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, mem_flags); if (!urb) return -ENOMEM; size = le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize) * BTUSB_MAX_ISOC_FRAMES; - buf = kmalloc(size, GFP_KERNEL); + buf = kmalloc(size, mem_flags); if (!buf) { usb_free_urb(urb); return -ENOMEM; @@ -473,7 +448,7 @@ static int btusb_submit_isoc_urb(struct hci_dev *hdev) usb_anchor_urb(urb, &data->isoc_anchor); - err = usb_submit_urb(urb, GFP_KERNEL); + err = usb_submit_urb(urb, mem_flags); if (err < 0) { BT_ERR("%s urb %p submission failed (%d)", hdev->name, urb, -err); @@ -520,7 +495,7 @@ static int btusb_open(struct hci_dev *hdev) if (test_and_set_bit(BTUSB_INTR_RUNNING, &data->flags)) return 0; - err = btusb_submit_intr_urb(hdev); + err = btusb_submit_intr_urb(hdev, GFP_KERNEL); if (err < 0) { clear_bit(BTUSB_INTR_RUNNING, &data->flags); clear_bit(HCI_RUNNING, &hdev->flags); @@ -589,7 +564,7 @@ static int btusb_send_frame(struct sk_buff *skb) return -ENOMEM; } - dr->bRequestType = USB_TYPE_CLASS; + dr->bRequestType = data->cmdreq_type; dr->bRequest = 0; dr->wIndex = 0; dr->wValue = 0; @@ -680,8 +655,19 @@ static void btusb_notify(struct hci_dev *hdev, unsigned int evt) BT_DBG("%s evt %d", hdev->name, evt); - if (evt == HCI_NOTIFY_CONN_ADD || evt == HCI_NOTIFY_CONN_DEL) - schedule_work(&data->work); + if (hdev->conn_hash.acl_num > 0) { + if (!test_and_set_bit(BTUSB_BULK_RUNNING, &data->flags)) { + if (btusb_submit_bulk_urb(hdev, GFP_ATOMIC) < 0) + clear_bit(BTUSB_BULK_RUNNING, &data->flags); + else + btusb_submit_bulk_urb(hdev, GFP_ATOMIC); + } + } else { + clear_bit(BTUSB_BULK_RUNNING, &data->flags); + usb_unlink_anchored_urbs(&data->bulk_anchor); + } + + schedule_work(&data->work); } static int inline __set_isoc_interface(struct hci_dev *hdev, int altsetting) @@ -732,18 +718,6 @@ static void btusb_work(struct work_struct *work) struct btusb_data *data = container_of(work, struct btusb_data, work); struct hci_dev *hdev = data->hdev; - if (hdev->conn_hash.acl_num > 0) { - if (!test_and_set_bit(BTUSB_BULK_RUNNING, &data->flags)) { - if (btusb_submit_bulk_urb(hdev) < 0) - clear_bit(BTUSB_BULK_RUNNING, &data->flags); - else - btusb_submit_bulk_urb(hdev); - } - } else { - clear_bit(BTUSB_BULK_RUNNING, &data->flags); - usb_kill_anchored_urbs(&data->bulk_anchor); - } - if (hdev->conn_hash.sco_num > 0) { if (data->isoc_altsetting != 2) { clear_bit(BTUSB_ISOC_RUNNING, &data->flags); @@ -754,10 +728,10 @@ static void btusb_work(struct work_struct *work) } if (!test_and_set_bit(BTUSB_ISOC_RUNNING, &data->flags)) { - if (btusb_submit_isoc_urb(hdev) < 0) + if (btusb_submit_isoc_urb(hdev, GFP_KERNEL) < 0) clear_bit(BTUSB_ISOC_RUNNING, &data->flags); else - btusb_submit_isoc_urb(hdev); + btusb_submit_isoc_urb(hdev, GFP_KERNEL); } } else { clear_bit(BTUSB_ISOC_RUNNING, &data->flags); @@ -828,6 +802,8 @@ static int btusb_probe(struct usb_interface *intf, return -ENODEV; } + data->cmdreq_type = USB_TYPE_CLASS; + data->udev = interface_to_usbdev(intf); data->intf = intf; @@ -862,11 +838,11 @@ static int btusb_probe(struct usb_interface *intf, hdev->owner = THIS_MODULE; - /* interface numbers are hardcoded in the spec */ + /* Interface numbers are hardcoded in the specification */ data->isoc = usb_ifnum_to_if(data->udev, 1); - if (reset || id->driver_info & BTUSB_RESET) - set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks); + if (!reset) + set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); if (force_scofix || id->driver_info & BTUSB_WRONG_SCO_MTU) { if (!disable_scofix) @@ -876,9 +852,23 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_BROKEN_ISOC) data->isoc = NULL; + if (id->driver_info & BTUSB_DIGIANSWER) { + data->cmdreq_type = USB_TYPE_VENDOR; + set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); + } + + if (id->driver_info & BTUSB_CSR) { + struct usb_device *udev = data->udev; + + /* Old firmware would otherwise execute USB reset */ + if (le16_to_cpu(udev->descriptor.bcdDevice) < 0x117) + set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); + } + if (id->driver_info & BTUSB_SNIFFER) { struct usb_device *udev = data->udev; + /* New sniffer firmware has crippled HCI interface */ if (le16_to_cpu(udev->descriptor.bcdDevice) > 0x997) set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); @@ -949,10 +939,71 @@ static void btusb_disconnect(struct usb_interface *intf) hci_free_dev(hdev); } +static int btusb_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct btusb_data *data = usb_get_intfdata(intf); + + BT_DBG("intf %p", intf); + + if (data->suspend_count++) + return 0; + + cancel_work_sync(&data->work); + + usb_kill_anchored_urbs(&data->tx_anchor); + + usb_kill_anchored_urbs(&data->isoc_anchor); + usb_kill_anchored_urbs(&data->bulk_anchor); + usb_kill_anchored_urbs(&data->intr_anchor); + + return 0; +} + +static int btusb_resume(struct usb_interface *intf) +{ + struct btusb_data *data = usb_get_intfdata(intf); + struct hci_dev *hdev = data->hdev; + int err; + + BT_DBG("intf %p", intf); + + if (--data->suspend_count) + return 0; + + if (!test_bit(HCI_RUNNING, &hdev->flags)) + return 0; + + if (test_bit(BTUSB_INTR_RUNNING, &data->flags)) { + err = btusb_submit_intr_urb(hdev, GFP_NOIO); + if (err < 0) { + clear_bit(BTUSB_INTR_RUNNING, &data->flags); + return err; + } + } + + if (test_bit(BTUSB_BULK_RUNNING, &data->flags)) { + if (btusb_submit_bulk_urb(hdev, GFP_NOIO) < 0) + clear_bit(BTUSB_BULK_RUNNING, &data->flags); + else + btusb_submit_bulk_urb(hdev, GFP_NOIO); + } + + if (test_bit(BTUSB_ISOC_RUNNING, &data->flags)) { + if (btusb_submit_isoc_urb(hdev, GFP_NOIO) < 0) + clear_bit(BTUSB_ISOC_RUNNING, &data->flags); + else + btusb_submit_isoc_urb(hdev, GFP_NOIO); + } + + return 0; +} + static struct usb_driver btusb_driver = { .name = "btusb", .probe = btusb_probe, .disconnect = btusb_disconnect, + .suspend = btusb_suspend, + .resume = btusb_resume, .id_table = btusb_table, }; diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c index 7938062c1cc7a13daf1306baa659c6cf477782be..894b2cb11ea6caf808ff55b6c3135d42e9ad33b5 100644 --- a/drivers/bluetooth/hci_bcsp.c +++ b/drivers/bluetooth/hci_bcsp.c @@ -47,11 +47,6 @@ #include "hci_uart.h" -#ifndef CONFIG_BT_HCIUART_DEBUG -#undef BT_DBG -#define BT_DBG( A... ) -#endif - #define VERSION "0.3" static int txcrc = 1; diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c index bfbae14cf93d0fe388fc879ff5ca5ed69b99a5f9..b0fafb0559964762ee7db79a32dd336d34e2017b 100644 --- a/drivers/bluetooth/hci_h4.c +++ b/drivers/bluetooth/hci_h4.c @@ -46,11 +46,6 @@ #include "hci_uart.h" -#ifndef CONFIG_BT_HCIUART_DEBUG -#undef BT_DBG -#define BT_DBG( A... ) -#endif - #define VERSION "1.2" struct h4_struct { diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 4426bb552bd90849b8df4e06c1a8e03f2a4af12f..af761dc434f638e9ab869a8e8d8508a98adbd175 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -46,11 +46,6 @@ #include "hci_uart.h" -#ifndef CONFIG_BT_HCIUART_DEBUG -#undef BT_DBG -#define BT_DBG( A... ) -#endif - #define VERSION "2.2" static int reset = 0; @@ -399,8 +394,8 @@ static int hci_uart_register_dev(struct hci_uart *hu) hdev->owner = THIS_MODULE; - if (reset) - set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks); + if (!reset) + set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); if (hci_register_dev(hdev) < 0) { BT_ERR("Can't register HCI device"); diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c deleted file mode 100644 index 3c453924f8386c9b92050ae978967d188ec3b4da..0000000000000000000000000000000000000000 --- a/drivers/bluetooth/hci_usb.c +++ /dev/null @@ -1,1136 +0,0 @@ -/* - HCI USB driver for Linux Bluetooth protocol stack (BlueZ) - Copyright (C) 2000-2001 Qualcomm Incorporated - Written 2000,2001 by Maxim Krasnyansky - - Copyright (C) 2003 Maxim Krasnyansky - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. - IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY - CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, - COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS - SOFTWARE IS DISCLAIMED. -*/ - -/* - * Bluetooth HCI USB driver. - * Based on original USB Bluetooth driver for Linux kernel - * Copyright (c) 2000 Greg Kroah-Hartman - * Copyright (c) 2000 Mark Douglas Corner - * - */ - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include - -#include "hci_usb.h" - -#ifndef CONFIG_BT_HCIUSB_DEBUG -#undef BT_DBG -#define BT_DBG(D...) -#endif - -#ifndef CONFIG_BT_HCIUSB_ZERO_PACKET -#undef URB_ZERO_PACKET -#define URB_ZERO_PACKET 0 -#endif - -static int ignore_dga; -static int ignore_csr; -static int ignore_sniffer; -static int disable_scofix; -static int force_scofix; -static int reset; - -#ifdef CONFIG_BT_HCIUSB_SCO -static int isoc = 2; -#endif - -#define VERSION "2.10" - -static struct usb_driver hci_usb_driver; - -static struct usb_device_id bluetooth_ids[] = { - /* Generic Bluetooth USB device */ - { USB_DEVICE_INFO(HCI_DEV_CLASS, HCI_DEV_SUBCLASS, HCI_DEV_PROTOCOL) }, - - /* AVM BlueFRITZ! USB v2.0 */ - { USB_DEVICE(0x057c, 0x3800) }, - - /* Bluetooth Ultraport Module from IBM */ - { USB_DEVICE(0x04bf, 0x030a) }, - - /* ALPS Modules with non-standard id */ - { USB_DEVICE(0x044e, 0x3001) }, - { USB_DEVICE(0x044e, 0x3002) }, - - /* Ericsson with non-standard id */ - { USB_DEVICE(0x0bdb, 0x1002) }, - - /* Canyon CN-BTU1 with HID interfaces */ - { USB_DEVICE(0x0c10, 0x0000), .driver_info = HCI_RESET }, - - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE (usb, bluetooth_ids); - -static struct usb_device_id blacklist_ids[] = { - /* CSR BlueCore devices */ - { USB_DEVICE(0x0a12, 0x0001), .driver_info = HCI_CSR }, - - /* Broadcom BCM2033 without firmware */ - { USB_DEVICE(0x0a5c, 0x2033), .driver_info = HCI_IGNORE }, - - /* Broadcom BCM2035 */ - { USB_DEVICE(0x0a5c, 0x2035), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, - { USB_DEVICE(0x0a5c, 0x200a), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, - { USB_DEVICE(0x0a5c, 0x2009), .driver_info = HCI_BCM92035 }, - - /* Broadcom BCM2045 */ - { USB_DEVICE(0x0a5c, 0x2039), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, - { USB_DEVICE(0x0a5c, 0x2101), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, - - /* IBM/Lenovo ThinkPad with Broadcom chip */ - { USB_DEVICE(0x0a5c, 0x201e), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, - { USB_DEVICE(0x0a5c, 0x2110), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, - - /* Targus ACB10US */ - { USB_DEVICE(0x0a5c, 0x2100), .driver_info = HCI_RESET }, - - /* ANYCOM Bluetooth USB-200 and USB-250 */ - { USB_DEVICE(0x0a5c, 0x2111), .driver_info = HCI_RESET }, - - /* HP laptop with Broadcom chip */ - { USB_DEVICE(0x03f0, 0x171d), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, - - /* Dell laptop with Broadcom chip */ - { USB_DEVICE(0x413c, 0x8126), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, - /* Dell Wireless 370 */ - { USB_DEVICE(0x413c, 0x8156), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, - /* Dell Wireless 410 */ - { USB_DEVICE(0x413c, 0x8152), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, - - /* Broadcom 2046 */ - { USB_DEVICE(0x0a5c, 0x2151), .driver_info = HCI_RESET }, - - /* Microsoft Wireless Transceiver for Bluetooth 2.0 */ - { USB_DEVICE(0x045e, 0x009c), .driver_info = HCI_RESET }, - - /* Kensington Bluetooth USB adapter */ - { USB_DEVICE(0x047d, 0x105d), .driver_info = HCI_RESET }, - { USB_DEVICE(0x047d, 0x105e), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, - - /* ISSC Bluetooth Adapter v3.1 */ - { USB_DEVICE(0x1131, 0x1001), .driver_info = HCI_RESET }, - - /* RTX Telecom based adapters with buggy SCO support */ - { USB_DEVICE(0x0400, 0x0807), .driver_info = HCI_BROKEN_ISOC }, - { USB_DEVICE(0x0400, 0x080a), .driver_info = HCI_BROKEN_ISOC }, - - /* CONWISE Technology based adapters with buggy SCO support */ - { USB_DEVICE(0x0e5e, 0x6622), .driver_info = HCI_BROKEN_ISOC }, - - /* Belkin F8T012 and F8T013 devices */ - { USB_DEVICE(0x050d, 0x0012), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, - { USB_DEVICE(0x050d, 0x0013), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, - - /* Digianswer devices */ - { USB_DEVICE(0x08fd, 0x0001), .driver_info = HCI_DIGIANSWER }, - { USB_DEVICE(0x08fd, 0x0002), .driver_info = HCI_IGNORE }, - - /* CSR BlueCore Bluetooth Sniffer */ - { USB_DEVICE(0x0a12, 0x0002), .driver_info = HCI_SNIFFER }, - - /* Frontline ComProbe Bluetooth Sniffer */ - { USB_DEVICE(0x16d3, 0x0002), .driver_info = HCI_SNIFFER }, - - { } /* Terminating entry */ -}; - -static struct _urb *_urb_alloc(int isoc, gfp_t gfp) -{ - struct _urb *_urb = kmalloc(sizeof(struct _urb) + - sizeof(struct usb_iso_packet_descriptor) * isoc, gfp); - if (_urb) { - memset(_urb, 0, sizeof(*_urb)); - usb_init_urb(&_urb->urb); - } - return _urb; -} - -static struct _urb *_urb_dequeue(struct _urb_queue *q) -{ - struct _urb *_urb = NULL; - unsigned long flags; - spin_lock_irqsave(&q->lock, flags); - { - struct list_head *head = &q->head; - struct list_head *next = head->next; - if (next != head) { - _urb = list_entry(next, struct _urb, list); - list_del(next); _urb->queue = NULL; - } - } - spin_unlock_irqrestore(&q->lock, flags); - return _urb; -} - -static void hci_usb_rx_complete(struct urb *urb); -static void hci_usb_tx_complete(struct urb *urb); - -#define __pending_tx(husb, type) (&husb->pending_tx[type-1]) -#define __pending_q(husb, type) (&husb->pending_q[type-1]) -#define __completed_q(husb, type) (&husb->completed_q[type-1]) -#define __transmit_q(husb, type) (&husb->transmit_q[type-1]) - -static inline struct _urb *__get_completed(struct hci_usb *husb, int type) -{ - return _urb_dequeue(__completed_q(husb, type)); -} - -#ifdef CONFIG_BT_HCIUSB_SCO -static void __fill_isoc_desc(struct urb *urb, int len, int mtu) -{ - int offset = 0, i; - - BT_DBG("len %d mtu %d", len, mtu); - - for (i=0; i < HCI_MAX_ISOC_FRAMES && len >= mtu; i++, offset += mtu, len -= mtu) { - urb->iso_frame_desc[i].offset = offset; - urb->iso_frame_desc[i].length = mtu; - BT_DBG("desc %d offset %d len %d", i, offset, mtu); - } - if (len && i < HCI_MAX_ISOC_FRAMES) { - urb->iso_frame_desc[i].offset = offset; - urb->iso_frame_desc[i].length = len; - BT_DBG("desc %d offset %d len %d", i, offset, len); - i++; - } - urb->number_of_packets = i; -} -#endif - -static int hci_usb_intr_rx_submit(struct hci_usb *husb) -{ - struct _urb *_urb; - struct urb *urb; - int err, pipe, interval, size; - void *buf; - - BT_DBG("%s", husb->hdev->name); - - size = le16_to_cpu(husb->intr_in_ep->desc.wMaxPacketSize); - - buf = kmalloc(size, GFP_ATOMIC); - if (!buf) - return -ENOMEM; - - _urb = _urb_alloc(0, GFP_ATOMIC); - if (!_urb) { - kfree(buf); - return -ENOMEM; - } - _urb->type = HCI_EVENT_PKT; - _urb_queue_tail(__pending_q(husb, _urb->type), _urb); - - urb = &_urb->urb; - pipe = usb_rcvintpipe(husb->udev, husb->intr_in_ep->desc.bEndpointAddress); - interval = husb->intr_in_ep->desc.bInterval; - usb_fill_int_urb(urb, husb->udev, pipe, buf, size, hci_usb_rx_complete, husb, interval); - - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err) { - BT_ERR("%s intr rx submit failed urb %p err %d", - husb->hdev->name, urb, err); - _urb_unlink(_urb); - kfree(_urb); - kfree(buf); - } - return err; -} - -static int hci_usb_bulk_rx_submit(struct hci_usb *husb) -{ - struct _urb *_urb; - struct urb *urb; - int err, pipe, size = HCI_MAX_FRAME_SIZE; - void *buf; - - buf = kmalloc(size, GFP_ATOMIC); - if (!buf) - return -ENOMEM; - - _urb = _urb_alloc(0, GFP_ATOMIC); - if (!_urb) { - kfree(buf); - return -ENOMEM; - } - _urb->type = HCI_ACLDATA_PKT; - _urb_queue_tail(__pending_q(husb, _urb->type), _urb); - - urb = &_urb->urb; - pipe = usb_rcvbulkpipe(husb->udev, husb->bulk_in_ep->desc.bEndpointAddress); - usb_fill_bulk_urb(urb, husb->udev, pipe, buf, size, hci_usb_rx_complete, husb); - urb->transfer_flags = 0; - - BT_DBG("%s urb %p", husb->hdev->name, urb); - - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err) { - BT_ERR("%s bulk rx submit failed urb %p err %d", - husb->hdev->name, urb, err); - _urb_unlink(_urb); - kfree(_urb); - kfree(buf); - } - return err; -} - -#ifdef CONFIG_BT_HCIUSB_SCO -static int hci_usb_isoc_rx_submit(struct hci_usb *husb) -{ - struct _urb *_urb; - struct urb *urb; - int err, mtu, size; - void *buf; - - mtu = le16_to_cpu(husb->isoc_in_ep->desc.wMaxPacketSize); - size = mtu * HCI_MAX_ISOC_FRAMES; - - buf = kmalloc(size, GFP_ATOMIC); - if (!buf) - return -ENOMEM; - - _urb = _urb_alloc(HCI_MAX_ISOC_FRAMES, GFP_ATOMIC); - if (!_urb) { - kfree(buf); - return -ENOMEM; - } - _urb->type = HCI_SCODATA_PKT; - _urb_queue_tail(__pending_q(husb, _urb->type), _urb); - - urb = &_urb->urb; - - urb->context = husb; - urb->dev = husb->udev; - urb->pipe = usb_rcvisocpipe(husb->udev, husb->isoc_in_ep->desc.bEndpointAddress); - urb->complete = hci_usb_rx_complete; - - urb->interval = husb->isoc_in_ep->desc.bInterval; - - urb->transfer_buffer_length = size; - urb->transfer_buffer = buf; - urb->transfer_flags = URB_ISO_ASAP; - - __fill_isoc_desc(urb, size, mtu); - - BT_DBG("%s urb %p", husb->hdev->name, urb); - - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err) { - BT_ERR("%s isoc rx submit failed urb %p err %d", - husb->hdev->name, urb, err); - _urb_unlink(_urb); - kfree(_urb); - kfree(buf); - } - return err; -} -#endif - -/* Initialize device */ -static int hci_usb_open(struct hci_dev *hdev) -{ - struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; - int i, err; - unsigned long flags; - - BT_DBG("%s", hdev->name); - - if (test_and_set_bit(HCI_RUNNING, &hdev->flags)) - return 0; - - write_lock_irqsave(&husb->completion_lock, flags); - - err = hci_usb_intr_rx_submit(husb); - if (!err) { - for (i = 0; i < HCI_MAX_BULK_RX; i++) - hci_usb_bulk_rx_submit(husb); - -#ifdef CONFIG_BT_HCIUSB_SCO - if (husb->isoc_iface) - for (i = 0; i < HCI_MAX_ISOC_RX; i++) - hci_usb_isoc_rx_submit(husb); -#endif - } else { - clear_bit(HCI_RUNNING, &hdev->flags); - } - - write_unlock_irqrestore(&husb->completion_lock, flags); - return err; -} - -/* Reset device */ -static int hci_usb_flush(struct hci_dev *hdev) -{ - struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; - int i; - - BT_DBG("%s", hdev->name); - - for (i = 0; i < 4; i++) - skb_queue_purge(&husb->transmit_q[i]); - return 0; -} - -static void hci_usb_unlink_urbs(struct hci_usb *husb) -{ - int i; - - BT_DBG("%s", husb->hdev->name); - - for (i = 0; i < 4; i++) { - struct _urb *_urb; - struct urb *urb; - - /* Kill pending requests */ - while ((_urb = _urb_dequeue(&husb->pending_q[i]))) { - urb = &_urb->urb; - BT_DBG("%s unlinking _urb %p type %d urb %p", - husb->hdev->name, _urb, _urb->type, urb); - usb_kill_urb(urb); - _urb_queue_tail(__completed_q(husb, _urb->type), _urb); - } - - /* Release completed requests */ - while ((_urb = _urb_dequeue(&husb->completed_q[i]))) { - urb = &_urb->urb; - BT_DBG("%s freeing _urb %p type %d urb %p", - husb->hdev->name, _urb, _urb->type, urb); - kfree(urb->setup_packet); - kfree(urb->transfer_buffer); - kfree(_urb); - } - } -} - -/* Close device */ -static int hci_usb_close(struct hci_dev *hdev) -{ - struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; - unsigned long flags; - - if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) - return 0; - - BT_DBG("%s", hdev->name); - - /* Synchronize with completion handlers */ - write_lock_irqsave(&husb->completion_lock, flags); - write_unlock_irqrestore(&husb->completion_lock, flags); - - hci_usb_unlink_urbs(husb); - hci_usb_flush(hdev); - return 0; -} - -static int __tx_submit(struct hci_usb *husb, struct _urb *_urb) -{ - struct urb *urb = &_urb->urb; - int err; - - BT_DBG("%s urb %p type %d", husb->hdev->name, urb, _urb->type); - - _urb_queue_tail(__pending_q(husb, _urb->type), _urb); - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err) { - BT_ERR("%s tx submit failed urb %p type %d err %d", - husb->hdev->name, urb, _urb->type, err); - _urb_unlink(_urb); - _urb_queue_tail(__completed_q(husb, _urb->type), _urb); - } else - atomic_inc(__pending_tx(husb, _urb->type)); - - return err; -} - -static inline int hci_usb_send_ctrl(struct hci_usb *husb, struct sk_buff *skb) -{ - struct _urb *_urb = __get_completed(husb, bt_cb(skb)->pkt_type); - struct usb_ctrlrequest *dr; - struct urb *urb; - - if (!_urb) { - _urb = _urb_alloc(0, GFP_ATOMIC); - if (!_urb) - return -ENOMEM; - _urb->type = bt_cb(skb)->pkt_type; - - dr = kmalloc(sizeof(*dr), GFP_ATOMIC); - if (!dr) { - kfree(_urb); - return -ENOMEM; - } - } else - dr = (void *) _urb->urb.setup_packet; - - dr->bRequestType = husb->ctrl_req; - dr->bRequest = 0; - dr->wIndex = 0; - dr->wValue = 0; - dr->wLength = __cpu_to_le16(skb->len); - - urb = &_urb->urb; - usb_fill_control_urb(urb, husb->udev, usb_sndctrlpipe(husb->udev, 0), - (void *) dr, skb->data, skb->len, hci_usb_tx_complete, husb); - - BT_DBG("%s skb %p len %d", husb->hdev->name, skb, skb->len); - - _urb->priv = skb; - return __tx_submit(husb, _urb); -} - -static inline int hci_usb_send_bulk(struct hci_usb *husb, struct sk_buff *skb) -{ - struct _urb *_urb = __get_completed(husb, bt_cb(skb)->pkt_type); - struct urb *urb; - int pipe; - - if (!_urb) { - _urb = _urb_alloc(0, GFP_ATOMIC); - if (!_urb) - return -ENOMEM; - _urb->type = bt_cb(skb)->pkt_type; - } - - urb = &_urb->urb; - pipe = usb_sndbulkpipe(husb->udev, husb->bulk_out_ep->desc.bEndpointAddress); - usb_fill_bulk_urb(urb, husb->udev, pipe, skb->data, skb->len, - hci_usb_tx_complete, husb); - urb->transfer_flags = URB_ZERO_PACKET; - - BT_DBG("%s skb %p len %d", husb->hdev->name, skb, skb->len); - - _urb->priv = skb; - return __tx_submit(husb, _urb); -} - -#ifdef CONFIG_BT_HCIUSB_SCO -static inline int hci_usb_send_isoc(struct hci_usb *husb, struct sk_buff *skb) -{ - struct _urb *_urb = __get_completed(husb, bt_cb(skb)->pkt_type); - struct urb *urb; - - if (!_urb) { - _urb = _urb_alloc(HCI_MAX_ISOC_FRAMES, GFP_ATOMIC); - if (!_urb) - return -ENOMEM; - _urb->type = bt_cb(skb)->pkt_type; - } - - BT_DBG("%s skb %p len %d", husb->hdev->name, skb, skb->len); - - urb = &_urb->urb; - - urb->context = husb; - urb->dev = husb->udev; - urb->pipe = usb_sndisocpipe(husb->udev, husb->isoc_out_ep->desc.bEndpointAddress); - urb->complete = hci_usb_tx_complete; - urb->transfer_flags = URB_ISO_ASAP; - - urb->interval = husb->isoc_out_ep->desc.bInterval; - - urb->transfer_buffer = skb->data; - urb->transfer_buffer_length = skb->len; - - __fill_isoc_desc(urb, skb->len, le16_to_cpu(husb->isoc_out_ep->desc.wMaxPacketSize)); - - _urb->priv = skb; - return __tx_submit(husb, _urb); -} -#endif - -static void hci_usb_tx_process(struct hci_usb *husb) -{ - struct sk_buff_head *q; - struct sk_buff *skb; - - BT_DBG("%s", husb->hdev->name); - - do { - clear_bit(HCI_USB_TX_WAKEUP, &husb->state); - - /* Process command queue */ - q = __transmit_q(husb, HCI_COMMAND_PKT); - if (!atomic_read(__pending_tx(husb, HCI_COMMAND_PKT)) && - (skb = skb_dequeue(q))) { - if (hci_usb_send_ctrl(husb, skb) < 0) - skb_queue_head(q, skb); - } - -#ifdef CONFIG_BT_HCIUSB_SCO - /* Process SCO queue */ - q = __transmit_q(husb, HCI_SCODATA_PKT); - if (atomic_read(__pending_tx(husb, HCI_SCODATA_PKT)) < HCI_MAX_ISOC_TX && - (skb = skb_dequeue(q))) { - if (hci_usb_send_isoc(husb, skb) < 0) - skb_queue_head(q, skb); - } -#endif - - /* Process ACL queue */ - q = __transmit_q(husb, HCI_ACLDATA_PKT); - while (atomic_read(__pending_tx(husb, HCI_ACLDATA_PKT)) < HCI_MAX_BULK_TX && - (skb = skb_dequeue(q))) { - if (hci_usb_send_bulk(husb, skb) < 0) { - skb_queue_head(q, skb); - break; - } - } - } while(test_bit(HCI_USB_TX_WAKEUP, &husb->state)); -} - -static inline void hci_usb_tx_wakeup(struct hci_usb *husb) -{ - /* Serialize TX queue processing to avoid data reordering */ - if (!test_and_set_bit(HCI_USB_TX_PROCESS, &husb->state)) { - hci_usb_tx_process(husb); - clear_bit(HCI_USB_TX_PROCESS, &husb->state); - } else - set_bit(HCI_USB_TX_WAKEUP, &husb->state); -} - -/* Send frames from HCI layer */ -static int hci_usb_send_frame(struct sk_buff *skb) -{ - struct hci_dev *hdev = (struct hci_dev *) skb->dev; - struct hci_usb *husb; - - if (!hdev) { - BT_ERR("frame for uknown device (hdev=NULL)"); - return -ENODEV; - } - - if (!test_bit(HCI_RUNNING, &hdev->flags)) - return -EBUSY; - - BT_DBG("%s type %d len %d", hdev->name, bt_cb(skb)->pkt_type, skb->len); - - husb = (struct hci_usb *) hdev->driver_data; - - switch (bt_cb(skb)->pkt_type) { - case HCI_COMMAND_PKT: - hdev->stat.cmd_tx++; - break; - - case HCI_ACLDATA_PKT: - hdev->stat.acl_tx++; - break; - -#ifdef CONFIG_BT_HCIUSB_SCO - case HCI_SCODATA_PKT: - hdev->stat.sco_tx++; - break; -#endif - - default: - kfree_skb(skb); - return 0; - } - - read_lock(&husb->completion_lock); - - skb_queue_tail(__transmit_q(husb, bt_cb(skb)->pkt_type), skb); - hci_usb_tx_wakeup(husb); - - read_unlock(&husb->completion_lock); - return 0; -} - -static void hci_usb_rx_complete(struct urb *urb) -{ - struct _urb *_urb = container_of(urb, struct _urb, urb); - struct hci_usb *husb = (void *) urb->context; - struct hci_dev *hdev = husb->hdev; - int err, count = urb->actual_length; - - BT_DBG("%s urb %p type %d status %d count %d flags %x", hdev->name, urb, - _urb->type, urb->status, count, urb->transfer_flags); - - read_lock(&husb->completion_lock); - - if (!test_bit(HCI_RUNNING, &hdev->flags)) - goto unlock; - - if (urb->status || !count) - goto resubmit; - - if (_urb->type == HCI_SCODATA_PKT) { -#ifdef CONFIG_BT_HCIUSB_SCO - int i; - for (i=0; i < urb->number_of_packets; i++) { - BT_DBG("desc %d status %d offset %d len %d", i, - urb->iso_frame_desc[i].status, - urb->iso_frame_desc[i].offset, - urb->iso_frame_desc[i].actual_length); - - if (!urb->iso_frame_desc[i].status) { - husb->hdev->stat.byte_rx += urb->iso_frame_desc[i].actual_length; - hci_recv_fragment(husb->hdev, _urb->type, - urb->transfer_buffer + urb->iso_frame_desc[i].offset, - urb->iso_frame_desc[i].actual_length); - } - } -#else - ; -#endif - } else { - husb->hdev->stat.byte_rx += count; - err = hci_recv_fragment(husb->hdev, _urb->type, urb->transfer_buffer, count); - if (err < 0) { - BT_ERR("%s corrupted packet: type %d count %d", - husb->hdev->name, _urb->type, count); - hdev->stat.err_rx++; - } - } - -resubmit: - urb->dev = husb->udev; - err = usb_submit_urb(urb, GFP_ATOMIC); - BT_DBG("%s urb %p type %d resubmit status %d", hdev->name, urb, - _urb->type, err); - -unlock: - read_unlock(&husb->completion_lock); -} - -static void hci_usb_tx_complete(struct urb *urb) -{ - struct _urb *_urb = container_of(urb, struct _urb, urb); - struct hci_usb *husb = (void *) urb->context; - struct hci_dev *hdev = husb->hdev; - - BT_DBG("%s urb %p status %d flags %x", hdev->name, urb, - urb->status, urb->transfer_flags); - - atomic_dec(__pending_tx(husb, _urb->type)); - - urb->transfer_buffer = NULL; - kfree_skb((struct sk_buff *) _urb->priv); - - if (!test_bit(HCI_RUNNING, &hdev->flags)) - return; - - if (!urb->status) - hdev->stat.byte_tx += urb->transfer_buffer_length; - else - hdev->stat.err_tx++; - - read_lock(&husb->completion_lock); - - _urb_unlink(_urb); - _urb_queue_tail(__completed_q(husb, _urb->type), _urb); - - hci_usb_tx_wakeup(husb); - - read_unlock(&husb->completion_lock); -} - -static void hci_usb_destruct(struct hci_dev *hdev) -{ - struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; - - BT_DBG("%s", hdev->name); - - kfree(husb); -} - -static void hci_usb_notify(struct hci_dev *hdev, unsigned int evt) -{ - BT_DBG("%s evt %d", hdev->name, evt); -} - -static int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct usb_host_endpoint *bulk_out_ep = NULL; - struct usb_host_endpoint *bulk_in_ep = NULL; - struct usb_host_endpoint *intr_in_ep = NULL; - struct usb_host_endpoint *ep; - struct usb_host_interface *uif; - struct usb_interface *isoc_iface; - struct hci_usb *husb; - struct hci_dev *hdev; - int i, e, size, isoc_ifnum, isoc_alts; - - BT_DBG("udev %p intf %p", udev, intf); - - if (!id->driver_info) { - const struct usb_device_id *match; - match = usb_match_id(intf, blacklist_ids); - if (match) - id = match; - } - - if (id->driver_info & HCI_IGNORE) - return -ENODEV; - - if (ignore_dga && id->driver_info & HCI_DIGIANSWER) - return -ENODEV; - - if (ignore_csr && id->driver_info & HCI_CSR) - return -ENODEV; - - if (ignore_sniffer && id->driver_info & HCI_SNIFFER) - return -ENODEV; - - if (intf->cur_altsetting->desc.bInterfaceNumber > 0) - return -ENODEV; - - /* Find endpoints that we need */ - uif = intf->cur_altsetting; - for (e = 0; e < uif->desc.bNumEndpoints; e++) { - ep = &uif->endpoint[e]; - - switch (ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { - case USB_ENDPOINT_XFER_INT: - if (ep->desc.bEndpointAddress & USB_DIR_IN) - intr_in_ep = ep; - break; - - case USB_ENDPOINT_XFER_BULK: - if (ep->desc.bEndpointAddress & USB_DIR_IN) - bulk_in_ep = ep; - else - bulk_out_ep = ep; - break; - } - } - - if (!bulk_in_ep || !bulk_out_ep || !intr_in_ep) { - BT_DBG("Bulk endpoints not found"); - goto done; - } - - if (!(husb = kzalloc(sizeof(struct hci_usb), GFP_KERNEL))) { - BT_ERR("Can't allocate: control structure"); - goto done; - } - - husb->udev = udev; - husb->bulk_out_ep = bulk_out_ep; - husb->bulk_in_ep = bulk_in_ep; - husb->intr_in_ep = intr_in_ep; - - if (id->driver_info & HCI_DIGIANSWER) - husb->ctrl_req = USB_TYPE_VENDOR; - else - husb->ctrl_req = USB_TYPE_CLASS; - - /* Find isochronous endpoints that we can use */ - size = 0; - isoc_iface = NULL; - isoc_alts = 0; - isoc_ifnum = 1; - -#ifdef CONFIG_BT_HCIUSB_SCO - if (isoc && !(id->driver_info & (HCI_BROKEN_ISOC | HCI_SNIFFER))) - isoc_iface = usb_ifnum_to_if(udev, isoc_ifnum); - - if (isoc_iface) { - int a; - struct usb_host_endpoint *isoc_out_ep = NULL; - struct usb_host_endpoint *isoc_in_ep = NULL; - - for (a = 0; a < isoc_iface->num_altsetting; a++) { - uif = &isoc_iface->altsetting[a]; - for (e = 0; e < uif->desc.bNumEndpoints; e++) { - ep = &uif->endpoint[e]; - - switch (ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { - case USB_ENDPOINT_XFER_ISOC: - if (le16_to_cpu(ep->desc.wMaxPacketSize) < size || - uif->desc.bAlternateSetting != isoc) - break; - size = le16_to_cpu(ep->desc.wMaxPacketSize); - - isoc_alts = uif->desc.bAlternateSetting; - - if (ep->desc.bEndpointAddress & USB_DIR_IN) - isoc_in_ep = ep; - else - isoc_out_ep = ep; - break; - } - } - } - - if (!isoc_in_ep || !isoc_out_ep) - BT_DBG("Isoc endpoints not found"); - else { - BT_DBG("isoc ifnum %d alts %d", isoc_ifnum, isoc_alts); - if (usb_driver_claim_interface(&hci_usb_driver, isoc_iface, husb) != 0) - BT_ERR("Can't claim isoc interface"); - else if (usb_set_interface(udev, isoc_ifnum, isoc_alts)) { - BT_ERR("Can't set isoc interface settings"); - husb->isoc_iface = isoc_iface; - usb_driver_release_interface(&hci_usb_driver, isoc_iface); - husb->isoc_iface = NULL; - } else { - husb->isoc_iface = isoc_iface; - husb->isoc_in_ep = isoc_in_ep; - husb->isoc_out_ep = isoc_out_ep; - } - } - } -#endif - - rwlock_init(&husb->completion_lock); - - for (i = 0; i < 4; i++) { - skb_queue_head_init(&husb->transmit_q[i]); - _urb_queue_init(&husb->pending_q[i]); - _urb_queue_init(&husb->completed_q[i]); - } - - /* Initialize and register HCI device */ - hdev = hci_alloc_dev(); - if (!hdev) { - BT_ERR("Can't allocate HCI device"); - goto probe_error; - } - - husb->hdev = hdev; - - hdev->type = HCI_USB; - hdev->driver_data = husb; - SET_HCIDEV_DEV(hdev, &intf->dev); - - hdev->open = hci_usb_open; - hdev->close = hci_usb_close; - hdev->flush = hci_usb_flush; - hdev->send = hci_usb_send_frame; - hdev->destruct = hci_usb_destruct; - hdev->notify = hci_usb_notify; - - hdev->owner = THIS_MODULE; - - if (reset || id->driver_info & HCI_RESET) - set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks); - - if (force_scofix || id->driver_info & HCI_WRONG_SCO_MTU) { - if (!disable_scofix) - set_bit(HCI_QUIRK_FIXUP_BUFFER_SIZE, &hdev->quirks); - } - - if (id->driver_info & HCI_SNIFFER) { - if (le16_to_cpu(udev->descriptor.bcdDevice) > 0x997) - set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); - } - - if (id->driver_info & HCI_BCM92035) { - unsigned char cmd[] = { 0x3b, 0xfc, 0x01, 0x00 }; - struct sk_buff *skb; - - skb = bt_skb_alloc(sizeof(cmd), GFP_KERNEL); - if (skb) { - memcpy(skb_put(skb, sizeof(cmd)), cmd, sizeof(cmd)); - skb_queue_tail(&hdev->driver_init, skb); - } - } - - if (hci_register_dev(hdev) < 0) { - BT_ERR("Can't register HCI device"); - hci_free_dev(hdev); - goto probe_error; - } - - usb_set_intfdata(intf, husb); - return 0; - -probe_error: - if (husb->isoc_iface) - usb_driver_release_interface(&hci_usb_driver, husb->isoc_iface); - kfree(husb); - -done: - return -EIO; -} - -static void hci_usb_disconnect(struct usb_interface *intf) -{ - struct hci_usb *husb = usb_get_intfdata(intf); - struct hci_dev *hdev; - - if (!husb || intf == husb->isoc_iface) - return; - - usb_set_intfdata(intf, NULL); - hdev = husb->hdev; - - BT_DBG("%s", hdev->name); - - hci_usb_close(hdev); - - if (husb->isoc_iface) - usb_driver_release_interface(&hci_usb_driver, husb->isoc_iface); - - if (hci_unregister_dev(hdev) < 0) - BT_ERR("Can't unregister HCI device %s", hdev->name); - - hci_free_dev(hdev); -} - -static int hci_usb_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct hci_usb *husb = usb_get_intfdata(intf); - struct list_head killed; - unsigned long flags; - int i; - - if (!husb || intf == husb->isoc_iface) - return 0; - - hci_suspend_dev(husb->hdev); - - INIT_LIST_HEAD(&killed); - - for (i = 0; i < 4; i++) { - struct _urb_queue *q = &husb->pending_q[i]; - struct _urb *_urb, *_tmp; - - while ((_urb = _urb_dequeue(q))) { - /* reset queue since _urb_dequeue sets it to NULL */ - _urb->queue = q; - usb_kill_urb(&_urb->urb); - list_add(&_urb->list, &killed); - } - - spin_lock_irqsave(&q->lock, flags); - - list_for_each_entry_safe(_urb, _tmp, &killed, list) { - list_move_tail(&_urb->list, &q->head); - } - - spin_unlock_irqrestore(&q->lock, flags); - } - - return 0; -} - -static int hci_usb_resume(struct usb_interface *intf) -{ - struct hci_usb *husb = usb_get_intfdata(intf); - unsigned long flags; - int i, err = 0; - - if (!husb || intf == husb->isoc_iface) - return 0; - - for (i = 0; i < 4; i++) { - struct _urb_queue *q = &husb->pending_q[i]; - struct _urb *_urb; - - spin_lock_irqsave(&q->lock, flags); - - list_for_each_entry(_urb, &q->head, list) { - err = usb_submit_urb(&_urb->urb, GFP_ATOMIC); - if (err) - break; - } - - spin_unlock_irqrestore(&q->lock, flags); - - if (err) - return -EIO; - } - - hci_resume_dev(husb->hdev); - - return 0; -} - -static struct usb_driver hci_usb_driver = { - .name = "hci_usb", - .probe = hci_usb_probe, - .disconnect = hci_usb_disconnect, - .suspend = hci_usb_suspend, - .resume = hci_usb_resume, - .id_table = bluetooth_ids, -}; - -static int __init hci_usb_init(void) -{ - int err; - - BT_INFO("HCI USB driver ver %s", VERSION); - - if ((err = usb_register(&hci_usb_driver)) < 0) - BT_ERR("Failed to register HCI USB driver"); - - return err; -} - -static void __exit hci_usb_exit(void) -{ - usb_deregister(&hci_usb_driver); -} - -module_init(hci_usb_init); -module_exit(hci_usb_exit); - -module_param(ignore_dga, bool, 0644); -MODULE_PARM_DESC(ignore_dga, "Ignore devices with id 08fd:0001"); - -module_param(ignore_csr, bool, 0644); -MODULE_PARM_DESC(ignore_csr, "Ignore devices with id 0a12:0001"); - -module_param(ignore_sniffer, bool, 0644); -MODULE_PARM_DESC(ignore_sniffer, "Ignore devices with id 0a12:0002"); - -module_param(disable_scofix, bool, 0644); -MODULE_PARM_DESC(disable_scofix, "Disable fixup of wrong SCO buffer size"); - -module_param(force_scofix, bool, 0644); -MODULE_PARM_DESC(force_scofix, "Force fixup of wrong SCO buffers size"); - -module_param(reset, bool, 0644); -MODULE_PARM_DESC(reset, "Send HCI reset command on initialization"); - -#ifdef CONFIG_BT_HCIUSB_SCO -module_param(isoc, int, 0644); -MODULE_PARM_DESC(isoc, "Set isochronous transfers for SCO over HCI support"); -#endif - -MODULE_AUTHOR("Marcel Holtmann "); -MODULE_DESCRIPTION("Bluetooth HCI USB driver ver " VERSION); -MODULE_VERSION(VERSION); -MODULE_LICENSE("GPL"); diff --git a/drivers/bluetooth/hci_usb.h b/drivers/bluetooth/hci_usb.h deleted file mode 100644 index 8e659914523f76990e1e736201044771531b02eb..0000000000000000000000000000000000000000 --- a/drivers/bluetooth/hci_usb.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - HCI USB driver for Linux Bluetooth protocol stack (BlueZ) - Copyright (C) 2000-2001 Qualcomm Incorporated - Written 2000,2001 by Maxim Krasnyansky - - Copyright (C) 2003 Maxim Krasnyansky - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. - IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY - CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, - COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS - SOFTWARE IS DISCLAIMED. -*/ - -/* Class, SubClass, and Protocol codes that describe a Bluetooth device */ -#define HCI_DEV_CLASS 0xe0 /* Wireless class */ -#define HCI_DEV_SUBCLASS 0x01 /* RF subclass */ -#define HCI_DEV_PROTOCOL 0x01 /* Bluetooth programming protocol */ - -#define HCI_IGNORE 0x01 -#define HCI_RESET 0x02 -#define HCI_DIGIANSWER 0x04 -#define HCI_CSR 0x08 -#define HCI_SNIFFER 0x10 -#define HCI_BCM92035 0x20 -#define HCI_BROKEN_ISOC 0x40 -#define HCI_WRONG_SCO_MTU 0x80 - -#define HCI_MAX_IFACE_NUM 3 - -#define HCI_MAX_BULK_TX 4 -#define HCI_MAX_BULK_RX 1 - -#define HCI_MAX_ISOC_RX 2 -#define HCI_MAX_ISOC_TX 2 - -#define HCI_MAX_ISOC_FRAMES 10 - -struct _urb_queue { - struct list_head head; - spinlock_t lock; -}; - -struct _urb { - struct list_head list; - struct _urb_queue *queue; - int type; - void *priv; - struct urb urb; -}; - -static inline void _urb_queue_init(struct _urb_queue *q) -{ - INIT_LIST_HEAD(&q->head); - spin_lock_init(&q->lock); -} - -static inline void _urb_queue_head(struct _urb_queue *q, struct _urb *_urb) -{ - unsigned long flags; - spin_lock_irqsave(&q->lock, flags); - /* _urb_unlink needs to know which spinlock to use, thus smp_mb(). */ - _urb->queue = q; smp_mb(); list_add(&_urb->list, &q->head); - spin_unlock_irqrestore(&q->lock, flags); -} - -static inline void _urb_queue_tail(struct _urb_queue *q, struct _urb *_urb) -{ - unsigned long flags; - spin_lock_irqsave(&q->lock, flags); - /* _urb_unlink needs to know which spinlock to use, thus smp_mb(). */ - _urb->queue = q; smp_mb(); list_add_tail(&_urb->list, &q->head); - spin_unlock_irqrestore(&q->lock, flags); -} - -static inline void _urb_unlink(struct _urb *_urb) -{ - struct _urb_queue *q; - unsigned long flags; - - smp_mb(); - q = _urb->queue; - /* If q is NULL, it will die at easy-to-debug NULL pointer dereference. - No need to BUG(). */ - spin_lock_irqsave(&q->lock, flags); - list_del(&_urb->list); _urb->queue = NULL; - spin_unlock_irqrestore(&q->lock, flags); -} - -struct hci_usb { - struct hci_dev *hdev; - - unsigned long state; - - struct usb_device *udev; - - struct usb_host_endpoint *bulk_in_ep; - struct usb_host_endpoint *bulk_out_ep; - struct usb_host_endpoint *intr_in_ep; - - struct usb_interface *isoc_iface; - struct usb_host_endpoint *isoc_out_ep; - struct usb_host_endpoint *isoc_in_ep; - - __u8 ctrl_req; - - struct sk_buff_head transmit_q[4]; - - rwlock_t completion_lock; - - atomic_t pending_tx[4]; /* Number of pending requests */ - struct _urb_queue pending_q[4]; /* Pending requests */ - struct _urb_queue completed_q[4]; /* Completed requests */ -}; - -/* States */ -#define HCI_USB_TX_PROCESS 1 -#define HCI_USB_TX_WAKEUP 2 diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index 7320a71b63685403c9972766c4eb716ba9b05791..0bbefba6469cee659e7b114e961a677e3fa65fa0 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -40,11 +40,6 @@ #include #include -#ifndef CONFIG_BT_HCIVHCI_DEBUG -#undef BT_DBG -#define BT_DBG(D...) -#endif - #define VERSION "1.2" static int minor = MISC_DYNAMIC_MINOR; diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 43d6ba83a1912ccbc5f668876e8e6cf7a82a3066..c602b547cc6e08afd842182b80fac140c13766cb 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -622,6 +622,16 @@ config HVC_BEAT help Toshiba's Cell Reference Set Beat Console device driver +config HVC_IUCV + bool "z/VM IUCV Hypervisor console support (VM only)" + depends on S390 + select HVC_DRIVER + select IUCV + default y + help + This driver provides a Hypervisor console (HVC) back-end to access + a Linux (console) terminal via a z/VM IUCV communication path. + config HVC_XEN bool "Xen Hypervisor Console support" depends on XEN @@ -631,6 +641,12 @@ config HVC_XEN help Xen virtual console device driver +config HVC_UDBG + bool "udbg based fake hypervisor console" + depends on PPC && EXPERIMENTAL + select HVC_DRIVER + default n + config VIRTIO_CONSOLE tristate "Virtio console" depends on VIRTIO diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 438f71317c5ce59b1f0fe5e70450cfe1be009fe6..9caf5b5ad1c05bfbe9ec4f7683a7f1c8c852005e 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -50,6 +50,8 @@ obj-$(CONFIG_HVC_BEAT) += hvc_beat.o obj-$(CONFIG_HVC_DRIVER) += hvc_console.o obj-$(CONFIG_HVC_IRQ) += hvc_irq.o obj-$(CONFIG_HVC_XEN) += hvc_xen.o +obj-$(CONFIG_HVC_IUCV) += hvc_iucv.o +obj-$(CONFIG_HVC_UDBG) += hvc_udbg.o obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o obj-$(CONFIG_RAW_DRIVER) += raw.o obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o diff --git a/drivers/char/bsr.c b/drivers/char/bsr.c index 456f54db73e2aa0fa395ede67cad3b2b80a40feb..977dfb1096a0c16120f1bc205ba45f4ccd80c4c1 100644 --- a/drivers/char/bsr.c +++ b/drivers/char/bsr.c @@ -60,6 +60,8 @@ struct bsr_dev { unsigned bsr_num; /* bsr id number for its type */ int bsr_minor; + struct list_head bsr_list; + dev_t bsr_dev; struct cdev bsr_cdev; struct device *bsr_device; @@ -67,8 +69,8 @@ struct bsr_dev { }; -static unsigned num_bsr_devs; -static struct bsr_dev *bsr_devs; +static unsigned total_bsr_devs; +static struct list_head bsr_devs = LIST_HEAD_INIT(bsr_devs); static struct class *bsr_class; static int bsr_major; @@ -146,24 +148,25 @@ const static struct file_operations bsr_fops = { static void bsr_cleanup_devs(void) { - int i; - for (i=0 ; i < num_bsr_devs; i++) { - struct bsr_dev *cur = bsr_devs + i; + struct bsr_dev *cur, *n; + + list_for_each_entry_safe(cur, n, &bsr_devs, bsr_list) { if (cur->bsr_device) { cdev_del(&cur->bsr_cdev); device_del(cur->bsr_device); } + list_del(&cur->bsr_list); + kfree(cur); } - - kfree(bsr_devs); } -static int bsr_create_devs(struct device_node *bn) +static int bsr_add_node(struct device_node *bn) { - int bsr_stride_len, bsr_bytes_len; + int bsr_stride_len, bsr_bytes_len, num_bsr_devs; const u32 *bsr_stride; const u32 *bsr_bytes; unsigned i; + int ret = -ENODEV; bsr_stride = of_get_property(bn, "ibm,lock-stride", &bsr_stride_len); bsr_bytes = of_get_property(bn, "ibm,#lock-bytes", &bsr_bytes_len); @@ -171,35 +174,36 @@ static int bsr_create_devs(struct device_node *bn) if (!bsr_stride || !bsr_bytes || (bsr_stride_len != bsr_bytes_len)) { printk(KERN_ERR "bsr of-node has missing/incorrect property\n"); - return -ENODEV; + return ret; } num_bsr_devs = bsr_bytes_len / sizeof(u32); - /* only a warning, its informational since we'll fail and exit */ - WARN_ON(num_bsr_devs > BSR_MAX_DEVS); - - bsr_devs = kzalloc(sizeof(struct bsr_dev) * num_bsr_devs, GFP_KERNEL); - if (!bsr_devs) - return -ENOMEM; - for (i = 0 ; i < num_bsr_devs; i++) { - struct bsr_dev *cur = bsr_devs + i; + struct bsr_dev *cur = kzalloc(sizeof(struct bsr_dev), + GFP_KERNEL); struct resource res; int result; + if (!cur) { + printk(KERN_ERR "Unable to alloc bsr dev\n"); + ret = -ENOMEM; + goto out_err; + } + result = of_address_to_resource(bn, i, &res); if (result < 0) { - printk(KERN_ERR "bsr of-node has invalid reg property\n"); - goto out_err; + printk(KERN_ERR "bsr of-node has invalid reg property, skipping\n"); + kfree(cur); + continue; } - cur->bsr_minor = i; + cur->bsr_minor = i + total_bsr_devs; cur->bsr_addr = res.start; cur->bsr_len = res.end - res.start + 1; cur->bsr_bytes = bsr_bytes[i]; cur->bsr_stride = bsr_stride[i]; - cur->bsr_dev = MKDEV(bsr_major, i); + cur->bsr_dev = MKDEV(bsr_major, i + total_bsr_devs); switch(cur->bsr_bytes) { case 8: @@ -220,14 +224,15 @@ static int bsr_create_devs(struct device_node *bn) } cur->bsr_num = bsr_types[cur->bsr_type]; - bsr_types[cur->bsr_type] = cur->bsr_num + 1; snprintf(cur->bsr_name, 32, "bsr%d_%d", cur->bsr_bytes, cur->bsr_num); cdev_init(&cur->bsr_cdev, &bsr_fops); result = cdev_add(&cur->bsr_cdev, cur->bsr_dev, 1); - if (result) + if (result) { + kfree(cur); goto out_err; + } cur->bsr_device = device_create(bsr_class, NULL, cur->bsr_dev, cur, cur->bsr_name); @@ -235,16 +240,37 @@ static int bsr_create_devs(struct device_node *bn) printk(KERN_ERR "device_create failed for %s\n", cur->bsr_name); cdev_del(&cur->bsr_cdev); + kfree(cur); goto out_err; } + + bsr_types[cur->bsr_type] = cur->bsr_num + 1; + list_add_tail(&cur->bsr_list, &bsr_devs); } + total_bsr_devs += num_bsr_devs; + return 0; out_err: bsr_cleanup_devs(); - return -ENODEV; + return ret; +} + +static int bsr_create_devs(struct device_node *bn) +{ + int ret; + + while (bn) { + ret = bsr_add_node(bn); + if (ret) { + of_node_put(bn); + return ret; + } + bn = of_find_compatible_node(bn, NULL, "ibm,bsr"); + } + return 0; } static int __init bsr_init(void) @@ -254,7 +280,7 @@ static int __init bsr_init(void) int ret = -ENODEV; int result; - np = of_find_compatible_node(NULL, "ibm,bsr", "ibm,bsr"); + np = of_find_compatible_node(NULL, NULL, "ibm,bsr"); if (!np) goto out_err; @@ -272,10 +298,10 @@ static int __init bsr_init(void) goto out_err_2; } - if ((ret = bsr_create_devs(np)) < 0) + if ((ret = bsr_create_devs(np)) < 0) { + np = NULL; goto out_err_3; - - of_node_put(np); + } return 0; diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index 5b819b12675a9dd855ceda7e2465577831af7460..fb57f67bb427fb86e23e9b6c723ba3fcae467ea9 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -642,8 +642,11 @@ int hvc_poll(struct hvc_struct *hp) /* Handle the SysRq Hack */ /* XXX should support a sequence */ if (buf[i] == '\x0f') { /* ^O */ - sysrq_pressed = 1; - continue; + /* if ^O is pressed again, reset + * sysrq_pressed and flip ^O char */ + sysrq_pressed = !sysrq_pressed; + if (sysrq_pressed) + continue; } else if (sysrq_pressed) { handle_sysrq(buf[i], tty); sysrq_pressed = 0; @@ -689,10 +692,8 @@ EXPORT_SYMBOL_GPL(hvc_poll); */ void hvc_resize(struct hvc_struct *hp, struct winsize ws) { - if ((hp->ws.ws_row != ws.ws_row) || (hp->ws.ws_col != ws.ws_col)) { - hp->ws = ws; - schedule_work(&hp->tty_resize); - } + hp->ws = ws; + schedule_work(&hp->tty_resize); } /* diff --git a/drivers/char/hvc_console.h b/drivers/char/hvc_console.h index 8297dbc2e6ec99f80b2db8fc2eb4e01da6028020..3c85d78c975c1f803278132d8c77fb2ddfd3eb56 100644 --- a/drivers/char/hvc_console.h +++ b/drivers/char/hvc_console.h @@ -48,7 +48,7 @@ struct hvc_struct { spinlock_t lock; int index; struct tty_struct *tty; - unsigned int count; + int count; int do_wakeup; char *outbuf; int outbuf_size; diff --git a/drivers/char/hvc_iseries.c b/drivers/char/hvc_iseries.c index b74a2f8ab9080fe995b21c370857d54c7ff3db02..449727b6166d417174b2ce3c662d0da31af73830 100644 --- a/drivers/char/hvc_iseries.c +++ b/drivers/char/hvc_iseries.c @@ -575,8 +575,10 @@ static int __init hvc_find_vtys(void) * of console adapters. */ if ((num_found >= MAX_NR_HVC_CONSOLES) || - (num_found >= VTTY_PORTS)) + (num_found >= VTTY_PORTS)) { + of_node_put(vty); break; + } vtermno = of_get_property(vty, "reg", NULL); if (!vtermno) diff --git a/drivers/char/hvc_iucv.c b/drivers/char/hvc_iucv.c new file mode 100644 index 0000000000000000000000000000000000000000..5ea7d7713fca42d0c5b091393669e20b46a9ca0f --- /dev/null +++ b/drivers/char/hvc_iucv.c @@ -0,0 +1,850 @@ +/* + * hvc_iucv.c - z/VM IUCV back-end for the Hypervisor Console (HVC) + * + * This back-end for HVC provides terminal access via + * z/VM IUCV communication paths. + * + * Copyright IBM Corp. 2008. + * + * Author(s): Hendrik Brueckner + */ +#define KMSG_COMPONENT "hvc_iucv" + +#include +#include +#include +#include +#include +#include + +#include "hvc_console.h" + + +/* HVC backend for z/VM IUCV */ +#define HVC_IUCV_MAGIC 0xc9e4c3e5 +#define MAX_HVC_IUCV_LINES HVC_ALLOC_TTY_ADAPTERS +#define MEMPOOL_MIN_NR (PAGE_SIZE / sizeof(struct iucv_tty_buffer)/4) + +/* IUCV TTY message */ +#define MSG_VERSION 0x02 /* Message version */ +#define MSG_TYPE_ERROR 0x01 /* Error message */ +#define MSG_TYPE_TERMENV 0x02 /* Terminal environment variable */ +#define MSG_TYPE_TERMIOS 0x04 /* Terminal IO struct update */ +#define MSG_TYPE_WINSIZE 0x08 /* Terminal window size update */ +#define MSG_TYPE_DATA 0x10 /* Terminal data */ + +#define MSG_SIZE(s) ((s) + offsetof(struct iucv_tty_msg, data)) +struct iucv_tty_msg { + u8 version; /* Message version */ + u8 type; /* Message type */ +#define MSG_MAX_DATALEN (~(u16)0) + u16 datalen; /* Payload length */ + u8 data[]; /* Payload buffer */ +} __attribute__((packed)); + +enum iucv_state_t { + IUCV_DISCONN = 0, + IUCV_CONNECTED = 1, + IUCV_SEVERED = 2, +}; + +enum tty_state_t { + TTY_CLOSED = 0, + TTY_OPENED = 1, +}; + +struct hvc_iucv_private { + struct hvc_struct *hvc; /* HVC console struct reference */ + u8 srv_name[8]; /* IUCV service name (ebcdic) */ + enum iucv_state_t iucv_state; /* IUCV connection status */ + enum tty_state_t tty_state; /* TTY status */ + struct iucv_path *path; /* IUCV path pointer */ + spinlock_t lock; /* hvc_iucv_private lock */ + struct list_head tty_outqueue; /* outgoing IUCV messages */ + struct list_head tty_inqueue; /* incoming IUCV messages */ +}; + +struct iucv_tty_buffer { + struct list_head list; /* list pointer */ + struct iucv_message msg; /* store an incoming IUCV message */ + size_t offset; /* data buffer offset */ + struct iucv_tty_msg *mbuf; /* buffer to store input/output data */ +}; + +/* IUCV callback handler */ +static int hvc_iucv_path_pending(struct iucv_path *, u8[8], u8[16]); +static void hvc_iucv_path_severed(struct iucv_path *, u8[16]); +static void hvc_iucv_msg_pending(struct iucv_path *, struct iucv_message *); +static void hvc_iucv_msg_complete(struct iucv_path *, struct iucv_message *); + + +/* Kernel module parameters */ +static unsigned long hvc_iucv_devices; + +/* Array of allocated hvc iucv tty lines... */ +static struct hvc_iucv_private *hvc_iucv_table[MAX_HVC_IUCV_LINES]; + +/* Kmem cache and mempool for iucv_tty_buffer elements */ +static struct kmem_cache *hvc_iucv_buffer_cache; +static mempool_t *hvc_iucv_mempool; + +/* IUCV handler callback functions */ +static struct iucv_handler hvc_iucv_handler = { + .path_pending = hvc_iucv_path_pending, + .path_severed = hvc_iucv_path_severed, + .message_complete = hvc_iucv_msg_complete, + .message_pending = hvc_iucv_msg_pending, +}; + + +/** + * hvc_iucv_get_private() - Return a struct hvc_iucv_private instance. + * @num: The HVC virtual terminal number (vtermno) + * + * This function returns the struct hvc_iucv_private instance that corresponds + * to the HVC virtual terminal number specified as parameter @num. + */ +struct hvc_iucv_private *hvc_iucv_get_private(uint32_t num) +{ + if ((num < HVC_IUCV_MAGIC) || (num - HVC_IUCV_MAGIC > hvc_iucv_devices)) + return NULL; + return hvc_iucv_table[num - HVC_IUCV_MAGIC]; +} + +/** + * alloc_tty_buffer() - Returns a new struct iucv_tty_buffer element. + * @size: Size of the internal buffer used to store data. + * @flags: Memory allocation flags passed to mempool. + * + * This function allocates a new struct iucv_tty_buffer element and, optionally, + * allocates an internal data buffer with the specified size @size. + * Note: The total message size arises from the internal buffer size and the + * members of the iucv_tty_msg structure. + * + * The function returns NULL if memory allocation has failed. + */ +static struct iucv_tty_buffer *alloc_tty_buffer(size_t size, gfp_t flags) +{ + struct iucv_tty_buffer *bufp; + + bufp = mempool_alloc(hvc_iucv_mempool, flags); + if (!bufp) + return NULL; + memset(bufp, 0, sizeof(struct iucv_tty_buffer)); + + if (size > 0) { + bufp->msg.length = MSG_SIZE(size); + bufp->mbuf = kmalloc(bufp->msg.length, flags); + if (!bufp->mbuf) { + mempool_free(bufp, hvc_iucv_mempool); + return NULL; + } + bufp->mbuf->version = MSG_VERSION; + bufp->mbuf->type = MSG_TYPE_DATA; + bufp->mbuf->datalen = (u16) size; + } + return bufp; +} + +/** + * destroy_tty_buffer() - destroy struct iucv_tty_buffer element. + * @bufp: Pointer to a struct iucv_tty_buffer element, SHALL NOT be NULL. + * + * The destroy_tty_buffer() function frees the internal data buffer and returns + * the struct iucv_tty_buffer element back to the mempool for freeing. + */ +static void destroy_tty_buffer(struct iucv_tty_buffer *bufp) +{ + kfree(bufp->mbuf); + mempool_free(bufp, hvc_iucv_mempool); +} + +/** + * destroy_tty_buffer_list() - call destroy_tty_buffer() for each list element. + * @list: List head pointer to a list containing struct iucv_tty_buffer + * elements. + * + * Calls destroy_tty_buffer() for each struct iucv_tty_buffer element in the + * list @list. + */ +static void destroy_tty_buffer_list(struct list_head *list) +{ + struct iucv_tty_buffer *ent, *next; + + list_for_each_entry_safe(ent, next, list, list) { + list_del(&ent->list); + destroy_tty_buffer(ent); + } +} + +/** + * hvc_iucv_write() - Receive IUCV message write data to HVC console buffer. + * @priv: Pointer to hvc_iucv_private structure. + * @buf: HVC console buffer for writing received terminal data. + * @count: HVC console buffer size. + * @has_more_data: Pointer to an int variable. + * + * The function picks up pending messages from the input queue and receives + * the message data that is then written to the specified buffer @buf. + * If the buffer size @count is less than the data message size, then the + * message is kept on the input queue and @has_more_data is set to 1. + * If the message data has been entirely written, the message is removed from + * the input queue. + * + * The function returns the number of bytes written to the terminal, zero if + * there are no pending data messages available or if there is no established + * IUCV path. + * If the IUCV path has been severed, then -EPIPE is returned to cause a + * hang up (that is issued by the HVC console layer). + */ +static int hvc_iucv_write(struct hvc_iucv_private *priv, + char *buf, int count, int *has_more_data) +{ + struct iucv_tty_buffer *rb; + int written; + int rc; + + /* Immediately return if there is no IUCV connection */ + if (priv->iucv_state == IUCV_DISCONN) + return 0; + + /* If the IUCV path has been severed, return -EPIPE to inform the + * hvc console layer to hang up the tty device. */ + if (priv->iucv_state == IUCV_SEVERED) + return -EPIPE; + + /* check if there are pending messages */ + if (list_empty(&priv->tty_inqueue)) + return 0; + + /* receive a iucv message and flip data to the tty (ldisc) */ + rb = list_first_entry(&priv->tty_inqueue, struct iucv_tty_buffer, list); + + written = 0; + if (!rb->mbuf) { /* message not yet received ... */ + /* allocate mem to store msg data; if no memory is available + * then leave the buffer on the list and re-try later */ + rb->mbuf = kmalloc(rb->msg.length, GFP_ATOMIC); + if (!rb->mbuf) + return -ENOMEM; + + rc = __iucv_message_receive(priv->path, &rb->msg, 0, + rb->mbuf, rb->msg.length, NULL); + switch (rc) { + case 0: /* Successful */ + break; + case 2: /* No message found */ + case 9: /* Message purged */ + break; + default: + written = -EIO; + } + /* remove buffer if an error has occured or received data + * is not correct */ + if (rc || (rb->mbuf->version != MSG_VERSION) || + (rb->msg.length != MSG_SIZE(rb->mbuf->datalen))) + goto out_remove_buffer; + } + + switch (rb->mbuf->type) { + case MSG_TYPE_DATA: + written = min_t(int, rb->mbuf->datalen - rb->offset, count); + memcpy(buf, rb->mbuf->data + rb->offset, written); + if (written < (rb->mbuf->datalen - rb->offset)) { + rb->offset += written; + *has_more_data = 1; + goto out_written; + } + break; + + case MSG_TYPE_WINSIZE: + if (rb->mbuf->datalen != sizeof(struct winsize)) + break; + hvc_resize(priv->hvc, *((struct winsize *)rb->mbuf->data)); + break; + + case MSG_TYPE_ERROR: /* ignored ... */ + case MSG_TYPE_TERMENV: /* ignored ... */ + case MSG_TYPE_TERMIOS: /* ignored ... */ + break; + } + +out_remove_buffer: + list_del(&rb->list); + destroy_tty_buffer(rb); + *has_more_data = !list_empty(&priv->tty_inqueue); + +out_written: + return written; +} + +/** + * hvc_iucv_get_chars() - HVC get_chars operation. + * @vtermno: HVC virtual terminal number. + * @buf: Pointer to a buffer to store data + * @count: Size of buffer available for writing + * + * The hvc_console thread calls this method to read characters from + * the terminal backend. If an IUCV communication path has been established, + * pending IUCV messages are received and data is copied into buffer @buf + * up to @count bytes. + * + * Locking: The routine gets called under an irqsave() spinlock; and + * the routine locks the struct hvc_iucv_private->lock to call + * helper functions. + */ +static int hvc_iucv_get_chars(uint32_t vtermno, char *buf, int count) +{ + struct hvc_iucv_private *priv = hvc_iucv_get_private(vtermno); + int written; + int has_more_data; + + if (count <= 0) + return 0; + + if (!priv) + return -ENODEV; + + spin_lock(&priv->lock); + has_more_data = 0; + written = hvc_iucv_write(priv, buf, count, &has_more_data); + spin_unlock(&priv->lock); + + /* if there are still messages on the queue... schedule another run */ + if (has_more_data) + hvc_kick(); + + return written; +} + +/** + * hvc_iucv_send() - Send an IUCV message containing terminal data. + * @priv: Pointer to struct hvc_iucv_private instance. + * @buf: Buffer containing data to send. + * @size: Size of buffer and amount of data to send. + * + * If an IUCV communication path is established, the function copies the buffer + * data to a newly allocated struct iucv_tty_buffer element, sends the data and + * puts the element to the outqueue. + * + * If there is no IUCV communication path established, the function returns 0. + * If an existing IUCV communicaton path has been severed, the function returns + * -EPIPE (can be passed to HVC layer to cause a tty hangup). + */ +static int hvc_iucv_send(struct hvc_iucv_private *priv, const char *buf, + int count) +{ + struct iucv_tty_buffer *sb; + int rc; + u16 len; + + if (priv->iucv_state == IUCV_SEVERED) + return -EPIPE; + + if (priv->iucv_state == IUCV_DISCONN) + return 0; + + len = min_t(u16, MSG_MAX_DATALEN, count); + + /* allocate internal buffer to store msg data and also compute total + * message length */ + sb = alloc_tty_buffer(len, GFP_ATOMIC); + if (!sb) + return -ENOMEM; + + sb->mbuf->datalen = len; + memcpy(sb->mbuf->data, buf, len); + + list_add_tail(&sb->list, &priv->tty_outqueue); + + rc = __iucv_message_send(priv->path, &sb->msg, 0, 0, + (void *) sb->mbuf, sb->msg.length); + if (rc) { + list_del(&sb->list); + destroy_tty_buffer(sb); + len = 0; + } + + return len; +} + +/** + * hvc_iucv_put_chars() - HVC put_chars operation. + * @vtermno: HVC virtual terminal number. + * @buf: Pointer to an buffer to read data from + * @count: Size of buffer available for reading + * + * The hvc_console thread calls this method to write characters from + * to the terminal backend. + * The function calls hvc_iucv_send() under the lock of the + * struct hvc_iucv_private instance that corresponds to the tty @vtermno. + * + * Locking: The method gets called under an irqsave() spinlock; and + * locks struct hvc_iucv_private->lock. + */ +static int hvc_iucv_put_chars(uint32_t vtermno, const char *buf, int count) +{ + struct hvc_iucv_private *priv = hvc_iucv_get_private(vtermno); + int sent; + + if (count <= 0) + return 0; + + if (!priv) + return -ENODEV; + + spin_lock(&priv->lock); + sent = hvc_iucv_send(priv, buf, count); + spin_unlock(&priv->lock); + + return sent; +} + +/** + * hvc_iucv_notifier_add() - HVC notifier for opening a TTY for the first time. + * @hp: Pointer to the HVC device (struct hvc_struct) + * @id: Additional data (originally passed to hvc_alloc): the index of an struct + * hvc_iucv_private instance. + * + * The function sets the tty state to TTY_OPEN for the struct hvc_iucv_private + * instance that is derived from @id. Always returns 0. + * + * Locking: struct hvc_iucv_private->lock, spin_lock_bh + */ +static int hvc_iucv_notifier_add(struct hvc_struct *hp, int id) +{ + struct hvc_iucv_private *priv; + + priv = hvc_iucv_get_private(id); + if (!priv) + return 0; + + spin_lock_bh(&priv->lock); + priv->tty_state = TTY_OPENED; + spin_unlock_bh(&priv->lock); + + return 0; +} + +/** + * hvc_iucv_cleanup() - Clean up function if the tty portion is finally closed. + * @priv: Pointer to the struct hvc_iucv_private instance. + * + * The functions severs the established IUCV communication path (if any), and + * destroy struct iucv_tty_buffer elements from the in- and outqueue. Finally, + * the functions resets the states to TTY_CLOSED and IUCV_DISCONN. + */ +static void hvc_iucv_cleanup(struct hvc_iucv_private *priv) +{ + destroy_tty_buffer_list(&priv->tty_outqueue); + destroy_tty_buffer_list(&priv->tty_inqueue); + + priv->tty_state = TTY_CLOSED; + priv->iucv_state = IUCV_DISCONN; +} + +/** + * hvc_iucv_notifier_hangup() - HVC notifier for tty hangups. + * @hp: Pointer to the HVC device (struct hvc_struct) + * @id: Additional data (originally passed to hvc_alloc): the index of an struct + * hvc_iucv_private instance. + * + * This routine notifies the HVC backend that a tty hangup (carrier loss, + * virtual or otherwise) has occured. + * + * The HVC backend for z/VM IUCV ignores virtual hangups (vhangup()), to keep + * an existing IUCV communication path established. + * (Background: vhangup() is called from user space (by getty or login) to + * disable writing to the tty by other applications). + * + * If the tty has been opened (e.g. getty) and an established IUCV path has been + * severed (we caused the tty hangup in that case), then the functions invokes + * hvc_iucv_cleanup() to clean up. + * + * Locking: struct hvc_iucv_private->lock + */ +static void hvc_iucv_notifier_hangup(struct hvc_struct *hp, int id) +{ + struct hvc_iucv_private *priv; + + priv = hvc_iucv_get_private(id); + if (!priv) + return; + + spin_lock_bh(&priv->lock); + /* NOTE: If the hangup was scheduled by ourself (from the iucv + * path_servered callback [IUCV_SEVERED]), then we have to + * finally clean up the tty backend structure and set state to + * TTY_CLOSED. + * + * If the tty was hung up otherwise (e.g. vhangup()), then we + * ignore this hangup and keep an established IUCV path open... + * (...the reason is that we are not able to connect back to the + * client if we disconnect on hang up) */ + priv->tty_state = TTY_CLOSED; + + if (priv->iucv_state == IUCV_SEVERED) + hvc_iucv_cleanup(priv); + spin_unlock_bh(&priv->lock); +} + +/** + * hvc_iucv_notifier_del() - HVC notifier for closing a TTY for the last time. + * @hp: Pointer to the HVC device (struct hvc_struct) + * @id: Additional data (originally passed to hvc_alloc): + * the index of an struct hvc_iucv_private instance. + * + * This routine notifies the HVC backend that the last tty device file + * descriptor has been closed. + * The function calls hvc_iucv_cleanup() to clean up the struct hvc_iucv_private + * instance. + * + * Locking: struct hvc_iucv_private->lock + */ +static void hvc_iucv_notifier_del(struct hvc_struct *hp, int id) +{ + struct hvc_iucv_private *priv; + struct iucv_path *path; + + priv = hvc_iucv_get_private(id); + if (!priv) + return; + + spin_lock_bh(&priv->lock); + path = priv->path; /* save reference to IUCV path */ + priv->path = NULL; + hvc_iucv_cleanup(priv); + spin_unlock_bh(&priv->lock); + + /* sever IUCV path outside of priv->lock due to lock ordering of: + * priv->lock <--> iucv_table_lock */ + if (path) { + iucv_path_sever(path, NULL); + iucv_path_free(path); + } +} + +/** + * hvc_iucv_path_pending() - IUCV handler to process a connection request. + * @path: Pending path (struct iucv_path) + * @ipvmid: Originator z/VM system identifier + * @ipuser: User specified data for this path + * (AF_IUCV: port/service name and originator port) + * + * The function uses the @ipuser data to check to determine if the pending + * path belongs to a terminal managed by this HVC backend. + * If the check is successful, then an additional check is done to ensure + * that a terminal cannot be accessed multiple times (only one connection + * to a terminal is allowed). In that particular case, the pending path is + * severed. If it is the first connection, the pending path is accepted and + * associated to the struct hvc_iucv_private. The iucv state is updated to + * reflect that a communication path has been established. + * + * Returns 0 if the path belongs to a terminal managed by the this HVC backend; + * otherwise returns -ENODEV in order to dispatch this path to other handlers. + * + * Locking: struct hvc_iucv_private->lock + */ +static int hvc_iucv_path_pending(struct iucv_path *path, + u8 ipvmid[8], u8 ipuser[16]) +{ + struct hvc_iucv_private *priv; + u8 nuser_data[16]; + int i, rc; + + priv = NULL; + for (i = 0; i < hvc_iucv_devices; i++) + if (hvc_iucv_table[i] && + (0 == memcmp(hvc_iucv_table[i]->srv_name, ipuser, 8))) { + priv = hvc_iucv_table[i]; + break; + } + + if (!priv) + return -ENODEV; + + spin_lock(&priv->lock); + + /* If the terminal is already connected or being severed, then sever + * this path to enforce that there is only ONE established communication + * path per terminal. */ + if (priv->iucv_state != IUCV_DISCONN) { + iucv_path_sever(path, ipuser); + iucv_path_free(path); + goto out_path_handled; + } + + /* accept path */ + memcpy(nuser_data, ipuser + 8, 8); /* remote service (for af_iucv) */ + memcpy(nuser_data + 8, ipuser, 8); /* local service (for af_iucv) */ + path->msglim = 0xffff; /* IUCV MSGLIMIT */ + path->flags &= ~IUCV_IPRMDATA; /* TODO: use IUCV_IPRMDATA */ + rc = iucv_path_accept(path, &hvc_iucv_handler, nuser_data, priv); + if (rc) { + iucv_path_sever(path, ipuser); + iucv_path_free(path); + goto out_path_handled; + } + priv->path = path; + priv->iucv_state = IUCV_CONNECTED; + +out_path_handled: + spin_unlock(&priv->lock); + return 0; +} + +/** + * hvc_iucv_path_severed() - IUCV handler to process a path sever. + * @path: Pending path (struct iucv_path) + * @ipuser: User specified data for this path + * (AF_IUCV: port/service name and originator port) + * + * The function also severs the path (as required by the IUCV protocol) and + * sets the iucv state to IUCV_SEVERED for the associated struct + * hvc_iucv_private instance. Later, the IUCV_SEVERED state triggers a tty + * hangup (hvc_iucv_get_chars() / hvc_iucv_write()). + * + * If tty portion of the HVC is closed then clean up the outqueue in addition. + * + * Locking: struct hvc_iucv_private->lock + */ +static void hvc_iucv_path_severed(struct iucv_path *path, u8 ipuser[16]) +{ + struct hvc_iucv_private *priv = path->private; + + spin_lock(&priv->lock); + priv->iucv_state = IUCV_SEVERED; + + /* NOTE: If the tty has not yet been opened by a getty program + * (e.g. to see console messages), then cleanup the + * hvc_iucv_private structure to allow re-connects. + * + * If the tty has been opened, the get_chars() callback returns + * -EPIPE to signal the hvc console layer to hang up the tty. */ + priv->path = NULL; + if (priv->tty_state == TTY_CLOSED) + hvc_iucv_cleanup(priv); + spin_unlock(&priv->lock); + + /* finally sever path (outside of priv->lock due to lock ordering) */ + iucv_path_sever(path, ipuser); + iucv_path_free(path); +} + +/** + * hvc_iucv_msg_pending() - IUCV handler to process an incoming IUCV message. + * @path: Pending path (struct iucv_path) + * @msg: Pointer to the IUCV message + * + * The function stores an incoming message on the input queue for later + * processing (by hvc_iucv_get_chars() / hvc_iucv_write()). + * However, if the tty has not yet been opened, the message is rejected. + * + * Locking: struct hvc_iucv_private->lock + */ +static void hvc_iucv_msg_pending(struct iucv_path *path, + struct iucv_message *msg) +{ + struct hvc_iucv_private *priv = path->private; + struct iucv_tty_buffer *rb; + + spin_lock(&priv->lock); + + /* reject messages if tty has not yet been opened */ + if (priv->tty_state == TTY_CLOSED) { + iucv_message_reject(path, msg); + goto unlock_return; + } + + /* allocate buffer an empty buffer element */ + rb = alloc_tty_buffer(0, GFP_ATOMIC); + if (!rb) { + iucv_message_reject(path, msg); + goto unlock_return; /* -ENOMEM */ + } + rb->msg = *msg; + + list_add_tail(&rb->list, &priv->tty_inqueue); + + hvc_kick(); /* wakup hvc console thread */ + +unlock_return: + spin_unlock(&priv->lock); +} + +/** + * hvc_iucv_msg_complete() - IUCV handler to process message completion + * @path: Pending path (struct iucv_path) + * @msg: Pointer to the IUCV message + * + * The function is called upon completion of message delivery and the + * message is removed from the outqueue. Additional delivery information + * can be found in msg->audit: rejected messages (0x040000 (IPADRJCT)) and + * purged messages (0x010000 (IPADPGNR)). + * + * Locking: struct hvc_iucv_private->lock + */ +static void hvc_iucv_msg_complete(struct iucv_path *path, + struct iucv_message *msg) +{ + struct hvc_iucv_private *priv = path->private; + struct iucv_tty_buffer *ent, *next; + LIST_HEAD(list_remove); + + spin_lock(&priv->lock); + list_for_each_entry_safe(ent, next, &priv->tty_outqueue, list) + if (ent->msg.id == msg->id) { + list_move(&ent->list, &list_remove); + break; + } + spin_unlock(&priv->lock); + destroy_tty_buffer_list(&list_remove); +} + + +/* HVC operations */ +static struct hv_ops hvc_iucv_ops = { + .get_chars = hvc_iucv_get_chars, + .put_chars = hvc_iucv_put_chars, + .notifier_add = hvc_iucv_notifier_add, + .notifier_del = hvc_iucv_notifier_del, + .notifier_hangup = hvc_iucv_notifier_hangup, +}; + +/** + * hvc_iucv_alloc() - Allocates a new struct hvc_iucv_private instance + * @id: hvc_iucv_table index + * + * This function allocates a new hvc_iucv_private struct and put the + * instance into hvc_iucv_table at index @id. + * Returns 0 on success; otherwise non-zero. + */ +static int __init hvc_iucv_alloc(int id) +{ + struct hvc_iucv_private *priv; + char name[9]; + int rc; + + priv = kzalloc(sizeof(struct hvc_iucv_private), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + spin_lock_init(&priv->lock); + INIT_LIST_HEAD(&priv->tty_outqueue); + INIT_LIST_HEAD(&priv->tty_inqueue); + + /* Finally allocate hvc */ + priv->hvc = hvc_alloc(HVC_IUCV_MAGIC + id, + HVC_IUCV_MAGIC + id, &hvc_iucv_ops, PAGE_SIZE); + if (IS_ERR(priv->hvc)) { + rc = PTR_ERR(priv->hvc); + kfree(priv); + return rc; + } + + /* setup iucv related information */ + snprintf(name, 9, "ihvc%-4d", id); + memcpy(priv->srv_name, name, 8); + ASCEBC(priv->srv_name, 8); + + hvc_iucv_table[id] = priv; + return 0; +} + +/** + * hvc_iucv_init() - Initialization of HVC backend for z/VM IUCV + */ +static int __init hvc_iucv_init(void) +{ + int rc, i; + + if (!MACHINE_IS_VM) { + pr_warning("The z/VM IUCV Hypervisor console cannot be " + "used without z/VM.\n"); + return -ENODEV; + } + + if (!hvc_iucv_devices) + return -ENODEV; + + if (hvc_iucv_devices > MAX_HVC_IUCV_LINES) + return -EINVAL; + + hvc_iucv_buffer_cache = kmem_cache_create(KMSG_COMPONENT, + sizeof(struct iucv_tty_buffer), + 0, 0, NULL); + if (!hvc_iucv_buffer_cache) { + pr_err("Not enough memory for driver initialization " + "(rs=%d).\n", 1); + return -ENOMEM; + } + + hvc_iucv_mempool = mempool_create_slab_pool(MEMPOOL_MIN_NR, + hvc_iucv_buffer_cache); + if (!hvc_iucv_mempool) { + pr_err("Not enough memory for driver initialization " + "(rs=%d).\n", 2); + kmem_cache_destroy(hvc_iucv_buffer_cache); + return -ENOMEM; + } + + /* allocate hvc_iucv_private structs */ + for (i = 0; i < hvc_iucv_devices; i++) { + rc = hvc_iucv_alloc(i); + if (rc) { + pr_err("Could not create new z/VM IUCV HVC backend " + "rc=%d.\n", rc); + goto out_error_hvc; + } + } + + /* register IUCV callback handler */ + rc = iucv_register(&hvc_iucv_handler, 0); + if (rc) { + pr_err("Could not register iucv handler (rc=%d).\n", rc); + goto out_error_iucv; + } + + return 0; + +out_error_iucv: + iucv_unregister(&hvc_iucv_handler, 0); +out_error_hvc: + for (i = 0; i < hvc_iucv_devices; i++) + if (hvc_iucv_table[i]) { + if (hvc_iucv_table[i]->hvc) + hvc_remove(hvc_iucv_table[i]->hvc); + kfree(hvc_iucv_table[i]); + } + mempool_destroy(hvc_iucv_mempool); + kmem_cache_destroy(hvc_iucv_buffer_cache); + return rc; +} + +/** + * hvc_iucv_console_init() - Early console initialization + */ +static int __init hvc_iucv_console_init(void) +{ + if (!MACHINE_IS_VM || !hvc_iucv_devices) + return -ENODEV; + return hvc_instantiate(HVC_IUCV_MAGIC, 0, &hvc_iucv_ops); +} + +/** + * hvc_iucv_config() - Parsing of hvc_iucv= kernel command line parameter + * @val: Parameter value (numeric) + */ +static int __init hvc_iucv_config(char *val) +{ + return strict_strtoul(val, 10, &hvc_iucv_devices); +} + + +module_init(hvc_iucv_init); +console_initcall(hvc_iucv_console_init); +__setup("hvc_iucv=", hvc_iucv_config); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("HVC back-end for z/VM IUCV."); +MODULE_AUTHOR("Hendrik Brueckner "); diff --git a/drivers/char/hvc_udbg.c b/drivers/char/hvc_udbg.c new file mode 100644 index 0000000000000000000000000000000000000000..bd63ba878a560eecf3513dd58989331337c1a7f4 --- /dev/null +++ b/drivers/char/hvc_udbg.c @@ -0,0 +1,96 @@ +/* + * udbg interface to hvc_console.c + * + * (C) Copyright David Gibson, IBM Corporation 2008. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "hvc_console.h" + +struct hvc_struct *hvc_udbg_dev; + +static int hvc_udbg_put(uint32_t vtermno, const char *buf, int count) +{ + int i; + + for (i = 0; i < count; i++) + udbg_putc(buf[i]); + + return i; +} + +static int hvc_udbg_get(uint32_t vtermno, char *buf, int count) +{ + int i, c; + + if (!udbg_getc_poll) + return 0; + + for (i = 0; i < count; i++) { + if ((c = udbg_getc_poll()) == -1) + break; + buf[i] = c; + } + + return i; +} + +static struct hv_ops hvc_udbg_ops = { + .get_chars = hvc_udbg_get, + .put_chars = hvc_udbg_put, +}; + +static int __init hvc_udbg_init(void) +{ + struct hvc_struct *hp; + + BUG_ON(hvc_udbg_dev); + + hp = hvc_alloc(0, NO_IRQ, &hvc_udbg_ops, 16); + if (IS_ERR(hp)) + return PTR_ERR(hp); + + hvc_udbg_dev = hp; + + return 0; +} +module_init(hvc_udbg_init); + +static void __exit hvc_udbg_exit(void) +{ + if (hvc_udbg_dev) + hvc_remove(hvc_udbg_dev); +} +module_exit(hvc_udbg_exit); + +static int __init hvc_udbg_console_init(void) +{ + hvc_instantiate(0, 0, &hvc_udbg_ops); + add_preferred_console("hvc", 0, NULL); + + return 0; +} +console_initcall(hvc_udbg_console_init); diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c index 019e0b58593da4f2356ef3725d03cd7f186ed1ad..bd62dc86b47d09148f7ee80932031d8b7ecf5fe5 100644 --- a/drivers/char/hvc_vio.c +++ b/drivers/char/hvc_vio.c @@ -153,8 +153,10 @@ static int hvc_find_vtys(void) /* We have statically defined space for only a certain number * of console adapters. */ - if (num_found >= MAX_NR_HVC_CONSOLES) + if (num_found >= MAX_NR_HVC_CONSOLES) { + of_node_put(vty); break; + } vtermno = of_get_property(vty, "reg", NULL); if (!vtermno) diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c index 473d9b14439a9cfdf4f8d071ef8da5553f2e3e90..6e6eb445d374f3d059ba3833c27b59e04bd73aa3 100644 --- a/drivers/char/hvcs.c +++ b/drivers/char/hvcs.c @@ -269,7 +269,7 @@ struct hvcs_struct { unsigned int index; struct tty_struct *tty; - unsigned int open_count; + int open_count; /* * Used to tell the driver kernel_thread what operations need to take diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c index 59c6f9ab94e4b279700ff1f50f1f39ae02b54fa2..af055287271a6f4a27b9f15136d5ab5e96dee2cc 100644 --- a/drivers/char/hvsi.c +++ b/drivers/char/hvsi.c @@ -75,7 +75,7 @@ struct hvsi_struct { spinlock_t lock; int index; struct tty_struct *tty; - unsigned int count; + int count; uint8_t throttle_buf[128]; uint8_t outbuf[N_OUTBUF]; /* to implement write_room and chars_in_buffer */ /* inbuf is for packet reassembly. leave a little room for leftovers. */ diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c index 8054ee839b3c36acb0b57c7f477d139f2c3ac06c..88cee4099be940c294127d0a172996d90c597912 100644 --- a/drivers/char/nvram.c +++ b/drivers/char/nvram.c @@ -32,9 +32,10 @@ * added changelog * 1.2 Erik Gilling: Cobalt Networks support * Tim Hockin: general cleanup, Cobalt support + * 1.3 Wim Van Sebroeck: convert PRINT_PROC to seq_file */ -#define NVRAM_VERSION "1.2" +#define NVRAM_VERSION "1.3" #include #include @@ -46,7 +47,7 @@ /* select machine configuration */ #if defined(CONFIG_ATARI) # define MACH ATARI -#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) /* and others?? */ +#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) /* and ?? */ # define MACH PC #else # error Cannot build nvram driver for this machine configuration. @@ -106,10 +107,11 @@ #include #include #include +#include #include +#include +#include -#include -#include #include static DEFINE_SPINLOCK(nvram_state_lock); @@ -122,8 +124,8 @@ static int mach_check_checksum(void); static void mach_set_checksum(void); #ifdef CONFIG_PROC_FS -static int mach_proc_infos(unsigned char *contents, char *buffer, int *len, - off_t *begin, off_t offset, int size); +static void mach_proc_infos(unsigned char *contents, struct seq_file *seq, + void *offset); #endif /* @@ -133,18 +135,17 @@ static int mach_proc_infos(unsigned char *contents, char *buffer, int *len, * * It is worth noting that these functions all access bytes of general * purpose memory in the NVRAM - that is to say, they all add the - * NVRAM_FIRST_BYTE offset. Pass them offsets into NVRAM as if you did not + * NVRAM_FIRST_BYTE offset. Pass them offsets into NVRAM as if you did not * know about the RTC cruft. */ -unsigned char -__nvram_read_byte(int i) +unsigned char __nvram_read_byte(int i) { return CMOS_READ(NVRAM_FIRST_BYTE + i); } +EXPORT_SYMBOL(__nvram_read_byte); -unsigned char -nvram_read_byte(int i) +unsigned char nvram_read_byte(int i) { unsigned long flags; unsigned char c; @@ -154,16 +155,16 @@ nvram_read_byte(int i) spin_unlock_irqrestore(&rtc_lock, flags); return c; } +EXPORT_SYMBOL(nvram_read_byte); /* This races nicely with trying to read with checksum checking (nvram_read) */ -void -__nvram_write_byte(unsigned char c, int i) +void __nvram_write_byte(unsigned char c, int i) { CMOS_WRITE(c, NVRAM_FIRST_BYTE + i); } +EXPORT_SYMBOL(__nvram_write_byte); -void -nvram_write_byte(unsigned char c, int i) +void nvram_write_byte(unsigned char c, int i) { unsigned long flags; @@ -171,15 +172,15 @@ nvram_write_byte(unsigned char c, int i) __nvram_write_byte(c, i); spin_unlock_irqrestore(&rtc_lock, flags); } +EXPORT_SYMBOL(nvram_write_byte); -int -__nvram_check_checksum(void) +int __nvram_check_checksum(void) { return mach_check_checksum(); } +EXPORT_SYMBOL(__nvram_check_checksum); -int -nvram_check_checksum(void) +int nvram_check_checksum(void) { unsigned long flags; int rv; @@ -189,16 +190,15 @@ nvram_check_checksum(void) spin_unlock_irqrestore(&rtc_lock, flags); return rv; } +EXPORT_SYMBOL(nvram_check_checksum); -static void -__nvram_set_checksum(void) +static void __nvram_set_checksum(void) { mach_set_checksum(); } #if 0 -void -nvram_set_checksum(void) +void nvram_set_checksum(void) { unsigned long flags; @@ -212,7 +212,7 @@ nvram_set_checksum(void) * The are the file operation function for user access to /dev/nvram */ -static loff_t nvram_llseek(struct file *file,loff_t offset, int origin ) +static loff_t nvram_llseek(struct file *file, loff_t offset, int origin) { lock_kernel(); switch (origin) { @@ -230,8 +230,8 @@ static loff_t nvram_llseek(struct file *file,loff_t offset, int origin ) return (offset >= 0) ? (file->f_pos = offset) : -EINVAL; } -static ssize_t -nvram_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) +static ssize_t nvram_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) { unsigned char contents[NVRAM_BYTES]; unsigned i = *ppos; @@ -254,13 +254,13 @@ nvram_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) return tmp - contents; - checksum_err: +checksum_err: spin_unlock_irq(&rtc_lock); return -EIO; } -static ssize_t -nvram_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) +static ssize_t nvram_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) { unsigned char contents[NVRAM_BYTES]; unsigned i = *ppos; @@ -287,14 +287,13 @@ nvram_write(struct file *file, const char __user *buf, size_t count, loff_t *ppo return tmp - contents; - checksum_err: +checksum_err: spin_unlock_irq(&rtc_lock); return -EIO; } -static int -nvram_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static int nvram_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) { int i; @@ -315,7 +314,7 @@ nvram_ioctl(struct inode *inode, struct file *file, return 0; case NVRAM_SETCKS: - /* just set checksum, contents unchanged (maybe useful after + /* just set checksum, contents unchanged (maybe useful after * checksum garbaged somehow...) */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; @@ -330,8 +329,7 @@ nvram_ioctl(struct inode *inode, struct file *file, } } -static int -nvram_open(struct inode *inode, struct file *file) +static int nvram_open(struct inode *inode, struct file *file) { lock_kernel(); spin_lock(&nvram_state_lock); @@ -356,8 +354,7 @@ nvram_open(struct inode *inode, struct file *file) return 0; } -static int -nvram_release(struct inode *inode, struct file *file) +static int nvram_release(struct inode *inode, struct file *file) { spin_lock(&nvram_state_lock); @@ -375,48 +372,47 @@ nvram_release(struct inode *inode, struct file *file) } #ifndef CONFIG_PROC_FS -static int -nvram_read_proc(char *buffer, char **start, off_t offset, - int size, int *eof, void *data) +static int nvram_add_proc_fs(void) { return 0; } + #else -static int -nvram_read_proc(char *buffer, char **start, off_t offset, - int size, int *eof, void *data) +static int nvram_proc_read(struct seq_file *seq, void *offset) { unsigned char contents[NVRAM_BYTES]; - int i, len = 0; - off_t begin = 0; + int i = 0; spin_lock_irq(&rtc_lock); for (i = 0; i < NVRAM_BYTES; ++i) contents[i] = __nvram_read_byte(i); spin_unlock_irq(&rtc_lock); - *eof = mach_proc_infos(contents, buffer, &len, &begin, offset, size); + mach_proc_infos(contents, seq, offset); - if (offset >= begin + len) - return 0; - *start = buffer + (offset - begin); - return (size < begin + len - offset) ? size : begin + len - offset; + return 0; +} +static int nvram_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, nvram_proc_read, NULL); } -/* This macro frees the machine specific function from bounds checking and - * this like that... */ -#define PRINT_PROC(fmt,args...) \ - do { \ - *len += sprintf(buffer+*len, fmt, ##args); \ - if (*begin + *len > offset + size) \ - return 0; \ - if (*begin + *len < offset) { \ - *begin += *len; \ - *len = 0; \ - } \ - } while(0) +static const struct file_operations nvram_proc_fops = { + .owner = THIS_MODULE, + .open = nvram_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int nvram_add_proc_fs(void) +{ + if (!proc_create("driver/nvram", 0, NULL, &nvram_proc_fops)) + return -ENOMEM; + return 0; +} #endif /* CONFIG_PROC_FS */ @@ -436,8 +432,7 @@ static struct miscdevice nvram_dev = { &nvram_fops }; -static int __init -nvram_init(void) +static int __init nvram_init(void) { int ret; @@ -451,23 +446,21 @@ nvram_init(void) NVRAM_MINOR); goto out; } - if (!create_proc_read_entry("driver/nvram", 0, NULL, nvram_read_proc, - NULL)) { + ret = nvram_add_proc_fs(); + if (ret) { printk(KERN_ERR "nvram: can't create /proc/driver/nvram\n"); - ret = -ENOMEM; goto outmisc; } ret = 0; printk(KERN_INFO "Non-volatile memory driver v" NVRAM_VERSION "\n"); - out: +out: return ret; - outmisc: +outmisc: misc_deregister(&nvram_dev); goto out; } -static void __exit -nvram_cleanup_module(void) +static void __exit nvram_cleanup_module(void) { remove_proc_entry("driver/nvram", NULL); misc_deregister(&nvram_dev); @@ -482,8 +475,7 @@ module_exit(nvram_cleanup_module); #if MACH == PC -static int -pc_check_checksum(void) +static int pc_check_checksum(void) { int i; unsigned short sum = 0; @@ -493,11 +485,10 @@ pc_check_checksum(void) sum += __nvram_read_byte(i); expect = __nvram_read_byte(PC_CKS_LOC)<<8 | __nvram_read_byte(PC_CKS_LOC+1); - return ((sum & 0xffff) == expect); + return (sum & 0xffff) == expect; } -static void -pc_set_checksum(void) +static void pc_set_checksum(void) { int i; unsigned short sum = 0; @@ -522,9 +513,8 @@ static char *gfx_types[] = { "monochrome", }; -static int -pc_proc_infos(unsigned char *nvram, char *buffer, int *len, - off_t *begin, off_t offset, int size) +static void pc_proc_infos(unsigned char *nvram, struct seq_file *seq, + void *offset) { int checksum; int type; @@ -533,56 +523,57 @@ pc_proc_infos(unsigned char *nvram, char *buffer, int *len, checksum = __nvram_check_checksum(); spin_unlock_irq(&rtc_lock); - PRINT_PROC("Checksum status: %svalid\n", checksum ? "" : "not "); + seq_printf(seq, "Checksum status: %svalid\n", checksum ? "" : "not "); - PRINT_PROC("# floppies : %d\n", + seq_printf(seq, "# floppies : %d\n", (nvram[6] & 1) ? (nvram[6] >> 6) + 1 : 0); - PRINT_PROC("Floppy 0 type : "); + seq_printf(seq, "Floppy 0 type : "); type = nvram[2] >> 4; if (type < ARRAY_SIZE(floppy_types)) - PRINT_PROC("%s\n", floppy_types[type]); + seq_printf(seq, "%s\n", floppy_types[type]); else - PRINT_PROC("%d (unknown)\n", type); - PRINT_PROC("Floppy 1 type : "); + seq_printf(seq, "%d (unknown)\n", type); + seq_printf(seq, "Floppy 1 type : "); type = nvram[2] & 0x0f; if (type < ARRAY_SIZE(floppy_types)) - PRINT_PROC("%s\n", floppy_types[type]); + seq_printf(seq, "%s\n", floppy_types[type]); else - PRINT_PROC("%d (unknown)\n", type); + seq_printf(seq, "%d (unknown)\n", type); - PRINT_PROC("HD 0 type : "); + seq_printf(seq, "HD 0 type : "); type = nvram[4] >> 4; if (type) - PRINT_PROC("%02x\n", type == 0x0f ? nvram[11] : type); + seq_printf(seq, "%02x\n", type == 0x0f ? nvram[11] : type); else - PRINT_PROC("none\n"); + seq_printf(seq, "none\n"); - PRINT_PROC("HD 1 type : "); + seq_printf(seq, "HD 1 type : "); type = nvram[4] & 0x0f; if (type) - PRINT_PROC("%02x\n", type == 0x0f ? nvram[12] : type); + seq_printf(seq, "%02x\n", type == 0x0f ? nvram[12] : type); else - PRINT_PROC("none\n"); + seq_printf(seq, "none\n"); - PRINT_PROC("HD type 48 data: %d/%d/%d C/H/S, precomp %d, lz %d\n", + seq_printf(seq, "HD type 48 data: %d/%d/%d C/H/S, precomp %d, lz %d\n", nvram[18] | (nvram[19] << 8), nvram[20], nvram[25], nvram[21] | (nvram[22] << 8), nvram[23] | (nvram[24] << 8)); - PRINT_PROC("HD type 49 data: %d/%d/%d C/H/S, precomp %d, lz %d\n", + seq_printf(seq, "HD type 49 data: %d/%d/%d C/H/S, precomp %d, lz %d\n", nvram[39] | (nvram[40] << 8), nvram[41], nvram[46], nvram[42] | (nvram[43] << 8), nvram[44] | (nvram[45] << 8)); - PRINT_PROC("DOS base memory: %d kB\n", nvram[7] | (nvram[8] << 8)); - PRINT_PROC("Extended memory: %d kB (configured), %d kB (tested)\n", + seq_printf(seq, "DOS base memory: %d kB\n", nvram[7] | (nvram[8] << 8)); + seq_printf(seq, "Extended memory: %d kB (configured), %d kB (tested)\n", nvram[9] | (nvram[10] << 8), nvram[34] | (nvram[35] << 8)); - PRINT_PROC("Gfx adapter : %s\n", gfx_types[(nvram[6] >> 4) & 3]); + seq_printf(seq, "Gfx adapter : %s\n", + gfx_types[(nvram[6] >> 4) & 3]); - PRINT_PROC("FPU : %sinstalled\n", + seq_printf(seq, "FPU : %sinstalled\n", (nvram[6] & 2) ? "" : "not "); - return 1; + return; } #endif @@ -590,20 +581,18 @@ pc_proc_infos(unsigned char *nvram, char *buffer, int *len, #if MACH == ATARI -static int -atari_check_checksum(void) +static int atari_check_checksum(void) { int i; unsigned char sum = 0; for (i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i) sum += __nvram_read_byte(i); - return (__nvram_read_byte(ATARI_CKS_LOC) == (~sum & 0xff) && - __nvram_read_byte(ATARI_CKS_LOC + 1) == (sum & 0xff)); + return (__nvram_read_byte(ATARI_CKS_LOC) == (~sum & 0xff)) && + (__nvram_read_byte(ATARI_CKS_LOC + 1) == (sum & 0xff)); } -static void -atari_set_checksum(void) +static void atari_set_checksum(void) { int i; unsigned char sum = 0; @@ -654,82 +643,75 @@ static char *colors[] = { "2", "4", "16", "256", "65536", "??", "??", "??" }; -static int -atari_proc_infos(unsigned char *nvram, char *buffer, int *len, - off_t *begin, off_t offset, int size) +static void atari_proc_infos(unsigned char *nvram, struct seq_file *seq, + void *offset) { int checksum = nvram_check_checksum(); int i; unsigned vmode; - PRINT_PROC("Checksum status : %svalid\n", checksum ? "" : "not "); + seq_printf(seq, "Checksum status : %svalid\n", checksum ? "" : "not "); - PRINT_PROC("Boot preference : "); + seq_printf(seq, "Boot preference : "); for (i = ARRAY_SIZE(boot_prefs) - 1; i >= 0; --i) { if (nvram[1] == boot_prefs[i].val) { - PRINT_PROC("%s\n", boot_prefs[i].name); + seq_printf(seq, "%s\n", boot_prefs[i].name); break; } } if (i < 0) - PRINT_PROC("0x%02x (undefined)\n", nvram[1]); + seq_printf(seq, "0x%02x (undefined)\n", nvram[1]); - PRINT_PROC("SCSI arbitration : %s\n", + seq_printf(seq, "SCSI arbitration : %s\n", (nvram[16] & 0x80) ? "on" : "off"); - PRINT_PROC("SCSI host ID : "); + seq_printf(seq, "SCSI host ID : "); if (nvram[16] & 0x80) - PRINT_PROC("%d\n", nvram[16] & 7); + seq_printf(seq, "%d\n", nvram[16] & 7); else - PRINT_PROC("n/a\n"); + seq_printf(seq, "n/a\n"); /* the following entries are defined only for the Falcon */ if ((atari_mch_cookie >> 16) != ATARI_MCH_FALCON) - return 1; + return; - PRINT_PROC("OS language : "); + seq_printf(seq, "OS language : "); if (nvram[6] < ARRAY_SIZE(languages)) - PRINT_PROC("%s\n", languages[nvram[6]]); + seq_printf(seq, "%s\n", languages[nvram[6]]); else - PRINT_PROC("%u (undefined)\n", nvram[6]); - PRINT_PROC("Keyboard language: "); + seq_printf(seq, "%u (undefined)\n", nvram[6]); + seq_printf(seq, "Keyboard language: "); if (nvram[7] < ARRAY_SIZE(languages)) - PRINT_PROC("%s\n", languages[nvram[7]]); + seq_printf(seq, "%s\n", languages[nvram[7]]); else - PRINT_PROC("%u (undefined)\n", nvram[7]); - PRINT_PROC("Date format : "); - PRINT_PROC(dateformat[nvram[8] & 7], + seq_printf(seq, "%u (undefined)\n", nvram[7]); + seq_printf(seq, "Date format : "); + seq_printf(seq, dateformat[nvram[8] & 7], nvram[9] ? nvram[9] : '/', nvram[9] ? nvram[9] : '/'); - PRINT_PROC(", %dh clock\n", nvram[8] & 16 ? 24 : 12); - PRINT_PROC("Boot delay : "); + seq_printf(seq, ", %dh clock\n", nvram[8] & 16 ? 24 : 12); + seq_printf(seq, "Boot delay : "); if (nvram[10] == 0) - PRINT_PROC("default"); + seq_printf(seq, "default"); else - PRINT_PROC("%ds%s\n", nvram[10], + seq_printf(seq, "%ds%s\n", nvram[10], nvram[10] < 8 ? ", no memory test" : ""); vmode = (nvram[14] << 8) || nvram[15]; - PRINT_PROC("Video mode : %s colors, %d columns, %s %s monitor\n", + seq_printf(seq, + "Video mode : %s colors, %d columns, %s %s monitor\n", colors[vmode & 7], vmode & 8 ? 80 : 40, vmode & 16 ? "VGA" : "TV", vmode & 32 ? "PAL" : "NTSC"); - PRINT_PROC(" %soverscan, compat. mode %s%s\n", + seq_printf(seq, " %soverscan, compat. mode %s%s\n", vmode & 64 ? "" : "no ", vmode & 128 ? "on" : "off", vmode & 256 ? (vmode & 16 ? ", line doubling" : ", half screen") : ""); - return 1; + return; } #endif #endif /* MACH == ATARI */ MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(__nvram_read_byte); -EXPORT_SYMBOL(nvram_read_byte); -EXPORT_SYMBOL(__nvram_write_byte); -EXPORT_SYMBOL(nvram_write_byte); -EXPORT_SYMBOL(__nvram_check_checksum); -EXPORT_SYMBOL(nvram_check_checksum); MODULE_ALIAS_MISCDEV(NVRAM_MINOR); diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index ce0d9da52a8ab808a24e8d30bff27d631b474713..94966edfb44dedc340d4d81f230c43a0aec9b7bf 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -274,6 +274,22 @@ static struct sysrq_key_op sysrq_showstate_blocked_op = { .enable_mask = SYSRQ_ENABLE_DUMP, }; +#ifdef CONFIG_TRACING +#include + +static void sysrq_ftrace_dump(int key, struct tty_struct *tty) +{ + ftrace_dump(); +} +static struct sysrq_key_op sysrq_ftrace_dump_op = { + .handler = sysrq_ftrace_dump, + .help_msg = "dumpZ-ftrace-buffer", + .action_msg = "Dump ftrace buffer", + .enable_mask = SYSRQ_ENABLE_DUMP, +}; +#else +#define sysrq_ftrace_dump_op (*(struct sysrq_key_op *)0) +#endif static void sysrq_handle_showmem(int key, struct tty_struct *tty) { @@ -406,7 +422,7 @@ static struct sysrq_key_op *sysrq_key_table[36] = { NULL, /* x */ /* y: May be registered on sparc64 for global register dump */ NULL, /* y */ - NULL /* z */ + &sysrq_ftrace_dump_op, /* z */ }; /* key2index calculation, -1 on invalid index */ diff --git a/drivers/char/tty_audit.c b/drivers/char/tty_audit.c index 5787249934c8b01b1603b38677cf5f55ff5a4ed9..34ab6d798f819ebf2a62ad56f0abdfec1addd8d2 100644 --- a/drivers/char/tty_audit.c +++ b/drivers/char/tty_audit.c @@ -67,6 +67,29 @@ static void tty_audit_buf_put(struct tty_audit_buf *buf) tty_audit_buf_free(buf); } +static void tty_audit_log(const char *description, struct task_struct *tsk, + uid_t loginuid, unsigned sessionid, int major, + int minor, unsigned char *data, size_t size) +{ + struct audit_buffer *ab; + + ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_TTY); + if (ab) { + char name[sizeof(tsk->comm)]; + uid_t uid = task_uid(tsk); + + audit_log_format(ab, "%s pid=%u uid=%u auid=%u ses=%u " + "major=%d minor=%d comm=", description, + tsk->pid, uid, loginuid, sessionid, + major, minor); + get_task_comm(name, tsk); + audit_log_untrustedstring(ab, name); + audit_log_format(ab, " data="); + audit_log_n_hex(ab, data, size); + audit_log_end(ab); + } +} + /** * tty_audit_buf_push - Push buffered data out * @@ -77,25 +100,12 @@ static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid, unsigned int sessionid, struct tty_audit_buf *buf) { - struct audit_buffer *ab; - if (buf->valid == 0) return; if (audit_enabled == 0) return; - ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_TTY); - if (ab) { - char name[sizeof(tsk->comm)]; - - audit_log_format(ab, "tty pid=%u uid=%u auid=%u ses=%u " - "major=%d minor=%d comm=", tsk->pid, tsk->uid, - loginuid, sessionid, buf->major, buf->minor); - get_task_comm(name, tsk); - audit_log_untrustedstring(ab, name); - audit_log_format(ab, " data="); - audit_log_n_hex(ab, buf->data, buf->valid); - audit_log_end(ab); - } + tty_audit_log("tty", tsk, loginuid, sessionid, buf->major, buf->minor, + buf->data, buf->valid); buf->valid = 0; } @@ -149,6 +159,42 @@ void tty_audit_fork(struct signal_struct *sig) sig->tty_audit_buf = NULL; } +/** + * tty_audit_tiocsti - Log TIOCSTI + */ +void tty_audit_tiocsti(struct tty_struct *tty, char ch) +{ + struct tty_audit_buf *buf; + int major, minor, should_audit; + + spin_lock_irq(¤t->sighand->siglock); + should_audit = current->signal->audit_tty; + buf = current->signal->tty_audit_buf; + if (buf) + atomic_inc(&buf->count); + spin_unlock_irq(¤t->sighand->siglock); + + major = tty->driver->major; + minor = tty->driver->minor_start + tty->index; + if (buf) { + mutex_lock(&buf->mutex); + if (buf->major == major && buf->minor == minor) + tty_audit_buf_push_current(buf); + mutex_unlock(&buf->mutex); + tty_audit_buf_put(buf); + } + + if (should_audit && audit_enabled) { + uid_t auid; + unsigned int sessionid; + + auid = audit_get_loginuid(current); + sessionid = audit_get_sessionid(current); + tty_audit_log("ioctl=TIOCSTI", current, auid, sessionid, major, + minor, &ch, 1); + } +} + /** * tty_audit_push_task - Flush task's pending audit data */ diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 1412a8d1e58de75059b5687b533e77e4667f44a3..db15f9ba7c0bd1324afdfdedb5bf1c5ba2948320 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -2018,6 +2018,7 @@ static int tiocsti(struct tty_struct *tty, char __user *p) return -EPERM; if (get_user(ch, p)) return -EFAULT; + tty_audit_tiocsti(tty, ch); ld = tty_ldisc_ref_wait(tty); ld->ops->receive_buf(tty, &ch, &mbz, 1); tty_ldisc_deref(ld); diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c index 5c9f67f98d10b43e58b2736d07ca76b8f498faac..c5afc98e2675009ab703a3ae361956d3f284fdf2 100644 --- a/drivers/connector/cn_proc.c +++ b/drivers/connector/cn_proc.c @@ -106,6 +106,7 @@ void proc_id_connector(struct task_struct *task, int which_id) struct proc_event *ev; __u8 buffer[CN_PROC_MSG_SIZE]; struct timespec ts; + const struct cred *cred; if (atomic_read(&proc_event_num_listeners) < 1) return; @@ -115,14 +116,19 @@ void proc_id_connector(struct task_struct *task, int which_id) ev->what = which_id; ev->event_data.id.process_pid = task->pid; ev->event_data.id.process_tgid = task->tgid; + rcu_read_lock(); + cred = __task_cred(task); if (which_id == PROC_EVENT_UID) { - ev->event_data.id.r.ruid = task->uid; - ev->event_data.id.e.euid = task->euid; + ev->event_data.id.r.ruid = cred->uid; + ev->event_data.id.e.euid = cred->euid; } else if (which_id == PROC_EVENT_GID) { - ev->event_data.id.r.rgid = task->gid; - ev->event_data.id.e.egid = task->egid; - } else + ev->event_data.id.r.rgid = cred->gid; + ev->event_data.id.e.egid = cred->egid; + } else { + rcu_read_unlock(); return; + } + rcu_read_unlock(); get_seq(&msg->seq, &ev->cpu); ktime_get_ts(&ts); /* get high res monotonic timestamp */ put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns); diff --git a/drivers/crypto/hifn_795x.c b/drivers/crypto/hifn_795x.c index 4d22b21bd3e30ad872adaef9b87cd003904832bd..0c79fe7f15673563257fe6a3a01a0c451f6dd997 100644 --- a/drivers/crypto/hifn_795x.c +++ b/drivers/crypto/hifn_795x.c @@ -38,9 +38,6 @@ #include -#undef dprintk - -#define HIFN_TEST //#define HIFN_DEBUG #ifdef HIFN_DEBUG @@ -363,14 +360,14 @@ static atomic_t hifn_dev_number; #define HIFN_NAMESIZE 32 #define HIFN_MAX_RESULT_ORDER 5 -#define HIFN_D_CMD_RSIZE 24*4 -#define HIFN_D_SRC_RSIZE 80*4 -#define HIFN_D_DST_RSIZE 80*4 -#define HIFN_D_RES_RSIZE 24*4 +#define HIFN_D_CMD_RSIZE 24*1 +#define HIFN_D_SRC_RSIZE 80*1 +#define HIFN_D_DST_RSIZE 80*1 +#define HIFN_D_RES_RSIZE 24*1 #define HIFN_D_DST_DALIGN 4 -#define HIFN_QUEUE_LENGTH HIFN_D_CMD_RSIZE-1 +#define HIFN_QUEUE_LENGTH (HIFN_D_CMD_RSIZE - 1) #define AES_MIN_KEY_SIZE 16 #define AES_MAX_KEY_SIZE 32 @@ -406,8 +403,6 @@ struct hifn_dma { u8 command_bufs[HIFN_D_CMD_RSIZE][HIFN_MAX_COMMAND]; u8 result_bufs[HIFN_D_CMD_RSIZE][HIFN_MAX_RESULT]; - u64 test_src, test_dst; - /* * Our current positions for insertion and removal from the descriptor * rings. @@ -434,9 +429,6 @@ struct hifn_device struct pci_dev *pdev; void __iomem *bar[3]; - unsigned long result_mem; - dma_addr_t dst; - void *desc_virt; dma_addr_t desc_dma; @@ -446,8 +438,6 @@ struct hifn_device spinlock_t lock; - void *priv; - u32 flags; int active, started; struct delayed_work work; @@ -657,12 +647,17 @@ struct ablkcipher_walk struct hifn_context { - u8 key[HIFN_MAX_CRYPT_KEY_LENGTH], *iv; + u8 key[HIFN_MAX_CRYPT_KEY_LENGTH]; struct hifn_device *dev; - unsigned int keysize, ivsize; + unsigned int keysize; +}; + +struct hifn_request_context +{ + u8 *iv; + unsigned int ivsize; u8 op, type, mode, unused; struct ablkcipher_walk walk; - atomic_t sg_num; }; #define crypto_alg_to_hifn(a) container_of(a, struct hifn_crypto_alg, alg) @@ -1168,7 +1163,8 @@ static int hifn_setup_crypto_command(struct hifn_device *dev, } static int hifn_setup_cmd_desc(struct hifn_device *dev, - struct hifn_context *ctx, void *priv, unsigned int nbytes) + struct hifn_context *ctx, struct hifn_request_context *rctx, + void *priv, unsigned int nbytes) { struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; int cmd_len, sa_idx; @@ -1179,7 +1175,7 @@ static int hifn_setup_cmd_desc(struct hifn_device *dev, buf_pos = buf = dma->command_bufs[dma->cmdi]; mask = 0; - switch (ctx->op) { + switch (rctx->op) { case ACRYPTO_OP_DECRYPT: mask = HIFN_BASE_CMD_CRYPT | HIFN_BASE_CMD_DECODE; break; @@ -1196,15 +1192,15 @@ static int hifn_setup_cmd_desc(struct hifn_device *dev, buf_pos += hifn_setup_base_command(dev, buf_pos, nbytes, nbytes, mask, dev->snum); - if (ctx->op == ACRYPTO_OP_ENCRYPT || ctx->op == ACRYPTO_OP_DECRYPT) { + if (rctx->op == ACRYPTO_OP_ENCRYPT || rctx->op == ACRYPTO_OP_DECRYPT) { u16 md = 0; if (ctx->keysize) md |= HIFN_CRYPT_CMD_NEW_KEY; - if (ctx->iv && ctx->mode != ACRYPTO_MODE_ECB) + if (rctx->iv && rctx->mode != ACRYPTO_MODE_ECB) md |= HIFN_CRYPT_CMD_NEW_IV; - switch (ctx->mode) { + switch (rctx->mode) { case ACRYPTO_MODE_ECB: md |= HIFN_CRYPT_CMD_MODE_ECB; break; @@ -1221,7 +1217,7 @@ static int hifn_setup_cmd_desc(struct hifn_device *dev, goto err_out; } - switch (ctx->type) { + switch (rctx->type) { case ACRYPTO_TYPE_AES_128: if (ctx->keysize != 16) goto err_out; @@ -1256,17 +1252,18 @@ static int hifn_setup_cmd_desc(struct hifn_device *dev, buf_pos += hifn_setup_crypto_command(dev, buf_pos, nbytes, nbytes, ctx->key, ctx->keysize, - ctx->iv, ctx->ivsize, md); + rctx->iv, rctx->ivsize, md); } dev->sa[sa_idx] = priv; + dev->started++; cmd_len = buf_pos - buf; dma->cmdr[dma->cmdi].l = __cpu_to_le32(cmd_len | HIFN_D_VALID | HIFN_D_LAST | HIFN_D_MASKDONEIRQ); if (++dma->cmdi == HIFN_D_CMD_RSIZE) { - dma->cmdr[dma->cmdi].l = __cpu_to_le32(HIFN_MAX_COMMAND | + dma->cmdr[dma->cmdi].l = __cpu_to_le32( HIFN_D_VALID | HIFN_D_LAST | HIFN_D_MASKDONEIRQ | HIFN_D_JUMP); dma->cmdi = 0; @@ -1284,7 +1281,7 @@ static int hifn_setup_cmd_desc(struct hifn_device *dev, } static int hifn_setup_src_desc(struct hifn_device *dev, struct page *page, - unsigned int offset, unsigned int size) + unsigned int offset, unsigned int size, int last) { struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; int idx; @@ -1296,12 +1293,12 @@ static int hifn_setup_src_desc(struct hifn_device *dev, struct page *page, dma->srcr[idx].p = __cpu_to_le32(addr); dma->srcr[idx].l = __cpu_to_le32(size | HIFN_D_VALID | - HIFN_D_MASKDONEIRQ | HIFN_D_LAST); + HIFN_D_MASKDONEIRQ | (last ? HIFN_D_LAST : 0)); if (++idx == HIFN_D_SRC_RSIZE) { dma->srcr[idx].l = __cpu_to_le32(HIFN_D_VALID | - HIFN_D_JUMP | - HIFN_D_MASKDONEIRQ | HIFN_D_LAST); + HIFN_D_JUMP | HIFN_D_MASKDONEIRQ | + (last ? HIFN_D_LAST : 0)); idx = 0; } @@ -1342,7 +1339,7 @@ static void hifn_setup_res_desc(struct hifn_device *dev) } static void hifn_setup_dst_desc(struct hifn_device *dev, struct page *page, - unsigned offset, unsigned size) + unsigned offset, unsigned size, int last) { struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; int idx; @@ -1353,12 +1350,12 @@ static void hifn_setup_dst_desc(struct hifn_device *dev, struct page *page, idx = dma->dsti; dma->dstr[idx].p = __cpu_to_le32(addr); dma->dstr[idx].l = __cpu_to_le32(size | HIFN_D_VALID | - HIFN_D_MASKDONEIRQ | HIFN_D_LAST); + HIFN_D_MASKDONEIRQ | (last ? HIFN_D_LAST : 0)); if (++idx == HIFN_D_DST_RSIZE) { dma->dstr[idx].l = __cpu_to_le32(HIFN_D_VALID | HIFN_D_JUMP | HIFN_D_MASKDONEIRQ | - HIFN_D_LAST); + (last ? HIFN_D_LAST : 0)); idx = 0; } dma->dsti = idx; @@ -1370,16 +1367,52 @@ static void hifn_setup_dst_desc(struct hifn_device *dev, struct page *page, } } -static int hifn_setup_dma(struct hifn_device *dev, struct page *spage, unsigned int soff, - struct page *dpage, unsigned int doff, unsigned int nbytes, void *priv, - struct hifn_context *ctx) +static int hifn_setup_dma(struct hifn_device *dev, + struct hifn_context *ctx, struct hifn_request_context *rctx, + struct scatterlist *src, struct scatterlist *dst, + unsigned int nbytes, void *priv) { - dprintk("%s: spage: %p, soffset: %u, dpage: %p, doffset: %u, nbytes: %u, priv: %p, ctx: %p.\n", - dev->name, spage, soff, dpage, doff, nbytes, priv, ctx); + struct scatterlist *t; + struct page *spage, *dpage; + unsigned int soff, doff; + unsigned int n, len; - hifn_setup_src_desc(dev, spage, soff, nbytes); - hifn_setup_cmd_desc(dev, ctx, priv, nbytes); - hifn_setup_dst_desc(dev, dpage, doff, nbytes); + n = nbytes; + while (n) { + spage = sg_page(src); + soff = src->offset; + len = min(src->length, n); + + hifn_setup_src_desc(dev, spage, soff, len, n - len == 0); + + src++; + n -= len; + } + + t = &rctx->walk.cache[0]; + n = nbytes; + while (n) { + if (t->length && rctx->walk.flags & ASYNC_FLAGS_MISALIGNED) { + BUG_ON(!sg_page(t)); + dpage = sg_page(t); + doff = 0; + len = t->length; + } else { + BUG_ON(!sg_page(dst)); + dpage = sg_page(dst); + doff = dst->offset; + len = dst->length; + } + len = min(len, n); + + hifn_setup_dst_desc(dev, dpage, doff, len, n - len == 0); + + dst++; + t++; + n -= len; + } + + hifn_setup_cmd_desc(dev, ctx, rctx, priv, nbytes); hifn_setup_res_desc(dev); return 0; } @@ -1424,32 +1457,26 @@ static void ablkcipher_walk_exit(struct ablkcipher_walk *w) w->num = 0; } -static int ablkcipher_add(void *daddr, unsigned int *drestp, struct scatterlist *src, +static int ablkcipher_add(unsigned int *drestp, struct scatterlist *dst, unsigned int size, unsigned int *nbytesp) { unsigned int copy, drest = *drestp, nbytes = *nbytesp; int idx = 0; - void *saddr; if (drest < size || size > nbytes) return -EINVAL; while (size) { - copy = min(drest, min(size, src->length)); - - saddr = kmap_atomic(sg_page(src), KM_SOFTIRQ1); - memcpy(daddr, saddr + src->offset, copy); - kunmap_atomic(saddr, KM_SOFTIRQ1); + copy = min(drest, min(size, dst->length)); size -= copy; drest -= copy; nbytes -= copy; - daddr += copy; dprintk("%s: copy: %u, size: %u, drest: %u, nbytes: %u.\n", __func__, copy, size, drest, nbytes); - src++; + dst++; idx++; } @@ -1462,8 +1489,7 @@ static int ablkcipher_add(void *daddr, unsigned int *drestp, struct scatterlist static int ablkcipher_walk(struct ablkcipher_request *req, struct ablkcipher_walk *w) { - struct scatterlist *src, *dst, *t; - void *daddr; + struct scatterlist *dst, *t; unsigned int nbytes = req->nbytes, offset, copy, diff; int idx, tidx, err; @@ -1473,26 +1499,22 @@ static int ablkcipher_walk(struct ablkcipher_request *req, if (idx >= w->num && (w->flags & ASYNC_FLAGS_MISALIGNED)) return -EINVAL; - src = &req->src[idx]; dst = &req->dst[idx]; - dprintk("\n%s: slen: %u, dlen: %u, soff: %u, doff: %u, offset: %u, " - "nbytes: %u.\n", - __func__, src->length, dst->length, src->offset, - dst->offset, offset, nbytes); + dprintk("\n%s: dlen: %u, doff: %u, offset: %u, nbytes: %u.\n", + __func__, dst->length, dst->offset, offset, nbytes); if (!IS_ALIGNED(dst->offset, HIFN_D_DST_DALIGN) || !IS_ALIGNED(dst->length, HIFN_D_DST_DALIGN) || offset) { - unsigned slen = min(src->length - offset, nbytes); + unsigned slen = min(dst->length - offset, nbytes); unsigned dlen = PAGE_SIZE; t = &w->cache[idx]; - daddr = kmap_atomic(sg_page(t), KM_SOFTIRQ0); - err = ablkcipher_add(daddr, &dlen, src, slen, &nbytes); + err = ablkcipher_add(&dlen, dst, slen, &nbytes); if (err < 0) - goto err_out_unmap; + return err; idx += err; @@ -1528,21 +1550,19 @@ static int ablkcipher_walk(struct ablkcipher_request *req, } else { copy += diff + nbytes; - src = &req->src[idx]; + dst = &req->dst[idx]; - err = ablkcipher_add(daddr + slen, &dlen, src, nbytes, &nbytes); + err = ablkcipher_add(&dlen, dst, nbytes, &nbytes); if (err < 0) - goto err_out_unmap; + return err; idx += err; } t->length = copy; t->offset = offset; - - kunmap_atomic(daddr, KM_SOFTIRQ0); } else { - nbytes -= min(src->length, nbytes); + nbytes -= min(dst->length, nbytes); idx++; } @@ -1550,26 +1570,22 @@ static int ablkcipher_walk(struct ablkcipher_request *req, } return tidx; - -err_out_unmap: - kunmap_atomic(daddr, KM_SOFTIRQ0); - return err; } static int hifn_setup_session(struct ablkcipher_request *req) { struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm); + struct hifn_request_context *rctx = ablkcipher_request_ctx(req); struct hifn_device *dev = ctx->dev; - struct page *spage, *dpage; - unsigned long soff, doff, dlen, flags; - unsigned int nbytes = req->nbytes, idx = 0, len; + unsigned long dlen, flags; + unsigned int nbytes = req->nbytes, idx = 0; int err = -EINVAL, sg_num; - struct scatterlist *src, *dst, *t; + struct scatterlist *dst; - if (ctx->iv && !ctx->ivsize && ctx->mode != ACRYPTO_MODE_ECB) + if (rctx->iv && !rctx->ivsize && rctx->mode != ACRYPTO_MODE_ECB) goto err_out_exit; - ctx->walk.flags = 0; + rctx->walk.flags = 0; while (nbytes) { dst = &req->dst[idx]; @@ -1577,27 +1593,23 @@ static int hifn_setup_session(struct ablkcipher_request *req) if (!IS_ALIGNED(dst->offset, HIFN_D_DST_DALIGN) || !IS_ALIGNED(dlen, HIFN_D_DST_DALIGN)) - ctx->walk.flags |= ASYNC_FLAGS_MISALIGNED; + rctx->walk.flags |= ASYNC_FLAGS_MISALIGNED; nbytes -= dlen; idx++; } - if (ctx->walk.flags & ASYNC_FLAGS_MISALIGNED) { - err = ablkcipher_walk_init(&ctx->walk, idx, GFP_ATOMIC); + if (rctx->walk.flags & ASYNC_FLAGS_MISALIGNED) { + err = ablkcipher_walk_init(&rctx->walk, idx, GFP_ATOMIC); if (err < 0) return err; } - nbytes = req->nbytes; - idx = 0; - - sg_num = ablkcipher_walk(req, &ctx->walk); + sg_num = ablkcipher_walk(req, &rctx->walk); if (sg_num < 0) { err = sg_num; goto err_out_exit; } - atomic_set(&ctx->sg_num, sg_num); spin_lock_irqsave(&dev->lock, flags); if (dev->started + sg_num > HIFN_QUEUE_LENGTH) { @@ -1605,37 +1617,11 @@ static int hifn_setup_session(struct ablkcipher_request *req) goto err_out; } - dev->snum++; - dev->started += sg_num; - - while (nbytes) { - src = &req->src[idx]; - dst = &req->dst[idx]; - t = &ctx->walk.cache[idx]; - - if (t->length) { - spage = dpage = sg_page(t); - soff = doff = 0; - len = t->length; - } else { - spage = sg_page(src); - soff = src->offset; - - dpage = sg_page(dst); - doff = dst->offset; - - len = dst->length; - } - - idx++; - - err = hifn_setup_dma(dev, spage, soff, dpage, doff, nbytes, - req, ctx); - if (err) - goto err_out; + err = hifn_setup_dma(dev, ctx, rctx, req->src, req->dst, req->nbytes, req); + if (err) + goto err_out; - nbytes -= min(len, nbytes); - } + dev->snum++; dev->active = HIFN_DEFAULT_ACTIVE_NUM; spin_unlock_irqrestore(&dev->lock, flags); @@ -1645,12 +1631,13 @@ static int hifn_setup_session(struct ablkcipher_request *req) err_out: spin_unlock_irqrestore(&dev->lock, flags); err_out_exit: - if (err) - dprintk("%s: iv: %p [%d], key: %p [%d], mode: %u, op: %u, " + if (err) { + printk("%s: iv: %p [%d], key: %p [%d], mode: %u, op: %u, " "type: %u, err: %d.\n", - dev->name, ctx->iv, ctx->ivsize, + dev->name, rctx->iv, rctx->ivsize, ctx->key, ctx->keysize, - ctx->mode, ctx->op, ctx->type, err); + rctx->mode, rctx->op, rctx->type, err); + } return err; } @@ -1660,31 +1647,33 @@ static int hifn_test(struct hifn_device *dev, int encdec, u8 snum) int n, err; u8 src[16]; struct hifn_context ctx; + struct hifn_request_context rctx; u8 fips_aes_ecb_from_zero[16] = { 0x66, 0xE9, 0x4B, 0xD4, 0xEF, 0x8A, 0x2C, 0x3B, 0x88, 0x4C, 0xFA, 0x59, 0xCA, 0x34, 0x2B, 0x2E}; + struct scatterlist sg; memset(src, 0, sizeof(src)); memset(ctx.key, 0, sizeof(ctx.key)); ctx.dev = dev; ctx.keysize = 16; - ctx.ivsize = 0; - ctx.iv = NULL; - ctx.op = (encdec)?ACRYPTO_OP_ENCRYPT:ACRYPTO_OP_DECRYPT; - ctx.mode = ACRYPTO_MODE_ECB; - ctx.type = ACRYPTO_TYPE_AES_128; - atomic_set(&ctx.sg_num, 1); - - err = hifn_setup_dma(dev, - virt_to_page(src), offset_in_page(src), - virt_to_page(src), offset_in_page(src), - sizeof(src), NULL, &ctx); + rctx.ivsize = 0; + rctx.iv = NULL; + rctx.op = (encdec)?ACRYPTO_OP_ENCRYPT:ACRYPTO_OP_DECRYPT; + rctx.mode = ACRYPTO_MODE_ECB; + rctx.type = ACRYPTO_TYPE_AES_128; + rctx.walk.cache[0].length = 0; + + sg_init_one(&sg, &src, sizeof(src)); + + err = hifn_setup_dma(dev, &ctx, &rctx, &sg, &sg, sizeof(src), NULL); if (err) goto err_out; + dev->started = 0; msleep(200); dprintk("%s: decoded: ", dev->name); @@ -1711,6 +1700,7 @@ static int hifn_start_device(struct hifn_device *dev) { int err; + dev->started = dev->active = 0; hifn_reset_dma(dev, 1); err = hifn_enable_crypto(dev); @@ -1764,90 +1754,65 @@ static int ablkcipher_get(void *saddr, unsigned int *srestp, unsigned int offset return idx; } -static void hifn_process_ready(struct ablkcipher_request *req, int error) +static inline void hifn_complete_sa(struct hifn_device *dev, int i) { - struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm); - struct hifn_device *dev; - - dprintk("%s: req: %p, ctx: %p.\n", __func__, req, ctx); + unsigned long flags; - dev = ctx->dev; - dprintk("%s: req: %p, started: %d, sg_num: %d.\n", - __func__, req, dev->started, atomic_read(&ctx->sg_num)); + spin_lock_irqsave(&dev->lock, flags); + dev->sa[i] = NULL; + dev->started--; + if (dev->started < 0) + printk("%s: started: %d.\n", __func__, dev->started); + spin_unlock_irqrestore(&dev->lock, flags); + BUG_ON(dev->started < 0); +} - if (--dev->started < 0) - BUG(); +static void hifn_process_ready(struct ablkcipher_request *req, int error) +{ + struct hifn_request_context *rctx = ablkcipher_request_ctx(req); - if (atomic_dec_and_test(&ctx->sg_num)) { + if (rctx->walk.flags & ASYNC_FLAGS_MISALIGNED) { unsigned int nbytes = req->nbytes; int idx = 0, err; struct scatterlist *dst, *t; void *saddr; - if (ctx->walk.flags & ASYNC_FLAGS_MISALIGNED) { - while (nbytes) { - t = &ctx->walk.cache[idx]; - dst = &req->dst[idx]; - - dprintk("\n%s: sg_page(t): %p, t->length: %u, " - "sg_page(dst): %p, dst->length: %u, " - "nbytes: %u.\n", - __func__, sg_page(t), t->length, - sg_page(dst), dst->length, nbytes); + while (nbytes) { + t = &rctx->walk.cache[idx]; + dst = &req->dst[idx]; - if (!t->length) { - nbytes -= min(dst->length, nbytes); - idx++; - continue; - } + dprintk("\n%s: sg_page(t): %p, t->length: %u, " + "sg_page(dst): %p, dst->length: %u, " + "nbytes: %u.\n", + __func__, sg_page(t), t->length, + sg_page(dst), dst->length, nbytes); - saddr = kmap_atomic(sg_page(t), KM_IRQ1); + if (!t->length) { + nbytes -= min(dst->length, nbytes); + idx++; + continue; + } - err = ablkcipher_get(saddr, &t->length, t->offset, - dst, nbytes, &nbytes); - if (err < 0) { - kunmap_atomic(saddr, KM_IRQ1); - break; - } + saddr = kmap_atomic(sg_page(t), KM_SOFTIRQ0); - idx += err; - kunmap_atomic(saddr, KM_IRQ1); + err = ablkcipher_get(saddr, &t->length, t->offset, + dst, nbytes, &nbytes); + if (err < 0) { + kunmap_atomic(saddr, KM_SOFTIRQ0); + break; } - ablkcipher_walk_exit(&ctx->walk); + idx += err; + kunmap_atomic(saddr, KM_SOFTIRQ0); } - req->base.complete(&req->base, error); + ablkcipher_walk_exit(&rctx->walk); } -} -static void hifn_check_for_completion(struct hifn_device *dev, int error) -{ - int i; - struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; - - for (i=0; iresr[i]; - - if (!(d->l & __cpu_to_le32(HIFN_D_VALID)) && dev->sa[i]) { - dev->success++; - dev->reset = 0; - hifn_process_ready(dev->sa[i], error); - dev->sa[i] = NULL; - } - - if (d->l & __cpu_to_le32(HIFN_D_DESTOVER | HIFN_D_OVER)) - if (printk_ratelimit()) - printk("%s: overflow detected [d: %u, o: %u] " - "at %d resr: l: %08x, p: %08x.\n", - dev->name, - !!(d->l & __cpu_to_le32(HIFN_D_DESTOVER)), - !!(d->l & __cpu_to_le32(HIFN_D_OVER)), - i, d->l, d->p); - } + req->base.complete(&req->base, error); } -static void hifn_clear_rings(struct hifn_device *dev) +static void hifn_clear_rings(struct hifn_device *dev, int error) { struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; int i, u; @@ -1864,21 +1829,26 @@ static void hifn_clear_rings(struct hifn_device *dev) if (dma->resr[i].l & __cpu_to_le32(HIFN_D_VALID)) break; - if (i != HIFN_D_RES_RSIZE) - u--; + if (dev->sa[i]) { + dev->success++; + dev->reset = 0; + hifn_process_ready(dev->sa[i], error); + hifn_complete_sa(dev, i); + } - if (++i == (HIFN_D_RES_RSIZE + 1)) + if (++i == HIFN_D_RES_RSIZE) i = 0; + u--; } dma->resk = i; dma->resu = u; i = dma->srck; u = dma->srcu; while (u != 0) { - if (i == HIFN_D_SRC_RSIZE) - i = 0; if (dma->srcr[i].l & __cpu_to_le32(HIFN_D_VALID)) break; - i++, u--; + if (++i == HIFN_D_SRC_RSIZE) + i = 0; + u--; } dma->srck = i; dma->srcu = u; @@ -1886,20 +1856,19 @@ static void hifn_clear_rings(struct hifn_device *dev) while (u != 0) { if (dma->cmdr[i].l & __cpu_to_le32(HIFN_D_VALID)) break; - if (i != HIFN_D_CMD_RSIZE) - u--; - if (++i == (HIFN_D_CMD_RSIZE + 1)) + if (++i == HIFN_D_CMD_RSIZE) i = 0; + u--; } dma->cmdk = i; dma->cmdu = u; i = dma->dstk; u = dma->dstu; while (u != 0) { - if (i == HIFN_D_DST_RSIZE) - i = 0; if (dma->dstr[i].l & __cpu_to_le32(HIFN_D_VALID)) break; - i++, u--; + if (++i == HIFN_D_DST_RSIZE) + i = 0; + u--; } dma->dstk = i; dma->dstu = u; @@ -1944,30 +1913,39 @@ static void hifn_work(struct work_struct *work) } else dev->active--; - if (dev->prev_success == dev->success && dev->started) + if ((dev->prev_success == dev->success) && dev->started) reset = 1; dev->prev_success = dev->success; spin_unlock_irqrestore(&dev->lock, flags); if (reset) { - dprintk("%s: r: %08x, active: %d, started: %d, " - "success: %lu: reset: %d.\n", - dev->name, r, dev->active, dev->started, - dev->success, reset); - if (++dev->reset >= 5) { - dprintk("%s: really hard reset.\n", dev->name); + int i; + struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; + + printk("%s: r: %08x, active: %d, started: %d, " + "success: %lu: qlen: %u/%u, reset: %d.\n", + dev->name, r, dev->active, dev->started, + dev->success, dev->queue.qlen, dev->queue.max_qlen, + reset); + + printk("%s: res: ", __func__); + for (i=0; iresr[i].l, dev->sa[i]); + if (dev->sa[i]) { + hifn_process_ready(dev->sa[i], -ENODEV); + hifn_complete_sa(dev, i); + } + } + printk("\n"); + hifn_reset_dma(dev, 1); hifn_stop_device(dev); hifn_start_device(dev); dev->reset = 0; } - spin_lock_irqsave(&dev->lock, flags); - hifn_check_for_completion(dev, -EBUSY); - hifn_clear_rings(dev); - dev->started = 0; - spin_unlock_irqrestore(&dev->lock, flags); + tasklet_schedule(&dev->tasklet); } schedule_delayed_work(&dev->work, HZ); @@ -1984,8 +1962,8 @@ static irqreturn_t hifn_interrupt(int irq, void *data) dprintk("%s: 1 dmacsr: %08x, dmareg: %08x, res: %08x [%d], " "i: %d.%d.%d.%d, u: %d.%d.%d.%d.\n", dev->name, dmacsr, dev->dmareg, dmacsr & dev->dmareg, dma->cmdi, - dma->cmdu, dma->srcu, dma->dstu, dma->resu, - dma->cmdi, dma->srci, dma->dsti, dma->resi); + dma->cmdi, dma->srci, dma->dsti, dma->resi, + dma->cmdu, dma->srcu, dma->dstu, dma->resu); if ((dmacsr & dev->dmareg) == 0) return IRQ_NONE; @@ -2002,11 +1980,10 @@ static irqreturn_t hifn_interrupt(int irq, void *data) if (restart) { u32 puisr = hifn_read_0(dev, HIFN_0_PUISR); - if (printk_ratelimit()) - printk("%s: overflow: r: %d, d: %d, puisr: %08x, d: %u.\n", - dev->name, !!(dmacsr & HIFN_DMACSR_R_OVER), - !!(dmacsr & HIFN_DMACSR_D_OVER), - puisr, !!(puisr & HIFN_PUISR_DSTOVER)); + printk(KERN_WARNING "%s: overflow: r: %d, d: %d, puisr: %08x, d: %u.\n", + dev->name, !!(dmacsr & HIFN_DMACSR_R_OVER), + !!(dmacsr & HIFN_DMACSR_D_OVER), + puisr, !!(puisr & HIFN_PUISR_DSTOVER)); if (!!(puisr & HIFN_PUISR_DSTOVER)) hifn_write_0(dev, HIFN_0_PUISR, HIFN_PUISR_DSTOVER); hifn_write_1(dev, HIFN_1_DMA_CSR, dmacsr & (HIFN_DMACSR_R_OVER | @@ -2016,12 +1993,11 @@ static irqreturn_t hifn_interrupt(int irq, void *data) restart = dmacsr & (HIFN_DMACSR_C_ABORT | HIFN_DMACSR_S_ABORT | HIFN_DMACSR_D_ABORT | HIFN_DMACSR_R_ABORT); if (restart) { - if (printk_ratelimit()) - printk("%s: abort: c: %d, s: %d, d: %d, r: %d.\n", - dev->name, !!(dmacsr & HIFN_DMACSR_C_ABORT), - !!(dmacsr & HIFN_DMACSR_S_ABORT), - !!(dmacsr & HIFN_DMACSR_D_ABORT), - !!(dmacsr & HIFN_DMACSR_R_ABORT)); + printk(KERN_WARNING "%s: abort: c: %d, s: %d, d: %d, r: %d.\n", + dev->name, !!(dmacsr & HIFN_DMACSR_C_ABORT), + !!(dmacsr & HIFN_DMACSR_S_ABORT), + !!(dmacsr & HIFN_DMACSR_D_ABORT), + !!(dmacsr & HIFN_DMACSR_R_ABORT)); hifn_reset_dma(dev, 1); hifn_init_dma(dev); hifn_init_registers(dev); @@ -2034,7 +2010,6 @@ static irqreturn_t hifn_interrupt(int irq, void *data) } tasklet_schedule(&dev->tasklet); - hifn_clear_rings(dev); return IRQ_HANDLED; } @@ -2048,21 +2023,25 @@ static void hifn_flush(struct hifn_device *dev) struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; int i; - spin_lock_irqsave(&dev->lock, flags); for (i=0; iresr[i]; if (dev->sa[i]) { hifn_process_ready(dev->sa[i], (d->l & __cpu_to_le32(HIFN_D_VALID))?-ENODEV:0); + hifn_complete_sa(dev, i); } } + spin_lock_irqsave(&dev->lock, flags); while ((async_req = crypto_dequeue_request(&dev->queue))) { ctx = crypto_tfm_ctx(async_req->tfm); req = container_of(async_req, struct ablkcipher_request, base); + spin_unlock_irqrestore(&dev->lock, flags); hifn_process_ready(req, -ENODEV); + + spin_lock_irqsave(&dev->lock, flags); } spin_unlock_irqrestore(&dev->lock, flags); } @@ -2121,6 +2100,7 @@ static int hifn_setup_crypto_req(struct ablkcipher_request *req, u8 op, u8 type, u8 mode) { struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm); + struct hifn_request_context *rctx = ablkcipher_request_ctx(req); unsigned ivsize; ivsize = crypto_ablkcipher_ivsize(crypto_ablkcipher_reqtfm(req)); @@ -2141,11 +2121,11 @@ static int hifn_setup_crypto_req(struct ablkcipher_request *req, u8 op, type = ACRYPTO_TYPE_AES_256; } - ctx->op = op; - ctx->mode = mode; - ctx->type = type; - ctx->iv = req->info; - ctx->ivsize = ivsize; + rctx->op = op; + rctx->mode = mode; + rctx->type = type; + rctx->iv = req->info; + rctx->ivsize = ivsize; /* * HEAVY TODO: needs to kick Herbert XU to write documentation. @@ -2158,7 +2138,7 @@ static int hifn_setup_crypto_req(struct ablkcipher_request *req, u8 op, static int hifn_process_queue(struct hifn_device *dev) { - struct crypto_async_request *async_req; + struct crypto_async_request *async_req, *backlog; struct hifn_context *ctx; struct ablkcipher_request *req; unsigned long flags; @@ -2166,12 +2146,16 @@ static int hifn_process_queue(struct hifn_device *dev) while (dev->started < HIFN_QUEUE_LENGTH) { spin_lock_irqsave(&dev->lock, flags); + backlog = crypto_get_backlog(&dev->queue); async_req = crypto_dequeue_request(&dev->queue); spin_unlock_irqrestore(&dev->lock, flags); if (!async_req) break; + if (backlog) + backlog->complete(backlog, -EINPROGRESS); + ctx = crypto_tfm_ctx(async_req->tfm); req = container_of(async_req, struct ablkcipher_request, base); @@ -2496,7 +2480,7 @@ static int hifn_cra_init(struct crypto_tfm *tfm) struct hifn_context *ctx = crypto_tfm_ctx(tfm); ctx->dev = ha->dev; - + tfm->crt_ablkcipher.reqsize = sizeof(struct hifn_request_context); return 0; } @@ -2574,7 +2558,10 @@ static void hifn_tasklet_callback(unsigned long data) * (like dev->success), but they are used in process * context or update is atomic (like setting dev->sa[i] to NULL). */ - hifn_check_for_completion(dev, 0); + hifn_clear_rings(dev, 0); + + if (dev->started < HIFN_QUEUE_LENGTH && dev->queue.qlen) + hifn_process_queue(dev); } static int hifn_probe(struct pci_dev *pdev, const struct pci_device_id *id) @@ -2631,22 +2618,11 @@ static int hifn_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_out_unmap_bars; } - dev->result_mem = __get_free_pages(GFP_KERNEL, HIFN_MAX_RESULT_ORDER); - if (!dev->result_mem) { - dprintk("Failed to allocate %d pages for result_mem.\n", - HIFN_MAX_RESULT_ORDER); - goto err_out_unmap_bars; - } - memset((void *)dev->result_mem, 0, PAGE_SIZE*(1<dst = pci_map_single(pdev, (void *)dev->result_mem, - PAGE_SIZE << HIFN_MAX_RESULT_ORDER, PCI_DMA_FROMDEVICE); - dev->desc_virt = pci_alloc_consistent(pdev, sizeof(struct hifn_dma), &dev->desc_dma); if (!dev->desc_virt) { dprintk("Failed to allocate descriptor rings.\n"); - goto err_out_free_result_pages; + goto err_out_unmap_bars; } memset(dev->desc_virt, 0, sizeof(struct hifn_dma)); @@ -2706,11 +2682,6 @@ static int hifn_probe(struct pci_dev *pdev, const struct pci_device_id *id) pci_free_consistent(pdev, sizeof(struct hifn_dma), dev->desc_virt, dev->desc_dma); -err_out_free_result_pages: - pci_unmap_single(pdev, dev->dst, PAGE_SIZE << HIFN_MAX_RESULT_ORDER, - PCI_DMA_FROMDEVICE); - free_pages(dev->result_mem, HIFN_MAX_RESULT_ORDER); - err_out_unmap_bars: for (i=0; i<3; ++i) if (dev->bar[i]) @@ -2748,10 +2719,6 @@ static void hifn_remove(struct pci_dev *pdev) pci_free_consistent(pdev, sizeof(struct hifn_dma), dev->desc_virt, dev->desc_dma); - pci_unmap_single(pdev, dev->dst, - PAGE_SIZE << HIFN_MAX_RESULT_ORDER, - PCI_DMA_FROMDEVICE); - free_pages(dev->result_mem, HIFN_MAX_RESULT_ORDER); for (i=0; i<3; ++i) if (dev->bar[i]) iounmap(dev->bar[i]); @@ -2782,6 +2749,11 @@ static int __devinit hifn_init(void) unsigned int freq; int err; + if (sizeof(dma_addr_t) > 4) { + printk(KERN_INFO "HIFN supports only 32-bit addresses.\n"); + return -EINVAL; + } + if (strncmp(hifn_pll_ref, "ext", 3) && strncmp(hifn_pll_ref, "pci", 3)) { printk(KERN_ERR "hifn795x: invalid hifn_pll_ref clock, " diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c index bf2917d197a018d13f1bc48ad4c93c0b0a93ccde..856b3cc2558387b7b239923c37c54f9d47b250ff 100644 --- a/drivers/crypto/padlock-aes.c +++ b/drivers/crypto/padlock-aes.c @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include #include #include "padlock.h" @@ -49,6 +51,8 @@ struct aes_ctx { u32 *D; }; +static DEFINE_PER_CPU(struct cword *, last_cword); + /* Tells whether the ACE is capable to generate the extended key for a given key_len. */ static inline int @@ -89,6 +93,7 @@ static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, const __le32 *key = (const __le32 *)in_key; u32 *flags = &tfm->crt_flags; struct crypto_aes_ctx gen_aes; + int cpu; if (key_len % 8) { *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; @@ -118,7 +123,7 @@ static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, /* Don't generate extended keys if the hardware can do it. */ if (aes_hw_extkey_available(key_len)) - return 0; + goto ok; ctx->D = ctx->d_data; ctx->cword.encrypt.keygen = 1; @@ -131,15 +136,30 @@ static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, memcpy(ctx->E, gen_aes.key_enc, AES_MAX_KEYLENGTH); memcpy(ctx->D, gen_aes.key_dec, AES_MAX_KEYLENGTH); + +ok: + for_each_online_cpu(cpu) + if (&ctx->cword.encrypt == per_cpu(last_cword, cpu) || + &ctx->cword.decrypt == per_cpu(last_cword, cpu)) + per_cpu(last_cword, cpu) = NULL; + return 0; } /* ====== Encryption/decryption routines ====== */ /* These are the real call to PadLock. */ -static inline void padlock_reset_key(void) +static inline void padlock_reset_key(struct cword *cword) +{ + int cpu = raw_smp_processor_id(); + + if (cword != per_cpu(last_cword, cpu)) + asm volatile ("pushfl; popfl"); +} + +static inline void padlock_store_cword(struct cword *cword) { - asm volatile ("pushfl; popfl"); + per_cpu(last_cword, raw_smp_processor_id()) = cword; } /* @@ -149,7 +169,7 @@ static inline void padlock_reset_key(void) */ static inline void padlock_xcrypt(const u8 *input, u8 *output, void *key, - void *control_word) + struct cword *control_word) { asm volatile (".byte 0xf3,0x0f,0xa7,0xc8" /* rep xcryptecb */ : "+S"(input), "+D"(output) @@ -213,22 +233,24 @@ static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { struct aes_ctx *ctx = aes_ctx(tfm); int ts_state; - padlock_reset_key(); + padlock_reset_key(&ctx->cword.encrypt); ts_state = irq_ts_save(); aes_crypt(in, out, ctx->E, &ctx->cword.encrypt); irq_ts_restore(ts_state); + padlock_store_cword(&ctx->cword.encrypt); } static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { struct aes_ctx *ctx = aes_ctx(tfm); int ts_state; - padlock_reset_key(); + padlock_reset_key(&ctx->cword.encrypt); ts_state = irq_ts_save(); aes_crypt(in, out, ctx->D, &ctx->cword.decrypt); irq_ts_restore(ts_state); + padlock_store_cword(&ctx->cword.encrypt); } static struct crypto_alg aes_alg = { @@ -261,7 +283,7 @@ static int ecb_aes_encrypt(struct blkcipher_desc *desc, int err; int ts_state; - padlock_reset_key(); + padlock_reset_key(&ctx->cword.encrypt); blkcipher_walk_init(&walk, dst, src, nbytes); err = blkcipher_walk_virt(desc, &walk); @@ -276,6 +298,8 @@ static int ecb_aes_encrypt(struct blkcipher_desc *desc, } irq_ts_restore(ts_state); + padlock_store_cword(&ctx->cword.encrypt); + return err; } @@ -288,7 +312,7 @@ static int ecb_aes_decrypt(struct blkcipher_desc *desc, int err; int ts_state; - padlock_reset_key(); + padlock_reset_key(&ctx->cword.decrypt); blkcipher_walk_init(&walk, dst, src, nbytes); err = blkcipher_walk_virt(desc, &walk); @@ -302,6 +326,9 @@ static int ecb_aes_decrypt(struct blkcipher_desc *desc, err = blkcipher_walk_done(desc, &walk, nbytes); } irq_ts_restore(ts_state); + + padlock_store_cword(&ctx->cword.encrypt); + return err; } @@ -336,7 +363,7 @@ static int cbc_aes_encrypt(struct blkcipher_desc *desc, int err; int ts_state; - padlock_reset_key(); + padlock_reset_key(&ctx->cword.encrypt); blkcipher_walk_init(&walk, dst, src, nbytes); err = blkcipher_walk_virt(desc, &walk); @@ -353,6 +380,8 @@ static int cbc_aes_encrypt(struct blkcipher_desc *desc, } irq_ts_restore(ts_state); + padlock_store_cword(&ctx->cword.decrypt); + return err; } @@ -365,7 +394,7 @@ static int cbc_aes_decrypt(struct blkcipher_desc *desc, int err; int ts_state; - padlock_reset_key(); + padlock_reset_key(&ctx->cword.encrypt); blkcipher_walk_init(&walk, dst, src, nbytes); err = blkcipher_walk_virt(desc, &walk); @@ -380,6 +409,9 @@ static int cbc_aes_decrypt(struct blkcipher_desc *desc, } irq_ts_restore(ts_state); + + padlock_store_cword(&ctx->cword.encrypt); + return err; } diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 24607669a52b1a0d41d6f51319c279284e1927f5..a3918c16b3dbb8650cef798fdfc173e4b66d5088 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -127,7 +127,6 @@ struct talitos_private { /* request callback tasklet */ struct tasklet_struct done_task; - struct tasklet_struct error_task; /* list of registered algorithms */ struct list_head alg_list; @@ -138,6 +137,7 @@ struct talitos_private { /* .features flag */ #define TALITOS_FTR_SRC_LINK_TBL_LEN_INCLUDES_EXTENT 0x00000001 +#define TALITOS_FTR_HW_AUTH_CHECK 0x00000002 /* * map virtual single (contiguous) pointer to h/w descriptor pointer @@ -184,6 +184,11 @@ static int reset_channel(struct device *dev, int ch) setbits32(priv->reg + TALITOS_CCCR_LO(ch), TALITOS_CCCR_LO_CDWE | TALITOS_CCCR_LO_CDIE); + /* and ICCR writeback, if available */ + if (priv->features & TALITOS_FTR_HW_AUTH_CHECK) + setbits32(priv->reg + TALITOS_CCCR_LO(ch), + TALITOS_CCCR_LO_IWSE); + return 0; } @@ -239,6 +244,11 @@ static int init_device(struct device *dev) setbits32(priv->reg + TALITOS_IMR, TALITOS_IMR_INIT); setbits32(priv->reg + TALITOS_IMR_LO, TALITOS_IMR_LO_INIT); + /* disable integrity check error interrupts (use writeback instead) */ + if (priv->features & TALITOS_FTR_HW_AUTH_CHECK) + setbits32(priv->reg + TALITOS_MDEUICR_LO, + TALITOS_MDEUICR_LO_ICE); + return 0; } @@ -370,6 +380,12 @@ static void talitos_done(unsigned long data) for (ch = 0; ch < priv->num_channels; ch++) flush_channel(dev, ch, 0, 0); + + /* At this point, all completed channels have been processed. + * Unmask done interrupts for channels completed later on. + */ + setbits32(priv->reg + TALITOS_IMR, TALITOS_IMR_INIT); + setbits32(priv->reg + TALITOS_IMR_LO, TALITOS_IMR_LO_INIT); } /* @@ -469,16 +485,13 @@ static void report_eu_error(struct device *dev, int ch, struct talitos_desc *des /* * recover from error interrupts */ -static void talitos_error(unsigned long data) +static void talitos_error(unsigned long data, u32 isr, u32 isr_lo) { struct device *dev = (struct device *)data; struct talitos_private *priv = dev_get_drvdata(dev); unsigned int timeout = TALITOS_TIMEOUT; int ch, error, reset_dev = 0, reset_ch = 0; - u32 isr, isr_lo, v, v_lo; - - isr = in_be32(priv->reg + TALITOS_ISR); - isr_lo = in_be32(priv->reg + TALITOS_ISR_LO); + u32 v, v_lo; for (ch = 0; ch < priv->num_channels; ch++) { /* skip channels without errors */ @@ -560,16 +573,19 @@ static irqreturn_t talitos_interrupt(int irq, void *data) isr = in_be32(priv->reg + TALITOS_ISR); isr_lo = in_be32(priv->reg + TALITOS_ISR_LO); - - /* ack */ + /* Acknowledge interrupt */ out_be32(priv->reg + TALITOS_ICR, isr); out_be32(priv->reg + TALITOS_ICR_LO, isr_lo); if (unlikely((isr & ~TALITOS_ISR_CHDONE) || isr_lo)) - talitos_error((unsigned long)data); + talitos_error((unsigned long)data, isr, isr_lo); else - if (likely(isr & TALITOS_ISR_CHDONE)) + if (likely(isr & TALITOS_ISR_CHDONE)) { + /* mask further done interrupts. */ + clrbits32(priv->reg + TALITOS_IMR, TALITOS_IMR_DONE); + /* done_task will unmask done interrupts at exit */ tasklet_schedule(&priv->done_task); + } return (isr || isr_lo) ? IRQ_HANDLED : IRQ_NONE; } @@ -802,7 +818,7 @@ static void ipsec_esp_encrypt_done(struct device *dev, aead_request_complete(areq, err); } -static void ipsec_esp_decrypt_done(struct device *dev, +static void ipsec_esp_decrypt_swauth_done(struct device *dev, struct talitos_desc *desc, void *context, int err) { @@ -834,6 +850,27 @@ static void ipsec_esp_decrypt_done(struct device *dev, aead_request_complete(req, err); } +static void ipsec_esp_decrypt_hwauth_done(struct device *dev, + struct talitos_desc *desc, void *context, + int err) +{ + struct aead_request *req = context; + struct ipsec_esp_edesc *edesc = + container_of(desc, struct ipsec_esp_edesc, desc); + + ipsec_esp_unmap(dev, edesc, req); + + /* check ICV auth status */ + if (!err) + if ((desc->hdr_lo & DESC_HDR_LO_ICCR1_MASK) != + DESC_HDR_LO_ICCR1_PASS) + err = -EBADMSG; + + kfree(edesc); + + aead_request_complete(req, err); +} + /* * convert scatterlist to SEC h/w link table format * stop at cryptlen bytes @@ -887,6 +924,7 @@ static int ipsec_esp(struct ipsec_esp_edesc *edesc, struct aead_request *areq, unsigned int authsize = ctx->authsize; unsigned int ivsize; int sg_count, ret; + int sg_link_tbl_len; /* hmac key */ map_single_talitos_ptr(dev, &desc->ptr[0], ctx->authkeylen, &ctx->key, @@ -924,33 +962,19 @@ static int ipsec_esp(struct ipsec_esp_edesc *edesc, struct aead_request *areq, if (sg_count == 1) { desc->ptr[4].ptr = cpu_to_be32(sg_dma_address(areq->src)); } else { - sg_count = sg_to_link_tbl(areq->src, sg_count, cryptlen, + sg_link_tbl_len = cryptlen; + + if ((edesc->desc.hdr & DESC_HDR_MODE1_MDEU_CICV) && + (edesc->desc.hdr & DESC_HDR_MODE0_ENCRYPT) == 0) { + sg_link_tbl_len = cryptlen + authsize; + } + sg_count = sg_to_link_tbl(areq->src, sg_count, sg_link_tbl_len, &edesc->link_tbl[0]); if (sg_count > 1) { - struct talitos_ptr *link_tbl_ptr = - &edesc->link_tbl[sg_count-1]; - struct scatterlist *sg; - struct talitos_private *priv = dev_get_drvdata(dev); - desc->ptr[4].j_extent |= DESC_PTR_LNKTBL_JUMP; desc->ptr[4].ptr = cpu_to_be32(edesc->dma_link_tbl); dma_sync_single_for_device(ctx->dev, edesc->dma_link_tbl, edesc->dma_len, DMA_BIDIRECTIONAL); - /* If necessary for this SEC revision, - * add a link table entry for ICV. - */ - if ((priv->features & - TALITOS_FTR_SRC_LINK_TBL_LEN_INCLUDES_EXTENT) && - (edesc->desc.hdr & DESC_HDR_MODE0_ENCRYPT) == 0) { - link_tbl_ptr->j_extent = 0; - link_tbl_ptr++; - link_tbl_ptr->j_extent = DESC_PTR_LNKTBL_RETURN; - link_tbl_ptr->len = cpu_to_be16(authsize); - sg = sg_last(areq->src, edesc->src_nents ? : 1); - link_tbl_ptr->ptr = cpu_to_be32( - (char *)sg_dma_address(sg) - + sg->length - authsize); - } } else { /* Only one segment now, so no link tbl needed */ desc->ptr[4].ptr = cpu_to_be32(sg_dma_address(areq->src)); @@ -975,13 +999,9 @@ static int ipsec_esp(struct ipsec_esp_edesc *edesc, struct aead_request *areq, desc->ptr[5].ptr = cpu_to_be32((struct talitos_ptr *) edesc->dma_link_tbl + edesc->src_nents + 1); - if (areq->src == areq->dst) { - memcpy(link_tbl_ptr, &edesc->link_tbl[0], - edesc->src_nents * sizeof(struct talitos_ptr)); - } else { - sg_count = sg_to_link_tbl(areq->dst, sg_count, cryptlen, - link_tbl_ptr); - } + sg_count = sg_to_link_tbl(areq->dst, sg_count, cryptlen, + link_tbl_ptr); + /* Add an entry to the link table for ICV data */ link_tbl_ptr += sg_count - 1; link_tbl_ptr->j_extent = 0; @@ -1106,11 +1126,14 @@ static int aead_authenc_encrypt(struct aead_request *req) return ipsec_esp(edesc, req, NULL, 0, ipsec_esp_encrypt_done); } + + static int aead_authenc_decrypt(struct aead_request *req) { struct crypto_aead *authenc = crypto_aead_reqtfm(req); struct talitos_ctx *ctx = crypto_aead_ctx(authenc); unsigned int authsize = ctx->authsize; + struct talitos_private *priv = dev_get_drvdata(ctx->dev); struct ipsec_esp_edesc *edesc; struct scatterlist *sg; void *icvdata; @@ -1122,22 +1145,39 @@ static int aead_authenc_decrypt(struct aead_request *req) if (IS_ERR(edesc)) return PTR_ERR(edesc); - /* stash incoming ICV for later cmp with ICV generated by the h/w */ - if (edesc->dma_len) - icvdata = &edesc->link_tbl[edesc->src_nents + - edesc->dst_nents + 2]; - else - icvdata = &edesc->link_tbl[0]; + if ((priv->features & TALITOS_FTR_HW_AUTH_CHECK) && + (((!edesc->src_nents && !edesc->dst_nents) || + priv->features & TALITOS_FTR_SRC_LINK_TBL_LEN_INCLUDES_EXTENT))) { + + /* decrypt and check the ICV */ + edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_DIR_INBOUND | + DESC_HDR_MODE1_MDEU_CICV; + + /* reset integrity check result bits */ + edesc->desc.hdr_lo = 0; + + return ipsec_esp(edesc, req, NULL, 0, ipsec_esp_decrypt_hwauth_done); + + } else { + + /* Have to check the ICV with software */ - sg = sg_last(req->src, edesc->src_nents ? : 1); + edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_DIR_INBOUND; + + /* stash incoming ICV for later cmp with ICV generated by the h/w */ + if (edesc->dma_len) + icvdata = &edesc->link_tbl[edesc->src_nents + + edesc->dst_nents + 2]; + else + icvdata = &edesc->link_tbl[0]; - memcpy(icvdata, (char *)sg_virt(sg) + sg->length - ctx->authsize, - ctx->authsize); + sg = sg_last(req->src, edesc->src_nents ? : 1); - /* decrypt */ - edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_DIR_INBOUND; + memcpy(icvdata, (char *)sg_virt(sg) + sg->length - ctx->authsize, + ctx->authsize); - return ipsec_esp(edesc, req, NULL, 0, ipsec_esp_decrypt_done); + return ipsec_esp(edesc, req, NULL, 0, ipsec_esp_decrypt_swauth_done); + } } static int aead_authenc_givencrypt( @@ -1391,7 +1431,6 @@ static int talitos_remove(struct of_device *ofdev) } tasklet_kill(&priv->done_task); - tasklet_kill(&priv->error_task); iounmap(priv->reg); @@ -1451,10 +1490,9 @@ static int talitos_probe(struct of_device *ofdev, priv->ofdev = ofdev; - INIT_LIST_HEAD(&priv->alg_list); - tasklet_init(&priv->done_task, talitos_done, (unsigned long)dev); - tasklet_init(&priv->error_task, talitos_error, (unsigned long)dev); + + INIT_LIST_HEAD(&priv->alg_list); priv->irq = irq_of_parse_and_map(np, 0); @@ -1508,6 +1546,9 @@ static int talitos_probe(struct of_device *ofdev, if (of_device_is_compatible(np, "fsl,sec3.0")) priv->features |= TALITOS_FTR_SRC_LINK_TBL_LEN_INCLUDES_EXTENT; + if (of_device_is_compatible(np, "fsl,sec2.1")) + priv->features |= TALITOS_FTR_HW_AUTH_CHECK; + priv->head_lock = kmalloc(sizeof(spinlock_t) * priv->num_channels, GFP_KERNEL); priv->tail_lock = kmalloc(sizeof(spinlock_t) * priv->num_channels, @@ -1551,7 +1592,7 @@ static int talitos_probe(struct of_device *ofdev, goto err_out; } for (i = 0; i < priv->num_channels; i++) - atomic_set(&priv->submit_count[i], -priv->chfifo_len); + atomic_set(&priv->submit_count[i], -(priv->chfifo_len - 1)); priv->head = kzalloc(sizeof(int) * priv->num_channels, GFP_KERNEL); priv->tail = kzalloc(sizeof(int) * priv->num_channels, GFP_KERNEL); diff --git a/drivers/crypto/talitos.h b/drivers/crypto/talitos.h index c48a405abf70c90a1f3cd177d8cde363abd36bb4..575981f0cfda76d943859a8ce1a5c74e5d2eafac 100644 --- a/drivers/crypto/talitos.h +++ b/drivers/crypto/talitos.h @@ -37,7 +37,8 @@ #define TALITOS_MCR_LO 0x1038 #define TALITOS_MCR_SWR 0x1 /* s/w reset */ #define TALITOS_IMR 0x1008 /* interrupt mask register */ -#define TALITOS_IMR_INIT 0x10fff /* enable channel IRQs */ +#define TALITOS_IMR_INIT 0x100ff /* enable channel IRQs */ +#define TALITOS_IMR_DONE 0x00055 /* done IRQs */ #define TALITOS_IMR_LO 0x100C #define TALITOS_IMR_LO_INIT 0x20000 /* allow RNGU error IRQs */ #define TALITOS_ISR 0x1010 /* interrupt status register */ @@ -55,6 +56,7 @@ #define TALITOS_CCCR_CONT 0x2 /* channel continue */ #define TALITOS_CCCR_RESET 0x1 /* channel reset */ #define TALITOS_CCCR_LO(ch) (ch * TALITOS_CH_STRIDE + 0x110c) +#define TALITOS_CCCR_LO_IWSE 0x80 /* chan. ICCR writeback enab. */ #define TALITOS_CCCR_LO_CDWE 0x10 /* chan. done writeback enab. */ #define TALITOS_CCCR_LO_NT 0x4 /* notification type */ #define TALITOS_CCCR_LO_CDIE 0x2 /* channel done IRQ enable */ @@ -102,6 +104,9 @@ #define TALITOS_AESUISR_LO 0x4034 #define TALITOS_MDEUISR 0x6030 /* message digest unit */ #define TALITOS_MDEUISR_LO 0x6034 +#define TALITOS_MDEUICR 0x6038 /* interrupt control */ +#define TALITOS_MDEUICR_LO 0x603c +#define TALITOS_MDEUICR_LO_ICE 0x4000 /* integrity check IRQ enable */ #define TALITOS_AFEUISR 0x8030 /* arc4 unit */ #define TALITOS_AFEUISR_LO 0x8034 #define TALITOS_RNGUISR 0xa030 /* random number unit */ @@ -129,31 +134,34 @@ */ /* written back when done */ -#define DESC_HDR_DONE __constant_cpu_to_be32(0xff000000) +#define DESC_HDR_DONE cpu_to_be32(0xff000000) +#define DESC_HDR_LO_ICCR1_MASK cpu_to_be32(0x00180000) +#define DESC_HDR_LO_ICCR1_PASS cpu_to_be32(0x00080000) +#define DESC_HDR_LO_ICCR1_FAIL cpu_to_be32(0x00100000) /* primary execution unit select */ -#define DESC_HDR_SEL0_MASK __constant_cpu_to_be32(0xf0000000) -#define DESC_HDR_SEL0_AFEU __constant_cpu_to_be32(0x10000000) -#define DESC_HDR_SEL0_DEU __constant_cpu_to_be32(0x20000000) -#define DESC_HDR_SEL0_MDEUA __constant_cpu_to_be32(0x30000000) -#define DESC_HDR_SEL0_MDEUB __constant_cpu_to_be32(0xb0000000) -#define DESC_HDR_SEL0_RNG __constant_cpu_to_be32(0x40000000) -#define DESC_HDR_SEL0_PKEU __constant_cpu_to_be32(0x50000000) -#define DESC_HDR_SEL0_AESU __constant_cpu_to_be32(0x60000000) -#define DESC_HDR_SEL0_KEU __constant_cpu_to_be32(0x70000000) -#define DESC_HDR_SEL0_CRCU __constant_cpu_to_be32(0x80000000) +#define DESC_HDR_SEL0_MASK cpu_to_be32(0xf0000000) +#define DESC_HDR_SEL0_AFEU cpu_to_be32(0x10000000) +#define DESC_HDR_SEL0_DEU cpu_to_be32(0x20000000) +#define DESC_HDR_SEL0_MDEUA cpu_to_be32(0x30000000) +#define DESC_HDR_SEL0_MDEUB cpu_to_be32(0xb0000000) +#define DESC_HDR_SEL0_RNG cpu_to_be32(0x40000000) +#define DESC_HDR_SEL0_PKEU cpu_to_be32(0x50000000) +#define DESC_HDR_SEL0_AESU cpu_to_be32(0x60000000) +#define DESC_HDR_SEL0_KEU cpu_to_be32(0x70000000) +#define DESC_HDR_SEL0_CRCU cpu_to_be32(0x80000000) /* primary execution unit mode (MODE0) and derivatives */ -#define DESC_HDR_MODE0_ENCRYPT __constant_cpu_to_be32(0x00100000) -#define DESC_HDR_MODE0_AESU_CBC __constant_cpu_to_be32(0x00200000) -#define DESC_HDR_MODE0_DEU_CBC __constant_cpu_to_be32(0x00400000) -#define DESC_HDR_MODE0_DEU_3DES __constant_cpu_to_be32(0x00200000) -#define DESC_HDR_MODE0_MDEU_INIT __constant_cpu_to_be32(0x01000000) -#define DESC_HDR_MODE0_MDEU_HMAC __constant_cpu_to_be32(0x00800000) -#define DESC_HDR_MODE0_MDEU_PAD __constant_cpu_to_be32(0x00400000) -#define DESC_HDR_MODE0_MDEU_MD5 __constant_cpu_to_be32(0x00200000) -#define DESC_HDR_MODE0_MDEU_SHA256 __constant_cpu_to_be32(0x00100000) -#define DESC_HDR_MODE0_MDEU_SHA1 __constant_cpu_to_be32(0x00000000) +#define DESC_HDR_MODE0_ENCRYPT cpu_to_be32(0x00100000) +#define DESC_HDR_MODE0_AESU_CBC cpu_to_be32(0x00200000) +#define DESC_HDR_MODE0_DEU_CBC cpu_to_be32(0x00400000) +#define DESC_HDR_MODE0_DEU_3DES cpu_to_be32(0x00200000) +#define DESC_HDR_MODE0_MDEU_INIT cpu_to_be32(0x01000000) +#define DESC_HDR_MODE0_MDEU_HMAC cpu_to_be32(0x00800000) +#define DESC_HDR_MODE0_MDEU_PAD cpu_to_be32(0x00400000) +#define DESC_HDR_MODE0_MDEU_MD5 cpu_to_be32(0x00200000) +#define DESC_HDR_MODE0_MDEU_SHA256 cpu_to_be32(0x00100000) +#define DESC_HDR_MODE0_MDEU_SHA1 cpu_to_be32(0x00000000) #define DESC_HDR_MODE0_MDEU_MD5_HMAC (DESC_HDR_MODE0_MDEU_MD5 | \ DESC_HDR_MODE0_MDEU_HMAC) #define DESC_HDR_MODE0_MDEU_SHA256_HMAC (DESC_HDR_MODE0_MDEU_SHA256 | \ @@ -162,18 +170,19 @@ DESC_HDR_MODE0_MDEU_HMAC) /* secondary execution unit select (SEL1) */ -#define DESC_HDR_SEL1_MASK __constant_cpu_to_be32(0x000f0000) -#define DESC_HDR_SEL1_MDEUA __constant_cpu_to_be32(0x00030000) -#define DESC_HDR_SEL1_MDEUB __constant_cpu_to_be32(0x000b0000) -#define DESC_HDR_SEL1_CRCU __constant_cpu_to_be32(0x00080000) +#define DESC_HDR_SEL1_MASK cpu_to_be32(0x000f0000) +#define DESC_HDR_SEL1_MDEUA cpu_to_be32(0x00030000) +#define DESC_HDR_SEL1_MDEUB cpu_to_be32(0x000b0000) +#define DESC_HDR_SEL1_CRCU cpu_to_be32(0x00080000) /* secondary execution unit mode (MODE1) and derivatives */ -#define DESC_HDR_MODE1_MDEU_INIT __constant_cpu_to_be32(0x00001000) -#define DESC_HDR_MODE1_MDEU_HMAC __constant_cpu_to_be32(0x00000800) -#define DESC_HDR_MODE1_MDEU_PAD __constant_cpu_to_be32(0x00000400) -#define DESC_HDR_MODE1_MDEU_MD5 __constant_cpu_to_be32(0x00000200) -#define DESC_HDR_MODE1_MDEU_SHA256 __constant_cpu_to_be32(0x00000100) -#define DESC_HDR_MODE1_MDEU_SHA1 __constant_cpu_to_be32(0x00000000) +#define DESC_HDR_MODE1_MDEU_CICV cpu_to_be32(0x00004000) +#define DESC_HDR_MODE1_MDEU_INIT cpu_to_be32(0x00001000) +#define DESC_HDR_MODE1_MDEU_HMAC cpu_to_be32(0x00000800) +#define DESC_HDR_MODE1_MDEU_PAD cpu_to_be32(0x00000400) +#define DESC_HDR_MODE1_MDEU_MD5 cpu_to_be32(0x00000200) +#define DESC_HDR_MODE1_MDEU_SHA256 cpu_to_be32(0x00000100) +#define DESC_HDR_MODE1_MDEU_SHA1 cpu_to_be32(0x00000000) #define DESC_HDR_MODE1_MDEU_MD5_HMAC (DESC_HDR_MODE1_MDEU_MD5 | \ DESC_HDR_MODE1_MDEU_HMAC) #define DESC_HDR_MODE1_MDEU_SHA256_HMAC (DESC_HDR_MODE1_MDEU_SHA256 | \ @@ -182,16 +191,16 @@ DESC_HDR_MODE1_MDEU_HMAC) /* direction of overall data flow (DIR) */ -#define DESC_HDR_DIR_INBOUND __constant_cpu_to_be32(0x00000002) +#define DESC_HDR_DIR_INBOUND cpu_to_be32(0x00000002) /* request done notification (DN) */ -#define DESC_HDR_DONE_NOTIFY __constant_cpu_to_be32(0x00000001) +#define DESC_HDR_DONE_NOTIFY cpu_to_be32(0x00000001) /* descriptor types */ -#define DESC_HDR_TYPE_AESU_CTR_NONSNOOP __constant_cpu_to_be32(0 << 3) -#define DESC_HDR_TYPE_IPSEC_ESP __constant_cpu_to_be32(1 << 3) -#define DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU __constant_cpu_to_be32(2 << 3) -#define DESC_HDR_TYPE_HMAC_SNOOP_NO_AFEU __constant_cpu_to_be32(4 << 3) +#define DESC_HDR_TYPE_AESU_CTR_NONSNOOP cpu_to_be32(0 << 3) +#define DESC_HDR_TYPE_IPSEC_ESP cpu_to_be32(1 << 3) +#define DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU cpu_to_be32(2 << 3) +#define DESC_HDR_TYPE_HMAC_SNOOP_NO_AFEU cpu_to_be32(4 << 3) /* link table extent field bits */ #define DESC_PTR_LNKTBL_JUMP 0x80 diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index e0dbd388757f2d8d62e5f8a4561b4d567e009746..e2667a8c2997155a141da0a15a5054430bb86e0c 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -161,7 +161,7 @@ config EDAC_PASEMI config EDAC_CELL tristate "Cell Broadband Engine memory controller" - depends on EDAC_MM_EDAC && PPC_CELL_NATIVE + depends on EDAC_MM_EDAC && PPC_CELL_COMMON help Support for error detection and correction on the Cell Broadband Engine internal memory controller diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c index 5fcd3d89c75d91cda65acd42fe34be8d987e9c67..4041e91432837b2d2cc9b898e10f04f20cc778ce 100644 --- a/drivers/edac/edac_device.c +++ b/drivers/edac/edac_device.c @@ -394,6 +394,12 @@ static void edac_device_workq_function(struct work_struct *work_req) mutex_lock(&device_ctls_mutex); + /* If we are being removed, bail out immediately */ + if (edac_dev->op_state == OP_OFFLINE) { + mutex_unlock(&device_ctls_mutex); + return; + } + /* Only poll controllers that are running polled and have a check */ if ((edac_dev->op_state == OP_RUNNING_POLL) && (edac_dev->edac_check != NULL)) { @@ -585,14 +591,14 @@ struct edac_device_ctl_info *edac_device_del_device(struct device *dev) /* mark this instance as OFFLINE */ edac_dev->op_state = OP_OFFLINE; - /* clear workq processing on this instance */ - edac_device_workq_teardown(edac_dev); - /* deregister from global list */ del_edac_device_from_global_list(edac_dev); mutex_unlock(&device_ctls_mutex); + /* clear workq processing on this instance */ + edac_device_workq_teardown(edac_dev); + /* Tear down the sysfs entries for this instance */ edac_device_remove_sysfs(edac_dev); diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index 8daf4793ac32485824194af5e14f332c50fc6f26..4a597d8c2f708ae4bb0e52a7c16a4fe0a0891092 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -467,6 +467,17 @@ const char *dmi_get_system_info(int field) } EXPORT_SYMBOL(dmi_get_system_info); +/** + * dmi_name_in_serial - Check if string is in the DMI product serial + * information. + */ +int dmi_name_in_serial(const char *str) +{ + int f = DMI_PRODUCT_SERIAL; + if (dmi_ident[f] && strstr(dmi_ident[f], str)) + return 1; + return 0; +} /** * dmi_name_in_vendors - Check if string is anywhere in the DMI vendor information. diff --git a/drivers/firmware/iscsi_ibft.c b/drivers/firmware/iscsi_ibft.c index 4353414a0b770c368b938760e8630f50bd065346..3ab3e4a41d670f48af0583c841dae8a6d040748f 100644 --- a/drivers/firmware/iscsi_ibft.c +++ b/drivers/firmware/iscsi_ibft.c @@ -284,15 +284,12 @@ static ssize_t sprintf_ipaddr(char *buf, u8 *ip) /* * IPV4 */ - str += sprintf(buf, NIPQUAD_FMT, ip[12], - ip[13], ip[14], ip[15]); + str += sprintf(buf, "%pI4", ip + 12); } else { /* * IPv6 */ - str += sprintf(str, NIP6_FMT, ntohs(ip[0]), ntohs(ip[1]), - ntohs(ip[2]), ntohs(ip[3]), ntohs(ip[4]), - ntohs(ip[5]), ntohs(ip[6]), ntohs(ip[7])); + str += sprintf(str, "%pI6", ip); } str += sprintf(str, "\n"); return str - buf; diff --git a/drivers/gpu/drm/radeon/radeon_irq.c b/drivers/gpu/drm/radeon/radeon_irq.c index 99be11418ac2dcecf8b3718ca5e8ba82478dc0b1..8289e16419a8d24566559223489037860809ec54 100644 --- a/drivers/gpu/drm/radeon/radeon_irq.c +++ b/drivers/gpu/drm/radeon/radeon_irq.c @@ -44,7 +44,7 @@ void radeon_irq_set_state(struct drm_device *dev, u32 mask, int state) else dev_priv->irq_enable_reg &= ~mask; - if (!dev->irq_enabled) + if (dev->irq_enabled) RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg); } @@ -57,7 +57,7 @@ static void r500_vbl_irq_set_state(struct drm_device *dev, u32 mask, int state) else dev_priv->r500_disp_irq_reg &= ~mask; - if (!dev->irq_enabled) + if (dev->irq_enabled) RADEON_WRITE(R500_DxMODE_INT_MASK, dev_priv->r500_disp_irq_reg); } diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 3384a717fec0d1d864eff63d8d0c798d7edd47cc..6c3d60b939bf20dbe47f8d4b2db13d1cbff68dc5 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -160,9 +160,39 @@ struct sh_mobile_i2c_data { static void activate_ch(struct sh_mobile_i2c_data *pd) { + unsigned long i2c_clk; + u_int32_t num; + u_int32_t denom; + u_int32_t tmp; + /* Make sure the clock is enabled */ clk_enable(pd->clk); + /* Get clock rate after clock is enabled */ + i2c_clk = clk_get_rate(pd->clk); + + /* Calculate the value for iccl. From the data sheet: + * iccl = (p clock / transfer rate) * (L / (L + H)) + * where L and H are the SCL low/high ratio (5/4 in this case). + * We also round off the result. + */ + num = i2c_clk * 5; + denom = NORMAL_SPEED * 9; + tmp = num * 10 / denom; + if (tmp % 10 >= 5) + pd->iccl = (u_int8_t)((num/denom) + 1); + else + pd->iccl = (u_int8_t)(num/denom); + + /* Calculate the value for icch. From the data sheet: + icch = (p clock / transfer rate) * (H / (L + H)) */ + num = i2c_clk * 4; + tmp = num * 10 / denom; + if (tmp % 10 >= 5) + pd->icch = (u_int8_t)((num/denom) + 1); + else + pd->icch = (u_int8_t)(num/denom); + /* Enable channel and configure rx ack */ iowrite8(ioread8(ICCR(pd)) | ICCR_ICE, ICCR(pd)); @@ -459,40 +489,6 @@ static struct i2c_algorithm sh_mobile_i2c_algorithm = { .master_xfer = sh_mobile_i2c_xfer, }; -static void sh_mobile_i2c_setup_channel(struct platform_device *dev) -{ - struct sh_mobile_i2c_data *pd = platform_get_drvdata(dev); - unsigned long peripheral_clk = clk_get_rate(pd->clk); - u_int32_t num; - u_int32_t denom; - u_int32_t tmp; - - spin_lock_init(&pd->lock); - init_waitqueue_head(&pd->wait); - - /* Calculate the value for iccl. From the data sheet: - * iccl = (p clock / transfer rate) * (L / (L + H)) - * where L and H are the SCL low/high ratio (5/4 in this case). - * We also round off the result. - */ - num = peripheral_clk * 5; - denom = NORMAL_SPEED * 9; - tmp = num * 10 / denom; - if (tmp % 10 >= 5) - pd->iccl = (u_int8_t)((num/denom) + 1); - else - pd->iccl = (u_int8_t)(num/denom); - - /* Calculate the value for icch. From the data sheet: - icch = (p clock / transfer rate) * (H / (L + H)) */ - num = peripheral_clk * 4; - tmp = num * 10 / denom; - if (tmp % 10 >= 5) - pd->icch = (u_int8_t)((num/denom) + 1); - else - pd->icch = (u_int8_t)(num/denom); -} - static int sh_mobile_i2c_hook_irqs(struct platform_device *dev, int hook) { struct resource *res; @@ -533,6 +529,7 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) struct sh_mobile_i2c_data *pd; struct i2c_adapter *adap; struct resource *res; + char clk_name[8]; int size; int ret; @@ -542,9 +539,10 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) return -ENOMEM; } - pd->clk = clk_get(&dev->dev, "peripheral_clk"); + snprintf(clk_name, sizeof(clk_name), "i2c%d", dev->id); + pd->clk = clk_get(&dev->dev, clk_name); if (IS_ERR(pd->clk)) { - dev_err(&dev->dev, "cannot get peripheral clock\n"); + dev_err(&dev->dev, "cannot get clock \"%s\"\n", clk_name); ret = PTR_ERR(pd->clk); goto err; } @@ -586,7 +584,8 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) strlcpy(adap->name, dev->name, sizeof(adap->name)); - sh_mobile_i2c_setup_channel(dev); + spin_lock_init(&pd->lock); + init_waitqueue_head(&pd->wait); ret = i2c_add_numbered_adapter(adap); if (ret < 0) { diff --git a/drivers/ide/cs5530.c b/drivers/ide/cs5530.c index 53f079cc00afc010f2cf62b643fe98432feceea8..d8ede85fe17f4428be6713394e678af59c1457b2 100644 --- a/drivers/ide/cs5530.c +++ b/drivers/ide/cs5530.c @@ -81,11 +81,12 @@ static u8 cs5530_udma_filter(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; ide_drive_t *mate = ide_get_pair_dev(drive); - u16 *mateid = mate->id; + u16 *mateid; u8 mask = hwif->ultra_mask; if (mate == NULL) goto out; + mateid = mate->id; if (ata_id_has_dma(mateid) && __ide_dma_bad_drive(mate) == 0) { if ((mateid[ATA_ID_FIELD_VALID] & 4) && diff --git a/drivers/ide/macide.c b/drivers/ide/macide.c index 43f97cc1d30e8e7481b423cb60d3973e91d3ac44..3c60064f1d4f757a3bf06193af4267b9b226ca58 100644 --- a/drivers/ide/macide.c +++ b/drivers/ide/macide.c @@ -18,7 +18,6 @@ #include #include -#include #include #include #include diff --git a/drivers/ide/sc1200.c b/drivers/ide/sc1200.c index f1a8758e3a99f7d8b6953782c4150c35fefb8097..ec7f766ef5e44ff6387e962592c5a985282de4c9 100644 --- a/drivers/ide/sc1200.c +++ b/drivers/ide/sc1200.c @@ -104,11 +104,12 @@ static u8 sc1200_udma_filter(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; ide_drive_t *mate = ide_get_pair_dev(drive); - u16 *mateid = mate->id; + u16 *mateid; u8 mask = hwif->ultra_mask; if (mate == NULL) goto out; + mateid = mate->id; if (ata_id_has_dma(mateid) && __ide_dma_bad_drive(mate) == 0) { if ((mateid[ATA_ID_FIELD_VALID] & 4) && diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index 09a2bec7fd3207b65abac3f93339b7cd46a66c8e..d98b05b28262776d954818b5989a49f5207a7f85 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -41,6 +41,8 @@ #include #include #include +#include +#include #include MODULE_AUTHOR("Sean Hefty"); @@ -49,8 +51,8 @@ MODULE_LICENSE("Dual BSD/GPL"); struct addr_req { struct list_head list; - struct sockaddr src_addr; - struct sockaddr dst_addr; + struct sockaddr_storage src_addr; + struct sockaddr_storage dst_addr; struct rdma_dev_addr *addr; struct rdma_addr_client *client; void *context; @@ -113,15 +115,32 @@ EXPORT_SYMBOL(rdma_copy_addr); int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr) { struct net_device *dev; - __be32 ip = ((struct sockaddr_in *) addr)->sin_addr.s_addr; - int ret; + int ret = -EADDRNOTAVAIL; - dev = ip_dev_find(&init_net, ip); - if (!dev) - return -EADDRNOTAVAIL; + switch (addr->sa_family) { + case AF_INET: + dev = ip_dev_find(&init_net, + ((struct sockaddr_in *) addr)->sin_addr.s_addr); + + if (!dev) + return ret; - ret = rdma_copy_addr(dev_addr, dev, NULL); - dev_put(dev); + ret = rdma_copy_addr(dev_addr, dev, NULL); + dev_put(dev); + break; + case AF_INET6: + for_each_netdev(&init_net, dev) { + if (ipv6_chk_addr(&init_net, + &((struct sockaddr_in6 *) addr)->sin6_addr, + dev, 1)) { + ret = rdma_copy_addr(dev_addr, dev, NULL); + break; + } + } + break; + default: + break; + } return ret; } EXPORT_SYMBOL(rdma_translate_ip); @@ -156,22 +175,37 @@ static void queue_req(struct addr_req *req) mutex_unlock(&lock); } -static void addr_send_arp(struct sockaddr_in *dst_in) +static void addr_send_arp(struct sockaddr *dst_in) { struct rtable *rt; struct flowi fl; - __be32 dst_ip = dst_in->sin_addr.s_addr; + struct dst_entry *dst; memset(&fl, 0, sizeof fl); - fl.nl_u.ip4_u.daddr = dst_ip; - if (ip_route_output_key(&init_net, &rt, &fl)) - return; + if (dst_in->sa_family == AF_INET) { + fl.nl_u.ip4_u.daddr = + ((struct sockaddr_in *) dst_in)->sin_addr.s_addr; - neigh_event_send(rt->u.dst.neighbour, NULL); - ip_rt_put(rt); + if (ip_route_output_key(&init_net, &rt, &fl)) + return; + + neigh_event_send(rt->u.dst.neighbour, NULL); + ip_rt_put(rt); + + } else { + fl.nl_u.ip6_u.daddr = + ((struct sockaddr_in6 *) dst_in)->sin6_addr; + + dst = ip6_route_output(&init_net, NULL, &fl); + if (!dst) + return; + + neigh_event_send(dst->neighbour, NULL); + dst_release(dst); + } } -static int addr_resolve_remote(struct sockaddr_in *src_in, +static int addr4_resolve_remote(struct sockaddr_in *src_in, struct sockaddr_in *dst_in, struct rdma_dev_addr *addr) { @@ -220,10 +254,51 @@ static int addr_resolve_remote(struct sockaddr_in *src_in, return ret; } +static int addr6_resolve_remote(struct sockaddr_in6 *src_in, + struct sockaddr_in6 *dst_in, + struct rdma_dev_addr *addr) +{ + struct flowi fl; + struct neighbour *neigh; + struct dst_entry *dst; + int ret = -ENODATA; + + memset(&fl, 0, sizeof fl); + fl.nl_u.ip6_u.daddr = dst_in->sin6_addr; + fl.nl_u.ip6_u.saddr = src_in->sin6_addr; + + dst = ip6_route_output(&init_net, NULL, &fl); + if (!dst) + return ret; + + if (dst->dev->flags & IFF_NOARP) { + ret = rdma_copy_addr(addr, dst->dev, NULL); + } else { + neigh = dst->neighbour; + if (neigh && (neigh->nud_state & NUD_VALID)) + ret = rdma_copy_addr(addr, neigh->dev, neigh->ha); + } + + dst_release(dst); + return ret; +} + +static int addr_resolve_remote(struct sockaddr *src_in, + struct sockaddr *dst_in, + struct rdma_dev_addr *addr) +{ + if (src_in->sa_family == AF_INET) { + return addr4_resolve_remote((struct sockaddr_in *) src_in, + (struct sockaddr_in *) dst_in, addr); + } else + return addr6_resolve_remote((struct sockaddr_in6 *) src_in, + (struct sockaddr_in6 *) dst_in, addr); +} + static void process_req(struct work_struct *work) { struct addr_req *req, *temp_req; - struct sockaddr_in *src_in, *dst_in; + struct sockaddr *src_in, *dst_in; struct list_head done_list; INIT_LIST_HEAD(&done_list); @@ -231,8 +306,8 @@ static void process_req(struct work_struct *work) mutex_lock(&lock); list_for_each_entry_safe(req, temp_req, &req_list, list) { if (req->status == -ENODATA) { - src_in = (struct sockaddr_in *) &req->src_addr; - dst_in = (struct sockaddr_in *) &req->dst_addr; + src_in = (struct sockaddr *) &req->src_addr; + dst_in = (struct sockaddr *) &req->dst_addr; req->status = addr_resolve_remote(src_in, dst_in, req->addr); if (req->status && time_after_eq(jiffies, req->timeout)) @@ -251,41 +326,72 @@ static void process_req(struct work_struct *work) list_for_each_entry_safe(req, temp_req, &done_list, list) { list_del(&req->list); - req->callback(req->status, &req->src_addr, req->addr, - req->context); + req->callback(req->status, (struct sockaddr *) &req->src_addr, + req->addr, req->context); put_client(req->client); kfree(req); } } -static int addr_resolve_local(struct sockaddr_in *src_in, - struct sockaddr_in *dst_in, +static int addr_resolve_local(struct sockaddr *src_in, + struct sockaddr *dst_in, struct rdma_dev_addr *addr) { struct net_device *dev; - __be32 src_ip = src_in->sin_addr.s_addr; - __be32 dst_ip = dst_in->sin_addr.s_addr; int ret; - dev = ip_dev_find(&init_net, dst_ip); - if (!dev) - return -EADDRNOTAVAIL; - - if (ipv4_is_zeronet(src_ip)) { - src_in->sin_family = dst_in->sin_family; - src_in->sin_addr.s_addr = dst_ip; - ret = rdma_copy_addr(addr, dev, dev->dev_addr); - } else if (ipv4_is_loopback(src_ip)) { - ret = rdma_translate_ip((struct sockaddr *)dst_in, addr); - if (!ret) - memcpy(addr->dst_dev_addr, dev->dev_addr, MAX_ADDR_LEN); + if (dst_in->sa_family == AF_INET) { + __be32 src_ip = ((struct sockaddr_in *) src_in)->sin_addr.s_addr; + __be32 dst_ip = ((struct sockaddr_in *) dst_in)->sin_addr.s_addr; + + dev = ip_dev_find(&init_net, dst_ip); + if (!dev) + return -EADDRNOTAVAIL; + + if (ipv4_is_zeronet(src_ip)) { + src_in->sa_family = dst_in->sa_family; + ((struct sockaddr_in *) src_in)->sin_addr.s_addr = dst_ip; + ret = rdma_copy_addr(addr, dev, dev->dev_addr); + } else if (ipv4_is_loopback(src_ip)) { + ret = rdma_translate_ip(dst_in, addr); + if (!ret) + memcpy(addr->dst_dev_addr, dev->dev_addr, MAX_ADDR_LEN); + } else { + ret = rdma_translate_ip(src_in, addr); + if (!ret) + memcpy(addr->dst_dev_addr, dev->dev_addr, MAX_ADDR_LEN); + } + dev_put(dev); } else { - ret = rdma_translate_ip((struct sockaddr *)src_in, addr); - if (!ret) - memcpy(addr->dst_dev_addr, dev->dev_addr, MAX_ADDR_LEN); + struct in6_addr *a; + + for_each_netdev(&init_net, dev) + if (ipv6_chk_addr(&init_net, + &((struct sockaddr_in6 *) addr)->sin6_addr, + dev, 1)) + break; + + if (!dev) + return -EADDRNOTAVAIL; + + a = &((struct sockaddr_in6 *) src_in)->sin6_addr; + + if (ipv6_addr_any(a)) { + src_in->sa_family = dst_in->sa_family; + ((struct sockaddr_in6 *) src_in)->sin6_addr = + ((struct sockaddr_in6 *) dst_in)->sin6_addr; + ret = rdma_copy_addr(addr, dev, dev->dev_addr); + } else if (ipv6_addr_loopback(a)) { + ret = rdma_translate_ip(dst_in, addr); + if (!ret) + memcpy(addr->dst_dev_addr, dev->dev_addr, MAX_ADDR_LEN); + } else { + ret = rdma_translate_ip(src_in, addr); + if (!ret) + memcpy(addr->dst_dev_addr, dev->dev_addr, MAX_ADDR_LEN); + } } - dev_put(dev); return ret; } @@ -296,7 +402,7 @@ int rdma_resolve_ip(struct rdma_addr_client *client, struct rdma_dev_addr *addr, void *context), void *context) { - struct sockaddr_in *src_in, *dst_in; + struct sockaddr *src_in, *dst_in; struct addr_req *req; int ret = 0; @@ -313,8 +419,8 @@ int rdma_resolve_ip(struct rdma_addr_client *client, req->client = client; atomic_inc(&client->refcount); - src_in = (struct sockaddr_in *) &req->src_addr; - dst_in = (struct sockaddr_in *) &req->dst_addr; + src_in = (struct sockaddr *) &req->src_addr; + dst_in = (struct sockaddr *) &req->dst_addr; req->status = addr_resolve_local(src_in, dst_in, addr); if (req->status == -EADDRNOTAVAIL) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index d951896ff7fc9f6023db24c6280d22870f98f946..2a2e50871b4063beb3c3ab8c4ae73ead5797e060 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -42,6 +42,7 @@ #include #include +#include #include #include @@ -636,7 +637,12 @@ static inline int cma_zero_addr(struct sockaddr *addr) static inline int cma_loopback_addr(struct sockaddr *addr) { - return ipv4_is_loopback(((struct sockaddr_in *) addr)->sin_addr.s_addr); + if (addr->sa_family == AF_INET) + return ipv4_is_loopback( + ((struct sockaddr_in *) addr)->sin_addr.s_addr); + else + return ipv6_addr_loopback( + &((struct sockaddr_in6 *) addr)->sin6_addr); } static inline int cma_any_addr(struct sockaddr *addr) @@ -1467,10 +1473,10 @@ static void cma_listen_on_all(struct rdma_id_private *id_priv) static int cma_bind_any(struct rdma_cm_id *id, sa_family_t af) { - struct sockaddr_in addr_in; + struct sockaddr_storage addr_in; memset(&addr_in, 0, sizeof addr_in); - addr_in.sin_family = af; + addr_in.ss_family = af; return rdma_bind_addr(id, (struct sockaddr *) &addr_in); } @@ -2073,7 +2079,7 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr) struct rdma_id_private *id_priv; int ret; - if (addr->sa_family != AF_INET) + if (addr->sa_family != AF_INET && addr->sa_family != AF_INET6) return -EAFNOSUPPORT; id_priv = container_of(id, struct rdma_id_private, id); @@ -2113,31 +2119,59 @@ EXPORT_SYMBOL(rdma_bind_addr); static int cma_format_hdr(void *hdr, enum rdma_port_space ps, struct rdma_route *route) { - struct sockaddr_in *src4, *dst4; struct cma_hdr *cma_hdr; struct sdp_hh *sdp_hdr; - src4 = (struct sockaddr_in *) &route->addr.src_addr; - dst4 = (struct sockaddr_in *) &route->addr.dst_addr; - - switch (ps) { - case RDMA_PS_SDP: - sdp_hdr = hdr; - if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION) - return -EINVAL; - sdp_set_ip_ver(sdp_hdr, 4); - sdp_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr; - sdp_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr; - sdp_hdr->port = src4->sin_port; - break; - default: - cma_hdr = hdr; - cma_hdr->cma_version = CMA_VERSION; - cma_set_ip_ver(cma_hdr, 4); - cma_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr; - cma_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr; - cma_hdr->port = src4->sin_port; - break; + if (route->addr.src_addr.ss_family == AF_INET) { + struct sockaddr_in *src4, *dst4; + + src4 = (struct sockaddr_in *) &route->addr.src_addr; + dst4 = (struct sockaddr_in *) &route->addr.dst_addr; + + switch (ps) { + case RDMA_PS_SDP: + sdp_hdr = hdr; + if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION) + return -EINVAL; + sdp_set_ip_ver(sdp_hdr, 4); + sdp_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr; + sdp_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr; + sdp_hdr->port = src4->sin_port; + break; + default: + cma_hdr = hdr; + cma_hdr->cma_version = CMA_VERSION; + cma_set_ip_ver(cma_hdr, 4); + cma_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr; + cma_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr; + cma_hdr->port = src4->sin_port; + break; + } + } else { + struct sockaddr_in6 *src6, *dst6; + + src6 = (struct sockaddr_in6 *) &route->addr.src_addr; + dst6 = (struct sockaddr_in6 *) &route->addr.dst_addr; + + switch (ps) { + case RDMA_PS_SDP: + sdp_hdr = hdr; + if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION) + return -EINVAL; + sdp_set_ip_ver(sdp_hdr, 6); + sdp_hdr->src_addr.ip6 = src6->sin6_addr; + sdp_hdr->dst_addr.ip6 = dst6->sin6_addr; + sdp_hdr->port = src6->sin6_port; + break; + default: + cma_hdr = hdr; + cma_hdr->cma_version = CMA_VERSION; + cma_set_ip_ver(cma_hdr, 6); + cma_hdr->src_addr.ip6 = src6->sin6_addr; + cma_hdr->dst_addr.ip6 = dst6->sin6_addr; + cma_hdr->port = src6->sin6_port; + break; + } } return 0; } diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c index 4d1042115598d39b95ccc76b12b80da0cbdf89c6..4f4d1bb9f069fa6a8f61c0027eb1f07c377d3664 100644 --- a/drivers/infiniband/core/sysfs.c +++ b/drivers/infiniband/core/sysfs.c @@ -262,15 +262,7 @@ static ssize_t show_port_gid(struct ib_port *p, struct port_attribute *attr, if (ret) return ret; - return sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", - be16_to_cpu(((__be16 *) gid.raw)[0]), - be16_to_cpu(((__be16 *) gid.raw)[1]), - be16_to_cpu(((__be16 *) gid.raw)[2]), - be16_to_cpu(((__be16 *) gid.raw)[3]), - be16_to_cpu(((__be16 *) gid.raw)[4]), - be16_to_cpu(((__be16 *) gid.raw)[5]), - be16_to_cpu(((__be16 *) gid.raw)[6]), - be16_to_cpu(((__be16 *) gid.raw)[7])); + return sprintf(buf, "%pI6\n", gid.raw); } static ssize_t show_port_pkey(struct ib_port *p, struct port_attribute *attr, diff --git a/drivers/infiniband/hw/amso1100/c2_provider.c b/drivers/infiniband/hw/amso1100/c2_provider.c index 69580e282af012a918fb6bf258333a34f258a584..5119d6508181633bf2ace7886bc0034afd74bcf8 100644 --- a/drivers/infiniband/hw/amso1100/c2_provider.c +++ b/drivers/infiniband/hw/amso1100/c2_provider.c @@ -653,7 +653,7 @@ static int c2_service_destroy(struct iw_cm_id *cm_id) static int c2_pseudo_up(struct net_device *netdev) { struct in_device *ind; - struct c2_dev *c2dev = netdev->priv; + struct c2_dev *c2dev = netdev->ml_priv; ind = in_dev_get(netdev); if (!ind) @@ -678,7 +678,7 @@ static int c2_pseudo_up(struct net_device *netdev) static int c2_pseudo_down(struct net_device *netdev) { struct in_device *ind; - struct c2_dev *c2dev = netdev->priv; + struct c2_dev *c2dev = netdev->ml_priv; ind = in_dev_get(netdev); if (!ind) @@ -746,14 +746,14 @@ static struct net_device *c2_pseudo_netdev_init(struct c2_dev *c2dev) /* change ethxxx to iwxxx */ strcpy(name, "iw"); strcat(name, &c2dev->netdev->name[3]); - netdev = alloc_netdev(sizeof(*netdev), name, setup); + netdev = alloc_netdev(0, name, setup); if (!netdev) { printk(KERN_ERR PFX "%s - etherdev alloc failed", __func__); return NULL; } - netdev->priv = c2dev; + netdev->ml_priv = c2dev; SET_NETDEV_DEV(netdev, &c2dev->pcidev->dev); diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h index 7fc35cf0cddf35285cd91586e6d1aa02145a6a00..c825142a2fb752c7514e3af7d95d13c6d2d60f8b 100644 --- a/drivers/infiniband/hw/ehca/ehca_classes.h +++ b/drivers/infiniband/hw/ehca/ehca_classes.h @@ -175,6 +175,13 @@ struct ehca_queue_map { unsigned int next_wqe_idx; /* Idx to first wqe to be flushed */ }; +/* function to calculate the next index for the qmap */ +static inline unsigned int next_index(unsigned int cur_index, unsigned int limit) +{ + unsigned int temp = cur_index + 1; + return (temp == limit) ? 0 : temp; +} + struct ehca_qp { union { struct ib_qp ib_qp; diff --git a/drivers/infiniband/hw/ehca/ehca_eq.c b/drivers/infiniband/hw/ehca/ehca_eq.c index 49660dfa186785f8d73b16b84e0ddcc141967cac..523e733c630e560acf6585ed1f35e772378e9649 100644 --- a/drivers/infiniband/hw/ehca/ehca_eq.c +++ b/drivers/infiniband/hw/ehca/ehca_eq.c @@ -113,7 +113,7 @@ int ehca_create_eq(struct ehca_shca *shca, if (h_ret != H_SUCCESS || vpage) goto create_eq_exit2; } else { - if (h_ret != H_PAGE_REGISTERED || !vpage) + if (h_ret != H_PAGE_REGISTERED) goto create_eq_exit2; } } diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c index bec7e0249358f6cb876729d9070c51d94f6e29e7..3b77b674cbf61a4caba20fc0fb42daa49f55eda9 100644 --- a/drivers/infiniband/hw/ehca/ehca_main.c +++ b/drivers/infiniband/hw/ehca/ehca_main.c @@ -717,6 +717,7 @@ static int __devinit ehca_probe(struct of_device *dev, const u64 *handle; struct ib_pd *ibpd; int ret, i, eq_size; + unsigned long flags; handle = of_get_property(dev->node, "ibm,hca-handle", NULL); if (!handle) { @@ -830,9 +831,9 @@ static int __devinit ehca_probe(struct of_device *dev, ehca_err(&shca->ib_device, "Cannot create device attributes ret=%d", ret); - spin_lock(&shca_list_lock); + spin_lock_irqsave(&shca_list_lock, flags); list_add(&shca->shca_list, &shca_list); - spin_unlock(&shca_list_lock); + spin_unlock_irqrestore(&shca_list_lock, flags); return 0; @@ -878,6 +879,7 @@ static int __devinit ehca_probe(struct of_device *dev, static int __devexit ehca_remove(struct of_device *dev) { struct ehca_shca *shca = dev->dev.driver_data; + unsigned long flags; int ret; sysfs_remove_group(&dev->dev.kobj, &ehca_dev_attr_grp); @@ -915,9 +917,9 @@ static int __devexit ehca_remove(struct of_device *dev) ib_dealloc_device(&shca->ib_device); - spin_lock(&shca_list_lock); + spin_lock_irqsave(&shca_list_lock, flags); list_del(&shca->shca_list); - spin_unlock(&shca_list_lock); + spin_unlock_irqrestore(&shca_list_lock, flags); return ret; } @@ -975,6 +977,7 @@ static int ehca_mem_notifier(struct notifier_block *nb, unsigned long action, void *data) { static unsigned long ehca_dmem_warn_time; + unsigned long flags; switch (action) { case MEM_CANCEL_OFFLINE: @@ -985,12 +988,12 @@ static int ehca_mem_notifier(struct notifier_block *nb, case MEM_GOING_ONLINE: case MEM_GOING_OFFLINE: /* only ok if no hca is attached to the lpar */ - spin_lock(&shca_list_lock); + spin_lock_irqsave(&shca_list_lock, flags); if (list_empty(&shca_list)) { - spin_unlock(&shca_list_lock); + spin_unlock_irqrestore(&shca_list_lock, flags); return NOTIFY_OK; } else { - spin_unlock(&shca_list_lock); + spin_unlock_irqrestore(&shca_list_lock, flags); if (printk_timed_ratelimit(&ehca_dmem_warn_time, 30 * 1000)) ehca_gen_err("DMEM operations are not allowed" diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index cadbf0cdd910e996ddca5029e6a66dcbe27382a9..f161cf173dbe3585e6cbf87275e71ef435ad018e 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c @@ -1138,14 +1138,14 @@ static int calc_left_cqes(u64 wqe_p, struct ipz_queue *ipz_queue, return -EFAULT; } - tail_idx = (qmap->tail + 1) % qmap->entries; + tail_idx = next_index(qmap->tail, qmap->entries); wqe_idx = q_ofs / ipz_queue->qe_size; /* check all processed wqes, whether a cqe is requested or not */ while (tail_idx != wqe_idx) { if (qmap->map[tail_idx].cqe_req) qmap->left_to_poll++; - tail_idx = (tail_idx + 1) % qmap->entries; + tail_idx = next_index(tail_idx, qmap->entries); } /* save index in queue, where we have to start flushing */ qmap->next_wqe_idx = wqe_idx; @@ -1195,14 +1195,14 @@ static int check_for_left_cqes(struct ehca_qp *my_qp, struct ehca_shca *shca) } else { spin_lock_irqsave(&my_qp->send_cq->spinlock, flags); my_qp->sq_map.left_to_poll = 0; - my_qp->sq_map.next_wqe_idx = (my_qp->sq_map.tail + 1) % - my_qp->sq_map.entries; + my_qp->sq_map.next_wqe_idx = next_index(my_qp->sq_map.tail, + my_qp->sq_map.entries); spin_unlock_irqrestore(&my_qp->send_cq->spinlock, flags); spin_lock_irqsave(&my_qp->recv_cq->spinlock, flags); my_qp->rq_map.left_to_poll = 0; - my_qp->rq_map.next_wqe_idx = (my_qp->rq_map.tail + 1) % - my_qp->rq_map.entries; + my_qp->rq_map.next_wqe_idx = next_index(my_qp->rq_map.tail, + my_qp->rq_map.entries); spin_unlock_irqrestore(&my_qp->recv_cq->spinlock, flags); } diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c index 00a648f4316c66b0f4585cfbf63db7792fee2c3d..c7112686782faeda1fb38e4a2a882598c0744856 100644 --- a/drivers/infiniband/hw/ehca/ehca_reqs.c +++ b/drivers/infiniband/hw/ehca/ehca_reqs.c @@ -726,13 +726,13 @@ static inline int ehca_poll_cq_one(struct ib_cq *cq, struct ib_wc *wc) * set left_to_poll to 0 because in error state, we will not * get any additional CQEs */ - my_qp->sq_map.next_wqe_idx = (my_qp->sq_map.tail + 1) % - my_qp->sq_map.entries; + my_qp->sq_map.next_wqe_idx = next_index(my_qp->sq_map.tail, + my_qp->sq_map.entries); my_qp->sq_map.left_to_poll = 0; ehca_add_to_err_list(my_qp, 1); - my_qp->rq_map.next_wqe_idx = (my_qp->rq_map.tail + 1) % - my_qp->rq_map.entries; + my_qp->rq_map.next_wqe_idx = next_index(my_qp->rq_map.tail, + my_qp->rq_map.entries); my_qp->rq_map.left_to_poll = 0; if (HAS_RQ(my_qp)) ehca_add_to_err_list(my_qp, 0); @@ -860,9 +860,8 @@ static int generate_flush_cqes(struct ehca_qp *my_qp, struct ib_cq *cq, /* mark as reported and advance next_wqe pointer */ qmap_entry->reported = 1; - qmap->next_wqe_idx++; - if (qmap->next_wqe_idx == qmap->entries) - qmap->next_wqe_idx = 0; + qmap->next_wqe_idx = next_index(qmap->next_wqe_idx, + qmap->entries); qmap_entry = &qmap->map[qmap->next_wqe_idx]; wc++; nr++; diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c index ad0aab60b051225deb5020623d02c7d09d56ef37..69c0ce321b4e7cecf4b475bd230cc5bda2614245 100644 --- a/drivers/infiniband/hw/ipath/ipath_driver.c +++ b/drivers/infiniband/hw/ipath/ipath_driver.c @@ -661,6 +661,8 @@ static int __devinit ipath_init_one(struct pci_dev *pdev, static void __devexit cleanup_device(struct ipath_devdata *dd) { int port; + struct ipath_portdata **tmp; + unsigned long flags; if (*dd->ipath_statusp & IPATH_STATUS_CHIP_PRESENT) { /* can't do anything more with chip; needs re-init */ @@ -742,20 +744,21 @@ static void __devexit cleanup_device(struct ipath_devdata *dd) /* * free any resources still in use (usually just kernel ports) - * at unload; we do for portcnt, not cfgports, because cfgports - * could have changed while we were loaded. + * at unload; we do for portcnt, because that's what we allocate. + * We acquire lock to be really paranoid that ipath_pd isn't being + * accessed from some interrupt-related code (that should not happen, + * but best to be sure). */ + spin_lock_irqsave(&dd->ipath_uctxt_lock, flags); + tmp = dd->ipath_pd; + dd->ipath_pd = NULL; + spin_unlock_irqrestore(&dd->ipath_uctxt_lock, flags); for (port = 0; port < dd->ipath_portcnt; port++) { - struct ipath_portdata *pd = dd->ipath_pd[port]; - dd->ipath_pd[port] = NULL; + struct ipath_portdata *pd = tmp[port]; + tmp[port] = NULL; /* debugging paranoia */ ipath_free_pddata(dd, pd); } - kfree(dd->ipath_pd); - /* - * debuggability, in case some cleanup path tries to use it - * after this - */ - dd->ipath_pd = NULL; + kfree(tmp); } static void __devexit ipath_remove_one(struct pci_dev *pdev) @@ -2586,6 +2589,7 @@ int ipath_reset_device(int unit) { int ret, i; struct ipath_devdata *dd = ipath_lookup(unit); + unsigned long flags; if (!dd) { ret = -ENODEV; @@ -2611,18 +2615,21 @@ int ipath_reset_device(int unit) goto bail; } + spin_lock_irqsave(&dd->ipath_uctxt_lock, flags); if (dd->ipath_pd) for (i = 1; i < dd->ipath_cfgports; i++) { - if (dd->ipath_pd[i] && dd->ipath_pd[i]->port_cnt) { - ipath_dbg("unit %u port %d is in use " - "(PID %u cmd %s), can't reset\n", - unit, i, - pid_nr(dd->ipath_pd[i]->port_pid), - dd->ipath_pd[i]->port_comm); - ret = -EBUSY; - goto bail; - } + if (!dd->ipath_pd[i] || !dd->ipath_pd[i]->port_cnt) + continue; + spin_unlock_irqrestore(&dd->ipath_uctxt_lock, flags); + ipath_dbg("unit %u port %d is in use " + "(PID %u cmd %s), can't reset\n", + unit, i, + pid_nr(dd->ipath_pd[i]->port_pid), + dd->ipath_pd[i]->port_comm); + ret = -EBUSY; + goto bail; } + spin_unlock_irqrestore(&dd->ipath_uctxt_lock, flags); if (dd->ipath_flags & IPATH_HAS_SEND_DMA) teardown_sdma(dd); @@ -2656,9 +2663,12 @@ static int ipath_signal_procs(struct ipath_devdata *dd, int sig) { int i, sub, any = 0; struct pid *pid; + unsigned long flags; if (!dd->ipath_pd) return 0; + + spin_lock_irqsave(&dd->ipath_uctxt_lock, flags); for (i = 1; i < dd->ipath_cfgports; i++) { if (!dd->ipath_pd[i] || !dd->ipath_pd[i]->port_cnt) continue; @@ -2682,6 +2692,7 @@ static int ipath_signal_procs(struct ipath_devdata *dd, int sig) any++; } } + spin_unlock_irqrestore(&dd->ipath_uctxt_lock, flags); return any; } diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c index 1af1f3a907c6eb25a7930a6fd2e22ca36ad7135b..239d4e8068ac14e5ce39c52218726f1ed1d732da 100644 --- a/drivers/infiniband/hw/ipath/ipath_file_ops.c +++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c @@ -223,8 +223,13 @@ static int ipath_get_base_info(struct file *fp, (unsigned long long) kinfo->spi_subport_rcvhdr_base); } - kinfo->spi_pioindex = (kinfo->spi_piobufbase - dd->ipath_piobufbase) / - dd->ipath_palign; + /* + * All user buffers are 2KB buffers. If we ever support + * giving 4KB buffers to user processes, this will need some + * work. + */ + kinfo->spi_pioindex = (kinfo->spi_piobufbase - + (dd->ipath_piobufbase & 0xffffffff)) / dd->ipath_palign; kinfo->spi_pioalign = dd->ipath_palign; kinfo->spi_qpair = IPATH_KD_QP; @@ -2041,7 +2046,9 @@ static int ipath_close(struct inode *in, struct file *fp) struct ipath_filedata *fd; struct ipath_portdata *pd; struct ipath_devdata *dd; + unsigned long flags; unsigned port; + struct pid *pid; ipath_cdbg(VERBOSE, "close on dev %lx, private data %p\n", (long)in->i_rdev, fp->private_data); @@ -2074,14 +2081,13 @@ static int ipath_close(struct inode *in, struct file *fp) mutex_unlock(&ipath_mutex); goto bail; } + /* early; no interrupt users after this */ + spin_lock_irqsave(&dd->ipath_uctxt_lock, flags); port = pd->port_port; - - if (pd->port_hdrqfull) { - ipath_cdbg(PROC, "%s[%u] had %u rcvhdrqfull errors " - "during run\n", pd->port_comm, pid_nr(pd->port_pid), - pd->port_hdrqfull); - pd->port_hdrqfull = 0; - } + dd->ipath_pd[port] = NULL; + pid = pd->port_pid; + pd->port_pid = NULL; + spin_unlock_irqrestore(&dd->ipath_uctxt_lock, flags); if (pd->port_rcvwait_to || pd->port_piowait_to || pd->port_rcvnowait || pd->port_pionowait) { @@ -2138,13 +2144,11 @@ static int ipath_close(struct inode *in, struct file *fp) unlock_expected_tids(pd); ipath_stats.sps_ports--; ipath_cdbg(PROC, "%s[%u] closed port %u:%u\n", - pd->port_comm, pid_nr(pd->port_pid), + pd->port_comm, pid_nr(pid), dd->ipath_unit, port); } - put_pid(pd->port_pid); - pd->port_pid = NULL; - dd->ipath_pd[pd->port_port] = NULL; /* before releasing mutex */ + put_pid(pid); mutex_unlock(&ipath_mutex); ipath_free_pddata(dd, pd); /* after releasing the mutex */ diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c index 8bb5170b4e416b1b660f333561ffa7c8bb4c7360..53912c327bfea25dc4bab902d788042973441140 100644 --- a/drivers/infiniband/hw/ipath/ipath_fs.c +++ b/drivers/infiniband/hw/ipath/ipath_fs.c @@ -86,7 +86,7 @@ static int create_file(const char *name, mode_t mode, *dentry = NULL; mutex_lock(&parent->d_inode->i_mutex); *dentry = lookup_one_len(name, parent, strlen(name)); - if (!IS_ERR(dentry)) + if (!IS_ERR(*dentry)) error = ipathfs_mknod(parent->d_inode, *dentry, mode, fops, data); else diff --git a/drivers/infiniband/hw/ipath/ipath_iba6120.c b/drivers/infiniband/hw/ipath/ipath_iba6120.c index 421cc2af891f06984095f5797863705c5b795121..fbf8c5379ea844de6ac31b0513c55156a6d8455b 100644 --- a/drivers/infiniband/hw/ipath/ipath_iba6120.c +++ b/drivers/infiniband/hw/ipath/ipath_iba6120.c @@ -721,6 +721,12 @@ static int ipath_pe_bringup_serdes(struct ipath_devdata *dd) INFINIPATH_HWE_SERDESPLLFAILED); } + dd->ibdeltainprog = 1; + dd->ibsymsnap = + ipath_read_creg32(dd, dd->ipath_cregs->cr_ibsymbolerrcnt); + dd->iblnkerrsnap = + ipath_read_creg32(dd, dd->ipath_cregs->cr_iblinkerrrecovcnt); + val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0); config1 = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig1); @@ -810,6 +816,36 @@ static void ipath_pe_quiet_serdes(struct ipath_devdata *dd) { u64 val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0); + if (dd->ibsymdelta || dd->iblnkerrdelta || + dd->ibdeltainprog) { + u64 diagc; + /* enable counter writes */ + diagc = ipath_read_kreg64(dd, dd->ipath_kregs->kr_hwdiagctrl); + ipath_write_kreg(dd, dd->ipath_kregs->kr_hwdiagctrl, + diagc | INFINIPATH_DC_COUNTERWREN); + + if (dd->ibsymdelta || dd->ibdeltainprog) { + val = ipath_read_creg32(dd, + dd->ipath_cregs->cr_ibsymbolerrcnt); + if (dd->ibdeltainprog) + val -= val - dd->ibsymsnap; + val -= dd->ibsymdelta; + ipath_write_creg(dd, + dd->ipath_cregs->cr_ibsymbolerrcnt, val); + } + if (dd->iblnkerrdelta || dd->ibdeltainprog) { + val = ipath_read_creg32(dd, + dd->ipath_cregs->cr_iblinkerrrecovcnt); + if (dd->ibdeltainprog) + val -= val - dd->iblnkerrsnap; + val -= dd->iblnkerrdelta; + ipath_write_creg(dd, + dd->ipath_cregs->cr_iblinkerrrecovcnt, val); + } + + /* and disable counter writes */ + ipath_write_kreg(dd, dd->ipath_kregs->kr_hwdiagctrl, diagc); + } val |= INFINIPATH_SERDC0_TXIDLE; ipath_dbg("Setting TxIdleEn on serdes (config0 = %llx)\n", (unsigned long long) val); @@ -1749,6 +1785,31 @@ static void ipath_pe_config_jint(struct ipath_devdata *dd, u16 a, u16 b) static int ipath_pe_ib_updown(struct ipath_devdata *dd, int ibup, u64 ibcs) { + if (ibup) { + if (dd->ibdeltainprog) { + dd->ibdeltainprog = 0; + dd->ibsymdelta += + ipath_read_creg32(dd, + dd->ipath_cregs->cr_ibsymbolerrcnt) - + dd->ibsymsnap; + dd->iblnkerrdelta += + ipath_read_creg32(dd, + dd->ipath_cregs->cr_iblinkerrrecovcnt) - + dd->iblnkerrsnap; + } + } else { + dd->ipath_lli_counter = 0; + if (!dd->ibdeltainprog) { + dd->ibdeltainprog = 1; + dd->ibsymsnap = + ipath_read_creg32(dd, + dd->ipath_cregs->cr_ibsymbolerrcnt); + dd->iblnkerrsnap = + ipath_read_creg32(dd, + dd->ipath_cregs->cr_iblinkerrrecovcnt); + } + } + ipath_setup_pe_setextled(dd, ipath_ib_linkstate(dd, ibcs), ipath_ib_linktrstate(dd, ibcs)); return 0; diff --git a/drivers/infiniband/hw/ipath/ipath_iba7220.c b/drivers/infiniband/hw/ipath/ipath_iba7220.c index 9839e20119bcfc64f483f68cf2b18d24e1786f77..b2a9d4c155d14fbe44006156ed76a8ea21d54592 100644 --- a/drivers/infiniband/hw/ipath/ipath_iba7220.c +++ b/drivers/infiniband/hw/ipath/ipath_iba7220.c @@ -951,6 +951,12 @@ static int ipath_7220_bringup_serdes(struct ipath_devdata *dd) INFINIPATH_HWE_SERDESPLLFAILED); } + dd->ibdeltainprog = 1; + dd->ibsymsnap = + ipath_read_creg32(dd, dd->ipath_cregs->cr_ibsymbolerrcnt); + dd->iblnkerrsnap = + ipath_read_creg32(dd, dd->ipath_cregs->cr_iblinkerrrecovcnt); + if (!dd->ipath_ibcddrctrl) { /* not on re-init after reset */ dd->ipath_ibcddrctrl = @@ -1084,6 +1090,37 @@ static void ipath_7220_config_jint(struct ipath_devdata *dd, static void ipath_7220_quiet_serdes(struct ipath_devdata *dd) { u64 val; + if (dd->ibsymdelta || dd->iblnkerrdelta || + dd->ibdeltainprog) { + u64 diagc; + /* enable counter writes */ + diagc = ipath_read_kreg64(dd, dd->ipath_kregs->kr_hwdiagctrl); + ipath_write_kreg(dd, dd->ipath_kregs->kr_hwdiagctrl, + diagc | INFINIPATH_DC_COUNTERWREN); + + if (dd->ibsymdelta || dd->ibdeltainprog) { + val = ipath_read_creg32(dd, + dd->ipath_cregs->cr_ibsymbolerrcnt); + if (dd->ibdeltainprog) + val -= val - dd->ibsymsnap; + val -= dd->ibsymdelta; + ipath_write_creg(dd, + dd->ipath_cregs->cr_ibsymbolerrcnt, val); + } + if (dd->iblnkerrdelta || dd->ibdeltainprog) { + val = ipath_read_creg32(dd, + dd->ipath_cregs->cr_iblinkerrrecovcnt); + if (dd->ibdeltainprog) + val -= val - dd->iblnkerrsnap; + val -= dd->iblnkerrdelta; + ipath_write_creg(dd, + dd->ipath_cregs->cr_iblinkerrrecovcnt, val); + } + + /* and disable counter writes */ + ipath_write_kreg(dd, dd->ipath_kregs->kr_hwdiagctrl, diagc); + } + dd->ipath_flags &= ~IPATH_IB_AUTONEG_INPROG; wake_up(&dd->ipath_autoneg_wait); cancel_delayed_work(&dd->ipath_autoneg_work); @@ -2325,7 +2362,7 @@ static void try_auto_neg(struct ipath_devdata *dd) static int ipath_7220_ib_updown(struct ipath_devdata *dd, int ibup, u64 ibcs) { - int ret = 0; + int ret = 0, symadj = 0; u32 ltstate = ipath_ib_linkstate(dd, ibcs); dd->ipath_link_width_active = @@ -2368,6 +2405,13 @@ static int ipath_7220_ib_updown(struct ipath_devdata *dd, int ibup, u64 ibcs) ipath_dbg("DDR negotiation try, %u/%u\n", dd->ipath_autoneg_tries, IPATH_AUTONEG_TRIES); + if (!dd->ibdeltainprog) { + dd->ibdeltainprog = 1; + dd->ibsymsnap = ipath_read_creg32(dd, + dd->ipath_cregs->cr_ibsymbolerrcnt); + dd->iblnkerrsnap = ipath_read_creg32(dd, + dd->ipath_cregs->cr_iblinkerrrecovcnt); + } try_auto_neg(dd); ret = 1; /* no other IB status change processing */ } else if ((dd->ipath_flags & IPATH_IB_AUTONEG_INPROG) @@ -2388,6 +2432,7 @@ static int ipath_7220_ib_updown(struct ipath_devdata *dd, int ibup, u64 ibcs) set_speed_fast(dd, dd->ipath_link_speed_enabled); wake_up(&dd->ipath_autoneg_wait); + symadj = 1; } else if (dd->ipath_flags & IPATH_IB_AUTONEG_FAILED) { /* * clear autoneg failure flag, and do setup @@ -2403,22 +2448,28 @@ static int ipath_7220_ib_updown(struct ipath_devdata *dd, int ibup, u64 ibcs) IBA7220_IBC_IBTA_1_2_MASK; ipath_write_kreg(dd, IPATH_KREG_OFFSET(IBNCModeCtrl), 0); + symadj = 1; } } /* - * if we are in 1X, and are in autoneg width, it - * could be due to an xgxs problem, so if we haven't + * if we are in 1X on rev1 only, and are in autoneg width, + * it could be due to an xgxs problem, so if we haven't * already tried, try twice to get to 4X; if we * tried, and couldn't, report it, since it will * probably not be what is desired. */ - if ((dd->ipath_link_width_enabled & (IB_WIDTH_1X | + if (dd->ipath_minrev == 1 && + (dd->ipath_link_width_enabled & (IB_WIDTH_1X | IB_WIDTH_4X)) == (IB_WIDTH_1X | IB_WIDTH_4X) && dd->ipath_link_width_active == IB_WIDTH_1X && dd->ipath_x1_fix_tries < 3) { - if (++dd->ipath_x1_fix_tries == 3) + if (++dd->ipath_x1_fix_tries == 3) { dev_info(&dd->pcidev->dev, "IB link is in 1X mode\n"); + if (!(dd->ipath_flags & + IPATH_IB_AUTONEG_INPROG)) + symadj = 1; + } else { ipath_cdbg(VERBOSE, "IB 1X in " "auto-width, try %u to be " @@ -2429,7 +2480,8 @@ static int ipath_7220_ib_updown(struct ipath_devdata *dd, int ibup, u64 ibcs) dd->ipath_f_xgxs_reset(dd); ret = 1; /* skip other processing */ } - } + } else if (!(dd->ipath_flags & IPATH_IB_AUTONEG_INPROG)) + symadj = 1; if (!ret) { dd->delay_mult = rate_to_delay @@ -2440,6 +2492,25 @@ static int ipath_7220_ib_updown(struct ipath_devdata *dd, int ibup, u64 ibcs) } } + if (symadj) { + if (dd->ibdeltainprog) { + dd->ibdeltainprog = 0; + dd->ibsymdelta += ipath_read_creg32(dd, + dd->ipath_cregs->cr_ibsymbolerrcnt) - + dd->ibsymsnap; + dd->iblnkerrdelta += ipath_read_creg32(dd, + dd->ipath_cregs->cr_iblinkerrrecovcnt) - + dd->iblnkerrsnap; + } + } else if (!ibup && !dd->ibdeltainprog + && !(dd->ipath_flags & IPATH_IB_AUTONEG_INPROG)) { + dd->ibdeltainprog = 1; + dd->ibsymsnap = ipath_read_creg32(dd, + dd->ipath_cregs->cr_ibsymbolerrcnt); + dd->iblnkerrsnap = ipath_read_creg32(dd, + dd->ipath_cregs->cr_iblinkerrrecovcnt); + } + if (!ret) ipath_setup_7220_setextled(dd, ipath_ib_linkstate(dd, ibcs), ltstate); diff --git a/drivers/infiniband/hw/ipath/ipath_init_chip.c b/drivers/infiniband/hw/ipath/ipath_init_chip.c index 3e5baa43fc822468b232819f62716a2aba1d8c1d..64aeefbd2a5d74c09ad5debc4f0cfe0177ae7263 100644 --- a/drivers/infiniband/hw/ipath/ipath_init_chip.c +++ b/drivers/infiniband/hw/ipath/ipath_init_chip.c @@ -229,6 +229,7 @@ static int init_chip_first(struct ipath_devdata *dd) spin_lock_init(&dd->ipath_kernel_tid_lock); spin_lock_init(&dd->ipath_user_tid_lock); spin_lock_init(&dd->ipath_sendctrl_lock); + spin_lock_init(&dd->ipath_uctxt_lock); spin_lock_init(&dd->ipath_sdma_lock); spin_lock_init(&dd->ipath_gpio_lock); spin_lock_init(&dd->ipath_eep_st_lock); diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h index 0bd8bcb184a18cf38c44cc33ae980210711dd44c..6ba4861dd6ac683e4637ea86a14bac9101af7164 100644 --- a/drivers/infiniband/hw/ipath/ipath_kernel.h +++ b/drivers/infiniband/hw/ipath/ipath_kernel.h @@ -355,6 +355,19 @@ struct ipath_devdata { /* errors masked because they occur too fast */ ipath_err_t ipath_maskederrs; u64 ipath_lastlinkrecov; /* link recoveries at last ACTIVE */ + /* these 5 fields are used to establish deltas for IB Symbol + * errors and linkrecovery errors. They can be reported on + * some chips during link negotiation prior to INIT, and with + * DDR when faking DDR negotiations with non-IBTA switches. + * The chip counters are adjusted at driver unload if there is + * a non-zero delta. + */ + u64 ibdeltainprog; + u64 ibsymdelta; + u64 ibsymsnap; + u64 iblnkerrdelta; + u64 iblnkerrsnap; + /* time in jiffies at which to re-enable maskederrs */ unsigned long ipath_unmasktime; /* count of egrfull errors, combined for all ports */ @@ -464,6 +477,8 @@ struct ipath_devdata { spinlock_t ipath_kernel_tid_lock; spinlock_t ipath_user_tid_lock; spinlock_t ipath_sendctrl_lock; + /* around ipath_pd and (user ports) port_cnt use (intr vs free) */ + spinlock_t ipath_uctxt_lock; /* * IPATH_STATUS_*, diff --git a/drivers/infiniband/hw/ipath/ipath_keys.c b/drivers/infiniband/hw/ipath/ipath_keys.c index 8f32b17a5eed019d304a4b3c4283019274e69170..c0e933fec2187d37c1d40b59f78ad4feea90c367 100644 --- a/drivers/infiniband/hw/ipath/ipath_keys.c +++ b/drivers/infiniband/hw/ipath/ipath_keys.c @@ -132,6 +132,7 @@ int ipath_lkey_ok(struct ipath_qp *qp, struct ipath_sge *isge, * (see ipath_get_dma_mr and ipath_dma.c). */ if (sge->lkey == 0) { + /* always a kernel port, no locking needed */ struct ipath_pd *pd = to_ipd(qp->ibqp.pd); if (pd->user) { @@ -211,6 +212,7 @@ int ipath_rkey_ok(struct ipath_qp *qp, struct ipath_sge_state *ss, * (see ipath_get_dma_mr and ipath_dma.c). */ if (rkey == 0) { + /* always a kernel port, no locking needed */ struct ipath_pd *pd = to_ipd(qp->ibqp.pd); if (pd->user) { diff --git a/drivers/infiniband/hw/ipath/ipath_mad.c b/drivers/infiniband/hw/ipath/ipath_mad.c index be4fc9ada8e7f1e872b740686a74404ae53525fc..17a123197477324bb78f6fc10b42f444b6cabbcb 100644 --- a/drivers/infiniband/hw/ipath/ipath_mad.c +++ b/drivers/infiniband/hw/ipath/ipath_mad.c @@ -348,6 +348,7 @@ static int recv_subn_get_portinfo(struct ib_smp *smp, */ static int get_pkeys(struct ipath_devdata *dd, u16 * pkeys) { + /* always a kernel port, no locking needed */ struct ipath_portdata *pd = dd->ipath_pd[0]; memcpy(pkeys, pd->port_pkeys, sizeof(pd->port_pkeys)); @@ -730,6 +731,7 @@ static int set_pkeys(struct ipath_devdata *dd, u16 *pkeys) int i; int changed = 0; + /* always a kernel port, no locking needed */ pd = dd->ipath_pd[0]; for (i = 0; i < ARRAY_SIZE(pd->port_pkeys); i++) { diff --git a/drivers/infiniband/hw/ipath/ipath_qp.c b/drivers/infiniband/hw/ipath/ipath_qp.c index 4715911101e4fff8363c0e748929302a213d05bc..3a5a89b609c4e99bc761e28193b24bd01600250c 100644 --- a/drivers/infiniband/hw/ipath/ipath_qp.c +++ b/drivers/infiniband/hw/ipath/ipath_qp.c @@ -745,6 +745,7 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd, struct ipath_swqe *swq = NULL; struct ipath_ibdev *dev; size_t sz; + size_t sg_list_sz; struct ib_qp *ret; if (init_attr->create_flags) { @@ -789,19 +790,31 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd, goto bail; } sz = sizeof(*qp); + sg_list_sz = 0; if (init_attr->srq) { struct ipath_srq *srq = to_isrq(init_attr->srq); - sz += sizeof(*qp->r_sg_list) * - srq->rq.max_sge; - } else - sz += sizeof(*qp->r_sg_list) * - init_attr->cap.max_recv_sge; - qp = kmalloc(sz, GFP_KERNEL); + if (srq->rq.max_sge > 1) + sg_list_sz = sizeof(*qp->r_sg_list) * + (srq->rq.max_sge - 1); + } else if (init_attr->cap.max_recv_sge > 1) + sg_list_sz = sizeof(*qp->r_sg_list) * + (init_attr->cap.max_recv_sge - 1); + qp = kmalloc(sz + sg_list_sz, GFP_KERNEL); if (!qp) { ret = ERR_PTR(-ENOMEM); goto bail_swq; } + if (sg_list_sz && (init_attr->qp_type == IB_QPT_UD || + init_attr->qp_type == IB_QPT_SMI || + init_attr->qp_type == IB_QPT_GSI)) { + qp->r_ud_sg_list = kmalloc(sg_list_sz, GFP_KERNEL); + if (!qp->r_ud_sg_list) { + ret = ERR_PTR(-ENOMEM); + goto bail_qp; + } + } else + qp->r_ud_sg_list = NULL; if (init_attr->srq) { sz = 0; qp->r_rq.size = 0; @@ -818,7 +831,7 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd, qp->r_rq.size * sz); if (!qp->r_rq.wq) { ret = ERR_PTR(-ENOMEM); - goto bail_qp; + goto bail_sg_list; } } @@ -848,7 +861,7 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd, if (err) { ret = ERR_PTR(err); vfree(qp->r_rq.wq); - goto bail_qp; + goto bail_sg_list; } qp->ip = NULL; qp->s_tx = NULL; @@ -925,6 +938,8 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd, vfree(qp->r_rq.wq); ipath_free_qp(&dev->qp_table, qp); free_qpn(&dev->qp_table, qp->ibqp.qp_num); +bail_sg_list: + kfree(qp->r_ud_sg_list); bail_qp: kfree(qp); bail_swq: @@ -989,6 +1004,7 @@ int ipath_destroy_qp(struct ib_qp *ibqp) kref_put(&qp->ip->ref, ipath_release_mmap_info); else vfree(qp->r_rq.wq); + kfree(qp->r_ud_sg_list); vfree(qp->s_wq); kfree(qp); return 0; diff --git a/drivers/infiniband/hw/ipath/ipath_rc.c b/drivers/infiniband/hw/ipath/ipath_rc.c index 7b93cda1a4bdcf9681c652fa525058078b48f570..9170710b950ddfafe16fffe2a7b7a157d8d0d97b 100644 --- a/drivers/infiniband/hw/ipath/ipath_rc.c +++ b/drivers/infiniband/hw/ipath/ipath_rc.c @@ -573,9 +573,8 @@ int ipath_make_rc_req(struct ipath_qp *qp) ohdr->u.rc.reth.length = cpu_to_be32(qp->s_len); qp->s_state = OP(RDMA_READ_REQUEST); hwords += sizeof(ohdr->u.rc.reth) / sizeof(u32); - bth2 = qp->s_psn++ & IPATH_PSN_MASK; - if (ipath_cmp24(qp->s_psn, qp->s_next_psn) > 0) - qp->s_next_psn = qp->s_psn; + bth2 = qp->s_psn & IPATH_PSN_MASK; + qp->s_psn = wqe->lpsn + 1; ss = NULL; len = 0; qp->s_cur++; diff --git a/drivers/infiniband/hw/ipath/ipath_sdma.c b/drivers/infiniband/hw/ipath/ipath_sdma.c index 284c9bca517e3bc7f55bd7661c3cb2a0ab7bfa7e..8e255adf5d9bf8b400712fdaf11b3ca8eb5a9d40 100644 --- a/drivers/infiniband/hw/ipath/ipath_sdma.c +++ b/drivers/infiniband/hw/ipath/ipath_sdma.c @@ -698,10 +698,8 @@ int ipath_sdma_verbs_send(struct ipath_devdata *dd, addr = dma_map_single(&dd->pcidev->dev, tx->txreq.map_addr, tx->map_len, DMA_TO_DEVICE); - if (dma_mapping_error(&dd->pcidev->dev, addr)) { - ret = -EIO; - goto unlock; - } + if (dma_mapping_error(&dd->pcidev->dev, addr)) + goto ioerr; dwoffset = tx->map_len >> 2; make_sdma_desc(dd, sdmadesc, (u64) addr, dwoffset, 0); @@ -741,6 +739,8 @@ int ipath_sdma_verbs_send(struct ipath_devdata *dd, dw = (len + 3) >> 2; addr = dma_map_single(&dd->pcidev->dev, sge->vaddr, dw << 2, DMA_TO_DEVICE); + if (dma_mapping_error(&dd->pcidev->dev, addr)) + goto unmap; make_sdma_desc(dd, sdmadesc, (u64) addr, dw, dwoffset); /* SDmaUseLargeBuf has to be set in every descriptor */ if (tx->txreq.flags & IPATH_SDMA_TXREQ_F_USELARGEBUF) @@ -798,7 +798,18 @@ int ipath_sdma_verbs_send(struct ipath_devdata *dd, list_add_tail(&tx->txreq.list, &dd->ipath_sdma_activelist); if (tx->txreq.flags & IPATH_SDMA_TXREQ_F_VL15) vl15_watchdog_enq(dd); - + goto unlock; + +unmap: + while (tail != dd->ipath_sdma_descq_tail) { + if (!tail) + tail = dd->ipath_sdma_descq_cnt - 1; + else + tail--; + unmap_desc(dd, tail); + } +ioerr: + ret = -EIO; unlock: spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags); fail: diff --git a/drivers/infiniband/hw/ipath/ipath_stats.c b/drivers/infiniband/hw/ipath/ipath_stats.c index c8e3d65f0de80fa2d0b2e0556cb66091c126dbf5..f63e143e3292130cceea8426442e6e263b797d53 100644 --- a/drivers/infiniband/hw/ipath/ipath_stats.c +++ b/drivers/infiniband/hw/ipath/ipath_stats.c @@ -112,6 +112,14 @@ u64 ipath_snap_cntr(struct ipath_devdata *dd, ipath_creg creg) dd->ipath_lastrpkts = val; } val64 = dd->ipath_rpkts; + } else if (creg == dd->ipath_cregs->cr_ibsymbolerrcnt) { + if (dd->ibdeltainprog) + val64 -= val64 - dd->ibsymsnap; + val64 -= dd->ibsymdelta; + } else if (creg == dd->ipath_cregs->cr_iblinkerrrecovcnt) { + if (dd->ibdeltainprog) + val64 -= val64 - dd->iblnkerrsnap; + val64 -= dd->iblnkerrdelta; } else val64 = (u64) val; diff --git a/drivers/infiniband/hw/ipath/ipath_ud.c b/drivers/infiniband/hw/ipath/ipath_ud.c index 729446f56aab580d2ffcd7200a124d22ea6e7c3e..91c74cc797ae78a75030a01553ae3b39fb0510b0 100644 --- a/drivers/infiniband/hw/ipath/ipath_ud.c +++ b/drivers/infiniband/hw/ipath/ipath_ud.c @@ -70,8 +70,6 @@ static void ipath_ud_loopback(struct ipath_qp *sqp, struct ipath_swqe *swqe) goto done; } - rsge.sg_list = NULL; - /* * Check that the qkey matches (except for QP0, see 9.6.1.4.1). * Qkeys with the high order bit set mean use the @@ -115,21 +113,6 @@ static void ipath_ud_loopback(struct ipath_qp *sqp, struct ipath_swqe *swqe) rq = &qp->r_rq; } - if (rq->max_sge > 1) { - /* - * XXX We could use GFP_KERNEL if ipath_do_send() - * was always called from the tasklet instead of - * from ipath_post_send(). - */ - rsge.sg_list = kmalloc((rq->max_sge - 1) * - sizeof(struct ipath_sge), - GFP_ATOMIC); - if (!rsge.sg_list) { - dev->n_pkt_drops++; - goto drop; - } - } - /* * Get the next work request entry to find where to put the data. * Note that it is safe to drop the lock after changing rq->tail @@ -147,6 +130,7 @@ static void ipath_ud_loopback(struct ipath_qp *sqp, struct ipath_swqe *swqe) goto drop; } wqe = get_rwqe_ptr(rq, tail); + rsge.sg_list = qp->r_ud_sg_list; if (!ipath_init_sge(qp, wqe, &rlen, &rsge)) { spin_unlock_irqrestore(&rq->lock, flags); dev->n_pkt_drops++; @@ -242,7 +226,6 @@ static void ipath_ud_loopback(struct ipath_qp *sqp, struct ipath_swqe *swqe) ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, swqe->wr.send_flags & IB_SEND_SOLICITED); drop: - kfree(rsge.sg_list); if (atomic_dec_and_test(&qp->refcount)) wake_up(&qp->wait); done:; diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c index eabc4247860b429db0d6603bba4e16c943d0af7c..cdf0e6abd34d53dabeec4548e74168a171462620 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.c +++ b/drivers/infiniband/hw/ipath/ipath_verbs.c @@ -1852,7 +1852,7 @@ unsigned ipath_get_npkeys(struct ipath_devdata *dd) } /** - * ipath_get_pkey - return the indexed PKEY from the port 0 PKEY table + * ipath_get_pkey - return the indexed PKEY from the port PKEY table * @dd: the infinipath device * @index: the PKEY index */ @@ -1860,6 +1860,7 @@ unsigned ipath_get_pkey(struct ipath_devdata *dd, unsigned index) { unsigned ret; + /* always a kernel port, no locking needed */ if (index >= ARRAY_SIZE(dd->ipath_pd[0]->port_pkeys)) ret = 0; else diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.h b/drivers/infiniband/hw/ipath/ipath_verbs.h index 9d12ae8a778eba131e5936e9e37e22a3390bfe10..11e3f613df939e69f6abda658a642fdc75918e06 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.h +++ b/drivers/infiniband/hw/ipath/ipath_verbs.h @@ -431,6 +431,7 @@ struct ipath_qp { u32 s_lsn; /* limit sequence number (credit) */ struct ipath_swqe *s_wq; /* send work queue */ struct ipath_swqe *s_wqe; + struct ipath_sge *r_ud_sg_list; struct ipath_rq r_rq; /* receive work queue */ struct ipath_sge r_sg_list[0]; /* verified SGEs */ }; diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c index 18308494a195bb0d4af1a068ddfd319a3f7b3488..8415ecce5c4c0ba5e646bea4e943f12ddcb94bdb 100644 --- a/drivers/infiniband/hw/mlx4/cq.c +++ b/drivers/infiniband/hw/mlx4/cq.c @@ -222,7 +222,7 @@ struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev, int entries, int vector } err = mlx4_cq_alloc(dev->dev, entries, &cq->buf.mtt, uar, - cq->db.dma, &cq->mcq, 0); + cq->db.dma, &cq->mcq, vector, 0); if (err) goto err_dbmap; @@ -325,15 +325,17 @@ static int mlx4_ib_get_outstanding_cqes(struct mlx4_ib_cq *cq) static void mlx4_ib_cq_resize_copy_cqes(struct mlx4_ib_cq *cq) { - struct mlx4_cqe *cqe; + struct mlx4_cqe *cqe, *new_cqe; int i; i = cq->mcq.cons_index; cqe = get_cqe(cq, i & cq->ibcq.cqe); while ((cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) != MLX4_CQE_OPCODE_RESIZE) { - memcpy(get_cqe_from_buf(&cq->resize_buf->buf, - (i + 1) & cq->resize_buf->cqe), - get_cqe(cq, i & cq->ibcq.cqe), sizeof(struct mlx4_cqe)); + new_cqe = get_cqe_from_buf(&cq->resize_buf->buf, + (i + 1) & cq->resize_buf->cqe); + memcpy(new_cqe, get_cqe(cq, i & cq->ibcq.cqe), sizeof(struct mlx4_cqe)); + new_cqe->owner_sr_opcode = (cqe->owner_sr_opcode & ~MLX4_CQE_OWNER_MASK) | + (((i + 1) & (cq->resize_buf->cqe + 1)) ? MLX4_CQE_OWNER_MASK : 0); cqe = get_cqe(cq, ++i & cq->ibcq.cqe); } ++cq->mcq.cons_index; diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index 2e80f8f47b02ad1fbc0fc1d3fe9ae3bf24313f5a..dcefe1fceb5ca9feb00f64aba343204e96e1bf14 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -578,7 +578,7 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB) ibdev->num_ports++; ibdev->ib_dev.phys_port_cnt = ibdev->num_ports; - ibdev->ib_dev.num_comp_vectors = 1; + ibdev->ib_dev.num_comp_vectors = dev->caps.num_comp_vectors; ibdev->ib_dev.dma_device = &dev->pdev->dev; ibdev->ib_dev.uverbs_abi_ver = MLX4_IB_UVERBS_ABI_VERSION; diff --git a/drivers/infiniband/hw/mthca/mthca_mcg.c b/drivers/infiniband/hw/mthca/mthca_mcg.c index 3f5f948792089a3bf33440794f263bf35dc33d6e..d4c81053e439fe0fa46bae57e42e92738792b9e6 100644 --- a/drivers/infiniband/hw/mthca/mthca_mcg.c +++ b/drivers/infiniband/hw/mthca/mthca_mcg.c @@ -87,17 +87,7 @@ static int find_mgm(struct mthca_dev *dev, } if (0) - mthca_dbg(dev, "Hash for %04x:%04x:%04x:%04x:" - "%04x:%04x:%04x:%04x is %04x\n", - be16_to_cpu(((__be16 *) gid)[0]), - be16_to_cpu(((__be16 *) gid)[1]), - be16_to_cpu(((__be16 *) gid)[2]), - be16_to_cpu(((__be16 *) gid)[3]), - be16_to_cpu(((__be16 *) gid)[4]), - be16_to_cpu(((__be16 *) gid)[5]), - be16_to_cpu(((__be16 *) gid)[6]), - be16_to_cpu(((__be16 *) gid)[7]), - *hash); + mthca_dbg(dev, "Hash for %pI6 is %04x\n", gid, *hash); *index = *hash; *prev = -1; @@ -264,16 +254,7 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) goto out; if (index == -1) { - mthca_err(dev, "MGID %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x " - "not found\n", - be16_to_cpu(((__be16 *) gid->raw)[0]), - be16_to_cpu(((__be16 *) gid->raw)[1]), - be16_to_cpu(((__be16 *) gid->raw)[2]), - be16_to_cpu(((__be16 *) gid->raw)[3]), - be16_to_cpu(((__be16 *) gid->raw)[4]), - be16_to_cpu(((__be16 *) gid->raw)[5]), - be16_to_cpu(((__be16 *) gid->raw)[6]), - be16_to_cpu(((__be16 *) gid->raw)[7])); + mthca_err(dev, "MGID %pI6 not found\n", gid->raw); err = -EINVAL; goto out; } diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c index aa1dc41f04c8fae5a8765bc9eb6853d9c28f4bf0..b9611ade9eab1aa917fcac20f0ef639404773981 100644 --- a/drivers/infiniband/hw/nes/nes.c +++ b/drivers/infiniband/hw/nes/nes.c @@ -142,14 +142,9 @@ static int nes_inetaddr_event(struct notifier_block *notifier, struct nes_device *nesdev; struct net_device *netdev; struct nes_vnic *nesvnic; - unsigned int addr; - unsigned int mask; - - addr = ntohl(ifa->ifa_address); - mask = ntohl(ifa->ifa_mask); - nes_debug(NES_DBG_NETDEV, "nes_inetaddr_event: ip address " NIPQUAD_FMT - ", netmask " NIPQUAD_FMT ".\n", - HIPQUAD(addr), HIPQUAD(mask)); + + nes_debug(NES_DBG_NETDEV, "nes_inetaddr_event: ip address %pI4, netmask %pI4.\n", + &ifa->ifa_address, &ifa->ifa_mask); list_for_each_entry(nesdev, &nes_dev_list, list) { nes_debug(NES_DBG_NETDEV, "Nesdev list entry = 0x%p. (%s)\n", nesdev, nesdev->netdev[0]->name); @@ -360,10 +355,8 @@ struct ib_qp *nes_get_qp(struct ib_device *device, int qpn) */ static void nes_print_macaddr(struct net_device *netdev) { - DECLARE_MAC_BUF(mac); - - nes_debug(NES_DBG_INIT, "%s: %s, IRQ %u\n", - netdev->name, print_mac(mac, netdev->dev_addr), netdev->irq); + nes_debug(NES_DBG_INIT, "%s: %pM, IRQ %u\n", + netdev->name, netdev->dev_addr, netdev->irq); } /** diff --git a/drivers/infiniband/hw/nes/nes.h b/drivers/infiniband/hw/nes/nes.h index 1595dc7bba9dcd6f58d1ff9134f6002ebf9b31b7..13a5bb1a7bcf5895ce829e686eae14dc2ddd4980 100644 --- a/drivers/infiniband/hw/nes/nes.h +++ b/drivers/infiniband/hw/nes/nes.h @@ -137,14 +137,18 @@ #ifdef CONFIG_INFINIBAND_NES_DEBUG #define nes_debug(level, fmt, args...) \ +do { \ if (level & nes_debug_level) \ - printk(KERN_ERR PFX "%s[%u]: " fmt, __func__, __LINE__, ##args) - -#define assert(expr) \ -if (!(expr)) { \ - printk(KERN_ERR PFX "Assertion failed! %s, %s, %s, line %d\n", \ - #expr, __FILE__, __func__, __LINE__); \ -} + printk(KERN_ERR PFX "%s[%u]: " fmt, __func__, __LINE__, ##args); \ +} while (0) + +#define assert(expr) \ +do { \ + if (!(expr)) { \ + printk(KERN_ERR PFX "Assertion failed! %s, %s, %s, line %d\n", \ + #expr, __FILE__, __func__, __LINE__); \ + } \ +} while (0) #define NES_EVENT_TIMEOUT 1200000 #else diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index 2caf9da81ad50d6db5db8bce1c24cb21c2bf46d5..a812db24347756a2e755988e590c416bc12dab60 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c @@ -86,15 +86,14 @@ static int mini_cm_accept(struct nes_cm_core *, struct ietf_mpa_frame *, struct nes_cm_node *); static int mini_cm_reject(struct nes_cm_core *, struct ietf_mpa_frame *, struct nes_cm_node *); -static void mini_cm_recv_pkt(struct nes_cm_core *, struct nes_vnic *, +static int mini_cm_recv_pkt(struct nes_cm_core *, struct nes_vnic *, struct sk_buff *); static int mini_cm_dealloc_core(struct nes_cm_core *); static int mini_cm_get(struct nes_cm_core *); static int mini_cm_set(struct nes_cm_core *, u32, u32); -static struct sk_buff *form_cm_frame(struct sk_buff *, struct nes_cm_node *, +static void form_cm_frame(struct sk_buff *, struct nes_cm_node *, void *, u32, void *, u32, u8); -static struct sk_buff *get_free_pkt(struct nes_cm_node *cm_node); static int add_ref_cm_node(struct nes_cm_node *); static int rem_ref_cm_node(struct nes_cm_core *, struct nes_cm_node *); @@ -251,7 +250,7 @@ static int parse_mpa(struct nes_cm_node *cm_node, u8 *buffer, u32 len) * form_cm_frame - get a free packet and build empty frame Use * node info to build. */ -static struct sk_buff *form_cm_frame(struct sk_buff *skb, +static void form_cm_frame(struct sk_buff *skb, struct nes_cm_node *cm_node, void *options, u32 optionsize, void *data, u32 datasize, u8 flags) { @@ -339,7 +338,6 @@ static struct sk_buff *form_cm_frame(struct sk_buff *skb, skb_shinfo(skb)->nr_frags = 0; cm_packets_created++; - return skb; } @@ -356,7 +354,6 @@ static void print_core(struct nes_cm_core *core) nes_debug(NES_DBG_CM, "State : %u \n", core->state); - nes_debug(NES_DBG_CM, "Tx Free cnt : %u \n", skb_queue_len(&core->tx_free_list)); nes_debug(NES_DBG_CM, "Listen Nodes : %u \n", atomic_read(&core->listen_node_cnt)); nes_debug(NES_DBG_CM, "Active Nodes : %u \n", atomic_read(&core->node_cnt)); @@ -381,8 +378,6 @@ int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb, int ret = 0; u32 was_timer_set; - if (!cm_node) - return -EINVAL; new_send = kzalloc(sizeof(*new_send), GFP_ATOMIC); if (!new_send) return -1; @@ -459,13 +454,23 @@ static void nes_cm_timer_tick(unsigned long pass) int ret = NETDEV_TX_OK; enum nes_cm_node_state last_state; + struct list_head timer_list; + INIT_LIST_HEAD(&timer_list); spin_lock_irqsave(&cm_core->ht_lock, flags); list_for_each_safe(list_node, list_core_temp, - &cm_core->connected_nodes) { + &cm_core->connected_nodes) { cm_node = container_of(list_node, struct nes_cm_node, list); - add_ref_cm_node(cm_node); - spin_unlock_irqrestore(&cm_core->ht_lock, flags); + if (!list_empty(&cm_node->recv_list) || (cm_node->send_entry)) { + add_ref_cm_node(cm_node); + list_add(&cm_node->timer_entry, &timer_list); + } + } + spin_unlock_irqrestore(&cm_core->ht_lock, flags); + + list_for_each_safe(list_node, list_core_temp, &timer_list) { + cm_node = container_of(list_node, struct nes_cm_node, + timer_entry); spin_lock_irqsave(&cm_node->recv_list_lock, flags); list_for_each_safe(list_core, list_node_temp, &cm_node->recv_list) { @@ -519,7 +524,7 @@ static void nes_cm_timer_tick(unsigned long pass) do { send_entry = cm_node->send_entry; if (!send_entry) - continue; + break; if (time_after(send_entry->timetosend, jiffies)) { if (cm_node->state != NES_CM_STATE_TSA) { if ((nexttimeout > @@ -528,18 +533,18 @@ static void nes_cm_timer_tick(unsigned long pass) nexttimeout = send_entry->timetosend; settimer = 1; - continue; + break; } } else { free_retrans_entry(cm_node); - continue; + break; } } if ((cm_node->state == NES_CM_STATE_TSA) || (cm_node->state == NES_CM_STATE_CLOSED)) { free_retrans_entry(cm_node); - continue; + break; } if (!send_entry->retranscount || @@ -557,7 +562,7 @@ static void nes_cm_timer_tick(unsigned long pass) NES_CM_EVENT_ABORTED); spin_lock_irqsave(&cm_node->retrans_list_lock, flags); - continue; + break; } atomic_inc(&send_entry->skb->users); cm_packets_retrans++; @@ -583,7 +588,7 @@ static void nes_cm_timer_tick(unsigned long pass) send_entry->retrycount--; nexttimeout = jiffies + NES_SHORT_TIME; settimer = 1; - continue; + break; } else { cm_packets_sent++; } @@ -615,14 +620,12 @@ static void nes_cm_timer_tick(unsigned long pass) spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags); rem_ref_cm_node(cm_node->cm_core, cm_node); - spin_lock_irqsave(&cm_core->ht_lock, flags); if (ret != NETDEV_TX_OK) { nes_debug(NES_DBG_CM, "rexmit failed for cm_node=%p\n", cm_node); break; } } - spin_unlock_irqrestore(&cm_core->ht_lock, flags); if (settimer) { if (!timer_pending(&cm_core->tcp_timer)) { @@ -683,7 +686,7 @@ static int send_syn(struct nes_cm_node *cm_node, u32 sendack, optionssize += 1; if (!skb) - skb = get_free_pkt(cm_node); + skb = dev_alloc_skb(MAX_CM_BUFFER); if (!skb) { nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n"); return -1; @@ -708,7 +711,7 @@ static int send_reset(struct nes_cm_node *cm_node, struct sk_buff *skb) int flags = SET_RST | SET_ACK; if (!skb) - skb = get_free_pkt(cm_node); + skb = dev_alloc_skb(MAX_CM_BUFFER); if (!skb) { nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n"); return -1; @@ -729,7 +732,7 @@ static int send_ack(struct nes_cm_node *cm_node, struct sk_buff *skb) int ret; if (!skb) - skb = get_free_pkt(cm_node); + skb = dev_alloc_skb(MAX_CM_BUFFER); if (!skb) { nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n"); @@ -752,7 +755,7 @@ static int send_fin(struct nes_cm_node *cm_node, struct sk_buff *skb) /* if we didn't get a frame get one */ if (!skb) - skb = get_free_pkt(cm_node); + skb = dev_alloc_skb(MAX_CM_BUFFER); if (!skb) { nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n"); @@ -766,46 +769,6 @@ static int send_fin(struct nes_cm_node *cm_node, struct sk_buff *skb) } -/** - * get_free_pkt - */ -static struct sk_buff *get_free_pkt(struct nes_cm_node *cm_node) -{ - struct sk_buff *skb, *new_skb; - - /* check to see if we need to repopulate the free tx pkt queue */ - if (skb_queue_len(&cm_node->cm_core->tx_free_list) < NES_CM_FREE_PKT_LO_WATERMARK) { - while (skb_queue_len(&cm_node->cm_core->tx_free_list) < - cm_node->cm_core->free_tx_pkt_max) { - /* replace the frame we took, we won't get it back */ - new_skb = dev_alloc_skb(cm_node->cm_core->mtu); - BUG_ON(!new_skb); - /* add a replacement frame to the free tx list head */ - skb_queue_head(&cm_node->cm_core->tx_free_list, new_skb); - } - } - - skb = skb_dequeue(&cm_node->cm_core->tx_free_list); - - return skb; -} - - -/** - * make_hashkey - generate hash key from node tuple - */ -static inline int make_hashkey(u16 loc_port, nes_addr_t loc_addr, u16 rem_port, - nes_addr_t rem_addr) -{ - u32 hashkey = 0; - - hashkey = loc_addr + rem_addr + loc_port + rem_port; - hashkey = (hashkey % NES_CM_HASHTABLE_SIZE); - - return hashkey; -} - - /** * find_node - find a cm node that matches the reference cm node */ @@ -813,18 +776,14 @@ static struct nes_cm_node *find_node(struct nes_cm_core *cm_core, u16 rem_port, nes_addr_t rem_addr, u16 loc_port, nes_addr_t loc_addr) { unsigned long flags; - u32 hashkey; struct list_head *hte; struct nes_cm_node *cm_node; - /* make a hash index key for this packet */ - hashkey = make_hashkey(loc_port, loc_addr, rem_port, rem_addr); - /* get a handle on the hte */ hte = &cm_core->connected_nodes; - nes_debug(NES_DBG_CM, "Searching for an owner node: " NIPQUAD_FMT ":%x from core %p->%p\n", - HIPQUAD(loc_addr), loc_port, cm_core, hte); + nes_debug(NES_DBG_CM, "Searching for an owner node: %pI4:%x from core %p->%p\n", + &loc_addr, loc_port, cm_core, hte); /* walk list and find cm_node associated with this session ID */ spin_lock_irqsave(&cm_core->ht_lock, flags); @@ -873,8 +832,8 @@ static struct nes_cm_listener *find_listener(struct nes_cm_core *cm_core, } spin_unlock_irqrestore(&cm_core->listen_list_lock, flags); - nes_debug(NES_DBG_CM, "Unable to find listener for " NIPQUAD_FMT ":%x\n", - HIPQUAD(dst_addr), dst_port); + nes_debug(NES_DBG_CM, "Unable to find listener for %pI4:%x\n", + &dst_addr, dst_port); /* no listener */ return NULL; @@ -887,7 +846,6 @@ static struct nes_cm_listener *find_listener(struct nes_cm_core *cm_core, static int add_hte_node(struct nes_cm_core *cm_core, struct nes_cm_node *cm_node) { unsigned long flags; - u32 hashkey; struct list_head *hte; if (!cm_node || !cm_core) @@ -896,11 +854,6 @@ static int add_hte_node(struct nes_cm_core *cm_core, struct nes_cm_node *cm_node nes_debug(NES_DBG_CM, "Adding Node %p to Active Connection HT\n", cm_node); - /* first, make an index into our hash table */ - hashkey = make_hashkey(cm_node->loc_port, cm_node->loc_addr, - cm_node->rem_port, cm_node->rem_addr); - cm_node->hashkey = hashkey; - spin_lock_irqsave(&cm_core->ht_lock, flags); /* get a handle on the hash table element (list head for this slot) */ @@ -925,28 +878,36 @@ static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core, struct list_head *list_pos = NULL; struct list_head *list_temp = NULL; struct nes_cm_node *cm_node = NULL; + struct list_head reset_list; nes_debug(NES_DBG_CM, "attempting listener= %p free_nodes= %d, " "refcnt=%d\n", listener, free_hanging_nodes, atomic_read(&listener->ref_count)); /* free non-accelerated child nodes for this listener */ + INIT_LIST_HEAD(&reset_list); if (free_hanging_nodes) { spin_lock_irqsave(&cm_core->ht_lock, flags); list_for_each_safe(list_pos, list_temp, - &g_cm_core->connected_nodes) { + &g_cm_core->connected_nodes) { cm_node = container_of(list_pos, struct nes_cm_node, list); if ((cm_node->listener == listener) && - (!cm_node->accelerated)) { - cleanup_retrans_entry(cm_node); - spin_unlock_irqrestore(&cm_core->ht_lock, - flags); - send_reset(cm_node, NULL); - spin_lock_irqsave(&cm_core->ht_lock, flags); + (!cm_node->accelerated)) { + add_ref_cm_node(cm_node); + list_add(&cm_node->reset_entry, &reset_list); } } spin_unlock_irqrestore(&cm_core->ht_lock, flags); } + + list_for_each_safe(list_pos, list_temp, &reset_list) { + cm_node = container_of(list_pos, struct nes_cm_node, + reset_entry); + cleanup_retrans_entry(cm_node); + send_reset(cm_node, NULL); + rem_ref_cm_node(cm_node->cm_core, cm_node); + } + spin_lock_irqsave(&cm_core->listen_list_lock, flags); if (!atomic_dec_return(&listener->ref_count)) { list_del(&listener->list); @@ -1027,7 +988,6 @@ static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip) struct flowi fl; struct neighbour *neigh; int rc = -1; - DECLARE_MAC_BUF(mac); memset(&fl, 0, sizeof fl); fl.nl_u.ip4_u.daddr = htonl(dst_ip); @@ -1041,8 +1001,8 @@ static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip) if (neigh) { if (neigh->nud_state & NUD_VALID) { nes_debug(NES_DBG_CM, "Neighbor MAC address for 0x%08X" - " is %s, Gateway is 0x%08X \n", dst_ip, - print_mac(mac, neigh->ha), ntohl(rt->rt_gateway)); + " is %pM, Gateway is 0x%08X \n", dst_ip, + neigh->ha, ntohl(rt->rt_gateway)); nes_manage_arp_cache(nesvnic->netdev, neigh->ha, dst_ip, NES_ARP_ADD); rc = nes_arp_table(nesvnic->nesdev, dst_ip, NULL, @@ -1071,7 +1031,6 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core, int arpindex = 0; struct nes_device *nesdev; struct nes_adapter *nesadapter; - DECLARE_MAC_BUF(mac); /* create an hte and cm_node for this instance */ cm_node = kzalloc(sizeof(*cm_node), GFP_ATOMIC); @@ -1084,10 +1043,9 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core, cm_node->loc_port = cm_info->loc_port; cm_node->rem_port = cm_info->rem_port; cm_node->send_write0 = send_first; - nes_debug(NES_DBG_CM, "Make node addresses : loc = " NIPQUAD_FMT - ":%x, rem = " NIPQUAD_FMT ":%x\n", - HIPQUAD(cm_node->loc_addr), cm_node->loc_port, - HIPQUAD(cm_node->rem_addr), cm_node->rem_port); + nes_debug(NES_DBG_CM, "Make node addresses : loc = %pI4:%x, rem = %pI4:%x\n", + &cm_node->loc_addr, cm_node->loc_port, + &cm_node->rem_addr, cm_node->rem_port); cm_node->listener = listener; cm_node->netdev = nesvnic->netdev; cm_node->cm_id = cm_info->cm_id; @@ -1126,7 +1084,10 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core, cm_node->loopbackpartner = NULL; /* get the mac addr for the remote node */ - arpindex = nes_arp_table(nesdev, cm_node->rem_addr, NULL, NES_ARP_RESOLVE); + if (ipv4_is_loopback(htonl(cm_node->rem_addr))) + arpindex = nes_arp_table(nesdev, ntohl(nesvnic->local_ipaddr), NULL, NES_ARP_RESOLVE); + else + arpindex = nes_arp_table(nesdev, cm_node->rem_addr, NULL, NES_ARP_RESOLVE); if (arpindex < 0) { arpindex = nes_addr_resolve_neigh(nesvnic, cm_info->rem_addr); if (arpindex < 0) { @@ -1137,8 +1098,8 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core, /* copy the mac addr to node context */ memcpy(cm_node->rem_mac, nesadapter->arp_table[arpindex].mac_addr, ETH_ALEN); - nes_debug(NES_DBG_CM, "Remote mac addr from arp table: %s\n", - print_mac(mac, cm_node->rem_mac)); + nes_debug(NES_DBG_CM, "Remote mac addr from arp table: %pM\n", + cm_node->rem_mac); add_hte_node(cm_core, cm_node); atomic_inc(&cm_nodes_created); @@ -1306,7 +1267,6 @@ static void drop_packet(struct sk_buff *skb) static void handle_fin_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb, struct tcphdr *tcph) { - atomic_inc(&cm_resets_recvd); nes_debug(NES_DBG_CM, "Received FIN, cm_node = %p, state = %u. " "refcnt=%d\n", cm_node, cm_node->state, atomic_read(&cm_node->ref_count)); @@ -1344,6 +1304,7 @@ static void handle_rst_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb, { int reset = 0; /* whether to send reset in case of err.. */ + int passive_state; atomic_inc(&cm_resets_recvd); nes_debug(NES_DBG_CM, "Received Reset, cm_node = %p, state = %u." " refcnt=%d\n", cm_node, cm_node->state, @@ -1357,7 +1318,14 @@ static void handle_rst_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb, cm_node->listener, cm_node->state); active_open_err(cm_node, skb, reset); break; - /* For PASSIVE open states, remove the cm_node event */ + case NES_CM_STATE_MPAREQ_RCVD: + passive_state = atomic_add_return(1, &cm_node->passive_state); + if (passive_state == NES_SEND_RESET_EVENT) + create_event(cm_node, NES_CM_EVENT_RESET); + cleanup_retrans_entry(cm_node); + cm_node->state = NES_CM_STATE_CLOSED; + dev_kfree_skb_any(skb); + break; case NES_CM_STATE_ESTABLISHED: case NES_CM_STATE_SYN_RCVD: case NES_CM_STATE_LISTENING: @@ -1365,7 +1333,14 @@ static void handle_rst_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb, passive_open_err(cm_node, skb, reset); break; case NES_CM_STATE_TSA: + active_open_err(cm_node, skb, reset); + break; + case NES_CM_STATE_CLOSED: + cleanup_retrans_entry(cm_node); + drop_packet(skb); + break; default: + drop_packet(skb); break; } } @@ -1394,6 +1369,9 @@ static void handle_rcv_mpa(struct nes_cm_node *cm_node, struct sk_buff *skb, dev_kfree_skb_any(skb); if (type == NES_CM_EVENT_CONNECTED) cm_node->state = NES_CM_STATE_TSA; + else + atomic_set(&cm_node->passive_state, + NES_PASSIVE_STATE_INDICATED); create_event(cm_node, type); } @@ -1474,7 +1452,7 @@ static void handle_syn_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb, int optionsize; optionsize = (tcph->doff << 2) - sizeof(struct tcphdr); - skb_pull(skb, tcph->doff << 2); + skb_trim(skb, 0); inc_sequence = ntohl(tcph->seq); switch (cm_node->state) { @@ -1507,6 +1485,10 @@ static void handle_syn_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb, cm_node->state = NES_CM_STATE_SYN_RCVD; send_syn(cm_node, 1, skb); break; + case NES_CM_STATE_CLOSED: + cleanup_retrans_entry(cm_node); + send_reset(cm_node, skb); + break; case NES_CM_STATE_TSA: case NES_CM_STATE_ESTABLISHED: case NES_CM_STATE_FIN_WAIT1: @@ -1515,7 +1497,6 @@ static void handle_syn_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb, case NES_CM_STATE_LAST_ACK: case NES_CM_STATE_CLOSING: case NES_CM_STATE_UNKNOWN: - case NES_CM_STATE_CLOSED: default: drop_packet(skb); break; @@ -1531,7 +1512,7 @@ static void handle_synack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb, int optionsize; optionsize = (tcph->doff << 2) - sizeof(struct tcphdr); - skb_pull(skb, tcph->doff << 2); + skb_trim(skb, 0); inc_sequence = ntohl(tcph->seq); switch (cm_node->state) { case NES_CM_STATE_SYN_SENT: @@ -1555,6 +1536,12 @@ static void handle_synack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb, /* passive open, so should not be here */ passive_open_err(cm_node, skb, 1); break; + case NES_CM_STATE_LISTENING: + case NES_CM_STATE_CLOSED: + cm_node->tcp_cntxt.loc_seq_num = ntohl(tcph->ack_seq); + cleanup_retrans_entry(cm_node); + send_reset(cm_node, skb); + break; case NES_CM_STATE_ESTABLISHED: case NES_CM_STATE_FIN_WAIT1: case NES_CM_STATE_FIN_WAIT2: @@ -1562,7 +1549,6 @@ static void handle_synack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb, case NES_CM_STATE_TSA: case NES_CM_STATE_CLOSING: case NES_CM_STATE_UNKNOWN: - case NES_CM_STATE_CLOSED: case NES_CM_STATE_MPAREQ_SENT: default: drop_packet(skb); @@ -1577,6 +1563,13 @@ static void handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb, u32 inc_sequence; u32 rem_seq_ack; u32 rem_seq; + int ret; + int optionsize; + u32 temp_seq = cm_node->tcp_cntxt.loc_seq_num; + + optionsize = (tcph->doff << 2) - sizeof(struct tcphdr); + cm_node->tcp_cntxt.loc_seq_num = ntohl(tcph->ack_seq); + if (check_seq(cm_node, tcph, skb)) return; @@ -1589,7 +1582,18 @@ static void handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb, switch (cm_node->state) { case NES_CM_STATE_SYN_RCVD: /* Passive OPEN */ + ret = handle_tcp_options(cm_node, tcph, skb, optionsize, 1); + if (ret) + break; cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq); + cm_node->tcp_cntxt.loc_seq_num = temp_seq; + if (cm_node->tcp_cntxt.rem_ack_num != + cm_node->tcp_cntxt.loc_seq_num) { + nes_debug(NES_DBG_CM, "rem_ack_num != loc_seq_num\n"); + cleanup_retrans_entry(cm_node); + send_reset(cm_node, skb); + return; + } cm_node->state = NES_CM_STATE_ESTABLISHED; if (datasize) { cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize; @@ -1621,11 +1625,15 @@ static void handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb, dev_kfree_skb_any(skb); } break; + case NES_CM_STATE_LISTENING: + case NES_CM_STATE_CLOSED: + cleanup_retrans_entry(cm_node); + send_reset(cm_node, skb); + break; case NES_CM_STATE_FIN_WAIT1: case NES_CM_STATE_SYN_SENT: case NES_CM_STATE_FIN_WAIT2: case NES_CM_STATE_TSA: - case NES_CM_STATE_CLOSED: case NES_CM_STATE_MPAREQ_RCVD: case NES_CM_STATE_LAST_ACK: case NES_CM_STATE_CLOSING: @@ -1648,9 +1656,9 @@ static int handle_tcp_options(struct nes_cm_node *cm_node, struct tcphdr *tcph, nes_debug(NES_DBG_CM, "%s: Node %p, Sending RESET\n", __func__, cm_node); if (passive) - passive_open_err(cm_node, skb, 0); + passive_open_err(cm_node, skb, 1); else - active_open_err(cm_node, skb, 0); + active_open_err(cm_node, skb, 1); return 1; } } @@ -1970,6 +1978,7 @@ static int mini_cm_reject(struct nes_cm_core *cm_core, struct ietf_mpa_frame *mpa_frame, struct nes_cm_node *cm_node) { int ret = 0; + int passive_state; nes_debug(NES_DBG_CM, "%s cm_node=%p type=%d state=%d\n", __func__, cm_node, cm_node->tcp_cntxt.client, cm_node->state); @@ -1977,9 +1986,13 @@ static int mini_cm_reject(struct nes_cm_core *cm_core, if (cm_node->tcp_cntxt.client) return ret; cleanup_retrans_entry(cm_node); - cm_node->state = NES_CM_STATE_CLOSED; - ret = send_reset(cm_node, NULL); + passive_state = atomic_add_return(1, &cm_node->passive_state); + cm_node->state = NES_CM_STATE_CLOSED; + if (passive_state == NES_SEND_RESET_EVENT) + rem_ref_cm_node(cm_core, cm_node); + else + ret = send_reset(cm_node, NULL); return ret; } @@ -2037,7 +2050,7 @@ static int mini_cm_close(struct nes_cm_core *cm_core, struct nes_cm_node *cm_nod * recv_pkt - recv an ETHERNET packet, and process it through CM * node state machine */ -static void mini_cm_recv_pkt(struct nes_cm_core *cm_core, +static int mini_cm_recv_pkt(struct nes_cm_core *cm_core, struct nes_vnic *nesvnic, struct sk_buff *skb) { struct nes_cm_node *cm_node = NULL; @@ -2045,33 +2058,24 @@ static void mini_cm_recv_pkt(struct nes_cm_core *cm_core, struct iphdr *iph; struct tcphdr *tcph; struct nes_cm_info nfo; + int skb_handled = 1; if (!skb) - return; + return 0; if (skb->len < sizeof(struct iphdr) + sizeof(struct tcphdr)) { - dev_kfree_skb_any(skb); - return; + return 0; } iph = (struct iphdr *)skb->data; tcph = (struct tcphdr *)(skb->data + sizeof(struct iphdr)); - skb_reset_network_header(skb); - skb_set_transport_header(skb, sizeof(*tcph)); - if (!tcph) { - dev_kfree_skb_any(skb); - return; - } - skb->len = ntohs(iph->tot_len); nfo.loc_addr = ntohl(iph->daddr); nfo.loc_port = ntohs(tcph->dest); nfo.rem_addr = ntohl(iph->saddr); nfo.rem_port = ntohs(tcph->source); - nes_debug(NES_DBG_CM, "Received packet: dest=" NIPQUAD_FMT - ":0x%04X src=" NIPQUAD_FMT ":0x%04X\n", - NIPQUAD(iph->daddr), tcph->dest, - NIPQUAD(iph->saddr), tcph->source); + nes_debug(NES_DBG_CM, "Received packet: dest=%pI4:0x%04X src=%pI4:0x%04X\n", + &iph->daddr, tcph->dest, &iph->saddr, tcph->source); do { cm_node = find_node(cm_core, @@ -2082,23 +2086,21 @@ static void mini_cm_recv_pkt(struct nes_cm_core *cm_core, /* Only type of packet accepted are for */ /* the PASSIVE open (syn only) */ if ((!tcph->syn) || (tcph->ack)) { - cm_packets_dropped++; + skb_handled = 0; break; } listener = find_listener(cm_core, nfo.loc_addr, nfo.loc_port, NES_CM_LISTENER_ACTIVE_STATE); - if (listener) { - nfo.cm_id = listener->cm_id; - nfo.conn_type = listener->conn_type; - } else { - nes_debug(NES_DBG_CM, "Unable to find listener " - "for the pkt\n"); - cm_packets_dropped++; - dev_kfree_skb_any(skb); + if (!listener) { + nfo.cm_id = NULL; + nfo.conn_type = 0; + nes_debug(NES_DBG_CM, "Unable to find listener for the pkt\n"); + skb_handled = 0; break; } - + nfo.cm_id = listener->cm_id; + nfo.conn_type = listener->conn_type; cm_node = make_cm_node(cm_core, nesvnic, &nfo, listener); if (!cm_node) { @@ -2124,9 +2126,13 @@ static void mini_cm_recv_pkt(struct nes_cm_core *cm_core, dev_kfree_skb_any(skb); break; } + skb_reset_network_header(skb); + skb_set_transport_header(skb, sizeof(*tcph)); + skb->len = ntohs(iph->tot_len); process_packet(cm_node, skb, cm_core); rem_ref_cm_node(cm_core, cm_node); } while (0); + return skb_handled; } @@ -2135,10 +2141,7 @@ static void mini_cm_recv_pkt(struct nes_cm_core *cm_core, */ static struct nes_cm_core *nes_cm_alloc_core(void) { - int i; - struct nes_cm_core *cm_core; - struct sk_buff *skb = NULL; /* setup the CM core */ /* alloc top level core control structure */ @@ -2156,19 +2159,6 @@ static struct nes_cm_core *nes_cm_alloc_core(void) atomic_set(&cm_core->events_posted, 0); - /* init the packet lists */ - skb_queue_head_init(&cm_core->tx_free_list); - - for (i = 0; i < NES_CM_DEFAULT_FRAME_CNT; i++) { - skb = dev_alloc_skb(cm_core->mtu); - if (!skb) { - kfree(cm_core); - return NULL; - } - /* add 'raw' skb to free frame list */ - skb_queue_head(&cm_core->tx_free_list, skb); - } - cm_core->api = &nes_cm_api; spin_lock_init(&cm_core->ht_lock); @@ -2397,7 +2387,6 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp) atomic_inc(&cm_disconnects); cm_event.event = IW_CM_EVENT_DISCONNECT; if (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET) { - issued_disconnect_reset = 1; cm_event.status = IW_CM_EVENT_STATUS_RESET; nes_debug(NES_DBG_CM, "Generating a CM " "Disconnect Event (status reset) for " @@ -2547,6 +2536,7 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) struct nes_v4_quad nes_quad; u32 crc_value; int ret; + int passive_state; ibqp = nes_get_qp(cm_id->device, conn_param->qpn); if (!ibqp) @@ -2714,8 +2704,6 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) conn_param->private_data_len + sizeof(struct ietf_mpa_frame)); - attr.qp_state = IB_QPS_RTS; - nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL); /* notify OF layer that accept event was successfull */ cm_id->add_ref(cm_id); @@ -2728,6 +2716,8 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) cm_event.private_data = NULL; cm_event.private_data_len = 0; ret = cm_id->event_handler(cm_id, &cm_event); + attr.qp_state = IB_QPS_RTS; + nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL); if (cm_node->loopbackpartner) { cm_node->loopbackpartner->mpa_frame_size = nesqp->private_data_len; @@ -2740,6 +2730,9 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) printk(KERN_ERR "%s[%u] OFA CM event_handler returned, " "ret=%d\n", __func__, __LINE__, ret); + passive_state = atomic_add_return(1, &cm_node->passive_state); + if (passive_state == NES_SEND_RESET_EVENT) + create_event(cm_node, NES_CM_EVENT_RESET); return 0; } @@ -2943,15 +2936,16 @@ int nes_destroy_listen(struct iw_cm_id *cm_id) */ int nes_cm_recv(struct sk_buff *skb, struct net_device *netdevice) { + int rc = 0; cm_packets_received++; if ((g_cm_core) && (g_cm_core->api)) { - g_cm_core->api->recv_pkt(g_cm_core, netdev_priv(netdevice), skb); + rc = g_cm_core->api->recv_pkt(g_cm_core, netdev_priv(netdevice), skb); } else { nes_debug(NES_DBG_CM, "Unable to process packet for CM," " cm is not setup properly.\n"); } - return 0; + return rc; } @@ -3222,6 +3216,18 @@ static void cm_event_reset(struct nes_cm_event *event) cm_event.private_data_len = 0; ret = cm_id->event_handler(cm_id, &cm_event); + cm_id->add_ref(cm_id); + atomic_inc(&cm_closes); + cm_event.event = IW_CM_EVENT_CLOSE; + cm_event.status = IW_CM_EVENT_STATUS_OK; + cm_event.provider_data = cm_id->provider_data; + cm_event.local_addr = cm_id->local_addr; + cm_event.remote_addr = cm_id->remote_addr; + cm_event.private_data = NULL; + cm_event.private_data_len = 0; + nes_debug(NES_DBG_CM, "NODE %p Generating CLOSE\n", event->cm_node); + ret = cm_id->event_handler(cm_id, &cm_event); + nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret); diff --git a/drivers/infiniband/hw/nes/nes_cm.h b/drivers/infiniband/hw/nes/nes_cm.h index 367b3d29014074252424c798f110821b5ce0c7c4..fafa35042ebdcc46d56446acfb40b395aad9c81b 100644 --- a/drivers/infiniband/hw/nes/nes_cm.h +++ b/drivers/infiniband/hw/nes/nes_cm.h @@ -76,6 +76,10 @@ enum nes_timer_type { NES_TIMER_TYPE_CLOSE, }; +#define NES_PASSIVE_STATE_INDICATED 0 +#define NES_DO_NOT_SEND_RESET_EVENT 1 +#define NES_SEND_RESET_EVENT 2 + #define MAX_NES_IFS 4 #define SET_ACK 1 @@ -161,6 +165,8 @@ struct nes_timer_entry { #define NES_CM_DEF_SEQ2 0x18ed5740 #define NES_CM_DEF_LOCAL_ID2 0xb807 +#define MAX_CM_BUFFER 512 + typedef u32 nes_addr_t; @@ -254,8 +260,6 @@ struct nes_cm_listener { /* per connection node and node state information */ struct nes_cm_node { - u32 hashkey; - nes_addr_t loc_addr, rem_addr; u16 loc_port, rem_port; @@ -292,7 +296,10 @@ struct nes_cm_node { int apbvt_set; int accept_pend; int freed; + struct list_head timer_entry; + struct list_head reset_entry; struct nes_qp *nesqp; + atomic_t passive_state; }; /* structure for client or CM to fill when making CM api calls. */ @@ -350,7 +357,6 @@ struct nes_cm_core { u32 mtu; u32 free_tx_pkt_max; u32 rx_pkt_posted; - struct sk_buff_head tx_free_list; atomic_t ht_node_cnt; struct list_head connected_nodes; /* struct list_head hashtable[NES_CM_HASHTABLE_SIZE]; */ @@ -390,7 +396,7 @@ struct nes_cm_ops { struct nes_cm_node *); int (*reject)(struct nes_cm_core *, struct ietf_mpa_frame *, struct nes_cm_node *); - void (*recv_pkt)(struct nes_cm_core *, struct nes_vnic *, + int (*recv_pkt)(struct nes_cm_core *, struct nes_vnic *, struct sk_buff *); int (*destroy_cm_core)(struct nes_cm_core *); int (*get)(struct nes_cm_core *); diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c index 7c49cc882d75c580c0c31e20b987cf177d04fc9c..5d139db1b771e745e9c248df0536c3bbdbc5d01e 100644 --- a/drivers/infiniband/hw/nes/nes_hw.c +++ b/drivers/infiniband/hw/nes/nes_hw.c @@ -2541,7 +2541,7 @@ static void nes_nic_napi_ce_handler(struct nes_device *nesdev, struct nes_hw_nic { struct nes_vnic *nesvnic = container_of(cq, struct nes_vnic, nic_cq); - netif_rx_schedule(nesdev->netdev[nesvnic->netdev_index], &nesvnic->napi); + netif_rx_schedule(&nesvnic->napi); } @@ -2700,27 +2700,33 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq) pkt_type, (pkt_type & NES_PKT_TYPE_APBVT_MASK)); */ if ((pkt_type & NES_PKT_TYPE_APBVT_MASK) == NES_PKT_TYPE_APBVT_BITS) { - nes_cm_recv(rx_skb, nesvnic->netdev); + if (nes_cm_recv(rx_skb, nesvnic->netdev)) + rx_skb = NULL; + } + if (rx_skb == NULL) + goto skip_rx_indicate0; + + + if ((cqe_misc & NES_NIC_CQE_TAG_VALID) && + (nesvnic->vlan_grp != NULL)) { + vlan_tag = (u16)(le32_to_cpu( + cq->cq_vbase[head].cqe_words[NES_NIC_CQE_TAG_PKT_TYPE_IDX]) + >> 16); + nes_debug(NES_DBG_CQ, "%s: Reporting stripped VLAN packet. Tag = 0x%04X\n", + nesvnic->netdev->name, vlan_tag); + if (nes_use_lro) + lro_vlan_hwaccel_receive_skb(&nesvnic->lro_mgr, rx_skb, + nesvnic->vlan_grp, vlan_tag, NULL); + else + nes_vlan_rx(rx_skb, nesvnic->vlan_grp, vlan_tag); } else { - if ((cqe_misc & NES_NIC_CQE_TAG_VALID) && (nesvnic->vlan_grp != NULL)) { - vlan_tag = (u16)(le32_to_cpu( - cq->cq_vbase[head].cqe_words[NES_NIC_CQE_TAG_PKT_TYPE_IDX]) - >> 16); - nes_debug(NES_DBG_CQ, "%s: Reporting stripped VLAN packet. Tag = 0x%04X\n", - nesvnic->netdev->name, vlan_tag); - if (nes_use_lro) - lro_vlan_hwaccel_receive_skb(&nesvnic->lro_mgr, rx_skb, - nesvnic->vlan_grp, vlan_tag, NULL); - else - nes_vlan_rx(rx_skb, nesvnic->vlan_grp, vlan_tag); - } else { - if (nes_use_lro) - lro_receive_skb(&nesvnic->lro_mgr, rx_skb, NULL); - else - nes_netif_rx(rx_skb); - } + if (nes_use_lro) + lro_receive_skb(&nesvnic->lro_mgr, rx_skb, NULL); + else + nes_netif_rx(rx_skb); } +skip_rx_indicate0: nesvnic->netdev->last_rx = jiffies; /* nesvnic->netstats.rx_packets++; */ /* nesvnic->netstats.rx_bytes += rx_pkt_size; */ diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c index 730358637bb62603111e936f02ac1ad5c336e780..57a47cf7e513ca60d86a1a108454f36248bcd16a 100644 --- a/drivers/infiniband/hw/nes/nes_nic.c +++ b/drivers/infiniband/hw/nes/nes_nic.c @@ -99,7 +99,6 @@ static int nics_per_function = 1; static int nes_netdev_poll(struct napi_struct *napi, int budget) { struct nes_vnic *nesvnic = container_of(napi, struct nes_vnic, napi); - struct net_device *netdev = nesvnic->netdev; struct nes_device *nesdev = nesvnic->nesdev; struct nes_hw_nic_cq *nescq = &nesvnic->nic_cq; @@ -112,7 +111,7 @@ static int nes_netdev_poll(struct napi_struct *napi, int budget) nes_nic_ce_handler(nesdev, nescq); if (nescq->cqes_pending == 0) { - netif_rx_complete(netdev, napi); + netif_rx_complete(napi); /* clear out completed cqes and arm */ nes_write32(nesdev->regs+NES_CQE_ALLOC, NES_CQE_ALLOC_NOTIFY_NEXT | nescq->cq_number | (nescq->cqe_allocs_pending << 16)); @@ -797,14 +796,13 @@ static int nes_netdev_set_mac_address(struct net_device *netdev, void *p) int i; u32 macaddr_low; u16 macaddr_high; - DECLARE_MAC_BUF(mac); if (!is_valid_ether_addr(mac_addr->sa_data)) return -EADDRNOTAVAIL; memcpy(netdev->dev_addr, mac_addr->sa_data, netdev->addr_len); - printk(PFX "%s: Address length = %d, Address = %s\n", - __func__, netdev->addr_len, print_mac(mac, mac_addr->sa_data)); + printk(PFX "%s: Address length = %d, Address = %pM\n", + __func__, netdev->addr_len, mac_addr->sa_data); macaddr_high = ((u16)netdev->dev_addr[0]) << 8; macaddr_high += (u16)netdev->dev_addr[1]; macaddr_low = ((u32)netdev->dev_addr[2]) << 24; @@ -909,9 +907,8 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev) if (mc_index >= max_pft_entries_avaiable) break; if (multicast_addr) { - DECLARE_MAC_BUF(mac); - nes_debug(NES_DBG_NIC_RX, "Assigning MC Address %s to register 0x%04X nic_idx=%d\n", - print_mac(mac, multicast_addr->dmi_addr), + nes_debug(NES_DBG_NIC_RX, "Assigning MC Address %pM to register 0x%04X nic_idx=%d\n", + multicast_addr->dmi_addr, perfect_filter_register_address+(mc_index * 8), mc_nic_index); macaddr_high = ((u16)multicast_addr->dmi_addr[0]) << 8; diff --git a/drivers/infiniband/hw/nes/nes_utils.c b/drivers/infiniband/hw/nes/nes_utils.c index fb8cbd71a2ef86b17b98539a471e0c4d7bf7b409..aa9b7348c7285a026a7e8831b1ad97f2ed7a00eb 100644 --- a/drivers/infiniband/hw/nes/nes_utils.c +++ b/drivers/infiniband/hw/nes/nes_utils.c @@ -540,11 +540,14 @@ struct nes_cqp_request *nes_get_cqp_request(struct nes_device *nesdev) if (!list_empty(&nesdev->cqp_avail_reqs)) { spin_lock_irqsave(&nesdev->cqp.lock, flags); - cqp_request = list_entry(nesdev->cqp_avail_reqs.next, + if (!list_empty(&nesdev->cqp_avail_reqs)) { + cqp_request = list_entry(nesdev->cqp_avail_reqs.next, struct nes_cqp_request, list); - list_del_init(&cqp_request->list); + list_del_init(&cqp_request->list); + } spin_unlock_irqrestore(&nesdev->cqp.lock, flags); - } else { + } + if (cqp_request == NULL) { cqp_request = kzalloc(sizeof(struct nes_cqp_request), GFP_KERNEL); if (cqp_request) { cqp_request->dynamic = 1; @@ -679,9 +682,8 @@ int nes_arp_table(struct nes_device *nesdev, u32 ip_addr, u8 *mac_addr, u32 acti /* DELETE or RESOLVE */ if (arp_index == nesadapter->arp_table_size) { - nes_debug(NES_DBG_NETDEV, "MAC for " NIPQUAD_FMT " not in ARP table - cannot %s\n", - HIPQUAD(ip_addr), - action == NES_ARP_RESOLVE ? "resolve" : "delete"); + nes_debug(NES_DBG_NETDEV, "MAC for %pI4 not in ARP table - cannot %s\n", + &ip_addr, action == NES_ARP_RESOLVE ? "resolve" : "delete"); return -1; } diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index d36c9a0bf1bb823619a04a8ce53902281b437cf7..4fdb72454f94f493045e56ce4a289fe01ad45266 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -1695,13 +1695,8 @@ static struct ib_cq *nes_create_cq(struct ib_device *ibdev, int entries, /* use 4k pbl */ nes_debug(NES_DBG_CQ, "pbl_entries=%u, use a 4k PBL\n", pbl_entries); if (nesadapter->free_4kpbl == 0) { - if (cqp_request->dynamic) { - spin_unlock_irqrestore(&nesadapter->pbl_lock, flags); - kfree(cqp_request); - } else { - list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs); - spin_unlock_irqrestore(&nesadapter->pbl_lock, flags); - } + spin_unlock_irqrestore(&nesadapter->pbl_lock, flags); + nes_free_cqp_request(nesdev, cqp_request); if (!context) pci_free_consistent(nesdev->pcidev, nescq->cq_mem_size, mem, nescq->hw_cq.cq_pbase); @@ -1717,13 +1712,8 @@ static struct ib_cq *nes_create_cq(struct ib_device *ibdev, int entries, /* use 256 byte pbl */ nes_debug(NES_DBG_CQ, "pbl_entries=%u, use a 256 byte PBL\n", pbl_entries); if (nesadapter->free_256pbl == 0) { - if (cqp_request->dynamic) { - spin_unlock_irqrestore(&nesadapter->pbl_lock, flags); - kfree(cqp_request); - } else { - list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs); - spin_unlock_irqrestore(&nesadapter->pbl_lock, flags); - } + spin_unlock_irqrestore(&nesadapter->pbl_lock, flags); + nes_free_cqp_request(nesdev, cqp_request); if (!context) pci_free_consistent(nesdev->pcidev, nescq->cq_mem_size, mem, nescq->hw_cq.cq_pbase); @@ -1928,13 +1918,8 @@ static int nes_reg_mr(struct nes_device *nesdev, struct nes_pd *nespd, /* Two level PBL */ if ((pbl_count+1) > nesadapter->free_4kpbl) { nes_debug(NES_DBG_MR, "Out of 4KB Pbls for two level request.\n"); - if (cqp_request->dynamic) { - spin_unlock_irqrestore(&nesadapter->pbl_lock, flags); - kfree(cqp_request); - } else { - list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs); - spin_unlock_irqrestore(&nesadapter->pbl_lock, flags); - } + spin_unlock_irqrestore(&nesadapter->pbl_lock, flags); + nes_free_cqp_request(nesdev, cqp_request); return -ENOMEM; } else { nesadapter->free_4kpbl -= pbl_count+1; @@ -1942,13 +1927,8 @@ static int nes_reg_mr(struct nes_device *nesdev, struct nes_pd *nespd, } else if (residual_page_count > 32) { if (pbl_count > nesadapter->free_4kpbl) { nes_debug(NES_DBG_MR, "Out of 4KB Pbls.\n"); - if (cqp_request->dynamic) { - spin_unlock_irqrestore(&nesadapter->pbl_lock, flags); - kfree(cqp_request); - } else { - list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs); - spin_unlock_irqrestore(&nesadapter->pbl_lock, flags); - } + spin_unlock_irqrestore(&nesadapter->pbl_lock, flags); + nes_free_cqp_request(nesdev, cqp_request); return -ENOMEM; } else { nesadapter->free_4kpbl -= pbl_count; @@ -1956,13 +1936,8 @@ static int nes_reg_mr(struct nes_device *nesdev, struct nes_pd *nespd, } else { if (pbl_count > nesadapter->free_256pbl) { nes_debug(NES_DBG_MR, "Out of 256B Pbls.\n"); - if (cqp_request->dynamic) { - spin_unlock_irqrestore(&nesadapter->pbl_lock, flags); - kfree(cqp_request); - } else { - list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs); - spin_unlock_irqrestore(&nesadapter->pbl_lock, flags); - } + spin_unlock_irqrestore(&nesadapter->pbl_lock, flags); + nes_free_cqp_request(nesdev, cqp_request); return -ENOMEM; } else { nesadapter->free_256pbl -= pbl_count; diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index e0c7dfabf2b4e6d6f13abab65ffcc4d11dffefcb..753a983a5fdc8c85d6467e430f27bef4afc716b1 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -732,29 +732,6 @@ extern int ipoib_debug_level; do { (void) (priv); } while (0) #endif /* CONFIG_INFINIBAND_IPOIB_DEBUG_DATA */ - -#define IPOIB_GID_FMT "%2.2x%2.2x:%2.2x%2.2x:%2.2x%2.2x:%2.2x%2.2x:" \ - "%2.2x%2.2x:%2.2x%2.2x:%2.2x%2.2x:%2.2x%2.2x" - -#define IPOIB_GID_RAW_ARG(gid) ((u8 *)(gid))[0], \ - ((u8 *)(gid))[1], \ - ((u8 *)(gid))[2], \ - ((u8 *)(gid))[3], \ - ((u8 *)(gid))[4], \ - ((u8 *)(gid))[5], \ - ((u8 *)(gid))[6], \ - ((u8 *)(gid))[7], \ - ((u8 *)(gid))[8], \ - ((u8 *)(gid))[9], \ - ((u8 *)(gid))[10],\ - ((u8 *)(gid))[11],\ - ((u8 *)(gid))[12],\ - ((u8 *)(gid))[13],\ - ((u8 *)(gid))[14],\ - ((u8 *)(gid))[15] - -#define IPOIB_GID_ARG(gid) IPOIB_GID_RAW_ARG((gid).raw) - #define IPOIB_QPN(ha) (be32_to_cpup((__be32 *) ha) & 0xffffff) #endif /* _IPOIB_H */ diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 7b14c2c395008fc2acc3b38505c81cbeb3111929..47d588ba2a7f73e830c249b7546c441c93e26fcf 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -1128,8 +1128,8 @@ static int ipoib_cm_tx_init(struct ipoib_cm_tx *p, u32 qpn, goto err_send_cm; } - ipoib_dbg(priv, "Request connection 0x%x for gid " IPOIB_GID_FMT " qpn 0x%x\n", - p->qp->qp_num, IPOIB_GID_ARG(pathrec->dgid), qpn); + ipoib_dbg(priv, "Request connection 0x%x for gid %pI6 qpn 0x%x\n", + p->qp->qp_num, pathrec->dgid.raw, qpn); return 0; @@ -1276,8 +1276,8 @@ void ipoib_cm_destroy_tx(struct ipoib_cm_tx *tx) if (test_and_clear_bit(IPOIB_FLAG_INITIALIZED, &tx->flags)) { list_move(&tx->list, &priv->cm.reap_list); queue_work(ipoib_workqueue, &priv->cm.reap_task); - ipoib_dbg(priv, "Reap connection for gid " IPOIB_GID_FMT "\n", - IPOIB_GID_ARG(tx->neigh->dgid)); + ipoib_dbg(priv, "Reap connection for gid %pI6\n", + tx->neigh->dgid.raw); tx->neigh = NULL; } } diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 28eb6f03c588987c1c417377205e53b34b2f5058..a1925810be3cb23f8e768b030c60d68944267b5f 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -446,11 +446,11 @@ int ipoib_poll(struct napi_struct *napi, int budget) if (dev->features & NETIF_F_LRO) lro_flush_all(&priv->lro.lro_mgr); - netif_rx_complete(dev, napi); + netif_rx_complete(napi); if (unlikely(ib_req_notify_cq(priv->recv_cq, IB_CQ_NEXT_COMP | IB_CQ_REPORT_MISSED_EVENTS)) && - netif_rx_reschedule(dev, napi)) + netif_rx_reschedule(napi)) goto poll_more; } @@ -462,7 +462,7 @@ void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr) struct net_device *dev = dev_ptr; struct ipoib_dev_priv *priv = netdev_priv(dev); - netif_rx_schedule(dev, &priv->napi); + netif_rx_schedule(&priv->napi); } static void drain_tx_cq(struct net_device *dev) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 85257f6b9576f77b6a5e24820ad895267d65e50c..19e06bc38b39e88c877aa9d29e49c85bfde9c84e 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -360,9 +360,9 @@ void ipoib_mark_paths_invalid(struct net_device *dev) spin_lock_irq(&priv->lock); list_for_each_entry_safe(path, tp, &priv->path_list, list) { - ipoib_dbg(priv, "mark path LID 0x%04x GID " IPOIB_GID_FMT " invalid\n", + ipoib_dbg(priv, "mark path LID 0x%04x GID %pI6 invalid\n", be16_to_cpu(path->pathrec.dlid), - IPOIB_GID_ARG(path->pathrec.dgid)); + path->pathrec.dgid.raw); path->valid = 0; } @@ -414,11 +414,11 @@ static void path_rec_completion(int status, unsigned long flags; if (!status) - ipoib_dbg(priv, "PathRec LID 0x%04x for GID " IPOIB_GID_FMT "\n", - be16_to_cpu(pathrec->dlid), IPOIB_GID_ARG(pathrec->dgid)); + ipoib_dbg(priv, "PathRec LID 0x%04x for GID %pI6\n", + be16_to_cpu(pathrec->dlid), pathrec->dgid.raw); else - ipoib_dbg(priv, "PathRec status %d for GID " IPOIB_GID_FMT "\n", - status, IPOIB_GID_ARG(path->pathrec.dgid)); + ipoib_dbg(priv, "PathRec status %d for GID %pI6\n", + status, path->pathrec.dgid.raw); skb_queue_head_init(&skqueue); @@ -528,8 +528,8 @@ static int path_rec_start(struct net_device *dev, { struct ipoib_dev_priv *priv = netdev_priv(dev); - ipoib_dbg(priv, "Start path record lookup for " IPOIB_GID_FMT "\n", - IPOIB_GID_ARG(path->pathrec.dgid)); + ipoib_dbg(priv, "Start path record lookup for %pI6\n", + path->pathrec.dgid.raw); init_completion(&path->done); @@ -766,12 +766,11 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) if ((be16_to_cpup((__be16 *) skb->data) != ETH_P_ARP) && (be16_to_cpup((__be16 *) skb->data) != ETH_P_RARP)) { - ipoib_warn(priv, "Unicast, no %s: type %04x, QPN %06x " - IPOIB_GID_FMT "\n", + ipoib_warn(priv, "Unicast, no %s: type %04x, QPN %06x %pI6\n", skb->dst ? "neigh" : "dst", be16_to_cpup((__be16 *) skb->data), IPOIB_QPN(phdr->hwaddr), - IPOIB_GID_RAW_ARG(phdr->hwaddr + 4)); + phdr->hwaddr + 4); dev_kfree_skb_any(skb); ++dev->stats.tx_dropped; return NETDEV_TX_OK; @@ -847,9 +846,9 @@ static void ipoib_neigh_cleanup(struct neighbour *n) else return; ipoib_dbg(priv, - "neigh_cleanup for %06x " IPOIB_GID_FMT "\n", + "neigh_cleanup for %06x %pI6\n", IPOIB_QPN(n->ha), - IPOIB_GID_RAW_ARG(n->ha + 4)); + n->ha + 4); spin_lock_irqsave(&priv->lock, flags); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index d9d1223c3fd5f7dc1609764c9a1db16e3a20018f..a2eb3b9789ebabb08f69f3b0421128900db22bd6 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -71,9 +71,8 @@ static void ipoib_mcast_free(struct ipoib_mcast *mcast) struct ipoib_neigh *neigh, *tmp; int tx_dropped = 0; - ipoib_dbg_mcast(netdev_priv(dev), - "deleting multicast group " IPOIB_GID_FMT "\n", - IPOIB_GID_ARG(mcast->mcmember.mgid)); + ipoib_dbg_mcast(netdev_priv(dev), "deleting multicast group %pI6\n", + mcast->mcmember.mgid.raw); spin_lock_irq(&priv->lock); @@ -205,9 +204,8 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast, if (!test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) { if (test_and_set_bit(IPOIB_MCAST_FLAG_ATTACHED, &mcast->flags)) { - ipoib_warn(priv, "multicast group " IPOIB_GID_FMT - " already attached\n", - IPOIB_GID_ARG(mcast->mcmember.mgid)); + ipoib_warn(priv, "multicast group %pI6 already attached\n", + mcast->mcmember.mgid.raw); return 0; } @@ -215,9 +213,8 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast, ret = ipoib_mcast_attach(dev, be16_to_cpu(mcast->mcmember.mlid), &mcast->mcmember.mgid, set_qkey); if (ret < 0) { - ipoib_warn(priv, "couldn't attach QP to multicast group " - IPOIB_GID_FMT "\n", - IPOIB_GID_ARG(mcast->mcmember.mgid)); + ipoib_warn(priv, "couldn't attach QP to multicast group %pI6\n", + mcast->mcmember.mgid.raw); clear_bit(IPOIB_MCAST_FLAG_ATTACHED, &mcast->flags); return ret; @@ -248,9 +245,8 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast, mcast->ah = ah; spin_unlock_irq(&priv->lock); - ipoib_dbg_mcast(priv, "MGID " IPOIB_GID_FMT - " AV %p, LID 0x%04x, SL %d\n", - IPOIB_GID_ARG(mcast->mcmember.mgid), + ipoib_dbg_mcast(priv, "MGID %pI6 AV %p, LID 0x%04x, SL %d\n", + mcast->mcmember.mgid.raw, mcast->ah->ah, be16_to_cpu(mcast->mcmember.mlid), mcast->mcmember.sl); @@ -295,9 +291,8 @@ ipoib_mcast_sendonly_join_complete(int status, if (status) { if (mcast->logcount++ < 20) - ipoib_dbg_mcast(netdev_priv(dev), "multicast join failed for " - IPOIB_GID_FMT ", status %d\n", - IPOIB_GID_ARG(mcast->mcmember.mgid), status); + ipoib_dbg_mcast(netdev_priv(dev), "multicast join failed for %pI6, status %d\n", + mcast->mcmember.mgid.raw, status); /* Flush out any queued packets */ netif_tx_lock_bh(dev); @@ -356,9 +351,8 @@ static int ipoib_mcast_sendonly_join(struct ipoib_mcast *mcast) ipoib_warn(priv, "ib_sa_join_multicast failed (ret = %d)\n", ret); } else { - ipoib_dbg_mcast(priv, "no multicast record for " IPOIB_GID_FMT - ", starting join\n", - IPOIB_GID_ARG(mcast->mcmember.mgid)); + ipoib_dbg_mcast(priv, "no multicast record for %pI6, starting join\n", + mcast->mcmember.mgid.raw); } return ret; @@ -386,9 +380,8 @@ static int ipoib_mcast_join_complete(int status, struct net_device *dev = mcast->dev; struct ipoib_dev_priv *priv = netdev_priv(dev); - ipoib_dbg_mcast(priv, "join completion for " IPOIB_GID_FMT - " (status %d)\n", - IPOIB_GID_ARG(mcast->mcmember.mgid), status); + ipoib_dbg_mcast(priv, "join completion for %pI6 (status %d)\n", + mcast->mcmember.mgid.raw, status); /* We trap for port events ourselves. */ if (status == -ENETRESET) @@ -417,15 +410,11 @@ static int ipoib_mcast_join_complete(int status, if (mcast->logcount++ < 20) { if (status == -ETIMEDOUT) { - ipoib_dbg_mcast(priv, "multicast join failed for " IPOIB_GID_FMT - ", status %d\n", - IPOIB_GID_ARG(mcast->mcmember.mgid), - status); + ipoib_dbg_mcast(priv, "multicast join failed for %pI6, status %d\n", + mcast->mcmember.mgid.raw, status); } else { - ipoib_warn(priv, "multicast join failed for " - IPOIB_GID_FMT ", status %d\n", - IPOIB_GID_ARG(mcast->mcmember.mgid), - status); + ipoib_warn(priv, "multicast join failed for %pI6, status %d\n", + mcast->mcmember.mgid.raw, status); } } @@ -457,8 +446,7 @@ static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast, ib_sa_comp_mask comp_mask; int ret = 0; - ipoib_dbg_mcast(priv, "joining MGID " IPOIB_GID_FMT "\n", - IPOIB_GID_ARG(mcast->mcmember.mgid)); + ipoib_dbg_mcast(priv, "joining MGID %pI6\n", mcast->mcmember.mgid.raw); rec.mgid = mcast->mcmember.mgid; rec.port_gid = priv->local_gid; @@ -643,8 +631,8 @@ static int ipoib_mcast_leave(struct net_device *dev, struct ipoib_mcast *mcast) ib_sa_free_multicast(mcast->mc); if (test_and_clear_bit(IPOIB_MCAST_FLAG_ATTACHED, &mcast->flags)) { - ipoib_dbg_mcast(priv, "leaving MGID " IPOIB_GID_FMT "\n", - IPOIB_GID_ARG(mcast->mcmember.mgid)); + ipoib_dbg_mcast(priv, "leaving MGID %pI6\n", + mcast->mcmember.mgid.raw); /* Remove ourselves from the multicast group */ ret = ib_detach_mcast(priv->qp, &mcast->mcmember.mgid, @@ -675,8 +663,8 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb) mcast = __ipoib_mcast_find(dev, mgid); if (!mcast) { /* Let's create a new send only group now */ - ipoib_dbg_mcast(priv, "setting up send only multicast group for " - IPOIB_GID_FMT "\n", IPOIB_GID_RAW_ARG(mgid)); + ipoib_dbg_mcast(priv, "setting up send only multicast group for %pI6\n", + mgid); mcast = ipoib_mcast_alloc(dev, 0); if (!mcast) { @@ -809,14 +797,14 @@ void ipoib_mcast_restart_task(struct work_struct *work) /* ignore group which is directly joined by userspace */ if (test_bit(IPOIB_FLAG_UMCAST, &priv->flags) && !ib_sa_get_mcmember_rec(priv->ca, priv->port, &mgid, &rec)) { - ipoib_dbg_mcast(priv, "ignoring multicast entry for mgid " - IPOIB_GID_FMT "\n", IPOIB_GID_ARG(mgid)); + ipoib_dbg_mcast(priv, "ignoring multicast entry for mgid %pI6\n", + mgid.raw); continue; } /* Not found or send-only group, let's add a new entry */ - ipoib_dbg_mcast(priv, "adding multicast entry for mgid " - IPOIB_GID_FMT "\n", IPOIB_GID_ARG(mgid)); + ipoib_dbg_mcast(priv, "adding multicast entry for mgid %pI6\n", + mgid.raw); nmcast = ipoib_mcast_alloc(dev, 0); if (!nmcast) { @@ -849,8 +837,8 @@ void ipoib_mcast_restart_task(struct work_struct *work) list_for_each_entry_safe(mcast, tmcast, &priv->multicast_list, list) { if (!test_bit(IPOIB_MCAST_FLAG_FOUND, &mcast->flags) && !test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) { - ipoib_dbg_mcast(priv, "deleting multicast group " IPOIB_GID_FMT "\n", - IPOIB_GID_ARG(mcast->mcmember.mgid)); + ipoib_dbg_mcast(priv, "deleting multicast group %pI6\n", + mcast->mcmember.mgid.raw); rb_erase(&mcast->rb_node, &priv->multicast_tree); diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index 81a82628a5f1ebba68217ca6d20a5d5fd48bacbd..861119593f2b8cae85bcaf91bca423101a2da4b1 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -252,6 +252,9 @@ struct iser_conn { wait_queue_head_t wait; /* waitq for conn/disconn */ atomic_t post_recv_buf_count; /* posted rx count */ atomic_t post_send_buf_count; /* posted tx count */ + atomic_t unexpected_pdu_count;/* count of received * + * unexpected pdus * + * not yet retired */ char name[ISER_OBJECT_NAME_SIZE]; struct iser_page_vec *page_vec; /* represents SG to fmr maps* * maps serialized as tx is*/ diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index cdd28318904732091be64ed22688109984e032a0..ed1aff21b7eaba88efd8593933f0f68ec62c2c38 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c @@ -183,14 +183,8 @@ static int iser_post_receive_control(struct iscsi_conn *conn) struct iser_regd_buf *regd_data; struct iser_dto *recv_dto = NULL; struct iser_device *device = iser_conn->ib_conn->device; - int rx_data_size, err = 0; - - rx_desc = kmem_cache_alloc(ig.desc_cache, GFP_NOIO); - if (rx_desc == NULL) { - iser_err("Failed to alloc desc for post recv\n"); - return -ENOMEM; - } - rx_desc->type = ISCSI_RX; + int rx_data_size, err; + int posts, outstanding_unexp_pdus; /* for the login sequence we must support rx of upto 8K; login is done * after conn create/bind (connect) and conn stop/bind (reconnect), @@ -201,46 +195,80 @@ static int iser_post_receive_control(struct iscsi_conn *conn) else /* FIXME till user space sets conn->max_recv_dlength correctly */ rx_data_size = 128; - rx_desc->data = kmalloc(rx_data_size, GFP_NOIO); - if (rx_desc->data == NULL) { - iser_err("Failed to alloc data buf for post recv\n"); - err = -ENOMEM; - goto post_rx_kmalloc_failure; - } + outstanding_unexp_pdus = + atomic_xchg(&iser_conn->ib_conn->unexpected_pdu_count, 0); - recv_dto = &rx_desc->dto; - recv_dto->ib_conn = iser_conn->ib_conn; - recv_dto->regd_vector_len = 0; + /* + * in addition to the response buffer, replace those consumed by + * unexpected pdus. + */ + for (posts = 0; posts < 1 + outstanding_unexp_pdus; posts++) { + rx_desc = kmem_cache_alloc(ig.desc_cache, GFP_NOIO); + if (rx_desc == NULL) { + iser_err("Failed to alloc desc for post recv %d\n", + posts); + err = -ENOMEM; + goto post_rx_cache_alloc_failure; + } + rx_desc->type = ISCSI_RX; + rx_desc->data = kmalloc(rx_data_size, GFP_NOIO); + if (rx_desc->data == NULL) { + iser_err("Failed to alloc data buf for post recv %d\n", + posts); + err = -ENOMEM; + goto post_rx_kmalloc_failure; + } - regd_hdr = &rx_desc->hdr_regd_buf; - memset(regd_hdr, 0, sizeof(struct iser_regd_buf)); - regd_hdr->device = device; - regd_hdr->virt_addr = rx_desc; /* == &rx_desc->iser_header */ - regd_hdr->data_size = ISER_TOTAL_HEADERS_LEN; + recv_dto = &rx_desc->dto; + recv_dto->ib_conn = iser_conn->ib_conn; + recv_dto->regd_vector_len = 0; - iser_reg_single(device, regd_hdr, DMA_FROM_DEVICE); + regd_hdr = &rx_desc->hdr_regd_buf; + memset(regd_hdr, 0, sizeof(struct iser_regd_buf)); + regd_hdr->device = device; + regd_hdr->virt_addr = rx_desc; /* == &rx_desc->iser_header */ + regd_hdr->data_size = ISER_TOTAL_HEADERS_LEN; - iser_dto_add_regd_buff(recv_dto, regd_hdr, 0, 0); + iser_reg_single(device, regd_hdr, DMA_FROM_DEVICE); - regd_data = &rx_desc->data_regd_buf; - memset(regd_data, 0, sizeof(struct iser_regd_buf)); - regd_data->device = device; - regd_data->virt_addr = rx_desc->data; - regd_data->data_size = rx_data_size; + iser_dto_add_regd_buff(recv_dto, regd_hdr, 0, 0); - iser_reg_single(device, regd_data, DMA_FROM_DEVICE); + regd_data = &rx_desc->data_regd_buf; + memset(regd_data, 0, sizeof(struct iser_regd_buf)); + regd_data->device = device; + regd_data->virt_addr = rx_desc->data; + regd_data->data_size = rx_data_size; - iser_dto_add_regd_buff(recv_dto, regd_data, 0, 0); + iser_reg_single(device, regd_data, DMA_FROM_DEVICE); - err = iser_post_recv(rx_desc); - if (!err) - return 0; + iser_dto_add_regd_buff(recv_dto, regd_data, 0, 0); - /* iser_post_recv failed */ + err = iser_post_recv(rx_desc); + if (err) { + iser_err("Failed iser_post_recv for post %d\n", posts); + goto post_rx_post_recv_failure; + } + } + /* all posts successful */ + return 0; + +post_rx_post_recv_failure: iser_dto_buffs_release(recv_dto); kfree(rx_desc->data); post_rx_kmalloc_failure: kmem_cache_free(ig.desc_cache, rx_desc); +post_rx_cache_alloc_failure: + if (posts > 0) { + /* + * response buffer posted, but did not replace all unexpected + * pdu recv bufs. Ignore error, retry occurs next send + */ + outstanding_unexp_pdus -= (posts - 1); + err = 0; + } + atomic_add(outstanding_unexp_pdus, + &iser_conn->ib_conn->unexpected_pdu_count); + return err; } @@ -274,8 +302,10 @@ int iser_conn_set_full_featured_mode(struct iscsi_conn *conn) struct iscsi_iser_conn *iser_conn = conn->dd_data; int i; - /* no need to keep it in a var, we are after login so if this should - * be negotiated, by now the result should be available here */ + /* + * FIXME this value should be declared to the target during login with + * the MaxOutstandingUnexpectedPDUs key when supported + */ int initial_post_recv_bufs_num = ISER_MAX_RX_MISC_PDUS; iser_dbg("Initially post: %d\n", initial_post_recv_bufs_num); @@ -478,6 +508,7 @@ int iser_send_control(struct iscsi_conn *conn, int err = 0; struct iser_regd_buf *regd_buf; struct iser_device *device; + unsigned char opcode; if (!iser_conn_state_comp(iser_conn->ib_conn, ISER_CONN_UP)) { iser_err("Failed to send, conn: 0x%p is not up\n", iser_conn->ib_conn); @@ -512,10 +543,15 @@ int iser_send_control(struct iscsi_conn *conn, data_seg_len); } - if (iser_post_receive_control(conn) != 0) { - iser_err("post_rcv_buff failed!\n"); - err = -ENOMEM; - goto send_control_error; + opcode = task->hdr->opcode & ISCSI_OPCODE_MASK; + + /* post recv buffer for response if one is expected */ + if (!(opcode == ISCSI_OP_NOOP_OUT && task->hdr->itt == RESERVED_ITT)) { + if (iser_post_receive_control(conn) != 0) { + iser_err("post_rcv_buff failed!\n"); + err = -ENOMEM; + goto send_control_error; + } } err = iser_post_send(mdesc); @@ -586,6 +622,20 @@ void iser_rcv_completion(struct iser_desc *rx_desc, * parallel to the execution of iser_conn_term. So the code that waits * * for the posted rx bufs refcount to become zero handles everything */ atomic_dec(&conn->ib_conn->post_recv_buf_count); + + /* + * if an unexpected PDU was received then the recv wr consumed must + * be replaced, this is done in the next send of a control-type PDU + */ + if (opcode == ISCSI_OP_NOOP_IN && hdr->itt == RESERVED_ITT) { + /* nop-in with itt = 0xffffffff */ + atomic_inc(&conn->ib_conn->unexpected_pdu_count); + } + else if (opcode == ISCSI_OP_ASYNC_EVENT) { + /* asyncronous message */ + atomic_inc(&conn->ib_conn->unexpected_pdu_count); + } + /* a reject PDU consumes the recv buf posted for the response */ } void iser_snd_completion(struct iser_desc *tx_desc) diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index 26ff6214a81f4b64ac2a0b406ece8febcbfbac59..319b188145be197d5a2fee93edfd204da867df04 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -498,6 +498,7 @@ void iser_conn_init(struct iser_conn *ib_conn) init_waitqueue_head(&ib_conn->wait); atomic_set(&ib_conn->post_recv_buf_count, 0); atomic_set(&ib_conn->post_send_buf_count, 0); + atomic_set(&ib_conn->unexpected_pdu_count, 0); atomic_set(&ib_conn->refcount, 1); INIT_LIST_HEAD(&ib_conn->conn_list); spin_lock_init(&ib_conn->lock); @@ -515,14 +516,14 @@ int iser_connect(struct iser_conn *ib_conn, struct sockaddr *src, *dst; int err = 0; - sprintf(ib_conn->name,"%d.%d.%d.%d:%d", - NIPQUAD(dst_addr->sin_addr.s_addr), dst_addr->sin_port); + sprintf(ib_conn->name, "%pI4:%d", + &dst_addr->sin_addr.s_addr, dst_addr->sin_port); /* the device is known only --after-- address resolution */ ib_conn->device = NULL; - iser_err("connecting to: %d.%d.%d.%d, port 0x%x\n", - NIPQUAD(dst_addr->sin_addr), dst_addr->sin_port); + iser_err("connecting to: %pI4, port 0x%x\n", + &dst_addr->sin_addr, dst_addr->sin_port); ib_conn->state = ISER_CONN_PENDING; diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 5b8b533f29089a7ccd428abffa65136ae8cb30e0..7c13db885bf67defc836d8d60552865ff0041a62 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -1514,15 +1514,7 @@ static ssize_t show_dgid(struct device *dev, struct device_attribute *attr, target->state == SRP_TARGET_REMOVED) return -ENODEV; - return sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", - be16_to_cpu(((__be16 *) target->path.dgid.raw)[0]), - be16_to_cpu(((__be16 *) target->path.dgid.raw)[1]), - be16_to_cpu(((__be16 *) target->path.dgid.raw)[2]), - be16_to_cpu(((__be16 *) target->path.dgid.raw)[3]), - be16_to_cpu(((__be16 *) target->path.dgid.raw)[4]), - be16_to_cpu(((__be16 *) target->path.dgid.raw)[5]), - be16_to_cpu(((__be16 *) target->path.dgid.raw)[6]), - be16_to_cpu(((__be16 *) target->path.dgid.raw)[7])); + return sprintf(buf, "%pI6\n", target->path.dgid.raw); } static ssize_t show_orig_dgid(struct device *dev, @@ -1534,15 +1526,7 @@ static ssize_t show_orig_dgid(struct device *dev, target->state == SRP_TARGET_REMOVED) return -ENODEV; - return sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", - be16_to_cpu(target->orig_dgid[0]), - be16_to_cpu(target->orig_dgid[1]), - be16_to_cpu(target->orig_dgid[2]), - be16_to_cpu(target->orig_dgid[3]), - be16_to_cpu(target->orig_dgid[4]), - be16_to_cpu(target->orig_dgid[5]), - be16_to_cpu(target->orig_dgid[6]), - be16_to_cpu(target->orig_dgid[7])); + return sprintf(buf, "%pI6\n", target->orig_dgid); } static ssize_t show_zero_req_lim(struct device *dev, @@ -1883,19 +1867,12 @@ static ssize_t srp_create_target(struct device *dev, shost_printk(KERN_DEBUG, target->scsi_host, PFX "new target: id_ext %016llx ioc_guid %016llx pkey %04x " - "service_id %016llx dgid %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", + "service_id %016llx dgid %pI6\n", (unsigned long long) be64_to_cpu(target->id_ext), (unsigned long long) be64_to_cpu(target->ioc_guid), be16_to_cpu(target->path.pkey), (unsigned long long) be64_to_cpu(target->service_id), - (int) be16_to_cpu(*(__be16 *) &target->path.dgid.raw[0]), - (int) be16_to_cpu(*(__be16 *) &target->path.dgid.raw[2]), - (int) be16_to_cpu(*(__be16 *) &target->path.dgid.raw[4]), - (int) be16_to_cpu(*(__be16 *) &target->path.dgid.raw[6]), - (int) be16_to_cpu(*(__be16 *) &target->path.dgid.raw[8]), - (int) be16_to_cpu(*(__be16 *) &target->path.dgid.raw[10]), - (int) be16_to_cpu(*(__be16 *) &target->path.dgid.raw[12]), - (int) be16_to_cpu(*(__be16 *) &target->path.dgid.raw[14])); + target->path.dgid.raw); ret = srp_create_target_ib(target); if (ret) diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c index c600ab7f93e8029b2b00923d445745db9e7059ff..5c8a1bcf7ca7436376223ad6a42a469b47cbf743 100644 --- a/drivers/input/keyboard/sh_keysc.c +++ b/drivers/input/keyboard/sh_keysc.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -39,6 +40,7 @@ static const struct { struct sh_keysc_priv { void __iomem *iomem_base; + struct clk *clk; unsigned long last_keys; struct input_dev *input; struct sh_keysc_info pdata; @@ -125,6 +127,7 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev) struct sh_keysc_info *pdata; struct resource *res; struct input_dev *input; + char clk_name[8]; int i, k; int irq, error; @@ -165,11 +168,19 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev) goto err1; } + snprintf(clk_name, sizeof(clk_name), "keysc%d", pdev->id); + priv->clk = clk_get(&pdev->dev, clk_name); + if (IS_ERR(priv->clk)) { + dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name); + error = PTR_ERR(priv->clk); + goto err2; + } + priv->input = input_allocate_device(); if (!priv->input) { dev_err(&pdev->dev, "failed to allocate input device\n"); error = -ENOMEM; - goto err2; + goto err3; } input = priv->input; @@ -187,7 +198,7 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev) error = request_irq(irq, sh_keysc_isr, 0, pdev->name, pdev); if (error) { dev_err(&pdev->dev, "failed to request IRQ\n"); - goto err3; + goto err4; } for (i = 0; i < SH_KEYSC_MAXKEYS; i++) { @@ -199,18 +210,22 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev) error = input_register_device(input); if (error) { dev_err(&pdev->dev, "failed to register input device\n"); - goto err4; + goto err5; } + clk_enable(priv->clk); + iowrite16((sh_keysc_mode[pdata->mode].kymd << 8) | pdata->scan_timing, priv->iomem_base + KYCR1_OFFS); iowrite16(0, priv->iomem_base + KYOUTDR_OFFS); iowrite16(KYCR2_IRQ_LEVEL, priv->iomem_base + KYCR2_OFFS); return 0; - err4: + err5: free_irq(irq, pdev); - err3: + err4: input_free_device(input); + err3: + clk_put(priv->clk); err2: iounmap(priv->iomem_base); err1: @@ -230,6 +245,9 @@ static int __devexit sh_keysc_remove(struct platform_device *pdev) free_irq(platform_get_irq(pdev, 0), pdev); iounmap(priv->iomem_base); + clk_disable(priv->clk); + clk_put(priv->clk); + platform_set_drvdata(pdev, NULL); kfree(priv); return 0; diff --git a/drivers/isdn/capi/capifs.c b/drivers/isdn/capi/capifs.c index 550e80f390a63f87da84f84e9ec0290f75ca7151..0aa66ec4cbdd216789e11c30f8024a219b2e587c 100644 --- a/drivers/isdn/capi/capifs.c +++ b/drivers/isdn/capi/capifs.c @@ -156,8 +156,8 @@ void capifs_new_ncci(unsigned int number, dev_t device) if (!inode) return; inode->i_ino = number+2; - inode->i_uid = config.setuid ? config.uid : current->fsuid; - inode->i_gid = config.setgid ? config.gid : current->fsgid; + inode->i_uid = config.setuid ? config.uid : current_fsuid(); + inode->i_gid = config.setgid ? config.gid : current_fsgid(); inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; init_special_inode(inode, S_IFCHR|config.mode, device); //inode->i_op = &capifs_file_inode_operations; diff --git a/drivers/isdn/gigaset/asyncdata.c b/drivers/isdn/gigaset/asyncdata.c index c2bd97d29273ce584b5182578d05d41fd995c3da..2a4ce96f04bd7ecfea5ce9111b231e076bc80a28 100644 --- a/drivers/isdn/gigaset/asyncdata.c +++ b/drivers/isdn/gigaset/asyncdata.c @@ -17,8 +17,6 @@ #include #include -//#define GIG_M10x_STUFF_VOICE_DATA - /* check if byte must be stuffed/escaped * I'm not sure which data should be encoded. * Therefore I will go the hard way and decode every value @@ -147,19 +145,17 @@ static inline int hdlc_loop(unsigned char c, unsigned char *src, int numbytes, } byte_stuff: c ^= PPP_TRANS; -#ifdef CONFIG_GIGASET_DEBUG if (unlikely(!muststuff(c))) gig_dbg(DEBUG_HDLC, "byte stuffed: 0x%02x", c); -#endif } else if (unlikely(c == PPP_FLAG)) { if (unlikely(inputstate & INS_skip_frame)) { - if (!(inputstate & INS_have_data)) { /* 7E 7E */ #ifdef CONFIG_GIGASET_DEBUG + if (!(inputstate & INS_have_data)) { /* 7E 7E */ ++bcs->emptycount; -#endif } else gig_dbg(DEBUG_HDLC, "7e----------------------------"); +#endif /* end of frame */ error = 1; @@ -226,11 +222,9 @@ static inline int hdlc_loop(unsigned char c, unsigned char *src, int numbytes, } break; -#ifdef CONFIG_GIGASET_DEBUG } else if (unlikely(muststuff(c))) { /* Should not happen. Possible after ZDLE=1. */ gig_dbg(DEBUG_HDLC, "not byte stuffed: 0x%02x", c); -#endif } /* add character */ @@ -394,20 +388,16 @@ void gigaset_m10x_input(struct inbuf_t *inbuf) inbuf->inputstate &= ~INS_DLE_char; switch (c) { case 'X': /*begin of command*/ -#ifdef CONFIG_GIGASET_DEBUG if (inbuf->inputstate & INS_command) - dev_err(cs->dev, + dev_warn(cs->dev, "received 'X' in command mode\n"); -#endif inbuf->inputstate |= INS_command | INS_DLE_command; break; case '.': /*end of command*/ -#ifdef CONFIG_GIGASET_DEBUG if (!(inbuf->inputstate & INS_command)) - dev_err(cs->dev, + dev_warn(cs->dev, "received '.' in hdlc mode\n"); -#endif inbuf->inputstate &= cs->dle ? ~(INS_DLE_command|INS_command) : ~INS_DLE_command; diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c index 3f11910c7ccdbf4c2edb31d360f3e40feba77d4b..18dd8aacbe8d4157bee715943ab0612873c2b75c 100644 --- a/drivers/isdn/gigaset/bas-gigaset.c +++ b/drivers/isdn/gigaset/bas-gigaset.c @@ -2067,7 +2067,7 @@ static int gigaset_initbcshw(struct bc_state *bcs) bcs->hw.bas = ubc = kmalloc(sizeof(struct bas_bc_state), GFP_KERNEL); if (!ubc) { - err("could not allocate bas_bc_state"); + pr_err("out of memory\n"); return 0; } @@ -2081,7 +2081,7 @@ static int gigaset_initbcshw(struct bc_state *bcs) ubc->isooutdone = ubc->isooutfree = ubc->isooutovfl = NULL; ubc->numsub = 0; if (!(ubc->isooutbuf = kmalloc(sizeof(struct isowbuf_t), GFP_KERNEL))) { - err("could not allocate isochronous output buffer"); + pr_err("out of memory\n"); kfree(ubc); bcs->hw.bas = NULL; return 0; @@ -2136,8 +2136,10 @@ static int gigaset_initcshw(struct cardstate *cs) struct bas_cardstate *ucs; cs->hw.bas = ucs = kmalloc(sizeof *ucs, GFP_KERNEL); - if (!ucs) + if (!ucs) { + pr_err("out of memory\n"); return 0; + } ucs->urb_cmd_in = NULL; ucs->urb_cmd_out = NULL; @@ -2503,12 +2505,11 @@ static int __init bas_gigaset_init(void) /* register this driver with the USB subsystem */ result = usb_register(&gigaset_usb_driver); if (result < 0) { - err("usb_register failed (error %d)", -result); + pr_err("error %d registering USB driver\n", -result); goto error; } - info(DRIVER_AUTHOR); - info(DRIVER_DESC); + pr_info(DRIVER_DESC "\n"); return 0; error: diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c index 9d3ce7718e58faac892540caf6c2e61eadd2f051..0048ce98bfa8d789dd2262db49bf672ec75f64b1 100644 --- a/drivers/isdn/gigaset/common.c +++ b/drivers/isdn/gigaset/common.c @@ -580,7 +580,7 @@ static struct bc_state *gigaset_initbcs(struct bc_state *bcs, } else if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL) skb_reserve(bcs->skb, HW_HDR_LEN); else { - warn("could not allocate skb"); + pr_err("out of memory\n"); bcs->inputstate |= INS_skip_frame; } @@ -634,20 +634,20 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, gig_dbg(DEBUG_INIT, "allocating cs"); if (!(cs = alloc_cs(drv))) { - err("maximum number of devices exceeded"); + pr_err("maximum number of devices exceeded\n"); return NULL; } gig_dbg(DEBUG_INIT, "allocating bcs[0..%d]", channels - 1); cs->bcs = kmalloc(channels * sizeof(struct bc_state), GFP_KERNEL); if (!cs->bcs) { - err("out of memory"); + pr_err("out of memory\n"); goto error; } gig_dbg(DEBUG_INIT, "allocating inbuf"); cs->inbuf = kmalloc(sizeof(struct inbuf_t), GFP_KERNEL); if (!cs->inbuf) { - err("out of memory"); + pr_err("out of memory\n"); goto error; } @@ -690,7 +690,7 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, for (i = 0; i < channels; ++i) { gig_dbg(DEBUG_INIT, "setting up bcs[%d].read", i); if (!gigaset_initbcs(cs->bcs + i, cs, i)) { - err("could not allocate channel %d data", i); + pr_err("could not allocate channel %d data\n", i); goto error; } } @@ -720,17 +720,15 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, gig_dbg(DEBUG_INIT, "setting up iif"); if (!gigaset_register_to_LL(cs, modulename)) { - err("register_isdn failed"); + pr_err("error registering ISDN device\n"); goto error; } make_valid(cs, VALID_ID); ++cs->cs_init; gig_dbg(DEBUG_INIT, "setting up hw"); - if (!cs->ops->initcshw(cs)) { - err("could not allocate device specific data"); + if (!cs->ops->initcshw(cs)) goto error; - } ++cs->cs_init; @@ -836,7 +834,7 @@ static void cleanup_cs(struct cardstate *cs) for (i = 0; i < cs->channels; ++i) { gigaset_freebcs(cs->bcs + i); if (!gigaset_initbcs(cs->bcs + i, cs, i)) - break; //FIXME error handling + pr_err("could not allocate channel %d data\n", i); } if (cs->waiting) { @@ -1120,8 +1118,7 @@ static int __init gigaset_init_module(void) if (gigaset_debuglevel == 1) gigaset_debuglevel = DEBUG_DEFAULT; - info(DRIVER_AUTHOR); - info(DRIVER_DESC); + pr_info(DRIVER_DESC "\n"); return 0; } diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c index 5cbf64d850eefbbb4405d670d969f5938e38148e..e582a4887bc15b4055e73ac6f9a8556ef8538ddf 100644 --- a/drivers/isdn/gigaset/ev-layer.c +++ b/drivers/isdn/gigaset/ev-layer.c @@ -203,15 +203,6 @@ struct reply_t gigaset_tab_nocid_m10x[]= /* with dle mode */ {EV_TIMEOUT, 120,121, -1, 0, 0, {ACT_FAILVER, ACT_INIT}}, {RSP_ERROR, 120,121, -1, 0, 0, {ACT_FAILVER, ACT_INIT}}, {RSP_OK, 121,121, -1, 0, 0, {ACT_GOTVER, ACT_INIT}}, -#if 0 - {EV_TIMEOUT, 120,121, -1, 130, 5, {ACT_FAILVER}, "^SGCI=1\r"}, - {RSP_ERROR, 120,121, -1, 130, 5, {ACT_FAILVER}, "^SGCI=1\r"}, - {RSP_OK, 121,121, -1, 130, 5, {ACT_GOTVER}, "^SGCI=1\r"}, - - {RSP_OK, 130,130, -1, 0, 0, {ACT_INIT}}, - {RSP_ERROR, 130,130, -1, 0, 0, {ACT_FAILINIT}}, - {EV_TIMEOUT, 130,130, -1, 0, 0, {ACT_FAILINIT}}, -#endif /* leave dle mode */ {RSP_INIT, 0, 0,SEQ_DLE0, 201, 5, {0}, "^SDLE=0\r"}, @@ -260,10 +251,6 @@ struct reply_t gigaset_tab_nocid_m10x[]= /* with dle mode */ {RSP_INIT, 0, 0,SEQ_NOCID, 0, 0, {ACT_ABORTCID}}, /* reset */ -#if 0 - {RSP_INIT, 0, 0,SEQ_SHUTDOWN, 503, 5, {0}, "^SGCI=0\r"}, - {RSP_OK, 503,503, -1, 504, 5, {0}, "Z\r"}, -#endif {RSP_INIT, 0, 0,SEQ_SHUTDOWN, 504, 5, {0}, "Z\r"}, {RSP_OK, 504,504, -1, 0, 0, {ACT_SDOWN}}, {RSP_ERROR, 501,599, -1, 0, 0, {ACT_FAILSDOWN}}, @@ -391,24 +378,6 @@ struct reply_t gigaset_tab_cid_m10x[] = /* for M10x */ }; -#if 0 -static struct reply_t tab_nocid[]= /* no dle mode */ //FIXME -{ - /* resp_code, min_ConState, max_ConState, parameter, new_ConState, timeout, action, command */ - - {RSP_ANY, -1, -1, -1, -1,-1, ACT_WARN, NULL}, - {RSP_LAST,0,0,0,0,0,0} -}; - -static struct reply_t tab_cid[] = /* no dle mode */ //FIXME -{ - /* resp_code, min_ConState, max_ConState, parameter, new_ConState, timeout, action, command */ - - {RSP_ANY, -1, -1, -1, -1,-1, ACT_WARN, NULL}, - {RSP_LAST,0,0,0,0,0,0} -}; -#endif - static const struct resp_type_t resp_type[] = { /*{"", RSP_EMPTY, RT_NOTHING},*/ @@ -665,13 +634,8 @@ void gigaset_handle_modem_response(struct cardstate *cs) dev_err(cs->dev, "out of memory\n"); ++curarg; } -#ifdef CONFIG_GIGASET_DEBUG - if (!event->ptr) - gig_dbg(DEBUG_CMD, "string==NULL"); - else - gig_dbg(DEBUG_CMD, "string==%s", - (char *) event->ptr); -#endif + gig_dbg(DEBUG_CMD, "string==%s", + event->ptr ? (char *) event->ptr : "NULL"); break; case RT_ZCAU: event->parameter = -1; @@ -697,9 +661,7 @@ void gigaset_handle_modem_response(struct cardstate *cs) ++curarg; } else event->parameter = -1; -#ifdef CONFIG_GIGASET_DEBUG gig_dbg(DEBUG_CMD, "parameter==%d", event->parameter); -#endif break; } diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h index 003752954993cffa46534a2a3a95383fcddd8645..747178f03d2c3ec26f50c6d15decda33801b2942 100644 --- a/drivers/isdn/gigaset/gigaset.h +++ b/drivers/isdn/gigaset/gigaset.h @@ -16,6 +16,9 @@ #ifndef GIGASET_H #define GIGASET_H +/* define global prefix for pr_ macros in linux/kernel.h */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -97,23 +100,6 @@ enum debuglevel { activated */ }; -/* Kernel message macros for situations where dev_printk and friends cannot be - * used for lack of reliable access to a device structure. - * linux/usb.h already contains these but in an obsolete form which clutters - * the log needlessly, and according to the USB maintainer those should be - * removed rather than fixed anyway. - */ -#undef err -#undef info -#undef warn - -#define err(format, arg...) printk(KERN_ERR KBUILD_MODNAME ": " \ - format "\n" , ## arg) -#define info(format, arg...) printk(KERN_INFO KBUILD_MODNAME ": " \ - format "\n" , ## arg) -#define warn(format, arg...) printk(KERN_WARNING KBUILD_MODNAME ": " \ - format "\n" , ## arg) - #ifdef CONFIG_GIGASET_DEBUG #define gig_dbg(level, format, arg...) \ diff --git a/drivers/isdn/gigaset/i4l.c b/drivers/isdn/gigaset/i4l.c index 3c127a8cbaf2261f473e28a01b29c0e00c2f2c93..69a702f0db93f3fa70ccd7fc6c649e611f4f0a5f 100644 --- a/drivers/isdn/gigaset/i4l.c +++ b/drivers/isdn/gigaset/i4l.c @@ -42,7 +42,7 @@ static int writebuf_from_LL(int driverID, int channel, int ack, unsigned skblen; if (!(cs = gigaset_get_cs_by_id(driverID))) { - err("%s: invalid driver ID (%d)", __func__, driverID); + pr_err("%s: invalid driver ID (%d)\n", __func__, driverID); return -ENODEV; } if (channel < 0 || channel >= cs->channels) { @@ -119,7 +119,7 @@ static int command_from_LL(isdn_ctrl *cntrl) gigaset_debugdrivers(); if (!cs) { - err("%s: invalid driver ID (%d)", __func__, cntrl->driver); + pr_err("%s: invalid driver ID (%d)\n", __func__, cntrl->driver); return -ENODEV; } diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c index 521951a898ece00218d3bd96645e94466c26a349..311e7ca0fb01956eb60ee4d2441e45a4878ea63f 100644 --- a/drivers/isdn/gigaset/interface.c +++ b/drivers/isdn/gigaset/interface.c @@ -107,7 +107,7 @@ static int if_config(struct cardstate *cs, int *arg) return -EBUSY; if (!cs->connected) { - err("not connected!"); + pr_err("%s: not connected\n", __func__); return -ENODEV; } @@ -143,9 +143,6 @@ static const struct tty_operations if_ops = { .set_termios = if_set_termios, .throttle = if_throttle, .unthrottle = if_unthrottle, -#if 0 - .break_ctl = serial_break, -#endif .tiocmget = if_tiocmget, .tiocmset = if_tiocmset, }; @@ -188,7 +185,7 @@ static void if_close(struct tty_struct *tty, struct file *filp) cs = (struct cardstate *) tty->driver_data; if (!cs) { - err("cs==NULL in %s", __func__); + pr_err("%s: no cardstate\n", __func__); return; } @@ -222,7 +219,7 @@ static int if_ioctl(struct tty_struct *tty, struct file *file, cs = (struct cardstate *) tty->driver_data; if (!cs) { - err("cs==NULL in %s", __func__); + pr_err("%s: no cardstate\n", __func__); return -ENODEV; } @@ -297,7 +294,7 @@ static int if_tiocmget(struct tty_struct *tty, struct file *file) cs = (struct cardstate *) tty->driver_data; if (!cs) { - err("cs==NULL in %s", __func__); + pr_err("%s: no cardstate\n", __func__); return -ENODEV; } @@ -323,7 +320,7 @@ static int if_tiocmset(struct tty_struct *tty, struct file *file, cs = (struct cardstate *) tty->driver_data; if (!cs) { - err("cs==NULL in %s", __func__); + pr_err("%s: no cardstate\n", __func__); return -ENODEV; } @@ -354,7 +351,7 @@ static int if_write(struct tty_struct *tty, const unsigned char *buf, int count) cs = (struct cardstate *) tty->driver_data; if (!cs) { - err("cs==NULL in %s", __func__); + pr_err("%s: no cardstate\n", __func__); return -ENODEV; } @@ -388,7 +385,7 @@ static int if_write_room(struct tty_struct *tty) cs = (struct cardstate *) tty->driver_data; if (!cs) { - err("cs==NULL in %s", __func__); + pr_err("%s: no cardstate\n", __func__); return -ENODEV; } @@ -420,7 +417,7 @@ static int if_chars_in_buffer(struct tty_struct *tty) cs = (struct cardstate *) tty->driver_data; if (!cs) { - err("cs==NULL in %s", __func__); + pr_err("%s: no cardstate\n", __func__); return -ENODEV; } @@ -451,7 +448,7 @@ static void if_throttle(struct tty_struct *tty) cs = (struct cardstate *) tty->driver_data; if (!cs) { - err("cs==NULL in %s", __func__); + pr_err("%s: no cardstate\n", __func__); return; } @@ -474,7 +471,7 @@ static void if_unthrottle(struct tty_struct *tty) cs = (struct cardstate *) tty->driver_data; if (!cs) { - err("cs==NULL in %s", __func__); + pr_err("%s: no cardstate\n", __func__); return; } @@ -501,7 +498,7 @@ static void if_set_termios(struct tty_struct *tty, struct ktermios *old) cs = (struct cardstate *) tty->driver_data; if (!cs) { - err("cs==NULL in %s", __func__); + pr_err("%s: no cardstate\n", __func__); return; } @@ -565,29 +562,6 @@ static void if_set_termios(struct tty_struct *tty, struct ktermios *old) cs->ops->set_line_ctrl(cs, cflag); -#if 0 - //FIXME this hangs M101 [ts 2005-03-09] - //FIXME do we need this? - /* - * Set flow control: well, I do not really now how to handle DTR/RTS. - * Just do what we have seen with SniffUSB on Win98. - */ - /* Drop DTR/RTS if no flow control otherwise assert */ - gig_dbg(DEBUG_IF, "%u: control_state %x", - cs->minor_index, control_state); - new_state = control_state; - if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS)) - new_state |= TIOCM_DTR | TIOCM_RTS; - else - new_state &= ~(TIOCM_DTR | TIOCM_RTS); - if (new_state != control_state) { - gig_dbg(DEBUG_IF, "%u: new_state %x", - cs->minor_index, new_state); - gigaset_set_modem_ctrl(cs, control_state, new_state); - control_state = new_state; - } -#endif - /* save off the modified port settings */ cs->control_state = control_state; @@ -701,7 +675,7 @@ void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname, ret = tty_register_driver(tty); if (ret < 0) { - warn("failed to register tty driver (error %d)", ret); + pr_err("error %d registering tty driver\n", ret); goto error; } gig_dbg(DEBUG_IF, "tty driver initialized"); @@ -709,7 +683,7 @@ void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname, return; enomem: - warn("could not allocate tty structures"); + pr_err("out of memory\n"); error: if (drv->tty) put_tty_driver(drv->tty); diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c index fbce5222d83cbab8e92826706ebfeba3256f1cec..b171e75cb52e51f920125abc984648f22415e961 100644 --- a/drivers/isdn/gigaset/isocdata.c +++ b/drivers/isdn/gigaset/isocdata.c @@ -88,11 +88,9 @@ static inline int isowbuf_startwrite(struct isowbuf_t *iwb) __func__); return 0; } -#ifdef CONFIG_GIGASET_DEBUG gig_dbg(DEBUG_ISO, "%s: acquired iso write semaphore, data[write]=%02x, nbits=%d", __func__, iwb->data[iwb->write], iwb->wbits); -#endif return 1; } @@ -173,13 +171,13 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size) __func__, read, write, limit); #ifdef CONFIG_GIGASET_DEBUG if (unlikely(size < 0 || size > BAS_OUTBUFPAD)) { - err("invalid size %d", size); + pr_err("invalid size %d\n", size); return -EINVAL; } src = iwb->read; if (unlikely(limit > BAS_OUTBUFSIZE + BAS_OUTBUFPAD || (read < src && limit >= src))) { - err("isoc write buffer frame reservation violated"); + pr_err("isoc write buffer frame reservation violated\n"); return -EFAULT; } #endif diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c index 07052ed2a0c56d46480cb04c375df1afc3779d31..ac245e7e96a557445212e50b0987c39c46efd960 100644 --- a/drivers/isdn/gigaset/ser-gigaset.c +++ b/drivers/isdn/gigaset/ser-gigaset.c @@ -16,7 +16,6 @@ #include #include #include -#include #include /* Version Information */ @@ -408,7 +407,7 @@ static int gigaset_initcshw(struct cardstate *cs) int rc; if (!(cs->hw.ser = kzalloc(sizeof(struct ser_cardstate), GFP_KERNEL))) { - err("%s: out of memory!", __func__); + pr_err("out of memory\n"); return 0; } @@ -416,7 +415,7 @@ static int gigaset_initcshw(struct cardstate *cs) cs->hw.ser->dev.id = cs->minor_index; cs->hw.ser->dev.dev.release = gigaset_device_release; if ((rc = platform_device_register(&cs->hw.ser->dev)) != 0) { - err("error %d registering platform device", rc); + pr_err("error %d registering platform device\n", rc); kfree(cs->hw.ser); cs->hw.ser = NULL; return 0; @@ -514,11 +513,10 @@ gigaset_tty_open(struct tty_struct *tty) gig_dbg(DEBUG_INIT, "Starting HLL for Gigaset M101"); - info(DRIVER_AUTHOR); - info(DRIVER_DESC); + pr_info(DRIVER_DESC "\n"); if (!driver) { - err("%s: no driver structure", __func__); + pr_err("%s: no driver structure\n", __func__); return -ENODEV; } @@ -571,11 +569,10 @@ gigaset_tty_close(struct tty_struct *tty) } /* prevent other callers from entering ldisc methods */ - /* FIXME: should use the tty state flags */ tty->disc_data = NULL; if (!cs->hw.ser) - err("%s: no hw cardstate", __func__); + pr_err("%s: no hw cardstate\n", __func__); else { /* wait for running methods to finish */ if (!atomic_dec_and_test(&cs->hw.ser->refcnt)) @@ -672,18 +669,6 @@ gigaset_tty_ioctl(struct tty_struct *tty, struct file *file, return rc; } -/* - * Poll on the tty. - * Unused, always return zero. - * - * FIXME: should probably return an exception - especially on hangup - */ -static unsigned int -gigaset_tty_poll(struct tty_struct *tty, struct file *file, poll_table *wait) -{ - return 0; -} - /* * Called by the tty driver when a block of data has been received. * Will not be re-entered while running but other ldisc functions @@ -773,7 +758,6 @@ static struct tty_ldisc_ops gigaset_ldisc = { .read = gigaset_tty_read, .write = gigaset_tty_write, .ioctl = gigaset_tty_ioctl, - .poll = gigaset_tty_poll, .receive_buf = gigaset_tty_receive, .write_wakeup = gigaset_tty_wakeup, }; @@ -788,7 +772,7 @@ static int __init ser_gigaset_init(void) gig_dbg(DEBUG_INIT, "%s", __func__); if ((rc = platform_driver_register(&device_driver)) != 0) { - err("error %d registering platform driver", rc); + pr_err("error %d registering platform driver\n", rc); return rc; } @@ -799,7 +783,7 @@ static int __init ser_gigaset_init(void) goto error; if ((rc = tty_register_ldisc(N_GIGASET_M101, &gigaset_ldisc)) != 0) { - err("error %d registering line discipline", rc); + pr_err("error %d registering line discipline\n", rc); goto error; } @@ -826,7 +810,7 @@ static void __exit ser_gigaset_exit(void) } if ((rc = tty_unregister_ldisc(N_GIGASET_M101)) != 0) - err("error %d unregistering line discipline", rc); + pr_err("error %d unregistering line discipline\n", rc); platform_driver_unregister(&device_driver); } diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c index 4661830a49db9a471f349c4d30fbc323f363ccaa..fba61f6705278250139bc2ac94e51f2409b025f5 100644 --- a/drivers/isdn/gigaset/usb-gigaset.c +++ b/drivers/isdn/gigaset/usb-gigaset.c @@ -407,7 +407,7 @@ static void gigaset_read_int_callback(struct urb *urb) spin_lock_irqsave(&cs->lock, flags); if (!cs->connected) { spin_unlock_irqrestore(&cs->lock, flags); - err("%s: disconnected", __func__); + pr_err("%s: disconnected\n", __func__); return; } r = usb_submit_urb(urb, GFP_ATOMIC); @@ -440,7 +440,7 @@ static void gigaset_write_bulk_callback(struct urb *urb) spin_lock_irqsave(&cs->lock, flags); if (!cs->connected) { - err("%s: not connected", __func__); + pr_err("%s: disconnected\n", __func__); } else { cs->hw.usb->busy = 0; tasklet_schedule(&cs->write_tasklet); @@ -612,8 +612,10 @@ static int gigaset_initcshw(struct cardstate *cs) cs->hw.usb = ucs = kmalloc(sizeof(struct usb_cardstate), GFP_KERNEL); - if (!ucs) + if (!ucs) { + pr_err("out of memory\n"); return 0; + } ucs->bchars[0] = 0; ucs->bchars[1] = 0; @@ -936,13 +938,11 @@ static int __init usb_gigaset_init(void) /* register this driver with the USB subsystem */ result = usb_register(&gigaset_usb_driver); if (result < 0) { - err("usb_gigaset: usb_register failed (error %d)", - -result); + pr_err("error %d registering USB driver\n", -result); goto error; } - info(DRIVER_AUTHOR); - info(DRIVER_DESC); + pr_info(DRIVER_DESC "\n"); return 0; error: diff --git a/drivers/isdn/hardware/eicon/di.c b/drivers/isdn/hardware/eicon/di.c index 10760b3c5eb56bda220b5b6b0d7390241d2b0a6d..b029d130eb2186fa28e5efed25cccdce9342a31b 100644 --- a/drivers/isdn/hardware/eicon/di.c +++ b/drivers/isdn/hardware/eicon/di.c @@ -353,13 +353,13 @@ void scom_clear_int(ADAPTER * a) /*------------------------------------------------------------------*/ /* return code handler */ /*------------------------------------------------------------------*/ -byte isdn_rc(ADAPTER * a, - byte Rc, - byte Id, - byte Ch, - word Ref, - dword extended_info_type, - dword extended_info) +static byte isdn_rc(ADAPTER *a, + byte Rc, + byte Id, + byte Ch, + word Ref, + dword extended_info_type, + dword extended_info) { ENTITY * this; byte e_no; @@ -555,13 +555,13 @@ byte isdn_rc(ADAPTER * a, /*------------------------------------------------------------------*/ /* indication handler */ /*------------------------------------------------------------------*/ -byte isdn_ind(ADAPTER * a, - byte Ind, - byte Id, - byte Ch, - PBUFFER * RBuffer, - byte MInd, - word MLength) +static byte isdn_ind(ADAPTER *a, + byte Ind, + byte Id, + byte Ch, + PBUFFER *RBuffer, + byte MInd, + word MLength) { ENTITY * this; word clength; diff --git a/drivers/isdn/hardware/eicon/message.c b/drivers/isdn/hardware/eicon/message.c index 599fed88222d02f82ab4ff2a7d068c02cdafcc13..4cc94f200b724a2843333bb29a87c2bc4c5f0934 100644 --- a/drivers/isdn/hardware/eicon/message.c +++ b/drivers/isdn/hardware/eicon/message.c @@ -592,7 +592,7 @@ word api_put(APPL * appl, CAPI_MSG * msg) /* api_parse function, check the format of api messages */ /*------------------------------------------------------------------*/ -word api_parse(byte * msg, word length, byte * format, API_PARSE * parms) +static word api_parse(byte *msg, word length, byte *format, API_PARSE *parms) { word i; word p; @@ -631,7 +631,7 @@ word api_parse(byte * msg, word length, byte * format, API_PARSE * parms) return false; } -void api_save_msg(API_PARSE *in, byte *format, API_SAVE *out) +static void api_save_msg(API_PARSE *in, byte *format, API_SAVE *out) { word i, j, n = 0; byte *p; @@ -663,7 +663,7 @@ void api_save_msg(API_PARSE *in, byte *format, API_SAVE *out) out->parms[i].length = 0; } -void api_load_msg(API_SAVE *in, API_PARSE *out) +static void api_load_msg(API_SAVE *in, API_PARSE *out) { word i; @@ -3414,7 +3414,8 @@ byte select_b_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, return false; } -byte manufacturer_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms) +static byte manufacturer_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a, + PLCI *plci, APPL *appl, API_PARSE *parms) { word command; word i; @@ -3742,7 +3743,8 @@ byte manufacturer_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * p } -byte manufacturer_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * msg) +static byte manufacturer_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a, + PLCI *plci, APPL *appl, API_PARSE *msg) { word indication; @@ -4074,7 +4076,8 @@ void callback(ENTITY * e) } -void control_rc(PLCI * plci, byte req, byte rc, byte ch, byte global_req, byte nl_rc) +static void control_rc(PLCI *plci, byte req, byte rc, byte ch, byte global_req, + byte nl_rc) { dword Id; dword rId; @@ -4740,7 +4743,7 @@ void control_rc(PLCI * plci, byte req, byte rc, byte ch, byte global_req, byte } } -void data_rc(PLCI * plci, byte ch) +static void data_rc(PLCI *plci, byte ch) { dword Id; DIVA_CAPI_ADAPTER * a; @@ -4776,7 +4779,7 @@ void data_rc(PLCI * plci, byte ch) } } -void data_ack(PLCI * plci, byte ch) +static void data_ack(PLCI *plci, byte ch) { dword Id; DIVA_CAPI_ADAPTER * a; @@ -4802,7 +4805,7 @@ void data_ack(PLCI * plci, byte ch) } } -void sig_ind(PLCI * plci) +static void sig_ind(PLCI *plci) { dword x_Id; dword Id; @@ -6170,7 +6173,7 @@ static void SendSetupInfo(APPL * appl, PLCI * plci, dword Id, byte * * par } -void SendInfo(PLCI * plci, dword Id, byte * * parms, byte iesent) +static void SendInfo(PLCI *plci, dword Id, byte **parms, byte iesent) { word i; word j; @@ -6346,7 +6349,8 @@ void SendInfo(PLCI * plci, dword Id, byte * * parms, byte iesent) } -byte SendMultiIE(PLCI * plci, dword Id, byte * * parms, byte ie_type, dword info_mask, byte setupParse) +static byte SendMultiIE(PLCI *plci, dword Id, byte **parms, byte ie_type, + dword info_mask, byte setupParse) { word i; word j; @@ -6465,7 +6469,7 @@ static void SendSSExtInd(APPL * appl, PLCI * plci, dword Id, byte * * parm } }; -void nl_ind(PLCI * plci) +static void nl_ind(PLCI *plci) { byte ch; word ncci; @@ -7247,7 +7251,7 @@ void nl_ind(PLCI * plci) /* find a free PLCI */ /*------------------------------------------------------------------*/ -word get_plci(DIVA_CAPI_ADAPTER * a) +static word get_plci(DIVA_CAPI_ADAPTER *a) { word i,j; PLCI * plci; @@ -7406,7 +7410,7 @@ static void add_ie(PLCI * plci, byte code, byte * p, word p_length) /* put a unstructured data into the buffer */ /*------------------------------------------------------------------*/ -void add_d(PLCI * plci, word length, byte * p) +static void add_d(PLCI *plci, word length, byte *p) { word i; @@ -7424,7 +7428,7 @@ void add_d(PLCI * plci, word length, byte * p) /* parameter buffer */ /*------------------------------------------------------------------*/ -void add_ai(PLCI * plci, API_PARSE * ai) +static void add_ai(PLCI *plci, API_PARSE *ai) { word i; API_PARSE ai_parms[5]; @@ -7445,7 +7449,8 @@ void add_ai(PLCI * plci, API_PARSE * ai) /* put parameter for b1 protocol in the parameter buffer */ /*------------------------------------------------------------------*/ -word add_b1(PLCI * plci, API_PARSE * bp, word b_channel_info, word b1_facilities) +static word add_b1(PLCI *plci, API_PARSE *bp, word b_channel_info, + word b1_facilities) { API_PARSE bp_parms[8]; API_PARSE mdm_cfg[9]; @@ -7909,7 +7914,7 @@ word add_b1(PLCI * plci, API_PARSE * bp, word b_channel_info, word b1_faciliti /* put parameter for b2 and B3 protocol in the parameter buffer */ /*------------------------------------------------------------------*/ -word add_b23(PLCI * plci, API_PARSE * bp) +static word add_b23(PLCI *plci, API_PARSE *bp) { word i, fax_control_bits; byte pos, len; @@ -8706,7 +8711,7 @@ void sig_req(PLCI * plci, byte req, byte Id) /* send a request for the network layer entity */ /*------------------------------------------------------------------*/ -void nl_req_ncci(PLCI * plci, byte req, byte ncci) +static void nl_req_ncci(PLCI *plci, byte req, byte ncci) { if(!plci) return; if(plci->adapter->adapter_disabled) return; @@ -8728,7 +8733,7 @@ void nl_req_ncci(PLCI * plci, byte req, byte ncci) plci->req_in_start = plci->req_in; } -void send_req(PLCI * plci) +static void send_req(PLCI *plci) { ENTITY * e; word l; @@ -8863,7 +8868,7 @@ void send_data(PLCI * plci) } } -void listen_check(DIVA_CAPI_ADAPTER * a) +static void listen_check(DIVA_CAPI_ADAPTER *a) { word i,j; PLCI * plci; @@ -8906,7 +8911,7 @@ void listen_check(DIVA_CAPI_ADAPTER * a) /* functions for all parameters sent in INDs */ /*------------------------------------------------------------------*/ -void IndParse(PLCI * plci, word * parms_id, byte ** parms, byte multiIEsize) +static void IndParse(PLCI *plci, word *parms_id, byte **parms, byte multiIEsize) { word ploc; /* points to current location within packet */ byte w; @@ -8991,7 +8996,7 @@ void IndParse(PLCI * plci, word * parms_id, byte ** parms, byte multiIEsize) /* try to match a cip from received BC and HLC */ /*------------------------------------------------------------------*/ -byte ie_compare(byte * ie1, byte * ie2) +static byte ie_compare(byte *ie1, byte *ie2) { word i; if(!ie1 || ! ie2) return false; @@ -9000,7 +9005,7 @@ byte ie_compare(byte * ie1, byte * ie2) return true; } -word find_cip(DIVA_CAPI_ADAPTER * a, byte * bc, byte * hlc) +static word find_cip(DIVA_CAPI_ADAPTER *a, byte *bc, byte *hlc) { word i; word j; @@ -9068,7 +9073,7 @@ static byte AddInfo(byte **add_i, /* voice and codec features */ /*------------------------------------------------------------------*/ -void SetVoiceChannel(PLCI *plci, byte *chi, DIVA_CAPI_ADAPTER * a) +static void SetVoiceChannel(PLCI *plci, byte *chi, DIVA_CAPI_ADAPTER *a) { byte voice_chi[] = "\x02\x18\x01"; byte channel; @@ -9086,7 +9091,7 @@ void SetVoiceChannel(PLCI *plci, byte *chi, DIVA_CAPI_ADAPTER * a) } } -void VoiceChannelOff(PLCI *plci) +static void VoiceChannelOff(PLCI *plci) { dbug(1,dprintf("ExtDevOFF")); add_p(plci,FTY,"\x02\x01\x08"); /* B Off */ @@ -9099,7 +9104,8 @@ void VoiceChannelOff(PLCI *plci) } -word AdvCodecSupport(DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl, byte hook_listen) +static word AdvCodecSupport(DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl, + byte hook_listen) { word j; PLCI *splci; @@ -9195,7 +9201,7 @@ word AdvCodecSupport(DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl, byte ho } -void CodecIdCheck(DIVA_CAPI_ADAPTER *a, PLCI *plci) +static void CodecIdCheck(DIVA_CAPI_ADAPTER *a, PLCI *plci) { dbug(1,dprintf("CodecIdCheck")); diff --git a/drivers/isdn/hardware/mISDN/hfc_multi.h b/drivers/isdn/hardware/mISDN/hfc_multi.h index a33d87afc84367cf6cfc3c03112e493334e522f1..7bbf7300593d3c01c9115a4ce9a6b737c21e4d8c 100644 --- a/drivers/isdn/hardware/mISDN/hfc_multi.h +++ b/drivers/isdn/hardware/mISDN/hfc_multi.h @@ -162,8 +162,8 @@ struct hfc_multi { void (*write_fifo)(struct hfc_multi *hc, u_char *data, int len); u_long pci_origmembase, plx_origmembase, dsp_origmembase; - u_char *pci_membase; /* PCI memory (MUST BE BYTE POINTER) */ - u_char *plx_membase; /* PLX memory */ + void __iomem *pci_membase; /* PCI memory */ + void __iomem *plx_membase; /* PLX memory */ u_char *dsp_membase; /* DSP on PLX */ u_long pci_iobase; /* PCI IO */ struct hfcm_hw hw; /* remember data of write-only-registers */ diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index 1eac03f39d0005e0e75b75f3925e1924193e794b..c63e2f49da8ad38df99133197bf12ab6df670ea7 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c @@ -171,9 +171,8 @@ static int (*unregister_interrupt)(void); static int interrupt_registered; static struct hfc_multi *syncmaster; -int plxsd_master; /* if we have a master card (yet) */ +static int plxsd_master; /* if we have a master card (yet) */ static spinlock_t plx_lock; /* may not acquire other lock inside */ -EXPORT_SYMBOL(plx_lock); #define TYP_E1 1 #define TYP_4S 4 @@ -422,7 +421,7 @@ HFC_wait_debug(struct hfc_multi *hc, const char *function, int line) #endif /* write fifo data (REGIO) */ -void +static void write_fifo_regio(struct hfc_multi *hc, u_char *data, int len) { outb(A_FIFO_DATA0, (hc->pci_iobase)+4); @@ -443,7 +442,7 @@ write_fifo_regio(struct hfc_multi *hc, u_char *data, int len) } } /* write fifo data (PCIMEM) */ -void +static void write_fifo_pcimem(struct hfc_multi *hc, u_char *data, int len) { while (len>>2) { @@ -465,7 +464,7 @@ write_fifo_pcimem(struct hfc_multi *hc, u_char *data, int len) } } /* read fifo data (REGIO) */ -void +static void read_fifo_regio(struct hfc_multi *hc, u_char *data, int len) { outb(A_FIFO_DATA0, (hc->pci_iobase)+4); @@ -487,7 +486,7 @@ read_fifo_regio(struct hfc_multi *hc, u_char *data, int len) } /* read fifo data (PCIMEM) */ -void +static void read_fifo_pcimem(struct hfc_multi *hc, u_char *data, int len) { while (len>>2) { @@ -706,7 +705,7 @@ vpm_out(struct hfc_multi *c, int which, unsigned short addr, } -void +static void vpm_init(struct hfc_multi *wc) { unsigned char reg; @@ -789,7 +788,8 @@ vpm_init(struct hfc_multi *wc) } } -void +#ifdef UNUSED +static void vpm_check(struct hfc_multi *hctmp) { unsigned char gpi2; @@ -799,6 +799,7 @@ vpm_check(struct hfc_multi *hctmp) if ((gpi2 & 0x3) != 0x3) printk(KERN_DEBUG "Got interrupt 0x%x from VPM!\n", gpi2); } +#endif /* UNUSED */ /* @@ -812,7 +813,7 @@ vpm_check(struct hfc_multi *hctmp) * */ -void +static void vpm_echocan_on(struct hfc_multi *hc, int ch, int taps) { unsigned int timeslot; @@ -844,7 +845,7 @@ vpm_echocan_on(struct hfc_multi *hc, int ch, int taps) vpm_out(hc, unit, timeslot, 0x7e); } -void +static void vpm_echocan_off(struct hfc_multi *hc, int ch) { unsigned int timeslot; @@ -887,8 +888,9 @@ vpm_echocan_off(struct hfc_multi *hc, int ch) static inline void hfcmulti_resync(struct hfc_multi *locked, struct hfc_multi *newmaster, int rm) { - struct hfc_multi *hc, *next, *pcmmaster = 0; - u_int *plx_acc_32, pv; + struct hfc_multi *hc, *next, *pcmmaster = NULL; + void __iomem *plx_acc_32; + u_int pv; u_long flags; spin_lock_irqsave(&HFClock, flags); @@ -916,7 +918,7 @@ hfcmulti_resync(struct hfc_multi *locked, struct hfc_multi *newmaster, int rm) /* Disable sync of all cards */ list_for_each_entry_safe(hc, next, &HFClist, list) { if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { - plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC); + plx_acc_32 = hc->plx_membase + PLX_GPIOC; pv = readl(plx_acc_32); pv &= ~PLX_SYNC_O_EN; writel(pv, plx_acc_32); @@ -938,7 +940,7 @@ hfcmulti_resync(struct hfc_multi *locked, struct hfc_multi *newmaster, int rm) printk(KERN_DEBUG "id=%d (0x%p) = syncronized with " "interface.\n", hc->id, hc); /* Enable new sync master */ - plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC); + plx_acc_32 = hc->plx_membase + PLX_GPIOC; pv = readl(plx_acc_32); pv |= PLX_SYNC_O_EN; writel(pv, plx_acc_32); @@ -968,7 +970,7 @@ hfcmulti_resync(struct hfc_multi *locked, struct hfc_multi *newmaster, int rm) "QUARTZ is automatically " "enabled by HFC-%dS\n", hc->type); } - plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC); + plx_acc_32 = hc->plx_membase + PLX_GPIOC; pv = readl(plx_acc_32); pv |= PLX_SYNC_O_EN; writel(pv, plx_acc_32); @@ -1013,7 +1015,8 @@ plxsd_checksync(struct hfc_multi *hc, int rm) static void release_io_hfcmulti(struct hfc_multi *hc) { - u_int *plx_acc_32, pv; + void __iomem *plx_acc_32; + u_int pv; u_long plx_flags; if (debug & DEBUG_HFCMULTI_INIT) @@ -1033,7 +1036,7 @@ release_io_hfcmulti(struct hfc_multi *hc) printk(KERN_DEBUG "%s: release PLXSD card %d\n", __func__, hc->id + 1); spin_lock_irqsave(&plx_lock, plx_flags); - plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC); + plx_acc_32 = hc->plx_membase + PLX_GPIOC; writel(PLX_GPIOC_INIT, plx_acc_32); pv = readl(plx_acc_32); /* Termination off */ @@ -1055,9 +1058,9 @@ release_io_hfcmulti(struct hfc_multi *hc) test_and_clear_bit(HFC_CHIP_PLXSD, &hc->chip); /* prevent resync */ pci_write_config_word(hc->pci_dev, PCI_COMMAND, 0); if (hc->pci_membase) - iounmap((void *)hc->pci_membase); + iounmap(hc->pci_membase); if (hc->plx_membase) - iounmap((void *)hc->plx_membase); + iounmap(hc->plx_membase); if (hc->pci_iobase) release_region(hc->pci_iobase, 8); @@ -1080,7 +1083,8 @@ init_chip(struct hfc_multi *hc) u_long flags, val, val2 = 0, rev; int i, err = 0; u_char r_conf_en, rval; - u_int *plx_acc_32, pv; + void __iomem *plx_acc_32; + u_int pv; u_long plx_flags, hfc_flags; int plx_count; struct hfc_multi *pos, *next, *plx_last_hc; @@ -1154,7 +1158,7 @@ init_chip(struct hfc_multi *hc) printk(KERN_DEBUG "%s: initializing PLXSD card %d\n", __func__, hc->id + 1); spin_lock_irqsave(&plx_lock, plx_flags); - plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC); + plx_acc_32 = hc->plx_membase + PLX_GPIOC; writel(PLX_GPIOC_INIT, plx_acc_32); pv = readl(plx_acc_32); /* The first and the last cards are terminating the PCM bus */ @@ -1190,8 +1194,7 @@ init_chip(struct hfc_multi *hc) "we disable termination\n", __func__, plx_last_hc->id + 1); spin_lock_irqsave(&plx_lock, plx_flags); - plx_acc_32 = (u_int *)(plx_last_hc->plx_membase - + PLX_GPIOC); + plx_acc_32 = plx_last_hc->plx_membase + PLX_GPIOC; pv = readl(plx_acc_32); pv &= ~PLX_TERM_ON; writel(pv, plx_acc_32); @@ -1240,7 +1243,7 @@ init_chip(struct hfc_multi *hc) /* Speech Design PLX bridge pcm and sync mode */ if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { spin_lock_irqsave(&plx_lock, plx_flags); - plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC); + plx_acc_32 = hc->plx_membase + PLX_GPIOC; pv = readl(plx_acc_32); /* Connect PCM */ if (hc->hw.r_pcm_md0 & V_PCM_MD) { @@ -1352,8 +1355,7 @@ init_chip(struct hfc_multi *hc) /* retry with master clock */ if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { spin_lock_irqsave(&plx_lock, plx_flags); - plx_acc_32 = (u_int *)(hc->plx_membase + - PLX_GPIOC); + plx_acc_32 = hc->plx_membase + PLX_GPIOC; pv = readl(plx_acc_32); pv |= PLX_MASTER_EN | PLX_SLAVE_EN_N; pv |= PLX_SYNC_O_EN; @@ -1389,7 +1391,7 @@ init_chip(struct hfc_multi *hc) if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip)) plxsd_master = 1; spin_lock_irqsave(&plx_lock, plx_flags); - plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC); + plx_acc_32 = hc->plx_membase + PLX_GPIOC; pv = readl(plx_acc_32); pv |= PLX_DSP_RES_N; writel(pv, plx_acc_32); @@ -2586,7 +2588,8 @@ hfcmulti_interrupt(int intno, void *dev_id) struct dchannel *dch; u_char r_irq_statech, status, r_irq_misc, r_irq_oview; int i; - u_short *plx_acc, wval; + void __iomem *plx_acc; + u_short wval; u_char e1_syncsta, temp; u_long flags; @@ -2606,7 +2609,7 @@ hfcmulti_interrupt(int intno, void *dev_id) if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { spin_lock_irqsave(&plx_lock, flags); - plx_acc = (u_short *)(hc->plx_membase + PLX_INTCSR); + plx_acc = hc->plx_membase + PLX_INTCSR; wval = readw(plx_acc); spin_unlock_irqrestore(&plx_lock, flags); if (!(wval & PLX_INTCSR_LINTI1_STATUS)) @@ -4091,7 +4094,7 @@ init_card(struct hfc_multi *hc) { int err = -EIO; u_long flags; - u_short *plx_acc; + void __iomem *plx_acc; u_long plx_flags; if (debug & DEBUG_HFCMULTI_INIT) @@ -4113,7 +4116,7 @@ init_card(struct hfc_multi *hc) if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { spin_lock_irqsave(&plx_lock, plx_flags); - plx_acc = (u_short *)(hc->plx_membase+PLX_INTCSR); + plx_acc = hc->plx_membase + PLX_INTCSR; writew((PLX_INTCSR_PCIINT_ENABLE | PLX_INTCSR_LINTI1_ENABLE), plx_acc); /* enable PCI & LINT1 irq */ spin_unlock_irqrestore(&plx_lock, plx_flags); @@ -4162,7 +4165,7 @@ init_card(struct hfc_multi *hc) error: if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { spin_lock_irqsave(&plx_lock, plx_flags); - plx_acc = (u_short *)(hc->plx_membase+PLX_INTCSR); + plx_acc = hc->plx_membase + PLX_INTCSR; writew(0x00, plx_acc); /*disable IRQs*/ spin_unlock_irqrestore(&plx_lock, plx_flags); } diff --git a/drivers/isdn/hysdn/hysdn_net.c b/drivers/isdn/hysdn/hysdn_net.c index 3f2a0a20c19b040538ba23fcce7d3d346d2e0f89..7ee5bd9f2bb42db57312be67c22f734aa72f14e4 100644 --- a/drivers/isdn/hysdn/hysdn_net.c +++ b/drivers/isdn/hysdn/hysdn_net.c @@ -76,7 +76,7 @@ static int net_open(struct net_device *dev) { struct in_device *in_dev; - hysdn_card *card = dev->priv; + hysdn_card *card = dev->ml_priv; int i; netif_start_queue(dev); /* start tx-queueing */ @@ -159,7 +159,7 @@ net_send_packet(struct sk_buff *skb, struct net_device *dev) spin_unlock_irq(&lp->lock); if (lp->sk_count <= 3) { - schedule_work(&((hysdn_card *) dev->priv)->irq_queue); + schedule_work(&((hysdn_card *) dev->ml_priv)->irq_queue); } return (0); /* success */ } /* net_send_packet */ @@ -295,7 +295,7 @@ hysdn_net_create(hysdn_card * card) kfree(dev); return (i); } - dev->priv = card; /* remember pointer to own data structure */ + dev->ml_priv = card; /* remember pointer to own data structure */ card->netif = dev; /* setup the local pointer */ if (card->debug_flags & LOG_NET_INIT) diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c index 484299b031f82d49b91dfeb303099a1920824933..8f9f4912de3243e4b118c09c4a346a006dc73981 100644 --- a/drivers/isdn/hysdn/hysdn_procconf.c +++ b/drivers/isdn/hysdn/hysdn_procconf.c @@ -246,7 +246,8 @@ hysdn_conf_open(struct inode *ino, struct file *filep) } if (card->debug_flags & (LOG_PROC_OPEN | LOG_PROC_ALL)) hysdn_addlog(card, "config open for uid=%d gid=%d mode=0x%x", - filep->f_uid, filep->f_gid, filep->f_mode); + filep->f_cred->fsuid, filep->f_cred->fsgid, + filep->f_mode); if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) { /* write only access -> write boot file or conf line */ @@ -331,7 +332,8 @@ hysdn_conf_close(struct inode *ino, struct file *filep) } if (card->debug_flags & (LOG_PROC_OPEN | LOG_PROC_ALL)) hysdn_addlog(card, "config close for uid=%d gid=%d mode=0x%x", - filep->f_uid, filep->f_gid, filep->f_mode); + filep->f_cred->fsuid, filep->f_cred->fsgid, + filep->f_mode); if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) { /* write only access -> write boot file or conf line */ diff --git a/drivers/isdn/i4l/isdn_concap.c b/drivers/isdn/i4l/isdn_concap.c index 0193b6f7c70ca705142fe0d7731dd242b4eacbb6..46048e55f241157663a41c5c2fcbe32ecbf50f63 100644 --- a/drivers/isdn/i4l/isdn_concap.c +++ b/drivers/isdn/i4l/isdn_concap.c @@ -42,7 +42,7 @@ static int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *skb) { struct net_device *ndev = concap -> net_dev; - isdn_net_dev *nd = ((isdn_net_local *) ndev->priv)->netdev; + isdn_net_dev *nd = ((isdn_net_local *) netdev_priv(ndev))->netdev; isdn_net_local *lp = isdn_net_get_locked_lp(nd); IX25DEBUG( "isdn_concap_dl_data_req: %s \n", concap->net_dev->name); @@ -61,7 +61,7 @@ static int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff * static int isdn_concap_dl_connect_req(struct concap_proto *concap) { struct net_device *ndev = concap -> net_dev; - isdn_net_local *lp = (isdn_net_local *) ndev->priv; + isdn_net_local *lp = (isdn_net_local *) netdev_priv(ndev); int ret; IX25DEBUG( "isdn_concap_dl_connect_req: %s \n", ndev -> name); diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c index 1bfc55d7a26c745d226f840edcfd784dd6930985..023ea11d2f9e399dfb5161e27721f3104a8d204d 100644 --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c @@ -120,7 +120,7 @@ static __inline__ int isdn_net_device_busy(isdn_net_local *lp) return 0; if (lp->master) - nd = ((isdn_net_local *) lp->master->priv)->netdev; + nd = ISDN_MASTER_PRIV(lp)->netdev; else nd = lp->netdev; @@ -213,9 +213,9 @@ isdn_net_reset(struct net_device *dev) { #ifdef CONFIG_ISDN_X25 struct concap_device_ops * dops = - ( (isdn_net_local *) dev->priv ) -> dops; + ((isdn_net_local *) netdev_priv(dev))->dops; struct concap_proto * cprot = - ( (isdn_net_local *) dev->priv ) -> netdev -> cprot; + ((isdn_net_local *) netdev_priv(dev))->netdev->cprot; #endif #ifdef CONFIG_ISDN_X25 if( cprot && cprot -> pops && dops ) @@ -250,11 +250,11 @@ isdn_net_open(struct net_device *dev) } /* If this interface has slaves, start them also */ - - if ((p = (((isdn_net_local *) dev->priv)->slave))) { + p = MASTER_TO_SLAVE(dev); + if (p) { while (p) { isdn_net_reset(p); - p = (((isdn_net_local *) p->priv)->slave); + p = MASTER_TO_SLAVE(p); } } isdn_lock_drivers(); @@ -483,7 +483,7 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c) isdn_net_ciscohdlck_connected(lp); if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) { if (lp->master) { /* is lp a slave? */ - isdn_net_dev *nd = ((isdn_net_local *)lp->master->priv)->netdev; + isdn_net_dev *nd = ISDN_MASTER_PRIV(lp)->netdev; isdn_net_add_to_bundle(nd, lp); } } @@ -823,7 +823,7 @@ isdn_net_dial(void) void isdn_net_hangup(struct net_device *d) { - isdn_net_local *lp = (isdn_net_local *) d->priv; + isdn_net_local *lp = (isdn_net_local *) netdev_priv(d); isdn_ctrl cmd; #ifdef CONFIG_ISDN_X25 struct concap_proto *cprot = lp->netdev->cprot; @@ -832,7 +832,7 @@ isdn_net_hangup(struct net_device *d) if (lp->flags & ISDN_NET_CONNECTED) { if (lp->slave != NULL) { - isdn_net_local *slp = (isdn_net_local *)lp->slave->priv; + isdn_net_local *slp = ISDN_SLAVE_PRIV(lp); if (slp->flags & ISDN_NET_CONNECTED) { printk(KERN_INFO "isdn_net: hang up slave %s before %s\n", @@ -865,8 +865,8 @@ isdn_net_hangup(struct net_device *d) } typedef struct { - unsigned short source; - unsigned short dest; + __be16 source; + __be16 dest; } ip_ports; static void @@ -890,15 +890,15 @@ isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp) proto = ETH_P_IP; switch (lp->p_encap) { case ISDN_NET_ENCAP_IPTYP: - proto = ntohs(*(unsigned short *) &buf[0]); + proto = ntohs(*(__be16 *)&buf[0]); p = &buf[2]; break; case ISDN_NET_ENCAP_ETHER: - proto = ntohs(*(unsigned short *) &buf[12]); + proto = ntohs(*(__be16 *)&buf[12]); p = &buf[14]; break; case ISDN_NET_ENCAP_CISCOHDLC: - proto = ntohs(*(unsigned short *) &buf[2]); + proto = ntohs(*(__be16 *)&buf[2]); p = &buf[4]; break; #ifdef CONFIG_ISDN_PPP @@ -942,18 +942,12 @@ isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp) strcpy(addinfo, " IDP"); break; } - printk(KERN_INFO - "OPEN: %d.%d.%d.%d -> %d.%d.%d.%d%s\n", - - p[12], p[13], p[14], p[15], - p[16], p[17], p[18], p[19], - addinfo); + printk(KERN_INFO "OPEN: %pI4 -> %pI4%s\n", + p + 12, p + 16, addinfo); break; case ETH_P_ARP: - printk(KERN_INFO - "OPEN: ARP %d.%d.%d.%d -> *.*.*.* ?%d.%d.%d.%d\n", - p[14], p[15], p[16], p[17], - p[24], p[25], p[26], p[27]); + printk(KERN_INFO "OPEN: ARP %pI4 -> *.*.*.* ?%pI4\n", + p + 14, p + 24); break; } } @@ -1054,10 +1048,10 @@ isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb) { isdn_net_dev *nd; isdn_net_local *slp; - isdn_net_local *lp = (isdn_net_local *) ndev->priv; + isdn_net_local *lp = (isdn_net_local *) netdev_priv(ndev); int retv = 0; - if (((isdn_net_local *) (ndev->priv))->master) { + if (((isdn_net_local *) netdev_priv(ndev))->master) { printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__); dev_kfree_skb(skb); return 0; @@ -1069,7 +1063,7 @@ isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb) return isdn_ppp_xmit(skb, ndev); } #endif - nd = ((isdn_net_local *) ndev->priv)->netdev; + nd = ((isdn_net_local *) netdev_priv(ndev))->netdev; lp = isdn_net_get_locked_lp(nd); if (!lp) { printk(KERN_WARNING "%s: all channels busy - requeuing!\n", ndev->name); @@ -1096,9 +1090,9 @@ isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb) } else { /* subsequent overload: if slavedelay exceeded, start dialing */ if (time_after(jiffies, lp->sqfull_stamp + lp->slavedelay)) { - slp = lp->slave->priv; + slp = ISDN_SLAVE_PRIV(lp); if (!(slp->flags & ISDN_NET_CONNECTED)) { - isdn_net_force_dial_lp((isdn_net_local *) lp->slave->priv); + isdn_net_force_dial_lp(ISDN_SLAVE_PRIV(lp)); } } } @@ -1118,7 +1112,7 @@ isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb) static void isdn_net_adjust_hdr(struct sk_buff *skb, struct net_device *dev) { - isdn_net_local *lp = (isdn_net_local *) dev->priv; + isdn_net_local *lp = (isdn_net_local *) netdev_priv(dev); if (!skb) return; if (lp->p_encap == ISDN_NET_ENCAP_ETHER) { @@ -1133,7 +1127,7 @@ isdn_net_adjust_hdr(struct sk_buff *skb, struct net_device *dev) static void isdn_net_tx_timeout(struct net_device * ndev) { - isdn_net_local *lp = (isdn_net_local *) ndev->priv; + isdn_net_local *lp = (isdn_net_local *) netdev_priv(ndev); printk(KERN_WARNING "isdn_tx_timeout dev %s dialstate %d\n", ndev->name, lp->dialstate); if (!lp->dialstate){ @@ -1167,7 +1161,7 @@ static void isdn_net_tx_timeout(struct net_device * ndev) static int isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) { - isdn_net_local *lp = (isdn_net_local *) ndev->priv; + isdn_net_local *lp = (isdn_net_local *) netdev_priv(ndev); #ifdef CONFIG_ISDN_X25 struct concap_proto * cprot = lp -> netdev -> cprot; /* At this point hard_start_xmit() passes control to the encapsulation @@ -1316,7 +1310,7 @@ isdn_net_close(struct net_device *dev) struct net_device *p; #ifdef CONFIG_ISDN_X25 struct concap_proto * cprot = - ( (isdn_net_local *) dev->priv ) -> netdev -> cprot; + ((isdn_net_local *) netdev_priv(dev))->netdev->cprot; /* printk(KERN_DEBUG "isdn_net_close %s\n" , dev-> name ); */ #endif @@ -1324,17 +1318,18 @@ isdn_net_close(struct net_device *dev) if( cprot && cprot -> pops ) cprot -> pops -> close( cprot ); #endif netif_stop_queue(dev); - if ((p = (((isdn_net_local *) dev->priv)->slave))) { + p = MASTER_TO_SLAVE(dev); + if (p) { /* If this interface has slaves, stop them also */ while (p) { #ifdef CONFIG_ISDN_X25 - cprot = ( (isdn_net_local *) p->priv ) + cprot = ((isdn_net_local *) netdev_priv(p)) -> netdev -> cprot; if( cprot && cprot -> pops ) cprot -> pops -> close( cprot ); #endif isdn_net_hangup(p); - p = (((isdn_net_local *) p->priv)->slave); + p = MASTER_TO_SLAVE(p); } } isdn_net_hangup(dev); @@ -1348,7 +1343,7 @@ isdn_net_close(struct net_device *dev) static struct net_device_stats * isdn_net_get_stats(struct net_device *dev) { - isdn_net_local *lp = (isdn_net_local *) dev->priv; + isdn_net_local *lp = (isdn_net_local *) netdev_priv(dev); return &lp->stats; } @@ -1361,7 +1356,7 @@ isdn_net_get_stats(struct net_device *dev) * This is normal practice and works for any 'now in use' protocol. */ -static unsigned short +static __be16 isdn_net_type_trans(struct sk_buff *skb, struct net_device *dev) { struct ethhdr *eth; @@ -1427,7 +1422,7 @@ isdn_net_ciscohdlck_alloc_skb(isdn_net_local *lp, int len) static int isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - isdn_net_local *lp = (isdn_net_local *) dev->priv; + isdn_net_local *lp = (isdn_net_local *) netdev_priv(dev); unsigned long len = 0; unsigned long expires = 0; int tmp = 0; @@ -1539,15 +1534,16 @@ isdn_net_ciscohdlck_slarp_send_keepalive(unsigned long data) p = skb_put(skb, 4 + 14); /* cisco header */ - p += put_u8 (p, CISCO_ADDR_UNICAST); - p += put_u8 (p, CISCO_CTRL); - p += put_u16(p, CISCO_TYPE_SLARP); + *(u8 *)(p + 0) = CISCO_ADDR_UNICAST; + *(u8 *)(p + 1) = CISCO_CTRL; + *(__be16 *)(p + 2) = cpu_to_be16(CISCO_TYPE_SLARP); /* slarp keepalive */ - p += put_u32(p, CISCO_SLARP_KEEPALIVE); - p += put_u32(p, lp->cisco_myseq); - p += put_u32(p, lp->cisco_yourseq); - p += put_u16(p, 0xffff); // reliablity, always 0xffff + *(__be32 *)(p + 4) = cpu_to_be32(CISCO_SLARP_KEEPALIVE); + *(__be32 *)(p + 8) = cpu_to_be32(lp->cisco_myseq); + *(__be32 *)(p + 12) = cpu_to_be32(lp->cisco_yourseq); + *(__be16 *)(p + 16) = cpu_to_be16(0xffff); // reliablity, always 0xffff + p += 18; isdn_net_write_super(lp, skb); @@ -1569,15 +1565,16 @@ isdn_net_ciscohdlck_slarp_send_request(isdn_net_local *lp) p = skb_put(skb, 4 + 14); /* cisco header */ - p += put_u8 (p, CISCO_ADDR_UNICAST); - p += put_u8 (p, CISCO_CTRL); - p += put_u16(p, CISCO_TYPE_SLARP); + *(u8 *)(p + 0) = CISCO_ADDR_UNICAST; + *(u8 *)(p + 1) = CISCO_CTRL; + *(__be16 *)(p + 2) = cpu_to_be16(CISCO_TYPE_SLARP); /* slarp request */ - p += put_u32(p, CISCO_SLARP_REQUEST); - p += put_u32(p, 0); // address - p += put_u32(p, 0); // netmask - p += put_u16(p, 0); // unused + *(__be32 *)(p + 4) = cpu_to_be32(CISCO_SLARP_REQUEST); + *(__be32 *)(p + 8) = cpu_to_be32(0); // address + *(__be32 *)(p + 12) = cpu_to_be32(0); // netmask + *(__be16 *)(p + 16) = cpu_to_be16(0); // unused + p += 18; isdn_net_write_super(lp, skb); } @@ -1634,18 +1631,17 @@ isdn_net_ciscohdlck_slarp_send_reply(isdn_net_local *lp) p = skb_put(skb, 4 + 14); /* cisco header */ - p += put_u8 (p, CISCO_ADDR_UNICAST); - p += put_u8 (p, CISCO_CTRL); - p += put_u16(p, CISCO_TYPE_SLARP); + *(u8 *)(p + 0) = CISCO_ADDR_UNICAST; + *(u8 *)(p + 1) = CISCO_CTRL; + *(__be16 *)(p + 2) = cpu_to_be16(CISCO_TYPE_SLARP); /* slarp reply, send own ip/netmask; if values are nonsense remote * should think we are unable to provide it with an address via SLARP */ - p += put_u32(p, CISCO_SLARP_REPLY); - *(__be32 *)p = addr; // address - p += 4; - *(__be32 *)p = mask; // netmask - p += 4; - p += put_u16(p, 0); // unused + *(__be32 *)(p + 4) = cpu_to_be32(CISCO_SLARP_REPLY); + *(__be32 *)(p + 8) = addr; // address + *(__be32 *)(p + 12) = mask; // netmask + *(__be16 *)(p + 16) = cpu_to_be16(0); // unused + p += 18; isdn_net_write_super(lp, skb); } @@ -1656,44 +1652,39 @@ isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb) unsigned char *p; int period; u32 code; - u32 my_seq, addr; - u32 your_seq, mask; - u32 local; + u32 my_seq; + u32 your_seq; + __be32 local; + __be32 *addr, *mask; u16 unused; if (skb->len < 14) return; p = skb->data; - p += get_u32(p, &code); - + code = be32_to_cpup((__be32 *)p); + p += 4; + switch (code) { case CISCO_SLARP_REQUEST: lp->cisco_yourseq = 0; isdn_net_ciscohdlck_slarp_send_reply(lp); break; case CISCO_SLARP_REPLY: - addr = ntohl(*(u32 *)p); - mask = ntohl(*(u32 *)(p+4)); - if (mask != 0xfffffffc) + addr = (__be32 *)p; + mask = (__be32 *)(p + 4); + if (*mask != cpu_to_be32(0xfffffffc)) goto slarp_reply_out; - if ((addr & 3) == 0 || (addr & 3) == 3) + if ((*addr & cpu_to_be32(3)) == cpu_to_be32(0) || + (*addr & cpu_to_be32(3)) == cpu_to_be32(3)) goto slarp_reply_out; - local = addr ^ 3; - printk(KERN_INFO "%s: got slarp reply: " - "remote ip: %d.%d.%d.%d, " - "local ip: %d.%d.%d.%d " - "mask: %d.%d.%d.%d\n", - lp->netdev->dev->name, - HIPQUAD(addr), - HIPQUAD(local), - HIPQUAD(mask)); + local = *addr ^ cpu_to_be32(3); + printk(KERN_INFO "%s: got slarp reply: remote ip: %pI4, local ip: %pI4 mask: %pI4\n", + lp->netdev->dev->name, addr, &local, mask); break; slarp_reply_out: - printk(KERN_INFO "%s: got invalid slarp " - "reply (%d.%d.%d.%d/%d.%d.%d.%d) " - "- ignored\n", lp->netdev->dev->name, - HIPQUAD(addr), HIPQUAD(mask)); + printk(KERN_INFO "%s: got invalid slarp reply (%pI4/%pI4) - ignored\n", + lp->netdev->dev->name, addr, mask); break; case CISCO_SLARP_KEEPALIVE: period = (int)((jiffies - lp->cisco_last_slarp_in @@ -1707,9 +1698,10 @@ isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb) lp->cisco_keepalive_period); } lp->cisco_last_slarp_in = jiffies; - p += get_u32(p, &my_seq); - p += get_u32(p, &your_seq); - p += get_u16(p, &unused); + my_seq = be32_to_cpup((__be32 *)(p + 0)); + your_seq = be32_to_cpup((__be32 *)(p + 4)); + unused = be16_to_cpup((__be16 *)(p + 8)); + p += 10; lp->cisco_yourseq = my_seq; lp->cisco_mineseen = your_seq; break; @@ -1728,9 +1720,10 @@ isdn_net_ciscohdlck_receive(isdn_net_local *lp, struct sk_buff *skb) goto out_free; p = skb->data; - p += get_u8 (p, &addr); - p += get_u8 (p, &ctrl); - p += get_u16(p, &type); + addr = *(u8 *)(p + 0); + ctrl = *(u8 *)(p + 1); + type = be16_to_cpup((__be16 *)(p + 2)); + p += 4; skb_pull(skb, 4); if (addr != CISCO_ADDR_UNICAST && addr != CISCO_ADDR_BROADCAST) { @@ -1771,7 +1764,7 @@ isdn_net_ciscohdlck_receive(isdn_net_local *lp, struct sk_buff *skb) static void isdn_net_receive(struct net_device *ndev, struct sk_buff *skb) { - isdn_net_local *lp = (isdn_net_local *) ndev->priv; + isdn_net_local *lp = (isdn_net_local *) netdev_priv(ndev); isdn_net_local *olp = lp; /* original 'lp' */ #ifdef CONFIG_ISDN_X25 struct concap_proto *cprot = lp -> netdev -> cprot; @@ -1785,7 +1778,7 @@ isdn_net_receive(struct net_device *ndev, struct sk_buff *skb) * handle master's statistics and hangup-timeout */ ndev = lp->master; - lp = (isdn_net_local *) ndev->priv; + lp = (isdn_net_local *) netdev_priv(ndev); lp->stats.rx_packets++; lp->stats.rx_bytes += skb->len; } @@ -1825,7 +1818,7 @@ isdn_net_receive(struct net_device *ndev, struct sk_buff *skb) /* IP with type field */ olp->huptimer = 0; lp->huptimer = 0; - skb->protocol = *(unsigned short *) &(skb->data[0]); + skb->protocol = *(__be16 *)&(skb->data[0]); skb_pull(skb, 2); if (*(unsigned short *) skb->data == 0xFFFF) skb->protocol = htons(ETH_P_802_3); @@ -1886,7 +1879,7 @@ static int isdn_net_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, const void *daddr, const void *saddr, unsigned plen) { - isdn_net_local *lp = dev->priv; + isdn_net_local *lp = netdev_priv(dev); unsigned char *p; ushort len = 0; @@ -1907,20 +1900,21 @@ static int isdn_net_header(struct sk_buff *skb, struct net_device *dev, break; case ISDN_NET_ENCAP_IPTYP: /* ethernet type field */ - *((ushort *) skb_push(skb, 2)) = htons(type); + *((__be16 *)skb_push(skb, 2)) = htons(type); len = 2; break; case ISDN_NET_ENCAP_UIHDLC: /* HDLC with UI-Frames (for ispa with -h1 option) */ - *((ushort *) skb_push(skb, 2)) = htons(0x0103); + *((__be16 *)skb_push(skb, 2)) = htons(0x0103); len = 2; break; case ISDN_NET_ENCAP_CISCOHDLC: case ISDN_NET_ENCAP_CISCOHDLCK: p = skb_push(skb, 4); - p += put_u8 (p, CISCO_ADDR_UNICAST); - p += put_u8 (p, CISCO_CTRL); - p += put_u16(p, type); + *(u8 *)(p + 0) = CISCO_ADDR_UNICAST; + *(u8 *)(p + 1) = CISCO_CTRL; + *(__be16 *)(p + 2) = cpu_to_be16(type); + p += 4; len = 4; break; #ifdef CONFIG_ISDN_X25 @@ -1942,7 +1936,7 @@ static int isdn_net_rebuild_header(struct sk_buff *skb) { struct net_device *dev = skb->dev; - isdn_net_local *lp = dev->priv; + isdn_net_local *lp = netdev_priv(dev); int ret = 0; if (lp->p_encap == ISDN_NET_ENCAP_ETHER) { @@ -1972,7 +1966,7 @@ isdn_net_rebuild_header(struct sk_buff *skb) static int isdn_header_cache(const struct neighbour *neigh, struct hh_cache *hh) { const struct net_device *dev = neigh->dev; - isdn_net_local *lp = dev->priv; + isdn_net_local *lp = netdev_priv(dev); if (lp->p_encap == ISDN_NET_ENCAP_ETHER) return eth_header_cache(neigh, hh); @@ -1983,9 +1977,9 @@ static void isdn_header_cache_update(struct hh_cache *hh, const struct net_device *dev, const unsigned char *haddr) { - isdn_net_local *lp = dev->priv; + isdn_net_local *lp = netdev_priv(dev); if (lp->p_encap == ISDN_NET_ENCAP_ETHER) - return eth_header_cache_update(hh, dev, haddr); + eth_header_cache_update(hh, dev, haddr); } static const struct header_ops isdn_header_ops = { @@ -2298,16 +2292,16 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup) * it's master and parent slave is online. If not, reject the call. */ if (lp->master) { - isdn_net_local *mlp = (isdn_net_local *) lp->master->priv; + isdn_net_local *mlp = ISDN_MASTER_PRIV(lp); printk(KERN_DEBUG "ICALLslv: %s\n", p->dev->name); printk(KERN_DEBUG "master=%s\n", lp->master->name); if (mlp->flags & ISDN_NET_CONNECTED) { printk(KERN_DEBUG "master online\n"); /* Master is online, find parent-slave (master if first slave) */ while (mlp->slave) { - if ((isdn_net_local *) mlp->slave->priv == lp) + if (ISDN_SLAVE_PRIV(mlp) == lp) break; - mlp = (isdn_net_local *) mlp->slave->priv; + mlp = ISDN_SLAVE_PRIV(mlp); } } else printk(KERN_DEBUG "master offline\n"); @@ -2519,7 +2513,7 @@ isdn_net_force_dial(char *name) */ static void _isdn_setup(struct net_device *dev) { - isdn_net_local *lp = dev->priv; + isdn_net_local *lp = netdev_priv(dev); dev->flags = IFF_NOARP | IFF_POINTOPOINT; lp->p_encap = ISDN_NET_ENCAP_RAWIP; @@ -2575,20 +2569,20 @@ isdn_net_new(char *name, struct net_device *master) kfree(netdev); return NULL; } - netdev->local = netdev->dev->priv; + netdev->local = netdev_priv(netdev->dev); netdev->dev->init = isdn_net_init; if (master) { /* Device shall be a slave */ - struct net_device *p = (((isdn_net_local *) master->priv)->slave); + struct net_device *p = MASTER_TO_SLAVE(master); struct net_device *q = master; netdev->local->master = master; /* Put device at end of slave-chain */ while (p) { q = p; - p = (((isdn_net_local *) p->priv)->slave); + p = MASTER_TO_SLAVE(p); } - ((isdn_net_local *) q->priv)->slave = netdev->dev; + MASTER_TO_SLAVE(q) = netdev->dev; } else { /* Device shall be a master */ /* @@ -3086,7 +3080,7 @@ isdn_net_force_hangup(char *name) /* If this interface has slaves, do a hangup for them also. */ while (q) { isdn_net_hangup(q); - q = (((isdn_net_local *) q->priv)->slave); + q = MASTER_TO_SLAVE(q); } isdn_net_hangup(p->dev); return 0; @@ -3116,8 +3110,10 @@ isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q) isdn_unexclusive_channel(p->local->pre_device, p->local->pre_channel); if (p->local->master) { /* It's a slave-device, so update master's slave-pointer if necessary */ - if (((isdn_net_local *) (p->local->master->priv))->slave == p->dev) - ((isdn_net_local *) (p->local->master->priv))->slave = p->local->slave; + if (((isdn_net_local *) ISDN_MASTER_PRIV(p->local))->slave == + p->dev) + ((isdn_net_local *)ISDN_MASTER_PRIV(p->local))->slave = + p->local->slave; } else { /* Unregister only if it's a master-device */ unregister_netdev(p->dev); diff --git a/drivers/isdn/i4l/isdn_net.h b/drivers/isdn/i4l/isdn_net.h index be4949715d55f605206f99e86430fe0c46ff1f1d..74032d0881efab82d80b93193a2ebfc372e9bd58 100644 --- a/drivers/isdn/i4l/isdn_net.h +++ b/drivers/isdn/i4l/isdn_net.h @@ -56,6 +56,11 @@ extern void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb); #define ISDN_NET_MAX_QUEUE_LENGTH 2 +#define ISDN_MASTER_PRIV(lp) ((isdn_net_local *) netdev_priv(lp->master)) +#define ISDN_SLAVE_PRIV(lp) ((isdn_net_local *) netdev_priv(lp->slave)) +#define MASTER_TO_SLAVE(master) \ + (((isdn_net_local *) netdev_priv(master))->slave) + /* * is this particular channel busy? */ @@ -126,7 +131,7 @@ static __inline__ void isdn_net_rm_from_bundle(isdn_net_local *lp) unsigned long flags; if (lp->master) - master_lp = (isdn_net_local *) lp->master->priv; + master_lp = ISDN_MASTER_PRIV(lp); // printk(KERN_DEBUG "%s: lp:%s(%p) mlp:%s(%p) last(%p) next(%p) mndq(%p)\n", // __func__, lp->name, lp, master_lp->name, master_lp, lp->last, lp->next, master_lp->netdev->queue); @@ -145,46 +150,3 @@ static __inline__ void isdn_net_rm_from_bundle(isdn_net_local *lp) spin_unlock_irqrestore(&master_lp->netdev->queue_lock, flags); } -static inline int -put_u8(unsigned char *p, u8 x) -{ - *p = x; - return 1; -} - -static inline int -put_u16(unsigned char *p, u16 x) -{ - *((u16 *)p) = htons(x); - return 2; -} - -static inline int -put_u32(unsigned char *p, u32 x) -{ - *((u32 *)p) = htonl(x); - return 4; -} - -static inline int -get_u8(unsigned char *p, u8 *x) -{ - *x = *p; - return 1; -} - -static inline int -get_u16(unsigned char *p, u16 *x) -{ - *x = ntohs(*((u16 *)p)); - return 2; -} - -static inline int -get_u32(unsigned char *p, u32 *x) -{ - *x = ntohl(*((u32 *)p)); - return 4; -} - - diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c index 77c280ef2eb64ddbb81cff6b78c40bcf7e302b3e..a3551dd0324d420664ea30df2978b772434ce418 100644 --- a/drivers/isdn/i4l/isdn_ppp.c +++ b/drivers/isdn/i4l/isdn_ppp.c @@ -1040,7 +1040,7 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff is = ippp_table[slot]; if (lp->master) { // FIXME? - mlp = (isdn_net_local *) lp->master->priv; + mlp = ISDN_MASTER_PRIV(lp); slot = mlp->ppp_slot; if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "isdn_ppp_push_higher: master->ppp_slot(%d)\n", @@ -1223,7 +1223,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev) struct ippp_struct *ipt,*ipts; int slot, retval = 0; - mlp = (isdn_net_local *) (netdev->priv); + mlp = (isdn_net_local *) netdev_priv(netdev); nd = mlp->netdev; /* get master lp */ slot = mlp->ppp_slot; @@ -1289,10 +1289,10 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev) *skb_push(skb, 4) = 1; /* indicate outbound */ { - u_int16_t *p = (u_int16_t *) skb->data; + __be16 *p = (__be16 *)skb->data; p++; - *p = htons(proto); + *p = htons(proto); } if (ipt->pass_filter @@ -1487,10 +1487,10 @@ int isdn_ppp_autodial_filter(struct sk_buff *skb, isdn_net_local *lp) *skb_pull(skb, IPPP_MAX_HEADER - 4) = 1; /* indicate outbound */ { - u_int16_t *p = (u_int16_t *) skb->data; + __be16 *p = (__be16 *)skb->data; p++; - *p = htons(proto); + *p = htons(proto); } drop |= is->pass_filter @@ -1810,14 +1810,14 @@ static u32 isdn_ppp_mp_get_seq( int short_seq, if( !short_seq ) { - seq = ntohl(*(u32*)skb->data) & MP_LONGSEQ_MASK; + seq = ntohl(*(__be32 *)skb->data) & MP_LONGSEQ_MASK; skb_push(skb,1); } else { /* convert 12-bit short seq number to 24-bit long one */ - seq = ntohs(*(u16*)skb->data) & MP_SHORTSEQ_MASK; + seq = ntohs(*(__be16 *)skb->data) & MP_SHORTSEQ_MASK; /* check for seqence wrap */ if( !(seq & MP_SHORTSEQ_MAXBIT) && @@ -2013,7 +2013,7 @@ isdn_ppp_dev_ioctl_stats(int slot, struct ifreq *ifr, struct net_device *dev) { struct ppp_stats __user *res = ifr->ifr_data; struct ppp_stats t; - isdn_net_local *lp = (isdn_net_local *) dev->priv; + isdn_net_local *lp = (isdn_net_local *) netdev_priv(dev); if (!access_ok(VERIFY_WRITE, res, sizeof(struct ppp_stats))) return -EFAULT; @@ -2052,7 +2052,7 @@ isdn_ppp_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { int error=0; int len; - isdn_net_local *lp = (isdn_net_local *) dev->priv; + isdn_net_local *lp = (isdn_net_local *) netdev_priv(dev); if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) @@ -2119,7 +2119,7 @@ isdn_ppp_dial_slave(char *name) sdev = lp->slave; while (sdev) { - isdn_net_local *mlp = (isdn_net_local *) sdev->priv; + isdn_net_local *mlp = (isdn_net_local *) netdev_priv(sdev); if (!(mlp->flags & ISDN_NET_CONNECTED)) break; sdev = mlp->slave; @@ -2127,7 +2127,7 @@ isdn_ppp_dial_slave(char *name) if (!sdev) return 2; - isdn_net_dial_req((isdn_net_local *) sdev->priv); + isdn_net_dial_req((isdn_net_local *) netdev_priv(sdev)); return 0; #else return -1; @@ -2150,10 +2150,10 @@ isdn_ppp_hangup_slave(char *name) sdev = lp->slave; while (sdev) { - isdn_net_local *mlp = (isdn_net_local *) sdev->priv; + isdn_net_local *mlp = (isdn_net_local *) netdev_priv(sdev); if (mlp->slave) { /* find last connected link in chain */ - isdn_net_local *nlp = (isdn_net_local *) mlp->slave->priv; + isdn_net_local *nlp = ISDN_SLAVE_PRIV(mlp); if (!(nlp->flags & ISDN_NET_CONNECTED)) break; @@ -2688,7 +2688,7 @@ static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, isdn_ppp_frame_log("ccp-rcv", skb->data, skb->len, 32, is->unit,lp->ppp_slot); if(lp->master) { - int slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot; + int slot = ISDN_MASTER_PRIV(lp)->ppp_slot; if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: slot(%d) out of range\n", __func__, slot); @@ -2875,7 +2875,7 @@ static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,lp->ppp_slot); if (lp->master) { - slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot; + slot = ISDN_MASTER_PRIV(lp)->ppp_slot; if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: slot(%d) out of range\n", __func__, slot); diff --git a/drivers/isdn/mISDN/core.c b/drivers/isdn/mISDN/core.c index 33068177b7c9486da1866344d2e25654ec2ad7d1..751665c448d0e9ebe284d6942cf709e4e29e9160 100644 --- a/drivers/isdn/mISDN/core.c +++ b/drivers/isdn/mISDN/core.c @@ -26,12 +26,12 @@ MODULE_LICENSE("GPL"); module_param(debug, uint, S_IRUGO | S_IWUSR); static LIST_HEAD(devices); -DEFINE_RWLOCK(device_lock); +static DEFINE_RWLOCK(device_lock); static u64 device_ids; #define MAX_DEVICE_ID 63 static LIST_HEAD(Bprotocols); -DEFINE_RWLOCK(bp_lock); +static DEFINE_RWLOCK(bp_lock); struct mISDNdevice *get_mdevice(u_int id) @@ -192,7 +192,7 @@ mISDN_unregister_Bprotocol(struct Bprotocol *bp) } EXPORT_SYMBOL(mISDN_unregister_Bprotocol); -int +static int mISDNInit(void) { int err; @@ -224,7 +224,7 @@ mISDNInit(void) return err; } -void mISDN_cleanup(void) +static void mISDN_cleanup(void) { misdn_sock_cleanup(); mISDN_timer_cleanup(); diff --git a/drivers/isdn/mISDN/dsp_audio.c b/drivers/isdn/mISDN/dsp_audio.c index 1c2dd56947737aa0cf82e07582c081bbeba199c5..de3795e3f43291ab2dd50df0bbc5f2975f4fb477 100644 --- a/drivers/isdn/mISDN/dsp_audio.c +++ b/drivers/isdn/mISDN/dsp_audio.c @@ -30,7 +30,7 @@ EXPORT_SYMBOL(dsp_audio_s16_to_law); /* alaw -> ulaw */ u8 dsp_audio_alaw_to_ulaw[256]; /* ulaw -> alaw */ -u8 dsp_audio_ulaw_to_alaw[256]; +static u8 dsp_audio_ulaw_to_alaw[256]; u8 dsp_silence; diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c index c2f51cc507608bada189220168178d05b34f908a..c884511e2d49038a465ab9e550a8e04739463de0 100644 --- a/drivers/isdn/mISDN/dsp_cmx.c +++ b/drivers/isdn/mISDN/dsp_cmx.c @@ -1540,11 +1540,13 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) schedule_work(&dsp->workq); } -u32 samplecount; +static u32 samplecount; struct timer_list dsp_spl_tl; u32 dsp_spl_jiffies; /* calculate the next time to fire */ -u32 dsp_start_jiffies; /* jiffies at the time, the calculation begins */ -struct timeval dsp_start_tv; /* time at start of calculation */ +#ifdef UNUSED +static u32 dsp_start_jiffies; /* jiffies at the time, the calculation begins */ +#endif /* UNUSED */ +static struct timeval dsp_start_tv; /* time at start of calculation */ void dsp_cmx_send(void *arg) diff --git a/drivers/isdn/mISDN/dsp_core.c b/drivers/isdn/mISDN/dsp_core.c index 2f10ed82c0db6a82756694f3290ceed075ad718b..1dc21d8034109f7a71b7f015baae329a994535b4 100644 --- a/drivers/isdn/mISDN/dsp_core.c +++ b/drivers/isdn/mISDN/dsp_core.c @@ -161,7 +161,7 @@ #include "core.h" #include "dsp.h" -const char *mISDN_dsp_revision = "2.0"; +static const char *mISDN_dsp_revision = "2.0"; static int debug; static int options; @@ -631,7 +631,6 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) int ret = 0; u8 *digits; int cont; - struct sk_buff *nskb; u_long flags; hh = mISDN_HEAD_P(skb); @@ -690,6 +689,7 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) digits = dsp_dtmf_goertzel_decode(dsp, skb->data, skb->len, (dsp_options&DSP_OPT_ULAW)?1:0); while (*digits) { + struct sk_buff *nskb; if (dsp_debug & DEBUG_DSP_DTMF) printk(KERN_DEBUG "%s: digit" "(%c) to layer %s\n", diff --git a/drivers/isdn/mISDN/dsp_hwec.c b/drivers/isdn/mISDN/dsp_hwec.c index eb892d9dd5c60db0b98631dcbdf8f86c062a0213..806a997fe7cc2907c7c21fb1cc130845b2cdcc9a 100644 --- a/drivers/isdn/mISDN/dsp_hwec.c +++ b/drivers/isdn/mISDN/dsp_hwec.c @@ -43,7 +43,7 @@ static struct mISDN_dsp_element dsp_hwec_p = { .free = NULL, .process_tx = NULL, .process_rx = NULL, - .num_args = sizeof(args) / sizeof(struct mISDN_dsp_element_arg), + .num_args = ARRAY_SIZE(args), .args = args, }; struct mISDN_dsp_element *dsp_hwec = &dsp_hwec_p; diff --git a/drivers/isdn/mISDN/dsp_pipeline.c b/drivers/isdn/mISDN/dsp_pipeline.c index 850260ab57d041cf7a55c86061bb134820021c35..5ee6651b45b903c3e1931fe316956e1166ce5d40 100644 --- a/drivers/isdn/mISDN/dsp_pipeline.c +++ b/drivers/isdn/mISDN/dsp_pipeline.c @@ -249,7 +249,7 @@ int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg) name = strsep(&tok, "("); args = strsep(&tok, ")"); if (args && !*args) - args = 0; + args = NULL; list_for_each_entry_safe(entry, n, &dsp_elements, list) if (!strcmp(entry->elem->name, name)) { diff --git a/drivers/isdn/mISDN/dsp_tones.c b/drivers/isdn/mISDN/dsp_tones.c index 23dd0dd215242dd37dfb111383181bdb3f194b4e..7a9af66f4b196b3e0ea79dff510e6c796df01038 100644 --- a/drivers/isdn/mISDN/dsp_tones.c +++ b/drivers/isdn/mISDN/dsp_tones.c @@ -231,120 +231,120 @@ dsp_audio_generate_ulaw_samples(void) * tone sequence definition * ****************************/ -struct pattern { +static struct pattern { int tone; u8 *data[10]; u32 *siz[10]; u32 seq[10]; } pattern[] = { {TONE_GERMAN_DIALTONE, - {DATA_GA, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_GA, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {DATA_GA, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_GA, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, {1900, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_GERMAN_OLDDIALTONE, - {DATA_GO, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_GO, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {DATA_GO, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_GO, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, {1998, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_AMERICAN_DIALTONE, - {DATA_DT, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_DT, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {DATA_DT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_DT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, {8000, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_GERMAN_DIALPBX, - {DATA_GA, DATA_S, DATA_GA, DATA_S, DATA_GA, DATA_S, 0, 0, 0, 0}, - {SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, 0, 0, 0, 0}, + {DATA_GA, DATA_S, DATA_GA, DATA_S, DATA_GA, DATA_S, NULL, NULL, NULL, NULL}, + {SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL}, {2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} }, {TONE_GERMAN_OLDDIALPBX, - {DATA_GO, DATA_S, DATA_GO, DATA_S, DATA_GO, DATA_S, 0, 0, 0, 0}, - {SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, 0, 0, 0, 0}, + {DATA_GO, DATA_S, DATA_GO, DATA_S, DATA_GO, DATA_S, NULL, NULL, NULL, NULL}, + {SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL}, {2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} }, {TONE_AMERICAN_DIALPBX, - {DATA_DT, DATA_S, DATA_DT, DATA_S, DATA_DT, DATA_S, 0, 0, 0, 0}, - {SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, 0, 0, 0, 0}, + {DATA_DT, DATA_S, DATA_DT, DATA_S, DATA_DT, DATA_S, NULL, NULL, NULL, NULL}, + {SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, NULL, NULL, NULL, NULL}, {2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} }, {TONE_GERMAN_RINGING, - {DATA_GA, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_GA, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, + {DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, {8000, 32000, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_GERMAN_OLDRINGING, - {DATA_GO, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_GO, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, + {DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, {8000, 40000, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_AMERICAN_RINGING, - {DATA_RI, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_RI, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, + {DATA_RI, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_RI, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, {8000, 32000, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_GERMAN_RINGPBX, - {DATA_GA, DATA_S, DATA_GA, DATA_S, 0, 0, 0, 0, 0, 0}, - {SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, 0, 0, 0, 0, 0, 0}, + {DATA_GA, DATA_S, DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL}, {4000, 4000, 4000, 28000, 0, 0, 0, 0, 0, 0} }, {TONE_GERMAN_OLDRINGPBX, - {DATA_GO, DATA_S, DATA_GO, DATA_S, 0, 0, 0, 0, 0, 0}, - {SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, 0, 0, 0, 0, 0, 0}, + {DATA_GO, DATA_S, DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL}, {4000, 4000, 4000, 28000, 0, 0, 0, 0, 0, 0} }, {TONE_AMERICAN_RINGPBX, - {DATA_RI, DATA_S, DATA_RI, DATA_S, 0, 0, 0, 0, 0, 0}, - {SIZE_RI, SIZE_S, SIZE_RI, SIZE_S, 0, 0, 0, 0, 0, 0}, + {DATA_RI, DATA_S, DATA_RI, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_RI, SIZE_S, SIZE_RI, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL}, {4000, 4000, 4000, 28000, 0, 0, 0, 0, 0, 0} }, {TONE_GERMAN_BUSY, - {DATA_GA, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_GA, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, + {DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, {4000, 4000, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_GERMAN_OLDBUSY, - {DATA_GO, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_GO, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, + {DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, {1000, 5000, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_AMERICAN_BUSY, - {DATA_BU, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_BU, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, + {DATA_BU, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_BU, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, {4000, 4000, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_GERMAN_HANGUP, - {DATA_GA, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_GA, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, + {DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, {4000, 4000, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_GERMAN_OLDHANGUP, - {DATA_GO, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_GO, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, + {DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, {1000, 5000, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_AMERICAN_HANGUP, - {DATA_DT, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_DT, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {DATA_DT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_DT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, {8000, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_SPECIAL_INFO, - {DATA_S1, DATA_S2, DATA_S3, DATA_S, 0, 0, 0, 0, 0, 0}, - {SIZE_S1, SIZE_S2, SIZE_S3, SIZE_S, 0, 0, 0, 0, 0, 0}, + {DATA_S1, DATA_S2, DATA_S3, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_S1, SIZE_S2, SIZE_S3, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL}, {2666, 2666, 2666, 8002, 0, 0, 0, 0, 0, 0} }, {TONE_GERMAN_GASSENBESETZT, - {DATA_GA, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_GA, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, + {DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, {2000, 2000, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_GERMAN_AUFSCHALTTON, - {DATA_GO, DATA_S, DATA_GO, DATA_S, 0, 0, 0, 0, 0, 0}, - {SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, 0, 0, 0, 0, 0, 0}, + {DATA_GO, DATA_S, DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL}, {1000, 5000, 1000, 17000, 0, 0, 0, 0, 0, 0} }, {0, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, }; @@ -467,7 +467,7 @@ dsp_tone_timeout(void *arg) /* set next tone */ if (pat->data[index] == DATA_S) - dsp_tone_hw_message(dsp, 0, 0); + dsp_tone_hw_message(dsp, NULL, 0); else dsp_tone_hw_message(dsp, pat->data[index], *(pat->siz[index])); /* set timer */ diff --git a/drivers/isdn/mISDN/l1oip_codec.c b/drivers/isdn/mISDN/l1oip_codec.c index a2dc4570ef434064170d440f7461ca2f801405d9..2ec4b28d9edc85aecf80c7007c3ea0f4038eb62a 100644 --- a/drivers/isdn/mISDN/l1oip_codec.c +++ b/drivers/isdn/mISDN/l1oip_codec.c @@ -49,6 +49,7 @@ NOTE: The bytes are handled as they are law-encoded. #include #include #include "core.h" +#include "l1oip.h" /* definitions of codec. don't use calculations, code may run slower. */ diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c index e42150a577805a7ad5f8d38971d34e4b5b04020d..0884dd6892f813868417a8b54d90bdf7025227f5 100644 --- a/drivers/isdn/mISDN/l1oip_core.c +++ b/drivers/isdn/mISDN/l1oip_core.c @@ -469,7 +469,7 @@ l1oip_socket_recv(struct l1oip *hc, u8 remotecodec, u8 channel, u16 timebase, static void l1oip_socket_parse(struct l1oip *hc, struct sockaddr_in *sin, u8 *buf, int len) { - u32 id; + u32 packet_id; u8 channel; u8 remotecodec; u16 timebase; @@ -508,7 +508,7 @@ l1oip_socket_parse(struct l1oip *hc, struct sockaddr_in *sin, u8 *buf, int len) } /* get id flag */ - id = (*buf>>4)&1; + packet_id = (*buf>>4)&1; /* check coding */ remotecodec = (*buf) & 0x0f; @@ -520,11 +520,11 @@ l1oip_socket_parse(struct l1oip *hc, struct sockaddr_in *sin, u8 *buf, int len) buf++; len--; - /* check id */ - if (id) { + /* check packet_id */ + if (packet_id) { if (!hc->id) { printk(KERN_WARNING "%s: packet error - packet has id " - "0x%x, but we have not\n", __func__, id); + "0x%x, but we have not\n", __func__, packet_id); return; } if (len < 4) { @@ -532,16 +532,16 @@ l1oip_socket_parse(struct l1oip *hc, struct sockaddr_in *sin, u8 *buf, int len) "short for ID value\n", __func__); return; } - id = (*buf++) << 24; - id += (*buf++) << 16; - id += (*buf++) << 8; - id += (*buf++); + packet_id = (*buf++) << 24; + packet_id += (*buf++) << 16; + packet_id += (*buf++) << 8; + packet_id += (*buf++); len -= 4; - if (id != hc->id) { + if (packet_id != hc->id) { printk(KERN_WARNING "%s: packet error - ID mismatch, " "got 0x%x, we 0x%x\n", - __func__, id, hc->id); + __func__, packet_id, hc->id); return; } } else { diff --git a/drivers/isdn/mISDN/layer1.c b/drivers/isdn/mISDN/layer1.c index fced1a2755f88dea2709273c3448d86be7b1b33b..b73e952d12cf0674f6eb09782f009b530c9b1720 100644 --- a/drivers/isdn/mISDN/layer1.c +++ b/drivers/isdn/mISDN/layer1.c @@ -18,10 +18,11 @@ #include #include +#include "core.h" #include "layer1.h" #include "fsm.h" -static int *debug; +static u_int *debug; struct layer1 { u_long Flags; diff --git a/drivers/isdn/mISDN/layer2.c b/drivers/isdn/mISDN/layer2.c index a7915a156c0419eff3cbafede3b69d649549e934..d6e2863f224a4aa6c0f76adac0681bf173ec81f9 100644 --- a/drivers/isdn/mISDN/layer2.c +++ b/drivers/isdn/mISDN/layer2.c @@ -15,10 +15,12 @@ * */ +#include +#include "core.h" #include "fsm.h" #include "layer2.h" -static int *debug; +static u_int *debug; static struct Fsm l2fsm = {NULL, 0, 0, NULL, NULL}; @@ -465,7 +467,7 @@ IsRNR(u_char *data, struct layer2 *l2) data[0] == RNR : (data[0] & 0xf) == RNR; } -int +static int iframe_error(struct layer2 *l2, struct sk_buff *skb) { u_int i; @@ -483,7 +485,7 @@ iframe_error(struct layer2 *l2, struct sk_buff *skb) return 0; } -int +static int super_error(struct layer2 *l2, struct sk_buff *skb) { if (skb->len != l2addrsize(l2) + @@ -492,7 +494,7 @@ super_error(struct layer2 *l2, struct sk_buff *skb) return 0; } -int +static int unnum_error(struct layer2 *l2, struct sk_buff *skb, int wantrsp) { int rsp = (*skb->data & 0x2) >> 1; @@ -505,7 +507,7 @@ unnum_error(struct layer2 *l2, struct sk_buff *skb, int wantrsp) return 0; } -int +static int UI_error(struct layer2 *l2, struct sk_buff *skb) { int rsp = *skb->data & 0x2; @@ -518,7 +520,7 @@ UI_error(struct layer2 *l2, struct sk_buff *skb) return 0; } -int +static int FRMR_error(struct layer2 *l2, struct sk_buff *skb) { u_int headers = l2addrsize(l2) + 1; @@ -1065,7 +1067,7 @@ l2_st6_dm_release(struct FsmInst *fi, int event, void *arg) } } -void +static void enquiry_cr(struct layer2 *l2, u_char typ, u_char cr, u_char pf) { struct sk_buff *skb; diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c index e5a20f9542d1bb4456c602f73b4343879d268bac..37a2de18cfd0f68d13c537a5f0c53ffbb252e509 100644 --- a/drivers/isdn/mISDN/socket.c +++ b/drivers/isdn/mISDN/socket.c @@ -18,7 +18,7 @@ #include #include "core.h" -static int *debug; +static u_int *debug; static struct proto mISDN_proto = { .name = "misdn", diff --git a/drivers/isdn/mISDN/stack.c b/drivers/isdn/mISDN/stack.c index 54cfddcc47849403791602baba2b612b4fcc96ec..d55b14ae4e99d4e1ffbf58e76d9bda93df2cfb63 100644 --- a/drivers/isdn/mISDN/stack.c +++ b/drivers/isdn/mISDN/stack.c @@ -36,7 +36,7 @@ _queue_message(struct mISDNstack *st, struct sk_buff *skb) } } -int +static int mISDN_queue_message(struct mISDNchannel *ch, struct sk_buff *skb) { _queue_message(ch->st, skb); diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c index 6fbae42127bfd8ebcc268db5dc029781d7618ad8..5c43d19e7c11676716e32be9357452a5f4db8a8c 100644 --- a/drivers/isdn/mISDN/tei.c +++ b/drivers/isdn/mISDN/tei.c @@ -393,7 +393,7 @@ dl_unit_data(struct manager *mgr, struct sk_buff *skb) return 0; } -unsigned int +static unsigned int random_ri(void) { u16 x; @@ -1287,7 +1287,7 @@ create_teimanager(struct mISDNdevice *dev) if (!mgr) return -ENOMEM; INIT_LIST_HEAD(&mgr->layer2); - mgr->lock = __RW_LOCK_UNLOCKED(mgr->lock); + rwlock_init(&mgr->lock); skb_queue_head_init(&mgr->sendq); mgr->nextid = 1; mgr->lastid = MISDN_ID_NONE; diff --git a/drivers/isdn/mISDN/timerdev.c b/drivers/isdn/mISDN/timerdev.c index 875fabe16e368c32b87f1a2e697accf45369eac6..f2b32186d4a19f2fbec632b5a7cf7c915a94134a 100644 --- a/drivers/isdn/mISDN/timerdev.c +++ b/drivers/isdn/mISDN/timerdev.c @@ -23,8 +23,9 @@ #include #include #include +#include "core.h" -static int *debug; +static u_int *debug; struct mISDNtimerdev { @@ -85,7 +86,7 @@ mISDN_close(struct inode *ino, struct file *filep) } static ssize_t -mISDN_read(struct file *filep, char *buf, size_t count, loff_t *off) +mISDN_read(struct file *filep, char __user *buf, size_t count, loff_t *off) { struct mISDNtimerdev *dev = filep->private_data; struct mISDNtimer *timer; @@ -115,7 +116,7 @@ mISDN_read(struct file *filep, char *buf, size_t count, loff_t *off) timer = (struct mISDNtimer *)dev->expired.next; list_del(&timer->list); spin_unlock_irqrestore(&dev->lock, flags); - if (put_user(timer->id, (int *)buf)) + if (put_user(timer->id, (int __user *)buf)) ret = -EFAULT; else ret = sizeof(int); @@ -274,7 +275,7 @@ static struct miscdevice mISDNtimer = { }; int -mISDN_inittimer(int *deb) +mISDN_inittimer(u_int *deb) { int err; diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c index 741a93a3eb6197eeae387b8445d63f7964d846b9..62dd1fdafecf4c92954cf279be538d77aa5c4d27 100644 --- a/drivers/macintosh/via-cuda.c +++ b/drivers/macintosh/via-cuda.c @@ -23,7 +23,6 @@ #else #include #include -#include #include #endif #include diff --git a/drivers/macintosh/via-macii.c b/drivers/macintosh/via-macii.c index 6e6dd17ab572f81bd775293ad907b8024407d2ee..817f37a875c9be194c7b7c08736a98acde8d74cb 100644 --- a/drivers/macintosh/via-macii.c +++ b/drivers/macintosh/via-macii.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include diff --git a/drivers/macintosh/via-maciisi.c b/drivers/macintosh/via-maciisi.c index 2dc788042707fb6dd6abc78abafc84d678c977cd..4d686c0bdea0f196db01d170a3d287f1e1b6a7d0 100644 --- a/drivers/macintosh/via-maciisi.c +++ b/drivers/macintosh/via-maciisi.c @@ -24,7 +24,6 @@ #include #include #include -#include #include static volatile unsigned char *via; diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index d524dc245a2c18af982e661970ff255199f85a60..b40fb9b6c862c3bdecd5b21ebbd5ef20e1fd7434 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -1814,7 +1814,7 @@ static int powerbook_sleep_grackle(void) _set_L2CR(save_l2cr); /* Restore userland MMU context */ - set_context(current->active_mm->context.id, current->active_mm->pgd); + switch_mmu_context(NULL, current->active_mm); /* Power things up */ pmu_unlock(); @@ -1903,7 +1903,7 @@ powerbook_sleep_Core99(void) _set_L3CR(save_l3cr); /* Restore userland MMU context */ - set_context(current->active_mm->context.id, current->active_mm->pgd); + switch_mmu_context(NULL, current->active_mm); /* Tell PMU we are ready */ pmu_unlock(); diff --git a/drivers/macintosh/via-pmu68k.c b/drivers/macintosh/via-pmu68k.c index b64741c95ac429d1d3089c0534bb4ca0975cec59..fb9fa614a0e8e2f1f4ff0792c3b0ec1e476239ff 100644 --- a/drivers/macintosh/via-pmu68k.c +++ b/drivers/macintosh/via-pmu68k.c @@ -35,7 +35,6 @@ #include #include -#include #include #include diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c index 7f2be4baaedab9cec03e721a5733e864d10016bb..7847e981ac33eaeaead929137aa68e0ef13937f2 100644 --- a/drivers/macintosh/windfarm_smu_sat.c +++ b/drivers/macintosh/windfarm_smu_sat.c @@ -87,11 +87,12 @@ struct smu_sdbp_header *smu_sat_get_sdb_partition(unsigned int sat_id, int id, return NULL; } - len = i2c_smbus_read_word_data(&sat->i2c, 9); - if (len < 0) { + err = i2c_smbus_read_word_data(&sat->i2c, 9); + if (err < 0) { printk(KERN_ERR "smu_sat_get_sdb_part rd len error\n"); return NULL; } + len = err; if (len == 0) { printk(KERN_ERR "smu_sat_get_sdb_part no partition %x\n", id); return NULL; diff --git a/drivers/md/dm.c b/drivers/md/dm.c index c99e4728ff4162ed16c4a7ec99fdc0c27c8cb35f..343094c3feeb834c55f8aa1ecd3baa57890eca1d 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -21,6 +21,7 @@ #include #include #include +#include #define DM_MSG_PREFIX "core" @@ -51,6 +52,8 @@ struct dm_target_io { union map_info info; }; +DEFINE_TRACE(block_bio_complete); + union map_info *dm_get_mapinfo(struct bio *bio) { if (bio && bio->bi_private) @@ -504,8 +507,7 @@ static void dec_pending(struct dm_io *io, int error) end_io_acct(io); if (io->error != DM_ENDIO_REQUEUE) { - blk_add_trace_bio(io->md->queue, io->bio, - BLK_TA_COMPLETE); + trace_block_bio_complete(io->md->queue, io->bio); bio_endio(io->bio, io->error); } @@ -598,7 +600,7 @@ static void __map_bio(struct dm_target *ti, struct bio *clone, if (r == DM_MAPIO_REMAPPED) { /* the bio has been remapped so dispatch it */ - blk_add_trace_remap(bdev_get_queue(clone->bi_bdev), clone, + trace_block_remap(bdev_get_queue(clone->bi_bdev), clone, tio->io->bio->bi_bdev->bd_dev, clone->bi_sector, sector); diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig index 73dc2ee9b014021a5681d83be1badd96802010bc..b34301d56cd2859f7b248ee0df8c7899317d59d5 100644 --- a/drivers/media/dvb/b2c2/Kconfig +++ b/drivers/media/dvb/b2c2/Kconfig @@ -9,11 +9,11 @@ config DVB_B2C2_FLEXCOP select DVB_STV0297 if !DVB_FE_CUSTOMISE select DVB_BCM3510 if !DVB_FE_CUSTOMISE select DVB_LGDT330X if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE select DVB_S5H1420 if !DVB_FE_CUSTOMISE select DVB_TUNER_ITD1000 if !DVB_FE_CUSTOMISE select DVB_ISL6421 if !DVB_FE_CUSTOMISE select DVB_CX24123 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE help Support for the digital TV receiver chip made by B2C2 Inc. included in Technisats PCI cards and USB boxes. diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c index a127a4175c402a45c1940d7dec586762557544b5..5cded370854167b2d3db6ffec80e7914ad7437f1 100644 --- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c +++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c @@ -628,12 +628,14 @@ int flexcop_frontend_init(struct flexcop_device *fc) } /* try the cable dvb (stv0297) */ + fc->fc_i2c_adap[0].no_base_addr = 1; fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c); if (fc->fe != NULL) { fc->dev_type = FC_CABLE; fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params; goto fe_found; } + fc->fc_i2c_adap[0].no_base_addr = 0; /* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */ fc->fe = dvb_attach(mt312_attach, diff --git a/drivers/media/dvb/b2c2/flexcop-i2c.c b/drivers/media/dvb/b2c2/flexcop-i2c.c index 43a112ec6d44f146b260c64cf12446d036e1283a..f13783f08f0f4e09bd054c38806792e1289af3a4 100644 --- a/drivers/media/dvb/b2c2/flexcop-i2c.c +++ b/drivers/media/dvb/b2c2/flexcop-i2c.c @@ -47,8 +47,12 @@ static int flexcop_i2c_read4(struct flexcop_i2c_adapter *i2c, int len = r100.tw_sm_c_100.total_bytes, /* remember total_bytes is buflen-1 */ ret; - r100.tw_sm_c_100.no_base_addr_ack_error = i2c->no_base_addr; ret = flexcop_i2c_operation(i2c->fc, &r100); + if (ret != 0) { + deb_i2c("Retrying operation\n"); + r100.tw_sm_c_100.no_base_addr_ack_error = i2c->no_base_addr; + ret = flexcop_i2c_operation(i2c->fc, &r100); + } if (ret != 0) { deb_i2c("read failed. %d\n", ret); return ret; diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c index 5f79c8dc383651aa9349e3445f854d24947aab9a..676413a915b45c3302995dfe82d49d283843c625 100644 --- a/drivers/media/dvb/b2c2/flexcop.c +++ b/drivers/media/dvb/b2c2/flexcop.c @@ -270,7 +270,7 @@ int flexcop_device_initialize(struct flexcop_device *fc) /* do the MAC address reading after initializing the dvb_adapter */ if (fc->get_mac_addr(fc, 0) == 0) { u8 *b = fc->dvb_adapter.proposed_mac; - info("MAC address = %02x:%02x:%02x:%02x:%02x:%02x", b[0],b[1],b[2],b[3],b[4],b[5]); + info("MAC address = %pM", b); flexcop_set_mac_filter(fc,b); flexcop_mac_filter_ctrl(fc,1); } else diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig index 7e9c090fc04ea9ae2e7273890fce6f5c04241db1..27edb0ece58752b0617f9bdb2bd26ef05500f510 100644 --- a/drivers/media/dvb/bt8xx/Kconfig +++ b/drivers/media/dvb/bt8xx/Kconfig @@ -8,7 +8,7 @@ config DVB_BT8XX select DVB_OR51211 if !DVB_FE_CUSTOMISE select DVB_LGDT330X if !DVB_FE_CUSTOMISE select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE help Support for PCI cards based on the Bt8xx PCI bridge. Examples are the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards, diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index aa3db57d32d94ce7ac01abb81b3ab41bbb501e2a..29e8f1546ab6d3dbafc2cd7ede40485fb771deea 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -917,9 +917,7 @@ static int dst_get_mac(struct dst_state *state) } memset(&state->mac_address, '\0', 8); memcpy(&state->mac_address, &state->rxbuffer, 6); - dprintk(verbose, DST_ERROR, 1, "MAC Address=[%02x:%02x:%02x:%02x:%02x:%02x]", - state->mac_address[0], state->mac_address[1], state->mac_address[2], - state->mac_address[4], state->mac_address[5], state->mac_address[6]); + dprintk(verbose, DST_ERROR, 1, "MAC Address=[%pM]", state->mac_address); return 0; } diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c index c1d92f838ca83ba608bd28678709bf9a5afa7be1..a21ce9edcc7ee1f383567ed8bc48a0d5d452c143 100644 --- a/drivers/media/dvb/dm1105/dm1105.c +++ b/drivers/media/dvb/dm1105/dm1105.c @@ -697,8 +697,7 @@ static void __devinit dm1105dvb_read_mac(struct dm1105dvb *dm1105dvb, u8 *mac) }; dm1105_i2c_xfer(&dm1105dvb->i2c_adap, msg , 2); - dev_info(&dm1105dvb->pdev->dev, "MAC %02x:%02x:%02x:%02x:%02x:%02x\n", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + dev_info(&dm1105dvb->pdev->dev, "MAC %pM\n", mac); } static int __devinit dm1105_probe(struct pci_dev *pdev, diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index c93019ca519e677e8a979e5feab9e22f93a5dc0d..03fd9dd5c6850472d520dbbe8609709a898087db 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -345,7 +345,7 @@ static inline void reset_ule( struct dvb_net_priv *p ) */ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) { - struct dvb_net_priv *priv = dev->priv; + struct dvb_net_priv *priv = netdev_priv(dev); unsigned long skipped = 0L; const u8 *ts, *ts_end, *from_where = NULL; u8 ts_remain = 0, how_much = 0, new_ts = 1; @@ -460,8 +460,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) /* Drop partly decoded SNDU, reset state, resync on PUSI. */ if (priv->ule_skb) { dev_kfree_skb( priv->ule_skb ); - ((struct dvb_net_priv *) dev->priv)->stats.rx_errors++; - ((struct dvb_net_priv *) dev->priv)->stats.rx_frame_errors++; + priv->stats.rx_errors++; + priv->stats.rx_frame_errors++; } reset_ule(priv); priv->need_pusi = 1; @@ -573,7 +573,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) if (priv->ule_skb == NULL) { printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); - ((struct dvb_net_priv *)dev->priv)->stats.rx_dropped++; + priv->stats.rx_dropped++; return; } @@ -800,7 +800,8 @@ static void dvb_net_sec(struct net_device *dev, { u8 *eth; struct sk_buff *skb; - struct net_device_stats *stats = &(((struct dvb_net_priv *) dev->priv)->stats); + struct net_device_stats *stats = + &((struct dvb_net_priv *) netdev_priv(dev))->stats; int snap = 0; /* note: pkt_len includes a 32bit checksum */ @@ -917,7 +918,7 @@ static int dvb_net_filter_sec_set(struct net_device *dev, struct dmx_section_filter **secfilter, u8 *mac, u8 *mac_mask) { - struct dvb_net_priv *priv = dev->priv; + struct dvb_net_priv *priv = netdev_priv(dev); int ret; *secfilter=NULL; @@ -961,7 +962,7 @@ static int dvb_net_filter_sec_set(struct net_device *dev, static int dvb_net_feed_start(struct net_device *dev) { int ret = 0, i; - struct dvb_net_priv *priv = dev->priv; + struct dvb_net_priv *priv = netdev_priv(dev); struct dmx_demux *demux = priv->demux; unsigned char *mac = (unsigned char *) dev->dev_addr; @@ -1060,7 +1061,7 @@ static int dvb_net_feed_start(struct net_device *dev) static int dvb_net_feed_stop(struct net_device *dev) { - struct dvb_net_priv *priv = dev->priv; + struct dvb_net_priv *priv = netdev_priv(dev); int i, ret = 0; dprintk("%s\n", __func__); @@ -1113,7 +1114,7 @@ static int dvb_net_feed_stop(struct net_device *dev) static int dvb_set_mc_filter (struct net_device *dev, struct dev_mc_list *mc) { - struct dvb_net_priv *priv = dev->priv; + struct dvb_net_priv *priv = netdev_priv(dev); if (priv->multi_num == DVB_NET_MULTICAST_MAX) return -ENOMEM; @@ -1165,7 +1166,7 @@ static void wq_set_multicast_list (struct work_struct *work) static void dvb_net_set_multicast_list (struct net_device *dev) { - struct dvb_net_priv *priv = dev->priv; + struct dvb_net_priv *priv = netdev_priv(dev); schedule_work(&priv->set_multicast_list_wq); } @@ -1185,7 +1186,7 @@ static void wq_restart_net_feed (struct work_struct *work) static int dvb_net_set_mac (struct net_device *dev, void *p) { - struct dvb_net_priv *priv = dev->priv; + struct dvb_net_priv *priv = netdev_priv(dev); struct sockaddr *addr=p; memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); @@ -1199,7 +1200,7 @@ static int dvb_net_set_mac (struct net_device *dev, void *p) static int dvb_net_open(struct net_device *dev) { - struct dvb_net_priv *priv = dev->priv; + struct dvb_net_priv *priv = netdev_priv(dev); priv->in_use++; dvb_net_feed_start(dev); @@ -1209,7 +1210,7 @@ static int dvb_net_open(struct net_device *dev) static int dvb_net_stop(struct net_device *dev) { - struct dvb_net_priv *priv = dev->priv; + struct dvb_net_priv *priv = netdev_priv(dev); priv->in_use--; return dvb_net_feed_stop(dev); @@ -1217,7 +1218,7 @@ static int dvb_net_stop(struct net_device *dev) static struct net_device_stats * dvb_net_get_stats(struct net_device *dev) { - return &((struct dvb_net_priv*) dev->priv)->stats; + return &((struct dvb_net_priv *) netdev_priv(dev))->stats; } static const struct header_ops dvb_header_ops = { @@ -1287,7 +1288,7 @@ static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid, u8 feedtype) dvbnet->device[if_num] = net; - priv = net->priv; + priv = netdev_priv(net); priv->net = net; priv->demux = dvbnet->demux; priv->pid = pid; @@ -1320,7 +1321,7 @@ static int dvb_net_remove_if(struct dvb_net *dvbnet, unsigned long num) if (!dvbnet->state[num]) return -EINVAL; - priv = net->priv; + priv = netdev_priv(net); if (priv->in_use) return -EBUSY; @@ -1376,7 +1377,7 @@ static int dvb_net_do_ioctl(struct inode *inode, struct file *file, netdev = dvbnet->device[dvbnetif->if_num]; - priv_data = netdev->priv; + priv_data = netdev_priv(netdev); dvbnetif->pid=priv_data->pid; dvbnetif->feedtype=priv_data->feedtype; break; @@ -1427,7 +1428,7 @@ static int dvb_net_do_ioctl(struct inode *inode, struct file *file, netdev = dvbnet->device[dvbnetif->if_num]; - priv_data = netdev->priv; + priv_data = netdev_priv(netdev); dvbnetif->pid=priv_data->pid; break; } diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 62b68c291d9968636ebe62a2a1605afc9a712d38..49f7b20c25d6f134f883d5c3c1e15cbebeb5a547 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -24,8 +24,8 @@ config DVB_USB_A800 tristate "AVerMedia AverTV DVB-T USB 2.0 (A800)" depends on DVB_USB select DVB_DIB3000MC - select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE select DVB_PLL if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE help Say Y here to support the AVerMedia AverTV DVB-T USB 2.0 (A800) receiver. @@ -34,7 +34,7 @@ config DVB_USB_DIBUSB_MB depends on DVB_USB select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_DIB3000MB - select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE help Support for USB 1.1 and 2.0 DVB-T receivers based on reference designs made by DiBcom () equipped with a DiB3000M-B demodulator. @@ -55,7 +55,7 @@ config DVB_USB_DIBUSB_MC tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)" depends on DVB_USB select DVB_DIB3000MC - select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE help Support for USB2.0 DVB-T receivers based on reference designs made by DiBcom () equipped with a DiB3000M-C/P demodulator. @@ -73,11 +73,11 @@ config DVB_USB_DIB0700 select DVB_DIB7000M select DVB_DIB3000MC select DVB_S5H1411 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_MT2266 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE select DVB_TUNER_DIB0070 + select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE + select MEDIA_TUNER_MT2266 if !MEDIA_TUNER_CUSTOMIZE + select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMIZE + select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMIZE help Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The USB bridge is also present in devices having the DiB7700 DVB-T-USB @@ -95,7 +95,7 @@ config DVB_USB_UMT_010 depends on DVB_USB select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_DIB3000MC - select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE help Say Y here to support the HanfTek UMT-010 USB2.0 stick-sized DVB-T receiver. @@ -107,11 +107,11 @@ config DVB_USB_CXUSB select DVB_LGDT330X if !DVB_FE_CUSTOMISE select DVB_MT352 if !DVB_FE_CUSTOMISE select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_MXL5005S if !DVB_FE_CUSTOMISE select DVB_DIB7000P if !DVB_FE_CUSTOMISE select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE + select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMIZE + select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMIZE help Say Y here to support the Conexant USB2.0 hybrid reference design. Currently, only DVB and ATSC modes are supported, analog mode @@ -124,9 +124,9 @@ config DVB_USB_M920X tristate "Uli m920x DVB-T USB2.0 support" depends on DVB_USB select DVB_MT352 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_TDA827X if !DVB_FE_CUSTOMISE select DVB_TDA1004X if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMIZE + select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMIZE help Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver. Currently, only devices with a product id of @@ -137,7 +137,7 @@ config DVB_USB_GL861 tristate "Genesys Logic GL861 USB2.0 support" depends on DVB_USB select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMIZE help Say Y here to support the MSI Megasky 580 (55801) DVB-T USB2.0 receiver with USB ID 0db0:5581. @@ -146,7 +146,7 @@ config DVB_USB_AU6610 tristate "Alcor Micro AU6610 USB2.0 support" depends on DVB_USB select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMIZE help Say Y here to support the Sigmatek DVB-110 DVB-T USB2.0 receiver. @@ -198,8 +198,8 @@ config DVB_USB_NOVA_T_USB2 tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support" depends on DVB_USB select DVB_DIB3000MC - select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE select DVB_PLL if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE help Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver. @@ -235,8 +235,8 @@ config DVB_USB_OPERA1 config DVB_USB_AF9005 tristate "Afatech AF9005 DVB-T USB1.1 support" depends on DVB_USB && EXPERIMENTAL - select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE + select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMIZE help Say Y here to support the Afatech AF9005 based DVB-T USB1.1 receiver and the TerraTec Cinergy T USB XE (Rev.1) @@ -284,7 +284,7 @@ config DVB_USB_DTV5100 tristate "AME DTV-5100 USB2.0 DVB-T support" depends on DVB_USB select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMIZE help Say Y here to support the AME DTV-5100 USB2.0 DVB-T receiver. @@ -293,9 +293,9 @@ config DVB_USB_AF9015 depends on DVB_USB && EXPERIMENTAL select DVB_AF9013 select DVB_PLL if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_MXL5005S if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE + select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMIZE + select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMIZE + select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMIZE help Say Y here to support the Afatech AF9015 based DVB-T USB2.0 receiver diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index f28d3ae59e046cd8e9d1d6c74565848ccb4a9833..3917327889117bcff8cf27f315c8a3d70fcb27c7 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -446,13 +446,13 @@ static int stk7700ph_tuner_attach(struct dvb_usb_adapter *adap) == NULL ? -ENODEV : 0; } -#define DEFAULT_RC_INTERVAL 150 +#define DEFAULT_RC_INTERVAL 50 static u8 rc_request[] = { REQUEST_POLL_RC, 0 }; /* Number of keypresses to ignore before start repeating */ -#define RC_REPEAT_DELAY 2 -#define RC_REPEAT_DELAY_V1_20 5 +#define RC_REPEAT_DELAY 6 +#define RC_REPEAT_DELAY_V1_20 10 diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c index ce8cd0c5d83120b173ad5fa4950d1f43a8c0a585..8a7d87bcd1d98b71c3bbbd6b62150ad8c9e8fba9 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c @@ -91,10 +91,7 @@ int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums) if (adap->dev->props.read_mac_address) { if (adap->dev->props.read_mac_address(adap->dev,adap->dvb_adap.proposed_mac) == 0) - info("MAC address: %02x:%02x:%02x:%02x:%02x:%02x",adap->dvb_adap.proposed_mac[0], - adap->dvb_adap.proposed_mac[1], adap->dvb_adap.proposed_mac[2], - adap->dvb_adap.proposed_mac[3], adap->dvb_adap.proposed_mac[4], - adap->dvb_adap.proposed_mac[5]); + info("MAC address: %pM",adap->dvb_adap.proposed_mac); else err("MAC address reading failed."); } diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c index a9653c63f4db8350b5fb66c4e184b6d44a16421f..d101b304e9b0e7348614ec4ec2c8d28e15a31317 100644 --- a/drivers/media/dvb/pluto2/pluto2.c +++ b/drivers/media/dvb/pluto2/pluto2.c @@ -560,8 +560,7 @@ static void __devinit pluto_read_mac(struct pluto *pluto, u8 *mac) mac[4] = (val >> 8) & 0xff; mac[5] = (val >> 0) & 0xff; - dev_info(&pluto->pdev->dev, "MAC %02x:%02x:%02x:%02x:%02x:%02x\n", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + dev_info(&pluto->pdev->dev, "MAC %pM\n", mac); } static int __devinit pluto_read_serial(struct pluto *pluto) diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig index 867027ceab3e71d29ce43b3944104043670eeb99..401a04effc06817befbc4d6772565c430648d78a 100644 --- a/drivers/media/dvb/ttpci/Kconfig +++ b/drivers/media/dvb/ttpci/Kconfig @@ -106,7 +106,7 @@ config DVB_BUDGET_CI select DVB_TDA1004X if !DVB_FE_CUSTOMISE select DVB_LNBP21 if !DVB_FE_CUSTOMISE select DVB_TDA10023 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_TDA827X if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMIZE select VIDEO_IR help Support for simple SAA7146 based DVB cards diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 47102c2c8250fc51df410059ba5b52c24ea5f510..057fd7e160c41f8ddb657dbbb499fdcda6e2bb06 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -759,7 +759,7 @@ config VIDEO_PXA27x config VIDEO_SH_MOBILE_CEU tristate "SuperH Mobile CEU Interface driver" - depends on VIDEO_DEV && SOC_CAMERA && HAS_DMA + depends on VIDEO_DEV && SOC_CAMERA && HAS_DMA && HAVE_CLK select VIDEOBUF_DMA_CONTIG ---help--- This is a v4l2 driver for the SuperH Mobile CEU Interface diff --git a/drivers/media/video/compat_ioctl32.c b/drivers/media/video/compat_ioctl32.c index e6ca4012b5f0f78fab90212e546aa1b6f0cd4946..0ea85a05e5c0d86911d9a62fe3445e472cf1e877 100644 --- a/drivers/media/video/compat_ioctl32.c +++ b/drivers/media/video/compat_ioctl32.c @@ -831,7 +831,7 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) { int ret = -ENOIOCTLCMD; - if (!file->f_op->ioctl) + if (!file->f_op->ioctl && !file->f_op->unlocked_ioctl) return ret; switch (cmd) { diff --git a/drivers/media/video/cx18/Kconfig b/drivers/media/video/cx18/Kconfig index ef48565de7f1b7c5fdcd61e69fdb6e78b9ca9f83..8940b5387decc4fda02d8f41a3a86189d2380803 100644 --- a/drivers/media/video/cx18/Kconfig +++ b/drivers/media/video/cx18/Kconfig @@ -9,7 +9,7 @@ config VIDEO_CX18 select VIDEO_CX2341X select VIDEO_CS5345 select DVB_S5H1409 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_MXL5005S if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMIZE ---help--- This is a video4linux driver for Conexant cx23418 based PCI combo video recorder devices. diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig index 8c1b7fa47a41cc36f35d3f4c763ff65c190e792c..00f1e2e8889e7fe23431827e17ce9f8b862d2714 100644 --- a/drivers/media/video/cx23885/Kconfig +++ b/drivers/media/video/cx23885/Kconfig @@ -11,16 +11,16 @@ config VIDEO_CX23885 select VIDEO_CX25840 select VIDEO_CX2341X select DVB_DIB7000P if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_MT2131 if !DVB_FE_CUSTOMISE select DVB_S5H1409 if !DVB_FE_CUSTOMISE select DVB_S5H1411 if !DVB_FE_CUSTOMISE select DVB_LGDT330X if !DVB_FE_CUSTOMISE select DVB_ZL10353 if !DVB_FE_CUSTOMISE + select DVB_TDA10048 if !DVB_FE_CUSTOMIZE + select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMIZE select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMIZE select MEDIA_TUNER_TDA8290 if !DVB_FE_CUSTOMIZE select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE - select DVB_TDA10048 if !DVB_FE_CUSTOMIZE ---help--- This is a video4linux driver for Conexant 23885 based TV cards. diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig index 0b9e5fac6239f5783e0f42e24f8eb9d1c700dfed..b0f837588e01ee9bb5a8d4c14f7617958a33be19 100644 --- a/drivers/media/video/cx88/Kconfig +++ b/drivers/media/video/cx88/Kconfig @@ -56,12 +56,12 @@ config VIDEO_CX88_DVB select DVB_NXT200X if !DVB_FE_CUSTOMISE select DVB_CX24123 if !DVB_FE_CUSTOMISE select DVB_ISL6421 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE select DVB_S5H1411 if !DVB_FE_CUSTOMISE select DVB_CX24116 if !DVB_FE_CUSTOMISE select DVB_STV0299 if !DVB_FE_CUSTOMISE select DVB_STV0288 if !DVB_FE_CUSTOMISE select DVB_STB6000 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE ---help--- This adds support for DVB/ATSC cards based on the Conexant 2388x chip. diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 610f535a257cd3c47b40d80484ad952177aaec38..4ea1f1e048979e51859652d93e24846a7f39fd3e 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -549,10 +549,11 @@ static int em28xx_config(struct em28xx *dev) static void em28xx_config_i2c(struct em28xx *dev) { struct v4l2_routing route; + int zero = 0; route.input = INPUT(dev->ctl_input)->vmux; route.output = 0; - em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, NULL); + em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, &zero); em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route); em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL); } diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 748a87e82e4423e2b9ecfb4c4ac621a339231e4a..02a6e9ef033740d7401b6bd1ccd5966552add823 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -1264,10 +1264,10 @@ static int vidioc_s_jpegcomp(struct file *file, void *priv, struct gspca_dev *gspca_dev = priv; int ret; - if (mutex_lock_interruptible(&gspca_dev->usb_lock)) - return -ERESTARTSYS; if (!gspca_dev->sd_desc->set_jcomp) return -EINVAL; + if (mutex_lock_interruptible(&gspca_dev->usb_lock)) + return -ERESTARTSYS; ret = gspca_dev->sd_desc->set_jcomp(gspca_dev, jpegcomp); mutex_unlock(&gspca_dev->usb_lock); return ret; diff --git a/drivers/media/video/pvrusb2/Kconfig b/drivers/media/video/pvrusb2/Kconfig index 19eb274c9cd09d2f361154ed764d152472df709f..854c2a88535880a3e2a6c2d560303c46faaa8f2f 100644 --- a/drivers/media/video/pvrusb2/Kconfig +++ b/drivers/media/video/pvrusb2/Kconfig @@ -42,7 +42,7 @@ config VIDEO_PVRUSB2_DVB select DVB_S5H1411 if !DVB_FE_CUSTOMISE select DVB_TDA10048 if !DVB_FE_CUSTOMIZE select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE - select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE select MEDIA_TUNER_TDA8290 if !DVB_FE_CUSTOMIZE ---help--- diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig index 7021bbf5897b3ac6988fd5d42d28bc70a4231c9f..fc2164e28e76d11bbcb12fa60de4cb69d8acb7f3 100644 --- a/drivers/media/video/saa7134/Kconfig +++ b/drivers/media/video/saa7134/Kconfig @@ -34,9 +34,9 @@ config VIDEO_SAA7134_DVB select DVB_NXT200X if !DVB_FE_CUSTOMISE select DVB_TDA10086 if !DVB_FE_CUSTOMISE select DVB_TDA826X if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_TDA827X if !DVB_FE_CUSTOMISE select DVB_ISL6421 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMIZE + select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE ---help--- This adds support for DVB cards based on the Philips saa7134 chip. diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index 2407607f2eff1ce0c28a26262d5ffbb08439d000..536b1a9b310ca602aa256493e742290c915f5674 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -89,6 +90,7 @@ struct sh_mobile_ceu_dev { unsigned int irq; void __iomem *base; + struct clk *clk; unsigned long video_limit; /* lock used to protect videobuf */ @@ -309,6 +311,8 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd) if (ret) goto err; + clk_enable(pcdev->clk); + ceu_write(pcdev, CAPSR, 1 << 16); /* reset */ while (ceu_read(pcdev, CSTSR) & 1) msleep(1); @@ -342,6 +346,8 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd) } spin_unlock_irqrestore(&pcdev->lock, flags); + clk_disable(pcdev->clk); + icd->ops->release(icd); dev_info(&icd->dev, @@ -550,6 +556,7 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev) struct sh_mobile_ceu_dev *pcdev; struct resource *res; void __iomem *base; + char clk_name[8]; unsigned int irq; int err = 0; @@ -615,6 +622,14 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev) goto exit_release_mem; } + snprintf(clk_name, sizeof(clk_name), "ceu%d", pdev->id); + pcdev->clk = clk_get(&pdev->dev, clk_name); + if (IS_ERR(pcdev->clk)) { + dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name); + err = PTR_ERR(pcdev->clk); + goto exit_free_irq; + } + pcdev->ici.priv = pcdev; pcdev->ici.dev.parent = &pdev->dev; pcdev->ici.nr = pdev->id; @@ -623,10 +638,12 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev) err = soc_camera_host_register(&pcdev->ici); if (err) - goto exit_free_irq; + goto exit_free_clk; return 0; +exit_free_clk: + clk_put(pcdev->clk); exit_free_irq: free_irq(pcdev->irq, pcdev); exit_release_mem: @@ -645,6 +662,7 @@ static int sh_mobile_ceu_remove(struct platform_device *pdev) struct sh_mobile_ceu_dev *pcdev = platform_get_drvdata(pdev); soc_camera_host_unregister(&pcdev->ici); + clk_put(pcdev->clk); free_irq(pcdev->irq, pcdev); if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) dma_release_declared_memory(&pdev->dev); diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c index 603ffd008c73fb65275e1001af623f02332163d8..a13f6eecd25b87f4d82d51ae3d67d761cce29e41 100644 --- a/drivers/message/fusion/mptlan.c +++ b/drivers/message/fusion/mptlan.c @@ -815,7 +815,7 @@ mpt_lan_wake_post_buckets_task(struct net_device *dev, int priority) * @priority: 0 = put it on the timer queue, 1 = put it on the immediate queue */ { - struct mpt_lan_priv *priv = dev->priv; + struct mpt_lan_priv *priv = netdev_priv(dev); if (test_and_set_bit(0, &priv->post_buckets_active) == 0) { if (priority) { @@ -834,7 +834,7 @@ mpt_lan_wake_post_buckets_task(struct net_device *dev, int priority) static int mpt_lan_receive_skb(struct net_device *dev, struct sk_buff *skb) { - struct mpt_lan_priv *priv = dev->priv; + struct mpt_lan_priv *priv = netdev_priv(dev); skb->protocol = mpt_lan_type_trans(skb, dev); @@ -866,7 +866,7 @@ mpt_lan_receive_skb(struct net_device *dev, struct sk_buff *skb) static int mpt_lan_receive_post_turbo(struct net_device *dev, u32 tmsg) { - struct mpt_lan_priv *priv = dev->priv; + struct mpt_lan_priv *priv = netdev_priv(dev); MPT_ADAPTER *mpt_dev = priv->mpt_dev; struct sk_buff *skb, *old_skb; unsigned long flags; @@ -921,7 +921,7 @@ static int mpt_lan_receive_post_free(struct net_device *dev, LANReceivePostReply_t *pRecvRep) { - struct mpt_lan_priv *priv = dev->priv; + struct mpt_lan_priv *priv = netdev_priv(dev); MPT_ADAPTER *mpt_dev = priv->mpt_dev; unsigned long flags; struct sk_buff *skb; @@ -976,7 +976,7 @@ static int mpt_lan_receive_post_reply(struct net_device *dev, LANReceivePostReply_t *pRecvRep) { - struct mpt_lan_priv *priv = dev->priv; + struct mpt_lan_priv *priv = netdev_priv(dev); MPT_ADAPTER *mpt_dev = priv->mpt_dev; struct sk_buff *skb, *old_skb; unsigned long flags; @@ -1427,11 +1427,9 @@ mptlan_probe(struct pci_dev *pdev, const struct pci_device_id *id) printk(KERN_INFO MYNAM ": %s: Fusion MPT LAN device " "registered as '%s'\n", ioc->name, dev->name); printk(KERN_INFO MYNAM ": %s/%s: " - "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n", + "LanAddr = %pM\n", IOC_AND_NETDEV_NAMES_s_s(dev), - dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], - dev->dev_addr[4], dev->dev_addr[5]); + dev->dev_addr); ioc->netdev = dev; @@ -1516,9 +1514,8 @@ mpt_lan_type_trans(struct sk_buff *skb, struct net_device *dev) printk (KERN_WARNING MYNAM ": %s: WARNING - Broadcast swap F/W bug detected!\n", NETDEV_PTR_TO_IOC_NAME_s(dev)); - printk (KERN_WARNING MYNAM ": Please update sender @ MAC_addr = %02x:%02x:%02x:%02x:%02x:%02x\n", - fch->saddr[0], fch->saddr[1], fch->saddr[2], - fch->saddr[3], fch->saddr[4], fch->saddr[5]); + printk (KERN_WARNING MYNAM ": Please update sender @ MAC_addr = %pM\n", + fch->saddr); } if (*fch->daddr & 1) { @@ -1537,7 +1534,6 @@ mpt_lan_type_trans(struct sk_buff *skb, struct net_device *dev) fcllc = (struct fcllc *)skb->data; - /* Strip the SNAP header from ARP packets since we don't * pass them through to the 802.2/SNAP layers. */ diff --git a/drivers/message/fusion/mptlan.h b/drivers/message/fusion/mptlan.h index 33927ee7dc3bcc791d604ea374935fa5e185a75c..c171afa93239ac775bf5081dd24c96e836530eb4 100644 --- a/drivers/message/fusion/mptlan.h +++ b/drivers/message/fusion/mptlan.h @@ -122,7 +122,7 @@ MODULE_DESCRIPTION(LANAME); #define dlprintk(x) #endif -#define NETDEV_TO_LANPRIV_PTR(d) ((struct mpt_lan_priv *)(d)->priv) +#define NETDEV_TO_LANPRIV_PTR(d) ((struct mpt_lan_priv *)netdev_priv(d)) #define NETDEV_PTR_TO_IOC_NAME_s(d) (NETDEV_TO_LANPRIV_PTR(d)->mpt_dev->name) #define IOC_AND_NETDEV_NAMES_s_s(d) NETDEV_PTR_TO_IOC_NAME_s(d), (d)->name diff --git a/drivers/misc/sgi-gru/gruprocfs.c b/drivers/misc/sgi-gru/gruprocfs.c index 533923f83f1aa061635571b86934ad2715014be7..73b0ca061bb567401cc4d30a145c9daf05e72160 100644 --- a/drivers/misc/sgi-gru/gruprocfs.c +++ b/drivers/misc/sgi-gru/gruprocfs.c @@ -317,7 +317,6 @@ int gru_proc_init(void) { struct proc_entry *p; - proc_mkdir("sgi_uv", NULL); proc_gru = proc_mkdir("sgi_uv/gru", NULL); for (p = proc_files; p->name; p++) diff --git a/drivers/misc/sgi-xp/xp.h b/drivers/misc/sgi-xp/xp.h index ed1722e50049ff2aea256edbb574bb9969cb3bda..7b4cbd5e03e99a3e4297dc6d4b6de219d30f7389 100644 --- a/drivers/misc/sgi-xp/xp.h +++ b/drivers/misc/sgi-xp/xp.h @@ -194,9 +194,10 @@ enum xp_retval { xpGruSendMqError, /* 59: gru send message queue related error */ xpBadChannelNumber, /* 60: invalid channel number */ - xpBadMsgType, /* 60: invalid message type */ + xpBadMsgType, /* 61: invalid message type */ + xpBiosError, /* 62: BIOS error */ - xpUnknownReason /* 61: unknown reason - must be last in enum */ + xpUnknownReason /* 63: unknown reason - must be last in enum */ }; /* @@ -345,6 +346,8 @@ extern unsigned long (*xp_pa) (void *); extern enum xp_retval (*xp_remote_memcpy) (unsigned long, const unsigned long, size_t); extern int (*xp_cpu_to_nasid) (int); +extern enum xp_retval (*xp_expand_memprotect) (unsigned long, unsigned long); +extern enum xp_retval (*xp_restrict_memprotect) (unsigned long, unsigned long); extern u64 xp_nofault_PIOR_target; extern int xp_nofault_PIOR(void *); diff --git a/drivers/misc/sgi-xp/xp_main.c b/drivers/misc/sgi-xp/xp_main.c index 66a1d19e08ad73ccd651f22efaddc4605fc0857a..9a2e77172d942f548402e9ce8ccce25d9e3bf935 100644 --- a/drivers/misc/sgi-xp/xp_main.c +++ b/drivers/misc/sgi-xp/xp_main.c @@ -51,6 +51,13 @@ EXPORT_SYMBOL_GPL(xp_remote_memcpy); int (*xp_cpu_to_nasid) (int cpuid); EXPORT_SYMBOL_GPL(xp_cpu_to_nasid); +enum xp_retval (*xp_expand_memprotect) (unsigned long phys_addr, + unsigned long size); +EXPORT_SYMBOL_GPL(xp_expand_memprotect); +enum xp_retval (*xp_restrict_memprotect) (unsigned long phys_addr, + unsigned long size); +EXPORT_SYMBOL_GPL(xp_restrict_memprotect); + /* * xpc_registrations[] keeps track of xpc_connect()'s done by the kernel-level * users of XPC. diff --git a/drivers/misc/sgi-xp/xp_sn2.c b/drivers/misc/sgi-xp/xp_sn2.c index 1440134caf3166d25339771b73df741b814e35e1..fb3ec9d735a901fb7825c1d254f188d0334a2509 100644 --- a/drivers/misc/sgi-xp/xp_sn2.c +++ b/drivers/misc/sgi-xp/xp_sn2.c @@ -120,6 +120,38 @@ xp_cpu_to_nasid_sn2(int cpuid) return cpuid_to_nasid(cpuid); } +static enum xp_retval +xp_expand_memprotect_sn2(unsigned long phys_addr, unsigned long size) +{ + u64 nasid_array = 0; + int ret; + + ret = sn_change_memprotect(phys_addr, size, SN_MEMPROT_ACCESS_CLASS_1, + &nasid_array); + if (ret != 0) { + dev_err(xp, "sn_change_memprotect(,, " + "SN_MEMPROT_ACCESS_CLASS_1,) failed ret=%d\n", ret); + return xpSalError; + } + return xpSuccess; +} + +static enum xp_retval +xp_restrict_memprotect_sn2(unsigned long phys_addr, unsigned long size) +{ + u64 nasid_array = 0; + int ret; + + ret = sn_change_memprotect(phys_addr, size, SN_MEMPROT_ACCESS_CLASS_0, + &nasid_array); + if (ret != 0) { + dev_err(xp, "sn_change_memprotect(,, " + "SN_MEMPROT_ACCESS_CLASS_0,) failed ret=%d\n", ret); + return xpSalError; + } + return xpSuccess; +} + enum xp_retval xp_init_sn2(void) { @@ -132,6 +164,8 @@ xp_init_sn2(void) xp_pa = xp_pa_sn2; xp_remote_memcpy = xp_remote_memcpy_sn2; xp_cpu_to_nasid = xp_cpu_to_nasid_sn2; + xp_expand_memprotect = xp_expand_memprotect_sn2; + xp_restrict_memprotect = xp_restrict_memprotect_sn2; return xp_register_nofault_code_sn2(); } diff --git a/drivers/misc/sgi-xp/xp_uv.c b/drivers/misc/sgi-xp/xp_uv.c index d9f7ce2510bcc26fe6f7c31fd287ebd4ad91f96b..d238576b26fa9b6c8f5d96b8f41760db444d43f1 100644 --- a/drivers/misc/sgi-xp/xp_uv.c +++ b/drivers/misc/sgi-xp/xp_uv.c @@ -15,6 +15,11 @@ #include #include +#if defined CONFIG_X86_64 +#include +#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV +#include +#endif #include "../sgi-gru/grukservices.h" #include "xp.h" @@ -49,18 +54,79 @@ xp_cpu_to_nasid_uv(int cpuid) return UV_PNODE_TO_NASID(uv_cpu_to_pnode(cpuid)); } +static enum xp_retval +xp_expand_memprotect_uv(unsigned long phys_addr, unsigned long size) +{ + int ret; + +#if defined CONFIG_X86_64 + ret = uv_bios_change_memprotect(phys_addr, size, UV_MEMPROT_ALLOW_RW); + if (ret != BIOS_STATUS_SUCCESS) { + dev_err(xp, "uv_bios_change_memprotect(,, " + "UV_MEMPROT_ALLOW_RW) failed, ret=%d\n", ret); + return xpBiosError; + } + +#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV + u64 nasid_array; + + ret = sn_change_memprotect(phys_addr, size, SN_MEMPROT_ACCESS_CLASS_1, + &nasid_array); + if (ret != 0) { + dev_err(xp, "sn_change_memprotect(,, " + "SN_MEMPROT_ACCESS_CLASS_1,) failed ret=%d\n", ret); + return xpSalError; + } +#else + #error not a supported configuration +#endif + return xpSuccess; +} + +static enum xp_retval +xp_restrict_memprotect_uv(unsigned long phys_addr, unsigned long size) +{ + int ret; + +#if defined CONFIG_X86_64 + ret = uv_bios_change_memprotect(phys_addr, size, + UV_MEMPROT_RESTRICT_ACCESS); + if (ret != BIOS_STATUS_SUCCESS) { + dev_err(xp, "uv_bios_change_memprotect(,, " + "UV_MEMPROT_RESTRICT_ACCESS) failed, ret=%d\n", ret); + return xpBiosError; + } + +#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV + u64 nasid_array; + + ret = sn_change_memprotect(phys_addr, size, SN_MEMPROT_ACCESS_CLASS_0, + &nasid_array); + if (ret != 0) { + dev_err(xp, "sn_change_memprotect(,, " + "SN_MEMPROT_ACCESS_CLASS_0,) failed ret=%d\n", ret); + return xpSalError; + } +#else + #error not a supported configuration +#endif + return xpSuccess; +} + enum xp_retval xp_init_uv(void) { BUG_ON(!is_uv()); xp_max_npartitions = XP_MAX_NPARTITIONS_UV; - xp_partition_id = 0; /* !!! not correct value */ - xp_region_size = 0; /* !!! not correct value */ + xp_partition_id = sn_partition_id; + xp_region_size = sn_region_size; xp_pa = xp_pa_uv; xp_remote_memcpy = xp_remote_memcpy_uv; xp_cpu_to_nasid = xp_cpu_to_nasid_uv; + xp_expand_memprotect = xp_expand_memprotect_uv; + xp_restrict_memprotect = xp_restrict_memprotect_uv; return xpSuccess; } diff --git a/drivers/misc/sgi-xp/xpc.h b/drivers/misc/sgi-xp/xpc.h index 619208d618627692c8cbaec3e0448b1d15479577..a5bd658c2e83b13a5d9dee5805a71eb191750e21 100644 --- a/drivers/misc/sgi-xp/xpc.h +++ b/drivers/misc/sgi-xp/xpc.h @@ -180,6 +180,18 @@ struct xpc_vars_part_sn2 { (XPC_RP_MACH_NASIDS(_rp) + \ xpc_nasid_mask_nlongs)) +/* + * Info pertinent to a GRU message queue using a watch list for irq generation. + */ +struct xpc_gru_mq_uv { + void *address; /* address of GRU message queue */ + unsigned int order; /* size of GRU message queue as a power of 2 */ + int irq; /* irq raised when message is received in mq */ + int mmr_blade; /* blade where watchlist was allocated from */ + unsigned long mmr_offset; /* offset of irq mmr located on mmr_blade */ + int watchlist_num; /* number of watchlist allocatd by BIOS */ +}; + /* * The activate_mq is used to send/receive GRU messages that affect XPC's * heartbeat, partition active state, and channel state. This is UV only. diff --git a/drivers/misc/sgi-xp/xpc_sn2.c b/drivers/misc/sgi-xp/xpc_sn2.c index b4882ccf6344a69607ee8c62f1ff3c84c32ce894..73b7fb8de47a32e0e38b8abe048ede7333fbe832 100644 --- a/drivers/misc/sgi-xp/xpc_sn2.c +++ b/drivers/misc/sgi-xp/xpc_sn2.c @@ -553,22 +553,17 @@ static u64 xpc_prot_vec_sn2[MAX_NUMNODES]; static enum xp_retval xpc_allow_amo_ops_sn2(struct amo *amos_page) { - u64 nasid_array = 0; - int ret; + enum xp_retval ret = xpSuccess; /* * On SHUB 1.1, we cannot call sn_change_memprotect() since the BIST * collides with memory operations. On those systems we call * xpc_allow_amo_ops_shub_wars_1_1_sn2() instead. */ - if (!enable_shub_wars_1_1()) { - ret = sn_change_memprotect(ia64_tpa((u64)amos_page), PAGE_SIZE, - SN_MEMPROT_ACCESS_CLASS_1, - &nasid_array); - if (ret != 0) - return xpSalError; - } - return xpSuccess; + if (!enable_shub_wars_1_1()) + ret = xp_expand_memprotect(ia64_tpa((u64)amos_page), PAGE_SIZE); + + return ret; } /* diff --git a/drivers/misc/sgi-xp/xpc_uv.c b/drivers/misc/sgi-xp/xpc_uv.c index 1ac694c01623b99419e3b7d2afb9a2c16d8ceda7..91a55b1b1037011c5e403b19dac8c710d18632d5 100644 --- a/drivers/misc/sgi-xp/xpc_uv.c +++ b/drivers/misc/sgi-xp/xpc_uv.c @@ -18,7 +18,15 @@ #include #include #include +#include #include +#if defined CONFIG_X86_64 +#include +#include +#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV +#include +#include +#endif #include "../sgi-gru/gru.h" #include "../sgi-gru/grukservices.h" #include "xpc.h" @@ -27,15 +35,17 @@ static atomic64_t xpc_heartbeat_uv; static DECLARE_BITMAP(xpc_heartbeating_to_mask_uv, XP_MAX_NPARTITIONS_UV); #define XPC_ACTIVATE_MSG_SIZE_UV (1 * GRU_CACHE_LINE_BYTES) -#define XPC_NOTIFY_MSG_SIZE_UV (2 * GRU_CACHE_LINE_BYTES) +#define XPC_ACTIVATE_MQ_SIZE_UV (4 * XP_MAX_NPARTITIONS_UV * \ + XPC_ACTIVATE_MSG_SIZE_UV) +#define XPC_ACTIVATE_IRQ_NAME "xpc_activate" -#define XPC_ACTIVATE_MQ_SIZE_UV (4 * XP_MAX_NPARTITIONS_UV * \ - XPC_ACTIVATE_MSG_SIZE_UV) -#define XPC_NOTIFY_MQ_SIZE_UV (4 * XP_MAX_NPARTITIONS_UV * \ - XPC_NOTIFY_MSG_SIZE_UV) +#define XPC_NOTIFY_MSG_SIZE_UV (2 * GRU_CACHE_LINE_BYTES) +#define XPC_NOTIFY_MQ_SIZE_UV (4 * XP_MAX_NPARTITIONS_UV * \ + XPC_NOTIFY_MSG_SIZE_UV) +#define XPC_NOTIFY_IRQ_NAME "xpc_notify" -static void *xpc_activate_mq_uv; -static void *xpc_notify_mq_uv; +static struct xpc_gru_mq_uv *xpc_activate_mq_uv; +static struct xpc_gru_mq_uv *xpc_notify_mq_uv; static int xpc_setup_partitions_sn_uv(void) @@ -52,62 +62,209 @@ xpc_setup_partitions_sn_uv(void) return 0; } -static void * -xpc_create_gru_mq_uv(unsigned int mq_size, int cpuid, unsigned int irq, +static int +xpc_get_gru_mq_irq_uv(struct xpc_gru_mq_uv *mq, int cpu, char *irq_name) +{ +#if defined CONFIG_X86_64 + mq->irq = uv_setup_irq(irq_name, cpu, mq->mmr_blade, mq->mmr_offset); + if (mq->irq < 0) { + dev_err(xpc_part, "uv_setup_irq() returned error=%d\n", + mq->irq); + } + +#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV + int mmr_pnode; + unsigned long mmr_value; + + if (strcmp(irq_name, XPC_ACTIVATE_IRQ_NAME) == 0) + mq->irq = SGI_XPC_ACTIVATE; + else if (strcmp(irq_name, XPC_NOTIFY_IRQ_NAME) == 0) + mq->irq = SGI_XPC_NOTIFY; + else + return -EINVAL; + + mmr_pnode = uv_blade_to_pnode(mq->mmr_blade); + mmr_value = (unsigned long)cpu_physical_id(cpu) << 32 | mq->irq; + + uv_write_global_mmr64(mmr_pnode, mq->mmr_offset, mmr_value); +#else + #error not a supported configuration +#endif + + return 0; +} + +static void +xpc_release_gru_mq_irq_uv(struct xpc_gru_mq_uv *mq) +{ +#if defined CONFIG_X86_64 + uv_teardown_irq(mq->irq, mq->mmr_blade, mq->mmr_offset); + +#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV + int mmr_pnode; + unsigned long mmr_value; + + mmr_pnode = uv_blade_to_pnode(mq->mmr_blade); + mmr_value = 1UL << 16; + + uv_write_global_mmr64(mmr_pnode, mq->mmr_offset, mmr_value); +#else + #error not a supported configuration +#endif +} + +static int +xpc_gru_mq_watchlist_alloc_uv(struct xpc_gru_mq_uv *mq) +{ + int ret; + +#if defined CONFIG_X86_64 + ret = uv_bios_mq_watchlist_alloc(mq->mmr_blade, uv_gpa(mq->address), + mq->order, &mq->mmr_offset); + if (ret < 0) { + dev_err(xpc_part, "uv_bios_mq_watchlist_alloc() failed, " + "ret=%d\n", ret); + return ret; + } +#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV + ret = sn_mq_watchlist_alloc(mq->mmr_blade, uv_gpa(mq->address), + mq->order, &mq->mmr_offset); + if (ret < 0) { + dev_err(xpc_part, "sn_mq_watchlist_alloc() failed, ret=%d\n", + ret); + return -EBUSY; + } +#else + #error not a supported configuration +#endif + + mq->watchlist_num = ret; + return 0; +} + +static void +xpc_gru_mq_watchlist_free_uv(struct xpc_gru_mq_uv *mq) +{ + int ret; + +#if defined CONFIG_X86_64 + ret = uv_bios_mq_watchlist_free(mq->mmr_blade, mq->watchlist_num); + BUG_ON(ret != BIOS_STATUS_SUCCESS); +#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV + ret = sn_mq_watchlist_free(mq->mmr_blade, mq->watchlist_num); + BUG_ON(ret != SALRET_OK); +#else + #error not a supported configuration +#endif +} + +static struct xpc_gru_mq_uv * +xpc_create_gru_mq_uv(unsigned int mq_size, int cpu, char *irq_name, irq_handler_t irq_handler) { + enum xp_retval xp_ret; int ret; int nid; - int mq_order; + int pg_order; struct page *page; - void *mq; + struct xpc_gru_mq_uv *mq; + + mq = kmalloc(sizeof(struct xpc_gru_mq_uv), GFP_KERNEL); + if (mq == NULL) { + dev_err(xpc_part, "xpc_create_gru_mq_uv() failed to kmalloc() " + "a xpc_gru_mq_uv structure\n"); + ret = -ENOMEM; + goto out_1; + } + + pg_order = get_order(mq_size); + mq->order = pg_order + PAGE_SHIFT; + mq_size = 1UL << mq->order; + + mq->mmr_blade = uv_cpu_to_blade_id(cpu); - nid = cpu_to_node(cpuid); - mq_order = get_order(mq_size); + nid = cpu_to_node(cpu); page = alloc_pages_node(nid, GFP_KERNEL | __GFP_ZERO | GFP_THISNODE, - mq_order); + pg_order); if (page == NULL) { dev_err(xpc_part, "xpc_create_gru_mq_uv() failed to alloc %d " "bytes of memory on nid=%d for GRU mq\n", mq_size, nid); - return NULL; + ret = -ENOMEM; + goto out_2; } + mq->address = page_address(page); - mq = page_address(page); - ret = gru_create_message_queue(mq, mq_size); + ret = gru_create_message_queue(mq->address, mq_size); if (ret != 0) { dev_err(xpc_part, "gru_create_message_queue() returned " "error=%d\n", ret); - free_pages((unsigned long)mq, mq_order); - return NULL; + ret = -EINVAL; + goto out_3; } - /* !!! Need to do some other things to set up IRQ */ + /* enable generation of irq when GRU mq operation occurs to this mq */ + ret = xpc_gru_mq_watchlist_alloc_uv(mq); + if (ret != 0) + goto out_3; - ret = request_irq(irq, irq_handler, 0, "xpc", NULL); + ret = xpc_get_gru_mq_irq_uv(mq, cpu, irq_name); + if (ret != 0) + goto out_4; + + ret = request_irq(mq->irq, irq_handler, 0, irq_name, NULL); if (ret != 0) { dev_err(xpc_part, "request_irq(irq=%d) returned error=%d\n", - irq, ret); - free_pages((unsigned long)mq, mq_order); - return NULL; + mq->irq, ret); + goto out_5; } - /* !!! enable generation of irq when GRU mq op occurs to this mq */ - - /* ??? allow other partitions to access GRU mq? */ + /* allow other partitions to access this GRU mq */ + xp_ret = xp_expand_memprotect(xp_pa(mq->address), mq_size); + if (xp_ret != xpSuccess) { + ret = -EACCES; + goto out_6; + } return mq; + + /* something went wrong */ +out_6: + free_irq(mq->irq, NULL); +out_5: + xpc_release_gru_mq_irq_uv(mq); +out_4: + xpc_gru_mq_watchlist_free_uv(mq); +out_3: + free_pages((unsigned long)mq->address, pg_order); +out_2: + kfree(mq); +out_1: + return ERR_PTR(ret); } static void -xpc_destroy_gru_mq_uv(void *mq, unsigned int mq_size, unsigned int irq) +xpc_destroy_gru_mq_uv(struct xpc_gru_mq_uv *mq) { - /* ??? disallow other partitions to access GRU mq? */ + unsigned int mq_size; + int pg_order; + int ret; + + /* disallow other partitions to access GRU mq */ + mq_size = 1UL << mq->order; + ret = xp_restrict_memprotect(xp_pa(mq->address), mq_size); + BUG_ON(ret != xpSuccess); - /* !!! disable generation of irq when GRU mq op occurs to this mq */ + /* unregister irq handler and release mq irq/vector mapping */ + free_irq(mq->irq, NULL); + xpc_release_gru_mq_irq_uv(mq); - free_irq(irq, NULL); + /* disable generation of irq when GRU mq op occurs to this mq */ + xpc_gru_mq_watchlist_free_uv(mq); - free_pages((unsigned long)mq, get_order(mq_size)); + pg_order = mq->order - PAGE_SHIFT; + free_pages((unsigned long)mq->address, pg_order); + + kfree(mq); } static enum xp_retval @@ -402,7 +559,10 @@ xpc_handle_activate_IRQ_uv(int irq, void *dev_id) struct xpc_partition *part; int wakeup_hb_checker = 0; - while ((msg_hdr = gru_get_next_message(xpc_activate_mq_uv)) != NULL) { + while (1) { + msg_hdr = gru_get_next_message(xpc_activate_mq_uv->address); + if (msg_hdr == NULL) + break; partid = msg_hdr->partid; if (partid < 0 || partid >= XP_MAX_NPARTITIONS_UV) { @@ -418,7 +578,7 @@ xpc_handle_activate_IRQ_uv(int irq, void *dev_id) } } - gru_free_message(xpc_activate_mq_uv, msg_hdr); + gru_free_message(xpc_activate_mq_uv->address, msg_hdr); } if (wakeup_hb_checker) @@ -482,7 +642,7 @@ xpc_send_local_activate_IRQ_uv(struct xpc_partition *part, int act_state_req) struct xpc_partition_uv *part_uv = &part->sn.uv; /* - * !!! Make our side think that the remote parition sent an activate + * !!! Make our side think that the remote partition sent an activate * !!! message our way by doing what the activate IRQ handler would * !!! do had one really been sent. */ @@ -500,14 +660,39 @@ static enum xp_retval xpc_get_partition_rsvd_page_pa_uv(void *buf, u64 *cookie, unsigned long *rp_pa, size_t *len) { - /* !!! call the UV version of sn_partition_reserved_page_pa() */ - return xpUnsupported; + s64 status; + enum xp_retval ret; + +#if defined CONFIG_X86_64 + status = uv_bios_reserved_page_pa((u64)buf, cookie, (u64 *)rp_pa, + (u64 *)len); + if (status == BIOS_STATUS_SUCCESS) + ret = xpSuccess; + else if (status == BIOS_STATUS_MORE_PASSES) + ret = xpNeedMoreInfo; + else + ret = xpBiosError; + +#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV + status = sn_partition_reserved_page_pa((u64)buf, cookie, rp_pa, len); + if (status == SALRET_OK) + ret = xpSuccess; + else if (status == SALRET_MORE_PASSES) + ret = xpNeedMoreInfo; + else + ret = xpSalError; + +#else + #error not a supported configuration +#endif + + return ret; } static int xpc_setup_rsvd_page_sn_uv(struct xpc_rsvd_page *rp) { - rp->sn.activate_mq_gpa = uv_gpa(xpc_activate_mq_uv); + rp->sn.activate_mq_gpa = uv_gpa(xpc_activate_mq_uv->address); return 0; } @@ -1411,22 +1596,18 @@ xpc_init_uv(void) return -E2BIG; } - /* ??? The cpuid argument's value is 0, is that what we want? */ - /* !!! The irq argument's value isn't correct. */ - xpc_activate_mq_uv = xpc_create_gru_mq_uv(XPC_ACTIVATE_MQ_SIZE_UV, 0, 0, + xpc_activate_mq_uv = xpc_create_gru_mq_uv(XPC_ACTIVATE_MQ_SIZE_UV, 0, + XPC_ACTIVATE_IRQ_NAME, xpc_handle_activate_IRQ_uv); - if (xpc_activate_mq_uv == NULL) - return -ENOMEM; + if (IS_ERR(xpc_activate_mq_uv)) + return PTR_ERR(xpc_activate_mq_uv); - /* ??? The cpuid argument's value is 0, is that what we want? */ - /* !!! The irq argument's value isn't correct. */ - xpc_notify_mq_uv = xpc_create_gru_mq_uv(XPC_NOTIFY_MQ_SIZE_UV, 0, 0, + xpc_notify_mq_uv = xpc_create_gru_mq_uv(XPC_NOTIFY_MQ_SIZE_UV, 0, + XPC_NOTIFY_IRQ_NAME, xpc_handle_notify_IRQ_uv); - if (xpc_notify_mq_uv == NULL) { - /* !!! The irq argument's value isn't correct. */ - xpc_destroy_gru_mq_uv(xpc_activate_mq_uv, - XPC_ACTIVATE_MQ_SIZE_UV, 0); - return -ENOMEM; + if (IS_ERR(xpc_notify_mq_uv)) { + xpc_destroy_gru_mq_uv(xpc_activate_mq_uv); + return PTR_ERR(xpc_notify_mq_uv); } return 0; @@ -1435,9 +1616,6 @@ xpc_init_uv(void) void xpc_exit_uv(void) { - /* !!! The irq argument's value isn't correct. */ - xpc_destroy_gru_mq_uv(xpc_notify_mq_uv, XPC_NOTIFY_MQ_SIZE_UV, 0); - - /* !!! The irq argument's value isn't correct. */ - xpc_destroy_gru_mq_uv(xpc_activate_mq_uv, XPC_ACTIVATE_MQ_SIZE_UV, 0); + xpc_destroy_gru_mq_uv(xpc_notify_mq_uv); + xpc_destroy_gru_mq_uv(xpc_activate_mq_uv); } diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c index 71513b3af7088e5f1ec115f5c08ff0c16039db04..8e6aa9508f4603dd2f4fa3f986e2612693da78f7 100644 --- a/drivers/misc/sgi-xp/xpnet.c +++ b/drivers/misc/sgi-xp/xpnet.c @@ -153,8 +153,7 @@ xpnet_receive(short partid, int channel, struct xpnet_message *msg) struct sk_buff *skb; void *dst; enum xp_retval ret; - struct xpnet_dev_private *priv = - (struct xpnet_dev_private *)xpnet_device->priv; + struct xpnet_dev_private *priv = netdev_priv(xpnet_device); if (!XPNET_VALID_MSG(msg)) { /* @@ -368,9 +367,7 @@ xpnet_dev_set_config(struct net_device *dev, struct ifmap *new_map) static struct net_device_stats * xpnet_dev_get_stats(struct net_device *dev) { - struct xpnet_dev_private *priv; - - priv = (struct xpnet_dev_private *)dev->priv; + struct xpnet_dev_private *priv = netdev_priv(dev); return &priv->stats; } @@ -456,7 +453,7 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) struct xpnet_pending_msg *queued_msg; u64 start_addr, end_addr; short dest_partid; - struct xpnet_dev_private *priv = (struct xpnet_dev_private *)dev->priv; + struct xpnet_dev_private *priv = netdev_priv(dev); u16 embedded_bytes = 0; dev_dbg(xpnet, ">skb->head=0x%p skb->data=0x%p skb->tail=0x%p " @@ -541,9 +538,7 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) static void xpnet_dev_tx_timeout(struct net_device *dev) { - struct xpnet_dev_private *priv; - - priv = (struct xpnet_dev_private *)dev->priv; + struct xpnet_dev_private *priv = netdev_priv(dev); priv->stats.tx_errors++; return; diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c index 7d15e7c6bcad51f65860ff6b42e09881e8e2064a..3d1318a3e6885901a5f1e4efab65b0964a5dc48e 100644 --- a/drivers/net/3c501.c +++ b/drivers/net/3c501.c @@ -297,8 +297,8 @@ static int __init el1_probe1(struct net_device *dev, int ioaddr) if (el_debug) printk(KERN_DEBUG "%s", version); - memset(dev->priv, 0, sizeof(struct net_local)); lp = netdev_priv(dev); + memset(lp, 0, sizeof(struct net_local)); spin_lock_init(&lp->lock); /* @@ -725,7 +725,6 @@ static void el_receive(struct net_device *dev) insb(DATAPORT, skb_put(skb, pkt_len), pkt_len); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } diff --git a/drivers/net/3c501.h b/drivers/net/3c501.h index cfec64efff78017b5db4ee3dd6d24ac42a983e32..f40b0493337a05162b2e522c09c5d7b867dbd52a 100644 --- a/drivers/net/3c501.h +++ b/drivers/net/3c501.h @@ -23,7 +23,7 @@ static const struct ethtool_ops netdev_ethtool_ops; static int el_debug = EL_DEBUG; /* - * Board-specific info in dev->priv. + * Board-specific info in netdev_priv(dev). */ struct net_local diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c index 900b0ffdcc686c576e5eefaddd973eff7a80b018..c092c3929224d6fd3925f53107cea65ca427aa3f 100644 --- a/drivers/net/3c503.c +++ b/drivers/net/3c503.c @@ -168,6 +168,21 @@ struct net_device * __init el2_probe(int unit) } #endif +static const struct net_device_ops el2_netdev_ops = { + .ndo_open = el2_open, + .ndo_stop = el2_close, + + .ndo_start_xmit = eip_start_xmit, + .ndo_tx_timeout = eip_tx_timeout, + .ndo_get_stats = eip_get_stats, + .ndo_set_multicast_list = eip_set_multicast_list, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = eip_poll, +#endif +}; + /* Probe for the Etherlink II card at I/O port base IOADDR, returning non-zero on success. If found, set the station address and memory parameters in DEVICE. */ @@ -177,7 +192,6 @@ el2_probe1(struct net_device *dev, int ioaddr) int i, iobase_reg, membase_reg, saved_406, wordlength, retval; static unsigned version_printed; unsigned long vendor_id; - DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, EL2_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -228,7 +242,7 @@ el2_probe1(struct net_device *dev, int ioaddr) /* Retrieve and print the ethernet address. */ for (i = 0; i < 6; i++) dev->dev_addr[i] = inb(ioaddr + i); - printk("%s", print_mac(mac, dev->dev_addr)); + printk("%pM", dev->dev_addr); /* Map the 8390 back into the window. */ outb(ECNTRL_THIN, ioaddr + 0x406); @@ -336,8 +350,7 @@ el2_probe1(struct net_device *dev, int ioaddr) ei_status.saved_irq = dev->irq; - dev->open = &el2_open; - dev->stop = &el2_close; + dev->netdev_ops = &el2_netdev_ops; dev->ethtool_ops = &netdev_ethtool_ops; #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = eip_poll; diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c index a424869707a5225b1f04e9d2e070a87d1987f19a..6124605bef05404bb2dee77114d5f8fcd1a1aff8 100644 --- a/drivers/net/3c505.c +++ b/drivers/net/3c505.c @@ -203,10 +203,10 @@ static inline int inb_command(unsigned int base_addr) static inline void outb_control(unsigned char val, struct net_device *dev) { outb(val, dev->base_addr + PORT_CONTROL); - ((elp_device *)(dev->priv))->hcr_val = val; + ((elp_device *)(netdev_priv(dev)))->hcr_val = val; } -#define HCR_VAL(x) (((elp_device *)((x)->priv))->hcr_val) +#define HCR_VAL(x) (((elp_device *)(netdev_priv(x)))->hcr_val) static inline void outb_command(unsigned char val, unsigned int base_addr) { @@ -247,7 +247,7 @@ static inline int get_status(unsigned int base_addr) static inline void set_hsf(struct net_device *dev, int hsf) { - elp_device *adapter = dev->priv; + elp_device *adapter = netdev_priv(dev); unsigned long flags; spin_lock_irqsave(&adapter->lock, flags); @@ -260,7 +260,7 @@ static bool start_receive(struct net_device *, pcb_struct *); static inline void adapter_reset(struct net_device *dev) { unsigned long timeout; - elp_device *adapter = dev->priv; + elp_device *adapter = netdev_priv(dev); unsigned char orig_hcr = adapter->hcr_val; outb_control(0, dev); @@ -293,7 +293,7 @@ static inline void adapter_reset(struct net_device *dev) */ static inline void check_3c505_dma(struct net_device *dev) { - elp_device *adapter = dev->priv; + elp_device *adapter = netdev_priv(dev); if (adapter->dmaing && time_after(jiffies, adapter->current_dma.start_time + 10)) { unsigned long flags, f; printk(KERN_ERR "%s: DMA %s timed out, %d bytes left\n", dev->name, adapter->current_dma.direction ? "download" : "upload", get_dma_residue(dev->dma)); @@ -340,7 +340,7 @@ static inline bool send_pcb_fast(unsigned int base_addr, unsigned char byte) /* Check to see if the receiver needs restarting, and kick it if so */ static inline void prime_rx(struct net_device *dev) { - elp_device *adapter = dev->priv; + elp_device *adapter = netdev_priv(dev); while (adapter->rx_active < ELP_RX_PCBS && netif_running(dev)) { if (!start_receive(dev, &adapter->itx_pcb)) break; @@ -375,7 +375,7 @@ static bool send_pcb(struct net_device *dev, pcb_struct * pcb) { int i; unsigned long timeout; - elp_device *adapter = dev->priv; + elp_device *adapter = netdev_priv(dev); unsigned long flags; check_3c505_dma(dev); @@ -463,7 +463,7 @@ static bool receive_pcb(struct net_device *dev, pcb_struct * pcb) unsigned long timeout; unsigned long flags; - elp_device *adapter = dev->priv; + elp_device *adapter = netdev_priv(dev); set_hsf(dev, 0); @@ -543,7 +543,7 @@ static bool receive_pcb(struct net_device *dev, pcb_struct * pcb) static bool start_receive(struct net_device *dev, pcb_struct * tx_pcb) { bool status; - elp_device *adapter = dev->priv; + elp_device *adapter = netdev_priv(dev); if (elp_debug >= 3) printk(KERN_DEBUG "%s: restarting receiver\n", dev->name); @@ -571,7 +571,7 @@ static bool start_receive(struct net_device *dev, pcb_struct * tx_pcb) static void receive_packet(struct net_device *dev, int len) { int rlen; - elp_device *adapter = dev->priv; + elp_device *adapter = netdev_priv(dev); void *target; struct sk_buff *skb; unsigned long flags; @@ -638,13 +638,10 @@ static irqreturn_t elp_interrupt(int irq, void *dev_id) int len; int dlen; int icount = 0; - struct net_device *dev; - elp_device *adapter; + struct net_device *dev = dev_id; + elp_device *adapter = netdev_priv(dev); unsigned long timeout; - dev = dev_id; - adapter = (elp_device *) dev->priv; - spin_lock(&adapter->lock); do { @@ -672,7 +669,6 @@ static irqreturn_t elp_interrupt(int irq, void *dev_id) skb->protocol = eth_type_trans(skb,dev); dev->stats.rx_bytes += skb->len; netif_rx(skb); - dev->last_rx = jiffies; } } adapter->dmaing = 0; @@ -838,11 +834,9 @@ static irqreturn_t elp_interrupt(int irq, void *dev_id) static int elp_open(struct net_device *dev) { - elp_device *adapter; + elp_device *adapter = netdev_priv(dev); int retval; - adapter = dev->priv; - if (elp_debug >= 3) printk(KERN_DEBUG "%s: request to open device\n", dev->name); @@ -971,7 +965,7 @@ static int elp_open(struct net_device *dev) static bool send_packet(struct net_device *dev, struct sk_buff *skb) { - elp_device *adapter = dev->priv; + elp_device *adapter = netdev_priv(dev); unsigned long target; unsigned long flags; @@ -1062,7 +1056,7 @@ static void elp_timeout(struct net_device *dev) static int elp_start_xmit(struct sk_buff *skb, struct net_device *dev) { unsigned long flags; - elp_device *adapter = dev->priv; + elp_device *adapter = netdev_priv(dev); spin_lock_irqsave(&adapter->lock, flags); check_3c505_dma(dev); @@ -1104,7 +1098,7 @@ static int elp_start_xmit(struct sk_buff *skb, struct net_device *dev) static struct net_device_stats *elp_get_stats(struct net_device *dev) { - elp_device *adapter = (elp_device *) dev->priv; + elp_device *adapter = netdev_priv(dev); if (elp_debug >= 3) printk(KERN_DEBUG "%s: request for stats\n", dev->name); @@ -1166,9 +1160,7 @@ static const struct ethtool_ops netdev_ethtool_ops = { static int elp_close(struct net_device *dev) { - elp_device *adapter; - - adapter = dev->priv; + elp_device *adapter = netdev_priv(dev); if (elp_debug >= 3) printk(KERN_DEBUG "%s: request to close device\n", dev->name); @@ -1209,7 +1201,7 @@ static int elp_close(struct net_device *dev) static void elp_set_mc_list(struct net_device *dev) { - elp_device *adapter = (elp_device *) dev->priv; + elp_device *adapter = netdev_priv(dev); struct dev_mc_list *dmi = dev->mc_list; int i; unsigned long flags; @@ -1380,12 +1372,11 @@ static int __init elp_autodetect(struct net_device *dev) static int __init elplus_setup(struct net_device *dev) { - elp_device *adapter = dev->priv; + elp_device *adapter = netdev_priv(dev); int i, tries, tries1, okay; unsigned long timeout; unsigned long cookie = 0; int err = -ENODEV; - DECLARE_MAC_BUF(mac); /* * setup adapter structure @@ -1522,9 +1513,9 @@ static int __init elplus_setup(struct net_device *dev) * print remainder of startup message */ printk(KERN_INFO "%s: 3c505 at %#lx, irq %d, dma %d, " - "addr %s, ", + "addr %pM, ", dev->name, dev->base_addr, dev->irq, dev->dma, - print_mac(mac, dev->dev_addr)); + dev->dev_addr); /* * read more information from the adapter diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c index 030c147211baf1184662c7d69373277cd309474c..423e65d0ba737740091fa9488f5305776475200b 100644 --- a/drivers/net/3c507.c +++ b/drivers/net/3c507.c @@ -357,7 +357,6 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr) static unsigned char init_ID_done, version_printed; int i, irq, irqval, retval; struct net_local *lp; - DECLARE_MAC_BUF(mac); if (init_ID_done == 0) { ushort lrs_state = 0xff; @@ -405,7 +404,7 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr) outb(0x01, ioaddr + MISC_CTRL); for (i = 0; i < 6; i++) dev->dev_addr[i] = inb(ioaddr + i); - printk(" %s", print_mac(mac, dev->dev_addr)); + printk(" %pM", dev->dev_addr); if (mem_start) net_debug = mem_start & 7; @@ -866,7 +865,6 @@ static void el16_rx(struct net_device *dev) skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } @@ -938,14 +936,3 @@ cleanup_module(void) } #endif /* MODULE */ MODULE_LICENSE("GPL"); - - -/* - * Local variables: - * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -I/usr/src/linux/drivers/net -Wall -Wstrict-prototypes -O6 -m486 -c 3c507.c" - * version-control: t - * kept-new-versions: 5 - * tab-width: 4 - * c-indent-level: 4 - * End: - */ diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index c7a4f3bcc2bc1fd31f597304c6fff13ee0aaba3b..535c234286ea80c27f8a2ca8170b88b1b9c87208 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -541,7 +541,6 @@ static int __devinit el3_common_init(struct net_device *dev) { struct el3_private *lp = netdev_priv(dev); int err; - DECLARE_MAC_BUF(mac); const char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"}; spin_lock_init(&lp->lock); @@ -575,9 +574,9 @@ static int __devinit el3_common_init(struct net_device *dev) } printk(KERN_INFO "%s: 3c5x9 found at %#3.3lx, %s port, " - "address %s, IRQ %d.\n", + "address %pM, IRQ %d.\n", dev->name, dev->base_addr, if_names[(dev->if_port & 0x03)], - print_mac(mac, dev->dev_addr), dev->irq); + dev->dev_addr, dev->irq); if (el3_debug > 0) printk(KERN_INFO "%s", version); @@ -1075,7 +1074,6 @@ el3_rx(struct net_device *dev) outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */ skb->protocol = eth_type_trans(skb,dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_bytes += pkt_len; dev->stats.rx_packets++; continue; diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c index a0f8b6e2d0af80af13b5774fe40ec9c5ee132db7..39ac12233aa72778362d0e00eee37830f7d387ce 100644 --- a/drivers/net/3c515.c +++ b/drivers/net/3c515.c @@ -570,7 +570,6 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr, unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */ int i; int irq; - DECLARE_MAC_BUF(mac); #ifdef __ISAPNP__ if (idev) { @@ -636,7 +635,7 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr, checksum = (checksum ^ (checksum >> 8)) & 0xff; if (checksum != 0x00) printk(" ***INVALID CHECKSUM %4.4x*** ", checksum); - printk(" %s", print_mac(mac, dev->dev_addr)); + printk(" %pM", dev->dev_addr); if (eeprom[16] == 0x11c7) { /* Corkscrew */ if (request_dma(dev->dma, "3c515")) { printk(", DMA %d allocation failed", dev->dma); @@ -1302,7 +1301,6 @@ static int corkscrew_rx(struct net_device *dev) outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */ skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; /* Wait a limited time to go to next packet. */ @@ -1389,7 +1387,6 @@ static int boomerang_rx(struct net_device *dev) } skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; } entry = (++vp->cur_rx) % RX_RING_SIZE; @@ -1580,11 +1577,3 @@ void cleanup_module(void) } } #endif /* MODULE */ - -/* - * Local variables: - * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c515.c" - * c-indent-level: 4 - * tab-width: 4 - * End: - */ diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c index e2ce41d3828ed47e90b31c7e09d7cb29649a1373..ff41e1ff56031876862db4a387c45a0dedb5d0b9 100644 --- a/drivers/net/3c523.c +++ b/drivers/net/3c523.c @@ -308,7 +308,7 @@ static int elmc_open(struct net_device *dev) static int __init check586(struct net_device *dev, unsigned long where, unsigned size) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); char *iscp_addrs[2]; int i = 0; @@ -347,9 +347,9 @@ static int __init check586(struct net_device *dev, unsigned long where, unsigned * set iscp at the right place, called by elmc_probe and open586. */ -void alloc586(struct net_device *dev) +static void alloc586(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); elmc_id_reset586(); DELAY(2); @@ -383,7 +383,6 @@ static int elmc_getinfo(char *buf, int slot, void *d) { int len = 0; struct net_device *dev = d; - DECLARE_MAC_BUF(mac); if (dev == NULL) return len; @@ -398,8 +397,8 @@ static int elmc_getinfo(char *buf, int slot, void *d) len += sprintf(buf + len, "Transceiver: %s\n", dev->if_port ? "External" : "Internal"); len += sprintf(buf + len, "Device: %s\n", dev->name); - len += sprintf(buf + len, "Hardware Address: %s\n", - print_mac(mac, dev->dev_addr)); + len += sprintf(buf + len, "Hardware Address: %pM\n", + dev->dev_addr); return len; } /* elmc_getinfo() */ @@ -416,8 +415,7 @@ static int __init do_elmc_probe(struct net_device *dev) int i = 0; unsigned int size = 0; int retval; - struct priv *pr = dev->priv; - DECLARE_MAC_BUF(mac); + struct priv *pr = netdev_priv(dev); if (MCA_bus == 0) { return -ENODEV; @@ -543,8 +541,8 @@ static int __init do_elmc_probe(struct net_device *dev) for (i = 0; i < 6; i++) dev->dev_addr[i] = inb(dev->base_addr + i); - printk(KERN_INFO "%s: hardware address %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: hardware address %pM\n", + dev->name, dev->dev_addr); dev->open = &elmc_open; dev->stop = &elmc_close; @@ -578,13 +576,14 @@ static int __init do_elmc_probe(struct net_device *dev) return retval; } +#ifdef MODULE static void cleanup_card(struct net_device *dev) { - mca_set_adapter_procfn(((struct priv *) (dev->priv))->slot, NULL, NULL); + mca_set_adapter_procfn(((struct priv *)netdev_priv(dev))->slot, + NULL, NULL); release_region(dev->base_addr, ELMC_IO_EXTENT); } - -#ifndef MODULE +#else struct net_device * __init elmc_probe(int unit) { struct net_device *dev = alloc_etherdev(sizeof(struct priv)); @@ -616,7 +615,7 @@ static int init586(struct net_device *dev) void *ptr; unsigned long s; int i, result = 0; - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); volatile struct configure_cmd_struct *cfg_cmd; volatile struct iasetup_cmd_struct *ias_cmd; volatile struct tdr_cmd_struct *tdr_cmd; @@ -852,7 +851,7 @@ static void *alloc_rfa(struct net_device *dev, void *ptr) volatile struct rfd_struct *rfd = (struct rfd_struct *) ptr; volatile struct rbd_struct *rbd; int i; - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); memset((char *) rfd, 0, sizeof(struct rfd_struct) * p->num_recv_buffs); p->rfd_first = rfd; @@ -913,7 +912,7 @@ elmc_interrupt(int irq, void *dev_id) } /* reading ELMC_CTRL also clears the INT bit. */ - p = (struct priv *) dev->priv; + p = netdev_priv(dev); while ((stat = p->scb->status & STAT_MASK)) { @@ -969,7 +968,7 @@ static void elmc_rcv_int(struct net_device *dev) unsigned short totlen; struct sk_buff *skb; struct rbd_struct *rbd; - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); for (; (status = p->rfd_top->status) & STAT_COMPL;) { rbd = (struct rbd_struct *) make32(p->rfd_top->rbd_offset); @@ -985,7 +984,6 @@ static void elmc_rcv_int(struct net_device *dev) skb_copy_to_linear_data(skb, (char *) p->base+(unsigned long) rbd->buffer,totlen); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += totlen; } else { @@ -1013,7 +1011,7 @@ static void elmc_rcv_int(struct net_device *dev) static void elmc_rnr_int(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); dev->stats.rx_errors++; @@ -1036,7 +1034,7 @@ static void elmc_rnr_int(struct net_device *dev) static void elmc_xmt_int(struct net_device *dev) { int status; - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); status = p->xmit_cmds[p->xmit_last]->cmd_status; if (!(status & STAT_COMPL)) { @@ -1079,7 +1077,7 @@ static void elmc_xmt_int(struct net_device *dev) static void startrecv586(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); p->scb->rfa_offset = make16(p->rfd_first); p->scb->cmd = RUC_START; @@ -1093,7 +1091,7 @@ static void startrecv586(struct net_device *dev) static void elmc_timeout(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); /* COMMAND-UNIT active? */ if (p->scb->status & CU_ACTIVE) { #ifdef DEBUG @@ -1129,7 +1127,7 @@ static int elmc_send_packet(struct sk_buff *skb, struct net_device *dev) #ifndef NO_NOPCOMMANDS int next_nop; #endif - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); netif_stop_queue(dev); @@ -1200,7 +1198,7 @@ static int elmc_send_packet(struct sk_buff *skb, struct net_device *dev) static struct net_device_stats *elmc_get_stats(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); unsigned short crc, aln, rsc, ovrn; crc = p->scb->crc_errs; /* get error-statistic from the ni82586 */ diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c index abc84f765973e2c30ef55b8e5c34973799dad415..2df3af3b9b20130ead927f93db05730029430d9c 100644 --- a/drivers/net/3c527.c +++ b/drivers/net/3c527.c @@ -335,7 +335,6 @@ static int __init mc32_probe1(struct net_device *dev, int slot) "82586 initialisation failure", "Adapter list configuration error" }; - DECLARE_MAC_BUF(mac); /* Time to play MCA games */ @@ -405,7 +404,7 @@ static int __init mc32_probe1(struct net_device *dev, int slot) dev->dev_addr[i] = mca_read_pos(slot,3); } - printk("%s: Address %s", dev->name, print_mac(mac, dev->dev_addr)); + printk("%s: Address %pM", dev->name, dev->dev_addr); mca_write_pos(slot, 6, 0); mca_write_pos(slot, 7, 0); @@ -1187,7 +1186,6 @@ static void mc32_rx_ring(struct net_device *dev) } skb->protocol=eth_type_trans(skb,dev); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += length; netif_rx(skb); diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 9ba295d9dd973b5713f7d49150a3807899ff3a77..665e7fdf27a15707f2a7aeffae50346371ff4ec1 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -803,7 +803,7 @@ static int vortex_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *dev = pci_get_drvdata(pdev); - if (dev && dev->priv) { + if (dev && netdev_priv(dev)) { if (netif_running(dev)) { netif_device_detach(dev); vortex_down(dev, 1); @@ -1013,7 +1013,6 @@ static int __devinit vortex_probe1(struct device *gendev, const char *print_name = "3c59x"; struct pci_dev *pdev = NULL; struct eisa_device *edev = NULL; - DECLARE_MAC_BUF(mac); if (!printed_version) { printk (version); @@ -1026,7 +1025,7 @@ static int __devinit vortex_probe1(struct device *gendev, } if ((edev = DEVICE_EISA(gendev))) { - print_name = edev->dev.bus_id; + print_name = dev_name(&edev->dev); } } @@ -1206,7 +1205,7 @@ static int __devinit vortex_probe1(struct device *gendev, ((__be16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]); memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); if (print_info) - printk(" %s", print_mac(mac, dev->dev_addr)); + printk(" %pM", dev->dev_addr); /* Unfortunately an all zero eeprom passes the checksum and this gets found in the wild in failure cases. Crypto is hard 8) */ if (!is_valid_ether_addr(dev->dev_addr)) { @@ -2447,7 +2446,6 @@ static int vortex_rx(struct net_device *dev) iowrite16(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */ skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; /* Wait a limited time to go to next packet. */ for (i = 200; i >= 0; i--) @@ -2530,7 +2528,6 @@ boomerang_rx(struct net_device *dev) } } netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; } entry = (++vp->cur_rx) % RX_RING_SIZE; @@ -2886,7 +2883,7 @@ static void vortex_get_drvinfo(struct net_device *dev, strcpy(info->bus_info, pci_name(VORTEX_PCI(vp))); } else { if (VORTEX_EISA(vp)) - sprintf(info->bus_info, vp->gendev->bus_id); + sprintf(info->bus_info, dev_name(vp->gendev)); else sprintf(info->bus_info, "EISA 0x%lx %d", dev->base_addr, dev->irq); @@ -3217,7 +3214,7 @@ static void __exit vortex_eisa_cleanup(void) #endif if (compaq_net_device) { - vp = compaq_net_device->priv; + vp = netdev_priv(compaq_net_device); ioaddr = ioport_map(compaq_net_device->base_addr, VORTEX_TOTAL_SIZE); diff --git a/drivers/net/7990.c b/drivers/net/7990.c index ad6b8a5b6574b4865b327bff0bb719878316ce27..7a331acc34add0b755b92c1c4379f4292c5b14e8 100644 --- a/drivers/net/7990.c +++ b/drivers/net/7990.c @@ -336,7 +336,6 @@ static int lance_rx (struct net_device *dev) len); skb->protocol = eth_type_trans (skb, dev); netif_rx (skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += len; } diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 9ba1f0b4642950d860375768c21bdae6624c321f..dd7ac8290aecfc7323554e90ab0850fe64713346 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -457,7 +457,6 @@ static inline void cp_rx_skb (struct cp_private *cp, struct sk_buff *skb, cp->dev->stats.rx_packets++; cp->dev->stats.rx_bytes += skb->len; - cp->dev->last_rx = jiffies; #if CP_VLAN_TAG_USED if (cp->vlgrp && (desc->opts2 & cpu_to_le32(RxVlanTagged))) { @@ -605,7 +604,7 @@ static int cp_rx_poll(struct napi_struct *napi, int budget) spin_lock_irqsave(&cp->lock, flags); cpw16_f(IntrMask, cp_intr_mask); - __netif_rx_complete(dev, napi); + __netif_rx_complete(napi); spin_unlock_irqrestore(&cp->lock, flags); } @@ -642,9 +641,9 @@ static irqreturn_t cp_interrupt (int irq, void *dev_instance) } if (status & (RxOK | RxErr | RxEmpty | RxFIFOOvr)) - if (netif_rx_schedule_prep(dev, &cp->napi)) { + if (netif_rx_schedule_prep(&cp->napi)) { cpw16_f(IntrMask, cp_norx_intr_mask); - __netif_rx_schedule(dev, &cp->napi); + __netif_rx_schedule(&cp->napi); } if (status & (TxOK | TxErr | TxEmpty | SWInt)) @@ -1818,6 +1817,26 @@ static void cp_set_d3_state (struct cp_private *cp) pci_set_power_state (cp->pdev, PCI_D3hot); } +static const struct net_device_ops cp_netdev_ops = { + .ndo_open = cp_open, + .ndo_stop = cp_close, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = cp_set_rx_mode, + .ndo_get_stats = cp_get_stats, + .ndo_do_ioctl = cp_ioctl, + .ndo_start_xmit = cp_start_xmit, + .ndo_tx_timeout = cp_tx_timeout, +#if CP_VLAN_TAG_USED + .ndo_vlan_rx_register = cp_vlan_rx_register, +#endif +#ifdef BROKEN + .ndo_change_mtu = cp_change_mtu, +#endif +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = cp_poll_controller, +#endif +}; + static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { struct net_device *dev; @@ -1826,7 +1845,6 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) void __iomem *regs; resource_size_t pciaddr; unsigned int addr_len, i, pci_using_dac; - DECLARE_MAC_BUF(mac); #ifndef MODULE static int version_printed; @@ -1931,26 +1949,13 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) cpu_to_le16(read_eeprom (regs, i + 7, addr_len)); memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); - dev->open = cp_open; - dev->stop = cp_close; - dev->set_multicast_list = cp_set_rx_mode; - dev->hard_start_xmit = cp_start_xmit; - dev->get_stats = cp_get_stats; - dev->do_ioctl = cp_ioctl; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = cp_poll_controller; -#endif + dev->netdev_ops = &cp_netdev_ops; netif_napi_add(dev, &cp->napi, cp_rx_poll, 16); -#ifdef BROKEN - dev->change_mtu = cp_change_mtu; -#endif dev->ethtool_ops = &cp_ethtool_ops; - dev->tx_timeout = cp_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; #if CP_VLAN_TAG_USED dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - dev->vlan_rx_register = cp_vlan_rx_register; #endif if (pci_using_dac) @@ -1967,10 +1972,10 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_iomap; printk (KERN_INFO "%s: RTL-8139C+ at 0x%lx, " - "%s, IRQ %d\n", + "%pM, IRQ %d\n", dev->name, dev->base_addr, - print_mac(mac, dev->dev_addr), + dev->dev_addr, dev->irq); pci_set_drvdata(pdev, dev); diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 63f906b04899de12271baa196bc7b424d0c067f8..fe370f8057933244e544cd5849e064e514edaa11 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -741,8 +741,7 @@ static void rtl8139_chip_reset (void __iomem *ioaddr) } -static int __devinit rtl8139_init_board (struct pci_dev *pdev, - struct net_device **dev_out) +static __devinit struct net_device * rtl8139_init_board (struct pci_dev *pdev) { void __iomem *ioaddr; struct net_device *dev; @@ -756,13 +755,11 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev, assert (pdev != NULL); - *dev_out = NULL; - /* dev and priv zeroed in alloc_etherdev */ dev = alloc_etherdev (sizeof (*tp)); if (dev == NULL) { dev_err(&pdev->dev, "Unable to alloc new net device\n"); - return -ENOMEM; + return ERR_PTR(-ENOMEM); } SET_NETDEV_DEV(dev, &pdev->dev); @@ -906,16 +903,29 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev, rtl8139_chip_reset (ioaddr); - *dev_out = dev; - return 0; + return dev; err_out: __rtl8139_cleanup_dev (dev); if (disable_dev_on_err) pci_disable_device (pdev); - return rc; + return ERR_PTR(rc); } +static const struct net_device_ops rtl8139_netdev_ops = { + .ndo_open = rtl8139_open, + .ndo_stop = rtl8139_close, + .ndo_get_stats = rtl8139_get_stats, + .ndo_validate_addr = eth_validate_addr, + .ndo_start_xmit = rtl8139_start_xmit, + .ndo_set_multicast_list = rtl8139_set_rx_mode, + .ndo_do_ioctl = netdev_ioctl, + .ndo_tx_timeout = rtl8139_tx_timeout, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = rtl8139_poll_controller, +#endif + +}; static int __devinit rtl8139_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) @@ -925,7 +935,6 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, int i, addr_len, option; void __iomem *ioaddr; static int board_idx = -1; - DECLARE_MAC_BUF(mac); assert (pdev != NULL); assert (ent != NULL); @@ -959,9 +968,9 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, use_io = 1; } - i = rtl8139_init_board (pdev, &dev); - if (i < 0) - return i; + dev = rtl8139_init_board (pdev); + if (IS_ERR(dev)) + return PTR_ERR(dev); assert (dev != NULL); tp = netdev_priv(dev); @@ -977,19 +986,10 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); /* The Rtl8139-specific entries in the device structure. */ - dev->open = rtl8139_open; - dev->hard_start_xmit = rtl8139_start_xmit; - netif_napi_add(dev, &tp->napi, rtl8139_poll, 64); - dev->stop = rtl8139_close; - dev->get_stats = rtl8139_get_stats; - dev->set_multicast_list = rtl8139_set_rx_mode; - dev->do_ioctl = netdev_ioctl; + dev->netdev_ops = &rtl8139_netdev_ops; dev->ethtool_ops = &rtl8139_ethtool_ops; - dev->tx_timeout = rtl8139_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = rtl8139_poll_controller; -#endif + netif_napi_add(dev, &tp->napi, rtl8139_poll, 64); /* note: the hardware is not capable of sg/csum/highdma, however * through the use of skb_copy_and_csum_dev we enable these @@ -1024,11 +1024,11 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, pci_set_drvdata (pdev, dev); printk (KERN_INFO "%s: %s at 0x%lx, " - "%s, IRQ %d\n", + "%pM, IRQ %d\n", dev->name, board_info[ent->driver_data].name, dev->base_addr, - print_mac(mac, dev->dev_addr), + dev->dev_addr, dev->irq); printk (KERN_DEBUG "%s: Identified 8139 chip type '%s'\n", @@ -2026,7 +2026,6 @@ static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp, skb->protocol = eth_type_trans (skb, dev); - dev->last_rx = jiffies; dev->stats.rx_bytes += pkt_size; dev->stats.rx_packets++; @@ -2129,7 +2128,7 @@ static int rtl8139_poll(struct napi_struct *napi, int budget) */ spin_lock_irqsave(&tp->lock, flags); RTL_W16_F(IntrMask, rtl8139_intr_mask); - __netif_rx_complete(dev, napi); + __netif_rx_complete(napi); spin_unlock_irqrestore(&tp->lock, flags); } spin_unlock(&tp->rx_lock); @@ -2179,9 +2178,9 @@ static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance) /* Receive packets are processed by poll routine. If not running start it now. */ if (status & RxAckBits){ - if (netif_rx_schedule_prep(dev, &tp->napi)) { + if (netif_rx_schedule_prep(&tp->napi)) { RTL_W16_F (IntrMask, rtl8139_norx_intr_mask); - __netif_rx_schedule(dev, &tp->napi); + __netif_rx_schedule(&tp->napi); } } diff --git a/drivers/net/82596.c b/drivers/net/82596.c index da292e647eb117c496e3c4c6f6108e0e8c316c94..b273596368e36d9c2a99e1143b673e518f93aeed 100644 --- a/drivers/net/82596.c +++ b/drivers/net/82596.c @@ -457,7 +457,7 @@ static inline int wait_cfg(struct net_device *dev, struct i596_cmd *cmd, int del static void i596_display_data(struct net_device *dev) { - struct i596_private *lp = dev->priv; + struct i596_private *lp = dev->ml_priv; struct i596_cmd *cmd; struct i596_rfd *rfd; struct i596_rbd *rbd; @@ -527,7 +527,7 @@ static irqreturn_t i596_error(int irq, void *dev_id) static inline void init_rx_bufs(struct net_device *dev) { - struct i596_private *lp = dev->priv; + struct i596_private *lp = dev->ml_priv; int i; struct i596_rfd *rfd; struct i596_rbd *rbd; @@ -578,7 +578,7 @@ static inline void init_rx_bufs(struct net_device *dev) static inline void remove_rx_bufs(struct net_device *dev) { - struct i596_private *lp = dev->priv; + struct i596_private *lp = dev->ml_priv; struct i596_rbd *rbd; int i; @@ -592,7 +592,7 @@ static inline void remove_rx_bufs(struct net_device *dev) static void rebuild_rx_bufs(struct net_device *dev) { - struct i596_private *lp = dev->priv; + struct i596_private *lp = dev->ml_priv; int i; /* Ensure rx frame/buffer descriptors are tidy */ @@ -611,7 +611,7 @@ static void rebuild_rx_bufs(struct net_device *dev) static int init_i596_mem(struct net_device *dev) { - struct i596_private *lp = dev->priv; + struct i596_private *lp = dev->ml_priv; #if !defined(ENABLE_MVME16x_NET) && !defined(ENABLE_BVME6000_NET) || defined(ENABLE_APRICOT) short ioaddr = dev->base_addr; #endif @@ -764,7 +764,7 @@ static int init_i596_mem(struct net_device *dev) static inline int i596_rx(struct net_device *dev) { - struct i596_private *lp = dev->priv; + struct i596_private *lp = dev->ml_priv; struct i596_rfd *rfd; struct i596_rbd *rbd; int frames = 0; @@ -841,7 +841,6 @@ static inline int i596_rx(struct net_device *dev) pkt_len); #endif netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes+=pkt_len; } @@ -959,7 +958,7 @@ static void i596_reset(struct net_device *dev, struct i596_private *lp, static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd) { - struct i596_private *lp = dev->priv; + struct i596_private *lp = dev->ml_priv; int ioaddr = dev->base_addr; unsigned long flags; @@ -1029,7 +1028,7 @@ static int i596_open(struct net_device *dev) static void i596_tx_timeout (struct net_device *dev) { - struct i596_private *lp = dev->priv; + struct i596_private *lp = dev->ml_priv; int ioaddr = dev->base_addr; /* Transmitter timeout, serious problems. */ @@ -1058,7 +1057,7 @@ static void i596_tx_timeout (struct net_device *dev) static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct i596_private *lp = dev->priv; + struct i596_private *lp = dev->ml_priv; struct tx_cmd *tx_cmd; struct i596_tbd *tbd; short length = skb->len; @@ -1116,12 +1115,8 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) static void print_eth(unsigned char *add, char *str) { - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); - - printk(KERN_DEBUG "i596 0x%p, %s --> %s %02X%02X, %s\n", - add, print_mac(mac, add + 6), print_mac(mac2, add), - add[12], add[13], str); + printk(KERN_DEBUG "i596 0x%p, %pM --> %pM %02X%02X, %s\n", + add, add + 6, add, add[12], add[13], str); } static int io = 0x300; @@ -1244,9 +1239,9 @@ struct net_device * __init i82596_probe(int unit) dev->tx_timeout = i596_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; - dev->priv = (void *)(dev->mem_start); + dev->ml_priv = (void *)(dev->mem_start); - lp = dev->priv; + lp = dev->ml_priv; DEB(DEB_INIT,printk(KERN_DEBUG "%s: lp at 0x%08lx (%zd bytes), " "lp->scb at 0x%08lx\n", dev->name, (unsigned long)lp, @@ -1307,7 +1302,7 @@ static irqreturn_t i596_interrupt(int irq, void *dev_id) } ioaddr = dev->base_addr; - lp = dev->priv; + lp = dev->ml_priv; spin_lock (&lp->lock); @@ -1450,7 +1445,7 @@ static irqreturn_t i596_interrupt(int irq, void *dev_id) static int i596_close(struct net_device *dev) { - struct i596_private *lp = dev->priv; + struct i596_private *lp = dev->ml_priv; unsigned long flags; netif_stop_queue(dev); @@ -1500,7 +1495,7 @@ static int i596_close(struct net_device *dev) static void set_multicast_list(struct net_device *dev) { - struct i596_private *lp = dev->priv; + struct i596_private *lp = dev->ml_priv; int config = 0, cnt; DEB(DEB_MULTI,printk(KERN_DEBUG "%s: set multicast list, %d entries, promisc %s, allmulti %s\n", @@ -1544,7 +1539,6 @@ static void set_multicast_list(struct net_device *dev) struct dev_mc_list *dmi; unsigned char *cp; struct mc_cmd *cmd; - DECLARE_MAC_BUF(mac); if (wait_cfg(dev, &lp->mc_cmd.cmd, 1000, "multicast list change request timed out")) return; @@ -1555,8 +1549,8 @@ static void set_multicast_list(struct net_device *dev) for (dmi = dev->mc_list; cnt && dmi != NULL; dmi = dmi->next, cnt--, cp += 6) { memcpy(cp, dmi->dmi_addr, 6); if (i596_debug > 1) - DEB(DEB_MULTI,printk(KERN_INFO "%s: Adding address %s\n", - dev->name, print_mac(mac, cp))); + DEB(DEB_MULTI,printk(KERN_INFO "%s: Adding address %pM\n", + dev->name, cp)); } i596_add_cmd(dev, &cmd->cmd); } @@ -1604,9 +1598,3 @@ void __exit cleanup_module(void) } #endif /* MODULE */ - -/* - * Local variables: - * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c 82596.c" - * End: - */ diff --git a/drivers/net/8390.c b/drivers/net/8390.c index f72a2e87d5697339045421b8c14568af4eeb789c..fbe609a51e02c5952e6b437f8183e344af0c4fbc 100644 --- a/drivers/net/8390.c +++ b/drivers/net/8390.c @@ -17,6 +17,30 @@ int ei_close(struct net_device *dev) } EXPORT_SYMBOL(ei_close); +int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + return __ei_start_xmit(skb, dev); +} +EXPORT_SYMBOL(ei_start_xmit); + +struct net_device_stats *ei_get_stats(struct net_device *dev) +{ + return __ei_get_stats(dev); +} +EXPORT_SYMBOL(ei_get_stats); + +void ei_set_multicast_list(struct net_device *dev) +{ + __ei_set_multicast_list(dev); +} +EXPORT_SYMBOL(ei_set_multicast_list); + +void ei_tx_timeout(struct net_device *dev) +{ + __ei_tx_timeout(dev); +} +EXPORT_SYMBOL(ei_tx_timeout); + irqreturn_t ei_interrupt(int irq, void *dev_id) { return __ei_interrupt(irq, dev_id); @@ -31,9 +55,33 @@ void ei_poll(struct net_device *dev) EXPORT_SYMBOL(ei_poll); #endif +const struct net_device_ops ei_netdev_ops = { + .ndo_open = ei_open, + .ndo_stop = ei_close, + .ndo_start_xmit = ei_start_xmit, + .ndo_tx_timeout = ei_tx_timeout, + .ndo_get_stats = ei_get_stats, + .ndo_set_multicast_list = ei_set_multicast_list, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = ei_poll, +#endif +}; +EXPORT_SYMBOL(ei_netdev_ops); + struct net_device *__alloc_ei_netdev(int size) { - return ____alloc_ei_netdev(size); + struct net_device *dev = ____alloc_ei_netdev(size); +#ifdef CONFIG_COMPAT_NET_DEV_OPS + if (dev) { + dev->hard_start_xmit = ei_start_xmit; + dev->get_stats = ei_get_stats; + dev->set_multicast_list = ei_set_multicast_list; + dev->tx_timeout = ei_tx_timeout; + } +#endif + return dev; } EXPORT_SYMBOL(__alloc_ei_netdev); diff --git a/drivers/net/8390.h b/drivers/net/8390.h index 8e209f5e7c1179e26eceef42f5abf250372db91e..3c61d6d2748a424e00ecc56c2cd15fc72fdb88cf 100644 --- a/drivers/net/8390.h +++ b/drivers/net/8390.h @@ -33,11 +33,19 @@ extern void ei_poll(struct net_device *dev); extern void eip_poll(struct net_device *dev); #endif + /* Without I/O delay - non ISA or later chips */ extern void NS8390_init(struct net_device *dev, int startp); extern int ei_open(struct net_device *dev); extern int ei_close(struct net_device *dev); extern irqreturn_t ei_interrupt(int irq, void *dev_id); +extern void ei_tx_timeout(struct net_device *dev); +extern int ei_start_xmit(struct sk_buff *skb, struct net_device *dev); +extern void ei_set_multicast_list(struct net_device *dev); +extern struct net_device_stats *ei_get_stats(struct net_device *dev); + +extern const struct net_device_ops ei_netdev_ops; + extern struct net_device *__alloc_ei_netdev(int size); static inline struct net_device *alloc_ei_netdev(void) { @@ -49,6 +57,13 @@ extern void NS8390p_init(struct net_device *dev, int startp); extern int eip_open(struct net_device *dev); extern int eip_close(struct net_device *dev); extern irqreturn_t eip_interrupt(int irq, void *dev_id); +extern void eip_tx_timeout(struct net_device *dev); +extern int eip_start_xmit(struct sk_buff *skb, struct net_device *dev); +extern void eip_set_multicast_list(struct net_device *dev); +extern struct net_device_stats *eip_get_stats(struct net_device *dev); + +extern const struct net_device_ops eip_netdev_ops; + extern struct net_device *__alloc_eip_netdev(int size); static inline struct net_device *alloc_eip_netdev(void) { diff --git a/drivers/net/8390p.c b/drivers/net/8390p.c index 4c6eea4611a2c213a1bbff4079c02a3006b65d98..ee70b358a816aedf83535017c55ab3af8d4cc254 100644 --- a/drivers/net/8390p.c +++ b/drivers/net/8390p.c @@ -22,6 +22,30 @@ int eip_close(struct net_device *dev) } EXPORT_SYMBOL(eip_close); +int eip_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + return __ei_start_xmit(skb, dev); +} +EXPORT_SYMBOL(eip_start_xmit); + +struct net_device_stats *eip_get_stats(struct net_device *dev) +{ + return __ei_get_stats(dev); +} +EXPORT_SYMBOL(eip_get_stats); + +void eip_set_multicast_list(struct net_device *dev) +{ + __ei_set_multicast_list(dev); +} +EXPORT_SYMBOL(eip_set_multicast_list); + +void eip_tx_timeout(struct net_device *dev) +{ + __ei_tx_timeout(dev); +} +EXPORT_SYMBOL(eip_tx_timeout); + irqreturn_t eip_interrupt(int irq, void *dev_id) { return __ei_interrupt(irq, dev_id); @@ -36,9 +60,33 @@ void eip_poll(struct net_device *dev) EXPORT_SYMBOL(eip_poll); #endif +const struct net_device_ops eip_netdev_ops = { + .ndo_open = eip_open, + .ndo_stop = eip_close, + .ndo_start_xmit = eip_start_xmit, + .ndo_tx_timeout = eip_tx_timeout, + .ndo_get_stats = eip_get_stats, + .ndo_set_multicast_list = eip_set_multicast_list, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = eip_poll, +#endif +}; +EXPORT_SYMBOL(eip_netdev_ops); + struct net_device *__alloc_eip_netdev(int size) { - return ____alloc_ei_netdev(size); + struct net_device *dev = ____alloc_ei_netdev(size); +#ifdef CONFIG_COMPAT_NET_DEV_OPS + if (dev) { + dev->hard_start_xmit = eip_start_xmit; + dev->get_stats = eip_get_stats; + dev->set_multicast_list = eip_set_multicast_list; + dev->tx_timeout = eip_tx_timeout; + } +#endif + return dev; } EXPORT_SYMBOL(__alloc_eip_netdev); diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 231eeaf1d5522513e44941871d76b67b38b0f38b..72a9212da865ebcd9e59c1198c3c2cb79c06df7a 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -61,6 +61,7 @@ config DUMMY config BONDING tristate "Bonding driver support" depends on INET + depends on IPV6 || IPV6=n ---help--- Say 'Y' or 'M' if you wish to be able to 'bond' multiple Ethernet Channels together. This is called 'Etherchannel' by Cisco, @@ -978,6 +979,20 @@ config SMC911X called smc911x. If you want to compile it as a module, say M here and read +config SMSC911X + tristate "SMSC LAN911x/LAN921x families embedded ethernet support" + depends on ARM || SUPERH + select CRC32 + select MII + select PHYLIB + ---help--- + Say Y here if you want support for SMSC LAN911x and LAN921x families + of ethernet controllers. + + To compile this driver as a module, choose M here and read + . The module + will be called smsc911x. + config NET_VENDOR_RACAL bool "Racal-Interlan (Micom) NI cards" depends on ISA @@ -1414,19 +1429,6 @@ config TC35815 depends on NET_PCI && PCI && MIPS select PHYLIB -config EEPRO100 - tristate "EtherExpressPro/100 support (eepro100, original Becker driver)" - depends on NET_PCI && PCI - select MII - help - If you have an Intel EtherExpress PRO/100 PCI network (Ethernet) - card, say Y and read the Ethernet-HOWTO, available from - . - - To compile this driver as a module, choose M here. The module - will be called eepro100. - - config E100 tristate "Intel(R) PRO/100+ support" depends on NET_PCI && PCI @@ -1636,6 +1638,22 @@ config EPIC100 More specific information and updates are available from . +config SMSC9420 + tristate "SMSC LAN9420 PCI ethernet adapter support" + depends on NET_PCI && PCI + select CRC32 + select PHYLIB + select SMSC_PHY + help + This is a driver for SMSC's LAN9420 PCI ethernet adapter. + Say Y if you want it compiled into the kernel, + and read the Ethernet-HOWTO, available from + . + + This driver is also available as a module. The module will be + called smsc9420. If you want to compile it as a module, say M + here and read + config SUNDANCE tristate "Sundance Alta support" depends on NET_PCI && PCI @@ -1981,10 +1999,10 @@ config IP1000 will be called ipg. This is recommended. config IGB - tristate "Intel(R) 82575 PCI-Express Gigabit Ethernet support" + tristate "Intel(R) 82575/82576 PCI-Express Gigabit Ethernet support" depends on PCI ---help--- - This driver supports Intel(R) 82575 gigabit ethernet family of + This driver supports Intel(R) 82575/82576 gigabit ethernet family of adapters. For more information on how to identify your adapter, go to the Adapter & Driver ID Guide at: @@ -2276,10 +2294,6 @@ config UGETH_MAGIC_PACKET bool "Magic Packet detection support" depends on UCC_GETH -config UGETH_FILTERING - bool "Mac address filtering support" - depends on UCC_GETH - config UGETH_TX_ON_DEMAND bool "Transmit on Demand support" depends on UCC_GETH @@ -2450,6 +2464,16 @@ config IXGBE_DCA driver. DCA is a method for warming the CPU cache before data is used, with the intent of lessening the impact of cache misses. +config IXGBE_DCB + bool "Data Center Bridging (DCB) Support" + default n + depends on IXGBE && DCB + ---help--- + Say Y here if you want to use Data Center Bridging (DCB) in the + driver. + + If unsure, say N. + config IXGB tristate "Intel(R) PRO/10GbE support" depends on PCI @@ -2626,7 +2650,7 @@ config RIONET_RX_SIZE default "128" config FDDI - bool "FDDI driver support" + tristate "FDDI driver support" depends on (PCI || EISA || TC) help Fiber Distributed Data Interface is a high speed local area network diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 017383ad5ec6e6de671b71c0165d783b525386f2..e5c34b4642111b22cc692362aac3c8ae881ab84d 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -53,10 +53,10 @@ obj-$(CONFIG_VORTEX) += 3c59x.o obj-$(CONFIG_TYPHOON) += typhoon.o obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o obj-$(CONFIG_PCNET32) += pcnet32.o -obj-$(CONFIG_EEPRO100) += eepro100.o obj-$(CONFIG_E100) += e100.o obj-$(CONFIG_TLAN) += tlan.o obj-$(CONFIG_EPIC100) += epic100.o +obj-$(CONFIG_SMSC9420) += smsc9420.o obj-$(CONFIG_SIS190) += sis190.o obj-$(CONFIG_SIS900) += sis900.o obj-$(CONFIG_R6040) += r6040.o @@ -98,7 +98,7 @@ obj-$(CONFIG_HAMACHI) += hamachi.o obj-$(CONFIG_NET) += Space.o loopback.o obj-$(CONFIG_SEEQ8005) += seeq8005.o obj-$(CONFIG_NET_SB1000) += sb1000.o -obj-$(CONFIG_MAC8390) += mac8390.o +obj-$(CONFIG_MAC8390) += mac8390.o 8390.o obj-$(CONFIG_APNE) += apne.o 8390.o obj-$(CONFIG_PCMCIA_PCNET) += 8390.o obj-$(CONFIG_HP100) += hp100.o @@ -125,7 +125,7 @@ obj-$(CONFIG_NE3210) += ne3210.o 8390.o obj-$(CONFIG_SB1250_MAC) += sb1250-mac.o obj-$(CONFIG_B44) += b44.o obj-$(CONFIG_FORCEDETH) += forcedeth.o -obj-$(CONFIG_NE_H8300) += ne-h8300.o +obj-$(CONFIG_NE_H8300) += ne-h8300.o 8390.o obj-$(CONFIG_AX88796) += ax88796.o obj-$(CONFIG_TSI108_ETH) += tsi108_eth.o @@ -191,7 +191,7 @@ obj-$(CONFIG_SC92031) += sc92031.o obj-$(CONFIG_LP486E) += lp486e.o obj-$(CONFIG_ETH16I) += eth16i.o -obj-$(CONFIG_ZORRO8390) += zorro8390.o +obj-$(CONFIG_ZORRO8390) += zorro8390.o 8390.o obj-$(CONFIG_HPLANCE) += hplance.o 7990.o obj-$(CONFIG_MVME147_NET) += mvme147.o 7990.o obj-$(CONFIG_EQUALIZER) += eql.o @@ -203,7 +203,7 @@ obj-$(CONFIG_SGI_IOC3_ETH) += ioc3-eth.o obj-$(CONFIG_DECLANCE) += declance.o obj-$(CONFIG_ATARILANCE) += atarilance.o obj-$(CONFIG_A2065) += a2065.o -obj-$(CONFIG_HYDRA) += hydra.o +obj-$(CONFIG_HYDRA) += hydra.o 8390.o obj-$(CONFIG_ARIADNE) += ariadne.o obj-$(CONFIG_CS89x0) += cs89x0.o obj-$(CONFIG_MACSONIC) += macsonic.o @@ -220,6 +220,7 @@ obj-$(CONFIG_S2IO) += s2io.o obj-$(CONFIG_MYRI10GE) += myri10ge/ obj-$(CONFIG_SMC91X) += smc91x.o obj-$(CONFIG_SMC911X) += smc911x.o +obj-$(CONFIG_SMSC911X) += smsc911x.o obj-$(CONFIG_BFIN_MAC) += bfin_mac.o obj-$(CONFIG_DM9000) += dm9000.o obj-$(CONFIG_PASEMI_MAC) += pasemi_mac_driver.o diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c index 9c0837435b68dd83b88fca7355308796c2257e2e..7a60bdd9a242f27320b23249455b794bb90bf4c8 100644 --- a/drivers/net/a2065.c +++ b/drivers/net/a2065.c @@ -324,7 +324,6 @@ static int lance_rx (struct net_device *dev) len); skb->protocol = eth_type_trans (skb, dev); netif_rx (skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += len; } @@ -710,7 +709,6 @@ static int __devinit a2065_init_one(struct zorro_dev *z, unsigned long board, base_addr, mem_start; struct resource *r1, *r2; int err; - DECLARE_MAC_BUF(mac); board = z->resource.start; base_addr = board+A2065_LANCE; @@ -787,8 +785,7 @@ static int __devinit a2065_init_one(struct zorro_dev *z, zorro_set_drvdata(z, dev); printk(KERN_INFO "%s: A2065 at 0x%08lx, Ethernet Address " - "%s\n", dev->name, board, - print_mac(mac, dev->dev_addr)); + "%pM\n", dev->name, board, dev->dev_addr); return 0; } diff --git a/drivers/net/ac3200.c b/drivers/net/ac3200.c index b1448637107f3fada6f1a97536dfd6492a9d9117..071a851a2ea1d6b5a4b4db6b0c0e51625ad38222 100644 --- a/drivers/net/ac3200.c +++ b/drivers/net/ac3200.c @@ -146,7 +146,6 @@ struct net_device * __init ac3200_probe(int unit) static int __init ac_probe1(int ioaddr, struct net_device *dev) { int i, retval; - DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, AC_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -171,8 +170,8 @@ static int __init ac_probe1(int ioaddr, struct net_device *dev) for (i = 0; i < 6; i++) dev->dev_addr[i] = inb(ioaddr + AC_SA_PROM + i); - printk(KERN_DEBUG "AC3200 in EISA slot %d, node %s", - ioaddr/0x1000, print_mac(mac, dev->dev_addr)); + printk(KERN_DEBUG "AC3200 in EISA slot %d, node %pM", + ioaddr/0x1000, dev->dev_addr); #if 0 /* Check the vendor ID/prefix. Redundant after checking the EISA ID */ if (inb(ioaddr + AC_SA_PROM + 0) != AC_ADDR0 diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index 66de80b64b92a3f937edf821e49ec748c6478ed3..517fce48d94a0c2eac28ed49110e05ab322d0e97 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -450,6 +450,20 @@ static const struct ethtool_ops ace_ethtool_ops = { static void ace_watchdog(struct net_device *dev); +static const struct net_device_ops ace_netdev_ops = { + .ndo_open = ace_open, + .ndo_stop = ace_close, + .ndo_tx_timeout = ace_watchdog, + .ndo_get_stats = ace_get_stats, + .ndo_start_xmit = ace_start_xmit, + .ndo_set_multicast_list = ace_set_multicast_list, + .ndo_set_mac_address = ace_set_mac_addr, + .ndo_change_mtu = ace_change_mtu, +#if ACENIC_DO_VLAN + .ndo_vlan_rx_register = ace_vlan_rx_register, +#endif +}; + static int __devinit acenic_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -466,27 +480,19 @@ static int __devinit acenic_probe_one(struct pci_dev *pdev, SET_NETDEV_DEV(dev, &pdev->dev); - ap = dev->priv; + ap = netdev_priv(dev); ap->pdev = pdev; ap->name = pci_name(pdev); dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; #if ACENIC_DO_VLAN dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - dev->vlan_rx_register = ace_vlan_rx_register; #endif - dev->tx_timeout = &ace_watchdog; dev->watchdog_timeo = 5*HZ; - dev->open = &ace_open; - dev->stop = &ace_close; - dev->hard_start_xmit = &ace_start_xmit; - dev->get_stats = &ace_get_stats; - dev->set_multicast_list = &ace_set_multicast_list; + dev->netdev_ops = &ace_netdev_ops; SET_ETHTOOL_OPS(dev, &ace_ethtool_ops); - dev->set_mac_address = &ace_set_mac_addr; - dev->change_mtu = &ace_change_mtu; /* we only display this string ONCE */ if (!boards_found) @@ -892,7 +898,6 @@ static int __devinit ace_init(struct net_device *dev) int board_idx, ecode = 0; short i; unsigned char cache_size; - DECLARE_MAC_BUF(mac); ap = netdev_priv(dev); regs = ap->regs; @@ -1019,7 +1024,7 @@ static int __devinit ace_init(struct net_device *dev) dev->dev_addr[4] = (mac2 >> 8) & 0xff; dev->dev_addr[5] = mac2 & 0xff; - printk("MAC: %s\n", print_mac(mac, dev->dev_addr)); + printk("MAC: %pM\n", dev->dev_addr); /* * Looks like this is necessary to deal with on all architectures, @@ -2034,7 +2039,6 @@ static void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm) #endif netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += retdesc->size; @@ -3220,10 +3224,3 @@ static int __devinit read_eeprom_byte(struct net_device *dev, ap->name, offset); goto out; } - - -/* - * Local variables: - * compile-command: "gcc -D__SMP__ -D__KERNEL__ -DMODULE -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -DMODVERSIONS -include ../../include/linux/modversions.h -c -o acenic.o acenic.c" - * End: - */ diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index 07a6697e3635608466a00a41d5139281d8eef686..187ac6eb6e945e69f8fca9cd87e1161dd1ceb919 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -809,7 +809,6 @@ static int amd8111e_rx_poll(struct napi_struct *napi, int budget) lp->coal_conf.rx_packets++; lp->coal_conf.rx_bytes += pkt_len; num_rx_pkt++; - dev->last_rx = jiffies; err_next_pkt: lp->rx_ring[rx_index].buff_phy_addr @@ -832,7 +831,7 @@ static int amd8111e_rx_poll(struct napi_struct *napi, int budget) if (rx_pkt_limit > 0) { /* Receive descriptor is empty now */ spin_lock_irqsave(&lp->lock, flags); - __netif_rx_complete(dev, napi); + __netif_rx_complete(napi); writel(VAL0|RINTEN0, mmio + INTEN0); writel(VAL2 | RDMD0, mmio + CMD0); spin_unlock_irqrestore(&lp->lock, flags); @@ -1171,11 +1170,11 @@ static irqreturn_t amd8111e_interrupt(int irq, void *dev_id) /* Check if Receive Interrupt has occurred. */ if (intr0 & RINT0) { - if (netif_rx_schedule_prep(dev, &lp->napi)) { + if (netif_rx_schedule_prep(&lp->napi)) { /* Disable receive interupts */ writel(RINTEN0, mmio + INTEN0); /* Schedule a polling routine */ - __netif_rx_schedule(dev, &lp->napi); + __netif_rx_schedule(&lp->napi); } else if (intren0 & RINTEN0) { printk("************Driver bug! \ interrupt while in poll\n"); @@ -1821,7 +1820,6 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev, unsigned long reg_addr,reg_len; struct amd8111e_priv* lp; struct net_device* dev; - DECLARE_MAC_BUF(mac); err = pci_enable_device(pdev); if(err){ @@ -1963,8 +1961,8 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev, chip_version = (readl(lp->mmio + CHIPID) & 0xf0000000)>>28; printk(KERN_INFO "%s: AMD-8111e Driver Version: %s\n", dev->name,MODULE_VERS); - printk(KERN_INFO "%s: [ Rev %x ] PCI 10/100BaseT Ethernet %s\n", - dev->name, chip_version, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: [ Rev %x ] PCI 10/100BaseT Ethernet %pM\n", + dev->name, chip_version, dev->dev_addr); if (lp->ext_phy_id) printk(KERN_INFO "%s: Found MII PHY ID 0x%08x at address 0x%02x\n", dev->name, lp->ext_phy_id, lp->ext_phy_addr); diff --git a/drivers/net/apne.c b/drivers/net/apne.c index 867f6fff543c848bfd95a741173c746005344017..1437f5d121214b18f6dcffe5e3a5937d17c03e95 100644 --- a/drivers/net/apne.c +++ b/drivers/net/apne.c @@ -78,9 +78,6 @@ struct net_device * __init apne_probe(int unit); static int apne_probe1(struct net_device *dev, int ioaddr); -static int apne_open(struct net_device *dev); -static int apne_close(struct net_device *dev); - static void apne_reset_8390(struct net_device *dev); static void apne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page); @@ -207,7 +204,6 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr) int neX000, ctron; #endif static unsigned version_printed; - DECLARE_MAC_BUF(mac); if (ei_debug && version_printed++ == 0) printk(version); @@ -315,6 +311,7 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr) dev->base_addr = ioaddr; dev->irq = IRQ_AMIGA_PORTS; + dev->netdev_ops = &ei_netdev_ops; /* Install the Interrupt handler */ i = request_irq(dev->irq, apne_interrupt, IRQF_SHARED, DRV_NAME, dev); @@ -323,7 +320,7 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr) for(i = 0; i < ETHER_ADDR_LEN; i++) dev->dev_addr[i] = SA_prom[i]; - printk(" %s\n", print_mac(mac, dev->dev_addr)); + printk(" %pM\n", dev->dev_addr); printk("%s: %s found.\n", dev->name, name); @@ -338,11 +335,7 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr) ei_status.block_input = &apne_block_input; ei_status.block_output = &apne_block_output; ei_status.get_8390_hdr = &apne_get_8390_hdr; - dev->open = &apne_open; - dev->stop = &apne_close; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = ei_poll; -#endif + NS8390_init(dev, 0); pcmcia_ack_int(pcmcia_get_intreq()); /* ack PCMCIA int req */ @@ -353,22 +346,6 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr) return 0; } -static int -apne_open(struct net_device *dev) -{ - ei_open(dev); - return 0; -} - -static int -apne_close(struct net_device *dev) -{ - if (ei_debug > 1) - printk("%s: Shutting down ethercard.\n", dev->name); - ei_close(dev); - return 0; -} - /* Hard reset the card. This used to pause for the same period that a 8390 reset command required, but that shouldn't be necessary. */ static void diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c index 735fc9476403c4df27229298af32021ddd9f1762..54819a34ba0a28a454c3e9684e8162f10ff4b977 100644 --- a/drivers/net/appletalk/cops.c +++ b/drivers/net/appletalk/cops.c @@ -851,7 +851,6 @@ static void cops_rx(struct net_device *dev) /* Send packet to a higher place. */ netif_rx(skb); - dev->last_rx = jiffies; } static void cops_timeout(struct net_device *dev) @@ -1025,11 +1024,3 @@ static void __exit cops_module_exit(void) module_init(cops_module_init); module_exit(cops_module_exit); #endif /* MODULE */ - -/* - * Local variables: - * compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -c cops.c" - * c-basic-offset: 4 - * c-file-offsets: ((substatement-open . 0)) - * End: - */ diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c index 1071144edd66fbdf0f594ec0104c065fdee06e82..9a0be9b2eaad66d5bec2776c54871d29b08e5e6f 100644 --- a/drivers/net/appletalk/ipddp.c +++ b/drivers/net/appletalk/ipddp.c @@ -108,7 +108,7 @@ static struct net_device * __init ipddp_init(void) */ static struct net_device_stats *ipddp_get_stats(struct net_device *dev) { - return dev->priv; + return netdev_priv(dev); } /* @@ -170,8 +170,8 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev) skb->protocol = htons(ETH_P_ATALK); /* Protocol has changed */ - ((struct net_device_stats *) dev->priv)->tx_packets++; - ((struct net_device_stats *) dev->priv)->tx_bytes+=skb->len; + ((struct net_device_stats *) netdev_priv(dev))->tx_packets++; + ((struct net_device_stats *) netdev_priv(dev))->tx_bytes += skb->len; if(aarp_send_ddp(rt->dev, skb, &rt->at, NULL) < 0) dev_kfree_skb(skb); diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c index fef5560bc7a2ee2d8c6aee66f6e413022fdfdca1..dc4d49605603147acc93acb476ec9aa94cc714cb 100644 --- a/drivers/net/appletalk/ltpc.c +++ b/drivers/net/appletalk/ltpc.c @@ -726,7 +726,8 @@ static int sendup_buffer (struct net_device *dev) int dnode, snode, llaptype, len; int sklen; struct sk_buff *skb; - struct net_device_stats *stats = &((struct ltpc_private *)dev->priv)->stats; + struct ltpc_private *ltpc_priv = netdev_priv(dev); + struct net_device_stats *stats = <pc_priv->stats; struct lt_rcvlap *ltc = (struct lt_rcvlap *) ltdmacbuf; if (ltc->command != LT_RCVLAP) { @@ -783,7 +784,6 @@ static int sendup_buffer (struct net_device *dev) /* toss it onwards */ netif_rx(skb); - dev->last_rx = jiffies; return 0; } @@ -823,7 +823,8 @@ static int ltpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct sockaddr_at *sa = (struct sockaddr_at *) &ifr->ifr_addr; /* we'll keep the localtalk node address in dev->pa_addr */ - struct atalk_addr *aa = &((struct ltpc_private *)dev->priv)->my_addr; + struct ltpc_private *ltpc_priv = netdev_priv(dev); + struct atalk_addr *aa = <pc_priv->my_addr; struct lt_init c; int ltflags; @@ -904,7 +905,8 @@ static int ltpc_xmit(struct sk_buff *skb, struct net_device *dev) * and skb->len is the length of the ddp data + ddp header */ - struct net_device_stats *stats = &((struct ltpc_private *)dev->priv)->stats; + struct ltpc_private *ltpc_priv = netdev_priv(dev); + struct net_device_stats *stats = <pc_priv->stats; int i; struct lt_sendlap cbuf; @@ -943,7 +945,8 @@ static int ltpc_xmit(struct sk_buff *skb, struct net_device *dev) static struct net_device_stats *ltpc_get_stats(struct net_device *dev) { - struct net_device_stats *stats = &((struct ltpc_private *) dev->priv)->stats; + struct ltpc_private *ltpc_priv = netdev_priv(dev); + struct net_device_stats *stats = <pc_priv->stats; return stats; } diff --git a/drivers/net/arcnet/arc-rawmode.c b/drivers/net/arcnet/arc-rawmode.c index e0a18e7c73cb59d36150bc9007fb82d39819bb21..3ff9affb1a914e212de008728985598e8e724bf8 100644 --- a/drivers/net/arcnet/arc-rawmode.c +++ b/drivers/net/arcnet/arc-rawmode.c @@ -87,7 +87,7 @@ MODULE_LICENSE("GPL"); static void rx(struct net_device *dev, int bufnum, struct archdr *pkthdr, int length) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); struct sk_buff *skb; struct archdr *pkt = pkthdr; int ofs; @@ -125,7 +125,6 @@ static void rx(struct net_device *dev, int bufnum, skb->protocol = __constant_htons(ETH_P_ARCNET); ; netif_rx(skb); - dev->last_rx = jiffies; } @@ -168,7 +167,7 @@ static int build_header(struct sk_buff *skb, struct net_device *dev, static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length, int bufnum) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); struct arc_hardware *hard = &pkt->hard; int ofs; diff --git a/drivers/net/arcnet/arc-rimi.c b/drivers/net/arcnet/arc-rimi.c index 8c8d6c453c457e3b5f236d15f812dc66ede25d49..e3082a9350fcafcd2b1a90ae21cdc08a284f15b4 100644 --- a/drivers/net/arcnet/arc-rimi.c +++ b/drivers/net/arcnet/arc-rimi.c @@ -194,7 +194,7 @@ static int __init arcrimi_found(struct net_device *dev) /* initialize the rest of the device structure. */ - lp = dev->priv; + lp = netdev_priv(dev); lp->card_name = "RIM I"; lp->hw.command = arcrimi_command; lp->hw.status = arcrimi_status; @@ -260,7 +260,7 @@ static int __init arcrimi_found(struct net_device *dev) */ static int arcrimi_reset(struct net_device *dev, int really_reset) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); void __iomem *ioaddr = lp->mem_start + 0x800; BUGMSG(D_INIT, "Resetting %s (status=%02Xh)\n", dev->name, ASTATUS()); @@ -281,7 +281,7 @@ static int arcrimi_reset(struct net_device *dev, int really_reset) static void arcrimi_setmask(struct net_device *dev, int mask) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); void __iomem *ioaddr = lp->mem_start + 0x800; AINTMASK(mask); @@ -289,7 +289,7 @@ static void arcrimi_setmask(struct net_device *dev, int mask) static int arcrimi_status(struct net_device *dev) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); void __iomem *ioaddr = lp->mem_start + 0x800; return ASTATUS(); @@ -297,7 +297,7 @@ static int arcrimi_status(struct net_device *dev) static void arcrimi_command(struct net_device *dev, int cmd) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); void __iomem *ioaddr = lp->mem_start + 0x800; ACOMMAND(cmd); @@ -306,7 +306,7 @@ static void arcrimi_command(struct net_device *dev, int cmd) static void arcrimi_copy_to_card(struct net_device *dev, int bufnum, int offset, void *buf, int count) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); void __iomem *memaddr = lp->mem_start + 0x800 + bufnum * 512 + offset; TIME("memcpy_toio", count, memcpy_toio(memaddr, buf, count)); } @@ -315,7 +315,7 @@ static void arcrimi_copy_to_card(struct net_device *dev, int bufnum, int offset, static void arcrimi_copy_from_card(struct net_device *dev, int bufnum, int offset, void *buf, int count) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); void __iomem *memaddr = lp->mem_start + 0x800 + bufnum * 512 + offset; TIME("memcpy_fromio", count, memcpy_fromio(buf, memaddr, count)); } @@ -361,7 +361,7 @@ static int __init arc_rimi_init(void) static void __exit arc_rimi_exit(void) { struct net_device *dev = my_dev; - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); unregister_netdev(dev); iounmap(lp->mem_start); diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index a5b07691e466d6cc43b210796144eece8947d15c..6b53e5ed125cfbb10c2be5f34edca1a04fe36097 100644 --- a/drivers/net/arcnet/arcnet.c +++ b/drivers/net/arcnet/arcnet.c @@ -181,7 +181,7 @@ EXPORT_SYMBOL(arcnet_dump_skb); static void arcnet_dump_packet(struct net_device *dev, int bufnum, char *desc, int take_arcnet_lock) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); int i, length; unsigned long flags = 0; static uint8_t buf[512]; @@ -247,7 +247,7 @@ void arcnet_unregister_proto(struct ArcProto *proto) */ static void release_arcbuf(struct net_device *dev, int bufnum) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); int i; lp->buf_queue[lp->first_free_buf++] = bufnum; @@ -269,7 +269,7 @@ static void release_arcbuf(struct net_device *dev, int bufnum) */ static int get_arcbuf(struct net_device *dev) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); int buf = -1, i; if (!atomic_dec_and_test(&lp->buf_lock)) { @@ -357,7 +357,7 @@ struct net_device *alloc_arcdev(char *name) dev = alloc_netdev(sizeof(struct arcnet_local), name && *name ? name : "arc%d", arcdev_setup); if(dev) { - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct arcnet_local *lp = netdev_priv(dev); spin_lock_init(&lp->lock); } @@ -374,7 +374,7 @@ struct net_device *alloc_arcdev(char *name) */ static int arcnet_open(struct net_device *dev) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); int count, newmtu, error; BUGMSG(D_INIT,"opened."); @@ -474,7 +474,7 @@ static int arcnet_open(struct net_device *dev) /* The inverse routine to arcnet_open - shuts down the card. */ static int arcnet_close(struct net_device *dev) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); netif_stop_queue(dev); @@ -556,7 +556,7 @@ static int arcnet_header(struct sk_buff *skb, struct net_device *dev, static int arcnet_rebuild_header(struct sk_buff *skb) { struct net_device *dev = skb->dev; - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); int status = 0; /* default is failure */ unsigned short type; uint8_t daddr=0; @@ -603,7 +603,7 @@ static int arcnet_rebuild_header(struct sk_buff *skb) /* Called by the kernel in order to transmit a packet. */ static int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); struct archdr *pkt; struct arc_rfc1201 *soft; struct ArcProto *proto; @@ -693,7 +693,7 @@ static int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev) */ static int go_tx(struct net_device *dev) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); BUGMSG(D_DURING, "go_tx: status=%Xh, intmask=%Xh, next_tx=%d, cur_tx=%d\n", ASTATUS(), lp->intmask, lp->next_tx, lp->cur_tx); @@ -723,7 +723,7 @@ static int go_tx(struct net_device *dev) static void arcnet_timeout(struct net_device *dev) { unsigned long flags; - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); int status = ASTATUS(); char *msg; @@ -771,8 +771,8 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id) BUGMSG(D_DURING, "\n"); BUGMSG(D_DURING, "in arcnet_interrupt\n"); - - lp = dev->priv; + + lp = netdev_priv(dev); BUG_ON(!lp); spin_lock(&lp->lock); @@ -1010,7 +1010,7 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id) */ static void arcnet_rx(struct net_device *dev, int bufnum) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); struct archdr pkt; struct arc_rfc1201 *soft; int length, ofs; @@ -1074,7 +1074,7 @@ static void arcnet_rx(struct net_device *dev, int bufnum) */ static struct net_device_stats *arcnet_get_stats(struct net_device *dev) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); return &lp->stats; } @@ -1091,7 +1091,7 @@ static void null_rx(struct net_device *dev, int bufnum, static int null_build_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, uint8_t daddr) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); BUGMSG(D_PROTO, "tx: can't build header for encap %02Xh; load a protocol driver.\n", @@ -1106,7 +1106,7 @@ static int null_build_header(struct sk_buff *skb, struct net_device *dev, static int null_prepare_tx(struct net_device *dev, struct archdr *pkt, int length, int bufnum) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); struct arc_hardware newpkt; BUGMSG(D_PROTO, "tx: no encap for this host; load a protocol driver.\n"); diff --git a/drivers/net/arcnet/capmode.c b/drivers/net/arcnet/capmode.c index 02cb8f1c11484b23460100c85f60faec62bd3ea5..30580bbe252d4ff11a346d0d7bbc0db1a0a2bef5 100644 --- a/drivers/net/arcnet/capmode.c +++ b/drivers/net/arcnet/capmode.c @@ -61,7 +61,7 @@ static struct ArcProto capmode_proto = }; -void arcnet_cap_init(void) +static void arcnet_cap_init(void) { int count; @@ -103,7 +103,7 @@ MODULE_LICENSE("GPL"); static void rx(struct net_device *dev, int bufnum, struct archdr *pkthdr, int length) { - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct arcnet_local *lp = netdev_priv(dev); struct sk_buff *skb; struct archdr *pkt = pkthdr; char *pktbuf, *pkthdrbuf; @@ -151,7 +151,6 @@ static void rx(struct net_device *dev, int bufnum, skb->protocol = __constant_htons(ETH_P_ARCNET); ; netif_rx(skb); - dev->last_rx = jiffies; } @@ -198,7 +197,7 @@ static int build_header(struct sk_buff *skb, static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length, int bufnum) { - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct arcnet_local *lp = netdev_priv(dev); struct arc_hardware *hard = &pkt->hard; int ofs; @@ -250,7 +249,7 @@ static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length, static int ack_tx(struct net_device *dev, int acked) { - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct arcnet_local *lp = netdev_priv(dev); struct sk_buff *ackskb; struct archdr *ackpkt; int length=sizeof(struct arc_cap); diff --git a/drivers/net/arcnet/com20020-isa.c b/drivers/net/arcnet/com20020-isa.c index 9289e6103de5ac039dbde468fe7e282254739e57..ea53a940272f1172ec4b51070d608becbf71e134 100644 --- a/drivers/net/arcnet/com20020-isa.c +++ b/drivers/net/arcnet/com20020-isa.c @@ -52,7 +52,7 @@ static int __init com20020isa_probe(struct net_device *dev) { int ioaddr; unsigned long airqmask; - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); int err; BUGLVL(D_NORMAL) printk(VERSION); @@ -151,7 +151,7 @@ static int __init com20020_init(void) if (node && node != 0xff) dev->dev_addr[0] = node; - lp = dev->priv; + lp = netdev_priv(dev); lp->backplane = backplane; lp->clockp = clockp & 7; lp->clockm = clockm & 3; diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c index b8c0fa6d401db146998c21c29b7928806a5fe9f3..8b51f632581d1810f2f712e2b3b63ae942b33ed3 100644 --- a/drivers/net/arcnet/com20020-pci.c +++ b/drivers/net/arcnet/com20020-pci.c @@ -72,7 +72,7 @@ static int __devinit com20020pci_probe(struct pci_dev *pdev, const struct pci_de dev = alloc_arcdev(device); if (!dev) return -ENOMEM; - lp = dev->priv; + lp = netdev_priv(dev); pci_set_drvdata(pdev, dev); diff --git a/drivers/net/arcnet/com20020.c b/drivers/net/arcnet/com20020.c index 70124a944e7d61f59b89fdb7544339278d7d3f40..103688358fb84721af7568c9a4f14a90ba81659c 100644 --- a/drivers/net/arcnet/com20020.c +++ b/drivers/net/arcnet/com20020.c @@ -89,7 +89,7 @@ static void com20020_copy_to_card(struct net_device *dev, int bufnum, int com20020_check(struct net_device *dev) { int ioaddr = dev->base_addr, status; - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); ARCRESET0; mdelay(RESETtime); @@ -159,7 +159,7 @@ int com20020_found(struct net_device *dev, int shared) /* Initialize the rest of the device structure. */ - lp = dev->priv; + lp = netdev_priv(dev); lp->hw.owner = THIS_MODULE; lp->hw.command = com20020_command; @@ -233,7 +233,7 @@ int com20020_found(struct net_device *dev, int shared) */ static int com20020_reset(struct net_device *dev, int really_reset) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); u_int ioaddr = dev->base_addr; u_char inbyte; @@ -300,7 +300,7 @@ static int com20020_status(struct net_device *dev) static void com20020_close(struct net_device *dev) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; /* disable transmitter */ @@ -317,7 +317,7 @@ static void com20020_close(struct net_device *dev) */ static void com20020_set_mc_list(struct net_device *dev) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; if ((dev->flags & IFF_PROMISC) && (dev->flags & IFF_UP)) { /* Enable promiscuous mode */ diff --git a/drivers/net/arcnet/com90io.c b/drivers/net/arcnet/com90io.c index 6599f1046c7b844aec858e5456196122e67ced64..89de29b3b1dc0d09628b093fb6ac34483984716e 100644 --- a/drivers/net/arcnet/com90io.c +++ b/drivers/net/arcnet/com90io.c @@ -248,7 +248,7 @@ static int __init com90io_found(struct net_device *dev) return -EBUSY; } - lp = dev->priv; + lp = netdev_priv(dev); lp->card_name = "COM90xx I/O"; lp->hw.command = com90io_command; lp->hw.status = com90io_status; @@ -290,7 +290,7 @@ static int __init com90io_found(struct net_device *dev) */ static int com90io_reset(struct net_device *dev, int really_reset) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); short ioaddr = dev->base_addr; BUGMSG(D_INIT, "Resetting %s (status=%02Xh)\n", dev->name, ASTATUS()); diff --git a/drivers/net/arcnet/com90xx.c b/drivers/net/arcnet/com90xx.c index 0d45553ff75c8c08032c57cfa041f28d617d64be..d762fe46251eb0fc62bdbacda2990cf3f89ff066 100644 --- a/drivers/net/arcnet/com90xx.c +++ b/drivers/net/arcnet/com90xx.c @@ -468,7 +468,7 @@ static int __init com90xx_found(int ioaddr, int airq, u_long shmem, void __iomem release_mem_region(shmem, MIRROR_SIZE); return -ENOMEM; } - lp = dev->priv; + lp = netdev_priv(dev); /* find the real shared memory start/end points, including mirrors */ /* guess the actual size of one "memory mirror" - the number of @@ -583,9 +583,9 @@ static void com90xx_setmask(struct net_device *dev, int mask) * * However, it does make sure the card is in a defined state. */ -int com90xx_reset(struct net_device *dev, int really_reset) +static int com90xx_reset(struct net_device *dev, int really_reset) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); short ioaddr = dev->base_addr; BUGMSG(D_INIT, "Resetting (status=%02Xh)\n", ASTATUS()); @@ -621,7 +621,7 @@ int com90xx_reset(struct net_device *dev, int really_reset) static void com90xx_copy_to_card(struct net_device *dev, int bufnum, int offset, void *buf, int count) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); void __iomem *memaddr = lp->mem_start + bufnum * 512 + offset; TIME("memcpy_toio", count, memcpy_toio(memaddr, buf, count)); } @@ -630,7 +630,7 @@ static void com90xx_copy_to_card(struct net_device *dev, int bufnum, int offset, static void com90xx_copy_from_card(struct net_device *dev, int bufnum, int offset, void *buf, int count) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); void __iomem *memaddr = lp->mem_start + bufnum * 512 + offset; TIME("memcpy_fromio", count, memcpy_fromio(buf, memaddr, count)); } @@ -656,7 +656,7 @@ static void __exit com90xx_exit(void) for (count = 0; count < numcards; count++) { dev = cards[count]; - lp = dev->priv; + lp = netdev_priv(dev); unregister_netdev(dev); free_irq(dev->irq, dev); diff --git a/drivers/net/arcnet/rfc1051.c b/drivers/net/arcnet/rfc1051.c index dab185bc51f1a1bc05b3c689ed7fac5834b06c96..49d39a9cb696331052f7a590cb72b71e4dab2452 100644 --- a/drivers/net/arcnet/rfc1051.c +++ b/drivers/net/arcnet/rfc1051.c @@ -88,7 +88,7 @@ MODULE_LICENSE("GPL"); */ static __be16 type_trans(struct sk_buff *skb, struct net_device *dev) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); struct archdr *pkt = (struct archdr *) skb->data; struct arc_rfc1051 *soft = &pkt->soft.rfc1051; int hdr_size = ARC_HDR_SIZE + RFC1051_HDR_SIZE; @@ -125,7 +125,7 @@ static __be16 type_trans(struct sk_buff *skb, struct net_device *dev) static void rx(struct net_device *dev, int bufnum, struct archdr *pkthdr, int length) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); struct sk_buff *skb; struct archdr *pkt = pkthdr; int ofs; @@ -159,7 +159,6 @@ static void rx(struct net_device *dev, int bufnum, skb->protocol = type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; } @@ -169,7 +168,7 @@ static void rx(struct net_device *dev, int bufnum, static int build_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, uint8_t daddr) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); int hdr_size = ARC_HDR_SIZE + RFC1051_HDR_SIZE; struct archdr *pkt = (struct archdr *) skb_push(skb, hdr_size); struct arc_rfc1051 *soft = &pkt->soft.rfc1051; @@ -220,7 +219,7 @@ static int build_header(struct sk_buff *skb, struct net_device *dev, static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length, int bufnum) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); struct arc_hardware *hard = &pkt->hard; int ofs; diff --git a/drivers/net/arcnet/rfc1201.c b/drivers/net/arcnet/rfc1201.c index 6d6d95cc4404b7a727a20f049dc8240db595351d..2303d3a1f4b63d512aea87ef1287fb39e54b10d9 100644 --- a/drivers/net/arcnet/rfc1201.c +++ b/drivers/net/arcnet/rfc1201.c @@ -92,7 +92,7 @@ static __be16 type_trans(struct sk_buff *skb, struct net_device *dev) { struct archdr *pkt = (struct archdr *) skb->data; struct arc_rfc1201 *soft = &pkt->soft.rfc1201; - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); int hdr_size = ARC_HDR_SIZE + RFC1201_HDR_SIZE; /* Pull off the arcnet header. */ @@ -134,7 +134,7 @@ static __be16 type_trans(struct sk_buff *skb, struct net_device *dev) static void rx(struct net_device *dev, int bufnum, struct archdr *pkthdr, int length) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); struct sk_buff *skb; struct archdr *pkt = pkthdr; struct arc_rfc1201 *soft = &pkthdr->soft.rfc1201; @@ -230,7 +230,6 @@ static void rx(struct net_device *dev, int bufnum, skb->protocol = type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; } else { /* split packet */ /* * NOTE: MSDOS ARP packet correction should only need to apply to @@ -366,7 +365,6 @@ static void rx(struct net_device *dev, int bufnum, skb->protocol = type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; } } } @@ -376,7 +374,7 @@ static void rx(struct net_device *dev, int bufnum, static int build_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, uint8_t daddr) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); int hdr_size = ARC_HDR_SIZE + RFC1201_HDR_SIZE; struct archdr *pkt = (struct archdr *) skb_push(skb, hdr_size); struct arc_rfc1201 *soft = &pkt->soft.rfc1201; @@ -443,7 +441,7 @@ static int build_header(struct sk_buff *skb, struct net_device *dev, static void load_pkt(struct net_device *dev, struct arc_hardware *hard, struct arc_rfc1201 *soft, int softlen, int bufnum) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); int ofs; /* assume length <= XMTU: someone should have handled that by now. */ @@ -476,7 +474,7 @@ static void load_pkt(struct net_device *dev, struct arc_hardware *hard, static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length, int bufnum) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); const int maxsegsize = XMTU - RFC1201_HDR_SIZE; struct Outgoing *out; @@ -511,7 +509,7 @@ static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length, static int continue_tx(struct net_device *dev, int bufnum) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); struct Outgoing *out = &lp->outgoing; struct arc_hardware *hard = &out->pkt->hard; struct arc_rfc1201 *soft = &out->pkt->soft.rfc1201, *newsoft; diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c index 29e53eb71c7484c2c8f2e4c0ecef185786bbb00c..e1d72e06f3e1b07849997566dd3b3502251ba347 100644 --- a/drivers/net/ariadne.c +++ b/drivers/net/ariadne.c @@ -165,7 +165,6 @@ static int __devinit ariadne_init_one(struct zorro_dev *z, struct net_device *dev; struct ariadne_private *priv; int err; - DECLARE_MAC_BUF(mac); r1 = request_mem_region(base_addr, sizeof(struct Am79C960), "Am79C960"); if (!r1) @@ -215,9 +214,8 @@ static int __devinit ariadne_init_one(struct zorro_dev *z, } zorro_set_drvdata(z, dev); - printk(KERN_INFO "%s: Ariadne at 0x%08lx, Ethernet Address " - "%s\n", dev->name, board, - print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: Ariadne at 0x%08lx, Ethernet Address %pM\n", + dev->name, board, dev->dev_addr); return 0; } @@ -613,14 +611,10 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev) #if 0 { - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); - - printk(KERN_DEBUG "TX pkt type 0x%04x from %s to %s " + printk(KERN_DEBUG "TX pkt type 0x%04x from %pM to %pM " " data 0x%08x len %d\n", ((u_short *)skb->data)[6], - print_mac(mac, ((const u8 *)skb->data)+6), - print_mac(mac, (const u8 *)skb->data), + skb->data + 6, skb->data, (int)skb->data, (int)skb->len); } #endif @@ -743,25 +737,22 @@ static int ariadne_rx(struct net_device *dev) skb->protocol=eth_type_trans(skb,dev); #if 0 { - DECLARE_MAC_BUF(mac); - printk(KERN_DEBUG "RX pkt type 0x%04x from ", ((u_short *)skb->data)[6]); { u_char *ptr = &((u_char *)skb->data)[6]; - printk("%s", print_mac(mac, ptr)); + printk("%pM", ptr); } printk(" to "); { u_char *ptr = (u_char *)skb->data; - printk("%s", print_mac(mac, ptr)); + printk("%pM", ptr); } printk(" data 0x%08x len %d\n", (int)skb->data, (int)skb->len); } #endif netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } diff --git a/drivers/net/arm/Kconfig b/drivers/net/arm/Kconfig index 8eda6eeb43b70ffbbc39463d0c9161cb89585fd1..2895db13bfa4459cebc86b89c2e7dc1fc5971495 100644 --- a/drivers/net/arm/Kconfig +++ b/drivers/net/arm/Kconfig @@ -40,6 +40,14 @@ config ARM_AT91_ETHER If you wish to compile a kernel for the AT91RM9200 and enable ethernet support, then you should always answer Y to this. +config ARM_KS8695_ETHER + tristate "KS8695 Ethernet support" + depends on ARM && ARCH_KS8695 + select MII + help + If you wish to compile a kernel for the KS8695 and want to + use the internal ethernet then you should answer Y to this. + config EP93XX_ETH tristate "EP93xx Ethernet support" depends on ARM && ARCH_EP93XX @@ -51,7 +59,7 @@ config EP93XX_ETH config IXP4XX_ETH tristate "Intel IXP4xx Ethernet support" depends on ARM && ARCH_IXP4XX && IXP4XX_NPE && IXP4XX_QMGR - select MII + select PHYLIB help Say Y here if you want to use built-in Ethernet ports on IXP4xx processor. diff --git a/drivers/net/arm/Makefile b/drivers/net/arm/Makefile index 7c812ac2b6a51c7305f8b5e69b51b219959f20df..c69c0cdba4a26b1cc254f1ac112cce46171c5f04 100644 --- a/drivers/net/arm/Makefile +++ b/drivers/net/arm/Makefile @@ -4,9 +4,10 @@ # obj-$(CONFIG_ARM_AM79C961A) += am79c961a.o -obj-$(CONFIG_ARM_ETHERH) += etherh.o +obj-$(CONFIG_ARM_ETHERH) += etherh.o ../8390.o obj-$(CONFIG_ARM_ETHER3) += ether3.o obj-$(CONFIG_ARM_ETHER1) += ether1.o obj-$(CONFIG_ARM_AT91_ETHER) += at91_ether.o +obj-$(CONFIG_ARM_KS8695_ETHER) += ks8695net.o obj-$(CONFIG_EP93XX_ETH) += ep93xx_eth.o obj-$(CONFIG_IXP4XX_ETH) += ixp4xx_eth.o diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c index aa4a5246be534a483e6ec42a6b67ba8986e371cd..0c628a9e5339af44f5c4cee91c39a279402d3f38 100644 --- a/drivers/net/arm/am79c961a.c +++ b/drivers/net/arm/am79c961a.c @@ -532,7 +532,6 @@ am79c961_rx(struct net_device *dev, struct dev_priv *priv) am_writeword(dev, hdraddr + 2, RMD_OWN); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; priv->stats.rx_bytes += len; priv->stats.rx_packets ++; } else { @@ -745,10 +744,8 @@ static int __init am79c961_probe(struct platform_device *pdev) ret = register_netdev(dev); if (ret == 0) { - DECLARE_MAC_BUF(mac); - - printk(KERN_INFO "%s: ether address %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: ether address %pM\n", + dev->name, dev->dev_addr); return 0; } diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c index 6f431a887e7e5fb4f2b6ca27217f204a3d063291..442938d5038020dfd334100b7c3faf73e1f72c02 100644 --- a/drivers/net/arm/at91_ether.c +++ b/drivers/net/arm/at91_ether.c @@ -485,7 +485,6 @@ static void update_mac_address(struct net_device *dev) static int set_mac_address(struct net_device *dev, void* addr) { struct sockaddr *address = addr; - DECLARE_MAC_BUF(mac); if (!is_valid_ether_addr(address->sa_data)) return -EADDRNOTAVAIL; @@ -493,8 +492,8 @@ static int set_mac_address(struct net_device *dev, void* addr) memcpy(dev->dev_addr, address->sa_data, dev->addr_len); update_mac_address(dev); - printk("%s: Setting MAC address to %s\n", dev->name, - print_mac(mac, dev->dev_addr)); + printk("%s: Setting MAC address to %pM\n", dev->name, + dev->dev_addr); return 0; } @@ -894,7 +893,6 @@ static void at91ether_rx(struct net_device *dev) memcpy(skb_put(skb, pktlen), p_recv, pktlen); skb->protocol = eth_type_trans(skb, dev); - dev->last_rx = jiffies; dev->stats.rx_bytes += pktlen; netif_rx(skb); } @@ -978,7 +976,6 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add struct at91_private *lp; unsigned int val; int res; - DECLARE_MAC_BUF(mac); dev = alloc_etherdev(sizeof(struct at91_private)); if (!dev) @@ -1084,11 +1081,11 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add gpio_request(lp->board_data.phy_irq_pin, "ethernet_phy"); /* Display ethernet banner */ - printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%s)\n", + printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%pM)\n", dev->name, (uint) dev->base_addr, dev->irq, at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_SPD ? "100-" : "10-", at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_FD ? "FullDuplex" : "HalfDuplex", - print_mac(mac, dev->dev_addr)); + dev->dev_addr); if ((phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) printk(KERN_INFO "%s: Davicom 9161 PHY %s\n", dev->name, (lp->phy_media == PORT_FIBRE) ? "(Fiber)" : "(Copper)"); else if (phy_type == MII_LXT971A_ID) diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c index 1267444d79da80d0e1fb18e12d204db06bae6efc..6ecc600c1bccd05c5e22e17af5248fe998e9ecb0 100644 --- a/drivers/net/arm/ep93xx_eth.c +++ b/drivers/net/arm/ep93xx_eth.c @@ -259,8 +259,6 @@ static int ep93xx_rx(struct net_device *dev, int processed, int budget) skb_put(skb, length); skb->protocol = eth_type_trans(skb, dev); - dev->last_rx = jiffies; - netif_receive_skb(skb); ep->stats.rx_packets++; @@ -300,7 +298,7 @@ static int ep93xx_poll(struct napi_struct *napi, int budget) int more = 0; spin_lock_irq(&ep->rx_lock); - __netif_rx_complete(dev, napi); + __netif_rx_complete(napi); wrl(ep, REG_INTEN, REG_INTEN_TX | REG_INTEN_RX); if (ep93xx_have_more_rx(ep)) { wrl(ep, REG_INTEN, REG_INTEN_TX); @@ -417,9 +415,9 @@ static irqreturn_t ep93xx_irq(int irq, void *dev_id) if (status & REG_INTSTS_RX) { spin_lock(&ep->rx_lock); - if (likely(netif_rx_schedule_prep(dev, &ep->napi))) { + if (likely(netif_rx_schedule_prep(&ep->napi))) { wrl(ep, REG_INTEN, REG_INTEN_TX); - __netif_rx_schedule(dev, &ep->napi); + __netif_rx_schedule(&ep->napi); } spin_unlock(&ep->rx_lock); } diff --git a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c index 3bb9e293e2efea6ba066b6ad61960002f89d1675..e380de4544637629dcd3260e8b463d10af272200 100644 --- a/drivers/net/arm/ether1.c +++ b/drivers/net/arm/ether1.c @@ -996,7 +996,6 @@ ether1_probe(struct expansion_card *ec, const struct ecard_id *id) { struct net_device *dev; int i, ret = 0; - DECLARE_MAC_BUF(mac); ether1_banner(); @@ -1044,8 +1043,8 @@ ether1_probe(struct expansion_card *ec, const struct ecard_id *id) if (ret) goto free; - printk(KERN_INFO "%s: ether1 in slot %d, %s\n", - dev->name, ec->slot_no, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: ether1 in slot %d, %pM\n", + dev->name, ec->slot_no, dev->dev_addr); ecard_set_drvdata(ec, dev); return 0; diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c index 67e96ae85035638ee009f2aadac0e5a7a538269b..21a7bef12d3b1c1965d166dad6db7ae9d5eecd6c 100644 --- a/drivers/net/arm/ether3.c +++ b/drivers/net/arm/ether3.c @@ -776,7 +776,6 @@ ether3_probe(struct expansion_card *ec, const struct ecard_id *id) const struct ether3_data *data = id->data; struct net_device *dev; int bus_type, ret; - DECLARE_MAC_BUF(mac); ether3_banner(); @@ -859,8 +858,8 @@ ether3_probe(struct expansion_card *ec, const struct ecard_id *id) if (ret) goto free; - printk("%s: %s in slot %d, %s\n", - dev->name, data->name, ec->slot_no, print_mac(mac, dev->dev_addr)); + printk("%s: %s in slot %d, %pM\n", + dev->name, data->name, ec->slot_no, dev->dev_addr); ecard_set_drvdata(ec, dev); return 0; diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c index 5c5f1e470d3c2d05fcc910fb97917cb487bf7533..6278606d1049546966f0b51aaad941dfbded6973 100644 --- a/drivers/net/arm/etherh.c +++ b/drivers/net/arm/etherh.c @@ -637,6 +637,21 @@ static const struct ethtool_ops etherh_ethtool_ops = { .get_drvinfo = etherh_get_drvinfo, }; +static const struct net_device_ops etherh_netdev_ops = { + .ndo_open = etherh_open, + .ndo_stop = etherh_close, + .ndo_set_config = etherh_set_config, + .ndo_start_xmit = ei_start_xmit, + .ndo_tx_timeout = ei_tx_timeout, + .ndo_get_stats = ei_get_stats, + .ndo_set_multicast_list = ei_set_multicast_list, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = ei_poll, +#endif +}; + static u32 etherh_regoffsets[16]; static u32 etherm_regoffsets[16]; @@ -648,7 +663,6 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id) struct net_device *dev; struct etherh_priv *eh; int ret; - DECLARE_MAC_BUF(mac); etherh_banner(); @@ -664,9 +678,7 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id) SET_NETDEV_DEV(dev, &ec->dev); - dev->open = etherh_open; - dev->stop = etherh_close; - dev->set_config = etherh_set_config; + dev->netdev_ops = ðerh_netdev_ops; dev->irq = ec->irq; dev->ethtool_ops = ðerh_ethtool_ops; @@ -746,8 +758,8 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id) if (ret) goto free; - printk(KERN_INFO "%s: %s in slot %d, %s\n", - dev->name, data->name, ec->slot_no, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: %s in slot %d, %pM\n", + dev->name, data->name, ec->slot_no, dev->dev_addr); ecard_set_drvdata(ec, dev); diff --git a/drivers/net/arm/ixp4xx_eth.c b/drivers/net/arm/ixp4xx_eth.c index e2d702b8b2e4766321824c26941074b40c950fa5..26af411fc42819f8b7190fc4b4ba263965f003d8 100644 --- a/drivers/net/arm/ixp4xx_eth.c +++ b/drivers/net/arm/ixp4xx_eth.c @@ -30,12 +30,11 @@ #include #include #include -#include +#include #include #include #include -#define DEBUG_QUEUES 0 #define DEBUG_DESC 0 #define DEBUG_RX 0 #define DEBUG_TX 0 @@ -59,7 +58,6 @@ #define NAPI_WEIGHT 16 #define MDIO_INTERVAL (3 * HZ) #define MAX_MDIO_RETRIES 100 /* microseconds, typically 30 cycles */ -#define MAX_MII_RESET_RETRIES 100 /* mdio_read() cycles, typically 4 */ #define MAX_CLOSE_WAIT 1000 /* microseconds, typically 2-3 cycles */ #define NPE_ID(port_id) ((port_id) >> 4) @@ -164,15 +162,14 @@ struct port { struct npe *npe; struct net_device *netdev; struct napi_struct napi; - struct net_device_stats stat; - struct mii_if_info mii; - struct delayed_work mdio_thread; + struct phy_device *phydev; struct eth_plat_info *plat; buffer_t *rx_buff_tab[RX_DESCS], *tx_buff_tab[TX_DESCS]; struct desc *desc_tab; /* coherent */ u32 desc_tab_phys; int id; /* logical port ID */ - u16 mii_bmcr; + int speed, duplex; + u8 firmware[4]; }; /* NPE message structure */ @@ -243,19 +240,20 @@ static inline void memcpy_swab32(u32 *dest, u32 *src, int cnt) static spinlock_t mdio_lock; static struct eth_regs __iomem *mdio_regs; /* mdio command and status only */ +struct mii_bus *mdio_bus; static int ports_open; static struct port *npe_port_tab[MAX_NPES]; static struct dma_pool *dma_pool; -static u16 mdio_cmd(struct net_device *dev, int phy_id, int location, - int write, u16 cmd) +static int ixp4xx_mdio_cmd(struct mii_bus *bus, int phy_id, int location, + int write, u16 cmd) { int cycles = 0; if (__raw_readl(&mdio_regs->mdio_command[3]) & 0x80) { - printk(KERN_ERR "%s: MII not ready to transmit\n", dev->name); - return 0; + printk(KERN_ERR "%s: MII not ready to transmit\n", bus->name); + return -1; } if (write) { @@ -274,107 +272,119 @@ static u16 mdio_cmd(struct net_device *dev, int phy_id, int location, } if (cycles == MAX_MDIO_RETRIES) { - printk(KERN_ERR "%s: MII write failed\n", dev->name); - return 0; + printk(KERN_ERR "%s #%i: MII write failed\n", bus->name, + phy_id); + return -1; } #if DEBUG_MDIO - printk(KERN_DEBUG "%s: mdio_cmd() took %i cycles\n", dev->name, - cycles); + printk(KERN_DEBUG "%s #%i: mdio_%s() took %i cycles\n", bus->name, + phy_id, write ? "write" : "read", cycles); #endif if (write) return 0; if (__raw_readl(&mdio_regs->mdio_status[3]) & 0x80) { - printk(KERN_ERR "%s: MII read failed\n", dev->name); - return 0; +#if DEBUG_MDIO + printk(KERN_DEBUG "%s #%i: MII read failed\n", bus->name, + phy_id); +#endif + return 0xFFFF; /* don't return error */ } return (__raw_readl(&mdio_regs->mdio_status[0]) & 0xFF) | - (__raw_readl(&mdio_regs->mdio_status[1]) << 8); + ((__raw_readl(&mdio_regs->mdio_status[1]) & 0xFF) << 8); } -static int mdio_read(struct net_device *dev, int phy_id, int location) +static int ixp4xx_mdio_read(struct mii_bus *bus, int phy_id, int location) { unsigned long flags; - u16 val; + int ret; spin_lock_irqsave(&mdio_lock, flags); - val = mdio_cmd(dev, phy_id, location, 0, 0); + ret = ixp4xx_mdio_cmd(bus, phy_id, location, 0, 0); spin_unlock_irqrestore(&mdio_lock, flags); - return val; +#if DEBUG_MDIO + printk(KERN_DEBUG "%s #%i: MII read [%i] -> 0x%X\n", bus->name, + phy_id, location, ret); +#endif + return ret; } -static void mdio_write(struct net_device *dev, int phy_id, int location, - int val) +static int ixp4xx_mdio_write(struct mii_bus *bus, int phy_id, int location, + u16 val) { unsigned long flags; + int ret; spin_lock_irqsave(&mdio_lock, flags); - mdio_cmd(dev, phy_id, location, 1, val); + ret = ixp4xx_mdio_cmd(bus, phy_id, location, 1, val); spin_unlock_irqrestore(&mdio_lock, flags); +#if DEBUG_MDIO + printk(KERN_DEBUG "%s #%i: MII read [%i] <- 0x%X, err = %i\n", + bus->name, phy_id, location, val, ret); +#endif + return ret; } -static void phy_reset(struct net_device *dev, int phy_id) +static int ixp4xx_mdio_register(void) { - struct port *port = netdev_priv(dev); - int cycles = 0; + int err; - mdio_write(dev, phy_id, MII_BMCR, port->mii_bmcr | BMCR_RESET); + if (!(mdio_bus = mdiobus_alloc())) + return -ENOMEM; - while (cycles < MAX_MII_RESET_RETRIES) { - if (!(mdio_read(dev, phy_id, MII_BMCR) & BMCR_RESET)) { -#if DEBUG_MDIO - printk(KERN_DEBUG "%s: phy_reset() took %i cycles\n", - dev->name, cycles); -#endif - return; - } - udelay(1); - cycles++; - } + /* All MII PHY accesses use NPE-B Ethernet registers */ + spin_lock_init(&mdio_lock); + mdio_regs = (struct eth_regs __iomem *)IXP4XX_EthB_BASE_VIRT; + __raw_writel(DEFAULT_CORE_CNTRL, &mdio_regs->core_control); + + mdio_bus->name = "IXP4xx MII Bus"; + mdio_bus->read = &ixp4xx_mdio_read; + mdio_bus->write = &ixp4xx_mdio_write; + strcpy(mdio_bus->id, "0"); - printk(KERN_ERR "%s: MII reset failed\n", dev->name); + if ((err = mdiobus_register(mdio_bus))) + mdiobus_free(mdio_bus); + return err; } -static void eth_set_duplex(struct port *port) +static void ixp4xx_mdio_remove(void) { - if (port->mii.full_duplex) - __raw_writel(DEFAULT_TX_CNTRL0 & ~TX_CNTRL0_HALFDUPLEX, - &port->regs->tx_control[0]); - else - __raw_writel(DEFAULT_TX_CNTRL0 | TX_CNTRL0_HALFDUPLEX, - &port->regs->tx_control[0]); + mdiobus_unregister(mdio_bus); + mdiobus_free(mdio_bus); } -static void phy_check_media(struct port *port, int init) +static void ixp4xx_adjust_link(struct net_device *dev) { - if (mii_check_media(&port->mii, 1, init)) - eth_set_duplex(port); - if (port->mii.force_media) { /* mii_check_media() doesn't work */ - struct net_device *dev = port->netdev; - int cur_link = mii_link_ok(&port->mii); - int prev_link = netif_carrier_ok(dev); - - if (!prev_link && cur_link) { - printk(KERN_INFO "%s: link up\n", dev->name); - netif_carrier_on(dev); - } else if (prev_link && !cur_link) { + struct port *port = netdev_priv(dev); + struct phy_device *phydev = port->phydev; + + if (!phydev->link) { + if (port->speed) { + port->speed = 0; printk(KERN_INFO "%s: link down\n", dev->name); - netif_carrier_off(dev); } + return; } -} + if (port->speed == phydev->speed && port->duplex == phydev->duplex) + return; -static void mdio_thread(struct work_struct *work) -{ - struct port *port = container_of(work, struct port, mdio_thread.work); + port->speed = phydev->speed; + port->duplex = phydev->duplex; + + if (port->duplex) + __raw_writel(DEFAULT_TX_CNTRL0 & ~TX_CNTRL0_HALFDUPLEX, + &port->regs->tx_control[0]); + else + __raw_writel(DEFAULT_TX_CNTRL0 | TX_CNTRL0_HALFDUPLEX, + &port->regs->tx_control[0]); - phy_check_media(port, 0); - schedule_delayed_work(&port->mdio_thread, MDIO_INTERVAL); + printk(KERN_INFO "%s: link up, speed %u Mb/s, %s duplex\n", + dev->name, port->speed, port->duplex ? "full" : "half"); } @@ -412,47 +422,13 @@ static inline void debug_desc(u32 phys, struct desc *desc) #endif } -static inline void debug_queue(unsigned int queue, int is_get, u32 phys) -{ -#if DEBUG_QUEUES - static struct { - int queue; - char *name; - } names[] = { - { TX_QUEUE(0x10), "TX#0 " }, - { TX_QUEUE(0x20), "TX#1 " }, - { TX_QUEUE(0x00), "TX#2 " }, - { RXFREE_QUEUE(0x10), "RX-free#0 " }, - { RXFREE_QUEUE(0x20), "RX-free#1 " }, - { RXFREE_QUEUE(0x00), "RX-free#2 " }, - { TXDONE_QUEUE, "TX-done " }, - }; - int i; - - for (i = 0; i < ARRAY_SIZE(names); i++) - if (names[i].queue == queue) - break; - - printk(KERN_DEBUG "Queue %i %s%s %X\n", queue, - i < ARRAY_SIZE(names) ? names[i].name : "", - is_get ? "->" : "<-", phys); -#endif -} - -static inline u32 queue_get_entry(unsigned int queue) -{ - u32 phys = qmgr_get_entry(queue); - debug_queue(queue, 1, phys); - return phys; -} - static inline int queue_get_desc(unsigned int queue, struct port *port, int is_tx) { u32 phys, tab_phys, n_desc; struct desc *tab; - if (!(phys = queue_get_entry(queue))) + if (!(phys = qmgr_get_entry(queue))) return -1; phys &= ~0x1F; /* mask out non-address bits */ @@ -468,7 +444,6 @@ static inline int queue_get_desc(unsigned int queue, struct port *port, static inline void queue_put_desc(unsigned int queue, u32 phys, struct desc *desc) { - debug_queue(queue, 0, phys); debug_desc(phys, desc); BUG_ON(phys & 0x1F); qmgr_put_entry(queue, phys); @@ -498,7 +473,7 @@ static void eth_rx_irq(void *pdev) printk(KERN_DEBUG "%s: eth_rx_irq\n", dev->name); #endif qmgr_disable_irq(port->plat->rxq); - netif_rx_schedule(dev, &port->napi); + netif_rx_schedule(&port->napi); } static int eth_poll(struct napi_struct *napi, int budget) @@ -526,7 +501,7 @@ static int eth_poll(struct napi_struct *napi, int budget) printk(KERN_DEBUG "%s: eth_poll netif_rx_complete\n", dev->name); #endif - netif_rx_complete(dev, napi); + netif_rx_complete(napi); qmgr_enable_irq(rxq); if (!qmgr_stat_empty(rxq) && netif_rx_reschedule(dev, napi)) { @@ -562,7 +537,7 @@ static int eth_poll(struct napi_struct *napi, int budget) #endif if (!skb) { - port->stat.rx_dropped++; + dev->stats.rx_dropped++; /* put the desc back on RX-ready queue */ desc->buf_len = MAX_MRU; desc->pkt_len = 0; @@ -588,9 +563,8 @@ static int eth_poll(struct napi_struct *napi, int budget) debug_pkt(dev, "eth_poll", skb->data, skb->len); skb->protocol = eth_type_trans(skb, dev); - dev->last_rx = jiffies; - port->stat.rx_packets++; - port->stat.rx_bytes += skb->len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; netif_receive_skb(skb); /* put the new buffer on RX-free queue */ @@ -618,7 +592,7 @@ static void eth_txdone_irq(void *unused) #if DEBUG_TX printk(KERN_DEBUG DRV_NAME ": eth_txdone_irq\n"); #endif - while ((phys = queue_get_entry(TXDONE_QUEUE)) != 0) { + while ((phys = qmgr_get_entry(TXDONE_QUEUE)) != 0) { u32 npe_id, n_desc; struct port *port; struct desc *desc; @@ -635,8 +609,8 @@ static void eth_txdone_irq(void *unused) debug_desc(phys, desc); if (port->tx_buff_tab[n_desc]) { /* not the draining packet */ - port->stat.tx_packets++; - port->stat.tx_bytes += desc->pkt_len; + port->netdev->stats.tx_packets++; + port->netdev->stats.tx_bytes += desc->pkt_len; dma_unmap_tx(port, desc); #if DEBUG_TX @@ -674,7 +648,7 @@ static int eth_xmit(struct sk_buff *skb, struct net_device *dev) if (unlikely(skb->len > MAX_MRU)) { dev_kfree_skb(skb); - port->stat.tx_errors++; + dev->stats.tx_errors++; return NETDEV_TX_OK; } @@ -690,7 +664,7 @@ static int eth_xmit(struct sk_buff *skb, struct net_device *dev) bytes = ALIGN(offset + len, 4); if (!(mem = kmalloc(bytes, GFP_ATOMIC))) { dev_kfree_skb(skb); - port->stat.tx_dropped++; + dev->stats.tx_dropped++; return NETDEV_TX_OK; } memcpy_swab32(mem, (u32 *)((int)skb->data & ~3), bytes / 4); @@ -704,7 +678,7 @@ static int eth_xmit(struct sk_buff *skb, struct net_device *dev) #else kfree(mem); #endif - port->stat.tx_dropped++; + dev->stats.tx_dropped++; return NETDEV_TX_OK; } @@ -747,12 +721,6 @@ static int eth_xmit(struct sk_buff *skb, struct net_device *dev) } -static struct net_device_stats *eth_stats(struct net_device *dev) -{ - struct port *port = netdev_priv(dev); - return &port->stat; -} - static void eth_set_mcast_list(struct net_device *dev) { struct port *port = netdev_priv(dev); @@ -786,41 +754,80 @@ static void eth_set_mcast_list(struct net_device *dev) static int eth_ioctl(struct net_device *dev, struct ifreq *req, int cmd) { struct port *port = netdev_priv(dev); - unsigned int duplex_chg; - int err; if (!netif_running(dev)) return -EINVAL; - err = generic_mii_ioctl(&port->mii, if_mii(req), cmd, &duplex_chg); - if (duplex_chg) - eth_set_duplex(port); - return err; + return phy_mii_ioctl(port->phydev, if_mii(req), cmd); +} + +/* ethtool support */ + +static void ixp4xx_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + struct port *port = netdev_priv(dev); + strcpy(info->driver, DRV_NAME); + snprintf(info->fw_version, sizeof(info->fw_version), "%u:%u:%u:%u", + port->firmware[0], port->firmware[1], + port->firmware[2], port->firmware[3]); + strcpy(info->bus_info, "internal"); } +static int ixp4xx_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct port *port = netdev_priv(dev); + return phy_ethtool_gset(port->phydev, cmd); +} + +static int ixp4xx_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct port *port = netdev_priv(dev); + return phy_ethtool_sset(port->phydev, cmd); +} + +static int ixp4xx_nway_reset(struct net_device *dev) +{ + struct port *port = netdev_priv(dev); + return phy_start_aneg(port->phydev); +} + +static struct ethtool_ops ixp4xx_ethtool_ops = { + .get_drvinfo = ixp4xx_get_drvinfo, + .get_settings = ixp4xx_get_settings, + .set_settings = ixp4xx_set_settings, + .nway_reset = ixp4xx_nway_reset, + .get_link = ethtool_op_get_link, +}; + static int request_queues(struct port *port) { int err; - err = qmgr_request_queue(RXFREE_QUEUE(port->id), RX_DESCS, 0, 0); + err = qmgr_request_queue(RXFREE_QUEUE(port->id), RX_DESCS, 0, 0, + "%s:RX-free", port->netdev->name); if (err) return err; - err = qmgr_request_queue(port->plat->rxq, RX_DESCS, 0, 0); + err = qmgr_request_queue(port->plat->rxq, RX_DESCS, 0, 0, + "%s:RX", port->netdev->name); if (err) goto rel_rxfree; - err = qmgr_request_queue(TX_QUEUE(port->id), TX_DESCS, 0, 0); + err = qmgr_request_queue(TX_QUEUE(port->id), TX_DESCS, 0, 0, + "%s:TX", port->netdev->name); if (err) goto rel_rx; - err = qmgr_request_queue(port->plat->txreadyq, TX_DESCS, 0, 0); + err = qmgr_request_queue(port->plat->txreadyq, TX_DESCS, 0, 0, + "%s:TX-ready", port->netdev->name); if (err) goto rel_tx; /* TX-done queue handles skbs sent out by the NPEs */ if (!ports_open) { - err = qmgr_request_queue(TXDONE_QUEUE, TXDONE_QUEUE_LEN, 0, 0); + err = qmgr_request_queue(TXDONE_QUEUE, TXDONE_QUEUE_LEN, 0, 0, + "%s:TX-done", DRV_NAME); if (err) goto rel_txready; } @@ -944,10 +951,12 @@ static int eth_open(struct net_device *dev) npe_name(npe)); return -EIO; } + port->firmware[0] = msg.byte4; + port->firmware[1] = msg.byte5; + port->firmware[2] = msg.byte6; + port->firmware[3] = msg.byte7; } - mdio_write(dev, port->plat->phy, MII_BMCR, port->mii_bmcr); - memset(&msg, 0, sizeof(msg)); msg.cmd = NPE_VLAN_SETRXQOSENTRY; msg.eth_id = port->id; @@ -985,6 +994,9 @@ static int eth_open(struct net_device *dev) return err; } + port->speed = 0; /* force "link up" message */ + phy_start(port->phydev); + for (i = 0; i < ETH_ALEN; i++) __raw_writel(dev->dev_addr[i], &port->regs->hw_addr[i]); __raw_writel(0x08, &port->regs->random_seed); @@ -1012,10 +1024,8 @@ static int eth_open(struct net_device *dev) __raw_writel(DEFAULT_RX_CNTRL0, &port->regs->rx_control[0]); napi_enable(&port->napi); - phy_check_media(port, 1); eth_set_mcast_list(dev); netif_start_queue(dev); - schedule_delayed_work(&port->mdio_thread, MDIO_INTERVAL); qmgr_set_irq(port->plat->rxq, QUEUE_IRQ_SRC_NOT_EMPTY, eth_rx_irq, dev); @@ -1026,7 +1036,7 @@ static int eth_open(struct net_device *dev) } ports_open++; /* we may already have RX data, enables IRQ */ - netif_rx_schedule(dev, &port->napi); + netif_rx_schedule(&port->napi); return 0; } @@ -1106,25 +1116,31 @@ static int eth_close(struct net_device *dev) printk(KERN_CRIT "%s: unable to disable loopback\n", dev->name); - port->mii_bmcr = mdio_read(dev, port->plat->phy, MII_BMCR) & - ~(BMCR_RESET | BMCR_PDOWN); /* may have been altered */ - mdio_write(dev, port->plat->phy, MII_BMCR, - port->mii_bmcr | BMCR_PDOWN); + phy_stop(port->phydev); if (!ports_open) qmgr_disable_irq(TXDONE_QUEUE); - cancel_rearming_delayed_work(&port->mdio_thread); destroy_queues(port); release_queues(port); return 0; } +static const struct net_device_ops ixp4xx_netdev_ops = { + .ndo_open = eth_open, + .ndo_stop = eth_close, + .ndo_start_xmit = eth_xmit, + .ndo_set_multicast_list = eth_set_mcast_list, + .ndo_do_ioctl = eth_ioctl, + +}; + static int __devinit eth_init_one(struct platform_device *pdev) { struct port *port; struct net_device *dev; struct eth_plat_info *plat = pdev->dev.platform_data; u32 regs_phys; + char phy_id[BUS_ID_SIZE]; int err; if (!(dev = alloc_etherdev(sizeof(struct port)))) @@ -1153,12 +1169,8 @@ static int __devinit eth_init_one(struct platform_device *pdev) goto err_free; } - dev->open = eth_open; - dev->hard_start_xmit = eth_xmit; - dev->stop = eth_close; - dev->get_stats = eth_stats; - dev->do_ioctl = eth_ioctl; - dev->set_multicast_list = eth_set_mcast_list; + dev->netdev_ops = &ixp4xx_netdev_ops; + dev->ethtool_ops = &ixp4xx_ethtool_ops; dev->tx_queue_len = 100; netif_napi_add(dev, &port->napi, eth_poll, NAPI_WEIGHT); @@ -1191,22 +1203,19 @@ static int __devinit eth_init_one(struct platform_device *pdev) __raw_writel(DEFAULT_CORE_CNTRL, &port->regs->core_control); udelay(50); - port->mii.dev = dev; - port->mii.mdio_read = mdio_read; - port->mii.mdio_write = mdio_write; - port->mii.phy_id = plat->phy; - port->mii.phy_id_mask = 0x1F; - port->mii.reg_num_mask = 0x1F; + snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, "0", plat->phy); + port->phydev = phy_connect(dev, phy_id, &ixp4xx_adjust_link, 0, + PHY_INTERFACE_MODE_MII); + if (IS_ERR(port->phydev)) { + printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); + return PTR_ERR(port->phydev); + } + + port->phydev->irq = PHY_POLL; printk(KERN_INFO "%s: MII PHY %i on %s\n", dev->name, plat->phy, npe_name(port->npe)); - phy_reset(dev, plat->phy); - port->mii_bmcr = mdio_read(dev, plat->phy, MII_BMCR) & - ~(BMCR_RESET | BMCR_PDOWN); - mdio_write(dev, plat->phy, MII_BMCR, port->mii_bmcr | BMCR_PDOWN); - - INIT_DELAYED_WORK(&port->mdio_thread, mdio_thread); return 0; err_unreg: @@ -1232,7 +1241,7 @@ static int __devexit eth_remove_one(struct platform_device *pdev) return 0; } -static struct platform_driver drv = { +static struct platform_driver ixp4xx_eth_driver = { .driver.name = DRV_NAME, .probe = eth_init_one, .remove = eth_remove_one, @@ -1240,20 +1249,19 @@ static struct platform_driver drv = { static int __init eth_init_module(void) { + int err; if (!(ixp4xx_read_feature_bits() & IXP4XX_FEATURE_NPEB_ETH0)) return -ENOSYS; - /* All MII PHY accesses use NPE-B Ethernet registers */ - spin_lock_init(&mdio_lock); - mdio_regs = (struct eth_regs __iomem *)IXP4XX_EthB_BASE_VIRT; - __raw_writel(DEFAULT_CORE_CNTRL, &mdio_regs->core_control); - - return platform_driver_register(&drv); + if ((err = ixp4xx_mdio_register())) + return err; + return platform_driver_register(&ixp4xx_eth_driver); } static void __exit eth_cleanup_module(void) { - platform_driver_unregister(&drv); + platform_driver_unregister(&ixp4xx_eth_driver); + ixp4xx_mdio_remove(); } MODULE_AUTHOR("Krzysztof Halasa"); diff --git a/drivers/net/arm/ks8695net.c b/drivers/net/arm/ks8695net.c new file mode 100644 index 0000000000000000000000000000000000000000..592daee9dc2815cb7e6f6977dfcdad8485204224 --- /dev/null +++ b/drivers/net/arm/ks8695net.c @@ -0,0 +1,1676 @@ +/* + * Micrel KS8695 (Centaur) Ethernet. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * Copyright 2008 Simtec Electronics + * Daniel Silverstone + * Vincent Sanders + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "ks8695net.h" + +#define MODULENAME "ks8695_ether" +#define MODULEVERSION "1.01" + +/* + * Transmit and device reset timeout, default 5 seconds. + */ +static int watchdog = 5000; + +/* Hardware structures */ + +/** + * struct rx_ring_desc - Receive descriptor ring element + * @status: The status of the descriptor element (E.g. who owns it) + * @length: The number of bytes in the block pointed to by data_ptr + * @data_ptr: The physical address of the data block to receive into + * @next_desc: The physical address of the next descriptor element. + */ +struct rx_ring_desc { + __le32 status; + __le32 length; + __le32 data_ptr; + __le32 next_desc; +}; + +/** + * struct tx_ring_desc - Transmit descriptor ring element + * @owner: Who owns the descriptor + * @status: The number of bytes in the block pointed to by data_ptr + * @data_ptr: The physical address of the data block to receive into + * @next_desc: The physical address of the next descriptor element. + */ +struct tx_ring_desc { + __le32 owner; + __le32 status; + __le32 data_ptr; + __le32 next_desc; +}; + +/** + * struct ks8695_skbuff - sk_buff wrapper for rx/tx rings. + * @skb: The buffer in the ring + * @dma_ptr: The mapped DMA pointer of the buffer + * @length: The number of bytes mapped to dma_ptr + */ +struct ks8695_skbuff { + struct sk_buff *skb; + dma_addr_t dma_ptr; + u32 length; +}; + +/* Private device structure */ + +#define MAX_TX_DESC 8 +#define MAX_TX_DESC_MASK 0x7 +#define MAX_RX_DESC 16 +#define MAX_RX_DESC_MASK 0xf + +#define MAX_RXBUF_SIZE 0x700 + +#define TX_RING_DMA_SIZE (sizeof(struct tx_ring_desc) * MAX_TX_DESC) +#define RX_RING_DMA_SIZE (sizeof(struct rx_ring_desc) * MAX_RX_DESC) +#define RING_DMA_SIZE (TX_RING_DMA_SIZE + RX_RING_DMA_SIZE) + +/** + * enum ks8695_dtype - Device type + * @KS8695_DTYPE_WAN: This device is a WAN interface + * @KS8695_DTYPE_LAN: This device is a LAN interface + * @KS8695_DTYPE_HPNA: This device is an HPNA interface + */ +enum ks8695_dtype { + KS8695_DTYPE_WAN, + KS8695_DTYPE_LAN, + KS8695_DTYPE_HPNA, +}; + +/** + * struct ks8695_priv - Private data for the KS8695 Ethernet + * @in_suspend: Flag to indicate if we're suspending/resuming + * @ndev: The net_device for this interface + * @dev: The platform device object for this interface + * @dtype: The type of this device + * @io_regs: The ioremapped registers for this interface + * @rx_irq_name: The textual name of the RX IRQ from the platform data + * @tx_irq_name: The textual name of the TX IRQ from the platform data + * @link_irq_name: The textual name of the link IRQ from the + * platform data if available + * @rx_irq: The IRQ number for the RX IRQ + * @tx_irq: The IRQ number for the TX IRQ + * @link_irq: The IRQ number for the link IRQ if available + * @regs_req: The resource request for the registers region + * @phyiface_req: The resource request for the phy/switch region + * if available + * @phyiface_regs: The ioremapped registers for the phy/switch if available + * @ring_base: The base pointer of the dma coherent memory for the rings + * @ring_base_dma: The DMA mapped equivalent of ring_base + * @tx_ring: The pointer in ring_base of the TX ring + * @tx_ring_used: The number of slots in the TX ring which are occupied + * @tx_ring_next_slot: The next slot to fill in the TX ring + * @tx_ring_dma: The DMA mapped equivalent of tx_ring + * @tx_buffers: The sk_buff mappings for the TX ring + * @txq_lock: A lock to protect the tx_buffers tx_ring_used etc variables + * @rx_ring: The pointer in ring_base of the RX ring + * @rx_ring_dma: The DMA mapped equivalent of rx_ring + * @rx_buffers: The sk_buff mappings for the RX ring + * @next_rx_desc_read: The next RX descriptor to read from on IRQ + * @msg_enable: The flags for which messages to emit + */ +struct ks8695_priv { + int in_suspend; + struct net_device *ndev; + struct device *dev; + enum ks8695_dtype dtype; + void __iomem *io_regs; + + const char *rx_irq_name, *tx_irq_name, *link_irq_name; + int rx_irq, tx_irq, link_irq; + + struct resource *regs_req, *phyiface_req; + void __iomem *phyiface_regs; + + void *ring_base; + dma_addr_t ring_base_dma; + + struct tx_ring_desc *tx_ring; + int tx_ring_used; + int tx_ring_next_slot; + dma_addr_t tx_ring_dma; + struct ks8695_skbuff tx_buffers[MAX_TX_DESC]; + spinlock_t txq_lock; + + struct rx_ring_desc *rx_ring; + dma_addr_t rx_ring_dma; + struct ks8695_skbuff rx_buffers[MAX_RX_DESC]; + int next_rx_desc_read; + + int msg_enable; +}; + +/* Register access */ + +/** + * ks8695_readreg - Read from a KS8695 ethernet register + * @ksp: The device to read from + * @reg: The register to read + */ +static inline u32 +ks8695_readreg(struct ks8695_priv *ksp, int reg) +{ + return readl(ksp->io_regs + reg); +} + +/** + * ks8695_writereg - Write to a KS8695 ethernet register + * @ksp: The device to write to + * @reg: The register to write + * @value: The value to write to the register + */ +static inline void +ks8695_writereg(struct ks8695_priv *ksp, int reg, u32 value) +{ + writel(value, ksp->io_regs + reg); +} + +/* Utility functions */ + +/** + * ks8695_port_type - Retrieve port-type as user-friendly string + * @ksp: The device to return the type for + * + * Returns a string indicating which of the WAN, LAN or HPNA + * ports this device is likely to represent. + */ +static const char * +ks8695_port_type(struct ks8695_priv *ksp) +{ + switch (ksp->dtype) { + case KS8695_DTYPE_LAN: + return "LAN"; + case KS8695_DTYPE_WAN: + return "WAN"; + case KS8695_DTYPE_HPNA: + return "HPNA"; + } + + return "UNKNOWN"; +} + +/** + * ks8695_update_mac - Update the MAC registers in the device + * @ksp: The device to update + * + * Updates the MAC registers in the KS8695 device from the address in the + * net_device structure associated with this interface. + */ +static void +ks8695_update_mac(struct ks8695_priv *ksp) +{ + /* Update the HW with the MAC from the net_device */ + struct net_device *ndev = ksp->ndev; + u32 machigh, maclow; + + maclow = ((ndev->dev_addr[2] << 24) | (ndev->dev_addr[3] << 16) | + (ndev->dev_addr[4] << 8) | (ndev->dev_addr[5] << 0)); + machigh = ((ndev->dev_addr[0] << 8) | (ndev->dev_addr[1] << 0)); + + ks8695_writereg(ksp, KS8695_MAL, maclow); + ks8695_writereg(ksp, KS8695_MAH, machigh); + +} + +/** + * ks8695_refill_rxbuffers - Re-fill the RX buffer ring + * @ksp: The device to refill + * + * Iterates the RX ring of the device looking for empty slots. + * For each empty slot, we allocate and map a new SKB and give it + * to the hardware. + * This can be called from interrupt context safely. + */ +static void +ks8695_refill_rxbuffers(struct ks8695_priv *ksp) +{ + /* Run around the RX ring, filling in any missing sk_buff's */ + int buff_n; + + for (buff_n = 0; buff_n < MAX_RX_DESC; ++buff_n) { + if (!ksp->rx_buffers[buff_n].skb) { + struct sk_buff *skb = dev_alloc_skb(MAX_RXBUF_SIZE); + dma_addr_t mapping; + + ksp->rx_buffers[buff_n].skb = skb; + if (skb == NULL) { + /* Failed to allocate one, perhaps + * we'll try again later. + */ + break; + } + + mapping = dma_map_single(ksp->dev, skb->data, + MAX_RXBUF_SIZE, + DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(ksp->dev, mapping))) { + /* Failed to DMA map this SKB, try later */ + dev_kfree_skb_irq(skb); + ksp->rx_buffers[buff_n].skb = NULL; + break; + } + ksp->rx_buffers[buff_n].dma_ptr = mapping; + skb->dev = ksp->ndev; + ksp->rx_buffers[buff_n].length = MAX_RXBUF_SIZE; + + /* Record this into the DMA ring */ + ksp->rx_ring[buff_n].data_ptr = cpu_to_le32(mapping); + ksp->rx_ring[buff_n].length = + cpu_to_le32(MAX_RXBUF_SIZE); + + wmb(); + + /* And give ownership over to the hardware */ + ksp->rx_ring[buff_n].status = cpu_to_le32(RDES_OWN); + } + } +} + +/* Maximum number of multicast addresses which the KS8695 HW supports */ +#define KS8695_NR_ADDRESSES 16 + +/** + * ks8695_init_partial_multicast - Init the mcast addr registers + * @ksp: The device to initialise + * @addr: The multicast address list to use + * @nr_addr: The number of addresses in the list + * + * This routine is a helper for ks8695_set_multicast - it writes + * the additional-address registers in the KS8695 ethernet device + * and cleans up any others left behind. + */ +static void +ks8695_init_partial_multicast(struct ks8695_priv *ksp, + struct dev_mc_list *addr, + int nr_addr) +{ + u32 low, high; + int i; + + for (i = 0; i < nr_addr; i++, addr = addr->next) { + /* Ran out of addresses? */ + if (!addr) + break; + /* Ran out of space in chip? */ + BUG_ON(i == KS8695_NR_ADDRESSES); + + low = (addr->dmi_addr[2] << 24) | (addr->dmi_addr[3] << 16) | + (addr->dmi_addr[4] << 8) | (addr->dmi_addr[5]); + high = (addr->dmi_addr[0] << 8) | (addr->dmi_addr[1]); + + ks8695_writereg(ksp, KS8695_AAL_(i), low); + ks8695_writereg(ksp, KS8695_AAH_(i), AAH_E | high); + } + + /* Clear the remaining Additional Station Addresses */ + for (; i < KS8695_NR_ADDRESSES; i++) { + ks8695_writereg(ksp, KS8695_AAL_(i), 0); + ks8695_writereg(ksp, KS8695_AAH_(i), 0); + } +} + +/* Interrupt handling */ + +/** + * ks8695_tx_irq - Transmit IRQ handler + * @irq: The IRQ which went off (ignored) + * @dev_id: The net_device for the interrupt + * + * Process the TX ring, clearing out any transmitted slots. + * Allows the net_device to pass us new packets once slots are + * freed. + */ +static irqreturn_t +ks8695_tx_irq(int irq, void *dev_id) +{ + struct net_device *ndev = (struct net_device *)dev_id; + struct ks8695_priv *ksp = netdev_priv(ndev); + int buff_n; + + for (buff_n = 0; buff_n < MAX_TX_DESC; ++buff_n) { + if (ksp->tx_buffers[buff_n].skb && + !(ksp->tx_ring[buff_n].owner & cpu_to_le32(TDES_OWN))) { + rmb(); + /* An SKB which is not owned by HW is present */ + /* Update the stats for the net_device */ + ndev->stats.tx_packets++; + ndev->stats.tx_bytes += ksp->tx_buffers[buff_n].length; + + /* Free the packet from the ring */ + ksp->tx_ring[buff_n].data_ptr = 0; + + /* Free the sk_buff */ + dma_unmap_single(ksp->dev, + ksp->tx_buffers[buff_n].dma_ptr, + ksp->tx_buffers[buff_n].length, + DMA_TO_DEVICE); + dev_kfree_skb_irq(ksp->tx_buffers[buff_n].skb); + ksp->tx_buffers[buff_n].skb = NULL; + ksp->tx_ring_used--; + } + } + + netif_wake_queue(ndev); + + return IRQ_HANDLED; +} + +/** + * ks8695_rx_irq - Receive IRQ handler + * @irq: The IRQ which went off (ignored) + * @dev_id: The net_device for the interrupt + * + * Process the RX ring, passing any received packets up to the + * host. If we received anything other than errors, we then + * refill the ring. + */ +static irqreturn_t +ks8695_rx_irq(int irq, void *dev_id) +{ + struct net_device *ndev = (struct net_device *)dev_id; + struct ks8695_priv *ksp = netdev_priv(ndev); + struct sk_buff *skb; + int buff_n; + u32 flags; + int pktlen; + int last_rx_processed = -1; + + buff_n = ksp->next_rx_desc_read; + do { + if (ksp->rx_buffers[buff_n].skb && + !(ksp->rx_ring[buff_n].status & cpu_to_le32(RDES_OWN))) { + rmb(); + flags = le32_to_cpu(ksp->rx_ring[buff_n].status); + /* Found an SKB which we own, this means we + * received a packet + */ + if ((flags & (RDES_FS | RDES_LS)) != + (RDES_FS | RDES_LS)) { + /* This packet is not the first and + * the last segment. Therefore it is + * a "spanning" packet and we can't + * handle it + */ + goto rx_failure; + } + + if (flags & (RDES_ES | RDES_RE)) { + /* It's an error packet */ + ndev->stats.rx_errors++; + if (flags & RDES_TL) + ndev->stats.rx_length_errors++; + if (flags & RDES_RF) + ndev->stats.rx_length_errors++; + if (flags & RDES_CE) + ndev->stats.rx_crc_errors++; + if (flags & RDES_RE) + ndev->stats.rx_missed_errors++; + + goto rx_failure; + } + + pktlen = flags & RDES_FLEN; + pktlen -= 4; /* Drop the CRC */ + + /* Retrieve the sk_buff */ + skb = ksp->rx_buffers[buff_n].skb; + + /* Clear it from the ring */ + ksp->rx_buffers[buff_n].skb = NULL; + ksp->rx_ring[buff_n].data_ptr = 0; + + /* Unmap the SKB */ + dma_unmap_single(ksp->dev, + ksp->rx_buffers[buff_n].dma_ptr, + ksp->rx_buffers[buff_n].length, + DMA_FROM_DEVICE); + + /* Relinquish the SKB to the network layer */ + skb_put(skb, pktlen); + skb->protocol = eth_type_trans(skb, ndev); + netif_rx(skb); + + /* Record stats */ + ndev->last_rx = jiffies; + ndev->stats.rx_packets++; + ndev->stats.rx_bytes += pktlen; + goto rx_finished; + +rx_failure: + /* This ring entry is an error, but we can + * re-use the skb + */ + /* Give the ring entry back to the hardware */ + ksp->rx_ring[buff_n].status = cpu_to_le32(RDES_OWN); +rx_finished: + /* And note this as processed so we can start + * from here next time + */ + last_rx_processed = buff_n; + } else { + /* Ran out of things to process, stop now */ + break; + } + buff_n = (buff_n + 1) & MAX_RX_DESC_MASK; + } while (buff_n != ksp->next_rx_desc_read); + + /* And note which RX descriptor we last did anything with */ + if (likely(last_rx_processed != -1)) + ksp->next_rx_desc_read = + (last_rx_processed + 1) & MAX_RX_DESC_MASK; + + /* And refill the buffers */ + ks8695_refill_rxbuffers(ksp); + + /* Kick the RX DMA engine, in case it became suspended */ + ks8695_writereg(ksp, KS8695_DRSC, 0); + + return IRQ_HANDLED; +} + +/** + * ks8695_link_irq - Link change IRQ handler + * @irq: The IRQ which went off (ignored) + * @dev_id: The net_device for the interrupt + * + * The WAN interface can generate an IRQ when the link changes, + * report this to the net layer and the user. + */ +static irqreturn_t +ks8695_link_irq(int irq, void *dev_id) +{ + struct net_device *ndev = (struct net_device *)dev_id; + struct ks8695_priv *ksp = netdev_priv(ndev); + u32 ctrl; + + ctrl = readl(ksp->phyiface_regs + KS8695_WMC); + if (ctrl & WMC_WLS) { + netif_carrier_on(ndev); + if (netif_msg_link(ksp)) + dev_info(ksp->dev, + "%s: Link is now up (10%sMbps/%s-duplex)\n", + ndev->name, + (ctrl & WMC_WSS) ? "0" : "", + (ctrl & WMC_WDS) ? "Full" : "Half"); + } else { + netif_carrier_off(ndev); + if (netif_msg_link(ksp)) + dev_info(ksp->dev, "%s: Link is now down.\n", + ndev->name); + } + + return IRQ_HANDLED; +} + + +/* KS8695 Device functions */ + +/** + * ks8695_reset - Reset a KS8695 ethernet interface + * @ksp: The interface to reset + * + * Perform an engine reset of the interface and re-program it + * with sensible defaults. + */ +static void +ks8695_reset(struct ks8695_priv *ksp) +{ + int reset_timeout = watchdog; + /* Issue the reset via the TX DMA control register */ + ks8695_writereg(ksp, KS8695_DTXC, DTXC_TRST); + while (reset_timeout--) { + if (!(ks8695_readreg(ksp, KS8695_DTXC) & DTXC_TRST)) + break; + msleep(1); + } + + if (reset_timeout == 0) { + dev_crit(ksp->dev, + "Timeout waiting for DMA engines to reset\n"); + /* And blithely carry on */ + } + + /* Definitely wait long enough before attempting to program + * the engines + */ + msleep(10); + + /* RX: unicast and broadcast */ + ks8695_writereg(ksp, KS8695_DRXC, DRXC_RU | DRXC_RB); + /* TX: pad and add CRC */ + ks8695_writereg(ksp, KS8695_DTXC, DTXC_TEP | DTXC_TAC); +} + +/** + * ks8695_shutdown - Shut down a KS8695 ethernet interface + * @ksp: The interface to shut down + * + * This disables packet RX/TX, cleans up IRQs, drains the rings, + * and basically places the interface into a clean shutdown + * state. + */ +static void +ks8695_shutdown(struct ks8695_priv *ksp) +{ + u32 ctrl; + int buff_n; + + /* Disable packet transmission */ + ctrl = ks8695_readreg(ksp, KS8695_DTXC); + ks8695_writereg(ksp, KS8695_DTXC, ctrl & ~DTXC_TE); + + /* Disable packet reception */ + ctrl = ks8695_readreg(ksp, KS8695_DRXC); + ks8695_writereg(ksp, KS8695_DRXC, ctrl & ~DRXC_RE); + + /* Release the IRQs */ + free_irq(ksp->rx_irq, ksp->ndev); + free_irq(ksp->tx_irq, ksp->ndev); + if (ksp->link_irq != -1) + free_irq(ksp->link_irq, ksp->ndev); + + /* Throw away any pending TX packets */ + for (buff_n = 0; buff_n < MAX_TX_DESC; ++buff_n) { + if (ksp->tx_buffers[buff_n].skb) { + /* Remove this SKB from the TX ring */ + ksp->tx_ring[buff_n].owner = 0; + ksp->tx_ring[buff_n].status = 0; + ksp->tx_ring[buff_n].data_ptr = 0; + + /* Unmap and bin this SKB */ + dma_unmap_single(ksp->dev, + ksp->tx_buffers[buff_n].dma_ptr, + ksp->tx_buffers[buff_n].length, + DMA_TO_DEVICE); + dev_kfree_skb_irq(ksp->tx_buffers[buff_n].skb); + ksp->tx_buffers[buff_n].skb = NULL; + } + } + + /* Purge the RX buffers */ + for (buff_n = 0; buff_n < MAX_RX_DESC; ++buff_n) { + if (ksp->rx_buffers[buff_n].skb) { + /* Remove the SKB from the RX ring */ + ksp->rx_ring[buff_n].status = 0; + ksp->rx_ring[buff_n].data_ptr = 0; + + /* Unmap and bin the SKB */ + dma_unmap_single(ksp->dev, + ksp->rx_buffers[buff_n].dma_ptr, + ksp->rx_buffers[buff_n].length, + DMA_FROM_DEVICE); + dev_kfree_skb_irq(ksp->rx_buffers[buff_n].skb); + ksp->rx_buffers[buff_n].skb = NULL; + } + } +} + + +/** + * ks8695_setup_irq - IRQ setup helper function + * @irq: The IRQ number to claim + * @irq_name: The name to give the IRQ claimant + * @handler: The function to call to handle the IRQ + * @ndev: The net_device to pass in as the dev_id argument to the handler + * + * Return 0 on success. + */ +static int +ks8695_setup_irq(int irq, const char *irq_name, + irq_handler_t handler, struct net_device *ndev) +{ + int ret; + + ret = request_irq(irq, handler, IRQF_SHARED, irq_name, ndev); + + if (ret) { + dev_err(&ndev->dev, "failure to request IRQ %d\n", irq); + return ret; + } + + return 0; +} + +/** + * ks8695_init_net - Initialise a KS8695 ethernet interface + * @ksp: The interface to initialise + * + * This routine fills the RX ring, initialises the DMA engines, + * allocates the IRQs and then starts the packet TX and RX + * engines. + */ +static int +ks8695_init_net(struct ks8695_priv *ksp) +{ + int ret; + u32 ctrl; + + ks8695_refill_rxbuffers(ksp); + + /* Initialise the DMA engines */ + ks8695_writereg(ksp, KS8695_RDLB, (u32) ksp->rx_ring_dma); + ks8695_writereg(ksp, KS8695_TDLB, (u32) ksp->tx_ring_dma); + + /* Request the IRQs */ + ret = ks8695_setup_irq(ksp->rx_irq, ksp->rx_irq_name, + ks8695_rx_irq, ksp->ndev); + if (ret) + return ret; + ret = ks8695_setup_irq(ksp->tx_irq, ksp->tx_irq_name, + ks8695_tx_irq, ksp->ndev); + if (ret) + return ret; + if (ksp->link_irq != -1) { + ret = ks8695_setup_irq(ksp->link_irq, ksp->link_irq_name, + ks8695_link_irq, ksp->ndev); + if (ret) + return ret; + } + + /* Set up the ring indices */ + ksp->next_rx_desc_read = 0; + ksp->tx_ring_next_slot = 0; + ksp->tx_ring_used = 0; + + /* Bring up transmission */ + ctrl = ks8695_readreg(ksp, KS8695_DTXC); + /* Enable packet transmission */ + ks8695_writereg(ksp, KS8695_DTXC, ctrl | DTXC_TE); + + /* Bring up the reception */ + ctrl = ks8695_readreg(ksp, KS8695_DRXC); + /* Enable packet reception */ + ks8695_writereg(ksp, KS8695_DRXC, ctrl | DRXC_RE); + /* And start the DMA engine */ + ks8695_writereg(ksp, KS8695_DRSC, 0); + + /* All done */ + return 0; +} + +/** + * ks8695_release_device - HW resource release for KS8695 e-net + * @ksp: The device to be freed + * + * This unallocates io memory regions, dma-coherent regions etc + * which were allocated in ks8695_probe. + */ +static void +ks8695_release_device(struct ks8695_priv *ksp) +{ + /* Unmap the registers */ + iounmap(ksp->io_regs); + if (ksp->phyiface_regs) + iounmap(ksp->phyiface_regs); + + /* And release the request */ + release_resource(ksp->regs_req); + kfree(ksp->regs_req); + if (ksp->phyiface_req) { + release_resource(ksp->phyiface_req); + kfree(ksp->phyiface_req); + } + + /* Free the ring buffers */ + dma_free_coherent(ksp->dev, RING_DMA_SIZE, + ksp->ring_base, ksp->ring_base_dma); +} + +/* Ethtool support */ + +/** + * ks8695_get_msglevel - Get the messages enabled for emission + * @ndev: The network device to read from + */ +static u32 +ks8695_get_msglevel(struct net_device *ndev) +{ + struct ks8695_priv *ksp = netdev_priv(ndev); + + return ksp->msg_enable; +} + +/** + * ks8695_set_msglevel - Set the messages enabled for emission + * @ndev: The network device to configure + * @value: The messages to set for emission + */ +static void +ks8695_set_msglevel(struct net_device *ndev, u32 value) +{ + struct ks8695_priv *ksp = netdev_priv(ndev); + + ksp->msg_enable = value; +} + +/** + * ks8695_get_settings - Get device-specific settings. + * @ndev: The network device to read settings from + * @cmd: The ethtool structure to read into + */ +static int +ks8695_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd) +{ + struct ks8695_priv *ksp = netdev_priv(ndev); + u32 ctrl; + + /* All ports on the KS8695 support these... */ + cmd->supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | + SUPPORTED_TP | SUPPORTED_MII); + cmd->transceiver = XCVR_INTERNAL; + + /* Port specific extras */ + switch (ksp->dtype) { + case KS8695_DTYPE_HPNA: + cmd->phy_address = 0; + /* not supported for HPNA */ + cmd->autoneg = AUTONEG_DISABLE; + + /* BUG: Erm, dtype hpna implies no phy regs */ + /* + ctrl = readl(KS8695_MISC_VA + KS8695_HMC); + cmd->speed = (ctrl & HMC_HSS) ? SPEED_100 : SPEED_10; + cmd->duplex = (ctrl & HMC_HDS) ? DUPLEX_FULL : DUPLEX_HALF; + */ + return -EOPNOTSUPP; + case KS8695_DTYPE_WAN: + cmd->advertising = ADVERTISED_TP | ADVERTISED_MII; + cmd->port = PORT_MII; + cmd->supported |= (SUPPORTED_Autoneg | SUPPORTED_Pause); + cmd->phy_address = 0; + + ctrl = readl(ksp->phyiface_regs + KS8695_WMC); + if ((ctrl & WMC_WAND) == 0) { + /* auto-negotiation is enabled */ + cmd->advertising |= ADVERTISED_Autoneg; + if (ctrl & WMC_WANA100F) + cmd->advertising |= ADVERTISED_100baseT_Full; + if (ctrl & WMC_WANA100H) + cmd->advertising |= ADVERTISED_100baseT_Half; + if (ctrl & WMC_WANA10F) + cmd->advertising |= ADVERTISED_10baseT_Full; + if (ctrl & WMC_WANA10H) + cmd->advertising |= ADVERTISED_10baseT_Half; + if (ctrl & WMC_WANAP) + cmd->advertising |= ADVERTISED_Pause; + cmd->autoneg = AUTONEG_ENABLE; + + cmd->speed = (ctrl & WMC_WSS) ? SPEED_100 : SPEED_10; + cmd->duplex = (ctrl & WMC_WDS) ? + DUPLEX_FULL : DUPLEX_HALF; + } else { + /* auto-negotiation is disabled */ + cmd->autoneg = AUTONEG_DISABLE; + + cmd->speed = (ctrl & WMC_WANF100) ? + SPEED_100 : SPEED_10; + cmd->duplex = (ctrl & WMC_WANFF) ? + DUPLEX_FULL : DUPLEX_HALF; + } + break; + case KS8695_DTYPE_LAN: + return -EOPNOTSUPP; + } + + return 0; +} + +/** + * ks8695_set_settings - Set device-specific settings. + * @ndev: The network device to configure + * @cmd: The settings to configure + */ +static int +ks8695_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd) +{ + struct ks8695_priv *ksp = netdev_priv(ndev); + u32 ctrl; + + if ((cmd->speed != SPEED_10) && (cmd->speed != SPEED_100)) + return -EINVAL; + if ((cmd->duplex != DUPLEX_HALF) && (cmd->duplex != DUPLEX_FULL)) + return -EINVAL; + if (cmd->port != PORT_MII) + return -EINVAL; + if (cmd->transceiver != XCVR_INTERNAL) + return -EINVAL; + if ((cmd->autoneg != AUTONEG_DISABLE) && + (cmd->autoneg != AUTONEG_ENABLE)) + return -EINVAL; + + if (cmd->autoneg == AUTONEG_ENABLE) { + if ((cmd->advertising & (ADVERTISED_10baseT_Half | + ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | + ADVERTISED_100baseT_Full)) == 0) + return -EINVAL; + + switch (ksp->dtype) { + case KS8695_DTYPE_HPNA: + /* HPNA does not support auto-negotiation. */ + return -EINVAL; + case KS8695_DTYPE_WAN: + ctrl = readl(ksp->phyiface_regs + KS8695_WMC); + + ctrl &= ~(WMC_WAND | WMC_WANA100F | WMC_WANA100H | + WMC_WANA10F | WMC_WANA10H); + if (cmd->advertising & ADVERTISED_100baseT_Full) + ctrl |= WMC_WANA100F; + if (cmd->advertising & ADVERTISED_100baseT_Half) + ctrl |= WMC_WANA100H; + if (cmd->advertising & ADVERTISED_10baseT_Full) + ctrl |= WMC_WANA10F; + if (cmd->advertising & ADVERTISED_10baseT_Half) + ctrl |= WMC_WANA10H; + + /* force a re-negotiation */ + ctrl |= WMC_WANR; + writel(ctrl, ksp->phyiface_regs + KS8695_WMC); + break; + case KS8695_DTYPE_LAN: + return -EOPNOTSUPP; + } + + } else { + switch (ksp->dtype) { + case KS8695_DTYPE_HPNA: + /* BUG: dtype_hpna implies no phy registers */ + /* + ctrl = __raw_readl(KS8695_MISC_VA + KS8695_HMC); + + ctrl &= ~(HMC_HSS | HMC_HDS); + if (cmd->speed == SPEED_100) + ctrl |= HMC_HSS; + if (cmd->duplex == DUPLEX_FULL) + ctrl |= HMC_HDS; + + __raw_writel(ctrl, KS8695_MISC_VA + KS8695_HMC); + */ + return -EOPNOTSUPP; + case KS8695_DTYPE_WAN: + ctrl = readl(ksp->phyiface_regs + KS8695_WMC); + + /* disable auto-negotiation */ + ctrl |= WMC_WAND; + ctrl &= ~(WMC_WANF100 | WMC_WANFF); + + if (cmd->speed == SPEED_100) + ctrl |= WMC_WANF100; + if (cmd->duplex == DUPLEX_FULL) + ctrl |= WMC_WANFF; + + writel(ctrl, ksp->phyiface_regs + KS8695_WMC); + break; + case KS8695_DTYPE_LAN: + return -EOPNOTSUPP; + } + } + + return 0; +} + +/** + * ks8695_nwayreset - Restart the autonegotiation on the port. + * @ndev: The network device to restart autoneotiation on + */ +static int +ks8695_nwayreset(struct net_device *ndev) +{ + struct ks8695_priv *ksp = netdev_priv(ndev); + u32 ctrl; + + switch (ksp->dtype) { + case KS8695_DTYPE_HPNA: + /* No phy means no autonegotiation on hpna */ + return -EINVAL; + case KS8695_DTYPE_WAN: + ctrl = readl(ksp->phyiface_regs + KS8695_WMC); + + if ((ctrl & WMC_WAND) == 0) + writel(ctrl | WMC_WANR, + ksp->phyiface_regs + KS8695_WMC); + else + /* auto-negotiation not enabled */ + return -EINVAL; + break; + case KS8695_DTYPE_LAN: + return -EOPNOTSUPP; + } + + return 0; +} + +/** + * ks8695_get_link - Retrieve link status of network interface + * @ndev: The network interface to retrive the link status of. + */ +static u32 +ks8695_get_link(struct net_device *ndev) +{ + struct ks8695_priv *ksp = netdev_priv(ndev); + u32 ctrl; + + switch (ksp->dtype) { + case KS8695_DTYPE_HPNA: + /* HPNA always has link */ + return 1; + case KS8695_DTYPE_WAN: + /* WAN we can read the PHY for */ + ctrl = readl(ksp->phyiface_regs + KS8695_WMC); + return ctrl & WMC_WLS; + case KS8695_DTYPE_LAN: + return -EOPNOTSUPP; + } + return 0; +} + +/** + * ks8695_get_pause - Retrieve network pause/flow-control advertising + * @ndev: The device to retrieve settings from + * @param: The structure to fill out with the information + */ +static void +ks8695_get_pause(struct net_device *ndev, struct ethtool_pauseparam *param) +{ + struct ks8695_priv *ksp = netdev_priv(ndev); + u32 ctrl; + + switch (ksp->dtype) { + case KS8695_DTYPE_HPNA: + /* No phy link on hpna to configure */ + return; + case KS8695_DTYPE_WAN: + ctrl = readl(ksp->phyiface_regs + KS8695_WMC); + + /* advertise Pause */ + param->autoneg = (ctrl & WMC_WANAP); + + /* current Rx Flow-control */ + ctrl = ks8695_readreg(ksp, KS8695_DRXC); + param->rx_pause = (ctrl & DRXC_RFCE); + + /* current Tx Flow-control */ + ctrl = ks8695_readreg(ksp, KS8695_DTXC); + param->tx_pause = (ctrl & DTXC_TFCE); + break; + case KS8695_DTYPE_LAN: + /* The LAN's "phy" is a direct-attached switch */ + return; + } +} + +/** + * ks8695_set_pause - Configure pause/flow-control + * @ndev: The device to configure + * @param: The pause parameters to set + * + * TODO: Implement this + */ +static int +ks8695_set_pause(struct net_device *ndev, struct ethtool_pauseparam *param) +{ + return -EOPNOTSUPP; +} + +/** + * ks8695_get_drvinfo - Retrieve driver information + * @ndev: The network device to retrieve info about + * @info: The info structure to fill out. + */ +static void +ks8695_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info) +{ + strlcpy(info->driver, MODULENAME, sizeof(info->driver)); + strlcpy(info->version, MODULEVERSION, sizeof(info->version)); + strlcpy(info->bus_info, ndev->dev.parent->bus_id, + sizeof(info->bus_info)); +} + +static struct ethtool_ops ks8695_ethtool_ops = { + .get_msglevel = ks8695_get_msglevel, + .set_msglevel = ks8695_set_msglevel, + .get_settings = ks8695_get_settings, + .set_settings = ks8695_set_settings, + .nway_reset = ks8695_nwayreset, + .get_link = ks8695_get_link, + .get_pauseparam = ks8695_get_pause, + .set_pauseparam = ks8695_set_pause, + .get_drvinfo = ks8695_get_drvinfo, +}; + +/* Network device interface functions */ + +/** + * ks8695_set_mac - Update MAC in net dev and HW + * @ndev: The network device to update + * @addr: The new MAC address to set + */ +static int +ks8695_set_mac(struct net_device *ndev, void *addr) +{ + struct ks8695_priv *ksp = netdev_priv(ndev); + struct sockaddr *address = addr; + + if (!is_valid_ether_addr(address->sa_data)) + return -EADDRNOTAVAIL; + + memcpy(ndev->dev_addr, address->sa_data, ndev->addr_len); + + ks8695_update_mac(ksp); + + dev_dbg(ksp->dev, "%s: Updated MAC address to %pM\n", + ndev->name, ndev->dev_addr); + + return 0; +} + +/** + * ks8695_set_multicast - Set up the multicast behaviour of the interface + * @ndev: The net_device to configure + * + * This routine, called by the net layer, configures promiscuity + * and multicast reception behaviour for the interface. + */ +static void +ks8695_set_multicast(struct net_device *ndev) +{ + struct ks8695_priv *ksp = netdev_priv(ndev); + u32 ctrl; + + ctrl = ks8695_readreg(ksp, KS8695_DRXC); + + if (ndev->flags & IFF_PROMISC) { + /* enable promiscuous mode */ + ctrl |= DRXC_RA; + } else if (ndev->flags & ~IFF_PROMISC) { + /* disable promiscuous mode */ + ctrl &= ~DRXC_RA; + } + + if (ndev->flags & IFF_ALLMULTI) { + /* enable all multicast mode */ + ctrl |= DRXC_RM; + } else if (ndev->mc_count > KS8695_NR_ADDRESSES) { + /* more specific multicast addresses than can be + * handled in hardware + */ + ctrl |= DRXC_RM; + } else { + /* enable specific multicasts */ + ctrl &= ~DRXC_RM; + ks8695_init_partial_multicast(ksp, ndev->mc_list, + ndev->mc_count); + } + + ks8695_writereg(ksp, KS8695_DRXC, ctrl); +} + +/** + * ks8695_timeout - Handle a network tx/rx timeout. + * @ndev: The net_device which timed out. + * + * A network transaction timed out, reset the device. + */ +static void +ks8695_timeout(struct net_device *ndev) +{ + struct ks8695_priv *ksp = netdev_priv(ndev); + + netif_stop_queue(ndev); + ks8695_shutdown(ksp); + + ks8695_reset(ksp); + + ks8695_update_mac(ksp); + + /* We ignore the return from this since it managed to init + * before it probably will be okay to init again. + */ + ks8695_init_net(ksp); + + /* Reconfigure promiscuity etc */ + ks8695_set_multicast(ndev); + + /* And start the TX queue once more */ + netif_start_queue(ndev); +} + +/** + * ks8695_start_xmit - Start a packet transmission + * @skb: The packet to transmit + * @ndev: The network device to send the packet on + * + * This routine, called by the net layer, takes ownership of the + * sk_buff and adds it to the TX ring. It then kicks the TX DMA + * engine to ensure transmission begins. + */ +static int +ks8695_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + struct ks8695_priv *ksp = netdev_priv(ndev); + int buff_n; + dma_addr_t dmap; + + spin_lock_irq(&ksp->txq_lock); + + if (ksp->tx_ring_used == MAX_TX_DESC) { + /* Somehow we got entered when we have no room */ + spin_unlock_irq(&ksp->txq_lock); + return NETDEV_TX_BUSY; + } + + buff_n = ksp->tx_ring_next_slot; + + BUG_ON(ksp->tx_buffers[buff_n].skb); + + dmap = dma_map_single(ksp->dev, skb->data, skb->len, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(ksp->dev, dmap))) { + /* Failed to DMA map this SKB, give it back for now */ + spin_unlock_irq(&ksp->txq_lock); + dev_dbg(ksp->dev, "%s: Could not map DMA memory for "\ + "transmission, trying later\n", ndev->name); + return NETDEV_TX_BUSY; + } + + ksp->tx_buffers[buff_n].dma_ptr = dmap; + /* Mapped okay, store the buffer pointer and length for later */ + ksp->tx_buffers[buff_n].skb = skb; + ksp->tx_buffers[buff_n].length = skb->len; + + /* Fill out the TX descriptor */ + ksp->tx_ring[buff_n].data_ptr = + cpu_to_le32(ksp->tx_buffers[buff_n].dma_ptr); + ksp->tx_ring[buff_n].status = + cpu_to_le32(TDES_IC | TDES_FS | TDES_LS | + (skb->len & TDES_TBS)); + + wmb(); + + /* Hand it over to the hardware */ + ksp->tx_ring[buff_n].owner = cpu_to_le32(TDES_OWN); + + if (++ksp->tx_ring_used == MAX_TX_DESC) + netif_stop_queue(ndev); + + ndev->trans_start = jiffies; + + /* Kick the TX DMA in case it decided to go IDLE */ + ks8695_writereg(ksp, KS8695_DTSC, 0); + + /* And update the next ring slot */ + ksp->tx_ring_next_slot = (buff_n + 1) & MAX_TX_DESC_MASK; + + spin_unlock_irq(&ksp->txq_lock); + return NETDEV_TX_OK; +} + +/** + * ks8695_stop - Stop (shutdown) a KS8695 ethernet interface + * @ndev: The net_device to stop + * + * This disables the TX queue and cleans up a KS8695 ethernet + * device. + */ +static int +ks8695_stop(struct net_device *ndev) +{ + struct ks8695_priv *ksp = netdev_priv(ndev); + + netif_stop_queue(ndev); + netif_carrier_off(ndev); + + ks8695_shutdown(ksp); + + return 0; +} + +/** + * ks8695_open - Open (bring up) a KS8695 ethernet interface + * @ndev: The net_device to open + * + * This resets, configures the MAC, initialises the RX ring and + * DMA engines and starts the TX queue for a KS8695 ethernet + * device. + */ +static int +ks8695_open(struct net_device *ndev) +{ + struct ks8695_priv *ksp = netdev_priv(ndev); + int ret; + + if (!is_valid_ether_addr(ndev->dev_addr)) + return -EADDRNOTAVAIL; + + ks8695_reset(ksp); + + ks8695_update_mac(ksp); + + ret = ks8695_init_net(ksp); + if (ret) { + ks8695_shutdown(ksp); + return ret; + } + + netif_start_queue(ndev); + + return 0; +} + +/* Platform device driver */ + +/** + * ks8695_init_switch - Init LAN switch to known good defaults. + * @ksp: The device to initialise + * + * This initialises the LAN switch in the KS8695 to a known-good + * set of defaults. + */ +static void __devinit +ks8695_init_switch(struct ks8695_priv *ksp) +{ + u32 ctrl; + + /* Default value for SEC0 according to datasheet */ + ctrl = 0x40819e00; + + /* LED0 = Speed LED1 = Link/Activity */ + ctrl &= ~(SEC0_LLED1S | SEC0_LLED0S); + ctrl |= (LLED0S_LINK | LLED1S_LINK_ACTIVITY); + + /* Enable Switch */ + ctrl |= SEC0_ENABLE; + + writel(ctrl, ksp->phyiface_regs + KS8695_SEC0); + + /* Defaults for SEC1 */ + writel(0x9400100, ksp->phyiface_regs + KS8695_SEC1); +} + +/** + * ks8695_init_wan_phy - Initialise the WAN PHY to sensible defaults + * @ksp: The device to initialise + * + * This initialises a KS8695's WAN phy to sensible values for + * autonegotiation etc. + */ +static void __devinit +ks8695_init_wan_phy(struct ks8695_priv *ksp) +{ + u32 ctrl; + + /* Support auto-negotiation */ + ctrl = (WMC_WANAP | WMC_WANA100F | WMC_WANA100H | + WMC_WANA10F | WMC_WANA10H); + + /* LED0 = Activity , LED1 = Link */ + ctrl |= (WLED0S_ACTIVITY | WLED1S_LINK); + + /* Restart Auto-negotiation */ + ctrl |= WMC_WANR; + + writel(ctrl, ksp->phyiface_regs + KS8695_WMC); + + writel(0, ksp->phyiface_regs + KS8695_WPPM); + writel(0, ksp->phyiface_regs + KS8695_PPS); +} + +static const struct net_device_ops ks8695_netdev_ops = { + .ndo_open = ks8695_open, + .ndo_stop = ks8695_stop, + .ndo_start_xmit = ks8695_start_xmit, + .ndo_tx_timeout = ks8695_timeout, + .ndo_set_mac_address = ks8695_set_mac, + .ndo_set_multicast_list = ks8695_set_multicast, +}; + +/** + * ks8695_probe - Probe and initialise a KS8695 ethernet interface + * @pdev: The platform device to probe + * + * Initialise a KS8695 ethernet device from platform data. + * + * This driver requires at least one IORESOURCE_MEM for the + * registers and two IORESOURCE_IRQ for the RX and TX IRQs + * respectively. It can optionally take an additional + * IORESOURCE_MEM for the switch or phy in the case of the lan or + * wan ports, and an IORESOURCE_IRQ for the link IRQ for the wan + * port. + */ +static int __devinit +ks8695_probe(struct platform_device *pdev) +{ + struct ks8695_priv *ksp; + struct net_device *ndev; + struct resource *regs_res, *phyiface_res; + struct resource *rxirq_res, *txirq_res, *linkirq_res; + int ret = 0; + int buff_n; + u32 machigh, maclow; + + /* Initialise a net_device */ + ndev = alloc_etherdev(sizeof(struct ks8695_priv)); + if (!ndev) { + dev_err(&pdev->dev, "could not allocate device.\n"); + return -ENOMEM; + } + + SET_NETDEV_DEV(ndev, &pdev->dev); + + dev_dbg(&pdev->dev, "ks8695_probe() called\n"); + + /* Configure our private structure a little */ + ksp = netdev_priv(ndev); + memset(ksp, 0, sizeof(struct ks8695_priv)); + + ksp->dev = &pdev->dev; + ksp->ndev = ndev; + ksp->msg_enable = NETIF_MSG_LINK; + + /* Retrieve resources */ + regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + phyiface_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + + rxirq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + txirq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 1); + linkirq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 2); + + if (!(regs_res && rxirq_res && txirq_res)) { + dev_err(ksp->dev, "insufficient resources\n"); + ret = -ENOENT; + goto failure; + } + + ksp->regs_req = request_mem_region(regs_res->start, + resource_size(regs_res), + pdev->name); + + if (!ksp->regs_req) { + dev_err(ksp->dev, "cannot claim register space\n"); + ret = -EIO; + goto failure; + } + + ksp->io_regs = ioremap(regs_res->start, resource_size(regs_res)); + + if (!ksp->io_regs) { + dev_err(ksp->dev, "failed to ioremap registers\n"); + ret = -EINVAL; + goto failure; + } + + if (phyiface_res) { + ksp->phyiface_req = + request_mem_region(phyiface_res->start, + resource_size(phyiface_res), + phyiface_res->name); + + if (!ksp->phyiface_req) { + dev_err(ksp->dev, + "cannot claim switch register space\n"); + ret = -EIO; + goto failure; + } + + ksp->phyiface_regs = ioremap(phyiface_res->start, + resource_size(phyiface_res)); + + if (!ksp->phyiface_regs) { + dev_err(ksp->dev, + "failed to ioremap switch registers\n"); + ret = -EINVAL; + goto failure; + } + } + + ksp->rx_irq = rxirq_res->start; + ksp->rx_irq_name = rxirq_res->name ? rxirq_res->name : "Ethernet RX"; + ksp->tx_irq = txirq_res->start; + ksp->tx_irq_name = txirq_res->name ? txirq_res->name : "Ethernet TX"; + ksp->link_irq = (linkirq_res ? linkirq_res->start : -1); + ksp->link_irq_name = (linkirq_res && linkirq_res->name) ? + linkirq_res->name : "Ethernet Link"; + + /* driver system setup */ + ndev->netdev_ops = &ks8695_netdev_ops; + SET_ETHTOOL_OPS(ndev, &ks8695_ethtool_ops); + ndev->watchdog_timeo = msecs_to_jiffies(watchdog); + + /* Retrieve the default MAC addr from the chip. */ + /* The bootloader should have left it in there for us. */ + + machigh = ks8695_readreg(ksp, KS8695_MAH); + maclow = ks8695_readreg(ksp, KS8695_MAL); + + ndev->dev_addr[0] = (machigh >> 8) & 0xFF; + ndev->dev_addr[1] = machigh & 0xFF; + ndev->dev_addr[2] = (maclow >> 24) & 0xFF; + ndev->dev_addr[3] = (maclow >> 16) & 0xFF; + ndev->dev_addr[4] = (maclow >> 8) & 0xFF; + ndev->dev_addr[5] = maclow & 0xFF; + + if (!is_valid_ether_addr(ndev->dev_addr)) + dev_warn(ksp->dev, "%s: Invalid ethernet MAC address. Please " + "set using ifconfig\n", ndev->name); + + /* In order to be efficient memory-wise, we allocate both + * rings in one go. + */ + ksp->ring_base = dma_alloc_coherent(&pdev->dev, RING_DMA_SIZE, + &ksp->ring_base_dma, GFP_KERNEL); + if (!ksp->ring_base) { + ret = -ENOMEM; + goto failure; + } + + /* Specify the TX DMA ring buffer */ + ksp->tx_ring = ksp->ring_base; + ksp->tx_ring_dma = ksp->ring_base_dma; + + /* And initialise the queue's lock */ + spin_lock_init(&ksp->txq_lock); + + /* Specify the RX DMA ring buffer */ + ksp->rx_ring = ksp->ring_base + TX_RING_DMA_SIZE; + ksp->rx_ring_dma = ksp->ring_base_dma + TX_RING_DMA_SIZE; + + /* Zero the descriptor rings */ + memset(ksp->tx_ring, 0, TX_RING_DMA_SIZE); + memset(ksp->rx_ring, 0, RX_RING_DMA_SIZE); + + /* Build the rings */ + for (buff_n = 0; buff_n < MAX_TX_DESC; ++buff_n) { + ksp->tx_ring[buff_n].next_desc = + cpu_to_le32(ksp->tx_ring_dma + + (sizeof(struct tx_ring_desc) * + ((buff_n + 1) & MAX_TX_DESC_MASK))); + } + + for (buff_n = 0; buff_n < MAX_RX_DESC; ++buff_n) { + ksp->rx_ring[buff_n].next_desc = + cpu_to_le32(ksp->rx_ring_dma + + (sizeof(struct rx_ring_desc) * + ((buff_n + 1) & MAX_RX_DESC_MASK))); + } + + /* Initialise the port (physically) */ + if (ksp->phyiface_regs && ksp->link_irq == -1) { + ks8695_init_switch(ksp); + ksp->dtype = KS8695_DTYPE_LAN; + } else if (ksp->phyiface_regs && ksp->link_irq != -1) { + ks8695_init_wan_phy(ksp); + ksp->dtype = KS8695_DTYPE_WAN; + } else { + /* No initialisation since HPNA does not have a PHY */ + ksp->dtype = KS8695_DTYPE_HPNA; + } + + /* And bring up the net_device with the net core */ + platform_set_drvdata(pdev, ndev); + ret = register_netdev(ndev); + + if (ret == 0) { + dev_info(ksp->dev, "ks8695 ethernet (%s) MAC: %pM\n", + ks8695_port_type(ksp), ndev->dev_addr); + } else { + /* Report the failure to register the net_device */ + dev_err(ksp->dev, "ks8695net: failed to register netdev.\n"); + goto failure; + } + + /* All is well */ + return 0; + + /* Error exit path */ +failure: + ks8695_release_device(ksp); + free_netdev(ndev); + + return ret; +} + +/** + * ks8695_drv_suspend - Suspend a KS8695 ethernet platform device. + * @pdev: The device to suspend + * @state: The suspend state + * + * This routine detaches and shuts down a KS8695 ethernet device. + */ +static int +ks8695_drv_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct net_device *ndev = platform_get_drvdata(pdev); + struct ks8695_priv *ksp = netdev_priv(ndev); + + ksp->in_suspend = 1; + + if (netif_running(ndev)) { + netif_device_detach(ndev); + ks8695_shutdown(ksp); + } + + return 0; +} + +/** + * ks8695_drv_resume - Resume a KS8695 ethernet platform device. + * @pdev: The device to resume + * + * This routine re-initialises and re-attaches a KS8695 ethernet + * device. + */ +static int +ks8695_drv_resume(struct platform_device *pdev) +{ + struct net_device *ndev = platform_get_drvdata(pdev); + struct ks8695_priv *ksp = netdev_priv(ndev); + + if (netif_running(ndev)) { + ks8695_reset(ksp); + ks8695_init_net(ksp); + ks8695_set_multicast(ndev); + netif_device_attach(ndev); + } + + ksp->in_suspend = 0; + + return 0; +} + +/** + * ks8695_drv_remove - Remove a KS8695 net device on driver unload. + * @pdev: The platform device to remove + * + * This unregisters and releases a KS8695 ethernet device. + */ +static int __devexit +ks8695_drv_remove(struct platform_device *pdev) +{ + struct net_device *ndev = platform_get_drvdata(pdev); + struct ks8695_priv *ksp = netdev_priv(ndev); + + platform_set_drvdata(pdev, NULL); + + unregister_netdev(ndev); + ks8695_release_device(ksp); + free_netdev(ndev); + + dev_dbg(&pdev->dev, "released and freed device\n"); + return 0; +} + +static struct platform_driver ks8695_driver = { + .driver = { + .name = MODULENAME, + .owner = THIS_MODULE, + }, + .probe = ks8695_probe, + .remove = __devexit_p(ks8695_drv_remove), + .suspend = ks8695_drv_suspend, + .resume = ks8695_drv_resume, +}; + +/* Module interface */ + +static int __init +ks8695_init(void) +{ + printk(KERN_INFO "%s Ethernet driver, V%s\n", + MODULENAME, MODULEVERSION); + + return platform_driver_register(&ks8695_driver); +} + +static void __exit +ks8695_cleanup(void) +{ + platform_driver_unregister(&ks8695_driver); +} + +module_init(ks8695_init); +module_exit(ks8695_cleanup); + +MODULE_AUTHOR("Simtec Electronics") +MODULE_DESCRIPTION("Micrel KS8695 (Centaur) Ethernet driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" MODULENAME); + +module_param(watchdog, int, 0400); +MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds"); diff --git a/drivers/net/arm/ks8695net.h b/drivers/net/arm/ks8695net.h new file mode 100644 index 0000000000000000000000000000000000000000..80eff6ea51631a88097f86a0e71413e9e8ff012d --- /dev/null +++ b/drivers/net/arm/ks8695net.h @@ -0,0 +1,107 @@ +/* + * Micrel KS8695 (Centaur) Ethernet. + * + * Copyright 2008 Simtec Electronics + * Daniel Silverstone + * Vincent Sanders + */ + +#ifndef KS8695NET_H +#define KS8695NET_H + +/* Receive descriptor flags */ +#define RDES_OWN (1 << 31) /* Ownership */ +#define RDES_FS (1 << 30) /* First Descriptor */ +#define RDES_LS (1 << 29) /* Last Descriptor */ +#define RDES_IPE (1 << 28) /* IP Checksum error */ +#define RDES_TCPE (1 << 27) /* TCP Checksum error */ +#define RDES_UDPE (1 << 26) /* UDP Checksum error */ +#define RDES_ES (1 << 25) /* Error summary */ +#define RDES_MF (1 << 24) /* Multicast Frame */ +#define RDES_RE (1 << 19) /* MII Error reported */ +#define RDES_TL (1 << 18) /* Frame too Long */ +#define RDES_RF (1 << 17) /* Runt Frame */ +#define RDES_CE (1 << 16) /* CRC error */ +#define RDES_FT (1 << 15) /* Frame Type */ +#define RDES_FLEN (0x7ff) /* Frame Length */ + +#define RDES_RER (1 << 25) /* Receive End of Ring */ +#define RDES_RBS (0x7ff) /* Receive Buffer Size */ + +/* Transmit descriptor flags */ + +#define TDES_OWN (1 << 31) /* Ownership */ + +#define TDES_IC (1 << 31) /* Interrupt on Completion */ +#define TDES_FS (1 << 30) /* First Segment */ +#define TDES_LS (1 << 29) /* Last Segment */ +#define TDES_IPCKG (1 << 28) /* IP Checksum generate */ +#define TDES_TCPCKG (1 << 27) /* TCP Checksum generate */ +#define TDES_UDPCKG (1 << 26) /* UDP Checksum generate */ +#define TDES_TER (1 << 25) /* Transmit End of Ring */ +#define TDES_TBS (0x7ff) /* Transmit Buffer Size */ + +/* + * Network controller register offsets + */ +#define KS8695_DTXC (0x00) /* DMA Transmit Control */ +#define KS8695_DRXC (0x04) /* DMA Receive Control */ +#define KS8695_DTSC (0x08) /* DMA Transmit Start Command */ +#define KS8695_DRSC (0x0c) /* DMA Receive Start Command */ +#define KS8695_TDLB (0x10) /* Transmit Descriptor List + * Base Address + */ +#define KS8695_RDLB (0x14) /* Receive Descriptor List + * Base Address + */ +#define KS8695_MAL (0x18) /* MAC Station Address Low */ +#define KS8695_MAH (0x1c) /* MAC Station Address High */ +#define KS8695_AAL_(n) (0x80 + ((n)*8)) /* MAC Additional + * Station Address + * (0..15) Low + */ +#define KS8695_AAH_(n) (0x84 + ((n)*8)) /* MAC Additional + * Station Address + * (0..15) High + */ + + +/* DMA Transmit Control Register */ +#define DTXC_TRST (1 << 31) /* Soft Reset */ +#define DTXC_TBS (0x3f << 24) /* Transmit Burst Size */ +#define DTXC_TUCG (1 << 18) /* Transmit UDP + * Checksum Generate + */ +#define DTXC_TTCG (1 << 17) /* Transmit TCP + * Checksum Generate + */ +#define DTXC_TICG (1 << 16) /* Transmit IP + * Checksum Generate + */ +#define DTXC_TFCE (1 << 9) /* Transmit Flow + * Control Enable + */ +#define DTXC_TLB (1 << 8) /* Loopback mode */ +#define DTXC_TEP (1 << 2) /* Transmit Enable Padding */ +#define DTXC_TAC (1 << 1) /* Transmit Add CRC */ +#define DTXC_TE (1 << 0) /* TX Enable */ + +/* DMA Receive Control Register */ +#define DRXC_RBS (0x3f << 24) /* Receive Burst Size */ +#define DRXC_RUCC (1 << 18) /* Receive UDP Checksum check */ +#define DRXC_RTCG (1 << 17) /* Receive TCP Checksum check */ +#define DRXC_RICG (1 << 16) /* Receive IP Checksum check */ +#define DRXC_RFCE (1 << 9) /* Receive Flow Control + * Enable + */ +#define DRXC_RB (1 << 6) /* Receive Broadcast */ +#define DRXC_RM (1 << 5) /* Receive Multicast */ +#define DRXC_RU (1 << 4) /* Receive Unicast */ +#define DRXC_RERR (1 << 3) /* Receive Error Frame */ +#define DRXC_RA (1 << 2) /* Receive All */ +#define DRXC_RE (1 << 0) /* RX Enable */ + +/* Additional Station Address High */ +#define AAH_E (1 << 31) /* Address Enabled */ + +#endif /* KS8695NET_H */ diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c index 7e874d485d24a36fbab6aee652eaf44c6cf72e78..72ea6e378f8dda5dec528cdad250c23cd6ce6677 100644 --- a/drivers/net/at1700.c +++ b/drivers/net/at1700.c @@ -265,7 +265,6 @@ static int __init at1700_probe1(struct net_device *dev, int ioaddr) unsigned int i, irq, is_fmv18x = 0, is_at1700 = 0; int slot, ret = -ENODEV; struct net_local *lp = netdev_priv(dev); - DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, AT1700_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -397,7 +396,7 @@ static int __init at1700_probe1(struct net_device *dev, int ioaddr) dev->dev_addr[i] = val; } } - printk("%s", print_mac(mac, dev->dev_addr)); + printk("%pM", dev->dev_addr); /* The EEPROM word 12 bit 0x0400 means use regular 100 ohm 10baseT signals, rather than 150 ohm shielded twisted pair compensation. @@ -768,7 +767,6 @@ net_rx(struct net_device *dev) insw(ioaddr + DATAPORT, skb_put(skb,pkt_len), (pkt_len + 1) >> 1); skb->protocol=eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } @@ -901,15 +899,3 @@ module_init(at1700_module_init); module_exit(at1700_module_exit); #endif /* MODULE */ MODULE_LICENSE("GPL"); - - -/* - * Local variables: - * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c at1700.c" - * alt-compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c at1700.c" - * tab-width: 4 - * c-basic-offset: 4 - * c-indent-level: 4 - * End: - */ - diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c index 0860cc280b019c230e969c5b7efaac96ae4101f2..2d81f6afcb589075009d6e45bc0db9dcd4b40c00 100644 --- a/drivers/net/atarilance.c +++ b/drivers/net/atarilance.c @@ -466,7 +466,6 @@ static unsigned long __init lance_probe1( struct net_device *dev, int i; static int did_version; unsigned short save1, save2; - DECLARE_MAC_BUF(mac); PROBE_PRINT(( "Probing for Lance card at mem %#lx io %#lx\n", (long)memaddr, (long)ioaddr )); @@ -521,7 +520,7 @@ static unsigned long __init lance_probe1( struct net_device *dev, return( 0 ); probe_ok: - lp = (struct lance_private *)dev->priv; + lp = netdev_priv(dev); MEM = (struct lance_memory *)memaddr; IO = lp->iobase = (struct lance_ioreg *)ioaddr; dev->base_addr = (unsigned long)ioaddr; /* informational only */ @@ -595,7 +594,7 @@ static unsigned long __init lance_probe1( struct net_device *dev, i = IO->mem; break; } - printk("%s\n", print_mac(mac, dev->dev_addr)); + printk("%pM\n", dev->dev_addr); if (lp->cardtype == OLD_RIEBL) { printk( "%s: Warning: This is a default ethernet address!\n", dev->name ); @@ -640,8 +639,8 @@ static unsigned long __init lance_probe1( struct net_device *dev, static int lance_open( struct net_device *dev ) - -{ struct lance_private *lp = (struct lance_private *)dev->priv; +{ + struct lance_private *lp = netdev_priv(dev); struct lance_ioreg *IO = lp->iobase; int i; @@ -681,8 +680,8 @@ static int lance_open( struct net_device *dev ) /* Initialize the LANCE Rx and Tx rings. */ static void lance_init_ring( struct net_device *dev ) - -{ struct lance_private *lp = (struct lance_private *)dev->priv; +{ + struct lance_private *lp = netdev_priv(dev); int i; unsigned offset; @@ -730,7 +729,7 @@ static void lance_init_ring( struct net_device *dev ) static void lance_tx_timeout (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); struct lance_ioreg *IO = lp->iobase; AREG = CSR0; @@ -772,14 +771,12 @@ static void lance_tx_timeout (struct net_device *dev) /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) - -{ struct lance_private *lp = (struct lance_private *)dev->priv; +{ + struct lance_private *lp = netdev_priv(dev); struct lance_ioreg *IO = lp->iobase; int entry, len; struct lance_tx_head *head; unsigned long flags; - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); DPRINTK( 2, ( "%s: lance_start_xmit() called, csr0 %4.4x.\n", dev->name, DREG )); @@ -802,12 +799,10 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) /* Fill in a Tx ring entry */ if (lance_debug >= 3) { - printk( "%s: TX pkt type 0x%04x from " - "%s to %s" + printk( "%s: TX pkt type 0x%04x from %pM to %pM" " data at 0x%08x len %d\n", dev->name, ((u_short *)skb->data)[6], - print_mac(mac, &skb->data[6]), - print_mac(mac2, skb->data), + &skb->data[6], skb->data, (int)skb->data, (int)skb->len ); } @@ -865,7 +860,7 @@ static irqreturn_t lance_interrupt( int irq, void *dev_id ) return IRQ_NONE; } - lp = (struct lance_private *)dev->priv; + lp = netdev_priv(dev); IO = lp->iobase; spin_lock (&lp->devlock); @@ -965,8 +960,8 @@ static irqreturn_t lance_interrupt( int irq, void *dev_id ) static int lance_rx( struct net_device *dev ) - -{ struct lance_private *lp = (struct lance_private *)dev->priv; +{ + struct lance_private *lp = netdev_priv(dev); int entry = lp->cur_rx & RX_RING_MOD_MASK; int i; @@ -1019,14 +1014,12 @@ static int lance_rx( struct net_device *dev ) if (lance_debug >= 3) { u_char *data = PKTBUF_ADDR(head); - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); - printk(KERN_DEBUG "%s: RX pkt type 0x%04x from %s to %s " + printk(KERN_DEBUG "%s: RX pkt type 0x%04x from %pM to %pM " "data %02x %02x %02x %02x %02x %02x %02x %02x " "len %d\n", dev->name, ((u_short *)data)[6], - print_mac(mac, &data[6]), print_mac(mac2, data), + &data[6], data, data[15], data[16], data[17], data[18], data[19], data[20], data[21], data[22], pkt_len); @@ -1037,7 +1030,6 @@ static int lance_rx( struct net_device *dev ) lp->memcpy_f( skb->data, PKTBUF_ADDR(head), pkt_len ); skb->protocol = eth_type_trans( skb, dev ); netif_rx( skb ); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } @@ -1057,8 +1049,8 @@ static int lance_rx( struct net_device *dev ) static int lance_close( struct net_device *dev ) - -{ struct lance_private *lp = (struct lance_private *)dev->priv; +{ + struct lance_private *lp = netdev_priv(dev); struct lance_ioreg *IO = lp->iobase; netif_stop_queue (dev); @@ -1084,8 +1076,8 @@ static int lance_close( struct net_device *dev ) */ static void set_multicast_list( struct net_device *dev ) - -{ struct lance_private *lp = (struct lance_private *)dev->priv; +{ + struct lance_private *lp = netdev_priv(dev); struct lance_ioreg *IO = lp->iobase; if (netif_running(dev)) @@ -1126,8 +1118,8 @@ static void set_multicast_list( struct net_device *dev ) /* This is needed for old RieblCards and possible for new RieblCards */ static int lance_set_mac_address( struct net_device *dev, void *addr ) - -{ struct lance_private *lp = (struct lance_private *)dev->priv; +{ + struct lance_private *lp = netdev_priv(dev); struct sockaddr *saddr = addr; int i; diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c index 9b603528143d6dcee4da35059d74a7a0e8902964..bb9094d4cbc9014f2686033162cfde22fcc0d972 100644 --- a/drivers/net/atl1e/atl1e_main.c +++ b/drivers/net/atl1e/atl1e_main.c @@ -1326,9 +1326,9 @@ static irqreturn_t atl1e_intr(int irq, void *data) AT_WRITE_REG(hw, REG_IMR, IMR_NORMAL_MASK & ~ISR_RX_EVENT); AT_WRITE_FLUSH(hw); - if (likely(netif_rx_schedule_prep(netdev, + if (likely(netif_rx_schedule_prep( &adapter->napi))) - __netif_rx_schedule(netdev, &adapter->napi); + __netif_rx_schedule(&adapter->napi); } } while (--max_ints > 0); /* re-enable Interrupt*/ @@ -1460,7 +1460,6 @@ static void atl1e_clean_rx_irq(struct atl1e_adapter *adapter, u8 que, netif_receive_skb(skb); } - netdev->last_rx = jiffies; skip_pkt: /* skip current packet whether it's ok or not. */ rx_page->read_offset += @@ -1502,7 +1501,6 @@ static int atl1e_clean(struct napi_struct *napi, int budget) { struct atl1e_adapter *adapter = container_of(napi, struct atl1e_adapter, napi); - struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; u32 imr_data; int work_done = 0; @@ -1516,7 +1514,7 @@ static int atl1e_clean(struct napi_struct *napi, int budget) /* If no Tx and not enough Rx work done, exit the polling mode */ if (work_done < budget) { quit_polling: - netif_rx_complete(netdev, napi); + netif_rx_complete(napi); imr_data = AT_READ_REG(&adapter->hw, REG_IMR); AT_WRITE_REG(&adapter->hw, REG_IMR, imr_data | ISR_RX_EVENT); /* test debug */ @@ -2254,26 +2252,33 @@ static void atl1e_shutdown(struct pci_dev *pdev) atl1e_suspend(pdev, PMSG_SUSPEND); } +static const struct net_device_ops atl1e_netdev_ops = { + .ndo_open = atl1e_open, + .ndo_stop = atl1e_close, + .ndo_start_xmit = atl1e_xmit_frame, + .ndo_get_stats = atl1e_get_stats, + .ndo_set_multicast_list = atl1e_set_multi, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = atl1e_set_mac_addr, + .ndo_change_mtu = atl1e_change_mtu, + .ndo_do_ioctl = atl1e_ioctl, + .ndo_tx_timeout = atl1e_tx_timeout, + .ndo_vlan_rx_register = atl1e_vlan_rx_register, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = atl1e_netpoll, +#endif + +}; + static int atl1e_init_netdev(struct net_device *netdev, struct pci_dev *pdev) { SET_NETDEV_DEV(netdev, &pdev->dev); pci_set_drvdata(pdev, netdev); netdev->irq = pdev->irq; - netdev->open = &atl1e_open; - netdev->stop = &atl1e_close; - netdev->hard_start_xmit = &atl1e_xmit_frame; - netdev->get_stats = &atl1e_get_stats; - netdev->set_multicast_list = &atl1e_set_multi; - netdev->set_mac_address = &atl1e_set_mac_addr; - netdev->change_mtu = &atl1e_change_mtu; - netdev->do_ioctl = &atl1e_ioctl; - netdev->tx_timeout = &atl1e_tx_timeout; + netdev->netdev_ops = &atl1e_netdev_ops; + netdev->watchdog_timeo = AT_TX_WATCHDOG; - netdev->vlan_rx_register = atl1e_vlan_rx_register; -#ifdef CONFIG_NET_POLL_CONTROLLER - netdev->poll_controller = atl1e_netpoll; -#endif atl1e_set_ethtool_ops(netdev); netdev->features = NETIF_F_SG | NETIF_F_HW_CSUM | @@ -2488,7 +2493,7 @@ static pci_ers_result_t atl1e_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state) { struct net_device *netdev = pci_get_drvdata(pdev); - struct atl1e_adapter *adapter = netdev->priv; + struct atl1e_adapter *adapter = netdev_priv(netdev); netif_device_detach(netdev); @@ -2511,7 +2516,7 @@ atl1e_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state) static pci_ers_result_t atl1e_io_slot_reset(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); - struct atl1e_adapter *adapter = netdev->priv; + struct atl1e_adapter *adapter = netdev_priv(netdev); if (pci_enable_device(pdev)) { dev_err(&pdev->dev, @@ -2539,7 +2544,7 @@ static pci_ers_result_t atl1e_io_slot_reset(struct pci_dev *pdev) static void atl1e_io_resume(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); - struct atl1e_adapter *adapter = netdev->priv; + struct atl1e_adapter *adapter = netdev_priv(netdev); if (netif_running(netdev)) { if (atl1e_up(adapter)) { diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index aef403d299eef1a5b04a4218070c0e51594fa288..c0ceee0d7c808ed4f4df1fdb12806239b37dad63 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -195,7 +195,7 @@ static int __devinit atl1_validate_option(int *value, struct atl1_option *opt, * value exists, a default value is used. The final value is stored * in a variable in the adapter structure. */ -void __devinit atl1_check_options(struct atl1_adapter *adapter) +static void __devinit atl1_check_options(struct atl1_adapter *adapter) { struct pci_dev *pdev = adapter->pdev; int bd = adapter->bd_number; @@ -523,7 +523,7 @@ static int atl1_get_permanent_address(struct atl1_hw *hw) * Reads the adapter's MAC address from the EEPROM * hw - Struct containing variables accessed by shared code */ -s32 atl1_read_mac_addr(struct atl1_hw *hw) +static s32 atl1_read_mac_addr(struct atl1_hw *hw) { u16 i; @@ -1390,7 +1390,8 @@ static u32 atl1_check_link(struct atl1_adapter *adapter) /* auto-neg, insert timer to re-config phy */ if (!adapter->phy_timer_pending) { adapter->phy_timer_pending = true; - mod_timer(&adapter->phy_config_timer, jiffies + 3 * HZ); + mod_timer(&adapter->phy_config_timer, + round_jiffies(jiffies + 3 * HZ)); } return 0; @@ -1662,6 +1663,7 @@ static void atl1_via_workaround(struct atl1_adapter *adapter) static void atl1_inc_smb(struct atl1_adapter *adapter) { + struct net_device *netdev = adapter->netdev; struct stats_msg_block *smb = adapter->smb.smb; /* Fill out the OS statistics structure */ @@ -1704,30 +1706,30 @@ static void atl1_inc_smb(struct atl1_adapter *adapter) adapter->soft_stats.tx_trunc += smb->tx_trunc; adapter->soft_stats.tx_pause += smb->tx_pause; - adapter->net_stats.rx_packets = adapter->soft_stats.rx_packets; - adapter->net_stats.tx_packets = adapter->soft_stats.tx_packets; - adapter->net_stats.rx_bytes = adapter->soft_stats.rx_bytes; - adapter->net_stats.tx_bytes = adapter->soft_stats.tx_bytes; - adapter->net_stats.multicast = adapter->soft_stats.multicast; - adapter->net_stats.collisions = adapter->soft_stats.collisions; - adapter->net_stats.rx_errors = adapter->soft_stats.rx_errors; - adapter->net_stats.rx_over_errors = + netdev->stats.rx_packets = adapter->soft_stats.rx_packets; + netdev->stats.tx_packets = adapter->soft_stats.tx_packets; + netdev->stats.rx_bytes = adapter->soft_stats.rx_bytes; + netdev->stats.tx_bytes = adapter->soft_stats.tx_bytes; + netdev->stats.multicast = adapter->soft_stats.multicast; + netdev->stats.collisions = adapter->soft_stats.collisions; + netdev->stats.rx_errors = adapter->soft_stats.rx_errors; + netdev->stats.rx_over_errors = adapter->soft_stats.rx_missed_errors; - adapter->net_stats.rx_length_errors = + netdev->stats.rx_length_errors = adapter->soft_stats.rx_length_errors; - adapter->net_stats.rx_crc_errors = adapter->soft_stats.rx_crc_errors; - adapter->net_stats.rx_frame_errors = + netdev->stats.rx_crc_errors = adapter->soft_stats.rx_crc_errors; + netdev->stats.rx_frame_errors = adapter->soft_stats.rx_frame_errors; - adapter->net_stats.rx_fifo_errors = adapter->soft_stats.rx_fifo_errors; - adapter->net_stats.rx_missed_errors = + netdev->stats.rx_fifo_errors = adapter->soft_stats.rx_fifo_errors; + netdev->stats.rx_missed_errors = adapter->soft_stats.rx_missed_errors; - adapter->net_stats.tx_errors = adapter->soft_stats.tx_errors; - adapter->net_stats.tx_fifo_errors = adapter->soft_stats.tx_fifo_errors; - adapter->net_stats.tx_aborted_errors = + netdev->stats.tx_errors = adapter->soft_stats.tx_errors; + netdev->stats.tx_fifo_errors = adapter->soft_stats.tx_fifo_errors; + netdev->stats.tx_aborted_errors = adapter->soft_stats.tx_aborted_errors; - adapter->net_stats.tx_window_errors = + netdev->stats.tx_window_errors = adapter->soft_stats.tx_window_errors; - adapter->net_stats.tx_carrier_errors = + netdev->stats.tx_carrier_errors = adapter->soft_stats.tx_carrier_errors; } @@ -1860,7 +1862,7 @@ static u16 atl1_alloc_rx_buffers(struct atl1_adapter *adapter) adapter->rx_buffer_len + NET_IP_ALIGN); if (unlikely(!skb)) { /* Better luck next round */ - adapter->net_stats.rx_dropped++; + adapter->netdev->stats.rx_dropped++; break; } @@ -2026,8 +2028,6 @@ static void atl1_intr_rx(struct atl1_adapter *adapter) buffer_info->skb = NULL; buffer_info->alloced = 0; rrd->xsz.valid = 0; - - adapter->netdev->last_rx = jiffies; } atomic_set(&rrd_ring->next_to_clean, rrd_next_to_clean); @@ -2524,17 +2524,6 @@ static irqreturn_t atl1_intr(int irq, void *data) return IRQ_HANDLED; } -/* - * atl1_watchdog - Timer Call-back - * @data: pointer to netdev cast into an unsigned long - */ -static void atl1_watchdog(unsigned long data) -{ - struct atl1_adapter *adapter = (struct atl1_adapter *)data; - - /* Reset the timer */ - mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ); -} /* * atl1_phy_config - Timer Call-back @@ -2607,7 +2596,6 @@ static s32 atl1_up(struct atl1_adapter *adapter) if (unlikely(err)) goto err_up; - mod_timer(&adapter->watchdog_timer, jiffies); atlx_irq_enable(adapter); atl1_check_link(adapter); netif_start_queue(netdev); @@ -2625,7 +2613,6 @@ static void atl1_down(struct atl1_adapter *adapter) struct net_device *netdev = adapter->netdev; netif_stop_queue(netdev); - del_timer_sync(&adapter->watchdog_timer); del_timer_sync(&adapter->phy_config_timer); adapter->phy_timer_pending = false; @@ -2893,6 +2880,22 @@ static void atl1_poll_controller(struct net_device *netdev) } #endif +static const struct net_device_ops atl1_netdev_ops = { + .ndo_open = atl1_open, + .ndo_stop = atl1_close, + .ndo_start_xmit = atl1_xmit_frame, + .ndo_set_multicast_list = atlx_set_multi, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = atl1_set_mac, + .ndo_change_mtu = atl1_change_mtu, + .ndo_do_ioctl = atlx_ioctl, + .ndo_tx_timeout = atlx_tx_timeout, + .ndo_vlan_rx_register = atlx_vlan_rx_register, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = atl1_poll_controller, +#endif +}; + /* * atl1_probe - Device Initialization Routine * @pdev: PCI device information struct @@ -2980,20 +2983,8 @@ static int __devinit atl1_probe(struct pci_dev *pdev, adapter->mii.phy_id_mask = 0x1f; adapter->mii.reg_num_mask = 0x1f; - netdev->open = &atl1_open; - netdev->stop = &atl1_close; - netdev->hard_start_xmit = &atl1_xmit_frame; - netdev->get_stats = &atlx_get_stats; - netdev->set_multicast_list = &atlx_set_multi; - netdev->set_mac_address = &atl1_set_mac; - netdev->change_mtu = &atl1_change_mtu; - netdev->do_ioctl = &atlx_ioctl; - netdev->tx_timeout = &atlx_tx_timeout; + netdev->netdev_ops = &atl1_netdev_ops; netdev->watchdog_timeo = 5 * HZ; -#ifdef CONFIG_NET_POLL_CONTROLLER - netdev->poll_controller = atl1_poll_controller; -#endif - netdev->vlan_rx_register = atlx_vlan_rx_register; netdev->ethtool_ops = &atl1_ethtool_ops; adapter->bd_number = cards_found; @@ -3049,13 +3040,8 @@ static int __devinit atl1_probe(struct pci_dev *pdev, netif_carrier_off(netdev); netif_stop_queue(netdev); - init_timer(&adapter->watchdog_timer); - adapter->watchdog_timer.function = &atl1_watchdog; - adapter->watchdog_timer.data = (unsigned long)adapter; - - init_timer(&adapter->phy_config_timer); - adapter->phy_config_timer.function = &atl1_phy_config; - adapter->phy_config_timer.data = (unsigned long)adapter; + setup_timer(&adapter->phy_config_timer, &atl1_phy_config, + (unsigned long)adapter); adapter->phy_timer_pending = false; INIT_WORK(&adapter->tx_timeout_task, atl1_tx_timeout_task); @@ -3173,8 +3159,6 @@ static struct atl1_stats atl1_gstrings_stats[] = { {"tx_bytes", ATL1_STAT(soft_stats.tx_bytes)}, {"rx_errors", ATL1_STAT(soft_stats.rx_errors)}, {"tx_errors", ATL1_STAT(soft_stats.tx_errors)}, - {"rx_dropped", ATL1_STAT(net_stats.rx_dropped)}, - {"tx_dropped", ATL1_STAT(net_stats.tx_dropped)}, {"multicast", ATL1_STAT(soft_stats.multicast)}, {"collisions", ATL1_STAT(soft_stats.collisions)}, {"rx_length_errors", ATL1_STAT(soft_stats.rx_length_errors)}, diff --git a/drivers/net/atlx/atl1.h b/drivers/net/atlx/atl1.h index ffa73fc8d95e6eca471ee18ec73986653bb492b3..146372fd66832843996b05216dd70d1e1d612c85 100644 --- a/drivers/net/atlx/atl1.h +++ b/drivers/net/atlx/atl1.h @@ -754,7 +754,7 @@ struct atl1_hw { struct atl1_adapter { struct net_device *netdev; struct pci_dev *pdev; - struct net_device_stats net_stats; + struct atl1_sft_stats soft_stats; struct vlan_group *vlgrp; u32 rx_buffer_len; @@ -765,7 +765,7 @@ struct atl1_adapter { struct work_struct tx_timeout_task; struct work_struct link_chg_task; struct work_struct pcie_dma_to_rst_task; - struct timer_list watchdog_timer; + struct timer_list phy_config_timer; bool phy_timer_pending; diff --git a/drivers/net/atlx/atl2.c b/drivers/net/atlx/atl2.c index 8571e8c0bc67b9973e16a8a85aa92b00049faed6..bc394491b63bb45397bc15df3d058987c0bec0d6 100644 --- a/drivers/net/atlx/atl2.c +++ b/drivers/net/atlx/atl2.c @@ -418,7 +418,7 @@ static void atl2_intr_rx(struct atl2_adapter *adapter) * Check that some rx space is free. If not, * free one and mark stats->rx_dropped++. */ - adapter->net_stats.rx_dropped++; + netdev->stats.rx_dropped++; break; } skb_reserve(skb, NET_IP_ALIGN); @@ -435,20 +435,19 @@ static void atl2_intr_rx(struct atl2_adapter *adapter) } else #endif netif_rx(skb); - adapter->net_stats.rx_bytes += rx_size; - adapter->net_stats.rx_packets++; - netdev->last_rx = jiffies; + netdev->stats.rx_bytes += rx_size; + netdev->stats.rx_packets++; } else { - adapter->net_stats.rx_errors++; + netdev->stats.rx_errors++; if (rxd->status.ok && rxd->status.pkt_size <= 60) - adapter->net_stats.rx_length_errors++; + netdev->stats.rx_length_errors++; if (rxd->status.mcast) - adapter->net_stats.multicast++; + netdev->stats.multicast++; if (rxd->status.crc) - adapter->net_stats.rx_crc_errors++; + netdev->stats.rx_crc_errors++; if (rxd->status.align) - adapter->net_stats.rx_frame_errors++; + netdev->stats.rx_frame_errors++; } /* advance write ptr */ @@ -463,6 +462,7 @@ static void atl2_intr_rx(struct atl2_adapter *adapter) static void atl2_intr_tx(struct atl2_adapter *adapter) { + struct net_device *netdev = adapter->netdev; u32 txd_read_ptr; u32 txs_write_ptr; struct tx_pkt_status *txs; @@ -522,20 +522,20 @@ static void atl2_intr_tx(struct atl2_adapter *adapter) /* tx statistics: */ if (txs->ok) { - adapter->net_stats.tx_bytes += txs->pkt_size; - adapter->net_stats.tx_packets++; + netdev->stats.tx_bytes += txs->pkt_size; + netdev->stats.tx_packets++; } else - adapter->net_stats.tx_errors++; + netdev->stats.tx_errors++; if (txs->defer) - adapter->net_stats.collisions++; + netdev->stats.collisions++; if (txs->abort_col) - adapter->net_stats.tx_aborted_errors++; + netdev->stats.tx_aborted_errors++; if (txs->late_col) - adapter->net_stats.tx_window_errors++; + netdev->stats.tx_window_errors++; if (txs->underun) - adapter->net_stats.tx_fifo_errors++; + netdev->stats.tx_fifo_errors++; } while (1); if (free_hole) { @@ -621,7 +621,7 @@ static irqreturn_t atl2_intr(int irq, void *data) /* link event */ if (status & (ISR_PHY | ISR_MANUAL)) { - adapter->net_stats.tx_carrier_errors++; + adapter->netdev->stats.tx_carrier_errors++; atl2_check_for_link(adapter); } @@ -644,7 +644,6 @@ static int atl2_request_irq(struct atl2_adapter *adapter) int flags, err = 0; flags = IRQF_SHARED; -#ifdef CONFIG_PCI_MSI adapter->have_msi = true; err = pci_enable_msi(adapter->pdev); if (err) @@ -652,7 +651,6 @@ static int atl2_request_irq(struct atl2_adapter *adapter) if (adapter->have_msi) flags &= ~IRQF_SHARED; -#endif return request_irq(adapter->pdev->irq, &atl2_intr, flags, netdev->name, netdev); @@ -723,7 +721,7 @@ static int atl2_open(struct net_device *netdev) clear_bit(__ATL2_DOWN, &adapter->flags); - mod_timer(&adapter->watchdog_timer, jiffies + 4*HZ); + mod_timer(&adapter->watchdog_timer, round_jiffies(jiffies + 4*HZ)); val = ATL2_READ_REG(&adapter->hw, REG_MASTER_CTRL); ATL2_WRITE_REG(&adapter->hw, REG_MASTER_CTRL, @@ -899,19 +897,6 @@ static int atl2_xmit_frame(struct sk_buff *skb, struct net_device *netdev) return NETDEV_TX_OK; } -/* - * atl2_get_stats - Get System Network Statistics - * @netdev: network interface device structure - * - * Returns the address of the device statistics structure. - * The statistics are actually updated from the timer callback. - */ -static struct net_device_stats *atl2_get_stats(struct net_device *netdev) -{ - struct atl2_adapter *adapter = netdev_priv(netdev); - return &adapter->net_stats; -} - /* * atl2_change_mtu - Change the Maximum Transfer Unit * @netdev: network interface device structure @@ -1050,18 +1035,21 @@ static void atl2_tx_timeout(struct net_device *netdev) static void atl2_watchdog(unsigned long data) { struct atl2_adapter *adapter = (struct atl2_adapter *) data; - u32 drop_rxd, drop_rxs; - unsigned long flags; if (!test_bit(__ATL2_DOWN, &adapter->flags)) { + u32 drop_rxd, drop_rxs; + unsigned long flags; + spin_lock_irqsave(&adapter->stats_lock, flags); drop_rxd = ATL2_READ_REG(&adapter->hw, REG_STS_RXD_OV); drop_rxs = ATL2_READ_REG(&adapter->hw, REG_STS_RXS_OV); - adapter->net_stats.rx_over_errors += (drop_rxd+drop_rxs); spin_unlock_irqrestore(&adapter->stats_lock, flags); + adapter->netdev->stats.rx_over_errors += drop_rxd + drop_rxs; + /* Reset the timer */ - mod_timer(&adapter->watchdog_timer, jiffies + 4 * HZ); + mod_timer(&adapter->watchdog_timer, + round_jiffies(jiffies + 4 * HZ)); } } @@ -1265,7 +1253,8 @@ static int atl2_check_link(struct atl2_adapter *adapter) * (if interval smaller than 5 seconds, something strange) */ if (!test_bit(__ATL2_DOWN, &adapter->flags)) { if (!test_and_set_bit(0, &adapter->cfg_phy)) - mod_timer(&adapter->phy_config_timer, jiffies + 5 * HZ); + mod_timer(&adapter->phy_config_timer, + round_jiffies(jiffies + 5 * HZ)); } return 0; @@ -1320,6 +1309,23 @@ static void atl2_poll_controller(struct net_device *netdev) } #endif + +static const struct net_device_ops atl2_netdev_ops = { + .ndo_open = atl2_open, + .ndo_stop = atl2_close, + .ndo_start_xmit = atl2_xmit_frame, + .ndo_set_multicast_list = atl2_set_multi, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = atl2_set_mac, + .ndo_change_mtu = atl2_change_mtu, + .ndo_do_ioctl = atl2_ioctl, + .ndo_tx_timeout = atl2_tx_timeout, + .ndo_vlan_rx_register = atl2_vlan_rx_register, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = atl2_poll_controller, +#endif +}; + /* * atl2_probe - Device Initialization Routine * @pdev: PCI device information struct @@ -1393,26 +1399,9 @@ static int __devinit atl2_probe(struct pci_dev *pdev, atl2_setup_pcicmd(pdev); - netdev->open = &atl2_open; - netdev->stop = &atl2_close; - netdev->hard_start_xmit = &atl2_xmit_frame; - netdev->get_stats = &atl2_get_stats; - netdev->set_multicast_list = &atl2_set_multi; - netdev->set_mac_address = &atl2_set_mac; - netdev->change_mtu = &atl2_change_mtu; - netdev->do_ioctl = &atl2_ioctl; + netdev->netdev_ops = &atl2_netdev_ops; atl2_set_ethtool_ops(netdev); - -#ifdef CONFIG_NET_POLL_CONTROLLER - netdev->poll_controller = atl2_poll_controller; -#endif -#ifdef HAVE_TX_TIMEOUT - netdev->tx_timeout = &atl2_tx_timeout; netdev->watchdog_timeo = 5 * HZ; -#endif -#ifdef NETIF_F_HW_VLAN_TX - netdev->vlan_rx_register = atl2_vlan_rx_register; -#endif strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1); netdev->mem_start = mmio_start; diff --git a/drivers/net/atlx/atl2.h b/drivers/net/atlx/atl2.h index 09974df76b1865d138d0ebac05319e3e8d7692cd..d918bbe621eae3d9e44dc1ad141fad8019a6f7fe 100644 --- a/drivers/net/atlx/atl2.h +++ b/drivers/net/atlx/atl2.h @@ -453,7 +453,6 @@ struct atl2_adapter { /* OS defined structs */ struct net_device *netdev; struct pci_dev *pdev; - struct net_device_stats net_stats; #ifdef NETIF_F_HW_VLAN_TX struct vlan_group *vlgrp; #endif diff --git a/drivers/net/atlx/atlx.c b/drivers/net/atlx/atlx.c index 3cc9d1089ca15b2c40ec80a88c124fe391116451..3dc01421567961450b6503f3bb2a98662bea2f07 100644 --- a/drivers/net/atlx/atlx.c +++ b/drivers/net/atlx/atlx.c @@ -181,19 +181,6 @@ static void atlx_clear_phy_int(struct atlx_adapter *adapter) spin_unlock_irqrestore(&adapter->lock, flags); } -/* - * atlx_get_stats - Get System Network Statistics - * @netdev: network interface device structure - * - * Returns the address of the device statistics structure. - * The statistics are actually updated from the timer callback. - */ -static struct net_device_stats *atlx_get_stats(struct net_device *netdev) -{ - struct atlx_adapter *adapter = netdev_priv(netdev); - return &adapter->net_stats; -} - /* * atlx_tx_timeout - Respond to a Tx Hang * @netdev: network interface device structure diff --git a/drivers/net/atp.c b/drivers/net/atp.c index c10cd8058e2303da73054ce892d52878123d225c..ea493ce23982abeb362f0d31618f4028495b9730 100644 --- a/drivers/net/atp.c +++ b/drivers/net/atp.c @@ -248,7 +248,6 @@ static int __init atp_probe1(long ioaddr) struct net_local *lp; int saved_ctrl_reg, status, i; int res; - DECLARE_MAC_BUF(mac); outb(0xff, ioaddr + PAR_DATA); /* Save the original value of the Control register, in case we guessed @@ -324,8 +323,8 @@ static int __init atp_probe1(long ioaddr) #endif printk(KERN_NOTICE "%s: Pocket adapter found at %#3lx, IRQ %d, " - "SAPROM %s.\n", - dev->name, dev->base_addr, dev->irq, print_mac(mac, dev->dev_addr)); + "SAPROM %pM.\n", + dev->name, dev->base_addr, dev->irq, dev->dev_addr); /* Reset the ethernet hardware and activate the printer pass-through. */ write_reg_high(ioaddr, CMR1, CMR1h_RESET | CMR1h_MUX); @@ -421,7 +420,7 @@ static unsigned short __init eeprom_op(long ioaddr, u32 cmd) registers that "should" only need to be set once at boot, so that there is non-reboot way to recover if something goes wrong. - This is an attachable device: if there is no dev->priv entry then it wasn't + This is an attachable device: if there is no private entry then it wasn't probed for at boot-time, and we need to probe for it again. */ static int net_open(struct net_device *dev) @@ -803,21 +802,22 @@ static void net_rx(struct net_device *dev) static void read_block(long ioaddr, int length, unsigned char *p, int data_mode) { - if (data_mode <= 3) { /* Mode 0 or 1 */ outb(Ctrl_LNibRead, ioaddr + PAR_CONTROL); outb(length == 8 ? RdAddr | HNib | MAR : RdAddr | MAR, ioaddr + PAR_DATA); if (data_mode <= 1) { /* Mode 0 or 1 */ - do *p++ = read_byte_mode0(ioaddr); while (--length > 0); - } else /* Mode 2 or 3 */ - do *p++ = read_byte_mode2(ioaddr); while (--length > 0); - } else if (data_mode <= 5) - do *p++ = read_byte_mode4(ioaddr); while (--length > 0); - else - do *p++ = read_byte_mode6(ioaddr); while (--length > 0); + do { *p++ = read_byte_mode0(ioaddr); } while (--length > 0); + } else { /* Mode 2 or 3 */ + do { *p++ = read_byte_mode2(ioaddr); } while (--length > 0); + } + } else if (data_mode <= 5) { + do { *p++ = read_byte_mode4(ioaddr); } while (--length > 0); + } else { + do { *p++ = read_byte_mode6(ioaddr); } while (--length > 0); + } - outb(EOC+HNib+MAR, ioaddr + PAR_DATA); + outb(EOC+HNib+MAR, ioaddr + PAR_DATA); outb(Ctrl_SelData, ioaddr + PAR_CONTROL); } @@ -913,7 +913,8 @@ static void __exit atp_cleanup_module(void) { struct net_device *next_dev; while (root_atp_dev) { - next_dev = ((struct net_local *)root_atp_dev->priv)->next_module; + struct net_local *atp_local = netdev_priv(root_atp_dev); + next_dev = atp_local->next_module; unregister_netdev(root_atp_dev); /* No need to release_region(), since we never snarf it. */ free_netdev(root_atp_dev); diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index 019b13c08ae6ead71f5a0b976b1e087a3df87df7..9c875bb3f76c642f93203f9096942af72a0e3e53 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -193,7 +193,7 @@ struct au1000_private *au_macs[NUM_ETH_INTERFACES]; */ static int au1000_mdio_read(struct net_device *dev, int phy_addr, int reg) { - struct au1000_private *aup = (struct au1000_private *) dev->priv; + struct au1000_private *aup = netdev_priv(dev); volatile u32 *const mii_control_reg = &aup->mac->mii_control; volatile u32 *const mii_data_reg = &aup->mac->mii_data; u32 timedout = 20; @@ -228,7 +228,7 @@ static int au1000_mdio_read(struct net_device *dev, int phy_addr, int reg) static void au1000_mdio_write(struct net_device *dev, int phy_addr, int reg, u16 value) { - struct au1000_private *aup = (struct au1000_private *) dev->priv; + struct au1000_private *aup = netdev_priv(dev); volatile u32 *const mii_control_reg = &aup->mac->mii_control; volatile u32 *const mii_data_reg = &aup->mac->mii_data; u32 timedout = 20; @@ -283,7 +283,7 @@ static int au1000_mdiobus_reset(struct mii_bus *bus) static int mii_probe (struct net_device *dev) { - struct au1000_private *const aup = (struct au1000_private *) dev->priv; + struct au1000_private *const aup = netdev_priv(dev); struct phy_device *phydev = NULL; #if defined(AU1XXX_PHY_STATIC_CONFIG) @@ -353,7 +353,6 @@ static int mii_probe (struct net_device *dev) } /* now we are supposed to have a proper phydev, to attach to... */ - BUG_ON(!phydev); BUG_ON(phydev->attached_dev); phydev = phy_connect(dev, phydev->dev.bus_id, &au1000_adjust_link, 0, @@ -415,7 +414,7 @@ void ReleaseDB(struct au1000_private *aup, db_dest_t *pDB) static void enable_rx_tx(struct net_device *dev) { - struct au1000_private *aup = (struct au1000_private *) dev->priv; + struct au1000_private *aup = netdev_priv(dev); if (au1000_debug > 4) printk(KERN_INFO "%s: enable_rx_tx\n", dev->name); @@ -426,7 +425,7 @@ static void enable_rx_tx(struct net_device *dev) static void hard_stop(struct net_device *dev) { - struct au1000_private *aup = (struct au1000_private *) dev->priv; + struct au1000_private *aup = netdev_priv(dev); if (au1000_debug > 4) printk(KERN_INFO "%s: hard stop\n", dev->name); @@ -438,7 +437,7 @@ static void hard_stop(struct net_device *dev) static void enable_mac(struct net_device *dev, int force_reset) { unsigned long flags; - struct au1000_private *aup = (struct au1000_private *) dev->priv; + struct au1000_private *aup = netdev_priv(dev); spin_lock_irqsave(&aup->lock, flags); @@ -457,7 +456,7 @@ static void enable_mac(struct net_device *dev, int force_reset) static void reset_mac_unlocked(struct net_device *dev) { - struct au1000_private *const aup = (struct au1000_private *) dev->priv; + struct au1000_private *const aup = netdev_priv(dev); int i; hard_stop(dev); @@ -483,7 +482,7 @@ static void reset_mac_unlocked(struct net_device *dev) static void reset_mac(struct net_device *dev) { - struct au1000_private *const aup = (struct au1000_private *) dev->priv; + struct au1000_private *const aup = netdev_priv(dev); unsigned long flags; if (au1000_debug > 4) @@ -572,7 +571,7 @@ static int __init au1000_init_module(void) static int au1000_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct au1000_private *aup = (struct au1000_private *)dev->priv; + struct au1000_private *aup = netdev_priv(dev); if (aup->phy_dev) return phy_ethtool_gset(aup->phy_dev, cmd); @@ -582,7 +581,7 @@ static int au1000_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) static int au1000_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct au1000_private *aup = (struct au1000_private *)dev->priv; + struct au1000_private *aup = netdev_priv(dev); if (!capable(CAP_NET_ADMIN)) return -EPERM; @@ -596,7 +595,7 @@ static int au1000_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) static void au1000_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct au1000_private *aup = (struct au1000_private *)dev->priv; + struct au1000_private *aup = netdev_priv(dev); strcpy(info->driver, DRV_NAME); strcpy(info->version, DRV_VERSION); @@ -652,7 +651,7 @@ static struct net_device * au1000_probe(int port_num) printk("%s: Au1xx0 Ethernet found at 0x%x, irq %d\n", dev->name, base, irq); - aup = dev->priv; + aup = netdev_priv(dev); spin_lock_init(&aup->lock); @@ -817,7 +816,7 @@ static struct net_device * au1000_probe(int port_num) */ static int au1000_init(struct net_device *dev) { - struct au1000_private *aup = (struct au1000_private *) dev->priv; + struct au1000_private *aup = netdev_priv(dev); unsigned long flags; int i; u32 control; @@ -868,7 +867,7 @@ static int au1000_init(struct net_device *dev) static void au1000_adjust_link(struct net_device *dev) { - struct au1000_private *aup = (struct au1000_private *) dev->priv; + struct au1000_private *aup = netdev_priv(dev); struct phy_device *phydev = aup->phy_dev; unsigned long flags; @@ -947,7 +946,7 @@ au1000_adjust_link(struct net_device *dev) static int au1000_open(struct net_device *dev) { int retval; - struct au1000_private *aup = (struct au1000_private *) dev->priv; + struct au1000_private *aup = netdev_priv(dev); if (au1000_debug > 4) printk("%s: open: dev=%p\n", dev->name, dev); @@ -982,7 +981,7 @@ static int au1000_open(struct net_device *dev) static int au1000_close(struct net_device *dev) { unsigned long flags; - struct au1000_private *const aup = (struct au1000_private *) dev->priv; + struct au1000_private *const aup = netdev_priv(dev); if (au1000_debug > 4) printk("%s: close: dev=%p\n", dev->name, dev); @@ -1013,7 +1012,7 @@ static void __exit au1000_cleanup_module(void) for (i = 0; i < num_ifs; i++) { dev = iflist[i].dev; if (dev) { - aup = (struct au1000_private *) dev->priv; + aup = netdev_priv(dev); unregister_netdev(dev); mdiobus_unregister(aup->mii_bus); mdiobus_free(aup->mii_bus); @@ -1035,7 +1034,7 @@ static void __exit au1000_cleanup_module(void) static void update_tx_stats(struct net_device *dev, u32 status) { - struct au1000_private *aup = (struct au1000_private *) dev->priv; + struct au1000_private *aup = netdev_priv(dev); struct net_device_stats *ps = &dev->stats; if (status & TX_FRAME_ABORTED) { @@ -1064,7 +1063,7 @@ static void update_tx_stats(struct net_device *dev, u32 status) */ static void au1000_tx_ack(struct net_device *dev) { - struct au1000_private *aup = (struct au1000_private *) dev->priv; + struct au1000_private *aup = netdev_priv(dev); volatile tx_dma_t *ptxd; ptxd = aup->tx_dma_ring[aup->tx_tail]; @@ -1091,7 +1090,7 @@ static void au1000_tx_ack(struct net_device *dev) */ static int au1000_tx(struct sk_buff *skb, struct net_device *dev) { - struct au1000_private *aup = (struct au1000_private *) dev->priv; + struct au1000_private *aup = netdev_priv(dev); struct net_device_stats *ps = &dev->stats; volatile tx_dma_t *ptxd; u32 buff_stat; @@ -1145,7 +1144,7 @@ static int au1000_tx(struct sk_buff *skb, struct net_device *dev) static inline void update_rx_stats(struct net_device *dev, u32 status) { - struct au1000_private *aup = (struct au1000_private *) dev->priv; + struct au1000_private *aup = netdev_priv(dev); struct net_device_stats *ps = &dev->stats; ps->rx_packets++; @@ -1173,7 +1172,7 @@ static inline void update_rx_stats(struct net_device *dev, u32 status) */ static int au1000_rx(struct net_device *dev) { - struct au1000_private *aup = (struct au1000_private *) dev->priv; + struct au1000_private *aup = netdev_priv(dev); struct sk_buff *skb; volatile rx_dma_t *prxd; u32 buff_stat, status; @@ -1240,7 +1239,6 @@ static int au1000_rx(struct net_device *dev) /* next descriptor */ prxd = aup->rx_dma_ring[aup->rx_head]; buff_stat = prxd->buff_stat; - dev->last_rx = jiffies; } return 0; } @@ -1276,7 +1274,7 @@ static void au1000_tx_timeout(struct net_device *dev) static void set_rx_mode(struct net_device *dev) { - struct au1000_private *aup = (struct au1000_private *) dev->priv; + struct au1000_private *aup = netdev_priv(dev); if (au1000_debug > 4) printk("%s: set_rx_mode: flags=%x\n", dev->name, dev->flags); @@ -1308,7 +1306,7 @@ static void set_rx_mode(struct net_device *dev) static int au1000_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct au1000_private *aup = (struct au1000_private *)dev->priv; + struct au1000_private *aup = netdev_priv(dev); if (!netif_running(dev)) return -EINVAL; diff --git a/drivers/net/ax88796.c b/drivers/net/ax88796.c index 9a314d88e7b67aa16b74e60c442bc655242d9bf8..337488ec707cfc2aad6b14ae7aec63315510529c 100644 --- a/drivers/net/ax88796.c +++ b/drivers/net/ax88796.c @@ -758,13 +758,10 @@ static int ax_init_dev(struct net_device *dev, int first_init) #endif ax_NS8390_init(dev, 0); - if (first_init) { - DECLARE_MAC_BUF(mac); - - dev_info(&ax->dev->dev, "%dbit, irq %d, %lx, MAC: %s\n", + if (first_init) + dev_info(&ax->dev->dev, "%dbit, irq %d, %lx, MAC: %pM\n", ei_status.word16 ? 16:8, dev->irq, dev->base_addr, - print_mac(mac, dev->dev_addr)); - } + dev->dev_addr); ret = register_netdev(dev); if (ret) diff --git a/drivers/net/b44.c b/drivers/net/b44.c index c3bda5ce67c488dba1fc7f51469f16522c5b1080..0e7470a201f0ec18eb06c860495d5e6022679845 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -829,7 +829,6 @@ static int b44_rx(struct b44 *bp, int budget) skb->ip_summed = CHECKSUM_NONE; skb->protocol = eth_type_trans(skb, bp->dev); netif_receive_skb(skb); - bp->dev->last_rx = jiffies; received++; budget--; next_pkt: @@ -847,7 +846,6 @@ static int b44_rx(struct b44 *bp, int budget) static int b44_poll(struct napi_struct *napi, int budget) { struct b44 *bp = container_of(napi, struct b44, napi); - struct net_device *netdev = bp->dev; int work_done; spin_lock_irq(&bp->lock); @@ -876,7 +874,7 @@ static int b44_poll(struct napi_struct *napi, int budget) } if (work_done < budget) { - netif_rx_complete(netdev, napi); + netif_rx_complete(napi); b44_enable_ints(bp); } @@ -908,13 +906,13 @@ static irqreturn_t b44_interrupt(int irq, void *dev_id) goto irq_ack; } - if (netif_rx_schedule_prep(dev, &bp->napi)) { + if (netif_rx_schedule_prep(&bp->napi)) { /* NOTE: These writes are posted by the readback of * the ISTAT register below. */ bp->istat = istat; __b44_disable_ints(bp); - __netif_rx_schedule(dev, &bp->napi); + __netif_rx_schedule(&bp->napi); } else { printk(KERN_ERR PFX "%s: Error, poll already scheduled\n", dev->name); @@ -2117,7 +2115,6 @@ static int __devinit b44_init_one(struct ssb_device *sdev, struct net_device *dev; struct b44 *bp; int err; - DECLARE_MAC_BUF(mac); instance++; @@ -2213,8 +2210,8 @@ static int __devinit b44_init_one(struct ssb_device *sdev, */ b44_chip_reset(bp, B44_CHIP_RESET_FULL); - printk(KERN_INFO "%s: Broadcom 44xx/47xx 10/100BaseT Ethernet %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: Broadcom 44xx/47xx 10/100BaseT Ethernet %pM\n", + dev->name, dev->dev_addr); return 0; diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index b458d607a9c669215b48ffa831fe0c86cd4fde88..78e31aa861e020e461336e2323cea4647d7cb9c8 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -741,7 +741,6 @@ static void bfin_mac_rx(struct net_device *dev) blackfin_dcache_invalidate_range((unsigned long)skb->head, (unsigned long)skb->tail); - dev->last_rx = jiffies; skb->protocol = eth_type_trans(skb, dev); #if defined(BFIN_MAC_CSUM_OFFLOAD) skb->csum = current_rx_ptr->status.ip_payload_csum; diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c index a42bd19646d371e0ce75245280e446215495258e..8a546a33d58124fb39cf67ff673e305f7a7fd418 100644 --- a/drivers/net/bmac.c +++ b/drivers/net/bmac.c @@ -716,13 +716,11 @@ static irqreturn_t bmac_rxdma_intr(int irq, void *dev_id) skb_put(skb, nb); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; ++dev->stats.rx_packets; dev->stats.rx_bytes += nb; } else { ++dev->stats.rx_dropped; } - dev->last_rx = jiffies; if ((skb = bp->rx_bufs[i]) == NULL) { bp->rx_bufs[i] = skb = dev_alloc_skb(RX_BUFLEN+2); if (skb != NULL) @@ -1258,7 +1256,6 @@ static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_i unsigned char addr[6]; struct net_device *dev; int is_bmac_plus = ((int)match->data) != 0; - DECLARE_MAC_BUF(mac); if (macio_resource_count(mdev) != 3 || macio_irq_count(mdev) != 3) { printk(KERN_ERR "BMAC: can't use, need 3 addrs and 3 intrs\n"); @@ -1368,8 +1365,8 @@ static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_i goto err_out_irq2; } - printk(KERN_INFO "%s: BMAC%s at %s", - dev->name, (is_bmac_plus ? "+" : ""), print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: BMAC%s at %pM", + dev->name, (is_bmac_plus ? "+" : ""), dev->dev_addr); XXDEBUG((", base_addr=%#0lx", dev->base_addr)); printk("\n"); diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 9e8222f9e90ee0f69416ffe985103d0f6b183df5..d4a3dac21dcfb83fdc7e6c2835705ac66433ec3c 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -57,8 +57,8 @@ #define DRV_MODULE_NAME "bnx2" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "1.8.1" -#define DRV_MODULE_RELDATE "Oct 7, 2008" +#define DRV_MODULE_VERSION "1.9.0" +#define DRV_MODULE_RELDATE "Dec 16, 2008" #define RUN_AT(x) (jiffies + (x)) @@ -89,6 +89,7 @@ typedef enum { BCM5709, BCM5709S, BCM5716, + BCM5716S, } board_t; /* indexed by board_t, above */ @@ -105,6 +106,7 @@ static struct { { "Broadcom NetXtreme II BCM5709 1000Base-T" }, { "Broadcom NetXtreme II BCM5709 1000Base-SX" }, { "Broadcom NetXtreme II BCM5716 1000Base-T" }, + { "Broadcom NetXtreme II BCM5716 1000Base-SX" }, }; static DEFINE_PCI_DEVICE_TABLE(bnx2_pci_tbl) = { @@ -128,6 +130,8 @@ static DEFINE_PCI_DEVICE_TABLE(bnx2_pci_tbl) = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709S }, { PCI_VENDOR_ID_BROADCOM, 0x163b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5716 }, + { PCI_VENDOR_ID_BROADCOM, 0x163c, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5716S }, { 0, } }; @@ -1652,7 +1656,7 @@ bnx2_setup_serdes_phy(struct bnx2 *bp, u8 port) * exchanging base pages plus 3 next pages and * normally completes in about 120 msec. */ - bp->current_interval = SERDES_AN_TIMEOUT; + bp->current_interval = BNX2_SERDES_AN_TIMEOUT; bp->serdes_an_pending = 1; mod_timer(&bp->timer, jiffies + bp->current_interval); } else { @@ -2274,7 +2278,7 @@ bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int ack, int silent) return 0; /* wait for an acknowledgement. */ - for (i = 0; i < (FW_ACK_TIME_OUT_MS / 10); i++) { + for (i = 0; i < (BNX2_FW_ACK_TIME_OUT_MS / 10); i++) { msleep(10); val = bnx2_shmem_rd(bp, BNX2_FW_MB); @@ -3000,7 +3004,6 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) #endif netif_receive_skb(skb); - bp->dev->last_rx = jiffies; rx_pkt++; next_rx: @@ -3040,7 +3043,6 @@ bnx2_msi(int irq, void *dev_instance) { struct bnx2_napi *bnapi = dev_instance; struct bnx2 *bp = bnapi->bp; - struct net_device *dev = bp->dev; prefetch(bnapi->status_blk.msi); REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, @@ -3051,7 +3053,7 @@ bnx2_msi(int irq, void *dev_instance) if (unlikely(atomic_read(&bp->intr_sem) != 0)) return IRQ_HANDLED; - netif_rx_schedule(dev, &bnapi->napi); + netif_rx_schedule(&bnapi->napi); return IRQ_HANDLED; } @@ -3061,7 +3063,6 @@ bnx2_msi_1shot(int irq, void *dev_instance) { struct bnx2_napi *bnapi = dev_instance; struct bnx2 *bp = bnapi->bp; - struct net_device *dev = bp->dev; prefetch(bnapi->status_blk.msi); @@ -3069,7 +3070,7 @@ bnx2_msi_1shot(int irq, void *dev_instance) if (unlikely(atomic_read(&bp->intr_sem) != 0)) return IRQ_HANDLED; - netif_rx_schedule(dev, &bnapi->napi); + netif_rx_schedule(&bnapi->napi); return IRQ_HANDLED; } @@ -3079,7 +3080,6 @@ bnx2_interrupt(int irq, void *dev_instance) { struct bnx2_napi *bnapi = dev_instance; struct bnx2 *bp = bnapi->bp; - struct net_device *dev = bp->dev; struct status_block *sblk = bnapi->status_blk.msi; /* When using INTx, it is possible for the interrupt to arrive @@ -3106,9 +3106,9 @@ bnx2_interrupt(int irq, void *dev_instance) if (unlikely(atomic_read(&bp->intr_sem) != 0)) return IRQ_HANDLED; - if (netif_rx_schedule_prep(dev, &bnapi->napi)) { + if (netif_rx_schedule_prep(&bnapi->napi)) { bnapi->last_status_idx = sblk->status_idx; - __netif_rx_schedule(dev, &bnapi->napi); + __netif_rx_schedule(&bnapi->napi); } return IRQ_HANDLED; @@ -3218,7 +3218,7 @@ static int bnx2_poll_msix(struct napi_struct *napi, int budget) rmb(); if (likely(!bnx2_has_fast_work(bnapi))) { - netif_rx_complete(bp->dev, napi); + netif_rx_complete(napi); REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num | BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | bnapi->last_status_idx); @@ -3251,7 +3251,7 @@ static int bnx2_poll(struct napi_struct *napi, int budget) rmb(); if (likely(!bnx2_has_work(bnapi))) { - netif_rx_complete(bp->dev, napi); + netif_rx_complete(napi); if (likely(bp->flags & BNX2_FLAG_USING_MSI_OR_MSIX)) { REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | @@ -4493,7 +4493,7 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code) static int bnx2_init_chip(struct bnx2 *bp) { - u32 val; + u32 val, mtu; int rc, i; /* Make sure the interrupt is not active. */ @@ -4585,11 +4585,19 @@ bnx2_init_chip(struct bnx2 *bp) REG_WR(bp, BNX2_EMAC_BACKOFF_SEED, val); /* Program the MTU. Also include 4 bytes for CRC32. */ - val = bp->dev->mtu + ETH_HLEN + 4; + mtu = bp->dev->mtu; + val = mtu + ETH_HLEN + ETH_FCS_LEN; if (val > (MAX_ETHERNET_PACKET_SIZE + 4)) val |= BNX2_EMAC_RX_MTU_SIZE_JUMBO_ENA; REG_WR(bp, BNX2_EMAC_RX_MTU_SIZE, val); + if (mtu < 1500) + mtu = 1500; + + bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG, BNX2_RBUF_CONFIG_VAL(mtu)); + bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG2, BNX2_RBUF_CONFIG2_VAL(mtu)); + bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG3, BNX2_RBUF_CONFIG3_VAL(mtu)); + for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) bp->bnx2_napi[i].last_status_idx = 0; @@ -5719,7 +5727,7 @@ bnx2_5708_serdes_timer(struct bnx2 *bp) bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); if (bmcr & BMCR_ANENABLE) { bnx2_enable_forced_2g5(bp); - bp->current_interval = SERDES_FORCED_TIMEOUT; + bp->current_interval = BNX2_SERDES_FORCED_TIMEOUT; } else { bnx2_disable_forced_2g5(bp); bp->serdes_an_pending = 2; @@ -5816,6 +5824,8 @@ bnx2_enable_msix(struct bnx2 *bp, int msix_vecs) { int i, rc; struct msix_entry msix_ent[BNX2_MAX_MSIX_VEC]; + struct net_device *dev = bp->dev; + const int len = sizeof(bp->irq_tbl[0].name); bnx2_setup_msix_tbl(bp); REG_WR(bp, BNX2_PCI_MSIX_CONTROL, BNX2_MAX_MSIX_HW_VEC - 1); @@ -5826,7 +5836,7 @@ bnx2_enable_msix(struct bnx2 *bp, int msix_vecs) msix_ent[i].entry = i; msix_ent[i].vector = 0; - strcpy(bp->irq_tbl[i].name, bp->dev->name); + snprintf(bp->irq_tbl[i].name, len, "%s-%d", dev->name, i); bp->irq_tbl[i].handler = bnx2_msi_1shot; } @@ -6173,7 +6183,7 @@ bnx2_get_stats(struct net_device *dev) { struct bnx2 *bp = netdev_priv(dev); struct statistics_block *stats_blk = bp->stats_blk; - struct net_device_stats *net_stats = &bp->net_stats; + struct net_device_stats *net_stats = &dev->stats; if (bp->stats_blk == NULL) { return net_stats; @@ -6540,7 +6550,7 @@ bnx2_nway_reset(struct net_device *dev) spin_lock_bh(&bp->phy_lock); - bp->current_interval = SERDES_AN_TIMEOUT; + bp->current_interval = BNX2_SERDES_AN_TIMEOUT; bp->serdes_an_pending = 1; mod_timer(&bp->timer, jiffies + bp->current_interval); } @@ -7615,7 +7625,8 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) if ((CHIP_ID(bp) == CHIP_ID_5708_A0) || (CHIP_ID(bp) == CHIP_ID_5708_B0) || - (CHIP_ID(bp) == CHIP_ID_5708_B1)) { + (CHIP_ID(bp) == CHIP_ID_5708_B1) || + !(REG_RD(bp, BNX2_PCI_CONFIG_3) & BNX2_PCI_CONFIG_3_VAUX_PRESET)) { bp->flags |= BNX2_FLAG_NO_WOL; bp->wol = 0; } @@ -7724,6 +7735,25 @@ bnx2_init_napi(struct bnx2 *bp) } } +static const struct net_device_ops bnx2_netdev_ops = { + .ndo_open = bnx2_open, + .ndo_start_xmit = bnx2_start_xmit, + .ndo_stop = bnx2_close, + .ndo_get_stats = bnx2_get_stats, + .ndo_set_rx_mode = bnx2_set_rx_mode, + .ndo_do_ioctl = bnx2_ioctl, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = bnx2_change_mac_addr, + .ndo_change_mtu = bnx2_change_mtu, + .ndo_tx_timeout = bnx2_tx_timeout, +#ifdef BCM_VLAN + .ndo_vlan_rx_register = bnx2_vlan_rx_register, +#endif +#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER) + .ndo_poll_controller = poll_bnx2, +#endif +}; + static int __devinit bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -7732,7 +7762,6 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) struct bnx2 *bp; int rc; char str[40]; - DECLARE_MAC_BUF(mac); if (version_printed++ == 0) printk(KERN_INFO "%s", version); @@ -7749,28 +7778,13 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) return rc; } - dev->open = bnx2_open; - dev->hard_start_xmit = bnx2_start_xmit; - dev->stop = bnx2_close; - dev->get_stats = bnx2_get_stats; - dev->set_rx_mode = bnx2_set_rx_mode; - dev->do_ioctl = bnx2_ioctl; - dev->set_mac_address = bnx2_change_mac_addr; - dev->change_mtu = bnx2_change_mtu; - dev->tx_timeout = bnx2_tx_timeout; + dev->netdev_ops = &bnx2_netdev_ops; dev->watchdog_timeo = TX_TIMEOUT; -#ifdef BCM_VLAN - dev->vlan_rx_register = bnx2_vlan_rx_register; -#endif dev->ethtool_ops = &bnx2_ethtool_ops; bp = netdev_priv(dev); bnx2_init_napi(bp); -#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER) - dev->poll_controller = poll_bnx2; -#endif - pci_set_drvdata(pdev, dev); memcpy(dev->dev_addr, bp->mac_addr, 6); @@ -7799,14 +7813,14 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) } printk(KERN_INFO "%s: %s (%c%d) %s found at mem %lx, " - "IRQ %d, node addr %s\n", + "IRQ %d, node addr %pM\n", dev->name, board_info[ent->driver_data].name, ((CHIP_ID(bp) & 0xf000) >> 12) + 'A', ((CHIP_ID(bp) & 0x0ff0) >> 4), bnx2_bus_string(bp, str), dev->base_addr, - bp->pdev->irq, print_mac(mac, dev->dev_addr)); + bp->pdev->irq, dev->dev_addr); return 0; } diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index 0b032c3c7b611c17cee29b12a62809839a1dae2b..900641ac63e04d4678d7f779fc4f0481e0b138af 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -4202,7 +4202,14 @@ struct l2_fhdr { #define BNX2_RBUF_CONFIG 0x0020000c #define BNX2_RBUF_CONFIG_XOFF_TRIP (0x3ffL<<0) +#define BNX2_RBUF_CONFIG_XOFF_TRIP_VAL(mtu) \ + ((((mtu) - 1500) * 31 / 1000) + 54) #define BNX2_RBUF_CONFIG_XON_TRIP (0x3ffL<<16) +#define BNX2_RBUF_CONFIG_XON_TRIP_VAL(mtu) \ + ((((mtu) - 1500) * 39 / 1000) + 66) +#define BNX2_RBUF_CONFIG_VAL(mtu) \ + (BNX2_RBUF_CONFIG_XOFF_TRIP_VAL(mtu) | \ + (BNX2_RBUF_CONFIG_XON_TRIP_VAL(mtu) << 16)) #define BNX2_RBUF_FW_BUF_ALLOC 0x00200010 #define BNX2_RBUF_FW_BUF_ALLOC_VALUE (0x1ffL<<7) @@ -4224,11 +4231,25 @@ struct l2_fhdr { #define BNX2_RBUF_CONFIG2 0x0020001c #define BNX2_RBUF_CONFIG2_MAC_DROP_TRIP (0x3ffL<<0) +#define BNX2_RBUF_CONFIG2_MAC_DROP_TRIP_VAL(mtu) \ + ((((mtu) - 1500) * 4 / 1000) + 5) #define BNX2_RBUF_CONFIG2_MAC_KEEP_TRIP (0x3ffL<<16) +#define BNX2_RBUF_CONFIG2_MAC_KEEP_TRIP_VAL(mtu) \ + ((((mtu) - 1500) * 2 / 100) + 30) +#define BNX2_RBUF_CONFIG2_VAL(mtu) \ + (BNX2_RBUF_CONFIG2_MAC_DROP_TRIP_VAL(mtu) | \ + (BNX2_RBUF_CONFIG2_MAC_KEEP_TRIP_VAL(mtu) << 16)) #define BNX2_RBUF_CONFIG3 0x00200020 #define BNX2_RBUF_CONFIG3_CU_DROP_TRIP (0x3ffL<<0) +#define BNX2_RBUF_CONFIG3_CU_DROP_TRIP_VAL(mtu) \ + ((((mtu) - 1500) * 12 / 1000) + 18) #define BNX2_RBUF_CONFIG3_CU_KEEP_TRIP (0x3ffL<<16) +#define BNX2_RBUF_CONFIG3_CU_KEEP_TRIP_VAL(mtu) \ + ((((mtu) - 1500) * 2 / 100) + 30) +#define BNX2_RBUF_CONFIG3_VAL(mtu) \ + (BNX2_RBUF_CONFIG3_CU_DROP_TRIP_VAL(mtu) | \ + (BNX2_RBUF_CONFIG3_CU_KEEP_TRIP_VAL(mtu) << 16)) #define BNX2_RBUF_PKT_DATA 0x00208000 #define BNX2_RBUF_CLIST_DATA 0x00210000 @@ -6606,7 +6627,7 @@ struct bnx2_irq { irq_handler_t handler; unsigned int vector; u8 requested; - char name[16]; + char name[IFNAMSIZ + 2]; }; struct bnx2_tx_ring_info { @@ -6661,8 +6682,6 @@ struct bnx2_napi { struct bnx2_tx_ring_info tx_ring; }; -#define BNX2_TIMER_INTERVAL HZ - struct bnx2 { /* Fields used in the tx and intr/napi performance paths are grouped */ /* together in the beginning of the structure. */ @@ -6710,7 +6729,11 @@ struct bnx2 { /* End of fields used in the performance code paths. */ - int current_interval; + unsigned int current_interval; +#define BNX2_TIMER_INTERVAL HZ +#define BNX2_SERDES_AN_TIMEOUT (HZ / 3) +#define BNX2_SERDES_FORCED_TIMEOUT (HZ / 10) + struct timer_list timer; struct work_struct reset_task; @@ -6825,9 +6848,6 @@ struct bnx2 { u8 flow_ctrl; /* actual flow ctrl settings */ /* may be different from */ /* req_flow_ctrl if autoneg */ -#define FLOW_CTRL_TX 1 -#define FLOW_CTRL_RX 2 - u32 advertising; u8 req_flow_ctrl; /* flow ctrl advertisement */ @@ -6842,8 +6862,6 @@ struct bnx2 { #define PHY_LOOPBACK 2 u8 serdes_an_pending; -#define SERDES_AN_TIMEOUT (HZ / 3) -#define SERDES_FORCED_TIMEOUT (HZ / 10) u8 mac_addr[8]; @@ -6854,8 +6872,6 @@ struct bnx2 { int pm_cap; int pcix_cap; - struct net_device_stats net_stats; - struct flash_spec *flash_info; u32 flash_size; @@ -6944,14 +6960,14 @@ struct fw_info { /* This value (in milliseconds) determines the frequency of the driver * issuing the PULSE message code. The firmware monitors this periodic * pulse to determine when to switch to an OS-absent mode. */ -#define DRV_PULSE_PERIOD_MS 250 +#define BNX2_DRV_PULSE_PERIOD_MS 250 /* This value (in milliseconds) determines how long the driver should * wait for an acknowledgement from the firmware before timing out. Once * the firmware has timed out, the driver will assume there is no firmware * running and there won't be any firmware-driver synchronization during a * driver reset. */ -#define FW_ACK_TIME_OUT_MS 1000 +#define BNX2_FW_ACK_TIME_OUT_MS 1000 #define BNX2_DRV_RESET_SIGNATURE 0x00000000 diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c index 4ce7fe9c5251143745985b70cb449df9f394edfd..67de94f1f30e10c38beee7cfc0e3bdf2a5715962 100644 --- a/drivers/net/bnx2x_link.c +++ b/drivers/net/bnx2x_link.c @@ -289,7 +289,7 @@ static u8 bnx2x_emac_enable(struct link_params *params, /* pause enable/disable */ bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_RX_MODE, EMAC_RX_MODE_FLOW_EN); - if (vars->flow_ctrl & FLOW_CTRL_RX) + if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX) bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_RX_MODE, EMAC_RX_MODE_FLOW_EN); @@ -297,7 +297,7 @@ static u8 bnx2x_emac_enable(struct link_params *params, bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_TX_MODE, (EMAC_TX_MODE_EXT_PAUSE_EN | EMAC_TX_MODE_FLOW_EN)); - if (vars->flow_ctrl & FLOW_CTRL_TX) + if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX) bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE, (EMAC_TX_MODE_EXT_PAUSE_EN | @@ -333,7 +333,7 @@ static u8 bnx2x_emac_enable(struct link_params *params, /* enable the NIG in/out to the emac */ REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x1); val = 0; - if (vars->flow_ctrl & FLOW_CTRL_TX) + if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX) val = 1; REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, val); @@ -396,7 +396,7 @@ static u8 bnx2x_bmac_enable(struct link_params *params, struct link_vars *vars, /* tx control */ val = 0xc0; - if (vars->flow_ctrl & FLOW_CTRL_TX) + if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX) val |= 0x800000; wb_data[0] = val; wb_data[1] = 0; @@ -423,7 +423,7 @@ static u8 bnx2x_bmac_enable(struct link_params *params, struct link_vars *vars, /* rx control set to don't strip crc */ val = 0x14; - if (vars->flow_ctrl & FLOW_CTRL_RX) + if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX) val |= 0x20; wb_data[0] = val; wb_data[1] = 0; @@ -460,7 +460,7 @@ static u8 bnx2x_bmac_enable(struct link_params *params, struct link_vars *vars, REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0); REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0); val = 0; - if (vars->flow_ctrl & FLOW_CTRL_TX) + if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX) val = 1; REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val); REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0); @@ -580,14 +580,14 @@ void bnx2x_link_status_update(struct link_params *params, } if (vars->link_status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED) - vars->flow_ctrl |= FLOW_CTRL_TX; + vars->flow_ctrl |= BNX2X_FLOW_CTRL_TX; else - vars->flow_ctrl &= ~FLOW_CTRL_TX; + vars->flow_ctrl &= ~BNX2X_FLOW_CTRL_TX; if (vars->link_status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED) - vars->flow_ctrl |= FLOW_CTRL_RX; + vars->flow_ctrl |= BNX2X_FLOW_CTRL_RX; else - vars->flow_ctrl &= ~FLOW_CTRL_RX; + vars->flow_ctrl &= ~BNX2X_FLOW_CTRL_RX; if (vars->phy_flags & PHY_XGXS_FLAG) { if (vars->line_speed && @@ -618,7 +618,7 @@ void bnx2x_link_status_update(struct link_params *params, vars->line_speed = 0; vars->duplex = DUPLEX_FULL; - vars->flow_ctrl = FLOW_CTRL_NONE; + vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; /* indicate no mac active */ vars->mac_type = MAC_TYPE_NONE; @@ -691,7 +691,7 @@ static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl, return -EINVAL; } - if (flow_ctrl & FLOW_CTRL_RX || + if (flow_ctrl & BNX2X_FLOW_CTRL_RX || line_speed == SPEED_10 || line_speed == SPEED_100 || line_speed == SPEED_1000 || @@ -1300,8 +1300,8 @@ static void bnx2x_calc_ieee_aneg_adv(struct link_params *params, u32 *ieee_fc) * Please refer to Table 28B-3 of the 802.3ab-1999 spec */ switch (params->req_flow_ctrl) { - case FLOW_CTRL_AUTO: - if (params->req_fc_auto_adv == FLOW_CTRL_BOTH) { + case BNX2X_FLOW_CTRL_AUTO: + if (params->req_fc_auto_adv == BNX2X_FLOW_CTRL_BOTH) { *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH; } else { @@ -1309,17 +1309,17 @@ static void bnx2x_calc_ieee_aneg_adv(struct link_params *params, u32 *ieee_fc) MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC; } break; - case FLOW_CTRL_TX: + case BNX2X_FLOW_CTRL_TX: *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC; break; - case FLOW_CTRL_RX: - case FLOW_CTRL_BOTH: + case BNX2X_FLOW_CTRL_RX: + case BNX2X_FLOW_CTRL_BOTH: *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH; break; - case FLOW_CTRL_NONE: + case BNX2X_FLOW_CTRL_NONE: default: *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE; break; @@ -1463,18 +1463,18 @@ static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result) { /* LD LP */ switch (pause_result) { /* ASYM P ASYM P */ case 0xb: /* 1 0 1 1 */ - vars->flow_ctrl = FLOW_CTRL_TX; + vars->flow_ctrl = BNX2X_FLOW_CTRL_TX; break; case 0xe: /* 1 1 1 0 */ - vars->flow_ctrl = FLOW_CTRL_RX; + vars->flow_ctrl = BNX2X_FLOW_CTRL_RX; break; case 0x5: /* 0 1 0 1 */ case 0x7: /* 0 1 1 1 */ case 0xd: /* 1 1 0 1 */ case 0xf: /* 1 1 1 1 */ - vars->flow_ctrl = FLOW_CTRL_BOTH; + vars->flow_ctrl = BNX2X_FLOW_CTRL_BOTH; break; default: @@ -1531,7 +1531,7 @@ static u8 bnx2x_ext_phy_resove_fc(struct link_params *params, DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x \n", pause_result); bnx2x_pause_resolve(vars, pause_result); - if (vars->flow_ctrl == FLOW_CTRL_NONE && + if (vars->flow_ctrl == BNX2X_FLOW_CTRL_NONE && ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) { bnx2x_cl45_read(bp, port, ext_phy_type, @@ -1567,10 +1567,10 @@ static void bnx2x_flow_ctrl_resolve(struct link_params *params, u16 lp_pause; /* link partner */ u16 pause_result; - vars->flow_ctrl = FLOW_CTRL_NONE; + vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; /* resolve from gp_status in case of AN complete and not sgmii */ - if ((params->req_flow_ctrl == FLOW_CTRL_AUTO) && + if ((params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) && (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) && (!(vars->phy_flags & PHY_SGMII_FLAG)) && (XGXS_EXT_PHY_TYPE(params->ext_phy_config) == @@ -1591,11 +1591,11 @@ static void bnx2x_flow_ctrl_resolve(struct link_params *params, MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7; DP(NETIF_MSG_LINK, "pause_result 0x%x\n", pause_result); bnx2x_pause_resolve(vars, pause_result); - } else if ((params->req_flow_ctrl == FLOW_CTRL_AUTO) && + } else if ((params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) && (bnx2x_ext_phy_resove_fc(params, vars))) { return; } else { - if (params->req_flow_ctrl == FLOW_CTRL_AUTO) + if (params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) vars->flow_ctrl = params->req_fc_auto_adv; else vars->flow_ctrl = params->req_flow_ctrl; @@ -1728,11 +1728,11 @@ static u8 bnx2x_link_settings_status(struct link_params *params, LINK_STATUS_PARALLEL_DETECTION_USED; } - if (vars->flow_ctrl & FLOW_CTRL_TX) + if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX) vars->link_status |= LINK_STATUS_TX_FLOW_CONTROL_ENABLED; - if (vars->flow_ctrl & FLOW_CTRL_RX) + if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX) vars->link_status |= LINK_STATUS_RX_FLOW_CONTROL_ENABLED; @@ -1742,7 +1742,7 @@ static u8 bnx2x_link_settings_status(struct link_params *params, vars->phy_link_up = 0; vars->duplex = DUPLEX_FULL; - vars->flow_ctrl = FLOW_CTRL_NONE; + vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; vars->autoneg = AUTO_NEG_DISABLED; vars->mac_type = MAC_TYPE_NONE; } @@ -3924,7 +3924,7 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) vars->link_up = 0; vars->line_speed = 0; vars->duplex = DUPLEX_FULL; - vars->flow_ctrl = FLOW_CTRL_NONE; + vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; vars->mac_type = MAC_TYPE_NONE; if (params->switch_cfg == SWITCH_CFG_1G) @@ -3946,12 +3946,12 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) vars->link_up = 1; vars->line_speed = SPEED_10000; vars->duplex = DUPLEX_FULL; - vars->flow_ctrl = FLOW_CTRL_NONE; + vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD); /* enable on E1.5 FPGA */ if (CHIP_IS_E1H(bp)) { vars->flow_ctrl |= - (FLOW_CTRL_TX | FLOW_CTRL_RX); + (BNX2X_FLOW_CTRL_TX | BNX2X_FLOW_CTRL_RX); vars->link_status |= (LINK_STATUS_TX_FLOW_CONTROL_ENABLED | LINK_STATUS_RX_FLOW_CONTROL_ENABLED); @@ -3974,7 +3974,7 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) vars->link_up = 1; vars->line_speed = SPEED_10000; vars->duplex = DUPLEX_FULL; - vars->flow_ctrl = FLOW_CTRL_NONE; + vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD); bnx2x_bmac_enable(params, vars, 0); @@ -3994,7 +3994,7 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) vars->link_up = 1; vars->line_speed = SPEED_10000; vars->duplex = DUPLEX_FULL; - vars->flow_ctrl = FLOW_CTRL_NONE; + vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; vars->mac_type = MAC_TYPE_BMAC; vars->phy_flags = PHY_XGXS_FLAG; @@ -4009,7 +4009,7 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) vars->link_up = 1; vars->line_speed = SPEED_1000; vars->duplex = DUPLEX_FULL; - vars->flow_ctrl = FLOW_CTRL_NONE; + vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; vars->mac_type = MAC_TYPE_EMAC; vars->phy_flags = PHY_XGXS_FLAG; @@ -4026,7 +4026,7 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) vars->link_up = 1; vars->line_speed = SPEED_10000; vars->duplex = DUPLEX_FULL; - vars->flow_ctrl = FLOW_CTRL_NONE; + vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; vars->phy_flags = PHY_XGXS_FLAG; diff --git a/drivers/net/bnx2x_link.h b/drivers/net/bnx2x_link.h index 86d54a17b41127c7bcb278d7e3b971305c6a3b27..47cb585f4278a8680b0eba010eeb8f145d040b8d 100644 --- a/drivers/net/bnx2x_link.h +++ b/drivers/net/bnx2x_link.h @@ -26,11 +26,11 @@ -#define FLOW_CTRL_AUTO PORT_FEATURE_FLOW_CONTROL_AUTO -#define FLOW_CTRL_TX PORT_FEATURE_FLOW_CONTROL_TX -#define FLOW_CTRL_RX PORT_FEATURE_FLOW_CONTROL_RX -#define FLOW_CTRL_BOTH PORT_FEATURE_FLOW_CONTROL_BOTH -#define FLOW_CTRL_NONE PORT_FEATURE_FLOW_CONTROL_NONE +#define BNX2X_FLOW_CTRL_AUTO PORT_FEATURE_FLOW_CONTROL_AUTO +#define BNX2X_FLOW_CTRL_TX PORT_FEATURE_FLOW_CONTROL_TX +#define BNX2X_FLOW_CTRL_RX PORT_FEATURE_FLOW_CONTROL_RX +#define BNX2X_FLOW_CTRL_BOTH PORT_FEATURE_FLOW_CONTROL_BOTH +#define BNX2X_FLOW_CTRL_NONE PORT_FEATURE_FLOW_CONTROL_NONE #define SPEED_AUTO_NEG 0 #define SPEED_12000 12000 diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 600210d7eff95da4f60840b530f149cec8259e45..ef8103b3523e0e80695caf1d032034c6ff3c9b6b 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -1328,7 +1328,6 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp, dev_kfree_skb(skb); } - bp->dev->last_rx = jiffies; /* put new skb in bin */ fp->tpa_pool[queue].skb = new_skb; @@ -1557,7 +1556,6 @@ static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget) #endif netif_receive_skb(skb); - bp->dev->last_rx = jiffies; next_rx: rx_buf->skb = NULL; @@ -1594,7 +1592,6 @@ static irqreturn_t bnx2x_msix_fp_int(int irq, void *fp_cookie) { struct bnx2x_fastpath *fp = fp_cookie; struct bnx2x *bp = fp->bp; - struct net_device *dev = bp->dev; int index = FP_IDX(fp); /* Return here if interrupt is disabled */ @@ -1617,7 +1614,7 @@ static irqreturn_t bnx2x_msix_fp_int(int irq, void *fp_cookie) prefetch(&fp->status_blk->c_status_block.status_block_index); prefetch(&fp->status_blk->u_status_block.status_block_index); - netif_rx_schedule(dev, &bnx2x_fp(bp, index, napi)); + netif_rx_schedule(&bnx2x_fp(bp, index, napi)); return IRQ_HANDLED; } @@ -1656,7 +1653,7 @@ static irqreturn_t bnx2x_interrupt(int irq, void *dev_instance) prefetch(&fp->status_blk->c_status_block.status_block_index); prefetch(&fp->status_blk->u_status_block.status_block_index); - netif_rx_schedule(dev, &bnx2x_fp(bp, 0, napi)); + netif_rx_schedule(&bnx2x_fp(bp, 0, napi)); status &= ~mask; } @@ -1923,10 +1920,10 @@ static void bnx2x_link_report(struct bnx2x *bp) else printk("half duplex"); - if (bp->link_vars.flow_ctrl != FLOW_CTRL_NONE) { - if (bp->link_vars.flow_ctrl & FLOW_CTRL_RX) { + if (bp->link_vars.flow_ctrl != BNX2X_FLOW_CTRL_NONE) { + if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_RX) { printk(", receive "); - if (bp->link_vars.flow_ctrl & FLOW_CTRL_TX) + if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_TX) printk("& transmit "); } else { printk(", transmit "); @@ -1950,11 +1947,11 @@ static u8 bnx2x_initial_phy_init(struct bnx2x *bp) /* It is recommended to turn off RX FC for jumbo frames for better performance */ if (IS_E1HMF(bp)) - bp->link_params.req_fc_auto_adv = FLOW_CTRL_BOTH; + bp->link_params.req_fc_auto_adv = BNX2X_FLOW_CTRL_BOTH; else if (bp->dev->mtu > 5000) - bp->link_params.req_fc_auto_adv = FLOW_CTRL_TX; + bp->link_params.req_fc_auto_adv = BNX2X_FLOW_CTRL_TX; else - bp->link_params.req_fc_auto_adv = FLOW_CTRL_BOTH; + bp->link_params.req_fc_auto_adv = BNX2X_FLOW_CTRL_BOTH; bnx2x_acquire_phy_lock(bp); rc = bnx2x_phy_init(&bp->link_params, &bp->link_vars); @@ -7364,9 +7361,9 @@ static void __devinit bnx2x_link_settings_requested(struct bnx2x *bp) bp->link_params.req_flow_ctrl = (bp->port.link_config & PORT_FEATURE_FLOW_CONTROL_MASK); - if ((bp->link_params.req_flow_ctrl == FLOW_CTRL_AUTO) && + if ((bp->link_params.req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) && !(bp->port.supported & SUPPORTED_Autoneg)) - bp->link_params.req_flow_ctrl = FLOW_CTRL_NONE; + bp->link_params.req_flow_ctrl = BNX2X_FLOW_CTRL_NONE; BNX2X_DEV_INFO("req_line_speed %d req_duplex %d req_flow_ctrl 0x%x" " advertising 0x%x\n", @@ -8355,13 +8352,13 @@ static void bnx2x_get_pauseparam(struct net_device *dev, { struct bnx2x *bp = netdev_priv(dev); - epause->autoneg = (bp->link_params.req_flow_ctrl == FLOW_CTRL_AUTO) && + epause->autoneg = (bp->link_params.req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) && (bp->link_params.req_line_speed == SPEED_AUTO_NEG); - epause->rx_pause = ((bp->link_vars.flow_ctrl & FLOW_CTRL_RX) == - FLOW_CTRL_RX); - epause->tx_pause = ((bp->link_vars.flow_ctrl & FLOW_CTRL_TX) == - FLOW_CTRL_TX); + epause->rx_pause = ((bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_RX) == + BNX2X_FLOW_CTRL_RX); + epause->tx_pause = ((bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_TX) == + BNX2X_FLOW_CTRL_TX); DP(NETIF_MSG_LINK, "ethtool_pauseparam: cmd %d\n" DP_LEVEL " autoneg %d rx_pause %d tx_pause %d\n", @@ -8380,16 +8377,16 @@ static int bnx2x_set_pauseparam(struct net_device *dev, DP_LEVEL " autoneg %d rx_pause %d tx_pause %d\n", epause->cmd, epause->autoneg, epause->rx_pause, epause->tx_pause); - bp->link_params.req_flow_ctrl = FLOW_CTRL_AUTO; + bp->link_params.req_flow_ctrl = BNX2X_FLOW_CTRL_AUTO; if (epause->rx_pause) - bp->link_params.req_flow_ctrl |= FLOW_CTRL_RX; + bp->link_params.req_flow_ctrl |= BNX2X_FLOW_CTRL_RX; if (epause->tx_pause) - bp->link_params.req_flow_ctrl |= FLOW_CTRL_TX; + bp->link_params.req_flow_ctrl |= BNX2X_FLOW_CTRL_TX; - if (bp->link_params.req_flow_ctrl == FLOW_CTRL_AUTO) - bp->link_params.req_flow_ctrl = FLOW_CTRL_NONE; + if (bp->link_params.req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) + bp->link_params.req_flow_ctrl = BNX2X_FLOW_CTRL_NONE; if (epause->autoneg) { if (!(bp->port.supported & SUPPORTED_Autoneg)) { @@ -8398,7 +8395,7 @@ static int bnx2x_set_pauseparam(struct net_device *dev, } if (bp->link_params.req_line_speed == SPEED_AUTO_NEG) - bp->link_params.req_flow_ctrl = FLOW_CTRL_AUTO; + bp->link_params.req_flow_ctrl = BNX2X_FLOW_CTRL_AUTO; } DP(NETIF_MSG_LINK, @@ -8769,7 +8766,6 @@ static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode, u8 link_up) rc = 0; test_loopback_rx_exit: - bp->dev->last_rx = jiffies; fp->rx_bd_cons = NEXT_RX_IDX(fp->rx_bd_cons); fp->rx_bd_prod = NEXT_RX_IDX(fp->rx_bd_prod); @@ -9287,7 +9283,7 @@ static int bnx2x_poll(struct napi_struct *napi, int budget) #ifdef BNX2X_STOP_ON_ERROR poll_panic: #endif - netif_rx_complete(bp->dev, napi); + netif_rx_complete(napi); bnx2x_ack_sb(bp, FP_SB_ID(fp), USTORM_ID, le16_to_cpu(fp->fp_u_idx), IGU_INT_NOP, 1); @@ -9853,11 +9849,8 @@ static void bnx2x_set_rx_mode(struct net_device *dev) mclist && (i < dev->mc_count); i++, mclist = mclist->next) { - DP(NETIF_MSG_IFUP, "Adding mcast MAC: " - "%02x:%02x:%02x:%02x:%02x:%02x\n", - mclist->dmi_addr[0], mclist->dmi_addr[1], - mclist->dmi_addr[2], mclist->dmi_addr[3], - mclist->dmi_addr[4], mclist->dmi_addr[5]); + DP(NETIF_MSG_IFUP, "Adding mcast MAC: %pM\n", + mclist->dmi_addr); crc = crc32c_le(0, mclist->dmi_addr, ETH_ALEN); bit = (crc >> 24) & 0xff; @@ -10008,6 +10001,25 @@ static void poll_bnx2x(struct net_device *dev) } #endif +static const struct net_device_ops bnx2x_netdev_ops = { + .ndo_open = bnx2x_open, + .ndo_stop = bnx2x_close, + .ndo_start_xmit = bnx2x_start_xmit, + .ndo_set_multicast_list = bnx2x_set_rx_mode, + .ndo_set_mac_address = bnx2x_change_mac_addr, + .ndo_validate_addr = eth_validate_addr, + .ndo_do_ioctl = bnx2x_ioctl, + .ndo_change_mtu = bnx2x_change_mtu, + .ndo_tx_timeout = bnx2x_tx_timeout, +#ifdef BCM_VLAN + .ndo_vlan_rx_register = bnx2x_vlan_rx_register, +#endif +#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER) + .ndo_poll_controller = poll_bnx2x, +#endif +}; + + static int __devinit bnx2x_init_dev(struct pci_dev *pdev, struct net_device *dev) { @@ -10092,8 +10104,7 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev, dev->irq = pdev->irq; - bp->regview = ioremap_nocache(dev->base_addr, - pci_resource_len(pdev, 0)); + bp->regview = pci_ioremap_bar(pdev, 0); if (!bp->regview) { printk(KERN_ERR PFX "Cannot map register space, aborting\n"); rc = -ENOMEM; @@ -10119,23 +10130,10 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev, REG_WR(bp, PXP2_REG_PGL_ADDR_90_F0 + BP_PORT(bp)*16, 0); REG_WR(bp, PXP2_REG_PGL_ADDR_94_F0 + BP_PORT(bp)*16, 0); - dev->hard_start_xmit = bnx2x_start_xmit; dev->watchdog_timeo = TX_TIMEOUT; + dev->netdev_ops = &bnx2x_netdev_ops; dev->ethtool_ops = &bnx2x_ethtool_ops; - dev->open = bnx2x_open; - dev->stop = bnx2x_close; - dev->set_multicast_list = bnx2x_set_rx_mode; - dev->set_mac_address = bnx2x_change_mac_addr; - dev->do_ioctl = bnx2x_ioctl; - dev->change_mtu = bnx2x_change_mtu; - dev->tx_timeout = bnx2x_tx_timeout; -#ifdef BCM_VLAN - dev->vlan_rx_register = bnx2x_vlan_rx_register; -#endif -#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER) - dev->poll_controller = poll_bnx2x; -#endif dev->features |= NETIF_F_SG; dev->features |= NETIF_F_HW_CSUM; if (bp->flags & USING_DAC_FLAG) @@ -10194,7 +10192,6 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev, struct net_device *dev = NULL; struct bnx2x *bp; int rc; - DECLARE_MAC_BUF(mac); if (version_printed++ == 0) printk(KERN_INFO "%s", version); @@ -10238,7 +10235,7 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev, bnx2x_get_pcie_width(bp), (bnx2x_get_pcie_speed(bp) == 2) ? "5GHz (Gen2)" : "2.5GHz", dev->base_addr, bp->pdev->irq); - printk(KERN_CONT "node addr %s\n", print_mac(mac, dev->dev_addr)); + printk(KERN_CONT "node addr %pM\n", dev->dev_addr); return 0; init_one_exit: diff --git a/drivers/net/bonding/Makefile b/drivers/net/bonding/Makefile index 5cdae2bc055a9c27d679af0793d97bce459c0fd1..6f9c6faef24c4079741128e2e88f18c2cea3f979 100644 --- a/drivers/net/bonding/Makefile +++ b/drivers/net/bonding/Makefile @@ -6,3 +6,6 @@ obj-$(CONFIG_BONDING) += bonding.o bonding-objs := bond_main.o bond_3ad.o bond_alb.o bond_sysfs.o +ipv6-$(subst m,y,$(CONFIG_IPV6)) += bond_ipv6.o +bonding-objs += $(ipv6-y) + diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 6106660a4a44b9a68f7a5b9a9c9c26a5b45ee689..8c2e5ab51f08fd35265eacd0b8881998fae8e6a8 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -20,13 +20,12 @@ * */ -//#define BONDING_DEBUG 1 - #include #include #include #include #include +#include #include #include #include @@ -96,33 +95,7 @@ static struct mac_addr null_mac_addr = {{0, 0, 0, 0, 0, 0}}; static u16 ad_ticks_per_sec; static const int ad_delta_in_ticks = (AD_TIMER_INTERVAL * HZ) / 1000; -// ================= 3AD api to bonding and kernel code ================== -static u16 __get_link_speed(struct port *port); -static u8 __get_duplex(struct port *port); -static inline void __initialize_port_locks(struct port *port); -//conversions -static u16 __ad_timer_to_ticks(u16 timer_type, u16 Par); - - -// ================= ad code helper functions ================== -//needed by ad_rx_machine(...) -static void __record_pdu(struct lacpdu *lacpdu, struct port *port); -static void __record_default(struct port *port); -static void __update_selected(struct lacpdu *lacpdu, struct port *port); -static void __update_default_selected(struct port *port); -static void __choose_matched(struct lacpdu *lacpdu, struct port *port); -static void __update_ntt(struct lacpdu *lacpdu, struct port *port); - -//needed for ad_mux_machine(..) -static void __attach_bond_to_agg(struct port *port); -static void __detach_bond_from_agg(struct port *port); -static int __agg_ports_are_ready(struct aggregator *aggregator); -static void __set_agg_ports_ready(struct aggregator *aggregator, int val); - -//needed for ad_agg_selection_logic(...) -static u32 __get_agg_bandwidth(struct aggregator *aggregator); -static struct aggregator *__get_active_agg(struct aggregator *aggregator); - +static const u8 lacpdu_mcast_addr[ETH_ALEN] = MULTICAST_LACPDU_ADDR; // ================= main 802.3ad protocol functions ================== static int ad_lacpdu_send(struct port *port); @@ -136,7 +109,6 @@ static void ad_agg_selection_logic(struct aggregator *aggregator); static void ad_clear_agg(struct aggregator *aggregator); static void ad_initialize_agg(struct aggregator *aggregator); static void ad_initialize_port(struct port *port, int lacp_fast); -static void ad_initialize_lacpdu(struct lacpdu *Lacpdu); static void ad_enable_collecting_distributing(struct port *port); static void ad_disable_collecting_distributing(struct port *port); static void ad_marker_info_received(struct bond_marker *marker_info, struct port *port); @@ -236,6 +208,17 @@ static inline struct aggregator *__get_next_agg(struct aggregator *aggregator) return &(SLAVE_AD_INFO(slave->next).aggregator); } +/* + * __agg_has_partner + * + * Return nonzero if aggregator has a partner (denoted by a non-zero ether + * address for the partner). Return 0 if not. + */ +static inline int __agg_has_partner(struct aggregator *agg) +{ + return !is_zero_ether_addr(agg->partner_system.mac_addr_value); +} + /** * __disable_port - disable the port's slave * @port: the port we're looking at @@ -274,14 +257,14 @@ static inline int __port_is_enabled(struct port *port) * __get_agg_selection_mode - get the aggregator selection mode * @port: the port we're looking at * - * Get the aggregator selection mode. Can be %BANDWIDTH or %COUNT. + * Get the aggregator selection mode. Can be %STABLE, %BANDWIDTH or %COUNT. */ static inline u32 __get_agg_selection_mode(struct port *port) { struct bonding *bond = __get_bond_by_port(port); if (bond == NULL) { - return AD_BANDWIDTH; + return BOND_AD_STABLE; } return BOND_AD_INFO(bond).agg_select_mode; @@ -369,7 +352,7 @@ static u16 __get_link_speed(struct port *port) } } - dprintk("Port %d Received link speed %d update from adapter\n", port->actor_port_number, speed); + pr_debug("Port %d Received link speed %d update from adapter\n", port->actor_port_number, speed); return speed; } @@ -395,12 +378,12 @@ static u8 __get_duplex(struct port *port) switch (slave->duplex) { case DUPLEX_FULL: retval=0x1; - dprintk("Port %d Received status full duplex update from adapter\n", port->actor_port_number); + pr_debug("Port %d Received status full duplex update from adapter\n", port->actor_port_number); break; case DUPLEX_HALF: default: retval=0x0; - dprintk("Port %d Received status NOT full duplex update from adapter\n", port->actor_port_number); + pr_debug("Port %d Received status NOT full duplex update from adapter\n", port->actor_port_number); break; } } @@ -473,33 +456,25 @@ static u16 __ad_timer_to_ticks(u16 timer_type, u16 par) */ static void __record_pdu(struct lacpdu *lacpdu, struct port *port) { - // validate lacpdu and port if (lacpdu && port) { + struct port_params *partner = &port->partner_oper; + // record the new parameter values for the partner operational - port->partner_oper_port_number = ntohs(lacpdu->actor_port); - port->partner_oper_port_priority = ntohs(lacpdu->actor_port_priority); - port->partner_oper_system = lacpdu->actor_system; - port->partner_oper_system_priority = ntohs(lacpdu->actor_system_priority); - port->partner_oper_key = ntohs(lacpdu->actor_key); - // zero partener's lase states - port->partner_oper_port_state = 0; - port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_LACP_ACTIVITY); - port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_LACP_TIMEOUT); - port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_AGGREGATION); - port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_SYNCHRONIZATION); - port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_COLLECTING); - port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_DISTRIBUTING); - port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_DEFAULTED); - port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_EXPIRED); + partner->port_number = ntohs(lacpdu->actor_port); + partner->port_priority = ntohs(lacpdu->actor_port_priority); + partner->system = lacpdu->actor_system; + partner->system_priority = ntohs(lacpdu->actor_system_priority); + partner->key = ntohs(lacpdu->actor_key); + partner->port_state = lacpdu->actor_state; // set actor_oper_port_state.defaulted to FALSE port->actor_oper_port_state &= ~AD_STATE_DEFAULTED; // set the partner sync. to on if the partner is sync. and the port is matched if ((port->sm_vars & AD_PORT_MATCHED) && (lacpdu->actor_state & AD_STATE_SYNCHRONIZATION)) { - port->partner_oper_port_state |= AD_STATE_SYNCHRONIZATION; + partner->port_state |= AD_STATE_SYNCHRONIZATION; } else { - port->partner_oper_port_state &= ~AD_STATE_SYNCHRONIZATION; + partner->port_state &= ~AD_STATE_SYNCHRONIZATION; } } } @@ -514,15 +489,10 @@ static void __record_pdu(struct lacpdu *lacpdu, struct port *port) */ static void __record_default(struct port *port) { - // validate the port if (port) { // record the partner admin parameters - port->partner_oper_port_number = port->partner_admin_port_number; - port->partner_oper_port_priority = port->partner_admin_port_priority; - port->partner_oper_system = port->partner_admin_system; - port->partner_oper_system_priority = port->partner_admin_system_priority; - port->partner_oper_key = port->partner_admin_key; - port->partner_oper_port_state = port->partner_admin_port_state; + memcpy(&port->partner_oper, &port->partner_admin, + sizeof(struct port_params)); // set actor_oper_port_state.defaulted to true port->actor_oper_port_state |= AD_STATE_DEFAULTED; @@ -544,16 +514,16 @@ static void __record_default(struct port *port) */ static void __update_selected(struct lacpdu *lacpdu, struct port *port) { - // validate lacpdu and port if (lacpdu && port) { + const struct port_params *partner = &port->partner_oper; + // check if any parameter is different - if ((ntohs(lacpdu->actor_port) != port->partner_oper_port_number) || - (ntohs(lacpdu->actor_port_priority) != port->partner_oper_port_priority) || - MAC_ADDRESS_COMPARE(&(lacpdu->actor_system), &(port->partner_oper_system)) || - (ntohs(lacpdu->actor_system_priority) != port->partner_oper_system_priority) || - (ntohs(lacpdu->actor_key) != port->partner_oper_key) || - ((lacpdu->actor_state & AD_STATE_AGGREGATION) != (port->partner_oper_port_state & AD_STATE_AGGREGATION)) - ) { + if (ntohs(lacpdu->actor_port) != partner->port_number + || ntohs(lacpdu->actor_port_priority) != partner->port_priority + || MAC_ADDRESS_COMPARE(&lacpdu->actor_system, &partner->system) + || ntohs(lacpdu->actor_system_priority) != partner->system_priority + || ntohs(lacpdu->actor_key) != partner->key + || (lacpdu->actor_state & AD_STATE_AGGREGATION) != (partner->port_state & AD_STATE_AGGREGATION)) { // update the state machine Selected variable port->sm_vars &= ~AD_PORT_SELECTED; } @@ -574,16 +544,18 @@ static void __update_selected(struct lacpdu *lacpdu, struct port *port) */ static void __update_default_selected(struct port *port) { - // validate the port if (port) { + const struct port_params *admin = &port->partner_admin; + const struct port_params *oper = &port->partner_oper; + // check if any parameter is different - if ((port->partner_admin_port_number != port->partner_oper_port_number) || - (port->partner_admin_port_priority != port->partner_oper_port_priority) || - MAC_ADDRESS_COMPARE(&(port->partner_admin_system), &(port->partner_oper_system)) || - (port->partner_admin_system_priority != port->partner_oper_system_priority) || - (port->partner_admin_key != port->partner_oper_key) || - ((port->partner_admin_port_state & AD_STATE_AGGREGATION) != (port->partner_oper_port_state & AD_STATE_AGGREGATION)) - ) { + if (admin->port_number != oper->port_number + || admin->port_priority != oper->port_priority + || MAC_ADDRESS_COMPARE(&admin->system, &oper->system) + || admin->system_priority != oper->system_priority + || admin->key != oper->key + || (admin->port_state & AD_STATE_AGGREGATION) + != (oper->port_state & AD_STATE_AGGREGATION)) { // update the state machine Selected variable port->sm_vars &= ~AD_PORT_SELECTED; } @@ -658,8 +630,8 @@ static void __update_ntt(struct lacpdu *lacpdu, struct port *port) ((lacpdu->partner_state & AD_STATE_SYNCHRONIZATION) != (port->actor_oper_port_state & AD_STATE_SYNCHRONIZATION)) || ((lacpdu->partner_state & AD_STATE_AGGREGATION) != (port->actor_oper_port_state & AD_STATE_AGGREGATION)) ) { - // set ntt to be TRUE - port->ntt = 1; + + port->ntt = true; } } } @@ -798,6 +770,7 @@ static struct aggregator *__get_active_agg(struct aggregator *aggregator) static inline void __update_lacpdu_from_port(struct port *port) { struct lacpdu *lacpdu = &port->lacpdu; + const struct port_params *partner = &port->partner_oper; /* update current actual Actor parameters */ /* lacpdu->subtype initialized @@ -818,12 +791,12 @@ static inline void __update_lacpdu_from_port(struct port *port) * lacpdu->partner_information_length initialized */ - lacpdu->partner_system_priority = htons(port->partner_oper_system_priority); - lacpdu->partner_system = port->partner_oper_system; - lacpdu->partner_key = htons(port->partner_oper_key); - lacpdu->partner_port_priority = htons(port->partner_oper_port_priority); - lacpdu->partner_port = htons(port->partner_oper_port_number); - lacpdu->partner_state = port->partner_oper_port_state; + lacpdu->partner_system_priority = htons(partner->system_priority); + lacpdu->partner_system = partner->system; + lacpdu->partner_key = htons(partner->key); + lacpdu->partner_port_priority = htons(partner->port_priority); + lacpdu->partner_port = htons(partner->port_number); + lacpdu->partner_state = partner->port_state; /* lacpdu->reserved_3_2 initialized * lacpdu->tlv_type_collector_info initialized @@ -853,7 +826,6 @@ static int ad_lacpdu_send(struct port *port) struct sk_buff *skb; struct lacpdu_header *lacpdu_header; int length = sizeof(struct lacpdu_header); - struct mac_addr lacpdu_multicast_address = AD_MULTICAST_LACPDU_ADDR; skb = dev_alloc_skb(length); if (!skb) { @@ -868,11 +840,11 @@ static int ad_lacpdu_send(struct port *port) lacpdu_header = (struct lacpdu_header *)skb_put(skb, length); - lacpdu_header->ad_header.destination_address = lacpdu_multicast_address; - /* Note: source addres is set to be the member's PERMANENT address, because we use it - to identify loopback lacpdus in receive. */ - lacpdu_header->ad_header.source_address = *((struct mac_addr *)(slave->perm_hwaddr)); - lacpdu_header->ad_header.length_type = PKT_TYPE_LACPDU; + memcpy(lacpdu_header->hdr.h_dest, lacpdu_mcast_addr, ETH_ALEN); + /* Note: source addres is set to be the member's PERMANENT address, + because we use it to identify loopback lacpdus in receive. */ + memcpy(lacpdu_header->hdr.h_source, slave->perm_hwaddr, ETH_ALEN); + lacpdu_header->hdr.h_proto = PKT_TYPE_LACPDU; lacpdu_header->lacpdu = port->lacpdu; // struct copy @@ -895,7 +867,6 @@ static int ad_marker_send(struct port *port, struct bond_marker *marker) struct sk_buff *skb; struct bond_marker_header *marker_header; int length = sizeof(struct bond_marker_header); - struct mac_addr lacpdu_multicast_address = AD_MULTICAST_LACPDU_ADDR; skb = dev_alloc_skb(length + 16); if (!skb) { @@ -911,11 +882,11 @@ static int ad_marker_send(struct port *port, struct bond_marker *marker) marker_header = (struct bond_marker_header *)skb_put(skb, length); - marker_header->ad_header.destination_address = lacpdu_multicast_address; - /* Note: source addres is set to be the member's PERMANENT address, because we use it - to identify loopback MARKERs in receive. */ - marker_header->ad_header.source_address = *((struct mac_addr *)(slave->perm_hwaddr)); - marker_header->ad_header.length_type = PKT_TYPE_LACPDU; + memcpy(marker_header->hdr.h_dest, lacpdu_mcast_addr, ETH_ALEN); + /* Note: source addres is set to be the member's PERMANENT address, + because we use it to identify loopback MARKERs in receive. */ + memcpy(marker_header->hdr.h_source, slave->perm_hwaddr, ETH_ALEN); + marker_header->hdr.h_proto = PKT_TYPE_LACPDU; marker_header->marker = *marker; // struct copy @@ -972,7 +943,7 @@ static void ad_mux_machine(struct port *port) break; case AD_MUX_ATTACHED: // check also if agg_select_timer expired(so the edable port will take place only after this timer) - if ((port->sm_vars & AD_PORT_SELECTED) && (port->partner_oper_port_state & AD_STATE_SYNCHRONIZATION) && !__check_agg_selection_timer(port)) { + if ((port->sm_vars & AD_PORT_SELECTED) && (port->partner_oper.port_state & AD_STATE_SYNCHRONIZATION) && !__check_agg_selection_timer(port)) { port->sm_mux_state = AD_MUX_COLLECTING_DISTRIBUTING;// next state } else if (!(port->sm_vars & AD_PORT_SELECTED) || (port->sm_vars & AD_PORT_STANDBY)) { // if UNSELECTED or STANDBY port->sm_vars &= ~AD_PORT_READY_N; @@ -984,7 +955,7 @@ static void ad_mux_machine(struct port *port) break; case AD_MUX_COLLECTING_DISTRIBUTING: if (!(port->sm_vars & AD_PORT_SELECTED) || (port->sm_vars & AD_PORT_STANDBY) || - !(port->partner_oper_port_state & AD_STATE_SYNCHRONIZATION) + !(port->partner_oper.port_state & AD_STATE_SYNCHRONIZATION) ) { port->sm_mux_state = AD_MUX_ATTACHED;// next state @@ -1007,7 +978,7 @@ static void ad_mux_machine(struct port *port) // check if the state machine was changed if (port->sm_mux_state != last_state) { - dprintk("Mux Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_mux_state); + pr_debug("Mux Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_mux_state); switch (port->sm_mux_state) { case AD_MUX_DETACHED: __detach_bond_from_agg(port); @@ -1015,7 +986,7 @@ static void ad_mux_machine(struct port *port) ad_disable_collecting_distributing(port); port->actor_oper_port_state &= ~AD_STATE_COLLECTING; port->actor_oper_port_state &= ~AD_STATE_DISTRIBUTING; - port->ntt = 1; + port->ntt = true; break; case AD_MUX_WAITING: port->sm_mux_timer_counter = __ad_timer_to_ticks(AD_WAIT_WHILE_TIMER, 0); @@ -1026,13 +997,13 @@ static void ad_mux_machine(struct port *port) port->actor_oper_port_state &= ~AD_STATE_COLLECTING; port->actor_oper_port_state &= ~AD_STATE_DISTRIBUTING; ad_disable_collecting_distributing(port); - port->ntt = 1; + port->ntt = true; break; case AD_MUX_COLLECTING_DISTRIBUTING: port->actor_oper_port_state |= AD_STATE_COLLECTING; port->actor_oper_port_state |= AD_STATE_DISTRIBUTING; ad_enable_collecting_distributing(port); - port->ntt = 1; + port->ntt = true; break; default: //to silence the compiler break; @@ -1106,7 +1077,7 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port) // check if the State machine was changed or new lacpdu arrived if ((port->sm_rx_state != last_state) || (lacpdu)) { - dprintk("Rx Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_rx_state); + pr_debug("Rx Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_rx_state); switch (port->sm_rx_state) { case AD_RX_INITIALIZE: if (!(port->actor_oper_port_key & AD_DUPLEX_KEY_BITS)) { @@ -1128,7 +1099,7 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port) case AD_RX_LACP_DISABLED: port->sm_vars &= ~AD_PORT_SELECTED; __record_default(port); - port->partner_oper_port_state &= ~AD_STATE_AGGREGATION; + port->partner_oper.port_state &= ~AD_STATE_AGGREGATION; port->sm_vars |= AD_PORT_MATCHED; port->actor_oper_port_state &= ~AD_STATE_EXPIRED; break; @@ -1136,9 +1107,9 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port) //Reset of the Synchronization flag. (Standard 43.4.12) //This reset cause to disable this port in the COLLECTING_DISTRIBUTING state of the //mux machine in case of EXPIRED even if LINK_DOWN didn't arrive for the port. - port->partner_oper_port_state &= ~AD_STATE_SYNCHRONIZATION; + port->partner_oper.port_state &= ~AD_STATE_SYNCHRONIZATION; port->sm_vars &= ~AD_PORT_MATCHED; - port->partner_oper_port_state |= AD_SHORT_TIMEOUT; + port->partner_oper.port_state |= AD_SHORT_TIMEOUT; port->sm_rx_timer_counter = __ad_timer_to_ticks(AD_CURRENT_WHILE_TIMER, (u16)(AD_SHORT_TIMEOUT)); port->actor_oper_port_state |= AD_STATE_EXPIRED; break; @@ -1191,11 +1162,13 @@ static void ad_tx_machine(struct port *port) // check if there is something to send if (port->ntt && (port->sm_vars & AD_PORT_LACP_ENABLED)) { __update_lacpdu_from_port(port); - // send the lacpdu + if (ad_lacpdu_send(port) >= 0) { - dprintk("Sent LACPDU on port %d\n", port->actor_port_number); - // mark ntt as false, so it will not be sent again until demanded - port->ntt = 0; + pr_debug("Sent LACPDU on port %d\n", port->actor_port_number); + + /* mark ntt as false, so it will not be sent again until + demanded */ + port->ntt = false; } } // restart tx timer(to verify that we will not exceed AD_MAX_TX_IN_SECOND @@ -1218,7 +1191,7 @@ static void ad_periodic_machine(struct port *port) // check if port was reinitialized if (((port->sm_vars & AD_PORT_BEGIN) || !(port->sm_vars & AD_PORT_LACP_ENABLED) || !port->is_enabled) || - (!(port->actor_oper_port_state & AD_STATE_LACP_ACTIVITY) && !(port->partner_oper_port_state & AD_STATE_LACP_ACTIVITY)) + (!(port->actor_oper_port_state & AD_STATE_LACP_ACTIVITY) && !(port->partner_oper.port_state & AD_STATE_LACP_ACTIVITY)) ) { port->sm_periodic_state = AD_NO_PERIODIC; // next state } @@ -1232,12 +1205,12 @@ static void ad_periodic_machine(struct port *port) // If not expired, check if there is some new timeout parameter from the partner state switch (port->sm_periodic_state) { case AD_FAST_PERIODIC: - if (!(port->partner_oper_port_state & AD_STATE_LACP_TIMEOUT)) { + if (!(port->partner_oper.port_state & AD_STATE_LACP_TIMEOUT)) { port->sm_periodic_state = AD_SLOW_PERIODIC; // next state } break; case AD_SLOW_PERIODIC: - if ((port->partner_oper_port_state & AD_STATE_LACP_TIMEOUT)) { + if ((port->partner_oper.port_state & AD_STATE_LACP_TIMEOUT)) { // stop current timer port->sm_periodic_timer_counter = 0; port->sm_periodic_state = AD_PERIODIC_TX; // next state @@ -1253,7 +1226,7 @@ static void ad_periodic_machine(struct port *port) port->sm_periodic_state = AD_FAST_PERIODIC; // next state break; case AD_PERIODIC_TX: - if (!(port->partner_oper_port_state & AD_STATE_LACP_TIMEOUT)) { + if (!(port->partner_oper.port_state & AD_STATE_LACP_TIMEOUT)) { port->sm_periodic_state = AD_SLOW_PERIODIC; // next state } else { port->sm_periodic_state = AD_FAST_PERIODIC; // next state @@ -1266,7 +1239,7 @@ static void ad_periodic_machine(struct port *port) // check if the state machine was changed if (port->sm_periodic_state != last_state) { - dprintk("Periodic Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_periodic_state); + pr_debug("Periodic Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_periodic_state); switch (port->sm_periodic_state) { case AD_NO_PERIODIC: port->sm_periodic_timer_counter = 0; // zero timer @@ -1278,7 +1251,7 @@ static void ad_periodic_machine(struct port *port) port->sm_periodic_timer_counter = __ad_timer_to_ticks(AD_PERIODIC_TIMER, (u16)(AD_SLOW_PERIODIC_TIME))-1; // decrement 1 tick we lost in the PERIODIC_TX cycle break; case AD_PERIODIC_TX: - port->ntt = 1; + port->ntt = true; break; default: //to silence the compiler break; @@ -1323,7 +1296,7 @@ static void ad_port_selection_logic(struct port *port) port->next_port_in_aggregator=NULL; port->actor_port_aggregator_identifier=0; - dprintk("Port %d left LAG %d\n", port->actor_port_number, temp_aggregator->aggregator_identifier); + pr_debug("Port %d left LAG %d\n", port->actor_port_number, temp_aggregator->aggregator_identifier); // if the aggregator is empty, clear its parameters, and set it ready to be attached if (!temp_aggregator->lag_ports) { ad_clear_agg(temp_aggregator); @@ -1352,11 +1325,11 @@ static void ad_port_selection_logic(struct port *port) } // check if current aggregator suits us if (((aggregator->actor_oper_aggregator_key == port->actor_oper_port_key) && // if all parameters match AND - !MAC_ADDRESS_COMPARE(&(aggregator->partner_system), &(port->partner_oper_system)) && - (aggregator->partner_system_priority == port->partner_oper_system_priority) && - (aggregator->partner_oper_aggregator_key == port->partner_oper_key) + !MAC_ADDRESS_COMPARE(&(aggregator->partner_system), &(port->partner_oper.system)) && + (aggregator->partner_system_priority == port->partner_oper.system_priority) && + (aggregator->partner_oper_aggregator_key == port->partner_oper.key) ) && - ((MAC_ADDRESS_COMPARE(&(port->partner_oper_system), &(null_mac_addr)) && // partner answers + ((MAC_ADDRESS_COMPARE(&(port->partner_oper.system), &(null_mac_addr)) && // partner answers !aggregator->is_individual) // but is not individual OR ) ) { @@ -1366,7 +1339,7 @@ static void ad_port_selection_logic(struct port *port) port->next_port_in_aggregator=aggregator->lag_ports; port->aggregator->num_of_ports++; aggregator->lag_ports=port; - dprintk("Port %d joined LAG %d(existing LAG)\n", port->actor_port_number, port->aggregator->aggregator_identifier); + pr_debug("Port %d joined LAG %d(existing LAG)\n", port->actor_port_number, port->aggregator->aggregator_identifier); // mark this port as selected port->sm_vars |= AD_PORT_SELECTED; @@ -1385,16 +1358,16 @@ static void ad_port_selection_logic(struct port *port) // update the new aggregator's parameters // if port was responsed from the end-user if (port->actor_oper_port_key & AD_DUPLEX_KEY_BITS) {// if port is full duplex - port->aggregator->is_individual = 0; + port->aggregator->is_individual = false; } else { - port->aggregator->is_individual = 1; + port->aggregator->is_individual = true; } port->aggregator->actor_admin_aggregator_key = port->actor_admin_port_key; port->aggregator->actor_oper_aggregator_key = port->actor_oper_port_key; - port->aggregator->partner_system=port->partner_oper_system; - port->aggregator->partner_system_priority = port->partner_oper_system_priority; - port->aggregator->partner_oper_aggregator_key = port->partner_oper_key; + port->aggregator->partner_system=port->partner_oper.system; + port->aggregator->partner_system_priority = port->partner_oper.system_priority; + port->aggregator->partner_oper_aggregator_key = port->partner_oper.key; port->aggregator->receive_state = 1; port->aggregator->transmit_state = 1; port->aggregator->lag_ports = port; @@ -1403,7 +1376,7 @@ static void ad_port_selection_logic(struct port *port) // mark this port as selected port->sm_vars |= AD_PORT_SELECTED; - dprintk("Port %d joined LAG %d(new LAG)\n", port->actor_port_number, port->aggregator->aggregator_identifier); + pr_debug("Port %d joined LAG %d(new LAG)\n", port->actor_port_number, port->aggregator->aggregator_identifier); } else { printk(KERN_ERR DRV_NAME ": %s: Port %d (on %s) did not find a suitable aggregator\n", port->slave->dev->master->name, @@ -1414,9 +1387,82 @@ static void ad_port_selection_logic(struct port *port) // else set ready=FALSE in all aggregator's ports __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator)); - if (!__check_agg_selection_timer(port) && (aggregator = __get_first_agg(port))) { - ad_agg_selection_logic(aggregator); + aggregator = __get_first_agg(port); + ad_agg_selection_logic(aggregator); +} + +/* + * Decide if "agg" is a better choice for the new active aggregator that + * the current best, according to the ad_select policy. + */ +static struct aggregator *ad_agg_selection_test(struct aggregator *best, + struct aggregator *curr) +{ + /* + * 0. If no best, select current. + * + * 1. If the current agg is not individual, and the best is + * individual, select current. + * + * 2. If current agg is individual and the best is not, keep best. + * + * 3. Therefore, current and best are both individual or both not + * individual, so: + * + * 3a. If current agg partner replied, and best agg partner did not, + * select current. + * + * 3b. If current agg partner did not reply and best agg partner + * did reply, keep best. + * + * 4. Therefore, current and best both have partner replies or + * both do not, so perform selection policy: + * + * BOND_AD_COUNT: Select by count of ports. If count is equal, + * select by bandwidth. + * + * BOND_AD_STABLE, BOND_AD_BANDWIDTH: Select by bandwidth. + */ + if (!best) + return curr; + + if (!curr->is_individual && best->is_individual) + return curr; + + if (curr->is_individual && !best->is_individual) + return best; + + if (__agg_has_partner(curr) && !__agg_has_partner(best)) + return curr; + + if (!__agg_has_partner(curr) && __agg_has_partner(best)) + return best; + + switch (__get_agg_selection_mode(curr->lag_ports)) { + case BOND_AD_COUNT: + if (curr->num_of_ports > best->num_of_ports) + return curr; + + if (curr->num_of_ports < best->num_of_ports) + return best; + + /*FALLTHROUGH*/ + case BOND_AD_STABLE: + case BOND_AD_BANDWIDTH: + if (__get_agg_bandwidth(curr) > __get_agg_bandwidth(best)) + return curr; + + break; + + default: + printk(KERN_WARNING DRV_NAME + ": %s: Impossible agg select mode %d\n", + curr->slave->dev->master->name, + __get_agg_selection_mode(curr->lag_ports)); + break; } + + return best; } /** @@ -1424,156 +1470,138 @@ static void ad_port_selection_logic(struct port *port) * @aggregator: the aggregator we're looking at * * It is assumed that only one aggregator may be selected for a team. - * The logic of this function is to select (at first time) the aggregator with - * the most ports attached to it, and to reselect the active aggregator only if - * the previous aggregator has no more ports related to it. + * + * The logic of this function is to select the aggregator according to + * the ad_select policy: + * + * BOND_AD_STABLE: select the aggregator with the most ports attached to + * it, and to reselect the active aggregator only if the previous + * aggregator has no more ports related to it. + * + * BOND_AD_BANDWIDTH: select the aggregator with the highest total + * bandwidth, and reselect whenever a link state change takes place or the + * set of slaves in the bond changes. + * + * BOND_AD_COUNT: select the aggregator with largest number of ports + * (slaves), and reselect whenever a link state change takes place or the + * set of slaves in the bond changes. * * FIXME: this function MUST be called with the first agg in the bond, or * __get_active_agg() won't work correctly. This function should be better * called with the bond itself, and retrieve the first agg from it. */ -static void ad_agg_selection_logic(struct aggregator *aggregator) +static void ad_agg_selection_logic(struct aggregator *agg) { - struct aggregator *best_aggregator = NULL, *active_aggregator = NULL; - struct aggregator *last_active_aggregator = NULL, *origin_aggregator; + struct aggregator *best, *active, *origin; struct port *port; - u16 num_of_aggs=0; - origin_aggregator = aggregator; + origin = agg; - //get current active aggregator - last_active_aggregator = __get_active_agg(aggregator); + active = __get_active_agg(agg); + best = active; - // search for the aggregator with the most ports attached to it. do { - // count how many candidate lag's we have - if (aggregator->lag_ports) { - num_of_aggs++; - } - if (aggregator->is_active && !aggregator->is_individual && // if current aggregator is the active aggregator - MAC_ADDRESS_COMPARE(&(aggregator->partner_system), &(null_mac_addr))) { // and partner answers to 802.3ad PDUs - if (aggregator->num_of_ports) { // if any ports attached to the current aggregator - best_aggregator=NULL; // disregard the best aggregator that was chosen by now - break; // stop the selection of other aggregator if there are any ports attached to this active aggregator - } else { // no ports attached to this active aggregator - aggregator->is_active = 0; // mark this aggregator as not active anymore - } - } - if (aggregator->num_of_ports) { // if any ports attached - if (best_aggregator) { // if there is a candidte aggregator - //The reasons for choosing new best aggregator: - // 1. if current agg is NOT individual and the best agg chosen so far is individual OR - // current and best aggs are both individual or both not individual, AND - // 2a. current agg partner reply but best agg partner do not reply OR - // 2b. current agg partner reply OR current agg partner do not reply AND best agg partner also do not reply AND - // current has more ports/bandwidth, or same amount of ports but current has faster ports, THEN - // current agg become best agg so far - - //if current agg is NOT individual and the best agg chosen so far is individual change best_aggregator - if (!aggregator->is_individual && best_aggregator->is_individual) { - best_aggregator=aggregator; - } - // current and best aggs are both individual or both not individual - else if ((aggregator->is_individual && best_aggregator->is_individual) || - (!aggregator->is_individual && !best_aggregator->is_individual)) { - // current and best aggs are both individual or both not individual AND - // current agg partner reply but best agg partner do not reply - if ((MAC_ADDRESS_COMPARE(&(aggregator->partner_system), &(null_mac_addr)) && - !MAC_ADDRESS_COMPARE(&(best_aggregator->partner_system), &(null_mac_addr)))) { - best_aggregator=aggregator; - } - // current agg partner reply OR current agg partner do not reply AND best agg partner also do not reply - else if (! (!MAC_ADDRESS_COMPARE(&(aggregator->partner_system), &(null_mac_addr)) && - MAC_ADDRESS_COMPARE(&(best_aggregator->partner_system), &(null_mac_addr)))) { - if ((__get_agg_selection_mode(aggregator->lag_ports) == AD_BANDWIDTH)&& - (__get_agg_bandwidth(aggregator) > __get_agg_bandwidth(best_aggregator))) { - best_aggregator=aggregator; - } else if (__get_agg_selection_mode(aggregator->lag_ports) == AD_COUNT) { - if (((aggregator->num_of_ports > best_aggregator->num_of_ports) && - (aggregator->actor_oper_aggregator_key & AD_SPEED_KEY_BITS))|| - ((aggregator->num_of_ports == best_aggregator->num_of_ports) && - ((u16)(aggregator->actor_oper_aggregator_key & AD_SPEED_KEY_BITS) > - (u16)(best_aggregator->actor_oper_aggregator_key & AD_SPEED_KEY_BITS)))) { - best_aggregator=aggregator; - } - } - } - } - } else { - best_aggregator=aggregator; + agg->is_active = 0; + + if (agg->num_of_ports) + best = ad_agg_selection_test(best, agg); + + } while ((agg = __get_next_agg(agg))); + + if (best && + __get_agg_selection_mode(best->lag_ports) == BOND_AD_STABLE) { + /* + * For the STABLE policy, don't replace the old active + * aggregator if it's still active (it has an answering + * partner) or if both the best and active don't have an + * answering partner. + */ + if (active && active->lag_ports && + active->lag_ports->is_enabled && + (__agg_has_partner(active) || + (!__agg_has_partner(active) && !__agg_has_partner(best)))) { + if (!(!active->actor_oper_aggregator_key && + best->actor_oper_aggregator_key)) { + best = NULL; + active->is_active = 1; } } - aggregator->is_active = 0; // mark all aggregators as not active anymore - } while ((aggregator = __get_next_agg(aggregator))); - - // if we have new aggregator selected, don't replace the old aggregator if it has an answering partner, - // or if both old aggregator and new aggregator don't have answering partner - if (best_aggregator) { - if (last_active_aggregator && last_active_aggregator->lag_ports && last_active_aggregator->lag_ports->is_enabled && - (MAC_ADDRESS_COMPARE(&(last_active_aggregator->partner_system), &(null_mac_addr)) || // partner answers OR - (!MAC_ADDRESS_COMPARE(&(last_active_aggregator->partner_system), &(null_mac_addr)) && // both old and new - !MAC_ADDRESS_COMPARE(&(best_aggregator->partner_system), &(null_mac_addr)))) // partner do not answer - ) { - // if new aggregator has link, and old aggregator does not, replace old aggregator.(do nothing) - // -> don't replace otherwise. - if (!(!last_active_aggregator->actor_oper_aggregator_key && best_aggregator->actor_oper_aggregator_key)) { - best_aggregator=NULL; - last_active_aggregator->is_active = 1; // don't replace good old aggregator + } - } - } + if (best && (best == active)) { + best = NULL; + active->is_active = 1; } // if there is new best aggregator, activate it - if (best_aggregator) { - for (aggregator = __get_first_agg(best_aggregator->lag_ports); - aggregator; - aggregator = __get_next_agg(aggregator)) { - - dprintk("Agg=%d; Ports=%d; a key=%d; p key=%d; Indiv=%d; Active=%d\n", - aggregator->aggregator_identifier, aggregator->num_of_ports, - aggregator->actor_oper_aggregator_key, aggregator->partner_oper_aggregator_key, - aggregator->is_individual, aggregator->is_active); + if (best) { + pr_debug("best Agg=%d; P=%d; a k=%d; p k=%d; Ind=%d; Act=%d\n", + best->aggregator_identifier, best->num_of_ports, + best->actor_oper_aggregator_key, + best->partner_oper_aggregator_key, + best->is_individual, best->is_active); + pr_debug("best ports %p slave %p %s\n", + best->lag_ports, best->slave, + best->slave ? best->slave->dev->name : "NULL"); + + for (agg = __get_first_agg(best->lag_ports); agg; + agg = __get_next_agg(agg)) { + + pr_debug("Agg=%d; P=%d; a k=%d; p k=%d; Ind=%d; Act=%d\n", + agg->aggregator_identifier, agg->num_of_ports, + agg->actor_oper_aggregator_key, + agg->partner_oper_aggregator_key, + agg->is_individual, agg->is_active); } // check if any partner replys - if (best_aggregator->is_individual) { - printk(KERN_WARNING DRV_NAME ": %s: Warning: No 802.3ad response from " - "the link partner for any adapters in the bond\n", - best_aggregator->slave->dev->master->name); + if (best->is_individual) { + printk(KERN_WARNING DRV_NAME ": %s: Warning: No 802.3ad" + " response from the link partner for any" + " adapters in the bond\n", + best->slave->dev->master->name); } - // check if there are more than one aggregator - if (num_of_aggs > 1) { - dprintk("Warning: More than one Link Aggregation Group was " - "found in the bond. Only one group will function in the bond\n"); - } - - best_aggregator->is_active = 1; - dprintk("LAG %d choosed as the active LAG\n", best_aggregator->aggregator_identifier); - dprintk("Agg=%d; Ports=%d; a key=%d; p key=%d; Indiv=%d; Active=%d\n", - best_aggregator->aggregator_identifier, best_aggregator->num_of_ports, - best_aggregator->actor_oper_aggregator_key, best_aggregator->partner_oper_aggregator_key, - best_aggregator->is_individual, best_aggregator->is_active); + best->is_active = 1; + pr_debug("LAG %d chosen as the active LAG\n", + best->aggregator_identifier); + pr_debug("Agg=%d; P=%d; a k=%d; p k=%d; Ind=%d; Act=%d\n", + best->aggregator_identifier, best->num_of_ports, + best->actor_oper_aggregator_key, + best->partner_oper_aggregator_key, + best->is_individual, best->is_active); // disable the ports that were related to the former active_aggregator - if (last_active_aggregator) { - for (port=last_active_aggregator->lag_ports; port; port=port->next_port_in_aggregator) { + if (active) { + for (port = active->lag_ports; port; + port = port->next_port_in_aggregator) { __disable_port(port); } } } - // if the selected aggregator is of join individuals(partner_system is NULL), enable their ports - active_aggregator = __get_active_agg(origin_aggregator); + /* + * if the selected aggregator is of join individuals + * (partner_system is NULL), enable their ports + */ + active = __get_active_agg(origin); - if (active_aggregator) { - if (!MAC_ADDRESS_COMPARE(&(active_aggregator->partner_system), &(null_mac_addr))) { - for (port=active_aggregator->lag_ports; port; port=port->next_port_in_aggregator) { + if (active) { + if (!__agg_has_partner(active)) { + for (port = active->lag_ports; port; + port = port->next_port_in_aggregator) { __enable_port(port); } } } + + if (origin->slave) { + struct bonding *bond; + + bond = bond_get_bond_by_slave(origin->slave); + if (bond) + bond_3ad_set_carrier(bond); + } } /** @@ -1584,7 +1612,7 @@ static void ad_agg_selection_logic(struct aggregator *aggregator) static void ad_clear_agg(struct aggregator *aggregator) { if (aggregator) { - aggregator->is_individual = 0; + aggregator->is_individual = false; aggregator->actor_admin_aggregator_key = 0; aggregator->actor_oper_aggregator_key = 0; aggregator->partner_system = null_mac_addr; @@ -1595,7 +1623,7 @@ static void ad_clear_agg(struct aggregator *aggregator) aggregator->lag_ports = NULL; aggregator->is_active = 0; aggregator->num_of_ports = 0; - dprintk("LAG %d was cleared\n", aggregator->aggregator_identifier); + pr_debug("LAG %d was cleared\n", aggregator->aggregator_identifier); } } @@ -1623,13 +1651,32 @@ static void ad_initialize_agg(struct aggregator *aggregator) */ static void ad_initialize_port(struct port *port, int lacp_fast) { + static const struct port_params tmpl = { + .system_priority = 0xffff, + .key = 1, + .port_number = 1, + .port_priority = 0xff, + .port_state = 1, + }; + static const struct lacpdu lacpdu = { + .subtype = 0x01, + .version_number = 0x01, + .tlv_type_actor_info = 0x01, + .actor_information_length = 0x14, + .tlv_type_partner_info = 0x02, + .partner_information_length = 0x14, + .tlv_type_collector_info = 0x03, + .collector_information_length = 0x10, + .collector_max_delay = htons(AD_COLLECTOR_MAX_DELAY), + }; + if (port) { port->actor_port_number = 1; port->actor_port_priority = 0xff; port->actor_system = null_mac_addr; port->actor_system_priority = 0xffff; port->actor_port_aggregator_identifier = 0; - port->ntt = 0; + port->ntt = false; port->actor_admin_port_key = 1; port->actor_oper_port_key = 1; port->actor_admin_port_state = AD_STATE_AGGREGATION | AD_STATE_LACP_ACTIVITY; @@ -1639,19 +1686,10 @@ static void ad_initialize_port(struct port *port, int lacp_fast) port->actor_oper_port_state |= AD_STATE_LACP_TIMEOUT; } - port->partner_admin_system = null_mac_addr; - port->partner_oper_system = null_mac_addr; - port->partner_admin_system_priority = 0xffff; - port->partner_oper_system_priority = 0xffff; - port->partner_admin_key = 1; - port->partner_oper_key = 1; - port->partner_admin_port_number = 1; - port->partner_oper_port_number = 1; - port->partner_admin_port_priority = 0xff; - port->partner_oper_port_priority = 0xff; - port->partner_admin_port_state = 1; - port->partner_oper_port_state = 1; - port->is_enabled = 1; + memcpy(&port->partner_admin, &tmpl, sizeof(tmpl)); + memcpy(&port->partner_oper, &tmpl, sizeof(tmpl)); + + port->is_enabled = true; // ****** private parameters ****** port->sm_vars = 0x3; port->sm_rx_state = 0; @@ -1667,7 +1705,7 @@ static void ad_initialize_port(struct port *port, int lacp_fast) port->next_port_in_aggregator = NULL; port->transaction_id = 0; - ad_initialize_lacpdu(&(port->lacpdu)); + memcpy(&port->lacpdu, &lacpdu, sizeof(lacpdu)); } } @@ -1680,7 +1718,7 @@ static void ad_initialize_port(struct port *port, int lacp_fast) static void ad_enable_collecting_distributing(struct port *port) { if (port->aggregator->is_active) { - dprintk("Enabling port %d(LAG %d)\n", port->actor_port_number, port->aggregator->aggregator_identifier); + pr_debug("Enabling port %d(LAG %d)\n", port->actor_port_number, port->aggregator->aggregator_identifier); __enable_port(port); } } @@ -1693,7 +1731,7 @@ static void ad_enable_collecting_distributing(struct port *port) static void ad_disable_collecting_distributing(struct port *port) { if (port->aggregator && MAC_ADDRESS_COMPARE(&(port->aggregator->partner_system), &(null_mac_addr))) { - dprintk("Disabling port %d(LAG %d)\n", port->actor_port_number, port->aggregator->aggregator_identifier); + pr_debug("Disabling port %d(LAG %d)\n", port->actor_port_number, port->aggregator->aggregator_identifier); __disable_port(port); } } @@ -1731,7 +1769,7 @@ static void ad_marker_info_send(struct port *port) // send the marker information if (ad_marker_send(port, &marker) >= 0) { - dprintk("Sent Marker Information on port %d\n", port->actor_port_number); + pr_debug("Sent Marker Information on port %d\n", port->actor_port_number); } } #endif @@ -1755,7 +1793,7 @@ static void ad_marker_info_received(struct bond_marker *marker_info, // send the marker response if (ad_marker_send(port, &marker) >= 0) { - dprintk("Sent Marker Response on port %d\n", port->actor_port_number); + pr_debug("Sent Marker Response on port %d\n", port->actor_port_number); } } @@ -1776,53 +1814,6 @@ static void ad_marker_response_received(struct bond_marker *marker, // DO NOTHING, SINCE WE DECIDED NOT TO IMPLEMENT THIS FEATURE FOR NOW } -/** - * ad_initialize_lacpdu - initialize a given lacpdu structure - * @lacpdu: lacpdu structure to initialize - * - */ -static void ad_initialize_lacpdu(struct lacpdu *lacpdu) -{ - u16 index; - - // initialize lacpdu data - lacpdu->subtype = 0x01; - lacpdu->version_number = 0x01; - lacpdu->tlv_type_actor_info = 0x01; - lacpdu->actor_information_length = 0x14; - // lacpdu->actor_system_priority updated on send - // lacpdu->actor_system updated on send - // lacpdu->actor_key updated on send - // lacpdu->actor_port_priority updated on send - // lacpdu->actor_port updated on send - // lacpdu->actor_state updated on send - lacpdu->tlv_type_partner_info = 0x02; - lacpdu->partner_information_length = 0x14; - for (index=0; index<=2; index++) { - lacpdu->reserved_3_1[index]=0; - } - // lacpdu->partner_system_priority updated on send - // lacpdu->partner_system updated on send - // lacpdu->partner_key updated on send - // lacpdu->partner_port_priority updated on send - // lacpdu->partner_port updated on send - // lacpdu->partner_state updated on send - for (index=0; index<=2; index++) { - lacpdu->reserved_3_2[index]=0; - } - lacpdu->tlv_type_collector_info = 0x03; - lacpdu->collector_information_length= 0x10; - lacpdu->collector_max_delay = htons(AD_COLLECTOR_MAX_DELAY); - for (index=0; index<=11; index++) { - lacpdu->reserved_12[index]=0; - } - lacpdu->tlv_type_terminator = 0x00; - lacpdu->terminator_length = 0; - for (index=0; index<=49; index++) { - lacpdu->reserved_50[index]=0; - } -} - ////////////////////////////////////////////////////////////////////////////////////// // ================= AD exported functions to the main bonding code ================== ////////////////////////////////////////////////////////////////////////////////////// @@ -1830,6 +1821,19 @@ static void ad_initialize_lacpdu(struct lacpdu *lacpdu) // Check aggregators status in team every T seconds #define AD_AGGREGATOR_SELECTION_TIMER 8 +/* + * bond_3ad_initiate_agg_selection(struct bonding *bond) + * + * Set the aggregation selection timer, to initiate an agg selection in + * the very near future. Called during first initialization, and during + * any down to up transitions of the bond. + */ +void bond_3ad_initiate_agg_selection(struct bonding *bond, int timeout) +{ + BOND_AD_INFO(bond).agg_select_timer = timeout; + BOND_AD_INFO(bond).agg_select_mode = bond->params.ad_select; +} + static u16 aggregator_identifier; /** @@ -1854,9 +1858,9 @@ void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution, int lacp_fas // initialize how many times this module is called in one second(should be about every 100ms) ad_ticks_per_sec = tick_resolution; - // initialize the aggregator selection timer(to activate an aggregation selection after initialize) - BOND_AD_INFO(bond).agg_select_timer = (AD_AGGREGATOR_SELECTION_TIMER * ad_ticks_per_sec); - BOND_AD_INFO(bond).agg_select_mode = AD_BANDWIDTH; + bond_3ad_initiate_agg_selection(bond, + AD_AGGREGATOR_SELECTION_TIMER * + ad_ticks_per_sec); } } @@ -1956,7 +1960,7 @@ void bond_3ad_unbind_slave(struct slave *slave) return; } - dprintk("Unbinding Link Aggregation Group %d\n", aggregator->aggregator_identifier); + pr_debug("Unbinding Link Aggregation Group %d\n", aggregator->aggregator_identifier); /* Tell the partner that this port is not suitable for aggregation */ port->actor_oper_port_state &= ~AD_STATE_AGGREGATION; @@ -1980,7 +1984,7 @@ void bond_3ad_unbind_slave(struct slave *slave) // if new aggregator found, copy the aggregator's parameters // and connect the related lag_ports to the new aggregator if ((new_aggregator) && ((!new_aggregator->lag_ports) || ((new_aggregator->lag_ports == port) && !new_aggregator->lag_ports->next_port_in_aggregator))) { - dprintk("Some port(s) related to LAG %d - replaceing with LAG %d\n", aggregator->aggregator_identifier, new_aggregator->aggregator_identifier); + pr_debug("Some port(s) related to LAG %d - replaceing with LAG %d\n", aggregator->aggregator_identifier, new_aggregator->aggregator_identifier); if ((new_aggregator->lag_ports == port) && new_aggregator->is_active) { printk(KERN_INFO DRV_NAME ": %s: Removing an active aggregator\n", @@ -2031,7 +2035,7 @@ void bond_3ad_unbind_slave(struct slave *slave) } } - dprintk("Unbinding port %d\n", port->actor_port_number); + pr_debug("Unbinding port %d\n", port->actor_port_number); // find the aggregator that this port is connected to temp_aggregator = __get_first_agg(port); for (; temp_aggregator; temp_aggregator = __get_next_agg(temp_aggregator)) { @@ -2162,7 +2166,7 @@ static void bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u switch (lacpdu->subtype) { case AD_TYPE_LACPDU: - dprintk("Received LACPDU on port %d\n", port->actor_port_number); + pr_debug("Received LACPDU on port %d\n", port->actor_port_number); ad_rx_machine(lacpdu, port); break; @@ -2171,17 +2175,17 @@ static void bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u switch (((struct bond_marker *)lacpdu)->tlv_type) { case AD_MARKER_INFORMATION_SUBTYPE: - dprintk("Received Marker Information on port %d\n", port->actor_port_number); + pr_debug("Received Marker Information on port %d\n", port->actor_port_number); ad_marker_info_received((struct bond_marker *)lacpdu, port); break; case AD_MARKER_RESPONSE_SUBTYPE: - dprintk("Received Marker Response on port %d\n", port->actor_port_number); + pr_debug("Received Marker Response on port %d\n", port->actor_port_number); ad_marker_response_received((struct bond_marker *)lacpdu, port); break; default: - dprintk("Received an unknown Marker subtype on slot %d\n", port->actor_port_number); + pr_debug("Received an unknown Marker subtype on slot %d\n", port->actor_port_number); } } } @@ -2209,7 +2213,7 @@ void bond_3ad_adapter_speed_changed(struct slave *slave) port->actor_admin_port_key &= ~AD_SPEED_KEY_BITS; port->actor_oper_port_key=port->actor_admin_port_key |= (__get_link_speed(port) << 1); - dprintk("Port %d changed speed\n", port->actor_port_number); + pr_debug("Port %d changed speed\n", port->actor_port_number); // there is no need to reselect a new aggregator, just signal the // state machines to reinitialize port->sm_vars |= AD_PORT_BEGIN; @@ -2237,7 +2241,7 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave) port->actor_admin_port_key &= ~AD_DUPLEX_KEY_BITS; port->actor_oper_port_key=port->actor_admin_port_key |= __get_duplex(port); - dprintk("Port %d changed duplex\n", port->actor_port_number); + pr_debug("Port %d changed duplex\n", port->actor_port_number); // there is no need to reselect a new aggregator, just signal the // state machines to reinitialize port->sm_vars |= AD_PORT_BEGIN; @@ -2267,14 +2271,14 @@ void bond_3ad_handle_link_change(struct slave *slave, char link) // on link down we are zeroing duplex and speed since some of the adaptors(ce1000.lan) report full duplex/speed instead of N/A(duplex) / 0(speed) // on link up we are forcing recheck on the duplex and speed since some of he adaptors(ce1000.lan) report if (link == BOND_LINK_UP) { - port->is_enabled = 1; + port->is_enabled = true; port->actor_admin_port_key &= ~AD_DUPLEX_KEY_BITS; port->actor_oper_port_key=port->actor_admin_port_key |= __get_duplex(port); port->actor_admin_port_key &= ~AD_SPEED_KEY_BITS; port->actor_oper_port_key=port->actor_admin_port_key |= (__get_link_speed(port) << 1); } else { /* link has failed */ - port->is_enabled = 0; + port->is_enabled = false; port->actor_admin_port_key &= ~AD_DUPLEX_KEY_BITS; port->actor_oper_port_key= (port->actor_admin_port_key &= ~AD_SPEED_KEY_BITS); } @@ -2346,7 +2350,7 @@ int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info) int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) { struct slave *slave, *start_at; - struct bonding *bond = dev->priv; + struct bonding *bond = netdev_priv(dev); int slave_agg_no; int slaves_in_agg; int agg_id; @@ -2426,7 +2430,7 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type* ptype, struct net_device *orig_dev) { - struct bonding *bond = dev->priv; + struct bonding *bond = netdev_priv(dev); struct slave *slave = NULL; int ret = NET_RX_DROP; @@ -2437,7 +2441,8 @@ int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct pac goto out; read_lock(&bond->lock); - slave = bond_get_slave_by_dev((struct bonding *)dev->priv, orig_dev); + slave = bond_get_slave_by_dev((struct bonding *)netdev_priv(dev), + orig_dev); if (!slave) goto out_unlock; diff --git a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h index b5ee45f6d55a41fec6bd93c890c75415d04e6de3..8a83eb283c21c8abecb64047be80a72faaa611b5 100644 --- a/drivers/net/bonding/bond_3ad.h +++ b/drivers/net/bonding/bond_3ad.h @@ -33,7 +33,6 @@ #define AD_TIMER_INTERVAL 100 /*msec*/ #define MULTICAST_LACPDU_ADDR {0x01, 0x80, 0xC2, 0x00, 0x00, 0x02} -#define AD_MULTICAST_LACPDU_ADDR {MULTICAST_LACPDU_ADDR} #define AD_LACP_SLOW 0 #define AD_LACP_FAST 1 @@ -42,10 +41,11 @@ typedef struct mac_addr { u8 mac_addr_value[ETH_ALEN]; } mac_addr_t; -typedef enum { - AD_BANDWIDTH = 0, - AD_COUNT -} agg_selection_t; +enum { + BOND_AD_STABLE = 0, + BOND_AD_BANDWIDTH = 1, + BOND_AD_COUNT = 2, +}; // rx machine states(43.4.11 in the 802.3ad standard) typedef enum { @@ -105,12 +105,6 @@ typedef enum { #pragma pack(1) -typedef struct ad_header { - struct mac_addr destination_address; - struct mac_addr source_address; - __be16 length_type; -} ad_header_t; - // Link Aggregation Control Protocol(LACP) data unit structure(43.4.2.2 in the 802.3ad standard) typedef struct lacpdu { u8 subtype; // = LACP(= 0x01) @@ -143,7 +137,7 @@ typedef struct lacpdu { } lacpdu_t; typedef struct lacpdu_header { - struct ad_header ad_header; + struct ethhdr hdr; struct lacpdu lacpdu; } lacpdu_header_t; @@ -164,7 +158,7 @@ typedef struct bond_marker { } bond_marker_t; typedef struct bond_marker_header { - struct ad_header ad_header; + struct ethhdr hdr; struct bond_marker marker; } bond_marker_header_t; @@ -183,7 +177,7 @@ struct port; typedef struct aggregator { struct mac_addr aggregator_mac_address; u16 aggregator_identifier; - u16 is_individual; // BOOLEAN + bool is_individual; u16 actor_admin_aggregator_key; u16 actor_oper_aggregator_key; struct mac_addr partner_system; @@ -198,6 +192,15 @@ typedef struct aggregator { u16 num_of_ports; } aggregator_t; +struct port_params { + struct mac_addr system; + u16 system_priority; + u16 key; + u16 port_number; + u16 port_priority; + u16 port_state; +}; + // port structure(43.4.6 in the 802.3ad standard) typedef struct port { u16 actor_port_number; @@ -205,24 +208,17 @@ typedef struct port { struct mac_addr actor_system; // This parameter is added here although it is not specified in the standard, just for simplification u16 actor_system_priority; // This parameter is added here although it is not specified in the standard, just for simplification u16 actor_port_aggregator_identifier; - u16 ntt; // BOOLEAN + bool ntt; u16 actor_admin_port_key; u16 actor_oper_port_key; u8 actor_admin_port_state; u8 actor_oper_port_state; - struct mac_addr partner_admin_system; - struct mac_addr partner_oper_system; - u16 partner_admin_system_priority; - u16 partner_oper_system_priority; - u16 partner_admin_key; - u16 partner_oper_key; - u16 partner_admin_port_number; - u16 partner_oper_port_number; - u16 partner_admin_port_priority; - u16 partner_oper_port_priority; - u8 partner_admin_port_state; - u8 partner_oper_port_state; - u16 is_enabled; // BOOLEAN + + struct port_params partner_admin; + struct port_params partner_oper; + + bool is_enabled; + // ****** PRIVATE PARAMETERS ****** u16 sm_vars; // all state machines variables for this port rx_states_t sm_rx_state; // state machine rx state @@ -241,10 +237,10 @@ typedef struct port { } port_t; // system structure -typedef struct ad_system { +struct ad_system { u16 sys_priority; struct mac_addr sys_mac_addr; -} ad_system_t; +}; #ifdef __ia64__ #pragma pack() @@ -255,7 +251,7 @@ typedef struct ad_system { #define SLAVE_AD_INFO(slave) ((slave)->ad_info) struct ad_bond_info { - ad_system_t system; // 802.3ad system structure + struct ad_system system; /* 802.3ad system structure */ u32 agg_select_timer; // Timer to select aggregator after all adapter's hand shakes u32 agg_select_mode; // Mode of selection of active aggregator(bandwidth/count) int lacp_fast; /* whether fast periodic tx should be @@ -277,6 +273,7 @@ void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution, int lacp_fas int bond_3ad_bind_slave(struct slave *slave); void bond_3ad_unbind_slave(struct slave *slave); void bond_3ad_state_machine_handler(struct work_struct *); +void bond_3ad_initiate_agg_selection(struct bonding *bond, int timeout); void bond_3ad_adapter_speed_changed(struct slave *slave); void bond_3ad_adapter_duplex_changed(struct slave *slave); void bond_3ad_handle_link_change(struct slave *slave, char link); diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 87437c788476ab8a05df31a0f7fd1887ffeef497..27fb7f5c21cf57029b62d830ada44b6f26904dac 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -20,8 +20,6 @@ * */ -//#define BONDING_DEBUG 1 - #include #include #include @@ -346,30 +344,37 @@ static void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp) static int rlb_arp_recv(struct sk_buff *skb, struct net_device *bond_dev, struct packet_type *ptype, struct net_device *orig_dev) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond; struct arp_pkt *arp = (struct arp_pkt *)skb->data; int res = NET_RX_DROP; if (dev_net(bond_dev) != &init_net) goto out; - if (!(bond_dev->flags & IFF_MASTER)) + while (bond_dev->priv_flags & IFF_802_1Q_VLAN) + bond_dev = vlan_dev_real_dev(bond_dev); + + if (!(bond_dev->priv_flags & IFF_BONDING) || + !(bond_dev->flags & IFF_MASTER)) goto out; if (!arp) { - dprintk("Packet has no ARP data\n"); + pr_debug("Packet has no ARP data\n"); goto out; } if (skb->len < sizeof(struct arp_pkt)) { - dprintk("Packet is too small to be an ARP\n"); + pr_debug("Packet is too small to be an ARP\n"); goto out; } if (arp->op_code == htons(ARPOP_REPLY)) { /* update rx hash table for this ARP */ + printk("rar: update orig %s bond_dev %s\n", orig_dev->name, + bond_dev->name); + bond = netdev_priv(bond_dev); rlb_update_entry_from_arp(bond, arp); - dprintk("Server received an ARP Reply from client\n"); + pr_debug("Server received an ARP Reply from client\n"); } res = NET_RX_SUCCESS; @@ -723,7 +728,7 @@ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond) if (tx_slave) { memcpy(arp->mac_src,tx_slave->dev->dev_addr, ETH_ALEN); } - dprintk("Server sent ARP Reply packet\n"); + pr_debug("Server sent ARP Reply packet\n"); } else if (arp->op_code == htons(ARPOP_REQUEST)) { /* Create an entry in the rx_hashtbl for this client as a * place holder. @@ -743,7 +748,7 @@ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond) * updated with their assigned mac. */ rlb_req_update_subnet_clients(bond, arp->ip_src); - dprintk("Server sent ARP Request packet\n"); + pr_debug("Server sent ARP Request packet\n"); } return tx_slave; @@ -818,7 +823,7 @@ static int rlb_initialize(struct bonding *bond) /*initialize packet type*/ pk_type->type = __constant_htons(ETH_P_ARP); - pk_type->dev = bond->dev; + pk_type->dev = NULL; pk_type->func = rlb_arp_recv; /* register to receive ARPs */ @@ -1211,11 +1216,6 @@ static int alb_set_mac_address(struct bonding *bond, void *addr) } bond_for_each_slave(bond, slave, i) { - if (slave->dev->set_mac_address == NULL) { - res = -EOPNOTSUPP; - goto unwind; - } - /* save net_device's current hw address */ memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN); @@ -1224,9 +1224,8 @@ static int alb_set_mac_address(struct bonding *bond, void *addr) /* restore net_device's hw address */ memcpy(slave->dev->dev_addr, tmp_addr, ETH_ALEN); - if (res) { + if (res) goto unwind; - } } return 0; @@ -1285,7 +1284,7 @@ void bond_alb_deinitialize(struct bonding *bond) int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); struct ethhdr *eth_data; struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); struct slave *tx_slave = NULL; @@ -1706,7 +1705,7 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave */ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); struct sockaddr *sa = addr; struct slave *slave, *swap_slave; int res; diff --git a/drivers/net/bonding/bond_ipv6.c b/drivers/net/bonding/bond_ipv6.c new file mode 100644 index 0000000000000000000000000000000000000000..0d73bf5ac5a5b1014be49e17193b2be6b216809f --- /dev/null +++ b/drivers/net/bonding/bond_ipv6.c @@ -0,0 +1,216 @@ +/* + * Copyright(c) 2008 Hewlett-Packard Development Company, L.P. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + */ + +#include +#include +#include +#include +#include +#include "bonding.h" + +/* + * Assign bond->master_ipv6 to the next IPv6 address in the list, or + * zero it out if there are none. + */ +static void bond_glean_dev_ipv6(struct net_device *dev, struct in6_addr *addr) +{ + struct inet6_dev *idev; + struct inet6_ifaddr *ifa; + + if (!dev) + return; + + idev = in6_dev_get(dev); + if (!idev) + return; + + read_lock_bh(&idev->lock); + ifa = idev->addr_list; + if (ifa) + ipv6_addr_copy(addr, &ifa->addr); + else + ipv6_addr_set(addr, 0, 0, 0, 0); + + read_unlock_bh(&idev->lock); + + in6_dev_put(idev); +} + +static void bond_na_send(struct net_device *slave_dev, + struct in6_addr *daddr, + int router, + unsigned short vlan_id) +{ + struct in6_addr mcaddr; + struct icmp6hdr icmp6h = { + .icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT, + }; + struct sk_buff *skb; + + icmp6h.icmp6_router = router; + icmp6h.icmp6_solicited = 0; + icmp6h.icmp6_override = 1; + + addrconf_addr_solict_mult(daddr, &mcaddr); + + pr_debug("ipv6 na on slave %s: dest %pI6, src %pI6\n", + slave_dev->name, &mcaddr, daddr); + + skb = ndisc_build_skb(slave_dev, &mcaddr, daddr, &icmp6h, daddr, + ND_OPT_TARGET_LL_ADDR); + + if (!skb) { + printk(KERN_ERR DRV_NAME ": NA packet allocation failed\n"); + return; + } + + if (vlan_id) { + skb = vlan_put_tag(skb, vlan_id); + if (!skb) { + printk(KERN_ERR DRV_NAME ": failed to insert VLAN tag\n"); + return; + } + } + + ndisc_send_skb(skb, slave_dev, NULL, &mcaddr, daddr, &icmp6h); +} + +/* + * Kick out an unsolicited Neighbor Advertisement for an IPv6 address on + * the bonding master. This will help the switch learn our address + * if in active-backup mode. + * + * Caller must hold curr_slave_lock for read or better + */ +void bond_send_unsolicited_na(struct bonding *bond) +{ + struct slave *slave = bond->curr_active_slave; + struct vlan_entry *vlan; + struct inet6_dev *idev; + int is_router; + + pr_debug("bond_send_unsol_na: bond %s slave %s\n", bond->dev->name, + slave ? slave->dev->name : "NULL"); + + if (!slave || !bond->send_unsol_na || + test_bit(__LINK_STATE_LINKWATCH_PENDING, &slave->dev->state)) + return; + + bond->send_unsol_na--; + + idev = in6_dev_get(bond->dev); + if (!idev) + return; + + is_router = !!idev->cnf.forwarding; + + in6_dev_put(idev); + + if (!ipv6_addr_any(&bond->master_ipv6)) + bond_na_send(slave->dev, &bond->master_ipv6, is_router, 0); + + list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { + if (!ipv6_addr_any(&vlan->vlan_ipv6)) { + bond_na_send(slave->dev, &vlan->vlan_ipv6, is_router, + vlan->vlan_id); + } + } +} + +/* + * bond_inet6addr_event: handle inet6addr notifier chain events. + * + * We keep track of device IPv6 addresses primarily to use as source + * addresses in NS probes. + * + * We track one IPv6 for the main device (if it has one). + */ +static int bond_inet6addr_event(struct notifier_block *this, + unsigned long event, + void *ptr) +{ + struct inet6_ifaddr *ifa = ptr; + struct net_device *vlan_dev, *event_dev = ifa->idev->dev; + struct bonding *bond; + struct vlan_entry *vlan; + + if (dev_net(event_dev) != &init_net) + return NOTIFY_DONE; + + list_for_each_entry(bond, &bond_dev_list, bond_list) { + if (bond->dev == event_dev) { + switch (event) { + case NETDEV_UP: + if (ipv6_addr_any(&bond->master_ipv6)) + ipv6_addr_copy(&bond->master_ipv6, + &ifa->addr); + return NOTIFY_OK; + case NETDEV_DOWN: + if (ipv6_addr_equal(&bond->master_ipv6, + &ifa->addr)) + bond_glean_dev_ipv6(bond->dev, + &bond->master_ipv6); + return NOTIFY_OK; + default: + return NOTIFY_DONE; + } + } + + list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { + vlan_dev = vlan_group_get_device(bond->vlgrp, + vlan->vlan_id); + if (vlan_dev == event_dev) { + switch (event) { + case NETDEV_UP: + if (ipv6_addr_any(&vlan->vlan_ipv6)) + ipv6_addr_copy(&vlan->vlan_ipv6, + &ifa->addr); + return NOTIFY_OK; + case NETDEV_DOWN: + if (ipv6_addr_equal(&vlan->vlan_ipv6, + &ifa->addr)) + bond_glean_dev_ipv6(vlan_dev, + &vlan->vlan_ipv6); + return NOTIFY_OK; + default: + return NOTIFY_DONE; + } + } + } + } + return NOTIFY_DONE; +} + +static struct notifier_block bond_inet6addr_notifier = { + .notifier_call = bond_inet6addr_event, +}; + +void bond_register_ipv6_notifier(void) +{ + register_inet6addr_notifier(&bond_inet6addr_notifier); +} + +void bond_unregister_ipv6_notifier(void) +{ + unregister_inet6addr_notifier(&bond_inet6addr_notifier); +} + diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index a3efba59eee98daa96aeae7dd1278865a31c6db6..460c2cad2755d2c5df58b626eceb280619271632 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -31,8 +31,6 @@ * */ -//#define BONDING_DEBUG 1 - #include #include #include @@ -89,6 +87,7 @@ static int max_bonds = BOND_DEFAULT_MAX_BONDS; static int num_grat_arp = 1; +static int num_unsol_na = 1; static int miimon = BOND_LINK_MON_INTERV; static int updelay = 0; static int downdelay = 0; @@ -96,6 +95,7 @@ static int use_carrier = 1; static char *mode = NULL; static char *primary = NULL; static char *lacp_rate = NULL; +static char *ad_select = NULL; static char *xmit_hash_policy = NULL; static int arp_interval = BOND_LINK_ARP_INTERV; static char *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, }; @@ -107,6 +107,8 @@ module_param(max_bonds, int, 0); MODULE_PARM_DESC(max_bonds, "Max number of bonded devices"); module_param(num_grat_arp, int, 0644); MODULE_PARM_DESC(num_grat_arp, "Number of gratuitous ARP packets to send on failover event"); +module_param(num_unsol_na, int, 0644); +MODULE_PARM_DESC(num_unsol_na, "Number of unsolicited IPv6 Neighbor Advertisements packets to send on failover event"); module_param(miimon, int, 0); MODULE_PARM_DESC(miimon, "Link check interval in milliseconds"); module_param(updelay, int, 0); @@ -127,6 +129,8 @@ MODULE_PARM_DESC(primary, "Primary network device to use"); module_param(lacp_rate, charp, 0); MODULE_PARM_DESC(lacp_rate, "LACPDU tx rate to request from 802.3ad partner " "(slow/fast)"); +module_param(ad_select, charp, 0); +MODULE_PARM_DESC(ad_select, "803.ad aggregation selection logic: stable (0, default), bandwidth (1), count (2)"); module_param(xmit_hash_policy, charp, 0); MODULE_PARM_DESC(xmit_hash_policy, "XOR hashing method: 0 for layer 2 (default)" ", 1 for layer 3+4"); @@ -150,7 +154,6 @@ LIST_HEAD(bond_dev_list); static struct proc_dir_entry *bond_proc_dir = NULL; #endif -extern struct rw_semaphore bonding_rwsem; static __be32 arp_target[BOND_MAX_ARP_TARGETS] = { 0, } ; static int arp_ip_count = 0; static int bond_mode = BOND_MODE_ROUNDROBIN; @@ -158,13 +161,13 @@ static int xmit_hashtype= BOND_XMIT_POLICY_LAYER2; static int lacp_fast = 0; -struct bond_parm_tbl bond_lacp_tbl[] = { +const struct bond_parm_tbl bond_lacp_tbl[] = { { "slow", AD_LACP_SLOW}, { "fast", AD_LACP_FAST}, { NULL, -1}, }; -struct bond_parm_tbl bond_mode_tbl[] = { +const struct bond_parm_tbl bond_mode_tbl[] = { { "balance-rr", BOND_MODE_ROUNDROBIN}, { "active-backup", BOND_MODE_ACTIVEBACKUP}, { "balance-xor", BOND_MODE_XOR}, @@ -175,14 +178,14 @@ struct bond_parm_tbl bond_mode_tbl[] = { { NULL, -1}, }; -struct bond_parm_tbl xmit_hashtype_tbl[] = { +const struct bond_parm_tbl xmit_hashtype_tbl[] = { { "layer2", BOND_XMIT_POLICY_LAYER2}, { "layer3+4", BOND_XMIT_POLICY_LAYER34}, { "layer2+3", BOND_XMIT_POLICY_LAYER23}, { NULL, -1}, }; -struct bond_parm_tbl arp_validate_tbl[] = { +const struct bond_parm_tbl arp_validate_tbl[] = { { "none", BOND_ARP_VALIDATE_NONE}, { "active", BOND_ARP_VALIDATE_ACTIVE}, { "backup", BOND_ARP_VALIDATE_BACKUP}, @@ -190,13 +193,20 @@ struct bond_parm_tbl arp_validate_tbl[] = { { NULL, -1}, }; -struct bond_parm_tbl fail_over_mac_tbl[] = { +const struct bond_parm_tbl fail_over_mac_tbl[] = { { "none", BOND_FOM_NONE}, { "active", BOND_FOM_ACTIVE}, { "follow", BOND_FOM_FOLLOW}, { NULL, -1}, }; +struct bond_parm_tbl ad_select_tbl[] = { +{ "stable", BOND_AD_STABLE}, +{ "bandwidth", BOND_AD_BANDWIDTH}, +{ "count", BOND_AD_COUNT}, +{ NULL, -1}, +}; + /*-------------------------- Forward declarations ---------------------------*/ static void bond_send_gratuitous_arp(struct bonding *bond); @@ -206,24 +216,20 @@ static void bond_deinit(struct net_device *bond_dev); static const char *bond_mode_name(int mode) { - switch (mode) { - case BOND_MODE_ROUNDROBIN : - return "load balancing (round-robin)"; - case BOND_MODE_ACTIVEBACKUP : - return "fault-tolerance (active-backup)"; - case BOND_MODE_XOR : - return "load balancing (xor)"; - case BOND_MODE_BROADCAST : - return "fault-tolerance (broadcast)"; - case BOND_MODE_8023AD: - return "IEEE 802.3ad Dynamic link aggregation"; - case BOND_MODE_TLB: - return "transmit load balancing"; - case BOND_MODE_ALB: - return "adaptive load balancing"; - default: + static const char *names[] = { + [BOND_MODE_ROUNDROBIN] = "load balancing (round-robin)", + [BOND_MODE_ACTIVEBACKUP] = "fault-tolerance (active-backup)", + [BOND_MODE_XOR] = "load balancing (xor)", + [BOND_MODE_BROADCAST] = "fault-tolerance (broadcast)", + [BOND_MODE_8023AD]= "IEEE 802.3ad Dynamic link aggregation", + [BOND_MODE_TLB] = "transmit load balancing", + [BOND_MODE_ALB] = "adaptive load balancing", + }; + + if (mode < 0 || mode > BOND_MODE_ALB) return "unknown"; - } + + return names[mode]; } /*---------------------------------- VLAN -----------------------------------*/ @@ -239,17 +245,16 @@ static int bond_add_vlan(struct bonding *bond, unsigned short vlan_id) { struct vlan_entry *vlan; - dprintk("bond: %s, vlan id %d\n", + pr_debug("bond: %s, vlan id %d\n", (bond ? bond->dev->name: "None"), vlan_id); - vlan = kmalloc(sizeof(struct vlan_entry), GFP_KERNEL); + vlan = kzalloc(sizeof(struct vlan_entry), GFP_KERNEL); if (!vlan) { return -ENOMEM; } INIT_LIST_HEAD(&vlan->vlan_list); vlan->vlan_id = vlan_id; - vlan->vlan_ip = 0; write_lock_bh(&bond->lock); @@ -257,7 +262,7 @@ static int bond_add_vlan(struct bonding *bond, unsigned short vlan_id) write_unlock_bh(&bond->lock); - dprintk("added VLAN ID %d on bond %s\n", vlan_id, bond->dev->name); + pr_debug("added VLAN ID %d on bond %s\n", vlan_id, bond->dev->name); return 0; } @@ -274,7 +279,7 @@ static int bond_del_vlan(struct bonding *bond, unsigned short vlan_id) struct vlan_entry *vlan; int res = -ENODEV; - dprintk("bond: %s, vlan id %d\n", bond->dev->name, vlan_id); + pr_debug("bond: %s, vlan id %d\n", bond->dev->name, vlan_id); write_lock_bh(&bond->lock); @@ -282,12 +287,10 @@ static int bond_del_vlan(struct bonding *bond, unsigned short vlan_id) if (vlan->vlan_id == vlan_id) { list_del(&vlan->vlan_list); - if ((bond->params.mode == BOND_MODE_TLB) || - (bond->params.mode == BOND_MODE_ALB)) { + if (bond_is_lb(bond)) bond_alb_clear_vlan(bond, vlan_id); - } - dprintk("removed VLAN ID %d from bond %s\n", vlan_id, + pr_debug("removed VLAN ID %d from bond %s\n", vlan_id, bond->dev->name); kfree(vlan); @@ -307,7 +310,7 @@ static int bond_del_vlan(struct bonding *bond, unsigned short vlan_id) } } - dprintk("couldn't find VLAN ID %d in bond %s\n", vlan_id, + pr_debug("couldn't find VLAN ID %d in bond %s\n", vlan_id, bond->dev->name); out: @@ -331,13 +334,13 @@ static int bond_has_challenged_slaves(struct bonding *bond) bond_for_each_slave(bond, slave, i) { if (slave->dev->features & NETIF_F_VLAN_CHALLENGED) { - dprintk("found VLAN challenged slave - %s\n", + pr_debug("found VLAN challenged slave - %s\n", slave->dev->name); return 1; } } - dprintk("no VLAN challenged slaves found\n"); + pr_debug("no VLAN challenged slaves found\n"); return 0; } @@ -442,7 +445,7 @@ int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_de */ static void bond_vlan_rx_register(struct net_device *bond_dev, struct vlan_group *grp) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); struct slave *slave; int i; @@ -450,10 +453,11 @@ static void bond_vlan_rx_register(struct net_device *bond_dev, struct vlan_group bond_for_each_slave(bond, slave, i) { struct net_device *slave_dev = slave->dev; + const struct net_device_ops *slave_ops = slave_dev->netdev_ops; if ((slave_dev->features & NETIF_F_HW_VLAN_RX) && - slave_dev->vlan_rx_register) { - slave_dev->vlan_rx_register(slave_dev, grp); + slave_ops->ndo_vlan_rx_register) { + slave_ops->ndo_vlan_rx_register(slave_dev, grp); } } } @@ -465,16 +469,17 @@ static void bond_vlan_rx_register(struct net_device *bond_dev, struct vlan_group */ static void bond_vlan_rx_add_vid(struct net_device *bond_dev, uint16_t vid) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); struct slave *slave; int i, res; bond_for_each_slave(bond, slave, i) { struct net_device *slave_dev = slave->dev; + const struct net_device_ops *slave_ops = slave_dev->netdev_ops; if ((slave_dev->features & NETIF_F_HW_VLAN_FILTER) && - slave_dev->vlan_rx_add_vid) { - slave_dev->vlan_rx_add_vid(slave_dev, vid); + slave_ops->ndo_vlan_rx_add_vid) { + slave_ops->ndo_vlan_rx_add_vid(slave_dev, vid); } } @@ -493,21 +498,22 @@ static void bond_vlan_rx_add_vid(struct net_device *bond_dev, uint16_t vid) */ static void bond_vlan_rx_kill_vid(struct net_device *bond_dev, uint16_t vid) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); struct slave *slave; struct net_device *vlan_dev; int i, res; bond_for_each_slave(bond, slave, i) { struct net_device *slave_dev = slave->dev; + const struct net_device_ops *slave_ops = slave_dev->netdev_ops; if ((slave_dev->features & NETIF_F_HW_VLAN_FILTER) && - slave_dev->vlan_rx_kill_vid) { + slave_ops->ndo_vlan_rx_kill_vid) { /* Save and then restore vlan_dev in the grp array, * since the slave's driver might clear it. */ vlan_dev = vlan_group_get_device(bond->vlgrp, vid); - slave_dev->vlan_rx_kill_vid(slave_dev, vid); + slave_ops->ndo_vlan_rx_kill_vid(slave_dev, vid); vlan_group_set_device(bond->vlgrp, vid, vlan_dev); } } @@ -523,26 +529,23 @@ static void bond_vlan_rx_kill_vid(struct net_device *bond_dev, uint16_t vid) static void bond_add_vlans_on_slave(struct bonding *bond, struct net_device *slave_dev) { struct vlan_entry *vlan; + const struct net_device_ops *slave_ops = slave_dev->netdev_ops; write_lock_bh(&bond->lock); - if (list_empty(&bond->vlan_list)) { + if (list_empty(&bond->vlan_list)) goto out; - } if ((slave_dev->features & NETIF_F_HW_VLAN_RX) && - slave_dev->vlan_rx_register) { - slave_dev->vlan_rx_register(slave_dev, bond->vlgrp); - } + slave_ops->ndo_vlan_rx_register) + slave_ops->ndo_vlan_rx_register(slave_dev, bond->vlgrp); if (!(slave_dev->features & NETIF_F_HW_VLAN_FILTER) || - !(slave_dev->vlan_rx_add_vid)) { + !(slave_ops->ndo_vlan_rx_add_vid)) goto out; - } - list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { - slave_dev->vlan_rx_add_vid(slave_dev, vlan->vlan_id); - } + list_for_each_entry(vlan, &bond->vlan_list, vlan_list) + slave_ops->ndo_vlan_rx_add_vid(slave_dev, vlan->vlan_id); out: write_unlock_bh(&bond->lock); @@ -550,34 +553,32 @@ static void bond_add_vlans_on_slave(struct bonding *bond, struct net_device *sla static void bond_del_vlans_from_slave(struct bonding *bond, struct net_device *slave_dev) { + const struct net_device_ops *slave_ops = slave_dev->netdev_ops; struct vlan_entry *vlan; struct net_device *vlan_dev; write_lock_bh(&bond->lock); - if (list_empty(&bond->vlan_list)) { + if (list_empty(&bond->vlan_list)) goto out; - } if (!(slave_dev->features & NETIF_F_HW_VLAN_FILTER) || - !(slave_dev->vlan_rx_kill_vid)) { + !(slave_ops->ndo_vlan_rx_kill_vid)) goto unreg; - } list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { /* Save and then restore vlan_dev in the grp array, * since the slave's driver might clear it. */ vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id); - slave_dev->vlan_rx_kill_vid(slave_dev, vlan->vlan_id); + slave_ops->ndo_vlan_rx_kill_vid(slave_dev, vlan->vlan_id); vlan_group_set_device(bond->vlgrp, vlan->vlan_id, vlan_dev); } unreg: if ((slave_dev->features & NETIF_F_HW_VLAN_RX) && - slave_dev->vlan_rx_register) { - slave_dev->vlan_rx_register(slave_dev, NULL); - } + slave_ops->ndo_vlan_rx_register) + slave_ops->ndo_vlan_rx_register(slave_dev, NULL); out: write_unlock_bh(&bond->lock); @@ -686,15 +687,15 @@ static int bond_update_speed_duplex(struct slave *slave) */ static int bond_check_dev_link(struct bonding *bond, struct net_device *slave_dev, int reporting) { + const struct net_device_ops *slave_ops = slave_dev->netdev_ops; static int (* ioctl)(struct net_device *, struct ifreq *, int); struct ifreq ifr; struct mii_ioctl_data *mii; - if (bond->params.use_carrier) { + if (bond->params.use_carrier) return netif_carrier_ok(slave_dev) ? BMSR_LSTATUS : 0; - } - ioctl = slave_dev->do_ioctl; + ioctl = slave_ops->ndo_do_ioctl; if (ioctl) { /* TODO: set pointer to correct ioctl on a per team member */ /* bases to make this more efficient. that is, once */ @@ -927,7 +928,7 @@ static int bond_mc_list_copy(struct dev_mc_list *mc_list, struct bonding *bond, */ static void bond_mc_list_flush(struct net_device *bond_dev, struct net_device *slave_dev) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); struct dev_mc_list *dmi; for (dmi = bond_dev->mc_list; dmi; dmi = dmi->next) { @@ -1164,10 +1165,8 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) bond_3ad_handle_link_change(new_active, BOND_LINK_UP); } - if ((bond->params.mode == BOND_MODE_TLB) || - (bond->params.mode == BOND_MODE_ALB)) { + if (bond_is_lb(bond)) bond_alb_handle_link_change(bond, new_active, BOND_LINK_UP); - } } else { if (USES_PRIMARY(bond->params.mode)) { printk(KERN_INFO DRV_NAME @@ -1182,8 +1181,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) bond_mc_swap(bond, new_active, old_active); } - if ((bond->params.mode == BOND_MODE_TLB) || - (bond->params.mode == BOND_MODE_ALB)) { + if (bond_is_lb(bond)) { bond_alb_handle_active_change(bond, new_active); if (old_active) bond_set_slave_inactive_flags(old_active); @@ -1208,6 +1206,9 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) bond->send_grat_arp = bond->params.num_grat_arp; bond_send_gratuitous_arp(bond); + bond->send_unsol_na = bond->params.num_unsol_na; + bond_send_unsolicited_na(bond); + write_unlock_bh(&bond->curr_slave_lock); read_unlock(&bond->lock); @@ -1315,9 +1316,9 @@ static void bond_detach_slave(struct bonding *bond, struct slave *slave) static int bond_sethwaddr(struct net_device *bond_dev, struct net_device *slave_dev) { - dprintk("bond_dev=%p\n", bond_dev); - dprintk("slave_dev=%p\n", slave_dev); - dprintk("slave_dev->addr_len=%d\n", slave_dev->addr_len); + pr_debug("bond_dev=%p\n", bond_dev); + pr_debug("slave_dev=%p\n", slave_dev); + pr_debug("slave_dev->addr_len=%d\n", slave_dev->addr_len); memcpy(bond_dev->dev_addr, slave_dev->dev_addr, slave_dev->addr_len); return 0; } @@ -1364,14 +1365,12 @@ static int bond_compute_features(struct bonding *bond) return 0; } - static void bond_setup_by_slave(struct net_device *bond_dev, struct net_device *slave_dev) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); - bond_dev->neigh_setup = slave_dev->neigh_setup; - bond_dev->header_ops = slave_dev->header_ops; + bond_dev->header_ops = slave_dev->header_ops; bond_dev->type = slave_dev->type; bond_dev->hard_header_len = slave_dev->hard_header_len; @@ -1385,7 +1384,8 @@ static void bond_setup_by_slave(struct net_device *bond_dev, /* enslave device to bond device */ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); + const struct net_device_ops *slave_ops = slave_dev->netdev_ops; struct slave *new_slave = NULL; struct dev_mc_list *dmi; struct sockaddr addr; @@ -1394,7 +1394,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) int res = 0; if (!bond->params.use_carrier && slave_dev->ethtool_ops == NULL && - slave_dev->do_ioctl == NULL) { + slave_ops->ndo_do_ioctl == NULL) { printk(KERN_WARNING DRV_NAME ": %s: Warning: no link monitoring support for %s\n", bond_dev->name, slave_dev->name); @@ -1409,14 +1409,14 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) /* already enslaved */ if (slave_dev->flags & IFF_SLAVE) { - dprintk("Error, Device was already enslaved\n"); + pr_debug("Error, Device was already enslaved\n"); return -EBUSY; } /* vlan challenged mutual exclusion */ /* no need to lock since we're protected by rtnl_lock */ if (slave_dev->features & NETIF_F_VLAN_CHALLENGED) { - dprintk("%s: NETIF_F_VLAN_CHALLENGED\n", slave_dev->name); + pr_debug("%s: NETIF_F_VLAN_CHALLENGED\n", slave_dev->name); if (!list_empty(&bond->vlan_list)) { printk(KERN_ERR DRV_NAME ": %s: Error: cannot enslave VLAN " @@ -1434,7 +1434,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) bond_dev->features |= NETIF_F_VLAN_CHALLENGED; } } else { - dprintk("%s: ! NETIF_F_VLAN_CHALLENGED\n", slave_dev->name); + pr_debug("%s: ! NETIF_F_VLAN_CHALLENGED\n", slave_dev->name); if (bond->slave_cnt == 0) { /* First slave, and it is not VLAN challenged, * so remove the block of adding VLANs over the bond. @@ -1476,7 +1476,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) goto err_undo_flags; } - if (slave_dev->set_mac_address == NULL) { + if (slave_ops->ndo_set_mac_address == NULL) { if (bond->slave_cnt == 0) { printk(KERN_WARNING DRV_NAME ": %s: Warning: The first slave device " @@ -1522,28 +1522,27 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) addr.sa_family = slave_dev->type; res = dev_set_mac_address(slave_dev, &addr); if (res) { - dprintk("Error %d calling set_mac_address\n", res); + pr_debug("Error %d calling set_mac_address\n", res); goto err_free; } } res = netdev_set_master(slave_dev, bond_dev); if (res) { - dprintk("Error %d calling netdev_set_master\n", res); + pr_debug("Error %d calling netdev_set_master\n", res); goto err_restore_mac; } /* open the slave since the application closed it */ res = dev_open(slave_dev); if (res) { - dprintk("Openning slave %s failed\n", slave_dev->name); + pr_debug("Openning slave %s failed\n", slave_dev->name); goto err_unset_master; } new_slave->dev = slave_dev; slave_dev->priv_flags |= IFF_BONDING; - if ((bond->params.mode == BOND_MODE_TLB) || - (bond->params.mode == BOND_MODE_ALB)) { + if (bond_is_lb(bond)) { /* bond_alb_init_slave() must be called before all other stages since * it might fail and we do not want to have to undo everything */ @@ -1641,18 +1640,18 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) if (!bond->params.miimon || (bond_check_dev_link(bond, slave_dev, 0) == BMSR_LSTATUS)) { if (bond->params.updelay) { - dprintk("Initial state of slave_dev is " + pr_debug("Initial state of slave_dev is " "BOND_LINK_BACK\n"); new_slave->link = BOND_LINK_BACK; new_slave->delay = bond->params.updelay; } else { - dprintk("Initial state of slave_dev is " + pr_debug("Initial state of slave_dev is " "BOND_LINK_UP\n"); new_slave->link = BOND_LINK_UP; } new_slave->jiffies = jiffies; } else { - dprintk("Initial state of slave_dev is " + pr_debug("Initial state of slave_dev is " "BOND_LINK_DOWN\n"); new_slave->link = BOND_LINK_DOWN; } @@ -1713,7 +1712,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) bond_set_slave_inactive_flags(new_slave); break; default: - dprintk("This slave is always active in trunk mode\n"); + pr_debug("This slave is always active in trunk mode\n"); /* always active in trunk mode */ new_slave->state = BOND_STATE_ACTIVE; @@ -1787,11 +1786,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) */ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); struct slave *slave, *oldcurrent; struct sockaddr addr; int mac_addr_differ; - DECLARE_MAC_BUF(mac); /* slave is not a slave or master is not master of this slave */ if (!(slave_dev->flags & IFF_SLAVE) || @@ -1820,11 +1818,11 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) if (!mac_addr_differ && (bond->slave_cnt > 1)) printk(KERN_WARNING DRV_NAME ": %s: Warning: the permanent HWaddr of %s - " - "%s - is still in use by %s. " + "%pM - is still in use by %s. " "Set the HWaddr of %s to a different address " "to avoid conflicts.\n", bond_dev->name, slave_dev->name, - print_mac(mac, slave->perm_hwaddr), + slave->perm_hwaddr, bond_dev->name, slave_dev->name); } @@ -1860,8 +1858,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) bond_change_active_slave(bond, NULL); } - if ((bond->params.mode == BOND_MODE_TLB) || - (bond->params.mode == BOND_MODE_ALB)) { + if (bond_is_lb(bond)) { /* Must be called only after the slave has been * detached from the list and the curr_active_slave * has been cleared (if our_slave == old_current), @@ -1981,7 +1978,7 @@ void bond_destroy(struct bonding *bond) static void bond_destructor(struct net_device *bond_dev) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); if (bond->wq) destroy_workqueue(bond->wq); @@ -1999,7 +1996,7 @@ static void bond_destructor(struct net_device *bond_dev) */ int bond_release_and_destroy(struct net_device *bond_dev, struct net_device *slave_dev) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); int ret; ret = bond_release(bond_dev, slave_dev); @@ -2016,7 +2013,7 @@ int bond_release_and_destroy(struct net_device *bond_dev, struct net_device *sl */ static int bond_release_all(struct net_device *bond_dev) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); struct slave *slave; struct net_device *slave_dev; struct sockaddr addr; @@ -2050,8 +2047,7 @@ static int bond_release_all(struct net_device *bond_dev) */ write_unlock_bh(&bond->lock); - if ((bond->params.mode == BOND_MODE_TLB) || - (bond->params.mode == BOND_MODE_ALB)) { + if (bond_is_lb(bond)) { /* must be called only after the slave * has been detached from the list */ @@ -2147,7 +2143,7 @@ static int bond_release_all(struct net_device *bond_dev) */ static int bond_ioctl_change_active(struct net_device *bond_dev, struct net_device *slave_dev) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); struct slave *old_active = NULL; struct slave *new_active = NULL; int res = 0; @@ -2196,7 +2192,7 @@ static int bond_ioctl_change_active(struct net_device *bond_dev, struct net_devi static int bond_info_query(struct net_device *bond_dev, struct ifbond *info) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); info->bond_mode = bond->params.mode; info->miimon = bond->params.miimon; @@ -2210,7 +2206,7 @@ static int bond_info_query(struct net_device *bond_dev, struct ifbond *info) static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *info) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); struct slave *slave; int i, found = 0; @@ -2378,8 +2374,7 @@ static void bond_miimon_commit(struct bonding *bond) if (bond->params.mode == BOND_MODE_8023AD) bond_3ad_handle_link_change(slave, BOND_LINK_UP); - if ((bond->params.mode == BOND_MODE_TLB) || - (bond->params.mode == BOND_MODE_ALB)) + if (bond_is_lb(bond)) bond_alb_handle_link_change(bond, slave, BOND_LINK_UP); @@ -2464,6 +2459,12 @@ void bond_mii_monitor(struct work_struct *work) read_unlock(&bond->curr_slave_lock); } + if (bond->send_unsol_na) { + read_lock(&bond->curr_slave_lock); + bond_send_unsolicited_na(bond); + read_unlock(&bond->curr_slave_lock); + } + if (bond_miimon_inspect(bond)) { read_unlock(&bond->lock); rtnl_lock(); @@ -2532,7 +2533,7 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op, __be32 dest_ { struct sk_buff *skb; - dprintk("arp %d on slave %s: dst %x src %x vid %d\n", arp_op, + pr_debug("arp %d on slave %s: dst %x src %x vid %d\n", arp_op, slave_dev->name, dest_ip, src_ip, vlan_id); skb = arp_create(arp_op, ETH_P_ARP, dest_ip, slave_dev, src_ip, @@ -2565,9 +2566,9 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) for (i = 0; (i < BOND_MAX_ARP_TARGETS); i++) { if (!targets[i]) continue; - dprintk("basa: target %x\n", targets[i]); + pr_debug("basa: target %x\n", targets[i]); if (list_empty(&bond->vlan_list)) { - dprintk("basa: empty vlan: arp_send\n"); + pr_debug("basa: empty vlan: arp_send\n"); bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i], bond->master_ip, 0); continue; @@ -2586,8 +2587,8 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) if (rv) { if (net_ratelimit()) { printk(KERN_WARNING DRV_NAME - ": %s: no route to arp_ip_target %u.%u.%u.%u\n", - bond->dev->name, NIPQUAD(fl.fl4_dst)); + ": %s: no route to arp_ip_target %pI4\n", + bond->dev->name, &fl.fl4_dst); } continue; } @@ -2597,7 +2598,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) */ if (rt->u.dst.dev == bond->dev) { ip_rt_put(rt); - dprintk("basa: rtdev == bond->dev: arp_send\n"); + pr_debug("basa: rtdev == bond->dev: arp_send\n"); bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i], bond->master_ip, 0); continue; @@ -2608,7 +2609,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id); if (vlan_dev == rt->u.dst.dev) { vlan_id = vlan->vlan_id; - dprintk("basa: vlan match on %s %d\n", + pr_debug("basa: vlan match on %s %d\n", vlan_dev->name, vlan_id); break; } @@ -2623,8 +2624,8 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) if (net_ratelimit()) { printk(KERN_WARNING DRV_NAME - ": %s: no path to arp_ip_target %u.%u.%u.%u via rt.dev %s\n", - bond->dev->name, NIPQUAD(fl.fl4_dst), + ": %s: no path to arp_ip_target %pI4 via rt.dev %s\n", + bond->dev->name, &fl.fl4_dst, rt->u.dst.dev ? rt->u.dst.dev->name : "NULL"); } ip_rt_put(rt); @@ -2643,7 +2644,7 @@ static void bond_send_gratuitous_arp(struct bonding *bond) struct vlan_entry *vlan; struct net_device *vlan_dev; - dprintk("bond_send_grat_arp: bond %s slave %s\n", bond->dev->name, + pr_debug("bond_send_grat_arp: bond %s slave %s\n", bond->dev->name, slave ? slave->dev->name : "NULL"); if (!slave || !bond->send_grat_arp || @@ -2673,10 +2674,8 @@ static void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32 targets = bond->params.arp_targets; for (i = 0; (i < BOND_MAX_ARP_TARGETS) && targets[i]; i++) { - dprintk("bva: sip %u.%u.%u.%u tip %u.%u.%u.%u t[%d] " - "%u.%u.%u.%u bhti(tip) %d\n", - NIPQUAD(sip), NIPQUAD(tip), i, NIPQUAD(targets[i]), - bond_has_this_ip(bond, tip)); + pr_debug("bva: sip %pI4 tip %pI4 t[%d] %pI4 bhti(tip) %d\n", + &sip, &tip, i, &targets[i], bond_has_this_ip(bond, tip)); if (sip == targets[i]) { if (bond_has_this_ip(bond, tip)) slave->last_arp_rx = jiffies; @@ -2699,10 +2698,10 @@ static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct pack if (!(dev->priv_flags & IFF_BONDING) || !(dev->flags & IFF_MASTER)) goto out; - bond = dev->priv; + bond = netdev_priv(dev); read_lock(&bond->lock); - dprintk("bond_arp_rcv: bond %s skb->dev %s orig_dev %s\n", + pr_debug("bond_arp_rcv: bond %s skb->dev %s orig_dev %s\n", bond->dev->name, skb->dev ? skb->dev->name : "NULL", orig_dev ? orig_dev->name : "NULL"); @@ -2728,10 +2727,10 @@ static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct pack arp_ptr += 4 + dev->addr_len; memcpy(&tip, arp_ptr, 4); - dprintk("bond_arp_rcv: %s %s/%d av %d sv %d sip %u.%u.%u.%u" - " tip %u.%u.%u.%u\n", bond->dev->name, slave->dev->name, - slave->state, bond->params.arp_validate, - slave_do_arp_validate(bond, slave), NIPQUAD(sip), NIPQUAD(tip)); + pr_debug("bond_arp_rcv: %s %s/%d av %d sv %d sip %pI4 tip %pI4\n", + bond->dev->name, slave->dev->name, slave->state, + bond->params.arp_validate, slave_do_arp_validate(bond, slave), + &sip, &tip); /* * Backup slaves won't see the ARP reply, but do come through @@ -3161,6 +3160,12 @@ void bond_activebackup_arp_mon(struct work_struct *work) read_unlock(&bond->curr_slave_lock); } + if (bond->send_unsol_na) { + read_lock(&bond->curr_slave_lock); + bond_send_unsolicited_na(bond); + read_unlock(&bond->curr_slave_lock); + } + if (bond_ab_arp_inspect(bond, delta_in_ticks)) { read_unlock(&bond->lock); rtnl_lock(); @@ -3239,7 +3244,6 @@ static void bond_info_show_master(struct seq_file *seq) struct bonding *bond = seq->private; struct slave *curr; int i; - u32 target; read_lock(&bond->curr_slave_lock); curr = bond->curr_active_slave; @@ -3293,8 +3297,7 @@ static void bond_info_show_master(struct seq_file *seq) continue; if (printed) seq_printf(seq, ","); - target = ntohl(bond->params.arp_targets[i]); - seq_printf(seq, " %d.%d.%d.%d", HIPQUAD(target)); + seq_printf(seq, " %pI4", &bond->params.arp_targets[i]); printed = 1; } seq_printf(seq, "\n"); @@ -3302,11 +3305,12 @@ static void bond_info_show_master(struct seq_file *seq) if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; - DECLARE_MAC_BUF(mac); seq_puts(seq, "\n802.3ad info\n"); seq_printf(seq, "LACP rate: %s\n", (bond->params.lacp_fast) ? "fast" : "slow"); + seq_printf(seq, "Aggregator selection policy (ad_select): %s\n", + ad_select_tbl[bond->params.ad_select].modename); if (bond_3ad_get_active_agg_info(bond, &ad_info)) { seq_printf(seq, "bond %s has no active aggregator\n", @@ -3322,8 +3326,8 @@ static void bond_info_show_master(struct seq_file *seq) ad_info.actor_key); seq_printf(seq, "\tPartner Key: %d\n", ad_info.partner_key); - seq_printf(seq, "\tPartner Mac Address: %s\n", - print_mac(mac, ad_info.partner_system)); + seq_printf(seq, "\tPartner Mac Address: %pM\n", + ad_info.partner_system); } } } @@ -3331,7 +3335,6 @@ static void bond_info_show_master(struct seq_file *seq) static void bond_info_show_slave(struct seq_file *seq, const struct slave *slave) { struct bonding *bond = seq->private; - DECLARE_MAC_BUF(mac); seq_printf(seq, "\nSlave Interface: %s\n", slave->dev->name); seq_printf(seq, "MII Status: %s\n", @@ -3339,9 +3342,7 @@ static void bond_info_show_slave(struct seq_file *seq, const struct slave *slave seq_printf(seq, "Link Failure Count: %u\n", slave->link_failure_count); - seq_printf(seq, - "Permanent HW addr: %s\n", - print_mac(mac, slave->perm_hwaddr)); + seq_printf(seq, "Permanent HW addr: %pM\n", slave->perm_hwaddr); if (bond->params.mode == BOND_MODE_8023AD) { const struct aggregator *agg @@ -3506,7 +3507,7 @@ static int bond_event_changename(struct bonding *bond) static int bond_master_netdev_event(unsigned long event, struct net_device *bond_dev) { - struct bonding *event_bond = bond_dev->priv; + struct bonding *event_bond = netdev_priv(bond_dev); switch (event) { case NETDEV_CHANGENAME: @@ -3524,7 +3525,7 @@ static int bond_master_netdev_event(unsigned long event, struct net_device *bond static int bond_slave_netdev_event(unsigned long event, struct net_device *slave_dev) { struct net_device *bond_dev = slave_dev->master; - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); switch (event) { case NETDEV_UNREGISTER: @@ -3591,7 +3592,7 @@ static int bond_netdev_event(struct notifier_block *this, unsigned long event, v if (dev_net(event_dev) != &init_net) return NOTIFY_DONE; - dprintk("event_dev: %s, event: %lx\n", + pr_debug("event_dev: %s, event: %lx\n", (event_dev ? event_dev->name : "None"), event); @@ -3599,12 +3600,12 @@ static int bond_netdev_event(struct notifier_block *this, unsigned long event, v return NOTIFY_DONE; if (event_dev->flags & IFF_MASTER) { - dprintk("IFF_MASTER\n"); + pr_debug("IFF_MASTER\n"); return bond_master_netdev_event(event, event_dev); } if (event_dev->flags & IFF_SLAVE) { - dprintk("IFF_SLAVE\n"); + pr_debug("IFF_SLAVE\n"); return bond_slave_netdev_event(event, event_dev); } @@ -3775,12 +3776,11 @@ static int bond_xmit_hash_policy_l2(struct sk_buff *skb, static int bond_open(struct net_device *bond_dev) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); bond->kill_timers = 0; - if ((bond->params.mode == BOND_MODE_TLB) || - (bond->params.mode == BOND_MODE_ALB)) { + if (bond_is_lb(bond)) { /* bond_alb_initialize must be called before the timer * is started. */ @@ -3816,6 +3816,7 @@ static int bond_open(struct net_device *bond_dev) queue_delayed_work(bond->wq, &bond->ad_work, 0); /* register to receive LACPDUs */ bond_register_lacpdu(bond); + bond_3ad_initiate_agg_selection(bond, 1); } return 0; @@ -3823,7 +3824,7 @@ static int bond_open(struct net_device *bond_dev) static int bond_close(struct net_device *bond_dev) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); if (bond->params.mode == BOND_MODE_8023AD) { /* Unregister the receive of LACPDUs */ @@ -3836,6 +3837,7 @@ static int bond_close(struct net_device *bond_dev) write_lock_bh(&bond->lock); bond->send_grat_arp = 0; + bond->send_unsol_na = 0; /* signal timers not to re-arm */ bond->kill_timers = 1; @@ -3863,8 +3865,7 @@ static int bond_close(struct net_device *bond_dev) } - if ((bond->params.mode == BOND_MODE_TLB) || - (bond->params.mode == BOND_MODE_ALB)) { + if (bond_is_lb(bond)) { /* Must be called only after all * slaves have been released */ @@ -3876,8 +3877,8 @@ static int bond_close(struct net_device *bond_dev) static struct net_device_stats *bond_get_stats(struct net_device *bond_dev) { - struct bonding *bond = bond_dev->priv; - struct net_device_stats *stats = &(bond->stats), *sstats; + struct bonding *bond = netdev_priv(bond_dev); + struct net_device_stats *stats = &bond->stats; struct net_device_stats local_stats; struct slave *slave; int i; @@ -3887,7 +3888,8 @@ static struct net_device_stats *bond_get_stats(struct net_device *bond_dev) read_lock_bh(&bond->lock); bond_for_each_slave(bond, slave, i) { - sstats = slave->dev->get_stats(slave->dev); + const struct net_device_stats *sstats = dev_get_stats(slave->dev); + local_stats.rx_packets += sstats->rx_packets; local_stats.rx_bytes += sstats->rx_bytes; local_stats.rx_errors += sstats->rx_errors; @@ -3932,7 +3934,7 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd struct mii_ioctl_data *mii = NULL; int res = 0; - dprintk("bond_ioctl: master=%s, cmd=%d\n", + pr_debug("bond_ioctl: master=%s, cmd=%d\n", bond_dev->name, cmd); switch (cmd) { @@ -3954,7 +3956,7 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd } if (mii->reg_num == 1) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); mii->val_out = 0; read_lock(&bond->lock); read_lock(&bond->curr_slave_lock); @@ -4010,12 +4012,12 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd down_write(&(bonding_rwsem)); slave_dev = dev_get_by_name(&init_net, ifr->ifr_slave); - dprintk("slave_dev=%p: \n", slave_dev); + pr_debug("slave_dev=%p: \n", slave_dev); if (!slave_dev) { res = -ENODEV; } else { - dprintk("slave_dev->name=%s: \n", slave_dev->name); + pr_debug("slave_dev->name=%s: \n", slave_dev->name); switch (cmd) { case BOND_ENSLAVE_OLD: case SIOCBONDENSLAVE: @@ -4046,7 +4048,7 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd static void bond_set_multicast_list(struct net_device *bond_dev) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); struct dev_mc_list *dmi; /* @@ -4102,17 +4104,31 @@ static void bond_set_multicast_list(struct net_device *bond_dev) read_unlock(&bond->lock); } +static int bond_neigh_setup(struct net_device *dev, struct neigh_parms *parms) +{ + struct bonding *bond = netdev_priv(dev); + struct slave *slave = bond->first_slave; + + if (slave) { + const struct net_device_ops *slave_ops + = slave->dev->netdev_ops; + if (slave_ops->ndo_neigh_setup) + return slave_ops->ndo_neigh_setup(dev, parms); + } + return 0; +} + /* * Change the MTU of all of a master's slaves to match the master */ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); struct slave *slave, *stop_at; int res = 0; int i; - dprintk("bond=%p, name=%s, new_mtu=%d\n", bond, + pr_debug("bond=%p, name=%s, new_mtu=%d\n", bond, (bond_dev ? bond_dev->name : "None"), new_mtu); /* Can't hold bond->lock with bh disabled here since @@ -4131,7 +4147,7 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu) */ bond_for_each_slave(bond, slave, i) { - dprintk("s %p s->p %p c_m %p\n", slave, + pr_debug("s %p s->p %p c_m %p\n", slave, slave->prev, slave->dev->change_mtu); res = dev_set_mtu(slave->dev, new_mtu); @@ -4145,7 +4161,7 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu) * means changing their mtu from timer context, which * is probably not a good idea. */ - dprintk("err %d %s\n", res, slave->dev->name); + pr_debug("err %d %s\n", res, slave->dev->name); goto unwind; } } @@ -4162,7 +4178,7 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu) tmp_res = dev_set_mtu(slave->dev, bond_dev->mtu); if (tmp_res) { - dprintk("unwind err %d dev %s\n", tmp_res, + pr_debug("unwind err %d dev %s\n", tmp_res, slave->dev->name); } } @@ -4179,13 +4195,17 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu) */ static int bond_set_mac_address(struct net_device *bond_dev, void *addr) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); struct sockaddr *sa = addr, tmp_sa; struct slave *slave, *stop_at; int res = 0; int i; - dprintk("bond=%p, name=%s\n", bond, (bond_dev ? bond_dev->name : "None")); + if (bond->params.mode == BOND_MODE_ALB) + return bond_alb_set_mac_address(bond_dev, addr); + + + pr_debug("bond=%p, name=%s\n", bond, (bond_dev ? bond_dev->name : "None")); /* * If fail_over_mac is set to active, do nothing and return @@ -4214,11 +4234,12 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr) */ bond_for_each_slave(bond, slave, i) { - dprintk("slave %p %s\n", slave, slave->dev->name); + const struct net_device_ops *slave_ops = slave->dev->netdev_ops; + pr_debug("slave %p %s\n", slave, slave->dev->name); - if (slave->dev->set_mac_address == NULL) { + if (slave_ops->ndo_set_mac_address == NULL) { res = -EOPNOTSUPP; - dprintk("EOPNOTSUPP %s\n", slave->dev->name); + pr_debug("EOPNOTSUPP %s\n", slave->dev->name); goto unwind; } @@ -4230,7 +4251,7 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr) * breakage anyway until ARP finish * updating, so... */ - dprintk("err %d %s\n", res, slave->dev->name); + pr_debug("err %d %s\n", res, slave->dev->name); goto unwind; } } @@ -4250,7 +4271,7 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr) tmp_res = dev_set_mac_address(slave->dev, &tmp_sa); if (tmp_res) { - dprintk("unwind err %d dev %s\n", tmp_res, + pr_debug("unwind err %d dev %s\n", tmp_res, slave->dev->name); } } @@ -4260,7 +4281,7 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr) static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); struct slave *slave, *start_at; int i, slave_no, res = 1; @@ -4309,7 +4330,7 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev */ static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_dev) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); int res = 1; read_lock(&bond->lock); @@ -4341,7 +4362,7 @@ static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_d */ static int bond_xmit_xor(struct sk_buff *skb, struct net_device *bond_dev) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); struct slave *slave, *start_at; int slave_no; int i; @@ -4387,7 +4408,7 @@ static int bond_xmit_xor(struct sk_buff *skb, struct net_device *bond_dev) */ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); struct slave *slave, *start_at; struct net_device *tx_dev = NULL; int i; @@ -4463,6 +4484,35 @@ static void bond_set_xmit_hash_policy(struct bonding *bond) } } +static int bond_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + const struct bonding *bond = netdev_priv(dev); + + switch (bond->params.mode) { + case BOND_MODE_ROUNDROBIN: + return bond_xmit_roundrobin(skb, dev); + case BOND_MODE_ACTIVEBACKUP: + return bond_xmit_activebackup(skb, dev); + case BOND_MODE_XOR: + return bond_xmit_xor(skb, dev); + case BOND_MODE_BROADCAST: + return bond_xmit_broadcast(skb, dev); + case BOND_MODE_8023AD: + return bond_3ad_xmit_xor(skb, dev); + case BOND_MODE_ALB: + case BOND_MODE_TLB: + return bond_alb_xmit(skb, dev); + default: + /* Should never happen, mode already checked */ + printk(KERN_ERR DRV_NAME ": %s: Error: Unknown bonding mode %d\n", + dev->name, bond->params.mode); + WARN_ON_ONCE(1); + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } +} + + /* * set bond mode specific net device operations */ @@ -4472,29 +4522,22 @@ void bond_set_mode_ops(struct bonding *bond, int mode) switch (mode) { case BOND_MODE_ROUNDROBIN: - bond_dev->hard_start_xmit = bond_xmit_roundrobin; break; case BOND_MODE_ACTIVEBACKUP: - bond_dev->hard_start_xmit = bond_xmit_activebackup; break; case BOND_MODE_XOR: - bond_dev->hard_start_xmit = bond_xmit_xor; bond_set_xmit_hash_policy(bond); break; case BOND_MODE_BROADCAST: - bond_dev->hard_start_xmit = bond_xmit_broadcast; break; case BOND_MODE_8023AD: bond_set_master_3ad_flags(bond); - bond_dev->hard_start_xmit = bond_3ad_xmit_xor; bond_set_xmit_hash_policy(bond); break; case BOND_MODE_ALB: bond_set_master_alb_flags(bond); /* FALLTHRU */ case BOND_MODE_TLB: - bond_dev->hard_start_xmit = bond_alb_xmit; - bond_dev->set_mac_address = bond_alb_set_mac_address; break; default: /* Should never happen, mode already checked */ @@ -4524,15 +4567,30 @@ static const struct ethtool_ops bond_ethtool_ops = { .get_flags = ethtool_op_get_flags, }; +static const struct net_device_ops bond_netdev_ops = { + .ndo_open = bond_open, + .ndo_stop = bond_close, + .ndo_start_xmit = bond_start_xmit, + .ndo_get_stats = bond_get_stats, + .ndo_do_ioctl = bond_do_ioctl, + .ndo_set_multicast_list = bond_set_multicast_list, + .ndo_change_mtu = bond_change_mtu, + .ndo_set_mac_address = bond_set_mac_address, + .ndo_neigh_setup = bond_neigh_setup, + .ndo_vlan_rx_register = bond_vlan_rx_register, + .ndo_vlan_rx_add_vid = bond_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = bond_vlan_rx_kill_vid, +}; + /* * Does not allocate but creates a /proc entry. * Allowed to fail. */ static int bond_init(struct net_device *bond_dev, struct bond_params *params) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); - dprintk("Begin bond_init for %s\n", bond_dev->name); + pr_debug("Begin bond_init for %s\n", bond_dev->name); /* initialize rwlocks */ rwlock_init(&bond->lock); @@ -4551,20 +4609,13 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params) bond->primary_slave = NULL; bond->dev = bond_dev; bond->send_grat_arp = 0; + bond->send_unsol_na = 0; bond->setup_by_slave = 0; INIT_LIST_HEAD(&bond->vlan_list); /* Initialize the device entry points */ - bond_dev->open = bond_open; - bond_dev->stop = bond_close; - bond_dev->get_stats = bond_get_stats; - bond_dev->do_ioctl = bond_do_ioctl; + bond_dev->netdev_ops = &bond_netdev_ops; bond_dev->ethtool_ops = &bond_ethtool_ops; - bond_dev->set_multicast_list = bond_set_multicast_list; - bond_dev->change_mtu = bond_change_mtu; - bond_dev->set_mac_address = bond_set_mac_address; - bond_dev->validate_addr = NULL; - bond_set_mode_ops(bond, bond->params.mode); bond_dev->destructor = bond_destructor; @@ -4573,6 +4624,8 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params) bond_dev->tx_queue_len = 0; bond_dev->flags |= IFF_MASTER|IFF_MULTICAST; bond_dev->priv_flags |= IFF_BONDING; + if (bond->params.arp_interval) + bond_dev->priv_flags |= IFF_MASTER_ARPMON; /* At first, we block adding VLANs. That's the only way to * prevent problems that occur when adding VLANs over an @@ -4591,9 +4644,6 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params) * when there are slaves that are not hw accel * capable */ - bond_dev->vlan_rx_register = bond_vlan_rx_register; - bond_dev->vlan_rx_add_vid = bond_vlan_rx_add_vid; - bond_dev->vlan_rx_kill_vid = bond_vlan_rx_kill_vid; bond_dev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER); @@ -4632,7 +4682,7 @@ static void bond_work_cancel_all(struct bonding *bond) */ static void bond_deinit(struct net_device *bond_dev) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); list_del(&bond->bond_list); @@ -4672,7 +4722,7 @@ static void bond_free_all(void) * some mode names are substrings of other names, and calls from sysfs * may have whitespace in the name (trailing newlines, for example). */ -int bond_parse_parm(const char *buf, struct bond_parm_tbl *tbl) +int bond_parse_parm(const char *buf, const struct bond_parm_tbl *tbl) { int mode = -1, i, rv; char *p, modestr[BOND_MAX_MODENAME_LEN + 1] = { 0, }; @@ -4751,6 +4801,23 @@ static int bond_check_params(struct bond_params *params) } } + if (ad_select) { + params->ad_select = bond_parse_parm(ad_select, ad_select_tbl); + if (params->ad_select == -1) { + printk(KERN_ERR DRV_NAME + ": Error: Invalid ad_select \"%s\"\n", + ad_select == NULL ? "NULL" : ad_select); + return -EINVAL; + } + + if (bond_mode != BOND_MODE_8023AD) { + printk(KERN_WARNING DRV_NAME + ": ad_select param only affects 802.3ad mode\n"); + } + } else { + params->ad_select = BOND_AD_STABLE; + } + if (max_bonds < 0 || max_bonds > INT_MAX) { printk(KERN_WARNING DRV_NAME ": Warning: max_bonds (%d) not in range %d-%d, so it " @@ -4798,6 +4865,13 @@ static int bond_check_params(struct bond_params *params) num_grat_arp = 1; } + if (num_unsol_na < 0 || num_unsol_na > 255) { + printk(KERN_WARNING DRV_NAME + ": Warning: num_unsol_na (%d) not in range 0-255 so it " + "was reset to 1 \n", num_unsol_na); + num_unsol_na = 1; + } + /* reset values for 802.3ad */ if (bond_mode == BOND_MODE_8023AD) { if (!miimon) { @@ -4999,6 +5073,7 @@ static int bond_check_params(struct bond_params *params) params->xmit_policy = xmit_hashtype; params->miimon = miimon; params->num_grat_arp = num_grat_arp; + params->num_unsol_na = num_unsol_na; params->arp_interval = arp_interval; params->arp_validate = arp_validate_value; params->updelay = updelay; @@ -5099,7 +5174,7 @@ int bond_create(char *name, struct bond_params *params) up_write(&bonding_rwsem); rtnl_unlock(); /* allows sysfs registration of net device */ - res = bond_create_sysfs_entry(bond_dev->priv); + res = bond_create_sysfs_entry(netdev_priv(bond_dev)); if (res < 0) { rtnl_lock(); down_write(&bonding_rwsem); @@ -5151,6 +5226,7 @@ static int __init bonding_init(void) register_netdevice_notifier(&bond_netdev_notifier); register_inetaddr_notifier(&bond_inetaddr_notifier); + bond_register_ipv6_notifier(); goto out; err: @@ -5173,6 +5249,7 @@ static void __exit bonding_exit(void) { unregister_netdevice_notifier(&bond_netdev_notifier); unregister_inetaddr_notifier(&bond_inetaddr_notifier); + bond_unregister_ipv6_notifier(); bond_destroy_sysfs(); diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 3bdb47382521149010c7e478039fd190cb6b3868..18cf4787874cadb1b3671aa1d2419d76a81c7020 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -36,22 +36,13 @@ #include #include -/* #define BONDING_DEBUG 1 */ #include "bonding.h" + #define to_dev(obj) container_of(obj,struct device,kobj) -#define to_bond(cd) ((struct bonding *)(to_net_dev(cd)->priv)) +#define to_bond(cd) ((struct bonding *)(netdev_priv(to_net_dev(cd)))) /*---------------------------- Declarations -------------------------------*/ - -extern struct list_head bond_dev_list; -extern struct bond_params bonding_defaults; -extern struct bond_parm_tbl bond_mode_tbl[]; -extern struct bond_parm_tbl bond_lacp_tbl[]; -extern struct bond_parm_tbl xmit_hashtype_tbl[]; -extern struct bond_parm_tbl arp_validate_tbl[]; -extern struct bond_parm_tbl fail_over_mac_tbl[]; - static int expected_refcount = -1; /*--------------------------- Data Structures -----------------------------*/ @@ -316,18 +307,12 @@ static ssize_t bonding_store_slaves(struct device *d, /* Set the slave's MTU to match the bond */ original_mtu = dev->mtu; - if (dev->mtu != bond->dev->mtu) { - if (dev->change_mtu) { - res = dev->change_mtu(dev, - bond->dev->mtu); - if (res) { - ret = res; - goto out; - } - } else { - dev->mtu = bond->dev->mtu; - } + res = dev_set_mtu(dev, bond->dev->mtu); + if (res) { + ret = res; + goto out; } + res = bond_enslave(bond->dev, dev); bond_for_each_slave(bond, slave, i) if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0) @@ -356,11 +341,7 @@ static ssize_t bonding_store_slaves(struct device *d, goto out; } /* set the slave MTU to the default */ - if (dev->change_mtu) { - dev->change_mtu(dev, original_mtu); - } else { - dev->mtu = original_mtu; - } + dev_set_mtu(dev, original_mtu); } else { printk(KERN_ERR DRV_NAME ": unable to remove non-existent slave %s for bond %s.\n", @@ -620,6 +601,8 @@ static ssize_t bonding_store_arp_interval(struct device *d, ": %s: Setting ARP monitoring interval to %d.\n", bond->dev->name, new_value); bond->params.arp_interval = new_value; + if (bond->params.arp_interval) + bond->dev->priv_flags |= IFF_MASTER_ARPMON; if (bond->params.miimon) { printk(KERN_INFO DRV_NAME ": %s: ARP monitoring cannot be used with MII monitoring. " @@ -672,8 +655,8 @@ static ssize_t bonding_show_arp_targets(struct device *d, for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) { if (bond->params.arp_targets[i]) - res += sprintf(buf + res, "%u.%u.%u.%u ", - NIPQUAD(bond->params.arp_targets[i])); + res += sprintf(buf + res, "%pI4 ", + &bond->params.arp_targets[i]); } if (res) buf[res-1] = '\n'; /* eat the leftover space */ @@ -695,8 +678,8 @@ static ssize_t bonding_store_arp_targets(struct device *d, if (buf[0] == '+') { if ((newtarget == 0) || (newtarget == htonl(INADDR_BROADCAST))) { printk(KERN_ERR DRV_NAME - ": %s: invalid ARP target %u.%u.%u.%u specified for addition\n", - bond->dev->name, NIPQUAD(newtarget)); + ": %s: invalid ARP target %pI4 specified for addition\n", + bond->dev->name, &newtarget); ret = -EINVAL; goto out; } @@ -704,8 +687,8 @@ static ssize_t bonding_store_arp_targets(struct device *d, for (i = 0; (i < BOND_MAX_ARP_TARGETS); i++) { if (targets[i] == newtarget) { /* duplicate */ printk(KERN_ERR DRV_NAME - ": %s: ARP target %u.%u.%u.%u is already present\n", - bond->dev->name, NIPQUAD(newtarget)); + ": %s: ARP target %pI4 is already present\n", + bond->dev->name, &newtarget); if (done) targets[i] = 0; ret = -EINVAL; @@ -713,8 +696,8 @@ static ssize_t bonding_store_arp_targets(struct device *d, } if (targets[i] == 0 && !done) { printk(KERN_INFO DRV_NAME - ": %s: adding ARP target %d.%d.%d.%d.\n", - bond->dev->name, NIPQUAD(newtarget)); + ": %s: adding ARP target %pI4.\n", + bond->dev->name, &newtarget); done = 1; targets[i] = newtarget; } @@ -731,8 +714,8 @@ static ssize_t bonding_store_arp_targets(struct device *d, else if (buf[0] == '-') { if ((newtarget == 0) || (newtarget == htonl(INADDR_BROADCAST))) { printk(KERN_ERR DRV_NAME - ": %s: invalid ARP target %d.%d.%d.%d specified for removal\n", - bond->dev->name, NIPQUAD(newtarget)); + ": %s: invalid ARP target %pI4 specified for removal\n", + bond->dev->name, &newtarget); ret = -EINVAL; goto out; } @@ -740,16 +723,16 @@ static ssize_t bonding_store_arp_targets(struct device *d, for (i = 0; (i < BOND_MAX_ARP_TARGETS); i++) { if (targets[i] == newtarget) { printk(KERN_INFO DRV_NAME - ": %s: removing ARP target %d.%d.%d.%d.\n", - bond->dev->name, NIPQUAD(newtarget)); + ": %s: removing ARP target %pI4.\n", + bond->dev->name, &newtarget); targets[i] = 0; done = 1; } } if (!done) { printk(KERN_INFO DRV_NAME - ": %s: unable to remove nonexistent ARP target %d.%d.%d.%d.\n", - bond->dev->name, NIPQUAD(newtarget)); + ": %s: unable to remove nonexistent ARP target %pI4.\n", + bond->dev->name, &newtarget); ret = -EINVAL; goto out; } @@ -942,6 +925,53 @@ static ssize_t bonding_store_lacp(struct device *d, } static DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, bonding_show_lacp, bonding_store_lacp); +static ssize_t bonding_show_ad_select(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct bonding *bond = to_bond(d); + + return sprintf(buf, "%s %d\n", + ad_select_tbl[bond->params.ad_select].modename, + bond->params.ad_select); +} + + +static ssize_t bonding_store_ad_select(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int new_value, ret = count; + struct bonding *bond = to_bond(d); + + if (bond->dev->flags & IFF_UP) { + printk(KERN_ERR DRV_NAME + ": %s: Unable to update ad_select because interface " + "is up.\n", bond->dev->name); + ret = -EPERM; + goto out; + } + + new_value = bond_parse_parm(buf, ad_select_tbl); + + if (new_value != -1) { + bond->params.ad_select = new_value; + printk(KERN_INFO DRV_NAME + ": %s: Setting ad_select to %s (%d).\n", + bond->dev->name, ad_select_tbl[new_value].modename, + new_value); + } else { + printk(KERN_ERR DRV_NAME + ": %s: Ignoring invalid ad_select value %.*s.\n", + bond->dev->name, (int)strlen(buf) - 1, buf); + ret = -EINVAL; + } +out: + return ret; +} + +static DEVICE_ATTR(ad_select, S_IRUGO | S_IWUSR, bonding_show_ad_select, bonding_store_ad_select); + /* * Show and set the number of grat ARP to send after a failover event. */ @@ -981,6 +1011,47 @@ static ssize_t bonding_store_n_grat_arp(struct device *d, return ret; } static DEVICE_ATTR(num_grat_arp, S_IRUGO | S_IWUSR, bonding_show_n_grat_arp, bonding_store_n_grat_arp); + +/* + * Show and set the number of unsolicted NA's to send after a failover event. + */ +static ssize_t bonding_show_n_unsol_na(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct bonding *bond = to_bond(d); + + return sprintf(buf, "%d\n", bond->params.num_unsol_na); +} + +static ssize_t bonding_store_n_unsol_na(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int new_value, ret = count; + struct bonding *bond = to_bond(d); + + if (sscanf(buf, "%d", &new_value) != 1) { + printk(KERN_ERR DRV_NAME + ": %s: no num_unsol_na value specified.\n", + bond->dev->name); + ret = -EINVAL; + goto out; + } + if (new_value < 0 || new_value > 255) { + printk(KERN_ERR DRV_NAME + ": %s: Invalid num_unsol_na value %d not in range 0-255; rejected.\n", + bond->dev->name, new_value); + ret = -EINVAL; + goto out; + } else { + bond->params.num_unsol_na = new_value; + } +out: + return ret; +} +static DEVICE_ATTR(num_unsol_na, S_IRUGO | S_IWUSR, bonding_show_n_unsol_na, bonding_store_n_unsol_na); + /* * Show and set the MII monitor interval. There are two tricky bits * here. First, if MII monitoring is activated, then we must disable @@ -1039,6 +1110,7 @@ static ssize_t bonding_store_miimon(struct device *d, "ARP monitoring. Disabling ARP monitoring...\n", bond->dev->name); bond->params.arp_interval = 0; + bond->dev->priv_flags &= ~IFF_MASTER_ARPMON; if (bond->params.arp_validate) { bond_unregister_arp(bond); bond->params.arp_validate = @@ -1391,13 +1463,11 @@ static ssize_t bonding_show_ad_partner_mac(struct device *d, { int count = 0; struct bonding *bond = to_bond(d); - DECLARE_MAC_BUF(mac); if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; if (!bond_3ad_get_active_agg_info(bond, &ad_info)) { - count = sprintf(buf,"%s\n", - print_mac(mac, ad_info.partner_system)); + count = sprintf(buf, "%pM\n", ad_info.partner_system); } } @@ -1417,8 +1487,10 @@ static struct attribute *per_bond_attrs[] = { &dev_attr_downdelay.attr, &dev_attr_updelay.attr, &dev_attr_lacp_rate.attr, + &dev_attr_ad_select.attr, &dev_attr_xmit_hash_policy.attr, &dev_attr_num_grat_arp.attr, + &dev_attr_num_unsol_na.attr, &dev_attr_miimon.attr, &dev_attr_primary.attr, &dev_attr_use_carrier.attr, diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index ffb668dd6d3b00eddbc328513b785e42c31d492d..ca849d2adf98d7a79861b6c333a6f0357fe789cf 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -19,23 +19,18 @@ #include #include #include +#include #include "bond_3ad.h" #include "bond_alb.h" -#define DRV_VERSION "3.3.0" -#define DRV_RELDATE "June 10, 2008" +#define DRV_VERSION "3.5.0" +#define DRV_RELDATE "November 4, 2008" #define DRV_NAME "bonding" #define DRV_DESCRIPTION "Ethernet Channel Bonding Driver" #define BOND_MAX_ARP_TARGETS 16 -#ifdef BONDING_DEBUG -#define dprintk(fmt, args...) \ - printk(KERN_DEBUG \ - DRV_NAME ": %s() %d: " fmt, __func__, __LINE__ , ## args ) -#else -#define dprintk(fmt, args...) -#endif /* BONDING_DEBUG */ +extern struct list_head bond_dev_list; #define IS_UP(dev) \ ((((dev)->flags & IFF_UP) == IFF_UP) && \ @@ -126,6 +121,7 @@ struct bond_params { int xmit_policy; int miimon; int num_grat_arp; + int num_unsol_na; int arp_interval; int arp_validate; int use_carrier; @@ -133,6 +129,7 @@ struct bond_params { int updelay; int downdelay; int lacp_fast; + int ad_select; char primary[IFNAMSIZ]; __be32 arp_targets[BOND_MAX_ARP_TARGETS]; }; @@ -148,6 +145,9 @@ struct vlan_entry { struct list_head vlan_list; __be32 vlan_ip; unsigned short vlan_id; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + struct in6_addr vlan_ipv6; +#endif }; struct slave { @@ -195,6 +195,7 @@ struct bonding { rwlock_t curr_slave_lock; s8 kill_timers; s8 send_grat_arp; + s8 send_unsol_na; s8 setup_by_slave; struct net_device_stats stats; #ifdef CONFIG_PROC_FS @@ -218,6 +219,9 @@ struct bonding { struct delayed_work arp_work; struct delayed_work alb_work; struct delayed_work ad_work; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + struct in6_addr master_ipv6; +#endif }; /** @@ -245,7 +249,13 @@ static inline struct bonding *bond_get_bond_by_slave(struct slave *slave) return NULL; } - return (struct bonding *)slave->dev->master->priv; + return (struct bonding *)netdev_priv(slave->dev->master); +} + +static inline bool bond_is_lb(const struct bonding *bond) +{ + return bond->params.mode == BOND_MODE_TLB + || bond->params.mode == BOND_MODE_ALB; } #define BOND_FOM_NONE 0 @@ -275,7 +285,7 @@ static inline unsigned long slave_last_rx(struct bonding *bond, static inline void bond_set_slave_inactive_flags(struct slave *slave) { - struct bonding *bond = slave->dev->master->priv; + struct bonding *bond = netdev_priv(slave->dev->master); if (bond->params.mode != BOND_MODE_TLB && bond->params.mode != BOND_MODE_ALB) slave->state = BOND_STATE_BACKUP; @@ -327,7 +337,7 @@ void bond_mii_monitor(struct work_struct *); void bond_loadbalance_arp_mon(struct work_struct *); void bond_activebackup_arp_mon(struct work_struct *); void bond_set_mode_ops(struct bonding *bond, int mode); -int bond_parse_parm(const char *mode_arg, struct bond_parm_tbl *tbl); +int bond_parse_parm(const char *mode_arg, const struct bond_parm_tbl *tbl); void bond_select_active_slave(struct bonding *bond); void bond_change_active_slave(struct bonding *bond, struct slave *new_active); void bond_register_arp(struct bonding *); @@ -335,11 +345,35 @@ void bond_unregister_arp(struct bonding *); /* exported from bond_main.c */ extern struct list_head bond_dev_list; -extern struct bond_parm_tbl bond_lacp_tbl[]; -extern struct bond_parm_tbl bond_mode_tbl[]; -extern struct bond_parm_tbl xmit_hashtype_tbl[]; -extern struct bond_parm_tbl arp_validate_tbl[]; -extern struct bond_parm_tbl fail_over_mac_tbl[]; +extern const struct bond_parm_tbl bond_lacp_tbl[]; +extern const struct bond_parm_tbl bond_mode_tbl[]; +extern const struct bond_parm_tbl xmit_hashtype_tbl[]; +extern const struct bond_parm_tbl arp_validate_tbl[]; +extern const struct bond_parm_tbl fail_over_mac_tbl[]; +extern struct bond_params bonding_defaults; +extern struct bond_parm_tbl ad_select_tbl[]; + +/* exported from bond_sysfs.c */ +extern struct rw_semaphore bonding_rwsem; + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +void bond_send_unsolicited_na(struct bonding *bond); +void bond_register_ipv6_notifier(void); +void bond_unregister_ipv6_notifier(void); +#else +static inline void bond_send_unsolicited_na(struct bonding *bond) +{ + return; +} +static inline void bond_register_ipv6_notifier(void) +{ + return; +} +static inline void bond_unregister_ipv6_notifier(void) +{ + return; +} +#endif #endif /* _LINUX_BONDING_H */ diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c index 103f0f1df28065e9b30fab934f1f43184f654293..a10c1d7b3b0a6383a0fd255d1132dfabe49cbeca 100644 --- a/drivers/net/can/vcan.c +++ b/drivers/net/can/vcan.c @@ -128,26 +128,30 @@ static int vcan_tx(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } +static const struct net_device_ops vcan_netdev_ops = { + .ndo_start_xmit = vcan_tx, +}; + static void vcan_setup(struct net_device *dev) { - dev->type = ARPHRD_CAN; - dev->mtu = sizeof(struct can_frame); - dev->hard_header_len = 0; - dev->addr_len = 0; - dev->tx_queue_len = 0; - dev->flags = IFF_NOARP; + dev->type = ARPHRD_CAN; + dev->mtu = sizeof(struct can_frame); + dev->hard_header_len = 0; + dev->addr_len = 0; + dev->tx_queue_len = 0; + dev->flags = IFF_NOARP; /* set flags according to driver capabilities */ if (echo) dev->flags |= IFF_ECHO; - dev->hard_start_xmit = vcan_tx; - dev->destructor = free_netdev; + dev->netdev_ops = &vcan_netdev_ops; + dev->destructor = free_netdev; } static struct rtnl_link_ops vcan_link_ops __read_mostly = { - .kind = "vcan", - .setup = vcan_setup, + .kind = "vcan", + .setup = vcan_setup, }; static __init int vcan_init_module(void) diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index 86909cfb14de77b458131940110d290e76c6197f..321f43d9f0e2caf56a2fb4263e338bc34a80f94e 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -2347,7 +2347,7 @@ static int cas_rx_ringN(struct cas *cp, int ring, int budget) drops = 0; while (1) { struct cas_rx_comp *rxc = rxcs + entry; - struct sk_buff *skb; + struct sk_buff *uninitialized_var(skb); int type, len; u64 words[4]; int i, dring; @@ -2405,7 +2405,6 @@ static int cas_rx_ringN(struct cas *cp, int ring, int budget) cp->net_stats[ring].rx_packets++; cp->net_stats[ring].rx_bytes += len; spin_unlock(&cp->stat_lock[ring]); - cp->dev->last_rx = jiffies; next: npackets++; @@ -2507,7 +2506,7 @@ static irqreturn_t cas_interruptN(int irq, void *dev_id) if (status & INTR_RX_DONE_ALT) { /* handle rx separately */ #ifdef USE_NAPI cas_mask_intr(cp); - netif_rx_schedule(dev, &cp->napi); + netif_rx_schedule(&cp->napi); #else cas_rx_ringN(cp, ring, 0); #endif @@ -2558,7 +2557,7 @@ static irqreturn_t cas_interrupt1(int irq, void *dev_id) if (status & INTR_RX_DONE_ALT) { /* handle rx separately */ #ifdef USE_NAPI cas_mask_intr(cp); - netif_rx_schedule(dev, &cp->napi); + netif_rx_schedule(&cp->napi); #else cas_rx_ringN(cp, 1, 0); #endif @@ -2614,7 +2613,7 @@ static irqreturn_t cas_interrupt(int irq, void *dev_id) if (status & INTR_RX_DONE) { #ifdef USE_NAPI cas_mask_intr(cp); - netif_rx_schedule(dev, &cp->napi); + netif_rx_schedule(&cp->napi); #else cas_rx_ringN(cp, 0, 0); #endif @@ -2692,7 +2691,7 @@ static int cas_poll(struct napi_struct *napi, int budget) #endif spin_unlock_irqrestore(&cp->lock, flags); if (enable_intr) { - netif_rx_complete(dev, napi); + netif_rx_complete(napi); cas_unmask_intr(cp); } return credits; @@ -4988,7 +4987,6 @@ static int __devinit cas_init_one(struct pci_dev *pdev, int i, err, pci_using_dac; u16 pci_cmd; u8 orig_cacheline_size = 0, cas_cacheline_size = 0; - DECLARE_MAC_BUF(mac); if (cas_version_printed++ == 0) printk(KERN_INFO "%s", version); @@ -5201,12 +5199,12 @@ static int __devinit cas_init_one(struct pci_dev *pdev, i = readl(cp->regs + REG_BIM_CFG); printk(KERN_INFO "%s: Sun Cassini%s (%sbit/%sMHz PCI/%s) " - "Ethernet[%d] %s\n", dev->name, + "Ethernet[%d] %pM\n", dev->name, (cp->cas_flags & CAS_FLAG_REG_PLUS) ? "+" : "", (i & BIM_CFG_32BIT) ? "32" : "64", (i & BIM_CFG_66MHZ) ? "66" : "33", (cp->phy_type == CAS_PHY_SERDES) ? "Fi" : "Cu", pdev->irq, - print_mac(mac, dev->dev_addr)); + dev->dev_addr); pci_set_drvdata(pdev, dev); cp->hw_running = 1; diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c index 638c9a27a7a64902f00dd2251382ed4ff8b1de55..9b6011e7678e3552d51b9692d53aad4477724519 100644 --- a/drivers/net/chelsio/cxgb2.c +++ b/drivers/net/chelsio/cxgb2.c @@ -120,7 +120,7 @@ static const char pci_speed[][4] = { */ static void t1_set_rxmode(struct net_device *dev) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; struct cmac *mac = adapter->port[dev->if_port].mac; struct t1_rx_mode rm; @@ -252,7 +252,7 @@ static void cxgb_down(struct adapter *adapter) static int cxgb_open(struct net_device *dev) { int err; - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; int other_ports = adapter->open_device_map & PORT_MASK; napi_enable(&adapter->napi); @@ -272,7 +272,7 @@ static int cxgb_open(struct net_device *dev) static int cxgb_close(struct net_device *dev) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; struct port_info *p = &adapter->port[dev->if_port]; struct cmac *mac = p->mac; @@ -298,7 +298,7 @@ static int cxgb_close(struct net_device *dev) static struct net_device_stats *t1_get_stats(struct net_device *dev) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; struct port_info *p = &adapter->port[dev->if_port]; struct net_device_stats *ns = &p->netstats; const struct cmac_statistics *pstats; @@ -346,14 +346,14 @@ static struct net_device_stats *t1_get_stats(struct net_device *dev) static u32 get_msglevel(struct net_device *dev) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; return adapter->msg_enable; } static void set_msglevel(struct net_device *dev, u32 val) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; adapter->msg_enable = val; } @@ -434,7 +434,7 @@ static int get_regs_len(struct net_device *dev) static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; strcpy(info->driver, DRV_NAME); strcpy(info->version, DRV_VERSION); @@ -461,7 +461,7 @@ static void get_strings(struct net_device *dev, u32 stringset, u8 *data) static void get_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; struct cmac *mac = adapter->port[dev->if_port].mac; const struct cmac_statistics *s; const struct sge_intr_counts *t; @@ -552,7 +552,7 @@ static inline void reg_block_dump(struct adapter *ap, void *buf, static void get_regs(struct net_device *dev, struct ethtool_regs *regs, void *buf) { - struct adapter *ap = dev->priv; + struct adapter *ap = dev->ml_priv; /* * Version scheme: bits 0..9: chip version, bits 10..15: chip revision @@ -574,7 +574,7 @@ static void get_regs(struct net_device *dev, struct ethtool_regs *regs, static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; struct port_info *p = &adapter->port[dev->if_port]; cmd->supported = p->link_config.supported; @@ -634,7 +634,7 @@ static int speed_duplex_to_caps(int speed, int duplex) static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; struct port_info *p = &adapter->port[dev->if_port]; struct link_config *lc = &p->link_config; @@ -669,7 +669,7 @@ static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd) static void get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; struct port_info *p = &adapter->port[dev->if_port]; epause->autoneg = (p->link_config.requested_fc & PAUSE_AUTONEG) != 0; @@ -680,7 +680,7 @@ static void get_pauseparam(struct net_device *dev, static int set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; struct port_info *p = &adapter->port[dev->if_port]; struct link_config *lc = &p->link_config; @@ -709,14 +709,14 @@ static int set_pauseparam(struct net_device *dev, static u32 get_rx_csum(struct net_device *dev) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; return (adapter->flags & RX_CSUM_ENABLED) != 0; } static int set_rx_csum(struct net_device *dev, u32 data) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; if (data) adapter->flags |= RX_CSUM_ENABLED; @@ -727,7 +727,7 @@ static int set_rx_csum(struct net_device *dev, u32 data) static int set_tso(struct net_device *dev, u32 value) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; if (!(adapter->flags & TSO_CAPABLE)) return value ? -EOPNOTSUPP : 0; @@ -736,7 +736,7 @@ static int set_tso(struct net_device *dev, u32 value) static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; int jumbo_fl = t1_is_T1B(adapter) ? 1 : 0; e->rx_max_pending = MAX_RX_BUFFERS; @@ -752,7 +752,7 @@ static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e) static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; int jumbo_fl = t1_is_T1B(adapter) ? 1 : 0; if (e->rx_pending > MAX_RX_BUFFERS || e->rx_mini_pending || @@ -776,7 +776,7 @@ static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e) static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; adapter->params.sge.rx_coalesce_usecs = c->rx_coalesce_usecs; adapter->params.sge.coalesce_enable = c->use_adaptive_rx_coalesce; @@ -787,7 +787,7 @@ static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c) static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; c->rx_coalesce_usecs = adapter->params.sge.rx_coalesce_usecs; c->rate_sample_interval = adapter->params.sge.sample_interval_usecs; @@ -797,7 +797,7 @@ static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c) static int get_eeprom_len(struct net_device *dev) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; return t1_is_asic(adapter) ? EEPROM_SIZE : 0; } @@ -810,7 +810,7 @@ static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e, { int i; u8 buf[EEPROM_SIZE] __attribute__((aligned(4))); - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; e->magic = EEPROM_MAGIC(adapter); for (i = e->offset & ~3; i < e->offset + e->len; i += sizeof(u32)) @@ -848,7 +848,7 @@ static const struct ethtool_ops t1_ethtool_ops = { static int t1_ioctl(struct net_device *dev, struct ifreq *req, int cmd) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; struct mii_ioctl_data *data = if_mii(req); switch (cmd) { @@ -887,7 +887,7 @@ static int t1_ioctl(struct net_device *dev, struct ifreq *req, int cmd) static int t1_change_mtu(struct net_device *dev, int new_mtu) { int ret; - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; struct cmac *mac = adapter->port[dev->if_port].mac; if (!mac->ops->set_mtu) @@ -902,7 +902,7 @@ static int t1_change_mtu(struct net_device *dev, int new_mtu) static int t1_set_mac_addr(struct net_device *dev, void *p) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; struct cmac *mac = adapter->port[dev->if_port].mac; struct sockaddr *addr = p; @@ -915,10 +915,10 @@ static int t1_set_mac_addr(struct net_device *dev, void *p) } #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) -static void vlan_rx_register(struct net_device *dev, +static void t1_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; spin_lock_irq(&adapter->async_lock); adapter->vlan_grp = grp; @@ -931,7 +931,7 @@ static void vlan_rx_register(struct net_device *dev, static void t1_netpoll(struct net_device *dev) { unsigned long flags; - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; local_irq_save(flags); t1_interrupt(adapter->pdev->irq, adapter); @@ -1010,6 +1010,24 @@ void t1_fatal_err(struct adapter *adapter) adapter->name); } +static const struct net_device_ops cxgb_netdev_ops = { + .ndo_open = cxgb_open, + .ndo_stop = cxgb_close, + .ndo_start_xmit = t1_start_xmit, + .ndo_get_stats = t1_get_stats, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = t1_set_rxmode, + .ndo_do_ioctl = t1_ioctl, + .ndo_change_mtu = t1_change_mtu, + .ndo_set_mac_address = t1_set_mac_addr, +#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) + .ndo_vlan_rx_register = t1_vlan_rx_register, +#endif +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = t1_netpoll, +#endif +}; + static int __devinit init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -1077,7 +1095,7 @@ static int __devinit init_one(struct pci_dev *pdev, SET_NETDEV_DEV(netdev, &pdev->dev); if (!adapter) { - adapter = netdev->priv; + adapter = netdev_priv(netdev); adapter->pdev = pdev; adapter->port[0].dev = netdev; /* so we don't leak it */ @@ -1118,7 +1136,7 @@ static int __devinit init_one(struct pci_dev *pdev, netdev->if_port = i; netdev->mem_start = mmio_start; netdev->mem_end = mmio_start + mmio_len - 1; - netdev->priv = adapter; + netdev->ml_priv = adapter; netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; netdev->features |= NETIF_F_LLTX; @@ -1130,7 +1148,6 @@ static int __devinit init_one(struct pci_dev *pdev, adapter->flags |= VLAN_ACCEL_CAPABLE; netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - netdev->vlan_rx_register = vlan_rx_register; #endif /* T204: disable TSO */ @@ -1140,19 +1157,10 @@ static int __devinit init_one(struct pci_dev *pdev, } } - netdev->open = cxgb_open; - netdev->stop = cxgb_close; - netdev->hard_start_xmit = t1_start_xmit; + netdev->netdev_ops = &cxgb_netdev_ops; netdev->hard_header_len += (adapter->flags & TSO_CAPABLE) ? sizeof(struct cpl_tx_pkt_lso) : sizeof(struct cpl_tx_pkt); - netdev->get_stats = t1_get_stats; - netdev->set_multicast_list = t1_set_rxmode; - netdev->do_ioctl = t1_ioctl; - netdev->change_mtu = t1_change_mtu; - netdev->set_mac_address = t1_set_mac_addr; -#ifdef CONFIG_NET_POLL_CONTROLLER - netdev->poll_controller = t1_netpoll; -#endif + netif_napi_add(netdev, &adapter->napi, t1_poll, 64); SET_ETHTOOL_OPS(netdev, &t1_ethtool_ops); @@ -1382,7 +1390,7 @@ static inline void t1_sw_reset(struct pci_dev *pdev) static void __devexit remove_one(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; int i; for_each_port(adapter, i) { diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c index 7092df50ff784007f34f72b74aac85d6a437a42e..d984b799576373f1c7a7064d8180f476f8870f48 100644 --- a/drivers/net/chelsio/sge.c +++ b/drivers/net/chelsio/sge.c @@ -1381,7 +1381,6 @@ static void sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len) st = per_cpu_ptr(sge->port_stats[p->iff], smp_processor_id()); skb->protocol = eth_type_trans(skb, adapter->port[p->iff].dev); - skb->dev->last_rx = jiffies; if ((adapter->flags & RX_CSUM_ENABLED) && p->csum == 0xffff && skb->protocol == htons(ETH_P_IP) && (skb->data[9] == IPPROTO_TCP || skb->data[9] == IPPROTO_UDP)) { @@ -1610,11 +1609,10 @@ static int process_pure_responses(struct adapter *adapter) int t1_poll(struct napi_struct *napi, int budget) { struct adapter *adapter = container_of(napi, struct adapter, napi); - struct net_device *dev = adapter->port[0].dev; int work_done = process_responses(adapter, budget); if (likely(work_done < budget)) { - netif_rx_complete(dev, napi); + netif_rx_complete(napi); writel(adapter->sge->respQ.cidx, adapter->regs + A_SG_SLEEPING); } @@ -1628,13 +1626,11 @@ irqreturn_t t1_interrupt(int irq, void *data) int handled; if (likely(responses_pending(adapter))) { - struct net_device *dev = sge->netdev; - writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE); if (napi_schedule_prep(&adapter->napi)) { if (process_pure_responses(adapter)) - __netif_rx_schedule(dev, &adapter->napi); + __netif_rx_schedule(&adapter->napi); else { /* no data, no NAPI needed */ writel(sge->respQ.cidx, adapter->regs + A_SG_SLEEPING); @@ -1782,7 +1778,7 @@ static inline int eth_hdr_len(const void *data) */ int t1_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; struct sge *sge = adapter->sge; struct sge_port_stats *st = per_cpu_ptr(sge->port_stats[dev->if_port], smp_processor_id()); diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c index 017a5361b980c2f37b8ff1e6b05ac1d8c90a158b..f66548751c384c1bf111f69b995dd701aa60b713 100644 --- a/drivers/net/cpmac.c +++ b/drivers/net/cpmac.c @@ -428,7 +428,7 @@ static int cpmac_poll(struct napi_struct *napi, int budget) printk(KERN_WARNING "%s: rx: polling, but no queue\n", priv->dev->name); spin_unlock(&priv->rx_lock); - netif_rx_complete(priv->dev, napi); + netif_rx_complete(napi); return 0; } @@ -514,7 +514,7 @@ static int cpmac_poll(struct napi_struct *napi, int budget) if (processed == 0) { /* we ran out of packets to read, * revert to interrupt-driven mode */ - netif_rx_complete(priv->dev, napi); + netif_rx_complete(napi); cpmac_write(priv->regs, CPMAC_RX_INT_ENABLE, 1); return 0; } @@ -536,7 +536,7 @@ static int cpmac_poll(struct napi_struct *napi, int budget) } spin_unlock(&priv->rx_lock); - netif_rx_complete(priv->dev, napi); + netif_rx_complete(napi); netif_tx_stop_all_queues(priv->dev); napi_disable(&priv->napi); @@ -802,9 +802,9 @@ static irqreturn_t cpmac_irq(int irq, void *dev_id) if (status & MAC_INT_RX) { queue = (status >> 8) & 7; - if (netif_rx_schedule_prep(dev, &priv->napi)) { + if (netif_rx_schedule_prep(&priv->napi)) { cpmac_write(priv->regs, CPMAC_RX_INT_CLEAR, 1 << queue); - __netif_rx_schedule(dev, &priv->napi); + __netif_rx_schedule(&priv->napi); } } @@ -1103,7 +1103,6 @@ static int __devinit cpmac_probe(struct platform_device *pdev) struct cpmac_priv *priv; struct net_device *dev; struct plat_cpmac_data *pdata; - DECLARE_MAC_BUF(mac); pdata = pdev->dev.platform_data; @@ -1180,8 +1179,8 @@ static int __devinit cpmac_probe(struct platform_device *pdev) if (netif_msg_probe(priv)) { printk(KERN_INFO "cpmac: device %s (regs: %p, irq: %d, phy: %s, " - "mac: %s)\n", dev->name, (void *)mem->start, dev->irq, - priv->phy_name, print_mac(mac, dev->dev_addr)); + "mac: %pM)\n", dev->name, (void *)mem->start, dev->irq, + priv->phy_name, dev->dev_addr); } return 0; diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c index 7e8a63106bdf42f2aa3ba4e4303e9920fab56713..c9806c58b2fde2644505fde1409dbf6af24674fd 100644 --- a/drivers/net/cris/eth_v10.c +++ b/drivers/net/cris/eth_v10.c @@ -419,7 +419,6 @@ e100_set_mac_address(struct net_device *dev, void *p) { struct net_local *np = netdev_priv(dev); struct sockaddr *addr = p; - DECLARE_MAC_BUF(mac); spin_lock(&np->lock); /* preemption protection */ @@ -440,8 +439,7 @@ e100_set_mac_address(struct net_device *dev, void *p) /* show it in the log as well */ - printk(KERN_INFO "%s: changed MAC to %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: changed MAC to %pM\n", dev->name, dev->dev_addr); spin_unlock(&np->lock); diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index 7107620f615dfd0d17bef1b06fce245ef12411f0..d548a45d59d563f837b1634335547950210aa043 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -521,7 +521,6 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) unsigned rev_type = 0; int eeprom_buff[CHKSUM_LEN]; int retval; - DECLARE_MAC_BUF(mac); /* Initialize the device structure. */ if (!modular) { @@ -846,7 +845,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) } /* print the ethernet address. */ - printk(", MAC %s", print_mac(mac, dev->dev_addr)); + printk(", MAC %pM", dev->dev_addr); dev->open = net_open; dev->stop = net_close; @@ -1025,14 +1024,13 @@ dma_rx(struct net_device *dev) } skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); - dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes += length; } #endif /* ALLOW_DMA */ -void __init reset_chip(struct net_device *dev) +static void __init reset_chip(struct net_device *dev) { #if !defined(CONFIG_MACH_MX31ADS) #if !defined(CONFIG_MACH_IXDP2351) && !defined(CONFIG_ARCH_IXDP2X01) @@ -1719,7 +1717,6 @@ net_rx(struct net_device *dev) skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); - dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes += length; } @@ -1817,11 +1814,10 @@ static int set_mac_address(struct net_device *dev, void *p) memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); - if (net_debug) { - DECLARE_MAC_BUF(mac); - printk("%s: Setting MAC address to %s.\n", - dev->name, print_mac(mac, dev->dev_addr)); - } + if (net_debug) + printk("%s: Setting MAC address to %pM.\n", + dev->name, dev->dev_addr); + /* set the Ethernet address */ for (i=0; i < ETH_ALEN/2; i++) writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8)); diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h index bc8e2413abd25d6c5106bcc83d10098fde44489d..5b346f9eaa8b482c556351a6d7eedf8c4fcce9ba 100644 --- a/drivers/net/cxgb3/adapter.h +++ b/drivers/net/cxgb3/adapter.h @@ -63,6 +63,7 @@ struct port_info { struct link_config link_config; struct net_device_stats netstats; int activity; + __be32 iscsi_ipv4addr; }; enum { /* adapter flags */ @@ -196,6 +197,7 @@ struct sge_qset { /* an SGE queue set */ int lro_frag_len; void *lro_va; struct net_device *netdev; + struct netdev_queue *tx_q; /* associated netdev TX queue */ unsigned long txq_stopped; /* which Tx queues are stopped */ struct timer_list tx_reclaim_timer; /* reclaims TX buffers */ unsigned long port_stats[SGE_PSTAT_MAX]; @@ -294,7 +296,8 @@ int t3_mgmt_tx(struct adapter *adap, struct sk_buff *skb); void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p); int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, int irq_vec_idx, const struct qset_params *p, - int ntxq, struct net_device *dev); + int ntxq, struct net_device *dev, + struct netdev_queue *netdevq); int t3_get_desc(const struct sge_qset *qs, unsigned int qnum, unsigned int idx, unsigned char *data); irqreturn_t t3_sge_intr_msix(int irq, void *cookie); diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h index e312d315a42d4e5ded041e3c1d8c717ae6ae02a6..db4f4f575b6a1e153a8be1e4056ddf3e97da4870 100644 --- a/drivers/net/cxgb3/common.h +++ b/drivers/net/cxgb3/common.h @@ -714,7 +714,7 @@ int t3_seeprom_read(struct adapter *adapter, u32 addr, __le32 *data); int t3_seeprom_write(struct adapter *adapter, u32 addr, __le32 data); int t3_seeprom_wp(struct adapter *adapter, int enable); int t3_get_tp_version(struct adapter *adapter, u32 *vers); -int t3_check_tpsram_version(struct adapter *adapter, int *must_load); +int t3_check_tpsram_version(struct adapter *adapter); int t3_check_tpsram(struct adapter *adapter, const u8 *tp_ram, unsigned int size); int t3_set_proto_sram(struct adapter *adap, const u8 *data); @@ -722,7 +722,7 @@ int t3_read_flash(struct adapter *adapter, unsigned int addr, unsigned int nwords, u32 *data, int byte_oriented); int t3_load_fw(struct adapter *adapter, const u8 * fw_data, unsigned int size); int t3_get_fw_version(struct adapter *adapter, u32 *vers); -int t3_check_fw_version(struct adapter *adapter, int *must_load); +int t3_check_fw_version(struct adapter *adapter); int t3_init_hw(struct adapter *adapter, u32 fw_params); void mac_prep(struct cmac *mac, struct adapter *adapter, int index); void early_hw_init(struct adapter *adapter, const struct adapter_info *ai); diff --git a/drivers/net/cxgb3/cxgb3_ctl_defs.h b/drivers/net/cxgb3/cxgb3_ctl_defs.h index 1d8d46eb3c960e0efd3725d731f947abb02b438f..369fe711fd7f0dc8e974c99acbd912add1bdb773 100644 --- a/drivers/net/cxgb3/cxgb3_ctl_defs.h +++ b/drivers/net/cxgb3/cxgb3_ctl_defs.h @@ -57,6 +57,9 @@ enum { RDMA_GET_MIB = 19, GET_RX_PAGE_INFO = 50, + GET_ISCSI_IPV4ADDR = 51, + + GET_EMBEDDED_INFO = 70, }; /* @@ -86,6 +89,12 @@ struct iff_mac { u16 vlan_tag; }; +/* Structure used to request a port's iSCSI IPv4 address */ +struct iscsi_ipv4addr { + struct net_device *dev; /* the net_device */ + __be32 ipv4addr; /* the return iSCSI IPv4 address */ +}; + struct pci_dev; /* @@ -169,4 +178,12 @@ struct ofld_page_info { unsigned int page_size; /* Page size, should be a power of 2 */ unsigned int num; /* Number of pages */ }; + +/* + * Structure used to get firmware and protocol engine versions. + */ +struct ch_embedded_info { + u32 fw_vers; + u32 tp_vers; +}; #endif /* _CXGB3_OFFLOAD_CTL_DEFS_H */ diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 2c341f83d3270e8d32a42d24e1a472fffd945599..2847f947499d9f9edcdaaf672c9f876d3602d571 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -493,6 +493,36 @@ static void enable_all_napi(struct adapter *adap) napi_enable(&adap->sge.qs[i].napi); } +/** + * set_qset_lro - Turn a queue set's LRO capability on and off + * @dev: the device the qset is attached to + * @qset_idx: the queue set index + * @val: the LRO switch + * + * Sets LRO on or off for a particular queue set. + * the device's features flag is updated to reflect the LRO + * capability when all queues belonging to the device are + * in the same state. + */ +static void set_qset_lro(struct net_device *dev, int qset_idx, int val) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + int i, lro_on = 1; + + adapter->params.sge.qset[qset_idx].lro = !!val; + adapter->sge.qs[qset_idx].lro_enabled = !!val; + + /* let ethtool report LRO on only if all queues are LRO enabled */ + for (i = pi->first_qset; i < pi->first_qset + pi->nqsets; ++i) + lro_on &= adapter->params.sge.qset[i].lro; + + if (lro_on) + dev->features |= NETIF_F_LRO; + else + dev->features &= ~NETIF_F_LRO; +} + /** * setup_sge_qsets - configure SGE Tx/Rx/response queues * @adap: the adapter @@ -516,12 +546,12 @@ static int setup_sge_qsets(struct adapter *adap) pi->qs = &adap->sge.qs[pi->first_qset]; for (j = pi->first_qset; j < pi->first_qset + pi->nqsets; ++j, ++qset_idx) { - if (!pi->rx_csum_offload) - adap->params.sge.qset[qset_idx].lro = 0; + set_qset_lro(dev, qset_idx, pi->rx_csum_offload); err = t3_sge_alloc_qset(adap, qset_idx, 1, (adap->flags & USING_MSIX) ? qset_idx + 1 : irq_idx, - &adap->params.sge.qset[qset_idx], ntxq, dev); + &adap->params.sge.qset[qset_idx], ntxq, dev, + netdev_get_tx_queue(dev, j)); if (err) { t3_stop_sge_timers(adap); t3_free_sge_resources(adap); @@ -824,8 +854,8 @@ static int bind_qsets(struct adapter *adap) return err; } -#define FW_FNAME "t3fw-%d.%d.%d.bin" -#define TPSRAM_NAME "t3%c_protocol_sram-%d.%d.%d.bin" +#define FW_FNAME "cxgb3/t3fw-%d.%d.%d.bin" +#define TPSRAM_NAME "cxgb3/t3%c_psram-%d.%d.%d.bin" static int upgrade_fw(struct adapter *adap) { @@ -928,21 +958,22 @@ static int update_tpsram(struct adapter *adap) static int cxgb_up(struct adapter *adap) { int err; - int must_load; if (!(adap->flags & FULL_INIT_DONE)) { - err = t3_check_fw_version(adap, &must_load); + err = t3_check_fw_version(adap); if (err == -EINVAL) { err = upgrade_fw(adap); - if (err && must_load) - goto out; + CH_WARN(adap, "FW upgrade to %d.%d.%d %s\n", + FW_VERSION_MAJOR, FW_VERSION_MINOR, + FW_VERSION_MICRO, err ? "failed" : "succeeded"); } - err = t3_check_tpsram_version(adap, &must_load); + err = t3_check_tpsram_version(adap); if (err == -EINVAL) { err = update_tpsram(adap); - if (err && must_load) - goto out; + CH_WARN(adap, "TP upgrade to %d.%d.%d %s\n", + TP_VERSION_MAJOR, TP_VERSION_MINOR, + TP_VERSION_MICRO, err ? "failed" : "succeeded"); } /* @@ -1136,9 +1167,10 @@ static int cxgb_open(struct net_device *dev) "Could not initialize offload capabilities\n"); } + dev->real_num_tx_queues = pi->nqsets; link_start(dev); t3_port_intr_enable(adapter, pi->port_id); - netif_start_queue(dev); + netif_tx_start_all_queues(dev); if (!other_ports) schedule_chk_task(adapter); @@ -1151,7 +1183,7 @@ static int cxgb_close(struct net_device *dev) struct adapter *adapter = pi->adapter; t3_port_intr_disable(adapter, pi->port_id); - netif_stop_queue(dev); + netif_tx_stop_all_queues(dev); pi->phy.ops->power_down(&pi->phy, 1); netif_carrier_off(dev); t3_mac_disable(&pi->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX); @@ -1634,13 +1666,10 @@ static int set_rx_csum(struct net_device *dev, u32 data) p->rx_csum_offload = data; if (!data) { - struct adapter *adap = p->adapter; int i; - for (i = p->first_qset; i < p->first_qset + p->nqsets; i++) { - adap->params.sge.qset[i].lro = 0; - adap->sge.qs[i].lro_enabled = 0; - } + for (i = p->first_qset; i < p->first_qset + p->nqsets; i++) + set_qset_lro(dev, i, 0); } return 0; } @@ -1795,6 +1824,25 @@ static void get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) memset(&wol->sopass, 0, sizeof(wol->sopass)); } +static int cxgb3_set_flags(struct net_device *dev, u32 data) +{ + struct port_info *pi = netdev_priv(dev); + int i; + + if (data & ETH_FLAG_LRO) { + if (!pi->rx_csum_offload) + return -EINVAL; + + for (i = pi->first_qset; i < pi->first_qset + pi->nqsets; i++) + set_qset_lro(dev, i, 1); + + } else + for (i = pi->first_qset; i < pi->first_qset + pi->nqsets; i++) + set_qset_lro(dev, i, 0); + + return 0; +} + static const struct ethtool_ops cxgb_ethtool_ops = { .get_settings = get_settings, .set_settings = set_settings, @@ -1824,6 +1872,8 @@ static const struct ethtool_ops cxgb_ethtool_ops = { .get_regs = get_regs, .get_wol = get_wol, .set_tso = ethtool_op_set_tso, + .get_flags = ethtool_op_get_flags, + .set_flags = cxgb3_set_flags, }; static int in_range(int val, int lo, int hi) @@ -1940,11 +1990,9 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) } } } - if (t.lro >= 0) { - struct sge_qset *qs = &adapter->sge.qs[t.qset_idx]; - q->lro = t.lro; - qs->lro_enabled = t.lro; - } + if (t.lro >= 0) + set_qset_lro(dev, t.qset_idx, t.lro); + break; } case CHELSIO_GET_QSET_PARAMS:{ @@ -2783,6 +2831,22 @@ static void __devinit print_port_info(struct adapter *adap, } } +static const struct net_device_ops cxgb_netdev_ops = { + .ndo_open = cxgb_open, + .ndo_stop = cxgb_close, + .ndo_start_xmit = t3_eth_xmit, + .ndo_get_stats = cxgb_get_stats, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = cxgb_set_rxmode, + .ndo_do_ioctl = cxgb_ioctl, + .ndo_change_mtu = cxgb_change_mtu, + .ndo_set_mac_address = cxgb_set_mac_addr, + .ndo_vlan_rx_register = vlan_rx_register, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = cxgb_netpoll, +#endif +}; + static int __devinit init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -2871,7 +2935,7 @@ static int __devinit init_one(struct pci_dev *pdev, for (i = 0; i < ai->nports; ++i) { struct net_device *netdev; - netdev = alloc_etherdev(sizeof(struct port_info)); + netdev = alloc_etherdev_mq(sizeof(struct port_info), SGE_QSETS); if (!netdev) { err = -ENOMEM; goto out_free_dev; @@ -2885,6 +2949,7 @@ static int __devinit init_one(struct pci_dev *pdev, pi->rx_csum_offload = 1; pi->port_id = i; netif_carrier_off(netdev); + netif_tx_stop_all_queues(netdev); netdev->irq = pdev->irq; netdev->mem_start = mmio_start; netdev->mem_end = mmio_start + mmio_len - 1; @@ -2894,20 +2959,7 @@ static int __devinit init_one(struct pci_dev *pdev, netdev->features |= NETIF_F_HIGHDMA; netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - netdev->vlan_rx_register = vlan_rx_register; - - netdev->open = cxgb_open; - netdev->stop = cxgb_close; - netdev->hard_start_xmit = t3_eth_xmit; - netdev->get_stats = cxgb_get_stats; - netdev->set_multicast_list = cxgb_set_rxmode; - netdev->do_ioctl = cxgb_ioctl; - netdev->change_mtu = cxgb_change_mtu; - netdev->set_mac_address = cxgb_set_mac_addr; -#ifdef CONFIG_NET_POLL_CONTROLLER - netdev->poll_controller = cxgb_netpoll; -#endif - + netdev->netdev_ops = &cxgb_netdev_ops; SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops); } diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c index 265aa8a15afaed2eb5a61177917d07cd6649b476..2d7f69aff1d949a47e952997932800593444338e 100644 --- a/drivers/net/cxgb3/cxgb3_offload.c +++ b/drivers/net/cxgb3/cxgb3_offload.c @@ -182,7 +182,9 @@ static struct net_device *get_iff_from_mac(struct adapter *adapter, static int cxgb_ulp_iscsi_ctl(struct adapter *adapter, unsigned int req, void *data) { + int i; int ret = 0; + unsigned int val = 0; struct ulp_iscsi_info *uiip = data; switch (req) { @@ -191,32 +193,55 @@ static int cxgb_ulp_iscsi_ctl(struct adapter *adapter, unsigned int req, uiip->llimit = t3_read_reg(adapter, A_ULPRX_ISCSI_LLIMIT); uiip->ulimit = t3_read_reg(adapter, A_ULPRX_ISCSI_ULIMIT); uiip->tagmask = t3_read_reg(adapter, A_ULPRX_ISCSI_TAGMASK); + + val = t3_read_reg(adapter, A_ULPRX_ISCSI_PSZ); + for (i = 0; i < 4; i++, val >>= 8) + uiip->pgsz_factor[i] = val & 0xFF; + + val = t3_read_reg(adapter, A_TP_PARA_REG7); + uiip->max_txsz = + uiip->max_rxsz = min((val >> S_PMMAXXFERLEN0)&M_PMMAXXFERLEN0, + (val >> S_PMMAXXFERLEN1)&M_PMMAXXFERLEN1); /* * On tx, the iscsi pdu has to be <= tx page size and has to * fit into the Tx PM FIFO. */ - uiip->max_txsz = min(adapter->params.tp.tx_pg_size, - t3_read_reg(adapter, A_PM1_TX_CFG) >> 17); - /* on rx, the iscsi pdu has to be < rx page size and the - whole pdu + cpl headers has to fit into one sge buffer */ - uiip->max_rxsz = min_t(unsigned int, - adapter->params.tp.rx_pg_size, - (adapter->sge.qs[0].fl[1].buf_size - - sizeof(struct cpl_rx_data) * 2 - - sizeof(struct cpl_rx_data_ddp))); + val = min(adapter->params.tp.tx_pg_size, + t3_read_reg(adapter, A_PM1_TX_CFG) >> 17); + uiip->max_txsz = min(val, uiip->max_txsz); + + /* set MaxRxData to 16224 */ + val = t3_read_reg(adapter, A_TP_PARA_REG2); + if ((val >> S_MAXRXDATA) != 0x3f60) { + val &= (M_RXCOALESCESIZE << S_RXCOALESCESIZE); + val |= V_MAXRXDATA(0x3f60); + printk(KERN_INFO + "%s, iscsi set MaxRxData to 16224 (0x%x).\n", + adapter->name, val); + t3_write_reg(adapter, A_TP_PARA_REG2, val); + } + + /* + * on rx, the iscsi pdu has to be < rx page size and the + * the max rx data length programmed in TP + */ + val = min(adapter->params.tp.rx_pg_size, + ((t3_read_reg(adapter, A_TP_PARA_REG2)) >> + S_MAXRXDATA) & M_MAXRXDATA); + uiip->max_rxsz = min(val, uiip->max_rxsz); break; case ULP_ISCSI_SET_PARAMS: t3_write_reg(adapter, A_ULPRX_ISCSI_TAGMASK, uiip->tagmask); - /* set MaxRxData and MaxCoalesceSize to 16224 */ - t3_write_reg(adapter, A_TP_PARA_REG2, 0x3f603f60); /* program the ddp page sizes */ - { - int i; - unsigned int val = 0; - for (i = 0; i < 4; i++) - val |= (uiip->pgsz_factor[i] & 0xF) << (8 * i); - if (val) - t3_write_reg(adapter, A_ULPRX_ISCSI_PSZ, val); + for (i = 0; i < 4; i++) + val |= (uiip->pgsz_factor[i] & 0xF) << (8 * i); + if (val && (val != t3_read_reg(adapter, A_ULPRX_ISCSI_PSZ))) { + printk(KERN_INFO + "%s, setting iscsi pgsz 0x%x, %u,%u,%u,%u.\n", + adapter->name, val, uiip->pgsz_factor[0], + uiip->pgsz_factor[1], uiip->pgsz_factor[2], + uiip->pgsz_factor[3]); + t3_write_reg(adapter, A_ULPRX_ISCSI_PSZ, val); } break; default: @@ -407,6 +432,21 @@ static int cxgb_offload_ctl(struct t3cdev *tdev, unsigned int req, void *data) rx_page_info->page_size = tp->rx_pg_size; rx_page_info->num = tp->rx_num_pgs; break; + case GET_ISCSI_IPV4ADDR: { + struct iscsi_ipv4addr *p = data; + struct port_info *pi = netdev_priv(p->dev); + p->ipv4addr = pi->iscsi_ipv4addr; + break; + } + case GET_EMBEDDED_INFO: { + struct ch_embedded_info *e = data; + + spin_lock(&adapter->stats_lock); + t3_get_fw_version(adapter, &e->fw_vers); + t3_get_tp_version(adapter, &e->tp_vers); + spin_unlock(&adapter->stats_lock); + break; + } default: return -EOPNOTSUPP; } diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index c6480be0bc1f7ed033b9a9ed0d856d12b4490255..6c641a889471012b5e6db7bac57da040d9f36ed8 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "common.h" #include "regs.h" #include "sge_defs.h" @@ -549,16 +550,15 @@ static void *alloc_ring(struct pci_dev *pdev, size_t nelem, size_t elem_size, if (!p) return NULL; - if (sw_size) { + if (sw_size && metadata) { s = kcalloc(nelem, sw_size, GFP_KERNEL); if (!s) { dma_free_coherent(&pdev->dev, len, p, *phys); return NULL; } - } - if (metadata) *(void **)metadata = s; + } memset(p, 0, len); return p; } @@ -1121,10 +1121,10 @@ static void write_tx_pkt_wr(struct adapter *adap, struct sk_buff *skb, htonl(V_WR_TID(q->token))); } -static inline void t3_stop_queue(struct net_device *dev, struct sge_qset *qs, - struct sge_txq *q) +static inline void t3_stop_tx_queue(struct netdev_queue *txq, + struct sge_qset *qs, struct sge_txq *q) { - netif_stop_queue(dev); + netif_tx_stop_queue(txq); set_bit(TXQ_ETH, &qs->txq_stopped); q->stops++; } @@ -1138,11 +1138,13 @@ static inline void t3_stop_queue(struct net_device *dev, struct sge_qset *qs, */ int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) { + int qidx; unsigned int ndesc, pidx, credits, gen, compl; const struct port_info *pi = netdev_priv(dev); struct adapter *adap = pi->adapter; - struct sge_qset *qs = pi->qs; - struct sge_txq *q = &qs->txq[TXQ_ETH]; + struct netdev_queue *txq; + struct sge_qset *qs; + struct sge_txq *q; /* * The chip min packet length is 9 octets but play safe and reject @@ -1153,6 +1155,11 @@ int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } + qidx = skb_get_queue_mapping(skb); + qs = &pi->qs[qidx]; + q = &qs->txq[TXQ_ETH]; + txq = netdev_get_tx_queue(dev, qidx); + spin_lock(&q->lock); reclaim_completed_tx(adap, q); @@ -1160,7 +1167,7 @@ int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) ndesc = calc_tx_descs(skb); if (unlikely(credits < ndesc)) { - t3_stop_queue(dev, qs, q); + t3_stop_tx_queue(txq, qs, q); dev_err(&adap->pdev->dev, "%s: Tx ring %u full while queue awake!\n", dev->name, q->cntxt_id & 7); @@ -1170,12 +1177,12 @@ int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) q->in_use += ndesc; if (unlikely(credits - ndesc < q->stop_thres)) { - t3_stop_queue(dev, qs, q); + t3_stop_tx_queue(txq, qs, q); if (should_restart_tx(q) && test_and_clear_bit(TXQ_ETH, &qs->txq_stopped)) { q->restarts++; - netif_wake_queue(dev); + netif_tx_wake_queue(txq); } } @@ -1839,7 +1846,7 @@ static void restart_tx(struct sge_qset *qs) test_and_clear_bit(TXQ_ETH, &qs->txq_stopped)) { qs->txq[TXQ_ETH].restarts++; if (netif_running(qs->netdev)) - netif_wake_queue(qs->netdev); + netif_tx_wake_queue(qs->tx_q); } if (test_bit(TXQ_OFLD, &qs->txq_stopped) && @@ -1856,6 +1863,54 @@ static void restart_tx(struct sge_qset *qs) } } +/** + * cxgb3_arp_process - process an ARP request probing a private IP address + * @adapter: the adapter + * @skb: the skbuff containing the ARP request + * + * Check if the ARP request is probing the private IP address + * dedicated to iSCSI, generate an ARP reply if so. + */ +static void cxgb3_arp_process(struct adapter *adapter, struct sk_buff *skb) +{ + struct net_device *dev = skb->dev; + struct port_info *pi; + struct arphdr *arp; + unsigned char *arp_ptr; + unsigned char *sha; + __be32 sip, tip; + + if (!dev) + return; + + skb_reset_network_header(skb); + arp = arp_hdr(skb); + + if (arp->ar_op != htons(ARPOP_REQUEST)) + return; + + arp_ptr = (unsigned char *)(arp + 1); + sha = arp_ptr; + arp_ptr += dev->addr_len; + memcpy(&sip, arp_ptr, sizeof(sip)); + arp_ptr += sizeof(sip); + arp_ptr += dev->addr_len; + memcpy(&tip, arp_ptr, sizeof(tip)); + + pi = netdev_priv(dev); + if (tip != pi->iscsi_ipv4addr) + return; + + arp_send(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha, + dev->dev_addr, sha); + +} + +static inline int is_arp(struct sk_buff *skb) +{ + return skb->protocol == htons(ETH_P_ARP); +} + /** * rx_eth - process an ingress ethernet packet * @adap: the adapter @@ -1876,11 +1931,10 @@ static void rx_eth(struct adapter *adap, struct sge_rspq *rq, skb_pull(skb, sizeof(*p) + pad); skb->protocol = eth_type_trans(skb, adap->port[p->iff]); - skb->dev->last_rx = jiffies; pi = netdev_priv(skb->dev); if (pi->rx_csum_offload && p->csum_valid && p->csum == htons(0xffff) && !p->fragment) { - rspq_to_qset(rq)->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++; + qs->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++; skb->ip_summed = CHECKSUM_UNNECESSARY; } else skb->ip_summed = CHECKSUM_NONE; @@ -1895,16 +1949,28 @@ static void rx_eth(struct adapter *adap, struct sge_rspq *rq, grp, ntohs(p->vlan), p); - else + else { + if (unlikely(pi->iscsi_ipv4addr && + is_arp(skb))) { + unsigned short vtag = ntohs(p->vlan) & + VLAN_VID_MASK; + skb->dev = vlan_group_get_device(grp, + vtag); + cxgb3_arp_process(adap, skb); + } __vlan_hwaccel_rx(skb, grp, ntohs(p->vlan), rq->polling); + } else dev_kfree_skb_any(skb); } else if (rq->polling) { if (lro) lro_receive_skb(&qs->lro_mgr, skb, p); - else + else { + if (unlikely(pi->iscsi_ipv4addr && is_arp(skb))) + cxgb3_arp_process(adap, skb); netif_receive_skb(skb); + } } else netif_rx(skb); } @@ -2308,7 +2374,7 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs, static inline int is_pure_response(const struct rsp_desc *r) { - u32 n = ntohl(r->flags) & (F_RSPD_ASYNC_NOTIF | F_RSPD_IMM_DATA_VALID); + __be32 n = r->flags & htonl(F_RSPD_ASYNC_NOTIF | F_RSPD_IMM_DATA_VALID); return (n | r->len_cq) == 0; } @@ -2826,6 +2892,7 @@ void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p) * @p: configuration parameters for this queue set * @ntxq: number of Tx queues for the queue set * @netdev: net device associated with this queue set + * @netdevq: net device TX queue associated with this queue set * * Allocate resources and initialize an SGE queue set. A queue set * comprises a response queue, two Rx free-buffer queues, and up to 3 @@ -2834,7 +2901,8 @@ void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p) */ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, int irq_vec_idx, const struct qset_params *p, - int ntxq, struct net_device *dev) + int ntxq, struct net_device *dev, + struct netdev_queue *netdevq) { int i, avail, ret = -ENOMEM; struct sge_qset *q = &adapter->sge.qs[id]; @@ -2970,6 +3038,7 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, q->adap = adapter; q->netdev = dev; + q->tx_q = netdevq; t3_update_qset_coalesce(q, p); init_lro_mgr(q, lro_mgr); diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index 9a0898b0dbcef2e8d214046c3ac9137de1ccfb23..2d1433077a8ee992a71ed1e89210ebf8749de816 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -925,11 +925,10 @@ int t3_get_tp_version(struct adapter *adapter, u32 *vers) /** * t3_check_tpsram_version - read the tp sram version * @adapter: the adapter - * @must_load: set to 1 if loading a new microcode image is required * * Reads the protocol sram version from flash. */ -int t3_check_tpsram_version(struct adapter *adapter, int *must_load) +int t3_check_tpsram_version(struct adapter *adapter) { int ret; u32 vers; @@ -938,7 +937,6 @@ int t3_check_tpsram_version(struct adapter *adapter, int *must_load) if (adapter->params.rev == T3_REV_A) return 0; - *must_load = 1; ret = t3_get_tp_version(adapter, &vers); if (ret) @@ -949,13 +947,7 @@ int t3_check_tpsram_version(struct adapter *adapter, int *must_load) if (major == TP_VERSION_MAJOR && minor == TP_VERSION_MINOR) return 0; - - if (major != TP_VERSION_MAJOR) - CH_ERR(adapter, "found wrong TP version (%u.%u), " - "driver needs version %d.%d\n", major, minor, - TP_VERSION_MAJOR, TP_VERSION_MINOR); else { - *must_load = 0; CH_ERR(adapter, "found wrong TP version (%u.%u), " "driver compiled for version %d.%d\n", major, minor, TP_VERSION_MAJOR, TP_VERSION_MINOR); @@ -1012,18 +1004,16 @@ int t3_get_fw_version(struct adapter *adapter, u32 *vers) /** * t3_check_fw_version - check if the FW is compatible with this driver * @adapter: the adapter - * @must_load: set to 1 if loading a new FW image is required - + * * Checks if an adapter's FW is compatible with the driver. Returns 0 * if the versions are compatible, a negative error otherwise. */ -int t3_check_fw_version(struct adapter *adapter, int *must_load) +int t3_check_fw_version(struct adapter *adapter) { int ret; u32 vers; unsigned int type, major, minor; - *must_load = 1; ret = t3_get_fw_version(adapter, &vers); if (ret) return ret; @@ -1035,17 +1025,11 @@ int t3_check_fw_version(struct adapter *adapter, int *must_load) if (type == FW_VERSION_T3 && major == FW_VERSION_MAJOR && minor == FW_VERSION_MINOR) return 0; - - if (major != FW_VERSION_MAJOR) - CH_ERR(adapter, "found wrong FW version(%u.%u), " - "driver needs version %u.%u\n", major, minor, - FW_VERSION_MAJOR, FW_VERSION_MINOR); - else if (minor < FW_VERSION_MINOR) { - *must_load = 0; + else if (major != FW_VERSION_MAJOR || minor < FW_VERSION_MINOR) CH_WARN(adapter, "found old FW minor version(%u.%u), " "driver compiled for version %u.%u\n", major, minor, FW_VERSION_MAJOR, FW_VERSION_MINOR); - } else { + else { CH_WARN(adapter, "found newer FW version(%u.%u), " "driver compiled for version %u.%u\n", major, minor, FW_VERSION_MAJOR, FW_VERSION_MINOR); diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h index bb8698a867545384842032a10d330c3ee785cc0b..b1b25c37aa1062099cbb38dbeafc0a6ce2d476de 100644 --- a/drivers/net/cxgb3/version.h +++ b/drivers/net/cxgb3/version.h @@ -35,7 +35,7 @@ #define DRV_DESC "Chelsio T3 Network Driver" #define DRV_NAME "cxgb3" /* Driver version */ -#define DRV_VERSION "1.1.0-ko" +#define DRV_VERSION "1.1.1-ko" /* Firmware version */ #define FW_VERSION_MAJOR 7 diff --git a/drivers/net/cxgb3/vsc8211.c b/drivers/net/cxgb3/vsc8211.c index 33f956bd6b59b8f96134c9e09cc23149f4556b77..d07130971b8f4bba321784ce079d51c54e905ec4 100644 --- a/drivers/net/cxgb3/vsc8211.c +++ b/drivers/net/cxgb3/vsc8211.c @@ -262,6 +262,7 @@ static int vsc8211_get_link_status_fiber(struct cphy *cphy, int *link_ok, return 0; } +#ifdef UNUSED /* * Enable/disable auto MDI/MDI-X in forced link speed mode. */ @@ -301,6 +302,7 @@ int vsc8211_set_speed_duplex(struct cphy *phy, int speed, int duplex) err = vsc8211_set_automdi(phy, 1); return err; } +#endif /* UNUSED */ static int vsc8211_power_down(struct cphy *cphy, int enable) { diff --git a/drivers/net/de600.c b/drivers/net/de600.c index cb849b091f980c9521e45ed0ac227420fa835c30..970f820ba814fc3b71d1f09401d74da5f0fa0b6a 100644 --- a/drivers/net/de600.c +++ b/drivers/net/de600.c @@ -369,7 +369,6 @@ static void de600_rx_intr(struct net_device *dev) netif_rx(skb); /* update stats */ - dev->last_rx = jiffies; dev->stats.rx_packets++; /* count all receives */ dev->stats.rx_bytes += size; /* count all received bytes */ @@ -384,7 +383,6 @@ static struct net_device * __init de600_probe(void) int i; struct net_device *dev; int err; - DECLARE_MAC_BUF(mac); dev = alloc_etherdev(0); if (!dev) @@ -439,7 +437,7 @@ static struct net_device * __init de600_probe(void) goto out1; } - printk(", Ethernet Address: %s\n", print_mac(mac, dev->dev_addr)); + printk(", Ethernet Address: %pM\n", dev->dev_addr); dev->open = de600_open; dev->stop = de600_close; diff --git a/drivers/net/de620.c b/drivers/net/de620.c index d454e143483ee39ad64ba0724753af67053527c0..bdfa89403389cb1470a3c1e1fa1bc6ab8f73a508 100644 --- a/drivers/net/de620.c +++ b/drivers/net/de620.c @@ -686,7 +686,6 @@ static int de620_rx_intr(struct net_device *dev) PRINTK(("Read %d bytes\n", size)); skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); /* deliver it "upstairs" */ - dev->last_rx = jiffies; /* count all receives */ dev->stats.rx_packets++; dev->stats.rx_bytes += size; @@ -800,7 +799,6 @@ struct net_device * __init de620_probe(int unit) struct net_device *dev; int err = -ENOMEM; int i; - DECLARE_MAC_BUF(mac); dev = alloc_etherdev(0); if (!dev) @@ -853,7 +851,7 @@ struct net_device * __init de620_probe(int unit) dev->broadcast[i] = 0xff; } - printk(", Ethernet Address: %s", print_mac(mac, dev->dev_addr)); + printk(", Ethernet Address: %pM", dev->dev_addr); printk(" (%dk RAM,", (nic_data.RAM_Size) ? (nic_data.RAM_Size >> 2) : 64); @@ -876,10 +874,7 @@ struct net_device * __init de620_probe(int unit) if (de620_debug) { printk("\nEEPROM contents:\n"); printk("RAM_Size = 0x%02X\n", nic_data.RAM_Size); - printk("NodeID = %02X:%02X:%02X:%02X:%02X:%02X\n", - nic_data.NodeID[0], nic_data.NodeID[1], - nic_data.NodeID[2], nic_data.NodeID[3], - nic_data.NodeID[4], nic_data.NodeID[5]); + printk("NodeID = %pM\n", nic_data.NodeID); printk("Model = %d\n", nic_data.Model); printk("Media = %d\n", nic_data.Media); printk("SCR = 0x%02x\n", nic_data.SCR); @@ -1008,20 +1003,3 @@ void cleanup_module(void) } #endif /* MODULE */ MODULE_LICENSE("GPL"); - - -/* - * (add '-DMODULE' when compiling as loadable module) - * - * compile-command: - * gcc -D__KERNEL__ -Wall -Wstrict-prototypes -O2 \ - * -fomit-frame-pointer -m486 \ - * -I/usr/src/linux/include -I../../net/inet -c de620.c -*/ -/* - * Local variables: - * kernel-compile-command: "gcc -D__KERNEL__ -Ilinux/include -I../../net/inet -Wall -Wstrict-prototypes -O2 -m486 -c de620.c" - * module-compile-command: "gcc -D__KERNEL__ -DMODULE -Ilinux/include -I../../net/inet -Wall -Wstrict-prototypes -O2 -m486 -c de620.c" - * compile-command: "gcc -D__KERNEL__ -DMODULE -Ilinux/include -I../../net/inet -Wall -Wstrict-prototypes -O2 -m486 -c de620.c" - * End: - */ diff --git a/drivers/net/declance.c b/drivers/net/declance.c index 3e3506411ac08a50501e8049bb6f0b74af9a0363..7ce3053530f9c62279f38dd17340e89167b6044b 100644 --- a/drivers/net/declance.c +++ b/drivers/net/declance.c @@ -622,7 +622,6 @@ static int lance_rx(struct net_device *dev) skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; } @@ -1023,7 +1022,6 @@ static int __init dec_lance_probe(struct device *bdev, const int type) int i, ret; unsigned long esar_base; unsigned char *esar; - DECLARE_MAC_BUF(mac); if (dec_lance_debug && version_printed++ == 0) printk(version); @@ -1035,7 +1033,7 @@ static int __init dec_lance_probe(struct device *bdev, const int type) dev = root_lance_dev; while (dev) { i++; - lp = (struct lance_private *)dev->priv; + lp = netdev_priv(dev); dev = lp->next; } snprintf(name, sizeof(name), fmt, i); @@ -1223,8 +1221,7 @@ static int __init dec_lance_probe(struct device *bdev, const int type) for (i = 0; i < 6; i++) dev->dev_addr[i] = esar[i * 4]; - printk(", addr = %s, irq = %d\n", - print_mac(mac, dev->dev_addr), dev->irq); + printk(", addr = %pM, irq = %d\n", dev->dev_addr, dev->irq); dev->open = &lance_open; dev->stop = &lance_close; diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c index c062aacf229ce2b23e773e45584734184d6e3ffa..6445cedd586844ad6f544c9e1f34af3d3212d0eb 100644 --- a/drivers/net/defxx.c +++ b/drivers/net/defxx.c @@ -477,6 +477,15 @@ static void dfx_get_bars(struct device *bdev, } } +static const struct net_device_ops dfx_netdev_ops = { + .ndo_open = dfx_open, + .ndo_stop = dfx_close, + .ndo_start_xmit = dfx_xmt_queue_pkt, + .ndo_get_stats = dfx_ctl_get_stats, + .ndo_set_multicast_list = dfx_ctl_set_multicast_list, + .ndo_set_mac_address = dfx_ctl_set_mac_address, +}; + /* * ================ * = dfx_register = @@ -511,7 +520,7 @@ static int __devinit dfx_register(struct device *bdev) int dfx_bus_pci = DFX_BUS_PCI(bdev); int dfx_bus_tc = DFX_BUS_TC(bdev); int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; - char *print_name = bdev->bus_id; + const char *print_name = dev_name(bdev); struct net_device *dev; DFX_board_t *bp; /* board pointer */ resource_size_t bar_start = 0; /* pointer to port */ @@ -573,13 +582,7 @@ static int __devinit dfx_register(struct device *bdev) } /* Initialize new device structure */ - - dev->get_stats = dfx_ctl_get_stats; - dev->open = dfx_open; - dev->stop = dfx_close; - dev->hard_start_xmit = dfx_xmt_queue_pkt; - dev->set_multicast_list = dfx_ctl_set_multicast_list; - dev->set_mac_address = dfx_ctl_set_mac_address; + dev->netdev_ops = &dfx_netdev_ops; if (dfx_bus_pci) pci_set_master(to_pci_dev(bdev)); @@ -3103,7 +3106,6 @@ static void dfx_rcv_queue_process( netif_rx(skb); /* Update the rcv counters */ - bp->dev->last_rx = jiffies; bp->rcv_total_frames++; if (*(p_buff + RCV_BUFF_K_DA) & 0x01) bp->rcv_multicast_frames++; @@ -3741,10 +3743,3 @@ MODULE_AUTHOR("Lawrence V. Stefani"); MODULE_DESCRIPTION("DEC FDDIcontroller TC/EISA/PCI (DEFTA/DEFEA/DEFPA) driver " DRV_VERSION " " DRV_RELDATE); MODULE_LICENSE("GPL"); - - -/* - * Local variables: - * kernel-compile-command: "gcc -D__KERNEL__ -I/root/linux/include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -c defxx.c" - * End: - */ diff --git a/drivers/net/depca.c b/drivers/net/depca.c index ace39ec0a367c121be87001b4e44bde930c0633f..e4cef491dc73fc8d6486b98976d9b937b12399ad 100644 --- a/drivers/net/depca.c +++ b/drivers/net/depca.c @@ -573,7 +573,6 @@ static int __init depca_hw_init (struct net_device *dev, struct device *device) s16 nicsr; u_long ioaddr; u_long mem_start; - DECLARE_MAC_BUF(mac); /* * We are now supposed to enter this function with the @@ -601,7 +600,7 @@ static int __init depca_hw_init (struct net_device *dev, struct device *device) return -ENXIO; } - lp = (struct depca_private *) dev->priv; + lp = netdev_priv(dev); mem_start = lp->mem_start; if (!mem_start || lp->adapter < DEPCA || lp->adapter >=unknown) @@ -633,7 +632,7 @@ static int __init depca_hw_init (struct net_device *dev, struct device *device) printk(", h/w address "); status = get_hw_addr(dev); - printk("%s", print_mac(mac, dev->dev_addr)); + printk("%pM", dev->dev_addr); if (status != 0) { printk(" which has an Ethernet PROM CRC error.\n"); return -ENXIO; @@ -821,7 +820,7 @@ static int __init depca_hw_init (struct net_device *dev, struct device *device) static int depca_open(struct net_device *dev) { - struct depca_private *lp = (struct depca_private *) dev->priv; + struct depca_private *lp = netdev_priv(dev); u_long ioaddr = dev->base_addr; s16 nicsr; int status = 0; @@ -866,7 +865,7 @@ static int depca_open(struct net_device *dev) /* Initialize the lance Rx and Tx descriptor rings. */ static void depca_init_ring(struct net_device *dev) { - struct depca_private *lp = (struct depca_private *) dev->priv; + struct depca_private *lp = netdev_priv(dev); u_int i; u_long offset; @@ -924,7 +923,7 @@ static void depca_tx_timeout(struct net_device *dev) */ static int depca_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct depca_private *lp = (struct depca_private *) dev->priv; + struct depca_private *lp = netdev_priv(dev); u_long ioaddr = dev->base_addr; int status = 0; @@ -972,7 +971,7 @@ static irqreturn_t depca_interrupt(int irq, void *dev_id) return IRQ_NONE; } - lp = (struct depca_private *) dev->priv; + lp = netdev_priv(dev); ioaddr = dev->base_addr; spin_lock(&lp->lock); @@ -1010,7 +1009,7 @@ static irqreturn_t depca_interrupt(int irq, void *dev_id) /* Called with lp->lock held */ static int depca_rx(struct net_device *dev) { - struct depca_private *lp = (struct depca_private *) dev->priv; + struct depca_private *lp = netdev_priv(dev); int i, entry; s32 status; @@ -1057,7 +1056,6 @@ static int depca_rx(struct net_device *dev) /* ** Update stats */ - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; for (i = 1; i < DEPCA_PKT_STAT_SZ - 1; i++) { @@ -1108,7 +1106,7 @@ static int depca_rx(struct net_device *dev) */ static int depca_tx(struct net_device *dev) { - struct depca_private *lp = (struct depca_private *) dev->priv; + struct depca_private *lp = netdev_priv(dev); int entry; s32 status; u_long ioaddr = dev->base_addr; @@ -1149,7 +1147,7 @@ static int depca_tx(struct net_device *dev) static int depca_close(struct net_device *dev) { - struct depca_private *lp = (struct depca_private *) dev->priv; + struct depca_private *lp = netdev_priv(dev); s16 nicsr; u_long ioaddr = dev->base_addr; @@ -1185,7 +1183,7 @@ static int depca_close(struct net_device *dev) static void LoadCSRs(struct net_device *dev) { - struct depca_private *lp = (struct depca_private *) dev->priv; + struct depca_private *lp = netdev_priv(dev); u_long ioaddr = dev->base_addr; outw(CSR1, DEPCA_ADDR); /* initialisation block address LSW */ @@ -1202,7 +1200,7 @@ static void LoadCSRs(struct net_device *dev) static int InitRestartDepca(struct net_device *dev) { - struct depca_private *lp = (struct depca_private *) dev->priv; + struct depca_private *lp = netdev_priv(dev); u_long ioaddr = dev->base_addr; int i, status = 0; @@ -1234,7 +1232,7 @@ static int InitRestartDepca(struct net_device *dev) */ static void set_multicast_list(struct net_device *dev) { - struct depca_private *lp = (struct depca_private *) dev->priv; + struct depca_private *lp = netdev_priv(dev); u_long ioaddr = dev->base_addr; netif_stop_queue(dev); @@ -1263,7 +1261,7 @@ static void set_multicast_list(struct net_device *dev) */ static void SetMulticastFilter(struct net_device *dev) { - struct depca_private *lp = (struct depca_private *) dev->priv; + struct depca_private *lp = netdev_priv(dev); struct dev_mc_list *dmi = dev->mc_list; char *addrs; int i, j, bit, byte; @@ -1431,7 +1429,7 @@ static int __init depca_mca_probe(struct device *device) dev->irq = irq; dev->base_addr = iobase; - lp = dev->priv; + lp = netdev_priv(dev); lp->depca_bus = DEPCA_BUS_MCA; lp->adapter = depca_mca_adapter_type[mdev->index]; lp->mem_start = mem_start; @@ -1534,7 +1532,7 @@ static int __init depca_isa_probe (struct platform_device *device) dev->base_addr = ioaddr; dev->irq = irq; /* Use whatever value the user gave * us, and 0 if he didn't. */ - lp = dev->priv; + lp = netdev_priv(dev); lp->depca_bus = DEPCA_BUS_ISA; lp->adapter = adapter; lp->mem_start = mem_start; @@ -1558,6 +1556,7 @@ static int __init depca_isa_probe (struct platform_device *device) #ifdef CONFIG_EISA static int __init depca_eisa_probe (struct device *device) { + enum depca_type adapter = unknown; struct eisa_device *edev; struct net_device *dev; struct depca_private *lp; @@ -1576,11 +1575,15 @@ static int __init depca_eisa_probe (struct device *device) * the EISA configuration structures (yet... :-), just rely on * the ISA probing to sort it out... */ - depca_shmem_probe (&mem_start); + adapter = depca_shmem_probe (&mem_start); + if (adapter == unknown) { + status = -ENODEV; + goto out_free; + } dev->base_addr = ioaddr; dev->irq = irq; - lp = dev->priv; + lp = netdev_priv(dev); lp->depca_bus = DEPCA_BUS_EISA; lp->adapter = edev->id.driver_data; lp->mem_start = mem_start; @@ -1605,7 +1608,7 @@ static int __devexit depca_device_remove (struct device *device) int bus; dev = device->driver_data; - lp = dev->priv; + lp = netdev_priv(dev); unregister_netdev (dev); iounmap (lp->sh_mem); @@ -1747,7 +1750,7 @@ static int __init DevicePresent(u_long ioaddr) static int __init get_hw_addr(struct net_device *dev) { u_long ioaddr = dev->base_addr; - struct depca_private *lp = dev->priv; + struct depca_private *lp = netdev_priv(dev); int i, k, tmp, status = 0; u_short j, x, chksum; @@ -1782,7 +1785,7 @@ static int __init get_hw_addr(struct net_device *dev) */ static int load_packet(struct net_device *dev, struct sk_buff *skb) { - struct depca_private *lp = (struct depca_private *) dev->priv; + struct depca_private *lp = netdev_priv(dev); int i, entry, end, len, status = 0; entry = lp->tx_new; /* Ring around buffer number. */ @@ -1837,11 +1840,10 @@ static int load_packet(struct net_device *dev, struct sk_buff *skb) static void depca_dbg_open(struct net_device *dev) { - struct depca_private *lp = (struct depca_private *) dev->priv; + struct depca_private *lp = netdev_priv(dev); u_long ioaddr = dev->base_addr; struct depca_init *p = &lp->init_block; int i; - DECLARE_MAC_BUF(mac); if (depca_debug > 1) { /* Do not copy the shadow init block into shared memory */ @@ -1880,7 +1882,7 @@ static void depca_dbg_open(struct net_device *dev) printk("...0x%8.8x\n", readl(&lp->tx_ring[i].base)); printk("Initialisation block at 0x%8.8lx(Phys)\n", lp->mem_start); printk(" mode: 0x%4.4x\n", p->mode); - printk(" physical address: %s\n", print_mac(mac, p->phys_addr)); + printk(" physical address: %pM\n", p->phys_addr); printk(" multicast hash table: "); for (i = 0; i < (HASH_TABLE_LEN >> 3) - 1; i++) { printk("%2.2x:", p->mcast_table[i]); @@ -1909,7 +1911,7 @@ static void depca_dbg_open(struct net_device *dev) */ static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct depca_private *lp = (struct depca_private *) dev->priv; + struct depca_private *lp = netdev_priv(dev); struct depca_ioctl *ioc = (struct depca_ioctl *) &rq->ifr_ifru; int i, status = 0; u_long ioaddr = dev->base_addr; diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index f8037110a522e3eb2616414908cacdaafa363c8f..c749e9fb47ef9d99922946f42013ab21951b5eb4 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -85,6 +85,19 @@ static int mii_write (struct net_device *dev, int phy_addr, int reg_num, static const struct ethtool_ops ethtool_ops; +static const struct net_device_ops netdev_ops = { + .ndo_open = rio_open, + .ndo_start_xmit = start_xmit, + .ndo_stop = rio_close, + .ndo_get_stats = get_stats, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, + .ndo_set_multicast_list = set_multicast, + .ndo_do_ioctl = rio_ioctl, + .ndo_tx_timeout = rio_tx_timeout, + .ndo_change_mtu = change_mtu, +}; + static int __devinit rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -97,7 +110,6 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) static int version_printed; void *ring_space; dma_addr_t ring_dma; - DECLARE_MAC_BUF(mac); if (!version_printed++) printk ("%s", version); @@ -198,15 +210,8 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) else if (tx_coalesce > TX_RING_SIZE-1) tx_coalesce = TX_RING_SIZE - 1; } - dev->open = &rio_open; - dev->hard_start_xmit = &start_xmit; - dev->stop = &rio_close; - dev->get_stats = &get_stats; - dev->set_multicast_list = &set_multicast; - dev->do_ioctl = &rio_ioctl; - dev->tx_timeout = &rio_tx_timeout; + dev->netdev_ops = &netdev_ops; dev->watchdog_timeo = TX_TIMEOUT; - dev->change_mtu = &change_mtu; SET_ETHTOOL_OPS(dev, ðtool_ops); #if 0 dev->features = NETIF_F_IP_CSUM; @@ -257,8 +262,8 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) card_idx++; - printk (KERN_INFO "%s: %s, %s, IRQ %d\n", - dev->name, np->name, print_mac(mac, dev->dev_addr), irq); + printk (KERN_INFO "%s: %s, %pM, IRQ %d\n", + dev->name, np->name, dev->dev_addr, irq); if (tx_coalesce > 1) printk(KERN_INFO "tx_coalesce:\t%d packets\n", tx_coalesce); @@ -892,7 +897,6 @@ receive_packet (struct net_device *dev) } #endif netif_rx (skb); - dev->last_rx = jiffies; } entry = (entry + 1) % RX_RING_SIZE; } diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index 5a9083e3f443b81f0b744cac37f3b36d274b88ff..bcf92917bbf3192504bd90e48e4165716615208d 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -137,7 +137,7 @@ typedef struct board_info { static inline board_info_t *to_dm9000_board(struct net_device *dev) { - return dev->priv; + return netdev_priv(dev); } /* DM9000 network board routine ---------------------------- */ @@ -626,7 +626,7 @@ static unsigned char dm9000_type_to_char(enum dm9000_type type) static void dm9000_hash_table(struct net_device *dev) { - board_info_t *db = (board_info_t *) dev->priv; + board_info_t *db = netdev_priv(dev); struct dev_mc_list *mcptr = dev->mc_list; int mc_cnt = dev->mc_count; int i, oft; @@ -677,7 +677,7 @@ dm9000_hash_table(struct net_device *dev) static void dm9000_init_dm9000(struct net_device *dev) { - board_info_t *db = dev->priv; + board_info_t *db = netdev_priv(dev); unsigned int imr; dm9000_dbg(db, 1, "entering %s\n", __func__); @@ -723,7 +723,7 @@ dm9000_init_dm9000(struct net_device *dev) /* Our watchdog timed out. Called by the networking layer */ static void dm9000_timeout(struct net_device *dev) { - board_info_t *db = (board_info_t *) dev->priv; + board_info_t *db = netdev_priv(dev); u8 reg_save; unsigned long flags; @@ -751,7 +751,7 @@ static int dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev) { unsigned long flags; - board_info_t *db = dev->priv; + board_info_t *db = netdev_priv(dev); dm9000_dbg(db, 3, "%s:\n", __func__); @@ -831,7 +831,7 @@ struct dm9000_rxhdr { static void dm9000_rx(struct net_device *dev) { - board_info_t *db = (board_info_t *) dev->priv; + board_info_t *db = netdev_priv(dev); struct dm9000_rxhdr rxhdr; struct sk_buff *skb; u8 rxbyte, *rdptr; @@ -928,7 +928,7 @@ dm9000_rx(struct net_device *dev) static irqreturn_t dm9000_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; - board_info_t *db = dev->priv; + board_info_t *db = netdev_priv(dev); int int_status; u8 reg_save; @@ -996,7 +996,7 @@ static void dm9000_poll_controller(struct net_device *dev) static int dm9000_open(struct net_device *dev) { - board_info_t *db = dev->priv; + board_info_t *db = netdev_priv(dev); unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK; if (netif_msg_ifup(db)) @@ -1046,7 +1046,7 @@ static void dm9000_msleep(board_info_t *db, unsigned int ms) static int dm9000_phy_read(struct net_device *dev, int phy_reg_unused, int reg) { - board_info_t *db = (board_info_t *) dev->priv; + board_info_t *db = netdev_priv(dev); unsigned long flags; unsigned int reg_save; int ret; @@ -1093,7 +1093,7 @@ static void dm9000_phy_write(struct net_device *dev, int phyaddr_unused, int reg, int value) { - board_info_t *db = (board_info_t *) dev->priv; + board_info_t *db = netdev_priv(dev); unsigned long flags; unsigned long reg_save; @@ -1134,7 +1134,7 @@ dm9000_phy_write(struct net_device *dev, static void dm9000_shutdown(struct net_device *dev) { - board_info_t *db = dev->priv; + board_info_t *db = netdev_priv(dev); /* RESET device */ dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET); /* PHY RESET */ @@ -1150,7 +1150,7 @@ dm9000_shutdown(struct net_device *dev) static int dm9000_stop(struct net_device *ndev) { - board_info_t *db = ndev->priv; + board_info_t *db = netdev_priv(ndev); if (netif_msg_ifdown(db)) dev_dbg(db->dev, "shutting down %s\n", ndev->name); @@ -1197,7 +1197,7 @@ dm9000_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "dm9000_probe()\n"); /* setup board info structure */ - db = ndev->priv; + db = netdev_priv(ndev); memset(db, 0, sizeof(*db)); db->dev = &pdev->dev; @@ -1385,13 +1385,11 @@ dm9000_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ndev); ret = register_netdev(ndev); - if (ret == 0) { - DECLARE_MAC_BUF(mac); - printk(KERN_INFO "%s: dm9000%c at %p,%p IRQ %d MAC: %s (%s)\n", + if (ret == 0) + printk(KERN_INFO "%s: dm9000%c at %p,%p IRQ %d MAC: %pM (%s)\n", ndev->name, dm9000_type_to_char(db->type), db->io_addr, db->io_data, ndev->irq, - print_mac(mac, ndev->dev_addr), mac_src); - } + ndev->dev_addr, mac_src); return 0; out: @@ -1410,7 +1408,7 @@ dm9000_drv_suspend(struct platform_device *dev, pm_message_t state) board_info_t *db; if (ndev) { - db = (board_info_t *) ndev->priv; + db = netdev_priv(ndev); db->in_suspend = 1; if (netif_running(ndev)) { @@ -1425,7 +1423,7 @@ static int dm9000_drv_resume(struct platform_device *dev) { struct net_device *ndev = platform_get_drvdata(dev); - board_info_t *db = (board_info_t *) ndev->priv; + board_info_t *db = netdev_priv(ndev); if (ndev) { @@ -1449,7 +1447,7 @@ dm9000_drv_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); unregister_netdev(ndev); - dm9000_release_board(pdev, (board_info_t *) ndev->priv); + dm9000_release_board(pdev, (board_info_t *) netdev_priv(ndev)); free_netdev(ndev); /* free device structure */ dev_dbg(&pdev->dev, "released and freed device\n"); diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c index 84e14f397d9ae1f5322dd0614855b6a53b5e3980..8ebd7d78940569054f5bab34b28b3db4e2c4eeae 100644 --- a/drivers/net/dummy.c +++ b/drivers/net/dummy.c @@ -57,18 +57,23 @@ static void set_multicast_list(struct net_device *dev) { } +static const struct net_device_ops dummy_netdev_ops = { + .ndo_start_xmit = dummy_xmit, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = set_multicast_list, + .ndo_set_mac_address = dummy_set_address, +}; + static void dummy_setup(struct net_device *dev) { + ether_setup(dev); + /* Initialize the device structure. */ - dev->hard_start_xmit = dummy_xmit; - dev->set_multicast_list = set_multicast_list; - dev->set_mac_address = dummy_set_address; + dev->netdev_ops = &dummy_netdev_ops; dev->destructor = free_netdev; /* Fill in device structure with ethernet-generic values. */ - ether_setup(dev); dev->tx_queue_len = 0; - dev->change_mtu = NULL; dev->flags |= IFF_NOARP; dev->flags &= ~IFF_MULTICAST; random_ether_addr(dev->dev_addr); diff --git a/drivers/net/e100.c b/drivers/net/e100.c index e8bfcce6b319da95be67ecc44e211b7f8ed7ac38..9f38b16ccbbd1b58f308225d15e59f94f1585a1c 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -1580,11 +1580,13 @@ static void e100_watchdog(unsigned long data) mii_ethtool_gset(&nic->mii, &cmd); if(mii_link_ok(&nic->mii) && !netif_carrier_ok(nic->netdev)) { - DPRINTK(LINK, INFO, "link up, %sMbps, %s-duplex\n", - cmd.speed == SPEED_100 ? "100" : "10", - cmd.duplex == DUPLEX_FULL ? "full" : "half"); + printk(KERN_INFO "e100: %s NIC Link is Up %s Mbps %s Duplex\n", + nic->netdev->name, + cmd.speed == SPEED_100 ? "100" : "10", + cmd.duplex == DUPLEX_FULL ? "Full" : "Half"); } else if(!mii_link_ok(&nic->mii) && netif_carrier_ok(nic->netdev)) { - DPRINTK(LINK, INFO, "link down\n"); + printk(KERN_INFO "e100: %s NIC Link is Down\n", + nic->netdev->name); } mii_check_link(&nic->mii); @@ -1880,7 +1882,6 @@ static int e100_rx_indicate(struct nic *nic, struct rx *rx, } else { dev->stats.rx_packets++; dev->stats.rx_bytes += actual_size; - nic->netdev->last_rx = jiffies; netif_receive_skb(skb); if(work_done) (*work_done)++; @@ -2048,9 +2049,9 @@ static irqreturn_t e100_intr(int irq, void *dev_id) if(stat_ack & stat_ack_rnr) nic->ru_running = RU_SUSPENDED; - if(likely(netif_rx_schedule_prep(netdev, &nic->napi))) { + if(likely(netif_rx_schedule_prep(&nic->napi))) { e100_disable_irq(nic); - __netif_rx_schedule(netdev, &nic->napi); + __netif_rx_schedule(&nic->napi); } return IRQ_HANDLED; @@ -2059,7 +2060,6 @@ static irqreturn_t e100_intr(int irq, void *dev_id) static int e100_poll(struct napi_struct *napi, int budget) { struct nic *nic = container_of(napi, struct nic, napi); - struct net_device *netdev = nic->netdev; unsigned int work_done = 0; e100_rx_clean(nic, &work_done, budget); @@ -2067,7 +2067,7 @@ static int e100_poll(struct napi_struct *napi, int budget) /* If budget not fully consumed, exit the polling mode */ if (work_done < budget) { - netif_rx_complete(netdev, napi); + netif_rx_complete(napi); e100_enable_irq(nic); } @@ -2322,7 +2322,8 @@ static int e100_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) { struct nic *nic = netdev_priv(netdev); - if(wol->wolopts != WAKE_MAGIC && wol->wolopts != 0) + if ((wol->wolopts && wol->wolopts != WAKE_MAGIC) || + !device_can_wakeup(&nic->pdev->dev)) return -EOPNOTSUPP; if(wol->wolopts) @@ -2330,6 +2331,8 @@ static int e100_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) else nic->flags &= ~wol_magic; + device_set_wakeup_enable(&nic->pdev->dev, wol->wolopts); + e100_exec_cb(nic, NULL, e100_configure); return 0; @@ -2610,13 +2613,27 @@ static int e100_close(struct net_device *netdev) return 0; } +static const struct net_device_ops e100_netdev_ops = { + .ndo_open = e100_open, + .ndo_stop = e100_close, + .ndo_start_xmit = e100_xmit_frame, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = e100_set_multicast_list, + .ndo_set_mac_address = e100_set_mac_address, + .ndo_change_mtu = e100_change_mtu, + .ndo_do_ioctl = e100_do_ioctl, + .ndo_tx_timeout = e100_tx_timeout, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = e100_netpoll, +#endif +}; + static int __devinit e100_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct net_device *netdev; struct nic *nic; int err; - DECLARE_MAC_BUF(mac); if(!(netdev = alloc_etherdev(sizeof(struct nic)))) { if(((1 << debug) - 1) & NETIF_MSG_PROBE) @@ -2624,19 +2641,9 @@ static int __devinit e100_probe(struct pci_dev *pdev, return -ENOMEM; } - netdev->open = e100_open; - netdev->stop = e100_close; - netdev->hard_start_xmit = e100_xmit_frame; - netdev->set_multicast_list = e100_set_multicast_list; - netdev->set_mac_address = e100_set_mac_address; - netdev->change_mtu = e100_change_mtu; - netdev->do_ioctl = e100_do_ioctl; + netdev->netdev_ops = &e100_netdev_ops; SET_ETHTOOL_OPS(netdev, &e100_ethtool_ops); - netdev->tx_timeout = e100_tx_timeout; netdev->watchdog_timeo = E100_WATCHDOG_PERIOD; -#ifdef CONFIG_NET_POLL_CONTROLLER - netdev->poll_controller = e100_netpoll; -#endif strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1); nic = netdev_priv(netdev); @@ -2734,8 +2741,10 @@ static int __devinit e100_probe(struct pci_dev *pdev, /* Wol magic packet can be enabled from eeprom */ if((nic->mac >= mac_82558_D101_A4) && - (nic->eeprom[eeprom_id] & eeprom_id_wol)) + (nic->eeprom[eeprom_id] & eeprom_id_wol)) { nic->flags |= wol_magic; + device_set_wakeup_enable(&pdev->dev, true); + } /* ack any pending wake events, disable PME */ pci_pme_active(pdev, false); @@ -2746,9 +2755,9 @@ static int __devinit e100_probe(struct pci_dev *pdev, goto err_out_free; } - DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, MAC addr %s\n", + DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, MAC addr %pM\n", (unsigned long long)pci_resource_start(pdev, use_io ? 1 : 0), - pdev->irq, print_mac(mac, netdev->dev_addr)); + pdev->irq, netdev->dev_addr); return 0; @@ -2794,11 +2803,10 @@ static int e100_suspend(struct pci_dev *pdev, pm_message_t state) pci_save_state(pdev); if ((nic->flags & wol_magic) | e100_asf(nic)) { - pci_enable_wake(pdev, PCI_D3hot, 1); - pci_enable_wake(pdev, PCI_D3cold, 1); + if (pci_enable_wake(pdev, PCI_D3cold, true)) + pci_enable_wake(pdev, PCI_D3hot, true); } else { - pci_enable_wake(pdev, PCI_D3hot, 0); - pci_enable_wake(pdev, PCI_D3cold, 0); + pci_enable_wake(pdev, PCI_D3hot, false); } pci_disable_device(pdev); @@ -2843,7 +2851,7 @@ static pci_ers_result_t e100_io_error_detected(struct pci_dev *pdev, pci_channel struct nic *nic = netdev_priv(netdev); /* Similar to calling e100_down(), but avoids adapter I/O. */ - netdev->stop(netdev); + e100_close(netdev); /* Detach; put netif into a state similar to hotplug unplug. */ napi_enable(&nic->napi); diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index 62f62970f978a4bc32bdc1c987a236056c9b6b84..f5581de04757701df1c0205980018361459da7a0 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -284,7 +284,6 @@ struct e1000_adapter { int cleaned_count); struct e1000_rx_ring *rx_ring; /* One per active queue */ struct napi_struct napi; - struct net_device *polling_netdev; /* One per active queue */ int num_tx_queues; int num_rx_queues; diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 872799b746f501a3af4264c13b4674dbb8802382..26474c92193f705a3b66e413fa5773da38ce87f2 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -888,6 +888,26 @@ static int e1000_is_need_ioport(struct pci_dev *pdev) } } +static const struct net_device_ops e1000_netdev_ops = { + .ndo_open = e1000_open, + .ndo_stop = e1000_close, + .ndo_start_xmit = e1000_xmit_frame, + .ndo_get_stats = e1000_get_stats, + .ndo_set_rx_mode = e1000_set_rx_mode, + .ndo_set_mac_address = e1000_set_mac, + .ndo_tx_timeout = e1000_tx_timeout, + .ndo_change_mtu = e1000_change_mtu, + .ndo_do_ioctl = e1000_ioctl, + .ndo_validate_addr = eth_validate_addr, + + .ndo_vlan_rx_register = e1000_vlan_rx_register, + .ndo_vlan_rx_add_vid = e1000_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = e1000_vlan_rx_kill_vid, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = e1000_netpoll, +#endif +}; + /** * e1000_probe - Device Initialization Routine * @pdev: PCI device information struct @@ -912,7 +932,6 @@ static int __devinit e1000_probe(struct pci_dev *pdev, u16 eeprom_data = 0; u16 eeprom_apme_mask = E1000_EEPROM_APME; int bars, need_ioport; - DECLARE_MAC_BUF(mac); /* do not allocate ioport bars when not needed */ need_ioport = e1000_is_need_ioport(pdev); @@ -967,8 +986,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev, hw->back = adapter; err = -EIO; - hw->hw_addr = ioremap(pci_resource_start(pdev, BAR_0), - pci_resource_len(pdev, BAR_0)); + hw->hw_addr = pci_ioremap_bar(pdev, BAR_0); if (!hw->hw_addr) goto err_ioremap; @@ -983,24 +1001,11 @@ static int __devinit e1000_probe(struct pci_dev *pdev, } } - netdev->open = &e1000_open; - netdev->stop = &e1000_close; - netdev->hard_start_xmit = &e1000_xmit_frame; - netdev->get_stats = &e1000_get_stats; - netdev->set_rx_mode = &e1000_set_rx_mode; - netdev->set_mac_address = &e1000_set_mac; - netdev->change_mtu = &e1000_change_mtu; - netdev->do_ioctl = &e1000_ioctl; + netdev->netdev_ops = &e1000_netdev_ops; e1000_set_ethtool_ops(netdev); - netdev->tx_timeout = &e1000_tx_timeout; netdev->watchdog_timeo = 5 * HZ; netif_napi_add(netdev, &adapter->napi, e1000_clean, 64); - netdev->vlan_rx_register = e1000_vlan_rx_register; - netdev->vlan_rx_add_vid = e1000_vlan_rx_add_vid; - netdev->vlan_rx_kill_vid = e1000_vlan_rx_kill_vid; -#ifdef CONFIG_NET_POLL_CONTROLLER - netdev->poll_controller = e1000_netpoll; -#endif + strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1); adapter->bd_number = cards_found; @@ -1016,9 +1021,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev, * because it depends on mac_type */ if ((hw->mac_type == e1000_ich8lan) && (pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) { - hw->flash_address = - ioremap(pci_resource_start(pdev, 1), - pci_resource_len(pdev, 1)); + hw->flash_address = pci_ioremap_bar(pdev, 1); if (!hw->flash_address) goto err_flashmap; } @@ -1195,7 +1198,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev, (hw->bus_width == e1000_bus_width_pciex_1) ? "Width x1" : "32-bit")); - printk("%s\n", print_mac(mac, netdev->dev_addr)); + printk("%pM\n", netdev->dev_addr); if (hw->bus_type == e1000_bus_type_pci_express) { DPRINTK(PROBE, WARNING, "This device (id %04x:%04x) will no " @@ -1239,12 +1242,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev, if (hw->flash_address) iounmap(hw->flash_address); err_flashmap: - for (i = 0; i < adapter->num_rx_queues; i++) - dev_put(&adapter->polling_netdev[i]); - kfree(adapter->tx_ring); kfree(adapter->rx_ring); - kfree(adapter->polling_netdev); err_sw_init: iounmap(hw->hw_addr); err_ioremap: @@ -1272,7 +1271,6 @@ static void __devexit e1000_remove(struct pci_dev *pdev) struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - int i; cancel_work_sync(&adapter->reset_task); @@ -1282,9 +1280,6 @@ static void __devexit e1000_remove(struct pci_dev *pdev) * would have already happened in close and is redundant. */ e1000_release_hw_control(adapter); - for (i = 0; i < adapter->num_rx_queues; i++) - dev_put(&adapter->polling_netdev[i]); - unregister_netdev(netdev); if (!e1000_check_phy_reset_block(hw)) @@ -1292,7 +1287,6 @@ static void __devexit e1000_remove(struct pci_dev *pdev) kfree(adapter->tx_ring); kfree(adapter->rx_ring); - kfree(adapter->polling_netdev); iounmap(hw->hw_addr); if (hw->flash_address) @@ -1318,7 +1312,6 @@ static int __devinit e1000_sw_init(struct e1000_adapter *adapter) struct e1000_hw *hw = &adapter->hw; struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; - int i; /* PCI config space info */ @@ -1375,11 +1368,6 @@ static int __devinit e1000_sw_init(struct e1000_adapter *adapter) return -ENOMEM; } - for (i = 0; i < adapter->num_rx_queues; i++) { - adapter->polling_netdev[i].priv = adapter; - dev_hold(&adapter->polling_netdev[i]); - set_bit(__LINK_STATE_START, &adapter->polling_netdev[i].state); - } spin_lock_init(&adapter->tx_queue_lock); /* Explicitly disable IRQ since the NIC can be in any state. */ @@ -1397,8 +1385,7 @@ static int __devinit e1000_sw_init(struct e1000_adapter *adapter) * @adapter: board private structure to initialize * * We allocate one ring per queue at run-time since we don't know the - * number of queues at compile-time. The polling_netdev array is - * intended for Multiqueue, but should work fine with a single queue. + * number of queues at compile-time. **/ static int __devinit e1000_alloc_queues(struct e1000_adapter *adapter) @@ -1415,15 +1402,6 @@ static int __devinit e1000_alloc_queues(struct e1000_adapter *adapter) return -ENOMEM; } - adapter->polling_netdev = kcalloc(adapter->num_rx_queues, - sizeof(struct net_device), - GFP_KERNEL); - if (!adapter->polling_netdev) { - kfree(adapter->tx_ring); - kfree(adapter->rx_ring); - return -ENOMEM; - } - return E1000_SUCCESS; } @@ -2521,10 +2499,11 @@ static void e1000_watchdog(unsigned long data) &adapter->link_duplex); ctrl = er32(CTRL); - DPRINTK(LINK, INFO, "NIC Link is Up %d Mbps %s, " - "Flow Control: %s\n", - adapter->link_speed, - adapter->link_duplex == FULL_DUPLEX ? + printk(KERN_INFO "e1000: %s NIC Link is Up %d Mbps %s, " + "Flow Control: %s\n", + netdev->name, + adapter->link_speed, + adapter->link_duplex == FULL_DUPLEX ? "Full Duplex" : "Half Duplex", ((ctrl & E1000_CTRL_TFCE) && (ctrl & E1000_CTRL_RFCE)) ? "RX/TX" : ((ctrl & @@ -2600,7 +2579,8 @@ static void e1000_watchdog(unsigned long data) if (netif_carrier_ok(netdev)) { adapter->link_speed = 0; adapter->link_duplex = 0; - DPRINTK(LINK, INFO, "NIC Link is Down\n"); + printk(KERN_INFO "e1000: %s NIC Link is Down\n", + netdev->name); netif_carrier_off(netdev); netif_stop_queue(netdev); mod_timer(&adapter->phy_info_timer, round_jiffies(jiffies + 2 * HZ)); @@ -3707,12 +3687,12 @@ static irqreturn_t e1000_intr_msi(int irq, void *data) mod_timer(&adapter->watchdog_timer, jiffies + 1); } - if (likely(netif_rx_schedule_prep(netdev, &adapter->napi))) { + if (likely(netif_rx_schedule_prep(&adapter->napi))) { adapter->total_tx_bytes = 0; adapter->total_tx_packets = 0; adapter->total_rx_bytes = 0; adapter->total_rx_packets = 0; - __netif_rx_schedule(netdev, &adapter->napi); + __netif_rx_schedule(&adapter->napi); } else e1000_irq_enable(adapter); @@ -3767,12 +3747,12 @@ static irqreturn_t e1000_intr(int irq, void *data) ew32(IMC, ~0); E1000_WRITE_FLUSH(); } - if (likely(netif_rx_schedule_prep(netdev, &adapter->napi))) { + if (likely(netif_rx_schedule_prep(&adapter->napi))) { adapter->total_tx_bytes = 0; adapter->total_tx_packets = 0; adapter->total_rx_bytes = 0; adapter->total_rx_packets = 0; - __netif_rx_schedule(netdev, &adapter->napi); + __netif_rx_schedule(&adapter->napi); } else /* this really should not happen! if it does it is basically a * bug, but not a hard error, so enable ints and continue */ @@ -3791,8 +3771,7 @@ static int e1000_clean(struct napi_struct *napi, int budget) struct net_device *poll_dev = adapter->netdev; int tx_cleaned = 0, work_done = 0; - /* Must NOT use netdev_priv macro here. */ - adapter = poll_dev->priv; + adapter = netdev_priv(poll_dev); /* e1000_clean is called per-cpu. This lock protects * tx_ring[0] from being cleaned by multiple cpus @@ -3814,7 +3793,7 @@ static int e1000_clean(struct napi_struct *napi, int budget) if (work_done < budget) { if (likely(adapter->itr_setting & 3)) e1000_set_itr(adapter); - netif_rx_complete(poll_dev, napi); + netif_rx_complete(napi); e1000_irq_enable(adapter); } @@ -4104,8 +4083,6 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, netif_receive_skb(skb); } - netdev->last_rx = jiffies; - next_desc: rx_desc->status = 0; @@ -4789,7 +4766,7 @@ static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state) { struct net_device *netdev = pci_get_drvdata(pdev); - struct e1000_adapter *adapter = netdev->priv; + struct e1000_adapter *adapter = netdev_priv(netdev); netif_device_detach(netdev); @@ -4811,7 +4788,7 @@ static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev, static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); - struct e1000_adapter *adapter = netdev->priv; + struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; int err; @@ -4845,7 +4822,7 @@ static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev) static void e1000_io_resume(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); - struct e1000_adapter *adapter = netdev->priv; + struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; e1000_init_manageability(adapter); diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c index b2c910c52df9756717246d21bdf2b115ab475d2c..cf43ee743b3cde3af28e061c61f57a1a1bc3936f 100644 --- a/drivers/net/e1000e/82571.c +++ b/drivers/net/e1000e/82571.c @@ -28,6 +28,7 @@ /* * 82571EB Gigabit Ethernet Controller + * 82571EB Gigabit Ethernet Controller (Copper) * 82571EB Gigabit Ethernet Controller (Fiber) * 82571EB Dual Port Gigabit Mezzanine Adapter * 82571EB Quad Port Gigabit Mezzanine Adapter @@ -331,8 +332,9 @@ static s32 e1000_get_variants_82571(struct e1000_adapter *adapter) case e1000_82573: if (pdev->device == E1000_DEV_ID_82573L) { - e1000_read_nvm(&adapter->hw, NVM_INIT_3GIO_3, 1, - &eeprom_data); + if (e1000_read_nvm(&adapter->hw, NVM_INIT_3GIO_3, 1, + &eeprom_data) < 0) + break; if (eeprom_data & NVM_WORD1A_ASPM_MASK) adapter->flags &= ~FLAG_HAS_JUMBO_FRAMES; } @@ -973,6 +975,12 @@ static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw) ew32(CTRL_EXT, reg); } + if (hw->mac.type == e1000_82571) { + reg = er32(PBA_ECC); + reg |= E1000_PBA_ECC_CORR_EN; + ew32(PBA_ECC, reg); + } + /* PCI-Ex Control Register */ if (hw->mac.type == e1000_82574) { reg = er32(GCR); @@ -1111,8 +1119,8 @@ static s32 e1000_setup_link_82571(struct e1000_hw *hw) * set it to full. */ if ((hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) && - hw->fc.type == e1000_fc_default) - hw->fc.type = e1000_fc_full; + hw->fc.requested_mode == e1000_fc_default) + hw->fc.requested_mode = e1000_fc_full; return e1000e_setup_link(hw); } @@ -1387,6 +1395,7 @@ static struct e1000_phy_operations e82_phy_ops_igp = { .set_d0_lplu_state = e1000_set_d0_lplu_state_82571, .set_d3_lplu_state = e1000e_set_d3_lplu_state, .write_phy_reg = e1000e_write_phy_reg_igp, + .cfg_on_link_up = NULL, }; static struct e1000_phy_operations e82_phy_ops_m88 = { @@ -1403,6 +1412,7 @@ static struct e1000_phy_operations e82_phy_ops_m88 = { .set_d0_lplu_state = e1000_set_d0_lplu_state_82571, .set_d3_lplu_state = e1000e_set_d3_lplu_state, .write_phy_reg = e1000e_write_phy_reg_m88, + .cfg_on_link_up = NULL, }; static struct e1000_phy_operations e82_phy_ops_bm = { @@ -1419,6 +1429,7 @@ static struct e1000_phy_operations e82_phy_ops_bm = { .set_d0_lplu_state = e1000_set_d0_lplu_state_82571, .set_d3_lplu_state = e1000e_set_d3_lplu_state, .write_phy_reg = e1000e_write_phy_reg_bm2, + .cfg_on_link_up = NULL, }; static struct e1000_nvm_operations e82571_nvm_ops = { diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h index 48f79ecb82a035e424c7ffa855bd9e92595087ba..e6caf29d42522b8302e480bcbdc6115a0f971635 100644 --- a/drivers/net/e1000e/defines.h +++ b/drivers/net/e1000e/defines.h @@ -372,6 +372,13 @@ #define E1000_ICR_TXQ1 0x00800000 /* Tx Queue 1 Interrupt */ #define E1000_ICR_OTHER 0x01000000 /* Other Interrupts */ +/* PBA ECC Register */ +#define E1000_PBA_ECC_COUNTER_MASK 0xFFF00000 /* ECC counter mask */ +#define E1000_PBA_ECC_COUNTER_SHIFT 20 /* ECC counter shift value */ +#define E1000_PBA_ECC_CORR_EN 0x00000001 /* ECC correction enable */ +#define E1000_PBA_ECC_STAT_CLR 0x00000002 /* Clear ECC error counter */ +#define E1000_PBA_ECC_INT_EN 0x00000004 /* Enable ICR bit 5 for ECC */ + /* * This defines the bits that are set in the Interrupt Mask * Set/Read Register. Each bit is documented below: @@ -565,6 +572,7 @@ #define E1000_EECD_FLUPD 0x00080000 /* Update FLASH */ #define E1000_EECD_AUPDEN 0x00100000 /* Enable Autonomous FLASH update */ #define E1000_EECD_SEC1VAL 0x00400000 /* Sector One Valid */ +#define E1000_EECD_SEC1VAL_VALID_MASK (E1000_EECD_AUTO_RD | E1000_EECD_PRES) #define E1000_NVM_RW_REG_DATA 16 /* Offset to data in NVM read/write registers */ #define E1000_NVM_RW_REG_DONE 2 /* Offset to READ/WRITE done bit */ diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h index c55fd6fdb91c16bcf0fba6049b1ef0d6ea3064ff..37bcb190eef80856c89caa08e3e93df1380b38e7 100644 --- a/drivers/net/e1000e/e1000.h +++ b/drivers/net/e1000e/e1000.h @@ -193,6 +193,7 @@ struct e1000_adapter { u16 mng_vlan_id; u16 link_speed; u16 link_duplex; + u16 eeprom_vers; spinlock_t tx_queue_lock; /* prevent concurrent tail updates */ @@ -388,6 +389,7 @@ extern int e1000e_setup_tx_resources(struct e1000_adapter *adapter); extern void e1000e_free_rx_resources(struct e1000_adapter *adapter); extern void e1000e_free_tx_resources(struct e1000_adapter *adapter); extern void e1000e_update_stats(struct e1000_adapter *adapter); +extern bool e1000_has_link(struct e1000_adapter *adapter); extern void e1000e_set_interrupt_capability(struct e1000_adapter *adapter); extern void e1000e_reset_interrupt_capability(struct e1000_adapter *adapter); diff --git a/drivers/net/e1000e/es2lan.c b/drivers/net/e1000e/es2lan.c index da9c09c248ede89e2a9096d9919fff6bbe6a3860..8964838c686b7fcb83fcd745574fc453cddb246d 100644 --- a/drivers/net/e1000e/es2lan.c +++ b/drivers/net/e1000e/es2lan.c @@ -112,6 +112,11 @@ static void e1000_initialize_hw_bits_80003es2lan(struct e1000_hw *hw); static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw); static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw); static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex); +static s32 e1000_cfg_on_link_up_80003es2lan(struct e1000_hw *hw); +static s32 e1000_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset, + u16 *data); +static s32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset, + u16 data); /** * e1000_init_phy_params_80003es2lan - Init ESB2 PHY func ptrs. @@ -275,8 +280,6 @@ static s32 e1000_acquire_phy_80003es2lan(struct e1000_hw *hw) u16 mask; mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM; - mask |= E1000_SWFW_CSR_SM; - return e1000_acquire_swfw_sync_80003es2lan(hw, mask); } @@ -292,7 +295,36 @@ static void e1000_release_phy_80003es2lan(struct e1000_hw *hw) u16 mask; mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM; - mask |= E1000_SWFW_CSR_SM; + e1000_release_swfw_sync_80003es2lan(hw, mask); +} + +/** + * e1000_acquire_mac_csr_80003es2lan - Acquire rights to access Kumeran register + * @hw: pointer to the HW structure + * + * Acquire the semaphore to access the Kumeran interface. + * + **/ +static s32 e1000_acquire_mac_csr_80003es2lan(struct e1000_hw *hw) +{ + u16 mask; + + mask = E1000_SWFW_CSR_SM; + + return e1000_acquire_swfw_sync_80003es2lan(hw, mask); +} + +/** + * e1000_release_mac_csr_80003es2lan - Release rights to access Kumeran Register + * @hw: pointer to the HW structure + * + * Release the semaphore used to access the Kumeran interface + **/ +static void e1000_release_mac_csr_80003es2lan(struct e1000_hw *hw) +{ + u16 mask; + + mask = E1000_SWFW_CSR_SM; e1000_release_swfw_sync_80003es2lan(hw, mask); } @@ -347,7 +379,7 @@ static s32 e1000_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask) u32 swmask = mask; u32 fwmask = mask << 16; s32 i = 0; - s32 timeout = 200; + s32 timeout = 50; while (i < timeout) { if (e1000e_get_hw_semaphore(hw)) @@ -715,13 +747,7 @@ static s32 e1000_get_link_up_info_80003es2lan(struct e1000_hw *hw, u16 *speed, ret_val = e1000e_get_speed_and_duplex_copper(hw, speed, duplex); - if (ret_val) - return ret_val; - if (*speed == SPEED_1000) - ret_val = e1000_cfg_kmrn_1000_80003es2lan(hw); - else - ret_val = e1000_cfg_kmrn_10_100_80003es2lan(hw, - *duplex); + hw->phy.ops.cfg_on_link_up(hw); } else { ret_val = e1000e_get_speed_and_duplex_fiber_serdes(hw, speed, @@ -763,8 +789,10 @@ static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw) ctrl = er32(CTRL); + ret_val = e1000_acquire_phy_80003es2lan(hw); hw_dbg(hw, "Issuing a global reset to MAC\n"); ew32(CTRL, ctrl | E1000_CTRL_RST); + e1000_release_phy_80003es2lan(hw); ret_val = e1000e_get_auto_rd_done(hw); if (ret_val) @@ -907,8 +935,7 @@ static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw) struct e1000_phy_info *phy = &hw->phy; s32 ret_val; u32 ctrl_ext; - u32 i = 0; - u16 data, data2; + u16 data; ret_val = e1e_rphy(hw, GG82563_PHY_MAC_SPEC_CTRL, &data); if (ret_val) @@ -972,19 +999,20 @@ static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw) } /* Bypass Rx and Tx FIFO's */ - ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL, + ret_val = e1000_write_kmrn_reg_80003es2lan(hw, + E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL, E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS | E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS); if (ret_val) return ret_val; - ret_val = e1000e_read_kmrn_reg(hw, + ret_val = e1000_read_kmrn_reg_80003es2lan(hw, E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE, &data); if (ret_val) return ret_val; data |= E1000_KMRNCTRLSTA_OPMODE_E_IDLE; - ret_val = e1000e_write_kmrn_reg(hw, + ret_val = e1000_write_kmrn_reg_80003es2lan(hw, E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE, data); if (ret_val) @@ -1019,18 +1047,9 @@ static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw) if (ret_val) return ret_val; - do { - ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, - &data); - if (ret_val) - return ret_val; - - ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, - &data2); - if (ret_val) - return ret_val; - i++; - } while ((data != data2) && (i < GG82563_MAX_KMRN_RETRY)); + ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, &data); + if (ret_val) + return ret_val; data &= ~GG82563_KMCR_PASS_FALSE_CARRIER; ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, data); @@ -1077,23 +1096,27 @@ static s32 e1000_setup_copper_link_80003es2lan(struct e1000_hw *hw) * iteration and increase the max iterations when * polling the phy; this fixes erroneous timeouts at 10Mbps. */ - ret_val = e1000e_write_kmrn_reg(hw, GG82563_REG(0x34, 4), 0xFFFF); + ret_val = e1000_write_kmrn_reg_80003es2lan(hw, GG82563_REG(0x34, 4), + 0xFFFF); if (ret_val) return ret_val; - ret_val = e1000e_read_kmrn_reg(hw, GG82563_REG(0x34, 9), ®_data); + ret_val = e1000_read_kmrn_reg_80003es2lan(hw, GG82563_REG(0x34, 9), + ®_data); if (ret_val) return ret_val; reg_data |= 0x3F; - ret_val = e1000e_write_kmrn_reg(hw, GG82563_REG(0x34, 9), reg_data); + ret_val = e1000_write_kmrn_reg_80003es2lan(hw, GG82563_REG(0x34, 9), + reg_data); if (ret_val) return ret_val; - ret_val = e1000e_read_kmrn_reg(hw, + ret_val = e1000_read_kmrn_reg_80003es2lan(hw, E1000_KMRNCTRLSTA_OFFSET_INB_CTRL, ®_data); if (ret_val) return ret_val; reg_data |= E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING; - ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_OFFSET_INB_CTRL, + ret_val = e1000_write_kmrn_reg_80003es2lan(hw, + E1000_KMRNCTRLSTA_OFFSET_INB_CTRL, reg_data); if (ret_val) return ret_val; @@ -1107,6 +1130,35 @@ static s32 e1000_setup_copper_link_80003es2lan(struct e1000_hw *hw) return 0; } +/** + * e1000_cfg_on_link_up_80003es2lan - es2 link configuration after link-up + * @hw: pointer to the HW structure + * @duplex: current duplex setting + * + * Configure the KMRN interface by applying last minute quirks for + * 10/100 operation. + **/ +static s32 e1000_cfg_on_link_up_80003es2lan(struct e1000_hw *hw) +{ + s32 ret_val = 0; + u16 speed; + u16 duplex; + + if (hw->phy.media_type == e1000_media_type_copper) { + ret_val = e1000e_get_speed_and_duplex_copper(hw, &speed, + &duplex); + if (ret_val) + return ret_val; + + if (speed == SPEED_1000) + ret_val = e1000_cfg_kmrn_1000_80003es2lan(hw); + else + ret_val = e1000_cfg_kmrn_10_100_80003es2lan(hw, duplex); + } + + return ret_val; +} + /** * e1000_cfg_kmrn_10_100_80003es2lan - Apply "quirks" for 10/100 operation * @hw: pointer to the HW structure @@ -1123,8 +1175,9 @@ static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex) u16 reg_data, reg_data2; reg_data = E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT; - ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_OFFSET_HD_CTRL, - reg_data); + ret_val = e1000_write_kmrn_reg_80003es2lan(hw, + E1000_KMRNCTRLSTA_OFFSET_HD_CTRL, + reg_data); if (ret_val) return ret_val; @@ -1170,8 +1223,9 @@ static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw) u32 i = 0; reg_data = E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT; - ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_OFFSET_HD_CTRL, - reg_data); + ret_val = e1000_write_kmrn_reg_80003es2lan(hw, + E1000_KMRNCTRLSTA_OFFSET_HD_CTRL, + reg_data); if (ret_val) return ret_val; @@ -1198,6 +1252,71 @@ static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw) return ret_val; } +/** + * e1000_read_kmrn_reg_80003es2lan - Read kumeran register + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Acquire semaphore, then read the PHY register at offset + * using the kumeran interface. The information retrieved is stored in data. + * Release the semaphore before exiting. + **/ +static s32 e1000_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset, + u16 *data) +{ + u32 kmrnctrlsta; + s32 ret_val = 0; + + ret_val = e1000_acquire_mac_csr_80003es2lan(hw); + if (ret_val) + return ret_val; + + kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) & + E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN; + ew32(KMRNCTRLSTA, kmrnctrlsta); + + udelay(2); + + kmrnctrlsta = er32(KMRNCTRLSTA); + *data = (u16)kmrnctrlsta; + + e1000_release_mac_csr_80003es2lan(hw); + + return ret_val; +} + +/** + * e1000_write_kmrn_reg_80003es2lan - Write kumeran register + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write at register offset + * + * Acquire semaphore, then write the data to PHY register + * at the offset using the kumeran interface. Release semaphore + * before exiting. + **/ +static s32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset, + u16 data) +{ + u32 kmrnctrlsta; + s32 ret_val = 0; + + ret_val = e1000_acquire_mac_csr_80003es2lan(hw); + if (ret_val) + return ret_val; + + kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) & + E1000_KMRNCTRLSTA_OFFSET) | data; + ew32(KMRNCTRLSTA, kmrnctrlsta); + + udelay(2); + + e1000_release_mac_csr_80003es2lan(hw); + + return ret_val; +} + /** * e1000_clear_hw_cntrs_80003es2lan - Clear device specific hardware counters * @hw: pointer to the HW structure @@ -1276,6 +1395,7 @@ static struct e1000_phy_operations es2_phy_ops = { .set_d0_lplu_state = NULL, .set_d3_lplu_state = e1000e_set_d3_lplu_state, .write_phy_reg = e1000_write_phy_reg_gg82563_80003es2lan, + .cfg_on_link_up = e1000_cfg_on_link_up_80003es2lan, }; static struct e1000_nvm_operations es2_nvm_ops = { diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index 62421ce9631191f3acfdc82d48030ded4655d551..e48956d924b0faff43c4c2156bc795c8e87b5b8a 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c @@ -173,11 +173,8 @@ static int e1000_get_settings(struct net_device *netdev, static u32 e1000_get_link(struct net_device *netdev) { struct e1000_adapter *adapter = netdev_priv(netdev); - struct e1000_hw *hw = &adapter->hw; - u32 status; - - status = er32(STATUS); - return (status & E1000_STATUS_LU) ? 1 : 0; + + return e1000_has_link(adapter); } static int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx) @@ -249,7 +246,7 @@ static int e1000_set_settings(struct net_device *netdev, ADVERTISED_Autoneg; ecmd->advertising = hw->phy.autoneg_advertised; if (adapter->fc_autoneg) - hw->fc.original_type = e1000_fc_default; + hw->fc.requested_mode = e1000_fc_default; } else { if (e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) { clear_bit(__E1000_RESETTING, &adapter->state); @@ -279,11 +276,11 @@ static void e1000_get_pauseparam(struct net_device *netdev, pause->autoneg = (adapter->fc_autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE); - if (hw->fc.type == e1000_fc_rx_pause) { + if (hw->fc.current_mode == e1000_fc_rx_pause) { pause->rx_pause = 1; - } else if (hw->fc.type == e1000_fc_tx_pause) { + } else if (hw->fc.current_mode == e1000_fc_tx_pause) { pause->tx_pause = 1; - } else if (hw->fc.type == e1000_fc_full) { + } else if (hw->fc.current_mode == e1000_fc_full) { pause->rx_pause = 1; pause->tx_pause = 1; } @@ -301,19 +298,8 @@ static int e1000_set_pauseparam(struct net_device *netdev, while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) msleep(1); - if (pause->rx_pause && pause->tx_pause) - hw->fc.type = e1000_fc_full; - else if (pause->rx_pause && !pause->tx_pause) - hw->fc.type = e1000_fc_rx_pause; - else if (!pause->rx_pause && pause->tx_pause) - hw->fc.type = e1000_fc_tx_pause; - else if (!pause->rx_pause && !pause->tx_pause) - hw->fc.type = e1000_fc_none; - - hw->fc.original_type = hw->fc.type; - if (adapter->fc_autoneg == AUTONEG_ENABLE) { - hw->fc.type = e1000_fc_default; + hw->fc.requested_mode = e1000_fc_default; if (netif_running(adapter->netdev)) { e1000e_down(adapter); e1000e_up(adapter); @@ -321,6 +307,17 @@ static int e1000_set_pauseparam(struct net_device *netdev, e1000e_reset(adapter); } } else { + if (pause->rx_pause && pause->tx_pause) + hw->fc.requested_mode = e1000_fc_full; + else if (pause->rx_pause && !pause->tx_pause) + hw->fc.requested_mode = e1000_fc_rx_pause; + else if (!pause->rx_pause && pause->tx_pause) + hw->fc.requested_mode = e1000_fc_tx_pause; + else if (!pause->rx_pause && !pause->tx_pause) + hw->fc.requested_mode = e1000_fc_none; + + hw->fc.current_mode = hw->fc.requested_mode; + retval = ((hw->phy.media_type == e1000_media_type_fiber) ? hw->mac.ops.setup_link(hw) : e1000e_force_mac_fc(hw)); } @@ -495,18 +492,19 @@ static int e1000_get_eeprom(struct net_device *netdev, for (i = 0; i < last_word - first_word + 1; i++) { ret_val = e1000_read_nvm(hw, first_word + i, 1, &eeprom_buff[i]); - if (ret_val) { - /* a read error occurred, throw away the - * result */ - memset(eeprom_buff, 0xff, sizeof(eeprom_buff)); + if (ret_val) break; - } } } - /* Device's eeprom is always little-endian, word addressable */ - for (i = 0; i < last_word - first_word + 1; i++) - le16_to_cpus(&eeprom_buff[i]); + if (ret_val) { + /* a read error occurred, throw away the result */ + memset(eeprom_buff, 0xff, sizeof(eeprom_buff)); + } else { + /* Device's eeprom is always little-endian, word addressable */ + for (i = 0; i < last_word - first_word + 1; i++) + le16_to_cpus(&eeprom_buff[i]); + } memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len); kfree(eeprom_buff); @@ -558,6 +556,9 @@ static int e1000_set_eeprom(struct net_device *netdev, ret_val = e1000_read_nvm(hw, last_word, 1, &eeprom_buff[last_word - first_word]); + if (ret_val) + goto out; + /* Device's eeprom is always little-endian, word addressable */ for (i = 0; i < last_word - first_word + 1; i++) le16_to_cpus(&eeprom_buff[i]); @@ -570,15 +571,18 @@ static int e1000_set_eeprom(struct net_device *netdev, ret_val = e1000_write_nvm(hw, first_word, last_word - first_word + 1, eeprom_buff); + if (ret_val) + goto out; + /* * Update the checksum over the first part of the EEPROM if needed - * and flush shadow RAM for 82573 controllers + * and flush shadow RAM for applicable controllers */ - if ((ret_val == 0) && ((first_word <= NVM_CHECKSUM_REG) || - (hw->mac.type == e1000_82574) || - (hw->mac.type == e1000_82573))) - e1000e_update_nvm_checksum(hw); + if ((first_word <= NVM_CHECKSUM_REG) || + (hw->mac.type == e1000_82574) || (hw->mac.type == e1000_82573)) + ret_val = e1000e_update_nvm_checksum(hw); +out: kfree(eeprom_buff); return ret_val; } @@ -588,7 +592,6 @@ static void e1000_get_drvinfo(struct net_device *netdev, { struct e1000_adapter *adapter = netdev_priv(netdev); char firmware_version[32]; - u16 eeprom_data; strncpy(drvinfo->driver, e1000e_driver_name, 32); strncpy(drvinfo->version, e1000e_driver_version, 32); @@ -597,11 +600,10 @@ static void e1000_get_drvinfo(struct net_device *netdev, * EEPROM image version # is reported as firmware version # for * PCI-E controllers */ - e1000_read_nvm(&adapter->hw, 5, 1, &eeprom_data); sprintf(firmware_version, "%d.%d-%d", - (eeprom_data & 0xF000) >> 12, - (eeprom_data & 0x0FF0) >> 4, - eeprom_data & 0x000F); + (adapter->eeprom_vers & 0xF000) >> 12, + (adapter->eeprom_vers & 0x0FF0) >> 4, + (adapter->eeprom_vers & 0x000F)); strncpy(drvinfo->fw_version, firmware_version, 32); strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); @@ -865,7 +867,7 @@ static int e1000_eeprom_test(struct e1000_adapter *adapter, u64 *data) for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) { if ((e1000_read_nvm(&adapter->hw, i, 1, &temp)) < 0) { *data = 1; - break; + return *data; } checksum += temp; } diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h index f66ed37a7f766484e59a91bab9b3565fa34f7555..f25e961c6b3bc37bfbc4ac60b39d41274945bd39 100644 --- a/drivers/net/e1000e/hw.h +++ b/drivers/net/e1000e/hw.h @@ -87,6 +87,7 @@ enum e1e_registers { E1000_EEMNGCTL = 0x01010, /* MNG EEprom Control */ E1000_EEWR = 0x0102C, /* EEPROM Write Register - RW */ E1000_FLOP = 0x0103C, /* FLASH Opcode Register */ + E1000_PBA_ECC = 0x01100, /* PBA ECC Register */ E1000_ERT = 0x02008, /* Early Rx Threshold - RW */ E1000_FCRTL = 0x02160, /* Flow Control Receive Threshold Low - RW */ E1000_FCRTH = 0x02168, /* Flow Control Receive Threshold High - RW */ @@ -436,7 +437,7 @@ enum e1000_rev_polarity{ e1000_rev_polarity_undefined = 0xFF }; -enum e1000_fc_type { +enum e1000_fc_mode { e1000_fc_none = 0, e1000_fc_rx_pause, e1000_fc_tx_pause, @@ -738,6 +739,7 @@ struct e1000_phy_operations { s32 (*set_d0_lplu_state)(struct e1000_hw *, bool); s32 (*set_d3_lplu_state)(struct e1000_hw *, bool); s32 (*write_phy_reg)(struct e1000_hw *, u32, u16); + s32 (*cfg_on_link_up)(struct e1000_hw *); }; /* Function pointers for the NVM. */ @@ -848,8 +850,8 @@ struct e1000_fc_info { u16 pause_time; /* Flow control pause timer */ bool send_xon; /* Flow control send XON */ bool strict_ieee; /* Strict IEEE mode */ - enum e1000_fc_type type; /* Type of flow control */ - enum e1000_fc_type original_type; + enum e1000_fc_mode current_mode; /* FC mode in effect */ + enum e1000_fc_mode requested_mode; /* FC mode requested by caller */ }; struct e1000_dev_spec_82571 { diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c index d115a6d30f29c0b3acb81c8038c6215993980e8d..f2a5963b5a9562f153391c4f2b8b364742736d1b 100644 --- a/drivers/net/e1000e/ich8lan.c +++ b/drivers/net/e1000e/ich8lan.c @@ -27,6 +27,7 @@ *******************************************************************************/ /* + * 82562G 10/100 Network Connection * 82562G-2 10/100 Network Connection * 82562GT 10/100 Network Connection * 82562GT-2 10/100 Network Connection @@ -40,6 +41,7 @@ * 82566MM Gigabit Network Connection * 82567LM Gigabit Network Connection * 82567LF Gigabit Network Connection + * 82567V Gigabit Network Connection * 82567LM-2 Gigabit Network Connection * 82567LF-2 Gigabit Network Connection * 82567V-2 Gigabit Network Connection @@ -92,6 +94,8 @@ #define E1000_ICH_NVM_SIG_WORD 0x13 #define E1000_ICH_NVM_SIG_MASK 0xC000 +#define E1000_ICH_NVM_VALID_SIG_MASK 0xC0 +#define E1000_ICH_NVM_SIG_VALUE 0x80 #define E1000_ICH8_LAN_INIT_TIMEOUT 1500 @@ -956,45 +960,62 @@ static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, bool active) * @bank: pointer to the variable that returns the active bank * * Reads signature byte from the NVM using the flash access registers. + * Word 0x13 bits 15:14 = 10b indicate a valid signature for that bank. **/ static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank) { + u32 eecd; struct e1000_nvm_info *nvm = &hw->nvm; - /* flash bank size is in words */ u32 bank1_offset = nvm->flash_bank_size * sizeof(u16); u32 act_offset = E1000_ICH_NVM_SIG_WORD * 2 + 1; - u8 bank_high_byte = 0; + u8 sig_byte = 0; + s32 ret_val = 0; - if (hw->mac.type != e1000_ich10lan) { - if (er32(EECD) & E1000_EECD_SEC1VAL) - *bank = 1; - else - *bank = 0; - } else { - /* - * Make sure the signature for bank 0 is valid, - * if not check for bank1 - */ - e1000_read_flash_byte_ich8lan(hw, act_offset, &bank_high_byte); - if ((bank_high_byte & 0xC0) == 0x80) { + switch (hw->mac.type) { + case e1000_ich8lan: + case e1000_ich9lan: + eecd = er32(EECD); + if ((eecd & E1000_EECD_SEC1VAL_VALID_MASK) == + E1000_EECD_SEC1VAL_VALID_MASK) { + if (eecd & E1000_EECD_SEC1VAL) + *bank = 1; + else + *bank = 0; + + return 0; + } + hw_dbg(hw, "Unable to determine valid NVM bank via EEC - " + "reading flash signature\n"); + /* fall-thru */ + default: + /* set bank to 0 in case flash read fails */ + *bank = 0; + + /* Check bank 0 */ + ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset, + &sig_byte); + if (ret_val) + return ret_val; + if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) == + E1000_ICH_NVM_SIG_VALUE) { *bank = 0; - } else { - /* - * find if segment 1 is valid by verifying - * bit 15:14 = 10b in word 0x13 - */ - e1000_read_flash_byte_ich8lan(hw, - act_offset + bank1_offset, - &bank_high_byte); + return 0; + } - /* bank1 has a valid signature equivalent to SEC1V */ - if ((bank_high_byte & 0xC0) == 0x80) { - *bank = 1; - } else { - hw_dbg(hw, "ERROR: EEPROM not present\n"); - return -E1000_ERR_NVM; - } + /* Check bank 1 */ + ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset + + bank1_offset, + &sig_byte); + if (ret_val) + return ret_val; + if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) == + E1000_ICH_NVM_SIG_VALUE) { + *bank = 1; + return 0; } + + hw_dbg(hw, "ERROR: No valid NVM bank present\n"); + return -E1000_ERR_NVM; } return 0; @@ -1027,11 +1048,11 @@ static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, ret_val = e1000_acquire_swflag_ich8lan(hw); if (ret_val) - return ret_val; + goto out; ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank); if (ret_val) - return ret_val; + goto release; act_offset = (bank) ? nvm->flash_bank_size : 0; act_offset += offset; @@ -1050,8 +1071,13 @@ static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, } } +release: e1000_release_swflag_ich8lan(hw); +out: + if (ret_val) + hw_dbg(hw, "NVM read error: %d\n", ret_val); + return ret_val; } @@ -1340,14 +1366,14 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) ret_val = e1000e_update_nvm_checksum_generic(hw); if (ret_val) - return ret_val; + goto out; if (nvm->type != e1000_nvm_flash_sw) - return ret_val; + goto out; ret_val = e1000_acquire_swflag_ich8lan(hw); if (ret_val) - return ret_val; + goto out; /* * We're writing to the opposite bank so if we're on bank 1, @@ -1355,17 +1381,27 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) * is going to be written */ ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank); - if (ret_val) - return ret_val; + if (ret_val) { + e1000_release_swflag_ich8lan(hw); + goto out; + } if (bank == 0) { new_bank_offset = nvm->flash_bank_size; old_bank_offset = 0; - e1000_erase_flash_bank_ich8lan(hw, 1); + ret_val = e1000_erase_flash_bank_ich8lan(hw, 1); + if (ret_val) { + e1000_release_swflag_ich8lan(hw); + goto out; + } } else { old_bank_offset = nvm->flash_bank_size; new_bank_offset = 0; - e1000_erase_flash_bank_ich8lan(hw, 0); + ret_val = e1000_erase_flash_bank_ich8lan(hw, 0); + if (ret_val) { + e1000_release_swflag_ich8lan(hw); + goto out; + } } for (i = 0; i < E1000_ICH8_SHADOW_RAM_WORDS; i++) { @@ -1377,9 +1413,11 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) if (dev_spec->shadow_ram[i].modified) { data = dev_spec->shadow_ram[i].value; } else { - e1000_read_flash_word_ich8lan(hw, - i + old_bank_offset, - &data); + ret_val = e1000_read_flash_word_ich8lan(hw, i + + old_bank_offset, + &data); + if (ret_val) + break; } /* @@ -1420,7 +1458,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) /* Possibly read-only, see e1000e_write_protect_nvm_ich8lan() */ hw_dbg(hw, "Flash commit failed.\n"); e1000_release_swflag_ich8lan(hw); - return ret_val; + goto out; } /* @@ -1430,14 +1468,18 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) * and we need to change bit 14 to 0b */ act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD; - e1000_read_flash_word_ich8lan(hw, act_offset, &data); + ret_val = e1000_read_flash_word_ich8lan(hw, act_offset, &data); + if (ret_val) { + e1000_release_swflag_ich8lan(hw); + goto out; + } data &= 0xBFFF; ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset * 2 + 1, (u8)(data >> 8)); if (ret_val) { e1000_release_swflag_ich8lan(hw); - return ret_val; + goto out; } /* @@ -1450,7 +1492,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset, 0); if (ret_val) { e1000_release_swflag_ich8lan(hw); - return ret_val; + goto out; } /* Great! Everything worked, we can now clear the cached entries. */ @@ -1468,6 +1510,10 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) e1000e_reload_nvm(hw); msleep(10); +out: + if (ret_val) + hw_dbg(hw, "NVM update error: %d\n", ret_val); + return ret_val; } @@ -1894,7 +1940,7 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) } ret_val = e1000_acquire_swflag_ich8lan(hw); /* Whether or not the swflag was acquired, we need to reset the part */ - hw_dbg(hw, "Issuing a global reset to ich8lan"); + hw_dbg(hw, "Issuing a global reset to ich8lan\n"); ew32(CTRL, (ctrl | E1000_CTRL_RST)); msleep(20); @@ -2074,12 +2120,17 @@ static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw) * the default flow control setting, so we explicitly * set it to full. */ - if (hw->fc.type == e1000_fc_default) - hw->fc.type = e1000_fc_full; + if (hw->fc.requested_mode == e1000_fc_default) + hw->fc.requested_mode = e1000_fc_full; - hw->fc.original_type = hw->fc.type; + /* + * Save off the requested flow control mode for use later. Depending + * on the link partner's capabilities, we may or may not use this mode. + */ + hw->fc.current_mode = hw->fc.requested_mode; - hw_dbg(hw, "After fix-ups FlowControl is now = %x\n", hw->fc.type); + hw_dbg(hw, "After fix-ups FlowControl is now = %x\n", + hw->fc.current_mode); /* Continue to configure the copper link. */ ret_val = e1000_setup_copper_link_ich8lan(hw); diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c index 089578f6855a21500188034b6f4fd09809658dfc..66741104ffd1b3e6c02ab4af574e915540591f58 100644 --- a/drivers/net/e1000e/lib.c +++ b/drivers/net/e1000e/lib.c @@ -575,20 +575,42 @@ s32 e1000e_check_for_serdes_link(struct e1000_hw *hw) */ /* SYNCH bit and IV bit are sticky. */ udelay(10); - if (E1000_RXCW_SYNCH & er32(RXCW)) { + rxcw = er32(RXCW); + if (rxcw & E1000_RXCW_SYNCH) { if (!(rxcw & E1000_RXCW_IV)) { - mac->serdes_has_link = 1; - hw_dbg(hw, "SERDES: Link is up.\n"); + mac->serdes_has_link = true; + hw_dbg(hw, "SERDES: Link up - forced.\n"); } } else { - mac->serdes_has_link = 0; - hw_dbg(hw, "SERDES: Link is down.\n"); + mac->serdes_has_link = false; + hw_dbg(hw, "SERDES: Link down - force failed.\n"); } } if (E1000_TXCW_ANE & er32(TXCW)) { status = er32(STATUS); - mac->serdes_has_link = (status & E1000_STATUS_LU); + if (status & E1000_STATUS_LU) { + /* SYNCH bit and IV bit are sticky, so reread rxcw. */ + udelay(10); + rxcw = er32(RXCW); + if (rxcw & E1000_RXCW_SYNCH) { + if (!(rxcw & E1000_RXCW_IV)) { + mac->serdes_has_link = true; + hw_dbg(hw, "SERDES: Link up - autoneg " + "completed sucessfully.\n"); + } else { + mac->serdes_has_link = false; + hw_dbg(hw, "SERDES: Link down - invalid" + "codewords detected in autoneg.\n"); + } + } else { + mac->serdes_has_link = false; + hw_dbg(hw, "SERDES: Link down - no sync.\n"); + } + } else { + mac->serdes_has_link = false; + hw_dbg(hw, "SERDES: Link down - autoneg failed\n"); + } } return 0; @@ -623,12 +645,12 @@ static s32 e1000_set_default_fc_generic(struct e1000_hw *hw) } if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == 0) - hw->fc.type = e1000_fc_none; + hw->fc.requested_mode = e1000_fc_none; else if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == NVM_WORD0F_ASM_DIR) - hw->fc.type = e1000_fc_tx_pause; + hw->fc.requested_mode = e1000_fc_tx_pause; else - hw->fc.type = e1000_fc_full; + hw->fc.requested_mode = e1000_fc_full; return 0; } @@ -656,23 +678,23 @@ s32 e1000e_setup_link(struct e1000_hw *hw) return 0; /* - * If flow control is set to default, set flow control based on - * the EEPROM flow control settings. + * If requested flow control is set to default, set flow control + * based on the EEPROM flow control settings. */ - if (hw->fc.type == e1000_fc_default) { + if (hw->fc.requested_mode == e1000_fc_default) { ret_val = e1000_set_default_fc_generic(hw); if (ret_val) return ret_val; } /* - * We want to save off the original Flow Control configuration just - * in case we get disconnected and then reconnected into a different - * hub or switch with different Flow Control capabilities. + * Save off the requested flow control mode for use later. Depending + * on the link partner's capabilities, we may or may not use this mode. */ - hw->fc.original_type = hw->fc.type; + hw->fc.current_mode = hw->fc.requested_mode; - hw_dbg(hw, "After fix-ups FlowControl is now = %x\n", hw->fc.type); + hw_dbg(hw, "After fix-ups FlowControl is now = %x\n", + hw->fc.current_mode); /* Call the necessary media_type subroutine to configure the link. */ ret_val = mac->ops.setup_physical_interface(hw); @@ -724,7 +746,7 @@ static s32 e1000_commit_fc_settings_generic(struct e1000_hw *hw) * do not support receiving pause frames). * 3: Both Rx and Tx flow control (symmetric) are enabled. */ - switch (hw->fc.type) { + switch (hw->fc.current_mode) { case e1000_fc_none: /* Flow control completely disabled by a software over-ride. */ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD); @@ -906,7 +928,7 @@ s32 e1000e_set_fc_watermarks(struct e1000_hw *hw) * ability to transmit pause frames is not enabled, then these * registers will be set to 0. */ - if (hw->fc.type & e1000_fc_tx_pause) { + if (hw->fc.current_mode & e1000_fc_tx_pause) { /* * We need to set up the Receive Threshold high and low water * marks as well as (optionally) enabling the transmission of @@ -945,7 +967,7 @@ s32 e1000e_force_mac_fc(struct e1000_hw *hw) * receive flow control. * * The "Case" statement below enables/disable flow control - * according to the "hw->fc.type" parameter. + * according to the "hw->fc.current_mode" parameter. * * The possible values of the "fc" parameter are: * 0: Flow control is completely disabled @@ -956,9 +978,9 @@ s32 e1000e_force_mac_fc(struct e1000_hw *hw) * 3: Both Rx and Tx flow control (symmetric) is enabled. * other: No other values should be possible at this point. */ - hw_dbg(hw, "hw->fc.type = %u\n", hw->fc.type); + hw_dbg(hw, "hw->fc.current_mode = %u\n", hw->fc.current_mode); - switch (hw->fc.type) { + switch (hw->fc.current_mode) { case e1000_fc_none: ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE)); break; @@ -1102,11 +1124,11 @@ s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw) * ONLY. Hence, we must now check to see if we need to * turn OFF the TRANSMISSION of PAUSE frames. */ - if (hw->fc.original_type == e1000_fc_full) { - hw->fc.type = e1000_fc_full; + if (hw->fc.requested_mode == e1000_fc_full) { + hw->fc.current_mode = e1000_fc_full; hw_dbg(hw, "Flow Control = FULL.\r\n"); } else { - hw->fc.type = e1000_fc_rx_pause; + hw->fc.current_mode = e1000_fc_rx_pause; hw_dbg(hw, "Flow Control = " "RX PAUSE frames only.\r\n"); } @@ -1124,7 +1146,7 @@ s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw) (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { - hw->fc.type = e1000_fc_tx_pause; + hw->fc.current_mode = e1000_fc_tx_pause; hw_dbg(hw, "Flow Control = Tx PAUSE frames only.\r\n"); } /* @@ -1140,14 +1162,14 @@ s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw) (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { - hw->fc.type = e1000_fc_rx_pause; + hw->fc.current_mode = e1000_fc_rx_pause; hw_dbg(hw, "Flow Control = Rx PAUSE frames only.\r\n"); } else { /* * Per the IEEE spec, at this point flow control * should be disabled. */ - hw->fc.type = e1000_fc_none; + hw->fc.current_mode = e1000_fc_none; hw_dbg(hw, "Flow Control = NONE.\r\n"); } @@ -1163,7 +1185,7 @@ s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw) } if (duplex == HALF_DUPLEX) - hw->fc.type = e1000_fc_none; + hw->fc.current_mode = e1000_fc_none; /* * Now we call a subroutine to actually force the MAC diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 122539a0e1feb112f2e4f575f347d78349bb8536..d4639facd1bddcb72a200ada597d02fc284529e7 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -102,9 +102,7 @@ static void e1000_receive_skb(struct e1000_adapter *adapter, vlan_hwaccel_receive_skb(skb, adapter->vlgrp, le16_to_cpu(vlan)); else - netif_receive_skb(skb); - - netdev->last_rx = jiffies; + napi_gro_receive(&adapter->napi, skb); } /** @@ -1181,12 +1179,12 @@ static irqreturn_t e1000_intr_msi(int irq, void *data) mod_timer(&adapter->watchdog_timer, jiffies + 1); } - if (netif_rx_schedule_prep(netdev, &adapter->napi)) { + if (netif_rx_schedule_prep(&adapter->napi)) { adapter->total_tx_bytes = 0; adapter->total_tx_packets = 0; adapter->total_rx_bytes = 0; adapter->total_rx_packets = 0; - __netif_rx_schedule(netdev, &adapter->napi); + __netif_rx_schedule(&adapter->napi); } return IRQ_HANDLED; @@ -1248,12 +1246,12 @@ static irqreturn_t e1000_intr(int irq, void *data) mod_timer(&adapter->watchdog_timer, jiffies + 1); } - if (netif_rx_schedule_prep(netdev, &adapter->napi)) { + if (netif_rx_schedule_prep(&adapter->napi)) { adapter->total_tx_bytes = 0; adapter->total_tx_packets = 0; adapter->total_rx_bytes = 0; adapter->total_rx_packets = 0; - __netif_rx_schedule(netdev, &adapter->napi); + __netif_rx_schedule(&adapter->napi); } return IRQ_HANDLED; @@ -1322,10 +1320,10 @@ static irqreturn_t e1000_intr_msix_rx(int irq, void *data) adapter->rx_ring->set_itr = 0; } - if (netif_rx_schedule_prep(netdev, &adapter->napi)) { + if (netif_rx_schedule_prep(&adapter->napi)) { adapter->total_rx_bytes = 0; adapter->total_rx_packets = 0; - __netif_rx_schedule(netdev, &adapter->napi); + __netif_rx_schedule(&adapter->napi); } return IRQ_HANDLED; } @@ -1480,7 +1478,7 @@ static int e1000_request_msix(struct e1000_adapter *adapter) int err = 0, vector = 0; if (strlen(netdev->name) < (IFNAMSIZ - 5)) - sprintf(adapter->rx_ring->name, "%s-rx0", netdev->name); + sprintf(adapter->rx_ring->name, "%s-rx-0", netdev->name); else memcpy(adapter->rx_ring->name, netdev->name, IFNAMSIZ); err = request_irq(adapter->msix_entries[vector].vector, @@ -1493,7 +1491,7 @@ static int e1000_request_msix(struct e1000_adapter *adapter) vector++; if (strlen(netdev->name) < (IFNAMSIZ - 5)) - sprintf(adapter->tx_ring->name, "%s-tx0", netdev->name); + sprintf(adapter->tx_ring->name, "%s-tx-0", netdev->name); else memcpy(adapter->tx_ring->name, netdev->name, IFNAMSIZ); err = request_irq(adapter->msix_entries[vector].vector, @@ -2003,8 +2001,7 @@ static int e1000_clean(struct napi_struct *napi, int budget) struct net_device *poll_dev = adapter->netdev; int tx_cleaned = 0, work_done = 0; - /* Must NOT use netdev_priv macro here. */ - adapter = poll_dev->priv; + adapter = netdev_priv(poll_dev); if (adapter->msix_entries && !(adapter->rx_ring->ims_val & adapter->tx_ring->ims_val)) @@ -2031,7 +2028,7 @@ static int e1000_clean(struct napi_struct *napi, int budget) if (work_done < budget) { if (adapter->itr_setting & 3) e1000_set_itr(adapter); - netif_rx_complete(poll_dev, napi); + netif_rx_complete(napi); if (adapter->msix_entries) ew32(IMS, adapter->rx_ring->ims_val); else @@ -2787,7 +2784,7 @@ void e1000e_reset(struct e1000_adapter *adapter) else fc->pause_time = E1000_FC_PAUSE_TIME; fc->send_xon = 1; - fc->type = fc->original_type; + fc->current_mode = fc->requested_mode; /* Allow time for pending master requests to run */ mac->ops.reset_hw(hw); @@ -3410,7 +3407,10 @@ static void e1000_print_link_info(struct e1000_adapter *adapter) struct e1000_hw *hw = &adapter->hw; u32 ctrl = er32(CTRL); - e_info("Link is Up %d Mbps %s, Flow Control: %s\n", + /* Link status message must follow this format for user tools */ + printk(KERN_INFO "e1000e: %s NIC Link is Up %d Mbps %s, " + "Flow Control: %s\n", + adapter->netdev->name, adapter->link_speed, (adapter->link_duplex == FULL_DUPLEX) ? "Full Duplex" : "Half Duplex", @@ -3420,7 +3420,7 @@ static void e1000_print_link_info(struct e1000_adapter *adapter) ((ctrl & E1000_CTRL_TFCE) ? "TX" : "None" ))); } -static bool e1000_has_link(struct e1000_adapter *adapter) +bool e1000_has_link(struct e1000_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; bool link_active = 0; @@ -3495,6 +3495,7 @@ static void e1000_watchdog_task(struct work_struct *work) struct e1000_adapter, watchdog_task); struct net_device *netdev = adapter->netdev; struct e1000_mac_info *mac = &adapter->hw.mac; + struct e1000_phy_info *phy = &adapter->hw.phy; struct e1000_ring *tx_ring = adapter->tx_ring; struct e1000_hw *hw = &adapter->hw; u32 link, tctl; @@ -3601,6 +3602,13 @@ static void e1000_watchdog_task(struct work_struct *work) tctl |= E1000_TCTL_EN; ew32(TCTL, tctl); + /* + * Perform any post-link-up configuration before + * reporting link up. + */ + if (phy->ops.cfg_on_link_up) + phy->ops.cfg_on_link_up(hw); + netif_carrier_on(netdev); netif_tx_wake_all_queues(netdev); @@ -3612,7 +3620,9 @@ static void e1000_watchdog_task(struct work_struct *work) if (netif_carrier_ok(netdev)) { adapter->link_speed = 0; adapter->link_duplex = 0; - e_info("Link is Down\n"); + /* Link status message must follow this format */ + printk(KERN_INFO "e1000e: %s NIC Link is Down\n", + adapter->netdev->name); netif_carrier_off(netdev); netif_tx_stop_all_queues(netdev); if (!test_bit(__E1000_DOWN, &adapter->state)) @@ -4464,7 +4474,27 @@ static int e1000_suspend(struct pci_dev *pdev, pm_message_t state) pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); + /* + * The pci-e switch on some quad port adapters will report a + * correctable error when the MAC transitions from D0 to D3. To + * prevent this we need to mask off the correctable errors on the + * downstream port of the pci-e switch. + */ + if (adapter->flags & FLAG_IS_QUAD_PORT) { + struct pci_dev *us_dev = pdev->bus->self; + int pos = pci_find_capability(us_dev, PCI_CAP_ID_EXP); + u16 devctl; + + pci_read_config_word(us_dev, pos + PCI_EXP_DEVCTL, &devctl); + pci_write_config_word(us_dev, pos + PCI_EXP_DEVCTL, + (devctl & ~PCI_EXP_DEVCTL_CERE)); + + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + pci_write_config_word(us_dev, pos + PCI_EXP_DEVCTL, devctl); + } else { + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + } return 0; } @@ -4669,14 +4699,12 @@ static void e1000_print_device_info(struct e1000_adapter *adapter) u32 pba_num; /* print bus type/speed/width info */ - e_info("(PCI Express:2.5GB/s:%s) %02x:%02x:%02x:%02x:%02x:%02x\n", + e_info("(PCI Express:2.5GB/s:%s) %pM\n", /* bus width */ ((hw->bus.width == e1000_bus_width_pcie_x4) ? "Width x4" : "Width x1"), /* MAC address */ - netdev->dev_addr[0], netdev->dev_addr[1], - netdev->dev_addr[2], netdev->dev_addr[3], - netdev->dev_addr[4], netdev->dev_addr[5]); + netdev->dev_addr); e_info("Intel(R) PRO/%s Network Connection\n", (hw->phy.type == e1000_phy_ife) ? "10/100" : "1000"); e1000e_read_pba_num(hw, &pba_num); @@ -4694,20 +4722,40 @@ static void e1000_eeprom_checks(struct e1000_adapter *adapter) return; ret_val = e1000_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &buf); - if (!(le16_to_cpu(buf) & (1 << 0))) { + if (!ret_val && (!(le16_to_cpu(buf) & (1 << 0)))) { /* Deep Smart Power Down (DSPD) */ dev_warn(&adapter->pdev->dev, "Warning: detected DSPD enabled in EEPROM\n"); } ret_val = e1000_read_nvm(hw, NVM_INIT_3GIO_3, 1, &buf); - if (le16_to_cpu(buf) & (3 << 2)) { + if (!ret_val && (le16_to_cpu(buf) & (3 << 2))) { /* ASPM enable */ dev_warn(&adapter->pdev->dev, "Warning: detected ASPM enabled in EEPROM\n"); } } +static const struct net_device_ops e1000e_netdev_ops = { + .ndo_open = e1000_open, + .ndo_stop = e1000_close, + .ndo_start_xmit = e1000_xmit_frame, + .ndo_get_stats = e1000_get_stats, + .ndo_set_multicast_list = e1000_set_multi, + .ndo_set_mac_address = e1000_set_mac, + .ndo_change_mtu = e1000_change_mtu, + .ndo_do_ioctl = e1000_ioctl, + .ndo_tx_timeout = e1000_tx_timeout, + .ndo_validate_addr = eth_validate_addr, + + .ndo_vlan_rx_register = e1000_vlan_rx_register, + .ndo_vlan_rx_add_vid = e1000_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = e1000_vlan_rx_kill_vid, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = e1000_netpoll, +#endif +}; + /** * e1000_probe - Device Initialization Routine * @pdev: PCI device information struct @@ -4766,7 +4814,10 @@ static int __devinit e1000_probe(struct pci_dev *pdev, goto err_pci_reg; pci_set_master(pdev); - pci_save_state(pdev); + /* PCI config space info */ + err = pci_save_state(pdev); + if (err) + goto err_alloc_etherdev; err = -ENOMEM; netdev = alloc_etherdev(sizeof(struct e1000_adapter)); @@ -4806,24 +4857,10 @@ static int __devinit e1000_probe(struct pci_dev *pdev, } /* construct the net_device struct */ - netdev->open = &e1000_open; - netdev->stop = &e1000_close; - netdev->hard_start_xmit = &e1000_xmit_frame; - netdev->get_stats = &e1000_get_stats; - netdev->set_multicast_list = &e1000_set_multi; - netdev->set_mac_address = &e1000_set_mac; - netdev->change_mtu = &e1000_change_mtu; - netdev->do_ioctl = &e1000_ioctl; + netdev->netdev_ops = &e1000e_netdev_ops; e1000e_set_ethtool_ops(netdev); - netdev->tx_timeout = &e1000_tx_timeout; netdev->watchdog_timeo = 5 * HZ; netif_napi_add(netdev, &adapter->napi, e1000_clean, 64); - netdev->vlan_rx_register = e1000_vlan_rx_register; - netdev->vlan_rx_add_vid = e1000_vlan_rx_add_vid; - netdev->vlan_rx_kill_vid = e1000_vlan_rx_kill_vid; -#ifdef CONFIG_NET_POLL_CONTROLLER - netdev->poll_controller = e1000_netpoll; -#endif strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1); netdev->mem_start = mmio_start; @@ -4924,10 +4961,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev, memcpy(netdev->perm_addr, adapter->hw.mac.addr, netdev->addr_len); if (!is_valid_ether_addr(netdev->perm_addr)) { - e_err("Invalid MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n", - netdev->perm_addr[0], netdev->perm_addr[1], - netdev->perm_addr[2], netdev->perm_addr[3], - netdev->perm_addr[4], netdev->perm_addr[5]); + e_err("Invalid MAC Address: %pM\n", netdev->perm_addr); err = -EIO; goto err_eeprom; } @@ -4948,8 +4982,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev, /* Initialize link parameters. User can change them with ethtool */ adapter->hw.mac.autoneg = 1; adapter->fc_autoneg = 1; - adapter->hw.fc.original_type = e1000_fc_default; - adapter->hw.fc.type = e1000_fc_default; + adapter->hw.fc.requested_mode = e1000_fc_default; + adapter->hw.fc.current_mode = e1000_fc_default; adapter->hw.phy.autoneg_advertised = 0x2f; /* ring size defaults */ @@ -4990,6 +5024,9 @@ static int __devinit e1000_probe(struct pci_dev *pdev, adapter->wol = adapter->eeprom_wol; device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol); + /* save off EEPROM version number */ + e1000_read_nvm(&adapter->hw, 5, 1, &adapter->eeprom_vers); + /* reset the hardware with the new settings */ e1000e_reset(adapter); diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c index 6cd333ae61d038fa6186794121a16561fe036551..dc4a9cba6a73dcc34f16590153cd2e8a557fd9c6 100644 --- a/drivers/net/e1000e/phy.c +++ b/drivers/net/e1000e/phy.c @@ -744,7 +744,7 @@ static s32 e1000_phy_setup_autoneg(struct e1000_hw *hw) * other: No software override. The flow control configuration * in the EEPROM is used. */ - switch (hw->fc.type) { + switch (hw->fc.current_mode) { case e1000_fc_none: /* * Flow control (Rx & Tx) is completely disabled by a @@ -1030,14 +1030,14 @@ s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw) e1000e_phy_force_speed_duplex_setup(hw, &phy_data); - /* Reset the phy to commit changes. */ - phy_data |= MII_CR_RESET; - ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data); if (ret_val) return ret_val; - udelay(1); + /* Reset the phy to commit changes. */ + ret_val = e1000e_commit_phy(hw); + if (ret_val) + return ret_val; if (phy->autoneg_wait_to_complete) { hw_dbg(hw, "Waiting for forced speed/duplex link on M88 phy.\n"); @@ -1114,7 +1114,7 @@ void e1000e_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl) u32 ctrl; /* Turn off flow control when forcing speed/duplex */ - hw->fc.type = e1000_fc_none; + hw->fc.current_mode = e1000_fc_none; /* Force speed/duplex on the mac */ ctrl = er32(CTRL); diff --git a/drivers/net/e2100.c b/drivers/net/e2100.c index 6390f51ea6fbdc7e455ed70c6650b29edc53fc8a..20eb05cddb83ab92bcb770a57b1c378b7f0c02bb 100644 --- a/drivers/net/e2100.c +++ b/drivers/net/e2100.c @@ -107,7 +107,7 @@ static void e21_block_output(struct net_device *dev, int count, const unsigned char *buf, int start_page); static void e21_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page); - +static int e21_open(struct net_device *dev); static int e21_close(struct net_device *dev); @@ -160,6 +160,21 @@ struct net_device * __init e2100_probe(int unit) } #endif +static const struct net_device_ops e21_netdev_ops = { + .ndo_open = e21_open, + .ndo_stop = e21_close, + + .ndo_start_xmit = ei_start_xmit, + .ndo_tx_timeout = ei_tx_timeout, + .ndo_get_stats = ei_get_stats, + .ndo_set_multicast_list = ei_set_multicast_list, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = ei_poll, +#endif +}; + static int __init e21_probe1(struct net_device *dev, int ioaddr) { int i, status, retval; @@ -265,11 +280,8 @@ static int __init e21_probe1(struct net_device *dev, int ioaddr) ei_status.block_input = &e21_block_input; ei_status.block_output = &e21_block_output; ei_status.get_8390_hdr = &e21_get_8390_hdr; - dev->open = &e21_open; - dev->stop = &e21_close; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = ei_poll; -#endif + + dev->netdev_ops = &e21_netdev_ops; NS8390_init(dev, 0); retval = register_netdev(dev); diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c index 1f11350e16cf24b6a1a25d44ab9f8c41d4481a79..e187c88ae1450329a51da2ba64024dd55da2c3e0 100644 --- a/drivers/net/eepro.c +++ b/drivers/net/eepro.c @@ -605,7 +605,7 @@ struct net_device * __init eepro_probe(int unit) static void __init printEEPROMInfo(struct net_device *dev) { - struct eepro_local *lp = (struct eepro_local *)dev->priv; + struct eepro_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; unsigned short Word; int i,j; @@ -690,7 +690,6 @@ static void __init eepro_print_info (struct net_device *dev) struct eepro_local * lp = netdev_priv(dev); int i; const char * ifmap[] = {"AUI", "10Base2", "10BaseT"}; - DECLARE_MAC_BUF(mac); i = inb(dev->base_addr + ID_REG); printk(KERN_DEBUG " id: %#x ",i); @@ -715,7 +714,7 @@ static void __init eepro_print_info (struct net_device *dev) break; } - printk(" %s", print_mac(mac, dev->dev_addr)); + printk(" %pM", dev->dev_addr); if (net_debug > 3) printk(KERN_DEBUG ", %dK RCV buffer", @@ -1396,7 +1395,7 @@ set_multicast_list(struct net_device *dev) #define eeprom_delay() { udelay(40); } #define EE_READ_CMD (6 << 6) -int +static int read_eeprom(int ioaddr, int location, struct net_device *dev) { int i; @@ -1581,7 +1580,6 @@ eepro_rx(struct net_device *dev) skb->protocol = eth_type_trans(skb,dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; } @@ -1676,7 +1674,7 @@ eepro_transmit_interrupt(struct net_device *dev) static int eepro_ethtool_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct eepro_local *lp = (struct eepro_local *)dev->priv; + struct eepro_local *lp = netdev_priv(dev); cmd->supported = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c deleted file mode 100644 index e3e26c595fa340b8de1a4c28d8152964c9b42d69..0000000000000000000000000000000000000000 --- a/drivers/net/eepro100.c +++ /dev/null @@ -1,2401 +0,0 @@ -/* drivers/net/eepro100.c: An Intel i82557-559 Ethernet driver for Linux. */ -/* - Written 1996-1999 by Donald Becker. - - The driver also contains updates by different kernel developers - (see incomplete list below). - Current maintainer is Andrey V. Savochkin . - Please use this email address and linux-kernel mailing list for bug reports. - - This software may be used and distributed according to the terms - of the GNU General Public License, incorporated herein by reference. - - This driver is for the Intel EtherExpress Pro100 (Speedo3) design. - It should work with all i82557/558/559 boards. - - Version history: - 1998 Apr - 2000 Feb Andrey V. Savochkin - Serious fixes for multicast filter list setting, TX timeout routine; - RX ring refilling logic; other stuff - 2000 Feb Jeff Garzik - Convert to new PCI driver interface - 2000 Mar 24 Dragan Stancevic - Disabled FC and ER, to avoid lockups when when we get FCP interrupts. - 2000 Jul 17 Goutham Rao - PCI DMA API fixes, adding pci_dma_sync_single calls where neccesary - 2000 Aug 31 David Mosberger - rx_align support: enables rx DMA without causing unaligned accesses. -*/ - -static const char * const version = -"eepro100.c:v1.09j-t 9/29/99 Donald Becker\n" -"eepro100.c: $Revision: 1.36 $ 2000/11/17 Modified by Andrey V. Savochkin and others\n"; - -/* A few user-configurable values that apply to all boards. - First set is undocumented and spelled per Intel recommendations. */ - -static int congenb /* = 0 */; /* Enable congestion control in the DP83840. */ -static int txfifo = 8; /* Tx FIFO threshold in 4 byte units, 0-15 */ -static int rxfifo = 8; /* Rx FIFO threshold, default 32 bytes. */ -/* Tx/Rx DMA burst length, 0-127, 0 == no preemption, tx==128 -> disabled. */ -static int txdmacount = 128; -static int rxdmacount /* = 0 */; - -#if defined(__ia64__) || defined(__alpha__) || defined(__sparc__) || defined(__mips__) || \ - defined(__arm__) - /* align rx buffers to 2 bytes so that IP header is aligned */ -# define rx_align(skb) skb_reserve((skb), 2) -# define RxFD_ALIGNMENT __attribute__ ((aligned (2), packed)) -#else -# define rx_align(skb) -# define RxFD_ALIGNMENT -#endif - -/* Set the copy breakpoint for the copy-only-tiny-buffer Rx method. - Lower values use more memory, but are faster. */ -static int rx_copybreak = 200; - -/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work = 20; - -/* Maximum number of multicast addresses to filter (vs. rx-all-multicast) */ -static int multicast_filter_limit = 64; - -/* 'options' is used to pass a transceiver override or full-duplex flag - e.g. "options=16" for FD, "options=32" for 100mbps-only. */ -static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1}; -static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1}; - -/* A few values that may be tweaked. */ -/* The ring sizes should be a power of two for efficiency. */ -#define TX_RING_SIZE 64 -#define RX_RING_SIZE 64 -/* How much slots multicast filter setup may take. - Do not descrease without changing set_rx_mode() implementaion. */ -#define TX_MULTICAST_SIZE 2 -#define TX_MULTICAST_RESERV (TX_MULTICAST_SIZE*2) -/* Actual number of TX packets queued, must be - <= TX_RING_SIZE-TX_MULTICAST_RESERV. */ -#define TX_QUEUE_LIMIT (TX_RING_SIZE-TX_MULTICAST_RESERV) -/* Hysteresis marking queue as no longer full. */ -#define TX_QUEUE_UNFULL (TX_QUEUE_LIMIT-4) - -/* Operational parameters that usually are not changed. */ - -/* Time in jiffies before concluding the transmitter is hung. */ -#define TX_TIMEOUT (2*HZ) -/* Size of an pre-allocated Rx buffer: + slack.*/ -#define PKT_BUF_SZ 1536 - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -static int use_io; -static int debug = -1; -#define DEBUG_DEFAULT (NETIF_MSG_DRV | \ - NETIF_MSG_HW | \ - NETIF_MSG_RX_ERR | \ - NETIF_MSG_TX_ERR) -#define DEBUG ((debug >= 0) ? (1<"); -MODULE_DESCRIPTION("Intel i82557/i82558/i82559 PCI EtherExpressPro driver"); -MODULE_LICENSE("GPL"); -module_param(use_io, int, 0); -module_param(debug, int, 0); -module_param_array(options, int, NULL, 0); -module_param_array(full_duplex, int, NULL, 0); -module_param(congenb, int, 0); -module_param(txfifo, int, 0); -module_param(rxfifo, int, 0); -module_param(txdmacount, int, 0); -module_param(rxdmacount, int, 0); -module_param(rx_copybreak, int, 0); -module_param(max_interrupt_work, int, 0); -module_param(multicast_filter_limit, int, 0); -MODULE_PARM_DESC(debug, "debug level (0-6)"); -MODULE_PARM_DESC(options, "Bits 0-3: transceiver type, bit 4: full duplex, bit 5: 100Mbps"); -MODULE_PARM_DESC(full_duplex, "full duplex setting(s) (1)"); -MODULE_PARM_DESC(congenb, "Enable congestion control (1)"); -MODULE_PARM_DESC(txfifo, "Tx FIFO threshold in 4 byte units, (0-15)"); -MODULE_PARM_DESC(rxfifo, "Rx FIFO threshold in 4 byte units, (0-15)"); -MODULE_PARM_DESC(txdmacount, "Tx DMA burst length; 128 - disable (0-128)"); -MODULE_PARM_DESC(rxdmacount, "Rx DMA burst length; 128 - disable (0-128)"); -MODULE_PARM_DESC(rx_copybreak, "copy breakpoint for copy-only-tiny-frames"); -MODULE_PARM_DESC(max_interrupt_work, "maximum events handled per interrupt"); -MODULE_PARM_DESC(multicast_filter_limit, "maximum number of filtered multicast addresses"); - -#define RUN_AT(x) (jiffies + (x)) - -#define netdevice_start(dev) -#define netdevice_stop(dev) -#define netif_set_tx_timeout(dev, tf, tm) \ - do { \ - (dev)->tx_timeout = (tf); \ - (dev)->watchdog_timeo = (tm); \ - } while(0) - - - -/* - Theory of Operation - -I. Board Compatibility - -This device driver is designed for the Intel i82557 "Speedo3" chip, Intel's -single-chip fast Ethernet controller for PCI, as used on the Intel -EtherExpress Pro 100 adapter. - -II. Board-specific settings - -PCI bus devices are configured by the system at boot time, so no jumpers -need to be set on the board. The system BIOS should be set to assign the -PCI INTA signal to an otherwise unused system IRQ line. While it's -possible to share PCI interrupt lines, it negatively impacts performance and -only recent kernels support it. - -III. Driver operation - -IIIA. General -The Speedo3 is very similar to other Intel network chips, that is to say -"apparently designed on a different planet". This chips retains the complex -Rx and Tx descriptors and multiple buffers pointers as previous chips, but -also has simplified Tx and Rx buffer modes. This driver uses the "flexible" -Tx mode, but in a simplified lower-overhead manner: it associates only a -single buffer descriptor with each frame descriptor. - -Despite the extra space overhead in each receive skbuff, the driver must use -the simplified Rx buffer mode to assure that only a single data buffer is -associated with each RxFD. The driver implements this by reserving space -for the Rx descriptor at the head of each Rx skbuff. - -The Speedo-3 has receive and command unit base addresses that are added to -almost all descriptor pointers. The driver sets these to zero, so that all -pointer fields are absolute addresses. - -The System Control Block (SCB) of some previous Intel chips exists on the -chip in both PCI I/O and memory space. This driver uses the I/O space -registers, but might switch to memory mapped mode to better support non-x86 -processors. - -IIIB. Transmit structure - -The driver must use the complex Tx command+descriptor mode in order to -have a indirect pointer to the skbuff data section. Each Tx command block -(TxCB) is associated with two immediately appended Tx Buffer Descriptor -(TxBD). A fixed ring of these TxCB+TxBD pairs are kept as part of the -speedo_private data structure for each adapter instance. - -The newer i82558 explicitly supports this structure, and can read the two -TxBDs in the same PCI burst as the TxCB. - -This ring structure is used for all normal transmit packets, but the -transmit packet descriptors aren't long enough for most non-Tx commands such -as CmdConfigure. This is complicated by the possibility that the chip has -already loaded the link address in the previous descriptor. So for these -commands we convert the next free descriptor on the ring to a NoOp, and point -that descriptor's link to the complex command. - -An additional complexity of these non-transmit commands are that they may be -added asynchronous to the normal transmit queue, so we disable interrupts -whenever the Tx descriptor ring is manipulated. - -A notable aspect of these special configure commands is that they do -work with the normal Tx ring entry scavenge method. The Tx ring scavenge -is done at interrupt time using the 'dirty_tx' index, and checking for the -command-complete bit. While the setup frames may have the NoOp command on the -Tx ring marked as complete, but not have completed the setup command, this -is not a problem. The tx_ring entry can be still safely reused, as the -tx_skbuff[] entry is always empty for config_cmd and mc_setup frames. - -Commands may have bits set e.g. CmdSuspend in the command word to either -suspend or stop the transmit/command unit. This driver always flags the last -command with CmdSuspend, erases the CmdSuspend in the previous command, and -then issues a CU_RESUME. -Note: Watch out for the potential race condition here: imagine - erasing the previous suspend - the chip processes the previous command - the chip processes the final command, and suspends - doing the CU_RESUME - the chip processes the next-yet-valid post-final-command. -So blindly sending a CU_RESUME is only safe if we do it immediately after -after erasing the previous CmdSuspend, without the possibility of an -intervening delay. Thus the resume command is always within the -interrupts-disabled region. This is a timing dependence, but handling this -condition in a timing-independent way would considerably complicate the code. - -Note: In previous generation Intel chips, restarting the command unit was a -notoriously slow process. This is presumably no longer true. - -IIIC. Receive structure - -Because of the bus-master support on the Speedo3 this driver uses the new -SKBUFF_RX_COPYBREAK scheme, rather than a fixed intermediate receive buffer. -This scheme allocates full-sized skbuffs as receive buffers. The value -SKBUFF_RX_COPYBREAK is used as the copying breakpoint: it is chosen to -trade-off the memory wasted by passing the full-sized skbuff to the queue -layer for all frames vs. the copying cost of copying a frame to a -correctly-sized skbuff. - -For small frames the copying cost is negligible (esp. considering that we -are pre-loading the cache with immediately useful header information), so we -allocate a new, minimally-sized skbuff. For large frames the copying cost -is non-trivial, and the larger copy might flush the cache of useful data, so -we pass up the skbuff the packet was received into. - -IV. Notes - -Thanks to Steve Williams of Intel for arranging the non-disclosure agreement -that stated that I could disclose the information. But I still resent -having to sign an Intel NDA when I'm helping Intel sell their own product! - -*/ - -static int speedo_found1(struct pci_dev *pdev, void __iomem *ioaddr, int fnd_cnt, int acpi_idle_state); - -/* Offsets to the various registers. - All accesses need not be longword aligned. */ -enum speedo_offsets { - SCBStatus = 0, SCBCmd = 2, /* Rx/Command Unit command and status. */ - SCBIntmask = 3, - SCBPointer = 4, /* General purpose pointer. */ - SCBPort = 8, /* Misc. commands and operands. */ - SCBflash = 12, SCBeeprom = 14, /* EEPROM and flash memory control. */ - SCBCtrlMDI = 16, /* MDI interface control. */ - SCBEarlyRx = 20, /* Early receive byte count. */ -}; -/* Commands that can be put in a command list entry. */ -enum commands { - CmdNOp = 0, CmdIASetup = 0x10000, CmdConfigure = 0x20000, - CmdMulticastList = 0x30000, CmdTx = 0x40000, CmdTDR = 0x50000, - CmdDump = 0x60000, CmdDiagnose = 0x70000, - CmdSuspend = 0x40000000, /* Suspend after completion. */ - CmdIntr = 0x20000000, /* Interrupt after completion. */ - CmdTxFlex = 0x00080000, /* Use "Flexible mode" for CmdTx command. */ -}; -/* Clear CmdSuspend (1<<30) avoiding interference with the card access to the - status bits. Previous driver versions used separate 16 bit fields for - commands and statuses. --SAW - */ -#if defined(__alpha__) -# define clear_suspend(cmd) clear_bit(30, &(cmd)->cmd_status); -#else -# define clear_suspend(cmd) ((__le16 *)&(cmd)->cmd_status)[1] &= ~cpu_to_le16(1<<14) -#endif - -enum SCBCmdBits { - SCBMaskCmdDone=0x8000, SCBMaskRxDone=0x4000, SCBMaskCmdIdle=0x2000, - SCBMaskRxSuspend=0x1000, SCBMaskEarlyRx=0x0800, SCBMaskFlowCtl=0x0400, - SCBTriggerIntr=0x0200, SCBMaskAll=0x0100, - /* The rest are Rx and Tx commands. */ - CUStart=0x0010, CUResume=0x0020, CUStatsAddr=0x0040, CUShowStats=0x0050, - CUCmdBase=0x0060, /* CU Base address (set to zero) . */ - CUDumpStats=0x0070, /* Dump then reset stats counters. */ - RxStart=0x0001, RxResume=0x0002, RxAbort=0x0004, RxAddrLoad=0x0006, - RxResumeNoResources=0x0007, -}; - -enum SCBPort_cmds { - PortReset=0, PortSelfTest=1, PortPartialReset=2, PortDump=3, -}; - -/* The Speedo3 Rx and Tx frame/buffer descriptors. */ -struct descriptor { /* A generic descriptor. */ - volatile __le32 cmd_status; /* All command and status fields. */ - __le32 link; /* struct descriptor * */ - unsigned char params[0]; -}; - -/* The Speedo3 Rx and Tx buffer descriptors. */ -struct RxFD { /* Receive frame descriptor. */ - volatile __le32 status; - __le32 link; /* struct RxFD * */ - __le32 rx_buf_addr; /* void * */ - __le32 count; -} RxFD_ALIGNMENT; - -/* Selected elements of the Tx/RxFD.status word. */ -enum RxFD_bits { - RxComplete=0x8000, RxOK=0x2000, - RxErrCRC=0x0800, RxErrAlign=0x0400, RxErrTooBig=0x0200, RxErrSymbol=0x0010, - RxEth2Type=0x0020, RxNoMatch=0x0004, RxNoIAMatch=0x0002, - TxUnderrun=0x1000, StatusComplete=0x8000, -}; - -#define CONFIG_DATA_SIZE 22 -struct TxFD { /* Transmit frame descriptor set. */ - __le32 status; - __le32 link; /* void * */ - __le32 tx_desc_addr; /* Always points to the tx_buf_addr element. */ - __le32 count; /* # of TBD (=1), Tx start thresh., etc. */ - /* This constitutes two "TBD" entries -- we only use one. */ -#define TX_DESCR_BUF_OFFSET 16 - __le32 tx_buf_addr0; /* void *, frame to be transmitted. */ - __le32 tx_buf_size0; /* Length of Tx frame. */ - __le32 tx_buf_addr1; /* void *, frame to be transmitted. */ - __le32 tx_buf_size1; /* Length of Tx frame. */ - /* the structure must have space for at least CONFIG_DATA_SIZE starting - * from tx_desc_addr field */ -}; - -/* Multicast filter setting block. --SAW */ -struct speedo_mc_block { - struct speedo_mc_block *next; - unsigned int tx; - dma_addr_t frame_dma; - unsigned int len; - struct descriptor frame __attribute__ ((__aligned__(16))); -}; - -/* Elements of the dump_statistics block. This block must be lword aligned. */ -struct speedo_stats { - __le32 tx_good_frames; - __le32 tx_coll16_errs; - __le32 tx_late_colls; - __le32 tx_underruns; - __le32 tx_lost_carrier; - __le32 tx_deferred; - __le32 tx_one_colls; - __le32 tx_multi_colls; - __le32 tx_total_colls; - __le32 rx_good_frames; - __le32 rx_crc_errs; - __le32 rx_align_errs; - __le32 rx_resource_errs; - __le32 rx_overrun_errs; - __le32 rx_colls_errs; - __le32 rx_runt_errs; - __le32 done_marker; -}; - -enum Rx_ring_state_bits { - RrNoMem=1, RrPostponed=2, RrNoResources=4, RrOOMReported=8, -}; - -/* Do not change the position (alignment) of the first few elements! - The later elements are grouped for cache locality. - - Unfortunately, all the positions have been shifted since there. - A new re-alignment is required. 2000/03/06 SAW */ -struct speedo_private { - void __iomem *regs; - struct TxFD *tx_ring; /* Commands (usually CmdTxPacket). */ - struct RxFD *rx_ringp[RX_RING_SIZE]; /* Rx descriptor, used as ring. */ - /* The addresses of a Tx/Rx-in-place packets/buffers. */ - struct sk_buff *tx_skbuff[TX_RING_SIZE]; - struct sk_buff *rx_skbuff[RX_RING_SIZE]; - /* Mapped addresses of the rings. */ - dma_addr_t tx_ring_dma; -#define TX_RING_ELEM_DMA(sp, n) ((sp)->tx_ring_dma + (n)*sizeof(struct TxFD)) - dma_addr_t rx_ring_dma[RX_RING_SIZE]; - struct descriptor *last_cmd; /* Last command sent. */ - unsigned int cur_tx, dirty_tx; /* The ring entries to be free()ed. */ - spinlock_t lock; /* Group with Tx control cache line. */ - u32 tx_threshold; /* The value for txdesc.count. */ - struct RxFD *last_rxf; /* Last filled RX buffer. */ - dma_addr_t last_rxf_dma; - unsigned int cur_rx, dirty_rx; /* The next free ring entry */ - long last_rx_time; /* Last Rx, in jiffies, to handle Rx hang. */ - struct net_device_stats stats; - struct speedo_stats *lstats; - dma_addr_t lstats_dma; - int chip_id; - struct pci_dev *pdev; - struct timer_list timer; /* Media selection timer. */ - struct speedo_mc_block *mc_setup_head; /* Multicast setup frame list head. */ - struct speedo_mc_block *mc_setup_tail; /* Multicast setup frame list tail. */ - long in_interrupt; /* Word-aligned dev->interrupt */ - unsigned char acpi_pwr; - signed char rx_mode; /* Current PROMISC/ALLMULTI setting. */ - unsigned int tx_full:1; /* The Tx queue is full. */ - unsigned int flow_ctrl:1; /* Use 802.3x flow control. */ - unsigned int rx_bug:1; /* Work around receiver hang errata. */ - unsigned char default_port:8; /* Last dev->if_port value. */ - unsigned char rx_ring_state; /* RX ring status flags. */ - unsigned short phy[2]; /* PHY media interfaces available. */ - unsigned short partner; /* Link partner caps. */ - struct mii_if_info mii_if; /* MII API hooks, info */ - u32 msg_enable; /* debug message level */ -}; - -/* The parameters for a CmdConfigure operation. - There are so many options that it would be difficult to document each bit. - We mostly use the default or recommended settings. */ -static const char i82557_config_cmd[CONFIG_DATA_SIZE] = { - 22, 0x08, 0, 0, 0, 0, 0x32, 0x03, 1, /* 1=Use MII 0=Use AUI */ - 0, 0x2E, 0, 0x60, 0, - 0xf2, 0x48, 0, 0x40, 0xf2, 0x80, /* 0x40=Force full-duplex */ - 0x3f, 0x05, }; -static const char i82558_config_cmd[CONFIG_DATA_SIZE] = { - 22, 0x08, 0, 1, 0, 0, 0x22, 0x03, 1, /* 1=Use MII 0=Use AUI */ - 0, 0x2E, 0, 0x60, 0x08, 0x88, - 0x68, 0, 0x40, 0xf2, 0x84, /* Disable FC */ - 0x31, 0x05, }; - -/* PHY media interface chips. */ -static const char * const phys[] = { - "None", "i82553-A/B", "i82553-C", "i82503", - "DP83840", "80c240", "80c24", "i82555", - "unknown-8", "unknown-9", "DP83840A", "unknown-11", - "unknown-12", "unknown-13", "unknown-14", "unknown-15", }; -enum phy_chips { NonSuchPhy=0, I82553AB, I82553C, I82503, DP83840, S80C240, - S80C24, I82555, DP83840A=10, }; -static const char is_mii[] = { 0, 1, 1, 0, 1, 1, 0, 1 }; -#define EE_READ_CMD (6) - -static int eepro100_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent); - -static int do_eeprom_cmd(void __iomem *ioaddr, int cmd, int cmd_len); -static int mdio_read(struct net_device *dev, int phy_id, int location); -static void mdio_write(struct net_device *dev, int phy_id, int location, int value); -static int speedo_open(struct net_device *dev); -static void speedo_resume(struct net_device *dev); -static void speedo_timer(unsigned long data); -static void speedo_init_rx_ring(struct net_device *dev); -static void speedo_tx_timeout(struct net_device *dev); -static int speedo_start_xmit(struct sk_buff *skb, struct net_device *dev); -static void speedo_refill_rx_buffers(struct net_device *dev, int force); -static int speedo_rx(struct net_device *dev); -static void speedo_tx_buffer_gc(struct net_device *dev); -static irqreturn_t speedo_interrupt(int irq, void *dev_instance); -static int speedo_close(struct net_device *dev); -static struct net_device_stats *speedo_get_stats(struct net_device *dev); -static int speedo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static void set_rx_mode(struct net_device *dev); -static void speedo_show_state(struct net_device *dev); -static const struct ethtool_ops ethtool_ops; - - - -#ifdef honor_default_port -/* Optional driver feature to allow forcing the transceiver setting. - Not recommended. */ -static int mii_ctrl[8] = { 0x3300, 0x3100, 0x0000, 0x0100, - 0x2000, 0x2100, 0x0400, 0x3100}; -#endif - -/* How to wait for the command unit to accept a command. - Typically this takes 0 ticks. */ -static inline unsigned char wait_for_cmd_done(struct net_device *dev, - struct speedo_private *sp) -{ - int wait = 1000; - void __iomem *cmd_ioaddr = sp->regs + SCBCmd; - unsigned char r; - - do { - udelay(1); - r = ioread8(cmd_ioaddr); - } while(r && --wait >= 0); - - if (wait < 0) - printk(KERN_ALERT "%s: wait_for_cmd_done timeout!\n", dev->name); - return r; -} - -static int __devinit eepro100_init_one (struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - void __iomem *ioaddr; - int irq, pci_bar; - int acpi_idle_state = 0, pm; - static int cards_found /* = 0 */; - unsigned long pci_base; - -#ifndef MODULE - /* when built-in, we only print version if device is found */ - static int did_version; - if (did_version++ == 0) - printk(version); -#endif - - /* save power state before pci_enable_device overwrites it */ - pm = pci_find_capability(pdev, PCI_CAP_ID_PM); - if (pm) { - u16 pwr_command; - pci_read_config_word(pdev, pm + PCI_PM_CTRL, &pwr_command); - acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK; - } - - if (pci_enable_device(pdev)) - goto err_out_free_mmio_region; - - pci_set_master(pdev); - - if (!request_region(pci_resource_start(pdev, 1), - pci_resource_len(pdev, 1), "eepro100")) { - dev_err(&pdev->dev, "eepro100: cannot reserve I/O ports\n"); - goto err_out_none; - } - if (!request_mem_region(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0), "eepro100")) { - dev_err(&pdev->dev, "eepro100: cannot reserve MMIO region\n"); - goto err_out_free_pio_region; - } - - irq = pdev->irq; - pci_bar = use_io ? 1 : 0; - pci_base = pci_resource_start(pdev, pci_bar); - if (DEBUG & NETIF_MSG_PROBE) - printk("Found Intel i82557 PCI Speedo at %#lx, IRQ %d.\n", - pci_base, irq); - - ioaddr = pci_iomap(pdev, pci_bar, 0); - if (!ioaddr) { - dev_err(&pdev->dev, "eepro100: cannot remap IO\n"); - goto err_out_free_mmio_region; - } - - if (speedo_found1(pdev, ioaddr, cards_found, acpi_idle_state) == 0) - cards_found++; - else - goto err_out_iounmap; - - return 0; - -err_out_iounmap: ; - pci_iounmap(pdev, ioaddr); -err_out_free_mmio_region: - release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); -err_out_free_pio_region: - release_region(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1)); -err_out_none: - return -ENODEV; -} - -#ifdef CONFIG_NET_POLL_CONTROLLER -/* - * Polling 'interrupt' - used by things like netconsole to send skbs - * without having to re-enable interrupts. It's not called while - * the interrupt routine is executing. - */ - -static void poll_speedo (struct net_device *dev) -{ - /* disable_irq is not very nice, but with the funny lockless design - we have no other choice. */ - disable_irq(dev->irq); - speedo_interrupt (dev->irq, dev); - enable_irq(dev->irq); -} -#endif - -static int __devinit speedo_found1(struct pci_dev *pdev, - void __iomem *ioaddr, int card_idx, int acpi_idle_state) -{ - struct net_device *dev; - struct speedo_private *sp; - const char *product; - int i, option; - u16 eeprom[0x100]; - int size; - void *tx_ring_space; - dma_addr_t tx_ring_dma; - DECLARE_MAC_BUF(mac); - - size = TX_RING_SIZE * sizeof(struct TxFD) + sizeof(struct speedo_stats); - tx_ring_space = pci_alloc_consistent(pdev, size, &tx_ring_dma); - if (tx_ring_space == NULL) - return -1; - - dev = alloc_etherdev(sizeof(struct speedo_private)); - if (dev == NULL) { - printk(KERN_ERR "eepro100: Could not allocate ethernet device.\n"); - pci_free_consistent(pdev, size, tx_ring_space, tx_ring_dma); - return -1; - } - - SET_NETDEV_DEV(dev, &pdev->dev); - - if (dev->mem_start > 0) - option = dev->mem_start; - else if (card_idx >= 0 && options[card_idx] >= 0) - option = options[card_idx]; - else - option = 0; - - rtnl_lock(); - if (dev_alloc_name(dev, dev->name) < 0) - goto err_free_unlock; - - /* Read the station address EEPROM before doing the reset. - Nominally his should even be done before accepting the device, but - then we wouldn't have a device name with which to report the error. - The size test is for 6 bit vs. 8 bit address serial EEPROMs. - */ - { - void __iomem *iobase; - int read_cmd, ee_size; - u16 sum; - int j; - - /* Use IO only to avoid postponed writes and satisfy EEPROM timing - requirements. */ - iobase = pci_iomap(pdev, 1, pci_resource_len(pdev, 1)); - if (!iobase) - goto err_free_unlock; - if ((do_eeprom_cmd(iobase, EE_READ_CMD << 24, 27) & 0xffe0000) - == 0xffe0000) { - ee_size = 0x100; - read_cmd = EE_READ_CMD << 24; - } else { - ee_size = 0x40; - read_cmd = EE_READ_CMD << 22; - } - - for (j = 0, i = 0, sum = 0; i < ee_size; i++) { - u16 value = do_eeprom_cmd(iobase, read_cmd | (i << 16), 27); - eeprom[i] = value; - sum += value; - if (i < 3) { - dev->dev_addr[j++] = value; - dev->dev_addr[j++] = value >> 8; - } - } - if (sum != 0xBABA) - printk(KERN_WARNING "%s: Invalid EEPROM checksum %#4.4x, " - "check settings before activating this device!\n", - dev->name, sum); - /* Don't unregister_netdev(dev); as the EEPro may actually be - usable, especially if the MAC address is set later. - On the other hand, it may be unusable if MDI data is corrupted. */ - - pci_iounmap(pdev, iobase); - } - - /* Reset the chip: stop Tx and Rx processes and clear counters. - This takes less than 10usec and will easily finish before the next - action. */ - iowrite32(PortReset, ioaddr + SCBPort); - ioread32(ioaddr + SCBPort); - udelay(10); - - if (eeprom[3] & 0x0100) - product = "OEM i82557/i82558 10/100 Ethernet"; - else - product = pci_name(pdev); - - printk(KERN_INFO "%s: %s, %s, IRQ %d.\n", dev->name, product, - print_mac(mac, dev->dev_addr), pdev->irq); - - sp = netdev_priv(dev); - - /* we must initialize this early, for mdio_{read,write} */ - sp->regs = ioaddr; - -#if 1 || defined(kernel_bloat) - /* OK, this is pure kernel bloat. I don't like it when other drivers - waste non-pageable kernel space to emit similar messages, but I need - them for bug reports. */ - { - const char *connectors[] = {" RJ45", " BNC", " AUI", " MII"}; - /* The self-test results must be paragraph aligned. */ - volatile s32 *self_test_results; - int boguscnt = 16000; /* Timeout for set-test. */ - if ((eeprom[3] & 0x03) != 0x03) - printk(KERN_INFO " Receiver lock-up bug exists -- enabling" - " work-around.\n"); - printk(KERN_INFO " Board assembly %4.4x%2.2x-%3.3d, Physical" - " connectors present:", - eeprom[8], eeprom[9]>>8, eeprom[9] & 0xff); - for (i = 0; i < 4; i++) - if (eeprom[5] & (1<>8)&15], eeprom[6] & 0x1f); - if (eeprom[7] & 0x0700) - printk(KERN_INFO " Secondary interface chip %s.\n", - phys[(eeprom[7]>>8)&7]); - if (((eeprom[6]>>8) & 0x3f) == DP83840 - || ((eeprom[6]>>8) & 0x3f) == DP83840A) { - int mdi_reg23 = mdio_read(dev, eeprom[6] & 0x1f, 23) | 0x0422; - if (congenb) - mdi_reg23 |= 0x0100; - printk(KERN_INFO" DP83840 specific setup, setting register 23 to %4.4x.\n", - mdi_reg23); - mdio_write(dev, eeprom[6] & 0x1f, 23, mdi_reg23); - } - if ((option >= 0) && (option & 0x70)) { - printk(KERN_INFO " Forcing %dMbs %s-duplex operation.\n", - (option & 0x20 ? 100 : 10), - (option & 0x10 ? "full" : "half")); - mdio_write(dev, eeprom[6] & 0x1f, MII_BMCR, - ((option & 0x20) ? 0x2000 : 0) | /* 100mbps? */ - ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */ - } - - /* Perform a system self-test. */ - self_test_results = (s32*) ((((long) tx_ring_space) + 15) & ~0xf); - self_test_results[0] = 0; - self_test_results[1] = -1; - iowrite32(tx_ring_dma | PortSelfTest, ioaddr + SCBPort); - do { - udelay(10); - } while (self_test_results[1] == -1 && --boguscnt >= 0); - - if (boguscnt < 0) { /* Test optimized out. */ - printk(KERN_ERR "Self test failed, status %8.8x:\n" - KERN_ERR " Failure to initialize the i82557.\n" - KERN_ERR " Verify that the card is a bus-master" - " capable slot.\n", - self_test_results[1]); - } else - printk(KERN_INFO " General self-test: %s.\n" - KERN_INFO " Serial sub-system self-test: %s.\n" - KERN_INFO " Internal registers self-test: %s.\n" - KERN_INFO " ROM checksum self-test: %s (%#8.8x).\n", - self_test_results[1] & 0x1000 ? "failed" : "passed", - self_test_results[1] & 0x0020 ? "failed" : "passed", - self_test_results[1] & 0x0008 ? "failed" : "passed", - self_test_results[1] & 0x0004 ? "failed" : "passed", - self_test_results[0]); - } -#endif /* kernel_bloat */ - - iowrite32(PortReset, ioaddr + SCBPort); - ioread32(ioaddr + SCBPort); - udelay(10); - - /* Return the chip to its original power state. */ - pci_set_power_state(pdev, acpi_idle_state); - - pci_set_drvdata (pdev, dev); - SET_NETDEV_DEV(dev, &pdev->dev); - - dev->irq = pdev->irq; - - sp->pdev = pdev; - sp->msg_enable = DEBUG; - sp->acpi_pwr = acpi_idle_state; - sp->tx_ring = tx_ring_space; - sp->tx_ring_dma = tx_ring_dma; - sp->lstats = (struct speedo_stats *)(sp->tx_ring + TX_RING_SIZE); - sp->lstats_dma = TX_RING_ELEM_DMA(sp, TX_RING_SIZE); - init_timer(&sp->timer); /* used in ioctl() */ - spin_lock_init(&sp->lock); - - sp->mii_if.full_duplex = option >= 0 && (option & 0x10) ? 1 : 0; - if (card_idx >= 0) { - if (full_duplex[card_idx] >= 0) - sp->mii_if.full_duplex = full_duplex[card_idx]; - } - sp->default_port = option >= 0 ? (option & 0x0f) : 0; - - sp->phy[0] = eeprom[6]; - sp->phy[1] = eeprom[7]; - - sp->mii_if.phy_id = eeprom[6] & 0x1f; - sp->mii_if.phy_id_mask = 0x1f; - sp->mii_if.reg_num_mask = 0x1f; - sp->mii_if.dev = dev; - sp->mii_if.mdio_read = mdio_read; - sp->mii_if.mdio_write = mdio_write; - - sp->rx_bug = (eeprom[3] & 0x03) == 3 ? 0 : 1; - if (((pdev->device > 0x1030 && (pdev->device < 0x103F))) - || (pdev->device == 0x2449) || (pdev->device == 0x2459) - || (pdev->device == 0x245D)) { - sp->chip_id = 1; - } - - if (sp->rx_bug) - printk(KERN_INFO " Receiver lock-up workaround activated.\n"); - - /* The Speedo-specific entries in the device structure. */ - dev->open = &speedo_open; - dev->hard_start_xmit = &speedo_start_xmit; - netif_set_tx_timeout(dev, &speedo_tx_timeout, TX_TIMEOUT); - dev->stop = &speedo_close; - dev->get_stats = &speedo_get_stats; - dev->set_multicast_list = &set_rx_mode; - dev->do_ioctl = &speedo_ioctl; - SET_ETHTOOL_OPS(dev, ðtool_ops); -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = &poll_speedo; -#endif - - if (register_netdevice(dev)) - goto err_free_unlock; - rtnl_unlock(); - - return 0; - - err_free_unlock: - rtnl_unlock(); - free_netdev(dev); - return -1; -} - -static void do_slow_command(struct net_device *dev, struct speedo_private *sp, int cmd) -{ - void __iomem *cmd_ioaddr = sp->regs + SCBCmd; - int wait = 0; - do - if (ioread8(cmd_ioaddr) == 0) break; - while(++wait <= 200); - if (wait > 100) - printk(KERN_ERR "Command %4.4x never accepted (%d polls)!\n", - ioread8(cmd_ioaddr), wait); - - iowrite8(cmd, cmd_ioaddr); - - for (wait = 0; wait <= 100; wait++) - if (ioread8(cmd_ioaddr) == 0) return; - for (; wait <= 20000; wait++) - if (ioread8(cmd_ioaddr) == 0) return; - else udelay(1); - printk(KERN_ERR "Command %4.4x was not accepted after %d polls!" - " Current status %8.8x.\n", - cmd, wait, ioread32(sp->regs + SCBStatus)); -} - -/* Serial EEPROM section. - A "bit" grungy, but we work our way through bit-by-bit :->. */ -/* EEPROM_Ctrl bits. */ -#define EE_SHIFT_CLK 0x01 /* EEPROM shift clock. */ -#define EE_CS 0x02 /* EEPROM chip select. */ -#define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */ -#define EE_DATA_READ 0x08 /* EEPROM chip data out. */ -#define EE_ENB (0x4800 | EE_CS) -#define EE_WRITE_0 0x4802 -#define EE_WRITE_1 0x4806 -#define EE_OFFSET SCBeeprom - -/* The fixes for the code were kindly provided by Dragan Stancevic - to strictly follow Intel specifications of EEPROM - access timing. - The publicly available sheet 64486302 (sec. 3.1) specifies 1us access - interval for serial EEPROM. However, it looks like that there is an - additional requirement dictating larger udelay's in the code below. - 2000/05/24 SAW */ -static int __devinit do_eeprom_cmd(void __iomem *ioaddr, int cmd, int cmd_len) -{ - unsigned retval = 0; - void __iomem *ee_addr = ioaddr + SCBeeprom; - - iowrite16(EE_ENB, ee_addr); udelay(2); - iowrite16(EE_ENB | EE_SHIFT_CLK, ee_addr); udelay(2); - - /* Shift the command bits out. */ - do { - short dataval = (cmd & (1 << cmd_len)) ? EE_WRITE_1 : EE_WRITE_0; - iowrite16(dataval, ee_addr); udelay(2); - iowrite16(dataval | EE_SHIFT_CLK, ee_addr); udelay(2); - retval = (retval << 1) | ((ioread16(ee_addr) & EE_DATA_READ) ? 1 : 0); - } while (--cmd_len >= 0); - iowrite16(EE_ENB, ee_addr); udelay(2); - - /* Terminate the EEPROM access. */ - iowrite16(EE_ENB & ~EE_CS, ee_addr); - return retval; -} - -static int mdio_read(struct net_device *dev, int phy_id, int location) -{ - struct speedo_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->regs; - int val, boguscnt = 64*10; /* <64 usec. to complete, typ 27 ticks */ - iowrite32(0x08000000 | (location<<16) | (phy_id<<21), ioaddr + SCBCtrlMDI); - do { - val = ioread32(ioaddr + SCBCtrlMDI); - if (--boguscnt < 0) { - printk(KERN_ERR " mdio_read() timed out with val = %8.8x.\n", val); - break; - } - } while (! (val & 0x10000000)); - return val & 0xffff; -} - -static void mdio_write(struct net_device *dev, int phy_id, int location, int value) -{ - struct speedo_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->regs; - int val, boguscnt = 64*10; /* <64 usec. to complete, typ 27 ticks */ - iowrite32(0x04000000 | (location<<16) | (phy_id<<21) | value, - ioaddr + SCBCtrlMDI); - do { - val = ioread32(ioaddr + SCBCtrlMDI); - if (--boguscnt < 0) { - printk(KERN_ERR" mdio_write() timed out with val = %8.8x.\n", val); - break; - } - } while (! (val & 0x10000000)); -} - -static int -speedo_open(struct net_device *dev) -{ - struct speedo_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->regs; - int retval; - - if (netif_msg_ifup(sp)) - printk(KERN_DEBUG "%s: speedo_open() irq %d.\n", dev->name, dev->irq); - - pci_set_power_state(sp->pdev, PCI_D0); - - /* Set up the Tx queue early.. */ - sp->cur_tx = 0; - sp->dirty_tx = 0; - sp->last_cmd = NULL; - sp->tx_full = 0; - sp->in_interrupt = 0; - - /* .. we can safely take handler calls during init. */ - retval = request_irq(dev->irq, &speedo_interrupt, IRQF_SHARED, dev->name, dev); - if (retval) { - return retval; - } - - dev->if_port = sp->default_port; - -#ifdef oh_no_you_dont_unless_you_honour_the_options_passed_in_to_us - /* Retrigger negotiation to reset previous errors. */ - if ((sp->phy[0] & 0x8000) == 0) { - int phy_addr = sp->phy[0] & 0x1f ; - /* Use 0x3300 for restarting NWay, other values to force xcvr: - 0x0000 10-HD - 0x0100 10-FD - 0x2000 100-HD - 0x2100 100-FD - */ -#ifdef honor_default_port - mdio_write(dev, phy_addr, MII_BMCR, mii_ctrl[dev->default_port & 7]); -#else - mdio_write(dev, phy_addr, MII_BMCR, 0x3300); -#endif - } -#endif - - speedo_init_rx_ring(dev); - - /* Fire up the hardware. */ - iowrite16(SCBMaskAll, ioaddr + SCBCmd); - speedo_resume(dev); - - netdevice_start(dev); - netif_start_queue(dev); - - /* Setup the chip and configure the multicast list. */ - sp->mc_setup_head = NULL; - sp->mc_setup_tail = NULL; - sp->flow_ctrl = sp->partner = 0; - sp->rx_mode = -1; /* Invalid -> always reset the mode. */ - set_rx_mode(dev); - if ((sp->phy[0] & 0x8000) == 0) - sp->mii_if.advertising = mdio_read(dev, sp->phy[0] & 0x1f, MII_ADVERTISE); - - mii_check_link(&sp->mii_if); - - if (netif_msg_ifup(sp)) { - printk(KERN_DEBUG "%s: Done speedo_open(), status %8.8x.\n", - dev->name, ioread16(ioaddr + SCBStatus)); - } - - /* Set the timer. The timer serves a dual purpose: - 1) to monitor the media interface (e.g. link beat) and perhaps switch - to an alternate media type - 2) to monitor Rx activity, and restart the Rx process if the receiver - hangs. */ - sp->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */ - sp->timer.data = (unsigned long)dev; - sp->timer.function = &speedo_timer; /* timer handler */ - add_timer(&sp->timer); - - /* No need to wait for the command unit to accept here. */ - if ((sp->phy[0] & 0x8000) == 0) - mdio_read(dev, sp->phy[0] & 0x1f, MII_BMCR); - - return 0; -} - -/* Start the chip hardware after a full reset. */ -static void speedo_resume(struct net_device *dev) -{ - struct speedo_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->regs; - - /* Start with a Tx threshold of 256 (0x..20.... 8 byte units). */ - sp->tx_threshold = 0x01208000; - - /* Set the segment registers to '0'. */ - if (wait_for_cmd_done(dev, sp) != 0) { - iowrite32(PortPartialReset, ioaddr + SCBPort); - udelay(10); - } - - iowrite32(0, ioaddr + SCBPointer); - ioread32(ioaddr + SCBPointer); /* Flush to PCI. */ - udelay(10); /* Bogus, but it avoids the bug. */ - - /* Note: these next two operations can take a while. */ - do_slow_command(dev, sp, RxAddrLoad); - do_slow_command(dev, sp, CUCmdBase); - - /* Load the statistics block and rx ring addresses. */ - iowrite32(sp->lstats_dma, ioaddr + SCBPointer); - ioread32(ioaddr + SCBPointer); /* Flush to PCI */ - - iowrite8(CUStatsAddr, ioaddr + SCBCmd); - sp->lstats->done_marker = 0; - wait_for_cmd_done(dev, sp); - - if (sp->rx_ringp[sp->cur_rx % RX_RING_SIZE] == NULL) { - if (netif_msg_rx_err(sp)) - printk(KERN_DEBUG "%s: NULL cur_rx in speedo_resume().\n", - dev->name); - } else { - iowrite32(sp->rx_ring_dma[sp->cur_rx % RX_RING_SIZE], - ioaddr + SCBPointer); - ioread32(ioaddr + SCBPointer); /* Flush to PCI */ - } - - /* Note: RxStart should complete instantly. */ - do_slow_command(dev, sp, RxStart); - do_slow_command(dev, sp, CUDumpStats); - - /* Fill the first command with our physical address. */ - { - struct descriptor *ias_cmd; - - ias_cmd = - (struct descriptor *)&sp->tx_ring[sp->cur_tx++ % TX_RING_SIZE]; - /* Avoid a bug(?!) here by marking the command already completed. */ - ias_cmd->cmd_status = cpu_to_le32((CmdSuspend | CmdIASetup) | 0xa000); - ias_cmd->link = - cpu_to_le32(TX_RING_ELEM_DMA(sp, sp->cur_tx % TX_RING_SIZE)); - memcpy(ias_cmd->params, dev->dev_addr, 6); - if (sp->last_cmd) - clear_suspend(sp->last_cmd); - sp->last_cmd = ias_cmd; - } - - /* Start the chip's Tx process and unmask interrupts. */ - iowrite32(TX_RING_ELEM_DMA(sp, sp->dirty_tx % TX_RING_SIZE), - ioaddr + SCBPointer); - /* We are not ACK-ing FCP and ER in the interrupt handler yet so they should - remain masked --Dragan */ - iowrite16(CUStart | SCBMaskEarlyRx | SCBMaskFlowCtl, ioaddr + SCBCmd); -} - -/* - * Sometimes the receiver stops making progress. This routine knows how to - * get it going again, without losing packets or being otherwise nasty like - * a chip reset would be. Previously the driver had a whole sequence - * of if RxSuspended, if it's no buffers do one thing, if it's no resources, - * do another, etc. But those things don't really matter. Separate logic - * in the ISR provides for allocating buffers--the other half of operation - * is just making sure the receiver is active. speedo_rx_soft_reset does that. - * This problem with the old, more involved algorithm is shown up under - * ping floods on the order of 60K packets/second on a 100Mbps fdx network. - */ -static void -speedo_rx_soft_reset(struct net_device *dev) -{ - struct speedo_private *sp = netdev_priv(dev); - struct RxFD *rfd; - void __iomem *ioaddr; - - ioaddr = sp->regs; - if (wait_for_cmd_done(dev, sp) != 0) { - printk("%s: previous command stalled\n", dev->name); - return; - } - /* - * Put the hardware into a known state. - */ - iowrite8(RxAbort, ioaddr + SCBCmd); - - rfd = sp->rx_ringp[sp->cur_rx % RX_RING_SIZE]; - - rfd->rx_buf_addr = cpu_to_le32(0xffffffff); - - if (wait_for_cmd_done(dev, sp) != 0) { - printk("%s: RxAbort command stalled\n", dev->name); - return; - } - iowrite32(sp->rx_ring_dma[sp->cur_rx % RX_RING_SIZE], - ioaddr + SCBPointer); - iowrite8(RxStart, ioaddr + SCBCmd); -} - - -/* Media monitoring and control. */ -static void speedo_timer(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct speedo_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->regs; - int phy_num = sp->phy[0] & 0x1f; - - /* We have MII and lost link beat. */ - if ((sp->phy[0] & 0x8000) == 0) { - int partner = mdio_read(dev, phy_num, MII_LPA); - if (partner != sp->partner) { - int flow_ctrl = sp->mii_if.advertising & partner & 0x0400 ? 1 : 0; - if (netif_msg_link(sp)) { - printk(KERN_DEBUG "%s: Link status change.\n", dev->name); - printk(KERN_DEBUG "%s: Old partner %x, new %x, adv %x.\n", - dev->name, sp->partner, partner, sp->mii_if.advertising); - } - sp->partner = partner; - if (flow_ctrl != sp->flow_ctrl) { - sp->flow_ctrl = flow_ctrl; - sp->rx_mode = -1; /* Trigger a reload. */ - } - } - } - mii_check_link(&sp->mii_if); - if (netif_msg_timer(sp)) { - printk(KERN_DEBUG "%s: Media control tick, status %4.4x.\n", - dev->name, ioread16(ioaddr + SCBStatus)); - } - if (sp->rx_mode < 0 || - (sp->rx_bug && jiffies - sp->last_rx_time > 2*HZ)) { - /* We haven't received a packet in a Long Time. We might have been - bitten by the receiver hang bug. This can be cleared by sending - a set multicast list command. */ - if (netif_msg_timer(sp)) - printk(KERN_DEBUG "%s: Sending a multicast list set command" - " from a timer routine," - " m=%d, j=%ld, l=%ld.\n", - dev->name, sp->rx_mode, jiffies, sp->last_rx_time); - set_rx_mode(dev); - } - /* We must continue to monitor the media. */ - sp->timer.expires = RUN_AT(2*HZ); /* 2.0 sec. */ - add_timer(&sp->timer); -} - -static void speedo_show_state(struct net_device *dev) -{ - struct speedo_private *sp = netdev_priv(dev); - int i; - - if (netif_msg_pktdata(sp)) { - printk(KERN_DEBUG "%s: Tx ring dump, Tx queue %u / %u:\n", - dev->name, sp->cur_tx, sp->dirty_tx); - for (i = 0; i < TX_RING_SIZE; i++) - printk(KERN_DEBUG "%s: %c%c%2d %8.8x.\n", dev->name, - i == sp->dirty_tx % TX_RING_SIZE ? '*' : ' ', - i == sp->cur_tx % TX_RING_SIZE ? '=' : ' ', - i, sp->tx_ring[i].status); - - printk(KERN_DEBUG "%s: Printing Rx ring" - " (next to receive into %u, dirty index %u).\n", - dev->name, sp->cur_rx, sp->dirty_rx); - for (i = 0; i < RX_RING_SIZE; i++) - printk(KERN_DEBUG "%s: %c%c%c%2d %8.8x.\n", dev->name, - sp->rx_ringp[i] == sp->last_rxf ? 'l' : ' ', - i == sp->dirty_rx % RX_RING_SIZE ? '*' : ' ', - i == sp->cur_rx % RX_RING_SIZE ? '=' : ' ', - i, (sp->rx_ringp[i] != NULL) ? - (unsigned)sp->rx_ringp[i]->status : 0); - } - -#if 0 - { - void __iomem *ioaddr = sp->regs; - int phy_num = sp->phy[0] & 0x1f; - for (i = 0; i < 16; i++) { - /* FIXME: what does it mean? --SAW */ - if (i == 6) i = 21; - printk(KERN_DEBUG "%s: PHY index %d register %d is %4.4x.\n", - dev->name, phy_num, i, mdio_read(dev, phy_num, i)); - } - } -#endif - -} - -/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ -static void -speedo_init_rx_ring(struct net_device *dev) -{ - struct speedo_private *sp = netdev_priv(dev); - struct RxFD *rxf, *last_rxf = NULL; - dma_addr_t last_rxf_dma = 0 /* to shut up the compiler */; - int i; - - sp->cur_rx = 0; - - for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb; - skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD)); - if (skb) - rx_align(skb); /* Align IP on 16 byte boundary */ - sp->rx_skbuff[i] = skb; - if (skb == NULL) - break; /* OK. Just initially short of Rx bufs. */ - skb->dev = dev; /* Mark as being used by this device. */ - rxf = (struct RxFD *)skb->data; - sp->rx_ringp[i] = rxf; - sp->rx_ring_dma[i] = - pci_map_single(sp->pdev, rxf, - PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_BIDIRECTIONAL); - skb_reserve(skb, sizeof(struct RxFD)); - if (last_rxf) { - last_rxf->link = cpu_to_le32(sp->rx_ring_dma[i]); - pci_dma_sync_single_for_device(sp->pdev, last_rxf_dma, - sizeof(struct RxFD), PCI_DMA_TODEVICE); - } - last_rxf = rxf; - last_rxf_dma = sp->rx_ring_dma[i]; - rxf->status = cpu_to_le32(0x00000001); /* '1' is flag value only. */ - rxf->link = 0; /* None yet. */ - /* This field unused by i82557. */ - rxf->rx_buf_addr = cpu_to_le32(0xffffffff); - rxf->count = cpu_to_le32(PKT_BUF_SZ << 16); - pci_dma_sync_single_for_device(sp->pdev, sp->rx_ring_dma[i], - sizeof(struct RxFD), PCI_DMA_TODEVICE); - } - sp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); - /* Mark the last entry as end-of-list. */ - last_rxf->status = cpu_to_le32(0xC0000002); /* '2' is flag value only. */ - pci_dma_sync_single_for_device(sp->pdev, sp->rx_ring_dma[RX_RING_SIZE-1], - sizeof(struct RxFD), PCI_DMA_TODEVICE); - sp->last_rxf = last_rxf; - sp->last_rxf_dma = last_rxf_dma; -} - -static void speedo_purge_tx(struct net_device *dev) -{ - struct speedo_private *sp = netdev_priv(dev); - int entry; - - while ((int)(sp->cur_tx - sp->dirty_tx) > 0) { - entry = sp->dirty_tx % TX_RING_SIZE; - if (sp->tx_skbuff[entry]) { - sp->stats.tx_errors++; - pci_unmap_single(sp->pdev, - le32_to_cpu(sp->tx_ring[entry].tx_buf_addr0), - sp->tx_skbuff[entry]->len, PCI_DMA_TODEVICE); - dev_kfree_skb_irq(sp->tx_skbuff[entry]); - sp->tx_skbuff[entry] = NULL; - } - sp->dirty_tx++; - } - while (sp->mc_setup_head != NULL) { - struct speedo_mc_block *t; - if (netif_msg_tx_err(sp)) - printk(KERN_DEBUG "%s: freeing mc frame.\n", dev->name); - pci_unmap_single(sp->pdev, sp->mc_setup_head->frame_dma, - sp->mc_setup_head->len, PCI_DMA_TODEVICE); - t = sp->mc_setup_head->next; - kfree(sp->mc_setup_head); - sp->mc_setup_head = t; - } - sp->mc_setup_tail = NULL; - sp->tx_full = 0; - netif_wake_queue(dev); -} - -static void reset_mii(struct net_device *dev) -{ - struct speedo_private *sp = netdev_priv(dev); - - /* Reset the MII transceiver, suggested by Fred Young @ scalable.com. */ - if ((sp->phy[0] & 0x8000) == 0) { - int phy_addr = sp->phy[0] & 0x1f; - int advertising = mdio_read(dev, phy_addr, MII_ADVERTISE); - int mii_bmcr = mdio_read(dev, phy_addr, MII_BMCR); - mdio_write(dev, phy_addr, MII_BMCR, 0x0400); - mdio_write(dev, phy_addr, MII_BMSR, 0x0000); - mdio_write(dev, phy_addr, MII_ADVERTISE, 0x0000); - mdio_write(dev, phy_addr, MII_BMCR, 0x8000); -#ifdef honor_default_port - mdio_write(dev, phy_addr, MII_BMCR, mii_ctrl[dev->default_port & 7]); -#else - mdio_read(dev, phy_addr, MII_BMCR); - mdio_write(dev, phy_addr, MII_BMCR, mii_bmcr); - mdio_write(dev, phy_addr, MII_ADVERTISE, advertising); -#endif - } -} - -static void speedo_tx_timeout(struct net_device *dev) -{ - struct speedo_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->regs; - int status = ioread16(ioaddr + SCBStatus); - unsigned long flags; - - if (netif_msg_tx_err(sp)) { - printk(KERN_WARNING "%s: Transmit timed out: status %4.4x " - " %4.4x at %d/%d command %8.8x.\n", - dev->name, status, ioread16(ioaddr + SCBCmd), - sp->dirty_tx, sp->cur_tx, - sp->tx_ring[sp->dirty_tx % TX_RING_SIZE].status); - - } - speedo_show_state(dev); -#if 0 - if ((status & 0x00C0) != 0x0080 - && (status & 0x003C) == 0x0010) { - /* Only the command unit has stopped. */ - printk(KERN_WARNING "%s: Trying to restart the transmitter...\n", - dev->name); - iowrite32(TX_RING_ELEM_DMA(sp, dirty_tx % TX_RING_SIZE]), - ioaddr + SCBPointer); - iowrite16(CUStart, ioaddr + SCBCmd); - reset_mii(dev); - } else { -#else - { -#endif - del_timer_sync(&sp->timer); - /* Reset the Tx and Rx units. */ - iowrite32(PortReset, ioaddr + SCBPort); - /* We may get spurious interrupts here. But I don't think that they - may do much harm. 1999/12/09 SAW */ - udelay(10); - /* Disable interrupts. */ - iowrite16(SCBMaskAll, ioaddr + SCBCmd); - synchronize_irq(dev->irq); - speedo_tx_buffer_gc(dev); - /* Free as much as possible. - It helps to recover from a hang because of out-of-memory. - It also simplifies speedo_resume() in case TX ring is full or - close-to-be full. */ - speedo_purge_tx(dev); - speedo_refill_rx_buffers(dev, 1); - spin_lock_irqsave(&sp->lock, flags); - speedo_resume(dev); - sp->rx_mode = -1; - dev->trans_start = jiffies; - spin_unlock_irqrestore(&sp->lock, flags); - set_rx_mode(dev); /* it takes the spinlock itself --SAW */ - /* Reset MII transceiver. Do it before starting the timer to serialize - mdio_xxx operations. Yes, it's a paranoya :-) 2000/05/09 SAW */ - reset_mii(dev); - sp->timer.expires = RUN_AT(2*HZ); - add_timer(&sp->timer); - } - return; -} - -static int -speedo_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct speedo_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->regs; - int entry; - - /* Prevent interrupts from changing the Tx ring from underneath us. */ - unsigned long flags; - - spin_lock_irqsave(&sp->lock, flags); - - /* Check if there are enough space. */ - if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) { - printk(KERN_ERR "%s: incorrect tbusy state, fixed.\n", dev->name); - netif_stop_queue(dev); - sp->tx_full = 1; - spin_unlock_irqrestore(&sp->lock, flags); - return 1; - } - - /* Calculate the Tx descriptor entry. */ - entry = sp->cur_tx++ % TX_RING_SIZE; - - sp->tx_skbuff[entry] = skb; - sp->tx_ring[entry].status = - cpu_to_le32(CmdSuspend | CmdTx | CmdTxFlex); - if (!(entry & ((TX_RING_SIZE>>2)-1))) - sp->tx_ring[entry].status |= cpu_to_le32(CmdIntr); - sp->tx_ring[entry].link = - cpu_to_le32(TX_RING_ELEM_DMA(sp, sp->cur_tx % TX_RING_SIZE)); - sp->tx_ring[entry].tx_desc_addr = - cpu_to_le32(TX_RING_ELEM_DMA(sp, entry) + TX_DESCR_BUF_OFFSET); - /* The data region is always in one buffer descriptor. */ - sp->tx_ring[entry].count = cpu_to_le32(sp->tx_threshold); - sp->tx_ring[entry].tx_buf_addr0 = - cpu_to_le32(pci_map_single(sp->pdev, skb->data, - skb->len, PCI_DMA_TODEVICE)); - sp->tx_ring[entry].tx_buf_size0 = cpu_to_le32(skb->len); - - /* workaround for hardware bug on 10 mbit half duplex */ - - if ((sp->partner == 0) && (sp->chip_id == 1)) { - wait_for_cmd_done(dev, sp); - iowrite8(0 , ioaddr + SCBCmd); - udelay(1); - } - - /* Trigger the command unit resume. */ - wait_for_cmd_done(dev, sp); - clear_suspend(sp->last_cmd); - /* We want the time window between clearing suspend flag on the previous - command and resuming CU to be as small as possible. - Interrupts in between are very undesired. --SAW */ - iowrite8(CUResume, ioaddr + SCBCmd); - sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry]; - - /* Leave room for set_rx_mode(). If there is no more space than reserved - for multicast filter mark the ring as full. */ - if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) { - netif_stop_queue(dev); - sp->tx_full = 1; - } - - spin_unlock_irqrestore(&sp->lock, flags); - - dev->trans_start = jiffies; - - return 0; -} - -static void speedo_tx_buffer_gc(struct net_device *dev) -{ - unsigned int dirty_tx; - struct speedo_private *sp = netdev_priv(dev); - - dirty_tx = sp->dirty_tx; - while ((int)(sp->cur_tx - dirty_tx) > 0) { - int entry = dirty_tx % TX_RING_SIZE; - int status = le32_to_cpu(sp->tx_ring[entry].status); - - if (netif_msg_tx_done(sp)) - printk(KERN_DEBUG " scavenge candidate %d status %4.4x.\n", - entry, status); - if ((status & StatusComplete) == 0) - break; /* It still hasn't been processed. */ - if (status & TxUnderrun) - if (sp->tx_threshold < 0x01e08000) { - if (netif_msg_tx_err(sp)) - printk(KERN_DEBUG "%s: TX underrun, threshold adjusted.\n", - dev->name); - sp->tx_threshold += 0x00040000; - } - /* Free the original skb. */ - if (sp->tx_skbuff[entry]) { - sp->stats.tx_packets++; /* Count only user packets. */ - sp->stats.tx_bytes += sp->tx_skbuff[entry]->len; - pci_unmap_single(sp->pdev, - le32_to_cpu(sp->tx_ring[entry].tx_buf_addr0), - sp->tx_skbuff[entry]->len, PCI_DMA_TODEVICE); - dev_kfree_skb_irq(sp->tx_skbuff[entry]); - sp->tx_skbuff[entry] = NULL; - } - dirty_tx++; - } - - if (netif_msg_tx_err(sp) && (int)(sp->cur_tx - dirty_tx) > TX_RING_SIZE) { - printk(KERN_ERR "out-of-sync dirty pointer, %d vs. %d," - " full=%d.\n", - dirty_tx, sp->cur_tx, sp->tx_full); - dirty_tx += TX_RING_SIZE; - } - - while (sp->mc_setup_head != NULL - && (int)(dirty_tx - sp->mc_setup_head->tx - 1) > 0) { - struct speedo_mc_block *t; - if (netif_msg_tx_err(sp)) - printk(KERN_DEBUG "%s: freeing mc frame.\n", dev->name); - pci_unmap_single(sp->pdev, sp->mc_setup_head->frame_dma, - sp->mc_setup_head->len, PCI_DMA_TODEVICE); - t = sp->mc_setup_head->next; - kfree(sp->mc_setup_head); - sp->mc_setup_head = t; - } - if (sp->mc_setup_head == NULL) - sp->mc_setup_tail = NULL; - - sp->dirty_tx = dirty_tx; -} - -/* The interrupt handler does all of the Rx thread work and cleans up - after the Tx thread. */ -static irqreturn_t speedo_interrupt(int irq, void *dev_instance) -{ - struct net_device *dev = (struct net_device *)dev_instance; - struct speedo_private *sp; - void __iomem *ioaddr; - long boguscnt = max_interrupt_work; - unsigned short status; - unsigned int handled = 0; - - sp = netdev_priv(dev); - ioaddr = sp->regs; - -#ifndef final_version - /* A lock to prevent simultaneous entry on SMP machines. */ - if (test_and_set_bit(0, (void*)&sp->in_interrupt)) { - printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n", - dev->name); - sp->in_interrupt = 0; /* Avoid halting machine. */ - return IRQ_NONE; - } -#endif - - do { - status = ioread16(ioaddr + SCBStatus); - /* Acknowledge all of the current interrupt sources ASAP. */ - /* Will change from 0xfc00 to 0xff00 when we start handling - FCP and ER interrupts --Dragan */ - iowrite16(status & 0xfc00, ioaddr + SCBStatus); - - if (netif_msg_intr(sp)) - printk(KERN_DEBUG "%s: interrupt status=%#4.4x.\n", - dev->name, status); - - if ((status & 0xfc00) == 0) - break; - handled = 1; - - - if ((status & 0x5000) || /* Packet received, or Rx error. */ - (sp->rx_ring_state&(RrNoMem|RrPostponed)) == RrPostponed) - /* Need to gather the postponed packet. */ - speedo_rx(dev); - - /* Always check if all rx buffers are allocated. --SAW */ - speedo_refill_rx_buffers(dev, 0); - - spin_lock(&sp->lock); - /* - * The chip may have suspended reception for various reasons. - * Check for that, and re-prime it should this be the case. - */ - switch ((status >> 2) & 0xf) { - case 0: /* Idle */ - break; - case 1: /* Suspended */ - case 2: /* No resources (RxFDs) */ - case 9: /* Suspended with no more RBDs */ - case 10: /* No resources due to no RBDs */ - case 12: /* Ready with no RBDs */ - speedo_rx_soft_reset(dev); - break; - case 3: case 5: case 6: case 7: case 8: - case 11: case 13: case 14: case 15: - /* these are all reserved values */ - break; - } - - - /* User interrupt, Command/Tx unit interrupt or CU not active. */ - if (status & 0xA400) { - speedo_tx_buffer_gc(dev); - if (sp->tx_full - && (int)(sp->cur_tx - sp->dirty_tx) < TX_QUEUE_UNFULL) { - /* The ring is no longer full. */ - sp->tx_full = 0; - netif_wake_queue(dev); /* Attention: under a spinlock. --SAW */ - } - } - - spin_unlock(&sp->lock); - - if (--boguscnt < 0) { - printk(KERN_ERR "%s: Too much work at interrupt, status=0x%4.4x.\n", - dev->name, status); - /* Clear all interrupt sources. */ - /* Will change from 0xfc00 to 0xff00 when we start handling - FCP and ER interrupts --Dragan */ - iowrite16(0xfc00, ioaddr + SCBStatus); - break; - } - } while (1); - - if (netif_msg_intr(sp)) - printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", - dev->name, ioread16(ioaddr + SCBStatus)); - - clear_bit(0, (void*)&sp->in_interrupt); - return IRQ_RETVAL(handled); -} - -static inline struct RxFD *speedo_rx_alloc(struct net_device *dev, int entry) -{ - struct speedo_private *sp = netdev_priv(dev); - struct RxFD *rxf; - struct sk_buff *skb; - /* Get a fresh skbuff to replace the consumed one. */ - skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD)); - if (skb) - rx_align(skb); /* Align IP on 16 byte boundary */ - sp->rx_skbuff[entry] = skb; - if (skb == NULL) { - sp->rx_ringp[entry] = NULL; - return NULL; - } - rxf = sp->rx_ringp[entry] = (struct RxFD *)skb->data; - sp->rx_ring_dma[entry] = - pci_map_single(sp->pdev, rxf, - PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE); - skb->dev = dev; - skb_reserve(skb, sizeof(struct RxFD)); - rxf->rx_buf_addr = cpu_to_le32(0xffffffff); - pci_dma_sync_single_for_device(sp->pdev, sp->rx_ring_dma[entry], - sizeof(struct RxFD), PCI_DMA_TODEVICE); - return rxf; -} - -static inline void speedo_rx_link(struct net_device *dev, int entry, - struct RxFD *rxf, dma_addr_t rxf_dma) -{ - struct speedo_private *sp = netdev_priv(dev); - rxf->status = cpu_to_le32(0xC0000001); /* '1' for driver use only. */ - rxf->link = 0; /* None yet. */ - rxf->count = cpu_to_le32(PKT_BUF_SZ << 16); - sp->last_rxf->link = cpu_to_le32(rxf_dma); - sp->last_rxf->status &= cpu_to_le32(~0xC0000000); - pci_dma_sync_single_for_device(sp->pdev, sp->last_rxf_dma, - sizeof(struct RxFD), PCI_DMA_TODEVICE); - sp->last_rxf = rxf; - sp->last_rxf_dma = rxf_dma; -} - -static int speedo_refill_rx_buf(struct net_device *dev, int force) -{ - struct speedo_private *sp = netdev_priv(dev); - int entry; - struct RxFD *rxf; - - entry = sp->dirty_rx % RX_RING_SIZE; - if (sp->rx_skbuff[entry] == NULL) { - rxf = speedo_rx_alloc(dev, entry); - if (rxf == NULL) { - unsigned int forw; - int forw_entry; - if (netif_msg_rx_err(sp) || !(sp->rx_ring_state & RrOOMReported)) { - printk(KERN_WARNING "%s: can't fill rx buffer (force %d)!\n", - dev->name, force); - sp->rx_ring_state |= RrOOMReported; - } - speedo_show_state(dev); - if (!force) - return -1; /* Better luck next time! */ - /* Borrow an skb from one of next entries. */ - for (forw = sp->dirty_rx + 1; forw != sp->cur_rx; forw++) - if (sp->rx_skbuff[forw % RX_RING_SIZE] != NULL) - break; - if (forw == sp->cur_rx) - return -1; - forw_entry = forw % RX_RING_SIZE; - sp->rx_skbuff[entry] = sp->rx_skbuff[forw_entry]; - sp->rx_skbuff[forw_entry] = NULL; - rxf = sp->rx_ringp[forw_entry]; - sp->rx_ringp[forw_entry] = NULL; - sp->rx_ringp[entry] = rxf; - } - } else { - rxf = sp->rx_ringp[entry]; - } - speedo_rx_link(dev, entry, rxf, sp->rx_ring_dma[entry]); - sp->dirty_rx++; - sp->rx_ring_state &= ~(RrNoMem|RrOOMReported); /* Mark the progress. */ - return 0; -} - -static void speedo_refill_rx_buffers(struct net_device *dev, int force) -{ - struct speedo_private *sp = netdev_priv(dev); - - /* Refill the RX ring. */ - while ((int)(sp->cur_rx - sp->dirty_rx) > 0 && - speedo_refill_rx_buf(dev, force) != -1); -} - -static int -speedo_rx(struct net_device *dev) -{ - struct speedo_private *sp = netdev_priv(dev); - int entry = sp->cur_rx % RX_RING_SIZE; - int rx_work_limit = sp->dirty_rx + RX_RING_SIZE - sp->cur_rx; - int alloc_ok = 1; - int npkts = 0; - - if (netif_msg_intr(sp)) - printk(KERN_DEBUG " In speedo_rx().\n"); - /* If we own the next entry, it's a new packet. Send it up. */ - while (sp->rx_ringp[entry] != NULL) { - int status; - int pkt_len; - - pci_dma_sync_single_for_cpu(sp->pdev, sp->rx_ring_dma[entry], - sizeof(struct RxFD), PCI_DMA_FROMDEVICE); - status = le32_to_cpu(sp->rx_ringp[entry]->status); - pkt_len = le32_to_cpu(sp->rx_ringp[entry]->count) & 0x3fff; - - if (!(status & RxComplete)) - break; - - if (--rx_work_limit < 0) - break; - - /* Check for a rare out-of-memory case: the current buffer is - the last buffer allocated in the RX ring. --SAW */ - if (sp->last_rxf == sp->rx_ringp[entry]) { - /* Postpone the packet. It'll be reaped at an interrupt when this - packet is no longer the last packet in the ring. */ - if (netif_msg_rx_err(sp)) - printk(KERN_DEBUG "%s: RX packet postponed!\n", - dev->name); - sp->rx_ring_state |= RrPostponed; - break; - } - - if (netif_msg_rx_status(sp)) - printk(KERN_DEBUG " speedo_rx() status %8.8x len %d.\n", status, - pkt_len); - if ((status & (RxErrTooBig|RxOK|0x0f90)) != RxOK) { - if (status & RxErrTooBig) - printk(KERN_ERR "%s: Ethernet frame overran the Rx buffer, " - "status %8.8x!\n", dev->name, status); - else if (! (status & RxOK)) { - /* There was a fatal error. This *should* be impossible. */ - sp->stats.rx_errors++; - printk(KERN_ERR "%s: Anomalous event in speedo_rx(), " - "status %8.8x.\n", - dev->name, status); - } - } else { - struct sk_buff *skb; - - /* Check if the packet is long enough to just accept without - copying to a properly sized skbuff. */ - if (pkt_len < rx_copybreak - && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { - skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - /* 'skb_put()' points to the start of sk_buff data area. */ - pci_dma_sync_single_for_cpu(sp->pdev, sp->rx_ring_dma[entry], - sizeof(struct RxFD) + pkt_len, - PCI_DMA_FROMDEVICE); - -#if 1 || USE_IP_CSUM - /* Packet is in one chunk -- we can copy + cksum. */ - skb_copy_to_linear_data(skb, sp->rx_skbuff[entry]->data, pkt_len); - skb_put(skb, pkt_len); -#else - skb_copy_from_linear_data(sp->rx_skbuff[entry], - skb_put(skb, pkt_len), - pkt_len); -#endif - pci_dma_sync_single_for_device(sp->pdev, sp->rx_ring_dma[entry], - sizeof(struct RxFD) + pkt_len, - PCI_DMA_FROMDEVICE); - npkts++; - } else { - /* Pass up the already-filled skbuff. */ - skb = sp->rx_skbuff[entry]; - if (skb == NULL) { - printk(KERN_ERR "%s: Inconsistent Rx descriptor chain.\n", - dev->name); - break; - } - sp->rx_skbuff[entry] = NULL; - skb_put(skb, pkt_len); - npkts++; - sp->rx_ringp[entry] = NULL; - pci_unmap_single(sp->pdev, sp->rx_ring_dma[entry], - PKT_BUF_SZ + sizeof(struct RxFD), - PCI_DMA_FROMDEVICE); - } - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - dev->last_rx = jiffies; - sp->stats.rx_packets++; - sp->stats.rx_bytes += pkt_len; - } - entry = (++sp->cur_rx) % RX_RING_SIZE; - sp->rx_ring_state &= ~RrPostponed; - /* Refill the recently taken buffers. - Do it one-by-one to handle traffic bursts better. */ - if (alloc_ok && speedo_refill_rx_buf(dev, 0) == -1) - alloc_ok = 0; - } - - /* Try hard to refill the recently taken buffers. */ - speedo_refill_rx_buffers(dev, 1); - - if (npkts) - sp->last_rx_time = jiffies; - - return 0; -} - -static int -speedo_close(struct net_device *dev) -{ - struct speedo_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->regs; - int i; - - netdevice_stop(dev); - netif_stop_queue(dev); - - if (netif_msg_ifdown(sp)) - printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n", - dev->name, ioread16(ioaddr + SCBStatus)); - - /* Shut off the media monitoring timer. */ - del_timer_sync(&sp->timer); - - iowrite16(SCBMaskAll, ioaddr + SCBCmd); - - /* Shutting down the chip nicely fails to disable flow control. So.. */ - iowrite32(PortPartialReset, ioaddr + SCBPort); - ioread32(ioaddr + SCBPort); /* flush posted write */ - /* - * The chip requires a 10 microsecond quiet period. Wait here! - */ - udelay(10); - - free_irq(dev->irq, dev); - speedo_show_state(dev); - - /* Free all the skbuffs in the Rx and Tx queues. */ - for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb = sp->rx_skbuff[i]; - sp->rx_skbuff[i] = NULL; - /* Clear the Rx descriptors. */ - if (skb) { - pci_unmap_single(sp->pdev, - sp->rx_ring_dma[i], - PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE); - dev_kfree_skb(skb); - } - } - - for (i = 0; i < TX_RING_SIZE; i++) { - struct sk_buff *skb = sp->tx_skbuff[i]; - sp->tx_skbuff[i] = NULL; - /* Clear the Tx descriptors. */ - if (skb) { - pci_unmap_single(sp->pdev, - le32_to_cpu(sp->tx_ring[i].tx_buf_addr0), - skb->len, PCI_DMA_TODEVICE); - dev_kfree_skb(skb); - } - } - - /* Free multicast setting blocks. */ - for (i = 0; sp->mc_setup_head != NULL; i++) { - struct speedo_mc_block *t; - t = sp->mc_setup_head->next; - kfree(sp->mc_setup_head); - sp->mc_setup_head = t; - } - sp->mc_setup_tail = NULL; - if (netif_msg_ifdown(sp)) - printk(KERN_DEBUG "%s: %d multicast blocks dropped.\n", dev->name, i); - - pci_set_power_state(sp->pdev, PCI_D2); - - return 0; -} - -/* The Speedo-3 has an especially awkward and unusable method of getting - statistics out of the chip. It takes an unpredictable length of time - for the dump-stats command to complete. To avoid a busy-wait loop we - update the stats with the previous dump results, and then trigger a - new dump. - - Oh, and incoming frames are dropped while executing dump-stats! - */ -static struct net_device_stats * -speedo_get_stats(struct net_device *dev) -{ - struct speedo_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->regs; - - /* Update only if the previous dump finished. */ - if (sp->lstats->done_marker == cpu_to_le32(0xA007)) { - sp->stats.tx_aborted_errors += le32_to_cpu(sp->lstats->tx_coll16_errs); - sp->stats.tx_window_errors += le32_to_cpu(sp->lstats->tx_late_colls); - sp->stats.tx_fifo_errors += le32_to_cpu(sp->lstats->tx_underruns); - sp->stats.tx_fifo_errors += le32_to_cpu(sp->lstats->tx_lost_carrier); - /*sp->stats.tx_deferred += le32_to_cpu(sp->lstats->tx_deferred);*/ - sp->stats.collisions += le32_to_cpu(sp->lstats->tx_total_colls); - sp->stats.rx_crc_errors += le32_to_cpu(sp->lstats->rx_crc_errs); - sp->stats.rx_frame_errors += le32_to_cpu(sp->lstats->rx_align_errs); - sp->stats.rx_over_errors += le32_to_cpu(sp->lstats->rx_resource_errs); - sp->stats.rx_fifo_errors += le32_to_cpu(sp->lstats->rx_overrun_errs); - sp->stats.rx_length_errors += le32_to_cpu(sp->lstats->rx_runt_errs); - sp->lstats->done_marker = 0x0000; - if (netif_running(dev)) { - unsigned long flags; - /* Take a spinlock to make wait_for_cmd_done and sending the - command atomic. --SAW */ - spin_lock_irqsave(&sp->lock, flags); - wait_for_cmd_done(dev, sp); - iowrite8(CUDumpStats, ioaddr + SCBCmd); - spin_unlock_irqrestore(&sp->lock, flags); - } - } - return &sp->stats; -} - -static void speedo_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) -{ - struct speedo_private *sp = netdev_priv(dev); - strncpy(info->driver, "eepro100", sizeof(info->driver)-1); - strncpy(info->version, version, sizeof(info->version)-1); - if (sp->pdev) - strcpy(info->bus_info, pci_name(sp->pdev)); -} - -static int speedo_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) -{ - struct speedo_private *sp = netdev_priv(dev); - spin_lock_irq(&sp->lock); - mii_ethtool_gset(&sp->mii_if, ecmd); - spin_unlock_irq(&sp->lock); - return 0; -} - -static int speedo_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) -{ - struct speedo_private *sp = netdev_priv(dev); - int res; - spin_lock_irq(&sp->lock); - res = mii_ethtool_sset(&sp->mii_if, ecmd); - spin_unlock_irq(&sp->lock); - return res; -} - -static int speedo_nway_reset(struct net_device *dev) -{ - struct speedo_private *sp = netdev_priv(dev); - return mii_nway_restart(&sp->mii_if); -} - -static u32 speedo_get_link(struct net_device *dev) -{ - struct speedo_private *sp = netdev_priv(dev); - return mii_link_ok(&sp->mii_if); -} - -static u32 speedo_get_msglevel(struct net_device *dev) -{ - struct speedo_private *sp = netdev_priv(dev); - return sp->msg_enable; -} - -static void speedo_set_msglevel(struct net_device *dev, u32 v) -{ - struct speedo_private *sp = netdev_priv(dev); - sp->msg_enable = v; -} - -static const struct ethtool_ops ethtool_ops = { - .get_drvinfo = speedo_get_drvinfo, - .get_settings = speedo_get_settings, - .set_settings = speedo_set_settings, - .nway_reset = speedo_nway_reset, - .get_link = speedo_get_link, - .get_msglevel = speedo_get_msglevel, - .set_msglevel = speedo_set_msglevel, -}; - -static int speedo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct speedo_private *sp = netdev_priv(dev); - struct mii_ioctl_data *data = if_mii(rq); - int phy = sp->phy[0] & 0x1f; - int saved_acpi; - int t; - - switch(cmd) { - case SIOCGMIIPHY: /* Get address of MII PHY in use. */ - data->phy_id = phy; - - case SIOCGMIIREG: /* Read MII PHY register. */ - /* FIXME: these operations need to be serialized with MDIO - access from the timeout handler. - They are currently serialized only with MDIO access from the - timer routine. 2000/05/09 SAW */ - saved_acpi = pci_set_power_state(sp->pdev, PCI_D0); - t = del_timer_sync(&sp->timer); - data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f); - if (t) - add_timer(&sp->timer); /* may be set to the past --SAW */ - pci_set_power_state(sp->pdev, saved_acpi); - return 0; - - case SIOCSMIIREG: /* Write MII PHY register. */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - saved_acpi = pci_set_power_state(sp->pdev, PCI_D0); - t = del_timer_sync(&sp->timer); - mdio_write(dev, data->phy_id, data->reg_num, data->val_in); - if (t) - add_timer(&sp->timer); /* may be set to the past --SAW */ - pci_set_power_state(sp->pdev, saved_acpi); - return 0; - default: - return -EOPNOTSUPP; - } -} - -/* Set or clear the multicast filter for this adaptor. - This is very ugly with Intel chips -- we usually have to execute an - entire configuration command, plus process a multicast command. - This is complicated. We must put a large configuration command and - an arbitrarily-sized multicast command in the transmit list. - To minimize the disruption -- the previous command might have already - loaded the link -- we convert the current command block, normally a Tx - command, into a no-op and link it to the new command. -*/ -static void set_rx_mode(struct net_device *dev) -{ - struct speedo_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->regs; - struct descriptor *last_cmd; - char new_rx_mode; - unsigned long flags; - int entry, i; - - if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ - new_rx_mode = 3; - } else if ((dev->flags & IFF_ALLMULTI) || - dev->mc_count > multicast_filter_limit) { - new_rx_mode = 1; - } else - new_rx_mode = 0; - - if (netif_msg_rx_status(sp)) - printk(KERN_DEBUG "%s: set_rx_mode %d -> %d\n", dev->name, - sp->rx_mode, new_rx_mode); - - if ((int)(sp->cur_tx - sp->dirty_tx) > TX_RING_SIZE - TX_MULTICAST_SIZE) { - /* The Tx ring is full -- don't add anything! Hope the mode will be - * set again later. */ - sp->rx_mode = -1; - return; - } - - if (new_rx_mode != sp->rx_mode) { - u8 *config_cmd_data; - - spin_lock_irqsave(&sp->lock, flags); - entry = sp->cur_tx++ % TX_RING_SIZE; - last_cmd = sp->last_cmd; - sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry]; - - sp->tx_skbuff[entry] = NULL; /* Redundant. */ - sp->tx_ring[entry].status = cpu_to_le32(CmdSuspend | CmdConfigure); - sp->tx_ring[entry].link = - cpu_to_le32(TX_RING_ELEM_DMA(sp, (entry + 1) % TX_RING_SIZE)); - config_cmd_data = (void *)&sp->tx_ring[entry].tx_desc_addr; - /* Construct a full CmdConfig frame. */ - memcpy(config_cmd_data, i82558_config_cmd, CONFIG_DATA_SIZE); - config_cmd_data[1] = (txfifo << 4) | rxfifo; - config_cmd_data[4] = rxdmacount; - config_cmd_data[5] = txdmacount + 0x80; - config_cmd_data[15] |= (new_rx_mode & 2) ? 1 : 0; - /* 0x80 doesn't disable FC 0x84 does. - Disable Flow control since we are not ACK-ing any FC interrupts - for now. --Dragan */ - config_cmd_data[19] = 0x84; - config_cmd_data[19] |= sp->mii_if.full_duplex ? 0x40 : 0; - config_cmd_data[21] = (new_rx_mode & 1) ? 0x0D : 0x05; - if (sp->phy[0] & 0x8000) { /* Use the AUI port instead. */ - config_cmd_data[15] |= 0x80; - config_cmd_data[8] = 0; - } - /* Trigger the command unit resume. */ - wait_for_cmd_done(dev, sp); - clear_suspend(last_cmd); - iowrite8(CUResume, ioaddr + SCBCmd); - if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) { - netif_stop_queue(dev); - sp->tx_full = 1; - } - spin_unlock_irqrestore(&sp->lock, flags); - } - - if (new_rx_mode == 0 && dev->mc_count < 4) { - /* The simple case of 0-3 multicast list entries occurs often, and - fits within one tx_ring[] entry. */ - struct dev_mc_list *mclist; - __le16 *setup_params, *eaddrs; - - spin_lock_irqsave(&sp->lock, flags); - entry = sp->cur_tx++ % TX_RING_SIZE; - last_cmd = sp->last_cmd; - sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry]; - - sp->tx_skbuff[entry] = NULL; - sp->tx_ring[entry].status = cpu_to_le32(CmdSuspend | CmdMulticastList); - sp->tx_ring[entry].link = - cpu_to_le32(TX_RING_ELEM_DMA(sp, (entry + 1) % TX_RING_SIZE)); - sp->tx_ring[entry].tx_desc_addr = 0; /* Really MC list count. */ - setup_params = (__le16 *)&sp->tx_ring[entry].tx_desc_addr; - *setup_params++ = cpu_to_le16(dev->mc_count*6); - /* Fill in the multicast addresses. */ - for (i = 0, mclist = dev->mc_list; i < dev->mc_count; - i++, mclist = mclist->next) { - eaddrs = (__le16 *)mclist->dmi_addr; - *setup_params++ = *eaddrs++; - *setup_params++ = *eaddrs++; - *setup_params++ = *eaddrs++; - } - - wait_for_cmd_done(dev, sp); - clear_suspend(last_cmd); - /* Immediately trigger the command unit resume. */ - iowrite8(CUResume, ioaddr + SCBCmd); - - if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) { - netif_stop_queue(dev); - sp->tx_full = 1; - } - spin_unlock_irqrestore(&sp->lock, flags); - } else if (new_rx_mode == 0) { - struct dev_mc_list *mclist; - __le16 *setup_params, *eaddrs; - struct speedo_mc_block *mc_blk; - struct descriptor *mc_setup_frm; - int i; - - mc_blk = kmalloc(sizeof(*mc_blk) + 2 + multicast_filter_limit*6, - GFP_ATOMIC); - if (mc_blk == NULL) { - printk(KERN_ERR "%s: Failed to allocate a setup frame.\n", - dev->name); - sp->rx_mode = -1; /* We failed, try again. */ - return; - } - mc_blk->next = NULL; - mc_blk->len = 2 + multicast_filter_limit*6; - mc_blk->frame_dma = - pci_map_single(sp->pdev, &mc_blk->frame, mc_blk->len, - PCI_DMA_TODEVICE); - mc_setup_frm = &mc_blk->frame; - - /* Fill the setup frame. */ - if (netif_msg_ifup(sp)) - printk(KERN_DEBUG "%s: Constructing a setup frame at %p.\n", - dev->name, mc_setup_frm); - mc_setup_frm->cmd_status = - cpu_to_le32(CmdSuspend | CmdIntr | CmdMulticastList); - /* Link set below. */ - setup_params = (__le16 *)&mc_setup_frm->params; - *setup_params++ = cpu_to_le16(dev->mc_count*6); - /* Fill in the multicast addresses. */ - for (i = 0, mclist = dev->mc_list; i < dev->mc_count; - i++, mclist = mclist->next) { - eaddrs = (__le16 *)mclist->dmi_addr; - *setup_params++ = *eaddrs++; - *setup_params++ = *eaddrs++; - *setup_params++ = *eaddrs++; - } - - /* Disable interrupts while playing with the Tx Cmd list. */ - spin_lock_irqsave(&sp->lock, flags); - - if (sp->mc_setup_tail) - sp->mc_setup_tail->next = mc_blk; - else - sp->mc_setup_head = mc_blk; - sp->mc_setup_tail = mc_blk; - mc_blk->tx = sp->cur_tx; - - entry = sp->cur_tx++ % TX_RING_SIZE; - last_cmd = sp->last_cmd; - sp->last_cmd = mc_setup_frm; - - /* Change the command to a NoOp, pointing to the CmdMulti command. */ - sp->tx_skbuff[entry] = NULL; - sp->tx_ring[entry].status = cpu_to_le32(CmdNOp); - sp->tx_ring[entry].link = cpu_to_le32(mc_blk->frame_dma); - - /* Set the link in the setup frame. */ - mc_setup_frm->link = - cpu_to_le32(TX_RING_ELEM_DMA(sp, (entry + 1) % TX_RING_SIZE)); - - pci_dma_sync_single_for_device(sp->pdev, mc_blk->frame_dma, - mc_blk->len, PCI_DMA_TODEVICE); - - wait_for_cmd_done(dev, sp); - clear_suspend(last_cmd); - /* Immediately trigger the command unit resume. */ - iowrite8(CUResume, ioaddr + SCBCmd); - - if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) { - netif_stop_queue(dev); - sp->tx_full = 1; - } - spin_unlock_irqrestore(&sp->lock, flags); - - if (netif_msg_rx_status(sp)) - printk(" CmdMCSetup frame length %d in entry %d.\n", - dev->mc_count, entry); - } - - sp->rx_mode = new_rx_mode; -} - -#ifdef CONFIG_PM -static int eepro100_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct net_device *dev = pci_get_drvdata (pdev); - struct speedo_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->regs; - - pci_save_state(pdev); - - if (!netif_running(dev)) - return 0; - - del_timer_sync(&sp->timer); - - netif_device_detach(dev); - iowrite32(PortPartialReset, ioaddr + SCBPort); - - /* XXX call pci_set_power_state ()? */ - pci_disable_device(pdev); - pci_set_power_state (pdev, PCI_D3hot); - return 0; -} - -static int eepro100_resume(struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata (pdev); - struct speedo_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->regs; - int rc; - - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - - rc = pci_enable_device(pdev); - if (rc) - return rc; - - pci_set_master(pdev); - - if (!netif_running(dev)) - return 0; - - /* I'm absolutely uncertain if this part of code may work. - The problems are: - - correct hardware reinitialization; - - correct driver behavior between different steps of the - reinitialization; - - serialization with other driver calls. - 2000/03/08 SAW */ - iowrite16(SCBMaskAll, ioaddr + SCBCmd); - speedo_resume(dev); - netif_device_attach(dev); - sp->rx_mode = -1; - sp->flow_ctrl = sp->partner = 0; - set_rx_mode(dev); - sp->timer.expires = RUN_AT(2*HZ); - add_timer(&sp->timer); - return 0; -} -#endif /* CONFIG_PM */ - -static void __devexit eepro100_remove_one (struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata (pdev); - struct speedo_private *sp = netdev_priv(dev); - - unregister_netdev(dev); - - release_region(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1)); - release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); - - pci_iounmap(pdev, sp->regs); - pci_free_consistent(pdev, TX_RING_SIZE * sizeof(struct TxFD) - + sizeof(struct speedo_stats), - sp->tx_ring, sp->tx_ring_dma); - pci_disable_device(pdev); - free_netdev(dev); -} - -static struct pci_device_id eepro100_pci_tbl[] = { - { PCI_VENDOR_ID_INTEL, 0x1229, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1209, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1029, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1030, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1031, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1032, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1033, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1034, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1035, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1036, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1037, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1038, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1039, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x103A, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x103B, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x103C, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x103D, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x103E, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1050, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1059, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1227, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x2449, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x2459, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x245D, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x5200, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x5201, PCI_ANY_ID, PCI_ANY_ID, }, - { 0,} -}; -MODULE_DEVICE_TABLE(pci, eepro100_pci_tbl); - -static struct pci_driver eepro100_driver = { - .name = "eepro100", - .id_table = eepro100_pci_tbl, - .probe = eepro100_init_one, - .remove = __devexit_p(eepro100_remove_one), -#ifdef CONFIG_PM - .suspend = eepro100_suspend, - .resume = eepro100_resume, -#endif /* CONFIG_PM */ -}; - -static int __init eepro100_init_module(void) -{ -#ifdef MODULE - printk(version); -#endif - return pci_register_driver(&eepro100_driver); -} - -static void __exit eepro100_cleanup_module(void) -{ - pci_unregister_driver(&eepro100_driver); -} - -module_init(eepro100_init_module); -module_exit(eepro100_cleanup_module); - -/* - * Local variables: - * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" - * c-indent-level: 4 - * c-basic-offset: 4 - * tab-width: 4 - * End: - */ diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c index b751c1b96cfa77e2d445e3c182a4d2003cb8de73..9ff3f2f5e3829a431b1bb6f010fa172ff005374d 100644 --- a/drivers/net/eexpress.c +++ b/drivers/net/eexpress.c @@ -967,7 +967,6 @@ static void eexp_hw_rx_pio(struct net_device *dev) insw(ioaddr+DATAPORT, skb_put(skb,pkt_len),(pkt_len+1)>>1); skb->protocol = eth_type_trans(skb,dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } @@ -1047,7 +1046,7 @@ static void eexp_hw_tx_pio(struct net_device *dev, unsigned short *buf, /* * Sanity check the suspected EtherExpress card * Read hardware address, reset card, size memory and initialize buffer - * memory pointers. These are held in dev->priv, in case someone has more + * memory pointers. These are held in netdev_priv(), in case someone has more * than one card in a machine. */ diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h index 002d918fb4c742fc4a66af17a1d427e19959cbe0..9930d5f8b9e11b199459e69936c64a6900ffe4cb 100644 --- a/drivers/net/ehea/ehea.h +++ b/drivers/net/ehea/ehea.h @@ -40,7 +40,7 @@ #include #define DRV_NAME "ehea" -#define DRV_VERSION "EHEA_0095" +#define DRV_VERSION "EHEA_0096" /* eHEA capability flags */ #define DLPAR_PORT_ADD_REM 1 diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 422fcb93e2c381b2b80d365244084559184dbc2f..a2f1905a23dfdc2d581b8751f631515bf326a448 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -728,7 +728,6 @@ static int ehea_proc_rwqes(struct net_device *dev, } ehea_proc_skb(pr, cqe, skb); - dev->last_rx = jiffies; } else { pr->p_stats.poll_receive_errors++; port_reset = ehea_treat_poll_error(pr, rq, cqe, @@ -831,7 +830,7 @@ static int ehea_poll(struct napi_struct *napi, int budget) while ((rx != budget) || force_irq) { pr->poll_counter = 0; force_irq = 0; - netif_rx_complete(dev, napi); + netif_rx_complete(napi); ehea_reset_cq_ep(pr->recv_cq); ehea_reset_cq_ep(pr->send_cq); ehea_reset_cq_n1(pr->recv_cq); @@ -842,7 +841,7 @@ static int ehea_poll(struct napi_struct *napi, int budget) if (!cqe && !cqe_skb) return rx; - if (!netif_rx_reschedule(dev, napi)) + if (!netif_rx_reschedule(napi)) return rx; cqe_skb = ehea_proc_cqes(pr, EHEA_POLL_MAX_CQES); @@ -860,7 +859,7 @@ static void ehea_netpoll(struct net_device *dev) int i; for (i = 0; i < port->num_def_qps; i++) - netif_rx_schedule(dev, &port->port_res[i].napi); + netif_rx_schedule(&port->port_res[i].napi); } #endif @@ -868,7 +867,7 @@ static irqreturn_t ehea_recv_irq_handler(int irq, void *param) { struct ehea_port_res *pr = param; - netif_rx_schedule(pr->port->netdev, &pr->napi); + netif_rx_schedule(&pr->napi); return IRQ_HANDLED; } diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c index 9d006878f0459db1dfe30c079639638ae2025fcf..225c692b5d9928997dac0fc3f6bb41175bbca8e4 100644 --- a/drivers/net/ehea/ehea_qmr.c +++ b/drivers/net/ehea/ehea_qmr.c @@ -182,7 +182,7 @@ struct ehea_cq *ehea_create_cq(struct ehea_adapter *adapter, goto out_kill_hwq; } } else { - if ((hret != H_PAGE_REGISTERED) || (!vpage)) { + if (hret != H_PAGE_REGISTERED) { ehea_error("CQ: registration of page failed " "hret=%lx\n", hret); goto out_kill_hwq; @@ -303,7 +303,7 @@ struct ehea_eq *ehea_create_eq(struct ehea_adapter *adapter, goto out_kill_hwq; } else { - if ((hret != H_PAGE_REGISTERED) || (!vpage)) + if (hret != H_PAGE_REGISTERED) goto out_kill_hwq; } @@ -653,7 +653,7 @@ static int ehea_update_busmap(unsigned long pfn, unsigned long nr_pages, int add int top = ehea_calc_index(i, EHEA_TOP_INDEX_SHIFT); int dir = ehea_calc_index(i, EHEA_DIR_INDEX_SHIFT); int idx = i & EHEA_INDEX_MASK; - + if (add) { int ret = ehea_init_bmap(ehea_bmap, top, dir); if (ret) @@ -780,7 +780,7 @@ void ehea_destroy_busmap(void) kfree(ehea_bmap); ehea_bmap = NULL; -out_destroy: +out_destroy: mutex_unlock(&ehea_busmap_mutex); } @@ -858,10 +858,10 @@ static u64 ehea_reg_mr_sections(int top, int dir, u64 *pt, for (idx = 0; idx < EHEA_MAP_ENTRIES; idx++) { if (!ehea_bmap->top[top]->dir[dir]->ent[idx]) continue; - + hret = ehea_reg_mr_section(top, dir, idx, pt, adapter, mr); if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED)) - return hret; + return hret; } return hret; } @@ -879,7 +879,7 @@ static u64 ehea_reg_mr_dir_sections(int top, u64 *pt, hret = ehea_reg_mr_sections(top, dir, pt, adapter, mr); if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED)) - return hret; + return hret; } return hret; } @@ -893,7 +893,7 @@ int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr) unsigned long top; - pt = kzalloc(PAGE_SIZE, GFP_KERNEL); + pt = (void *)get_zeroed_page(GFP_KERNEL); if (!pt) { ehea_error("no mem"); ret = -ENOMEM; @@ -937,7 +937,7 @@ int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr) mr->adapter = adapter; ret = 0; out: - kfree(pt); + free_page((unsigned long)pt); return ret; } diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c index 36cb6e95b465c2545b822d30c14a675b6bd39e07..b0ef46c51a9d556069c38ed97d0cdf3086555d6f 100644 --- a/drivers/net/enc28j60.c +++ b/drivers/net/enc28j60.c @@ -196,16 +196,32 @@ static void enc28j60_soft_reset(struct enc28j60_net *priv) */ static void enc28j60_set_bank(struct enc28j60_net *priv, u8 addr) { - if ((addr & BANK_MASK) != priv->bank) { - u8 b = (addr & BANK_MASK) >> 5; + u8 b = (addr & BANK_MASK) >> 5; - if (b != (ECON1_BSEL1 | ECON1_BSEL0)) + /* These registers (EIE, EIR, ESTAT, ECON2, ECON1) + * are present in all banks, no need to switch bank + */ + if (addr >= EIE && addr <= ECON1) + return; + + /* Clear or set each bank selection bit as needed */ + if ((b & ECON1_BSEL0) != (priv->bank & ECON1_BSEL0)) { + if (b & ECON1_BSEL0) + spi_write_op(priv, ENC28J60_BIT_FIELD_SET, ECON1, + ECON1_BSEL0); + else spi_write_op(priv, ENC28J60_BIT_FIELD_CLR, ECON1, - ECON1_BSEL1 | ECON1_BSEL0); - if (b != 0) - spi_write_op(priv, ENC28J60_BIT_FIELD_SET, ECON1, b); - priv->bank = (addr & BANK_MASK); + ECON1_BSEL0); } + if ((b & ECON1_BSEL1) != (priv->bank & ECON1_BSEL1)) { + if (b & ECON1_BSEL1) + spi_write_op(priv, ENC28J60_BIT_FIELD_SET, ECON1, + ECON1_BSEL1); + else + spi_write_op(priv, ENC28J60_BIT_FIELD_CLR, ECON1, + ECON1_BSEL1); + } + priv->bank = b; } /* @@ -477,12 +493,10 @@ static int enc28j60_set_hw_macaddr(struct net_device *ndev) mutex_lock(&priv->lock); if (!priv->hw_enable) { - if (netif_msg_drv(priv)) { - DECLARE_MAC_BUF(mac); + if (netif_msg_drv(priv)) printk(KERN_INFO DRV_NAME - ": %s: Setting MAC address to %s\n", - ndev->name, print_mac(mac, ndev->dev_addr)); - } + ": %s: Setting MAC address to %pM\n", + ndev->name, ndev->dev_addr); /* NOTE: MAC address in ENC28J60 is byte-backward */ nolock_regb_write(priv, MAADR5, ndev->dev_addr[0]); nolock_regb_write(priv, MAADR4, ndev->dev_addr[1]); @@ -958,7 +972,6 @@ static void enc28j60_hw_rx(struct net_device *ndev) /* update statistics */ ndev->stats.rx_packets++; ndev->stats.rx_bytes += len; - ndev->last_rx = jiffies; netif_rx_ni(skb); } } @@ -1340,11 +1353,9 @@ static int enc28j60_net_open(struct net_device *dev) printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __func__); if (!is_valid_ether_addr(dev->dev_addr)) { - if (netif_msg_ifup(priv)) { - DECLARE_MAC_BUF(mac); - dev_err(&dev->dev, "invalid MAC address %s\n", - print_mac(mac, dev->dev_addr)); - } + if (netif_msg_ifup(priv)) + dev_err(&dev->dev, "invalid MAC address %pM\n", + dev->dev_addr); return -EADDRNOTAVAIL; } /* Reset the hardware here (and take it out of low power mode) */ @@ -1465,7 +1476,7 @@ enc28j60_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); strlcpy(info->version, DRV_VERSION, sizeof(info->version)); strlcpy(info->bus_info, - dev->dev.parent->bus_id, sizeof(info->bus_info)); + dev_name(dev->dev.parent), sizeof(info->bus_info)); } static int diff --git a/drivers/net/enic/cq_desc.h b/drivers/net/enic/cq_desc.h index c036a8bfd04343559fb23f3b22f99c53e63d0ad0..1eb289f773bf1b32880908d8199da790423ea13d 100644 --- a/drivers/net/enic/cq_desc.h +++ b/drivers/net/enic/cq_desc.h @@ -44,9 +44,10 @@ struct cq_desc { u8 type_color; }; -#define CQ_DESC_TYPE_BITS 7 +#define CQ_DESC_TYPE_BITS 4 #define CQ_DESC_TYPE_MASK ((1 << CQ_DESC_TYPE_BITS) - 1) #define CQ_DESC_COLOR_MASK 1 +#define CQ_DESC_COLOR_SHIFT 7 #define CQ_DESC_Q_NUM_BITS 10 #define CQ_DESC_Q_NUM_MASK ((1 << CQ_DESC_Q_NUM_BITS) - 1) #define CQ_DESC_COMP_NDX_BITS 12 @@ -58,7 +59,7 @@ static inline void cq_desc_dec(const struct cq_desc *desc_arg, const struct cq_desc *desc = desc_arg; const u8 type_color = desc->type_color; - *color = (type_color >> CQ_DESC_TYPE_BITS) & CQ_DESC_COLOR_MASK; + *color = (type_color >> CQ_DESC_COLOR_SHIFT) & CQ_DESC_COLOR_MASK; /* * Make sure color bit is read from desc *before* other fields diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h index 7f677e89a78875311c5b7a51b09ec14349079770..a832cc5d6a1e3c9061b290f393adeaa897504508 100644 --- a/drivers/net/enic/enic.h +++ b/drivers/net/enic/enic.h @@ -33,7 +33,7 @@ #define DRV_NAME "enic" #define DRV_DESCRIPTION "Cisco 10G Ethernet Driver" -#define DRV_VERSION "0.0.1-18163.472-k1" +#define DRV_VERSION "1.0.0.648" #define DRV_COPYRIGHT "Copyright 2008 Cisco Systems, Inc" #define PFX DRV_NAME ": " diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 180e968dc54d87401eaa174c30a724223425d4bf..d039e16f276355a1552e4b6be6a7aecdf1bd0b66 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -273,6 +273,8 @@ static struct ethtool_ops enic_ethtool_ops = { .set_sg = ethtool_op_set_sg, .get_tso = ethtool_op_get_tso, .set_tso = enic_set_tso, + .get_flags = ethtool_op_get_flags, + .set_flags = ethtool_op_set_flags, }; static void enic_free_wq_buf(struct vnic_wq *wq, struct vnic_wq_buf *buf) @@ -409,8 +411,8 @@ static irqreturn_t enic_isr_legacy(int irq, void *data) } if (ENIC_TEST_INTR(pba, ENIC_INTX_WQ_RQ)) { - if (netif_rx_schedule_prep(netdev, &enic->napi)) - __netif_rx_schedule(netdev, &enic->napi); + if (netif_rx_schedule_prep(&enic->napi)) + __netif_rx_schedule(&enic->napi); } else { vnic_intr_unmask(&enic->intr[ENIC_INTX_WQ_RQ]); } @@ -438,7 +440,7 @@ static irqreturn_t enic_isr_msi(int irq, void *data) * writes). */ - netif_rx_schedule(enic->netdev, &enic->napi); + netif_rx_schedule(&enic->napi); return IRQ_HANDLED; } @@ -448,7 +450,7 @@ static irqreturn_t enic_isr_msix_rq(int irq, void *data) struct enic *enic = data; /* schedule NAPI polling for RQ cleanup */ - netif_rx_schedule(enic->netdev, &enic->napi); + netif_rx_schedule(&enic->napi); return IRQ_HANDLED; } @@ -895,6 +897,7 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq, int skipped, void *opaque) { struct enic *enic = vnic_dev_priv(rq->vdev); + struct net_device *netdev = enic->netdev; struct sk_buff *skb; u8 type, color, eop, sop, ingress_port, vlan_stripped; @@ -929,7 +932,7 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq, if (net_ratelimit()) printk(KERN_ERR PFX "%s: packet error: bad FCS\n", - enic->netdev->name); + netdev->name); } dev_kfree_skb_any(skb); @@ -943,19 +946,18 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq, */ skb_put(skb, bytes_written); - skb->protocol = eth_type_trans(skb, enic->netdev); + skb->protocol = eth_type_trans(skb, netdev); if (enic->csum_rx_enabled && !csum_not_calc) { skb->csum = htons(checksum); skb->ip_summed = CHECKSUM_COMPLETE; } - skb->dev = enic->netdev; - enic->netdev->last_rx = jiffies; + skb->dev = netdev; if (enic->vlan_group && vlan_stripped) { - if (ENIC_SETTING(enic, LRO) && ipv4) + if ((netdev->features & NETIF_F_LRO) && ipv4) lro_vlan_hwaccel_receive_skb(&enic->lro_mgr, skb, enic->vlan_group, vlan, cq_desc); @@ -965,7 +967,7 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq, } else { - if (ENIC_SETTING(enic, LRO) && ipv4) + if ((netdev->features & NETIF_F_LRO) && ipv4) lro_receive_skb(&enic->lro_mgr, skb, cq_desc); else netif_receive_skb(skb); @@ -1063,10 +1065,10 @@ static int enic_poll(struct napi_struct *napi, int budget) /* If no work done, flush all LROs and exit polling */ - if (ENIC_SETTING(enic, LRO)) + if (netdev->features & NETIF_F_LRO) lro_flush_all(&enic->lro_mgr); - netif_rx_complete(netdev, napi); + netif_rx_complete(napi); vnic_intr_unmask(&enic->intr[ENIC_MSIX_RQ]); } @@ -1107,10 +1109,10 @@ static int enic_poll_msix(struct napi_struct *napi, int budget) /* If no work done, flush all LROs and exit polling */ - if (ENIC_SETTING(enic, LRO)) + if (netdev->features & NETIF_F_LRO) lro_flush_all(&enic->lro_mgr); - netif_rx_complete(netdev, napi); + netif_rx_complete(napi); vnic_intr_unmask(&enic->intr[ENIC_MSIX_RQ]); } @@ -1591,6 +1593,23 @@ static void enic_iounmap(struct enic *enic) iounmap(enic->bar0.vaddr); } +static const struct net_device_ops enic_netdev_ops = { + .ndo_open = enic_open, + .ndo_stop = enic_stop, + .ndo_start_xmit = enic_hard_start_xmit, + .ndo_get_stats = enic_get_stats, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = enic_set_multicast_list, + .ndo_change_mtu = enic_change_mtu, + .ndo_vlan_rx_register = enic_vlan_rx_register, + .ndo_vlan_rx_add_vid = enic_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = enic_vlan_rx_kill_vid, + .ndo_tx_timeout = enic_tx_timeout, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = enic_poll_controller, +#endif +}; + static int __devinit enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -1746,13 +1765,13 @@ static int __devinit enic_probe(struct pci_dev *pdev, } /* Get available resource counts - */ + */ enic_get_res_counts(enic); /* Set interrupt mode based on resource counts and system * capabilities - */ + */ err = enic_set_intr_mode(enic); if (err) { @@ -1814,21 +1833,9 @@ static int __devinit enic_probe(struct pci_dev *pdev, goto err_out_free_vnic_resources; } - netdev->open = enic_open; - netdev->stop = enic_stop; - netdev->hard_start_xmit = enic_hard_start_xmit; - netdev->get_stats = enic_get_stats; - netdev->set_multicast_list = enic_set_multicast_list; - netdev->change_mtu = enic_change_mtu; - netdev->vlan_rx_register = enic_vlan_rx_register; - netdev->vlan_rx_add_vid = enic_vlan_rx_add_vid; - netdev->vlan_rx_kill_vid = enic_vlan_rx_kill_vid; - netdev->tx_timeout = enic_tx_timeout; + netdev->netdev_ops = &enic_netdev_ops; netdev->watchdog_timeo = 2 * HZ; netdev->ethtool_ops = &enic_ethtool_ops; -#ifdef CONFIG_NET_POLL_CONTROLLER - netdev->poll_controller = enic_poll_controller; -#endif switch (vnic_dev_get_intr_mode(enic->vdev)) { default: @@ -1845,22 +1852,23 @@ static int __devinit enic_probe(struct pci_dev *pdev, if (ENIC_SETTING(enic, TSO)) netdev->features |= NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN; + if (ENIC_SETTING(enic, LRO)) + netdev->features |= NETIF_F_LRO; if (using_dac) netdev->features |= NETIF_F_HIGHDMA; enic->csum_rx_enabled = ENIC_SETTING(enic, RXCSUM); - if (ENIC_SETTING(enic, LRO)) { - enic->lro_mgr.max_aggr = ENIC_LRO_MAX_AGGR; - enic->lro_mgr.max_desc = ENIC_LRO_MAX_DESC; - enic->lro_mgr.lro_arr = enic->lro_desc; - enic->lro_mgr.get_skb_header = enic_get_skb_header; - enic->lro_mgr.features = LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID; - enic->lro_mgr.dev = netdev; - enic->lro_mgr.ip_summed = CHECKSUM_COMPLETE; - enic->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY; - } + enic->lro_mgr.max_aggr = ENIC_LRO_MAX_AGGR; + enic->lro_mgr.max_desc = ENIC_LRO_MAX_DESC; + enic->lro_mgr.lro_arr = enic->lro_desc; + enic->lro_mgr.get_skb_header = enic_get_skb_header; + enic->lro_mgr.features = LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID; + enic->lro_mgr.dev = netdev; + enic->lro_mgr.ip_summed = CHECKSUM_COMPLETE; + enic->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY; + err = register_netdev(netdev); if (err) { diff --git a/drivers/net/enic/enic_res.c b/drivers/net/enic/enic_res.c index 95184b9108ef18fec0bbffda0518c4b9754c64c8..e5fc9384f8f51891eefe153fdab71ca7fa7b98c7 100644 --- a/drivers/net/enic/enic_res.c +++ b/drivers/net/enic/enic_res.c @@ -90,11 +90,8 @@ int enic_get_vnic_config(struct enic *enic) c->intr_timer = min_t(u16, VNIC_INTR_TIMER_MAX, c->intr_timer); - printk(KERN_INFO PFX "vNIC MAC addr %02x:%02x:%02x:%02x:%02x:%02x " - "wq/rq %d/%d\n", - enic->mac_addr[0], enic->mac_addr[1], enic->mac_addr[2], - enic->mac_addr[3], enic->mac_addr[4], enic->mac_addr[5], - c->wq_desc_count, c->rq_desc_count); + printk(KERN_INFO PFX "vNIC MAC addr %pM wq/rq %d/%d\n", + enic->mac_addr, c->wq_desc_count, c->rq_desc_count); printk(KERN_INFO PFX "vNIC mtu %d csum tx/rx %d/%d tso/lro %d/%d " "intr timer %d\n", c->mtu, ENIC_SETTING(enic, TXCSUM), diff --git a/drivers/net/enic/enic_res.h b/drivers/net/enic/enic_res.h index 68534a29b7ace04487be5e1608d24f8619771ac0..7bf272fa859b32ea530911573ce8450c8e7fc607 100644 --- a/drivers/net/enic/enic_res.h +++ b/drivers/net/enic/enic_res.h @@ -58,8 +58,6 @@ static inline void enic_queue_wq_desc_ex(struct vnic_wq *wq, (u16)vlan_tag, 0 /* loopback */); - wmb(); - vnic_wq_post(wq, os_buf, dma_addr, len, sop, eop); } @@ -127,8 +125,6 @@ static inline void enic_queue_rq_desc(struct vnic_rq *rq, (u64)dma_addr | VNIC_PADDR_TARGET, type, (u16)len); - wmb(); - vnic_rq_post(rq, os_buf, os_buf_index, dma_addr, len); } diff --git a/drivers/net/enic/vnic_dev.c b/drivers/net/enic/vnic_dev.c index 4d104f5c30f97b454880dfaefb147c12656de09a..11708579b6ce7c5bfd8143234bea6c1122cb1748 100644 --- a/drivers/net/enic/vnic_dev.c +++ b/drivers/net/enic/vnic_dev.c @@ -43,6 +43,7 @@ struct vnic_dev { struct vnic_devcmd_notify *notify; struct vnic_devcmd_notify notify_copy; dma_addr_t notify_pa; + u32 notify_sz; u32 *linkstatus; dma_addr_t linkstatus_pa; struct vnic_stats *stats; @@ -235,14 +236,6 @@ int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, struct vnic_devcmd __iomem *devcmd = vdev->devcmd; int delay; u32 status; - int dev_cmd_err[] = { - /* convert from fw's version of error.h to host's version */ - 0, /* ERR_SUCCESS */ - EINVAL, /* ERR_EINVAL */ - EFAULT, /* ERR_EFAULT */ - EPERM, /* ERR_EPERM */ - EBUSY, /* ERR_EBUSY */ - }; int err; status = ioread32(&devcmd->status); @@ -270,10 +263,12 @@ int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, if (!(status & STAT_BUSY)) { if (status & STAT_ERROR) { - err = dev_cmd_err[(int)readq(&devcmd->args[0])]; - printk(KERN_ERR "Error %d devcmd %d\n", - err, _CMD_N(cmd)); - return -err; + err = (int)readq(&devcmd->args[0]); + if (err != ERR_ECMDUNKNOWN || + cmd != CMD_CAPABILITY) + printk(KERN_ERR "Error %d devcmd %d\n", + err, _CMD_N(cmd)); + return err; } if (_CMD_DIR(cmd) & _CMD_DIR_READ) { @@ -290,6 +285,17 @@ int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, return -ETIMEDOUT; } +static int vnic_dev_capable(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd) +{ + u64 a0 = (u32)cmd, a1 = 0; + int wait = 1000; + int err; + + err = vnic_dev_cmd(vdev, CMD_CAPABILITY, &a0, &a1, wait); + + return !(err || a0); +} + int vnic_dev_fw_info(struct vnic_dev *vdev, struct vnic_devcmd_fw_info **fw_info) { @@ -489,10 +495,7 @@ void vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr) err = vnic_dev_cmd(vdev, CMD_ADDR_ADD, &a0, &a1, wait); if (err) - printk(KERN_ERR - "Can't add addr [%02x:%02x:%02x:%02x:%02x:%02x], %d\n", - addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], - err); + printk(KERN_ERR "Can't add addr [%pM], %d\n", addr, err); } void vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr) @@ -507,16 +510,14 @@ void vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr) err = vnic_dev_cmd(vdev, CMD_ADDR_DEL, &a0, &a1, wait); if (err) - printk(KERN_ERR - "Can't del addr [%02x:%02x:%02x:%02x:%02x:%02x], %d\n", - addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], - err); + printk(KERN_ERR "Can't del addr [%pM], %d\n", addr, err); } int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr) { u64 a0, a1; int wait = 1000; + int r; if (!vdev->notify) { vdev->notify = pci_alloc_consistent(vdev->pdev, @@ -524,13 +525,16 @@ int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr) &vdev->notify_pa); if (!vdev->notify) return -ENOMEM; + memset(vdev->notify, 0, sizeof(struct vnic_devcmd_notify)); } a0 = vdev->notify_pa; a1 = ((u64)intr << 32) & 0x0000ffff00000000ULL; a1 += sizeof(struct vnic_devcmd_notify); - return vnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait); + r = vnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait); + vdev->notify_sz = (r == 0) ? (u32)a1 : 0; + return r; } void vnic_dev_notify_unset(struct vnic_dev *vdev) @@ -543,22 +547,22 @@ void vnic_dev_notify_unset(struct vnic_dev *vdev) a1 += sizeof(struct vnic_devcmd_notify); vnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait); + vdev->notify_sz = 0; } static int vnic_dev_notify_ready(struct vnic_dev *vdev) { u32 *words; - unsigned int nwords = sizeof(struct vnic_devcmd_notify) / 4; + unsigned int nwords = vdev->notify_sz / 4; unsigned int i; u32 csum; - if (!vdev->notify) + if (!vdev->notify || !vdev->notify_sz) return 0; do { csum = 0; - memcpy(&vdev->notify_copy, vdev->notify, - sizeof(struct vnic_devcmd_notify)); + memcpy(&vdev->notify_copy, vdev->notify, vdev->notify_sz); words = (u32 *)&vdev->notify_copy; for (i = 1; i < nwords; i++) csum += words[i]; @@ -571,7 +575,20 @@ int vnic_dev_init(struct vnic_dev *vdev, int arg) { u64 a0 = (u32)arg, a1 = 0; int wait = 1000; - return vnic_dev_cmd(vdev, CMD_INIT, &a0, &a1, wait); + int r = 0; + + if (vnic_dev_capable(vdev, CMD_INIT)) + r = vnic_dev_cmd(vdev, CMD_INIT, &a0, &a1, wait); + else { + vnic_dev_cmd(vdev, CMD_INIT_v1, &a0, &a1, wait); + if (a0 & CMD_INITF_DEFAULT_MAC) { + // Emulate these for old CMD_INIT_v1 which + // didn't pass a0 so no CMD_INITF_*. + vnic_dev_cmd(vdev, CMD_MAC_ADDR, &a0, &a1, wait); + vnic_dev_cmd(vdev, CMD_ADDR_ADD, &a0, &a1, wait); + } + } + return r; } int vnic_dev_link_status(struct vnic_dev *vdev) @@ -672,3 +689,4 @@ struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev, return NULL; } + diff --git a/drivers/net/enic/vnic_devcmd.h b/drivers/net/enic/vnic_devcmd.h index d8617a3373b14aa1c4b952204607df4344888b79..8062c75154e60d83098aa61293ec338931b7614f 100644 --- a/drivers/net/enic/vnic_devcmd.h +++ b/drivers/net/enic/vnic_devcmd.h @@ -168,7 +168,8 @@ enum vnic_devcmd_cmd { CMD_CLOSE = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 25), /* initialize virtual link: (u32)a0=flags (see CMD_INITF_*) */ - CMD_INIT = _CMDCNW(_CMD_DIR_READ, _CMD_VTYPE_ALL, 26), +/***** Replaced by CMD_INIT *****/ + CMD_INIT_v1 = _CMDCNW(_CMD_DIR_READ, _CMD_VTYPE_ALL, 26), /* variant of CMD_INIT, with provisioning info * (u64)a0=paddr of vnic_devcmd_provinfo @@ -198,6 +199,14 @@ enum vnic_devcmd_cmd { /* undo initialize of virtual link */ CMD_DEINIT = _CMDCNW(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 34), + + /* initialize virtual link: (u32)a0=flags (see CMD_INITF_*) */ + CMD_INIT = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 35), + + /* check fw capability of a cmd: + * in: (u32)a0=cmd + * out: (u32)a0=errno, 0:valid cmd, a1=supported VNIC_STF_* bits */ + CMD_CAPABILITY = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 36), }; /* flags for CMD_OPEN */ @@ -249,8 +258,16 @@ struct vnic_devcmd_notify { u32 uif; /* uplink interface */ u32 status; /* status bits (see VNIC_STF_*) */ u32 error; /* error code (see ERR_*) for first ERR */ + u32 link_down_cnt; /* running count of link down transitions */ }; #define VNIC_STF_FATAL_ERR 0x0001 /* fatal fw error */ +#define VNIC_STF_STD_PAUSE 0x0002 /* standard link-level pause on */ +#define VNIC_STF_PFC_PAUSE 0x0004 /* priority flow control pause on */ +/* all supported status flags */ +#define VNIC_STF_ALL (VNIC_STF_FATAL_ERR |\ + VNIC_STF_STD_PAUSE |\ + VNIC_STF_PFC_PAUSE |\ + 0) struct vnic_devcmd_provinfo { u8 oui[3]; diff --git a/drivers/net/enic/vnic_intr.h b/drivers/net/enic/vnic_intr.h index ccc408116af89b07bd1bf500b2a7d124746059e0..ce633a5a7e3c4d7924c43858942fc833257ef50b 100644 --- a/drivers/net/enic/vnic_intr.h +++ b/drivers/net/enic/vnic_intr.h @@ -78,7 +78,7 @@ static inline void vnic_intr_return_credits(struct vnic_intr *intr, static inline u32 vnic_intr_legacy_pba(u32 __iomem *legacy_pba) { - /* get and ack interrupt in one read (clear-and-ack-on-read) */ + /* read PBA without clearing */ return ioread32(legacy_pba); } diff --git a/drivers/net/enic/vnic_resource.h b/drivers/net/enic/vnic_resource.h index 144d2812f081082a2b9d294992d97b1053e14849..b61c22aec41a65968c887fa800b7062bf59dd254 100644 --- a/drivers/net/enic/vnic_resource.h +++ b/drivers/net/enic/vnic_resource.h @@ -38,7 +38,7 @@ enum vnic_res_type { RES_TYPE_INTR_CTRL, /* Interrupt ctrl table */ RES_TYPE_INTR_TABLE, /* MSI/MSI-X Interrupt table */ RES_TYPE_INTR_PBA, /* MSI/MSI-X PBA table */ - RES_TYPE_INTR_PBA_LEGACY, /* Legacy intr status, r2c */ + RES_TYPE_INTR_PBA_LEGACY, /* Legacy intr status */ RES_TYPE_RSVD6, RES_TYPE_RSVD7, RES_TYPE_DEVCMD, /* Device command region */ diff --git a/drivers/net/enic/vnic_rq.h b/drivers/net/enic/vnic_rq.h index 82bfca67cc4d18cac256fa61d01fe90b013f5d1b..fd0ef66d2e9f5cfb66d1fe9e0f15858b8da056c6 100644 --- a/drivers/net/enic/vnic_rq.h +++ b/drivers/net/enic/vnic_rq.h @@ -132,8 +132,15 @@ static inline void vnic_rq_post(struct vnic_rq *rq, #define VNIC_RQ_RETURN_RATE 0xf /* keep 2^n - 1 */ #endif - if ((buf->index & VNIC_RQ_RETURN_RATE) == 0) + if ((buf->index & VNIC_RQ_RETURN_RATE) == 0) { + /* Adding write memory barrier prevents compiler and/or CPU + * reordering, thus avoiding descriptor posting before + * descriptor is initialized. Otherwise, hardware can read + * stale descriptor fields. + */ + wmb(); iowrite32(buf->index, &rq->ctrl->posted_index); + } } static inline void vnic_rq_return_descs(struct vnic_rq *rq, unsigned int count) diff --git a/drivers/net/enic/vnic_rss.h b/drivers/net/enic/vnic_rss.h index e325d65d7c34b4d70684b6f5cccb10ef97c06241..5fbb3c923bcd6a0610bacda69cdc7694d4b507b4 100644 --- a/drivers/net/enic/vnic_rss.h +++ b/drivers/net/enic/vnic_rss.h @@ -1,6 +1,19 @@ /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _VNIC_RSS_H_ diff --git a/drivers/net/enic/vnic_wq.h b/drivers/net/enic/vnic_wq.h index 7081828d8a42bd98a8ed7bdacf1cc1254da63b9f..c826137dc6517c2d9d5c5bcef23c45b063659f37 100644 --- a/drivers/net/enic/vnic_wq.h +++ b/drivers/net/enic/vnic_wq.h @@ -108,8 +108,15 @@ static inline void vnic_wq_post(struct vnic_wq *wq, buf->len = len; buf = buf->next; - if (eop) + if (eop) { + /* Adding write memory barrier prevents compiler and/or CPU + * reordering, thus avoiding descriptor posting before + * descriptor is initialized. Otherwise, hardware can read + * stale descriptor fields. + */ + wmb(); iowrite32(buf->index, &wq->ctrl->posted_index); + } wq->to_use = buf; wq->ring.desc_avail--; diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index 76118ddd104272f82f194746739ceacbb102c017..f9b37c80dda61f7eb84ca32a26dc93789d57c678 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -322,7 +322,6 @@ static int __devinit epic_init_one (struct pci_dev *pdev, int i, ret, option = 0, duplex = 0; void *ring_space; dma_addr_t ring_dma; - DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -364,7 +363,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev, ioaddr = pci_resource_start (pdev, 0); #else ioaddr = pci_resource_start (pdev, 1); - ioaddr = (long) ioremap (ioaddr, pci_resource_len (pdev, 1)); + ioaddr = (long) pci_ioremap_bar(pdev, 1); if (!ioaddr) { dev_err(&pdev->dev, "ioremap failed\n"); goto err_out_free_netdev; @@ -372,7 +371,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev, #endif pci_set_drvdata(pdev, dev); - ep = dev->priv; + ep = netdev_priv(dev); ep->mii.dev = dev; ep->mii.mdio_read = mdio_read; ep->mii.mdio_write = mdio_write; @@ -499,9 +498,9 @@ static int __devinit epic_init_one (struct pci_dev *pdev, if (ret < 0) goto err_out_unmap_rx; - printk(KERN_INFO "%s: %s at %#lx, IRQ %d, %s\n", + printk(KERN_INFO "%s: %s at %#lx, IRQ %d, %pM\n", dev->name, pci_id_tbl[chip_idx].name, ioaddr, dev->irq, - print_mac(mac, dev->dev_addr)); + dev->dev_addr); out: return ret; @@ -655,7 +654,7 @@ static void mdio_write(struct net_device *dev, int phy_id, int loc, int value) static int epic_open(struct net_device *dev) { - struct epic_private *ep = dev->priv; + struct epic_private *ep = netdev_priv(dev); long ioaddr = dev->base_addr; int i; int retval; @@ -767,7 +766,7 @@ static int epic_open(struct net_device *dev) static void epic_pause(struct net_device *dev) { long ioaddr = dev->base_addr; - struct epic_private *ep = dev->priv; + struct epic_private *ep = netdev_priv(dev); netif_stop_queue (dev); @@ -790,7 +789,7 @@ static void epic_pause(struct net_device *dev) static void epic_restart(struct net_device *dev) { long ioaddr = dev->base_addr; - struct epic_private *ep = dev->priv; + struct epic_private *ep = netdev_priv(dev); int i; /* Soft reset the chip. */ @@ -842,7 +841,7 @@ static void epic_restart(struct net_device *dev) static void check_media(struct net_device *dev) { - struct epic_private *ep = dev->priv; + struct epic_private *ep = netdev_priv(dev); long ioaddr = dev->base_addr; int mii_lpa = ep->mii_phy_cnt ? mdio_read(dev, ep->phys[0], MII_LPA) : 0; int negotiated = mii_lpa & ep->mii.advertising; @@ -864,7 +863,7 @@ static void check_media(struct net_device *dev) static void epic_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct epic_private *ep = dev->priv; + struct epic_private *ep = netdev_priv(dev); long ioaddr = dev->base_addr; int next_tick = 5*HZ; @@ -885,7 +884,7 @@ static void epic_timer(unsigned long data) static void epic_tx_timeout(struct net_device *dev) { - struct epic_private *ep = dev->priv; + struct epic_private *ep = netdev_priv(dev); long ioaddr = dev->base_addr; if (debug > 0) { @@ -914,7 +913,7 @@ static void epic_tx_timeout(struct net_device *dev) /* Initialize the Rx and Tx rings, along with various 'dev' bits. */ static void epic_init_ring(struct net_device *dev) { - struct epic_private *ep = dev->priv; + struct epic_private *ep = netdev_priv(dev); int i; ep->tx_full = 0; @@ -960,7 +959,7 @@ static void epic_init_ring(struct net_device *dev) static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct epic_private *ep = dev->priv; + struct epic_private *ep = netdev_priv(dev); int entry, free_count; u32 ctrl_word; unsigned long flags; @@ -1088,7 +1087,7 @@ static void epic_tx(struct net_device *dev, struct epic_private *ep) static irqreturn_t epic_interrupt(int irq, void *dev_instance) { struct net_device *dev = dev_instance; - struct epic_private *ep = dev->priv; + struct epic_private *ep = netdev_priv(dev); long ioaddr = dev->base_addr; unsigned int handled = 0; int status; @@ -1110,9 +1109,9 @@ static irqreturn_t epic_interrupt(int irq, void *dev_instance) if ((status & EpicNapiEvent) && !ep->reschedule_in_poll) { spin_lock(&ep->napi_lock); - if (netif_rx_schedule_prep(dev, &ep->napi)) { + if (netif_rx_schedule_prep(&ep->napi)) { epic_napi_irq_off(dev, ep); - __netif_rx_schedule(dev, &ep->napi); + __netif_rx_schedule(&ep->napi); } else ep->reschedule_in_poll++; spin_unlock(&ep->napi_lock); @@ -1156,7 +1155,7 @@ static irqreturn_t epic_interrupt(int irq, void *dev_instance) static int epic_rx(struct net_device *dev, int budget) { - struct epic_private *ep = dev->priv; + struct epic_private *ep = netdev_priv(dev); int entry = ep->cur_rx % RX_RING_SIZE; int rx_work_limit = ep->dirty_rx + RX_RING_SIZE - ep->cur_rx; int work_done = 0; @@ -1223,7 +1222,6 @@ static int epic_rx(struct net_device *dev, int budget) } skb->protocol = eth_type_trans(skb, dev); netif_receive_skb(skb); - dev->last_rx = jiffies; ep->stats.rx_packets++; ep->stats.rx_bytes += pkt_len; } @@ -1290,7 +1288,7 @@ static int epic_poll(struct napi_struct *napi, int budget) more = ep->reschedule_in_poll; if (!more) { - __netif_rx_complete(dev, napi); + __netif_rx_complete(napi); outl(EpicNapiEvent, ioaddr + INTSTAT); epic_napi_irq_on(dev, ep); } else @@ -1308,7 +1306,7 @@ static int epic_poll(struct napi_struct *napi, int budget) static int epic_close(struct net_device *dev) { long ioaddr = dev->base_addr; - struct epic_private *ep = dev->priv; + struct epic_private *ep = netdev_priv(dev); struct sk_buff *skb; int i; @@ -1358,7 +1356,7 @@ static int epic_close(struct net_device *dev) static struct net_device_stats *epic_get_stats(struct net_device *dev) { - struct epic_private *ep = dev->priv; + struct epic_private *ep = netdev_priv(dev); long ioaddr = dev->base_addr; if (netif_running(dev)) { @@ -1379,7 +1377,7 @@ static struct net_device_stats *epic_get_stats(struct net_device *dev) static void set_rx_mode(struct net_device *dev) { long ioaddr = dev->base_addr; - struct epic_private *ep = dev->priv; + struct epic_private *ep = netdev_priv(dev); unsigned char mc_filter[8]; /* Multicast hash filter */ int i; @@ -1418,7 +1416,7 @@ static void set_rx_mode(struct net_device *dev) static void netdev_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info) { - struct epic_private *np = dev->priv; + struct epic_private *np = netdev_priv(dev); strcpy (info->driver, DRV_NAME); strcpy (info->version, DRV_VERSION); @@ -1427,7 +1425,7 @@ static void netdev_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo * static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct epic_private *np = dev->priv; + struct epic_private *np = netdev_priv(dev); int rc; spin_lock_irq(&np->lock); @@ -1439,7 +1437,7 @@ static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct epic_private *np = dev->priv; + struct epic_private *np = netdev_priv(dev); int rc; spin_lock_irq(&np->lock); @@ -1451,13 +1449,13 @@ static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) static int netdev_nway_reset(struct net_device *dev) { - struct epic_private *np = dev->priv; + struct epic_private *np = netdev_priv(dev); return mii_nway_restart(&np->mii); } static u32 netdev_get_link(struct net_device *dev) { - struct epic_private *np = dev->priv; + struct epic_private *np = netdev_priv(dev); return mii_link_ok(&np->mii); } @@ -1506,7 +1504,7 @@ static const struct ethtool_ops netdev_ethtool_ops = { static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct epic_private *np = dev->priv; + struct epic_private *np = netdev_priv(dev); long ioaddr = dev->base_addr; struct mii_ioctl_data *data = if_mii(rq); int rc; @@ -1534,7 +1532,7 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) static void __devexit epic_remove_one (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct epic_private *ep = dev->priv; + struct epic_private *ep = netdev_priv(dev); pci_free_consistent(pdev, TX_TOTAL_SIZE, ep->tx_ring, ep->tx_ring_dma); pci_free_consistent(pdev, RX_TOTAL_SIZE, ep->rx_ring, ep->rx_ring_dma); diff --git a/drivers/net/eql.c b/drivers/net/eql.c index 18f1364d3d5bfeb25c94e30572cb98115fbf7af9..40125694bd9f641209eb03fb90a04e8ad4d99998 100644 --- a/drivers/net/eql.c +++ b/drivers/net/eql.c @@ -162,6 +162,13 @@ static void eql_timer(unsigned long param) static char version[] __initdata = "Equalizer2002: Simon Janes (simon@ncm.com) and David S. Miller (davem@redhat.com)\n"; +static const struct net_device_ops eql_netdev_ops = { + .ndo_open = eql_open, + .ndo_stop = eql_close, + .ndo_do_ioctl = eql_ioctl, + .ndo_start_xmit = eql_slave_xmit, +}; + static void __init eql_setup(struct net_device *dev) { equalizer_t *eql = netdev_priv(dev); @@ -175,10 +182,7 @@ static void __init eql_setup(struct net_device *dev) INIT_LIST_HEAD(&eql->queue.all_slaves); eql->queue.master_dev = dev; - dev->open = eql_open; - dev->stop = eql_close; - dev->do_ioctl = eql_ioctl; - dev->hard_start_xmit = eql_slave_xmit; + dev->netdev_ops = &eql_netdev_ops; /* * Now we undo some of the things that eth_setup does diff --git a/drivers/net/es3210.c b/drivers/net/es3210.c index deefa51b8c31b652cdbbc1509dfcb6d006f0d915..5569f2ffb62cbc2814df1012e11f5ff7e1995727 100644 --- a/drivers/net/es3210.c +++ b/drivers/net/es3210.c @@ -64,9 +64,6 @@ static const char version[] = static int es_probe1(struct net_device *dev, int ioaddr); -static int es_open(struct net_device *dev); -static int es_close(struct net_device *dev); - static void es_reset_8390(struct net_device *dev); static void es_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page); @@ -179,7 +176,6 @@ static int __init es_probe1(struct net_device *dev, int ioaddr) { int i, retval; unsigned long eisa_id; - DECLARE_MAC_BUF(mac); if (!request_region(ioaddr + ES_SA_PROM, ES_IO_EXTENT, "es3210")) return -ENODEV; @@ -205,14 +201,14 @@ static int __init es_probe1(struct net_device *dev, int ioaddr) if (dev->dev_addr[0] != ES_ADDR0 || dev->dev_addr[1] != ES_ADDR1 || dev->dev_addr[2] != ES_ADDR2) { - printk("es3210.c: card not found %s (invalid_prefix).\n", - print_mac(mac, dev->dev_addr)); + printk("es3210.c: card not found %pM (invalid_prefix).\n", + dev->dev_addr); retval = -ENODEV; goto out; } - printk("es3210.c: ES3210 rev. %ld at %#x, node %s", - eisa_id>>24, ioaddr, print_mac(mac, dev->dev_addr)); + printk("es3210.c: ES3210 rev. %ld at %#x, node %pM", + eisa_id>>24, ioaddr, dev->dev_addr); /* Snarf the interrupt now. */ if (dev->irq == 0) { @@ -290,11 +286,7 @@ static int __init es_probe1(struct net_device *dev, int ioaddr) ei_status.block_output = &es_block_output; ei_status.get_8390_hdr = &es_get_8390_hdr; - dev->open = &es_open; - dev->stop = &es_close; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = ei_poll; -#endif + dev->netdev_ops = &ei_netdev_ops; NS8390_init(dev, 0); retval = register_netdev(dev); @@ -386,22 +378,6 @@ static void es_block_output(struct net_device *dev, int count, memcpy_toio(shmem, buf, count); } -static int es_open(struct net_device *dev) -{ - ei_open(dev); - return 0; -} - -static int es_close(struct net_device *dev) -{ - - if (ei_debug > 1) - printk("%s: Shutting down ethercard.\n", dev->name); - - ei_close(dev); - return 0; -} - #ifdef MODULE #define MAX_ES_CARDS 4 /* Max number of ES3210 cards per module */ #define NAMELEN 8 /* # of chars for storing dev->name */ diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c index bee8b3fbc56591c9d8f493ae2295dba5ba849793..5c048f2fd74f856bb4e3ef65a07d54376aa18eb6 100644 --- a/drivers/net/eth16i.c +++ b/drivers/net/eth16i.c @@ -1205,7 +1205,6 @@ static void eth16i_rx(struct net_device *dev) printk(KERN_DEBUG ".\n"); } netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; @@ -1466,7 +1465,7 @@ void __exit cleanup_module(void) for(this_dev = 0; this_dev < MAX_ETH16I_CARDS; this_dev++) { struct net_device *dev = dev_eth16i[this_dev]; - if(dev->priv) { + if (netdev_priv(dev)) { unregister_netdev(dev); free_irq(dev->irq, dev); release_region(dev->base_addr, ETH16I_IO_EXTENT); @@ -1475,15 +1474,3 @@ void __exit cleanup_module(void) } } #endif /* MODULE */ - -/* - * Local variables: - * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c eth16i.c" - * alt-compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict -prototypes -O6 -c eth16i.c" - * tab-width: 8 - * c-basic-offset: 8 - * c-indent-level: 8 - * End: - */ - -/* End of file eth16i.c */ diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c index 593a120e31b2bdc406dd8e3e6cfd8aeca27d1798..b852303c9362a8a3f5c1888624a7d23edd4d2cb5 100644 --- a/drivers/net/ewrk3.c +++ b/drivers/net/ewrk3.c @@ -396,7 +396,6 @@ ewrk3_hw_init(struct net_device *dev, u_long iobase) u_long mem_start, shmem_length; u_char cr, cmr, icr, nicsr, lemac, hard_strapped = 0; u_char eeprom_image[EEPROM_MAX], chksum, eisa_cr = 0; - DECLARE_MAC_BUF(mac); /* ** Stop the EWRK3. Enable the DBR ROM. Disable interrupts and remote boot. @@ -461,7 +460,7 @@ ewrk3_hw_init(struct net_device *dev, u_long iobase) if (lemac != LeMAC2) DevicePresent(iobase); /* need after EWRK3_INIT */ status = get_hw_addr(dev, eeprom_image, lemac); - printk("%s\n", print_mac(mac, dev->dev_addr)); + printk("%pM\n", dev->dev_addr); if (status) { printk(" which has an EEPROM CRC error.\n"); @@ -646,10 +645,8 @@ static int ewrk3_open(struct net_device *dev) ewrk3_init(dev); if (ewrk3_debug > 1) { - DECLARE_MAC_BUF(mac); printk("%s: ewrk3 open with irq %d\n", dev->name, dev->irq); - printk(" physical address: %s\n", - print_mac(mac, dev->dev_addr)); + printk(" physical address: %pM\n", dev->dev_addr); if (lp->shmem_length == 0) { printk(" no shared memory, I/O only mode\n"); } else { @@ -1029,7 +1026,6 @@ static int ewrk3_rx(struct net_device *dev) /* ** Update stats */ - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } else { @@ -1971,13 +1967,3 @@ module_exit(ewrk3_exit_module); module_init(ewrk3_init_module); #endif /* MODULE */ MODULE_LICENSE("GPL"); - - - -/* - * Local variables: - * compile-command: "gcc -D__KERNEL__ -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c ewrk3.c" - * - * compile-command: "gcc -D__KERNEL__ -DMODULE -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c ewrk3.c" - * End: - */ diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c index b455ae931f7ac3f76d4efa6d506269f77a3c111c..31ab1ff623fcfca4575939569dfdeb79dc6dd218 100644 --- a/drivers/net/fealnx.c +++ b/drivers/net/fealnx.c @@ -486,7 +486,6 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev, #else int bar = 1; #endif - DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -665,9 +664,9 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev, if (err) goto err_out_free_tx; - printk(KERN_INFO "%s: %s at %p, %s, IRQ %d.\n", + printk(KERN_INFO "%s: %s at %p, %pM, IRQ %d.\n", dev->name, skel_netdrv_tbl[chip_id].chip_name, ioaddr, - print_mac(mac, dev->dev_addr), irq); + dev->dev_addr, irq); return 0; @@ -1727,7 +1726,6 @@ static int netdev_rx(struct net_device *dev) } skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; np->stats.rx_packets++; np->stats.rx_bytes += pkt_len; } diff --git a/drivers/net/fec.c b/drivers/net/fec.c index ecd5c71a7a8a5f6470f7362a051434f61529e5b3..7e33c129d51cb4d936fa16ea146b55721fa660ce 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -1155,7 +1155,7 @@ static phy_info_t const phy_info_ks8721bl = { static void mii_parse_dp8384x_sr2(uint mii_reg, struct net_device *dev) { - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); *s &= ~(PHY_STAT_SPMASK | PHY_STAT_LINK | PHY_STAT_ANC); @@ -2562,7 +2562,6 @@ static int __init fec_enet_module_init(void) { struct net_device *dev; int i, err; - DECLARE_MAC_BUF(mac); printk("FEC ENET Version 0.2\n"); @@ -2581,8 +2580,7 @@ static int __init fec_enet_module_init(void) return -EIO; } - printk("%s: ethernet %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk("%s: ethernet %pM\n", dev->name, dev->dev_addr); } return 0; } diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c index aec3b97e794d865d9de5373e6a45c072069ad6f6..cd8e98b45ec50d9e253dcc9251ce8e62f8703ab6 100644 --- a/drivers/net/fec_mpc52xx.c +++ b/drivers/net/fec_mpc52xx.c @@ -216,7 +216,7 @@ static int mpc52xx_fec_init_phy(struct net_device *dev) struct phy_device *phydev; char phy_id[BUS_ID_SIZE]; - snprintf(phy_id, BUS_ID_SIZE, "%x:%02x", + snprintf(phy_id, sizeof(phy_id), "%x:%02x", (unsigned int)dev->base_addr, priv->phy_addr); priv->link = PHY_DOWN; @@ -487,7 +487,6 @@ static irqreturn_t mpc52xx_fec_rx_interrupt(int irq, void *dev_id) rskb->protocol = eth_type_trans(rskb, dev); netif_rx(rskb); - dev->last_rx = jiffies; } else { /* Can't get a new one : reuse the same & drop pkt */ dev_notice(&dev->dev, "Memory squeeze, dropping packet.\n"); diff --git a/drivers/net/fec_mpc52xx_phy.c b/drivers/net/fec_mpc52xx_phy.c index 45dd9bdc5d62ac0299058434aa4862ca277d8828..dd9bfa42ac348b3039c56d90dd6cab9f0c61fa50 100644 --- a/drivers/net/fec_mpc52xx_phy.c +++ b/drivers/net/fec_mpc52xx_phy.c @@ -122,9 +122,6 @@ static int mpc52xx_fec_mdio_probe(struct of_device *of, out_be32(&priv->regs->mii_speed, ((mpc52xx_find_ipb_freq(of->node) >> 20) / 5) << 1); - /* enable MII interrupt */ - out_be32(&priv->regs->imask, in_be32(&priv->regs->imask) | FEC_IMASK_MII); - err = mdiobus_register(bus); if (err) goto out_unmap; @@ -156,7 +153,7 @@ static int mpc52xx_fec_mdio_remove(struct of_device *of) iounmap(priv->regs); for (i=0; iirq[i]) + if (bus->irq[i] != PHY_POLL) irq_dispose_mapping(bus->irq[i]); kfree(priv); kfree(bus->irq); diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index cc7328b1552136f0fa7c8e8f5587b61e110f216b..5b68dc20168db466a867f63e44823e500568e837 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -712,12 +712,12 @@ struct nv_skb_map { /* * SMP locking: - * All hardware access under dev->priv->lock, except the performance + * All hardware access under netdev_priv(dev)->lock, except the performance * critical parts: * - rx is (pseudo-) lockless: it relies on the single-threading provided * by the arch code for interrupts. * - tx setup is lockless: it relies on netif_tx_lock. Actual submission - * needs dev->priv->lock :-( + * needs netdev_priv(dev)->lock :-( * - set_multicast_list: preparation lockless, relies on netif_tx_lock. */ @@ -818,7 +818,7 @@ struct fe_priv { * Maximum number of loops until we assume that a bit in the irq mask * is stuck. Overridable with module param. */ -static int max_interrupt_work = 5; +static int max_interrupt_work = 15; /* * Optimization can be either throuput mode or cpu mode @@ -1446,9 +1446,9 @@ static int phy_init(struct net_device *dev) /* some phys clear out pause advertisment on reset, set it back */ mii_rw(dev, np->phyaddr, MII_ADVERTISE, reg); - /* restart auto negotiation */ + /* restart auto negotiation, power down phy */ mii_control = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ); - mii_control |= (BMCR_ANRESTART | BMCR_ANENABLE); + mii_control |= (BMCR_ANRESTART | BMCR_ANENABLE | BMCR_PDOWN); if (mii_rw(dev, np->phyaddr, MII_BMCR, mii_control)) { return PHY_ERROR; } @@ -1760,7 +1760,7 @@ static void nv_do_rx_refill(unsigned long data) struct fe_priv *np = netdev_priv(dev); /* Just reschedule NAPI rx processing */ - netif_rx_schedule(dev, &np->napi); + netif_rx_schedule(&np->napi); } #else static void nv_do_rx_refill(unsigned long data) @@ -2735,7 +2735,6 @@ static int nv_rx_process(struct net_device *dev, int limit) #else netif_rx(skb); #endif - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += len; next_pkt: @@ -2848,7 +2847,6 @@ static int nv_rx_process_optimized(struct net_device *dev, int limit) } } - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += len; } else { @@ -3405,7 +3403,7 @@ static irqreturn_t nv_nic_irq(int foo, void *data) #ifdef CONFIG_FORCEDETH_NAPI if (events & NVREG_IRQ_RX_ALL) { - netif_rx_schedule(dev, &np->napi); + netif_rx_schedule(&np->napi); /* Disable furthur receive irq's */ spin_lock(&np->lock); @@ -3522,7 +3520,7 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data) #ifdef CONFIG_FORCEDETH_NAPI if (events & NVREG_IRQ_RX_ALL) { - netif_rx_schedule(dev, &np->napi); + netif_rx_schedule(&np->napi); /* Disable furthur receive irq's */ spin_lock(&np->lock); @@ -3680,7 +3678,7 @@ static int nv_napi_poll(struct napi_struct *napi, int budget) /* re-enable receive interrupts */ spin_lock_irqsave(&np->lock, flags); - __netif_rx_complete(dev, napi); + __netif_rx_complete(napi); np->irqmask |= NVREG_IRQ_RX_ALL; if (np->msi_flags & NV_MSI_X_ENABLED) @@ -3706,7 +3704,7 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data) writel(NVREG_IRQ_RX_ALL, base + NvRegMSIXIrqStatus); if (events) { - netif_rx_schedule(dev, &np->napi); + netif_rx_schedule(&np->napi); /* disable receive interrupts on the nic */ writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask); pci_push(base); @@ -5210,6 +5208,10 @@ static int nv_open(struct net_device *dev) dprintk(KERN_DEBUG "nv_open: begin\n"); + /* power up phy */ + mii_rw(dev, np->phyaddr, MII_BMCR, + mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ) & ~BMCR_PDOWN); + /* erase previous misconfiguration */ if (np->driver_data & DEV_HAS_POWER_CNTRL) nv_mac_reset(dev); @@ -5403,6 +5405,10 @@ static int nv_close(struct net_device *dev) if (np->wolenabled) { writel(NVREG_PFF_ALWAYS|NVREG_PFF_MYADDR, base + NvRegPacketFilterFlags); nv_start_rx(dev); + } else { + /* power down phy */ + mii_rw(dev, np->phyaddr, MII_BMCR, + mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ)|BMCR_PDOWN); } /* FIXME: power down nic */ @@ -5410,6 +5416,38 @@ static int nv_close(struct net_device *dev) return 0; } +static const struct net_device_ops nv_netdev_ops = { + .ndo_open = nv_open, + .ndo_stop = nv_close, + .ndo_get_stats = nv_get_stats, + .ndo_start_xmit = nv_start_xmit, + .ndo_tx_timeout = nv_tx_timeout, + .ndo_change_mtu = nv_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = nv_set_mac_address, + .ndo_set_multicast_list = nv_set_multicast, + .ndo_vlan_rx_register = nv_vlan_rx_register, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = nv_poll_controller, +#endif +}; + +static const struct net_device_ops nv_netdev_ops_optimized = { + .ndo_open = nv_open, + .ndo_stop = nv_close, + .ndo_get_stats = nv_get_stats, + .ndo_start_xmit = nv_start_xmit_optimized, + .ndo_tx_timeout = nv_tx_timeout, + .ndo_change_mtu = nv_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = nv_set_mac_address, + .ndo_set_multicast_list = nv_set_multicast, + .ndo_vlan_rx_register = nv_vlan_rx_register, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = nv_poll_controller, +#endif +}; + static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) { struct net_device *dev; @@ -5420,7 +5458,6 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i u32 powerstate, txreg; u32 phystate_orig = 0, phystate; int phyinitialized = 0; - DECLARE_MAC_BUF(mac); static int printed_version; if (!printed_version++) @@ -5530,7 +5567,6 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i if (id->driver_data & DEV_HAS_VLAN) { np->vlanctl_bits = NVREG_VLANCONTROL_ENABLE; dev->features |= NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX; - dev->vlan_rx_register = nv_vlan_rx_register; } np->msi_flags = 0; @@ -5580,25 +5616,15 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i if (!np->rx_skb || !np->tx_skb) goto out_freering; - dev->open = nv_open; - dev->stop = nv_close; - if (!nv_optimized(np)) - dev->hard_start_xmit = nv_start_xmit; + dev->netdev_ops = &nv_netdev_ops; else - dev->hard_start_xmit = nv_start_xmit_optimized; - dev->get_stats = nv_get_stats; - dev->change_mtu = nv_change_mtu; - dev->set_mac_address = nv_set_mac_address; - dev->set_multicast_list = nv_set_multicast; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = nv_poll_controller; -#endif + dev->netdev_ops = &nv_netdev_ops_optimized; + #ifdef CONFIG_FORCEDETH_NAPI netif_napi_add(dev, &np->napi, nv_napi_poll, RX_WORK_PER_LOOP); #endif SET_ETHTOOL_OPS(dev, &ops); - dev->tx_timeout = nv_tx_timeout; dev->watchdog_timeo = NV_WATCHDOG_TIMEO; pci_set_drvdata(pci_dev, dev); @@ -5653,8 +5679,8 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i * to 01:23:45:67:89:ab */ dev_printk(KERN_ERR, &pci_dev->dev, - "Invalid Mac address detected: %s\n", - print_mac(mac, dev->dev_addr)); + "Invalid Mac address detected: %pM\n", + dev->dev_addr); dev_printk(KERN_ERR, &pci_dev->dev, "Please complain to your hardware vendor. Switching to a random MAC.\n"); dev->dev_addr[0] = 0x00; @@ -5663,8 +5689,8 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i get_random_bytes(&dev->dev_addr[3], 3); } - dprintk(KERN_DEBUG "%s: MAC Address %s\n", - pci_name(pci_dev), print_mac(mac, dev->dev_addr)); + dprintk(KERN_DEBUG "%s: MAC Address %pM\n", + pci_name(pci_dev), dev->dev_addr); /* set mac address */ nv_copy_mac_to_hw(dev); @@ -6141,7 +6167,7 @@ static struct pci_device_id pci_tbl[] = { }, { /* MCP79 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_36), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, }, { /* MCP79 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_37), diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index a6f49d02578711ed090a7625a34152e4b36655bc..4e6a9195fe5f6503e5bd609098a203186fab936c 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -209,7 +209,7 @@ static int fs_enet_rx_napi(struct napi_struct *napi, int budget) if (received < budget) { /* done */ - netif_rx_complete(dev, napi); + netif_rx_complete(napi); (*fep->ops->napi_enable_rx)(dev); } return received; @@ -478,7 +478,7 @@ fs_enet_interrupt(int irq, void *dev_id) /* NOTE: it is possible for FCCs in NAPI mode */ /* to submit a spurious interrupt while in poll */ if (napi_ok) - __netif_rx_schedule(dev, &fep->napi); + __netif_rx_schedule(&fep->napi); } } @@ -1117,10 +1117,7 @@ static int __devinit fs_enet_probe(struct of_device *ofdev, if (ret) goto out_free_bd; - printk(KERN_INFO "%s: fs_enet: %02x:%02x:%02x:%02x:%02x:%02x\n", - ndev->name, - ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2], - ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]); + printk(KERN_INFO "%s: fs_enet: %pM\n", ndev->name, ndev->dev_addr); return 0; diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index c4af949bf860d81ffd69ce6ff6eceb9cf0c8a69a..c672ecfc95957f24cc3cb0f358bface91b0a2fbd 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -25,11 +25,8 @@ * * Theory of operation * - * The driver is initialized through platform_device. Structures which - * define the configuration needed by the board are defined in a - * board structure in arch/ppc/platforms (though I do not - * discount the possibility that other architectures could one - * day be supported. + * The driver is initialized through of_device. Configuration information + * is therefore conveyed through an OF-style device tree. * * The Gianfar Ethernet Controller uses a ring of buffer * descriptors. The beginning is indicated by a register @@ -78,7 +75,7 @@ #include #include #include -#include +#include #include #include #include @@ -92,6 +89,8 @@ #include #include #include +#include +#include #include "gianfar.h" #include "gianfar_mii.h" @@ -119,8 +118,9 @@ static irqreturn_t gfar_interrupt(int irq, void *dev_id); static void adjust_link(struct net_device *dev); static void init_registers(struct net_device *dev); static int init_phy(struct net_device *dev); -static int gfar_probe(struct platform_device *pdev); -static int gfar_remove(struct platform_device *pdev); +static int gfar_probe(struct of_device *ofdev, + const struct of_device_id *match); +static int gfar_remove(struct of_device *ofdev); static void free_skb_resources(struct gfar_private *priv); static void gfar_set_multi(struct net_device *dev); static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr); @@ -131,7 +131,8 @@ static void gfar_netpoll(struct net_device *dev); #endif int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit); static int gfar_clean_tx_ring(struct net_device *dev); -static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int length); +static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, + int amount_pull); static void gfar_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp); void gfar_halt(struct net_device *dev); @@ -149,29 +150,163 @@ MODULE_LICENSE("GPL"); /* Returns 1 if incoming frames use an FCB */ static inline int gfar_uses_fcb(struct gfar_private *priv) { - return (priv->vlan_enable || priv->rx_csum_enable); + return priv->vlgrp || priv->rx_csum_enable; +} + +static int gfar_of_init(struct net_device *dev) +{ + struct device_node *phy, *mdio; + const unsigned int *id; + const char *model; + const char *ctype; + const void *mac_addr; + const phandle *ph; + u64 addr, size; + int err = 0; + struct gfar_private *priv = netdev_priv(dev); + struct device_node *np = priv->node; + char bus_name[MII_BUS_ID_SIZE]; + + if (!np || !of_device_is_available(np)) + return -ENODEV; + + /* get a pointer to the register memory */ + addr = of_translate_address(np, of_get_address(np, 0, &size, NULL)); + priv->regs = ioremap(addr, size); + + if (priv->regs == NULL) + return -ENOMEM; + + priv->interruptTransmit = irq_of_parse_and_map(np, 0); + + model = of_get_property(np, "model", NULL); + + /* If we aren't the FEC we have multiple interrupts */ + if (model && strcasecmp(model, "FEC")) { + priv->interruptReceive = irq_of_parse_and_map(np, 1); + + priv->interruptError = irq_of_parse_and_map(np, 2); + + if (priv->interruptTransmit < 0 || + priv->interruptReceive < 0 || + priv->interruptError < 0) { + err = -EINVAL; + goto err_out; + } + } + + mac_addr = of_get_mac_address(np); + if (mac_addr) + memcpy(dev->dev_addr, mac_addr, MAC_ADDR_LEN); + + if (model && !strcasecmp(model, "TSEC")) + priv->device_flags = + FSL_GIANFAR_DEV_HAS_GIGABIT | + FSL_GIANFAR_DEV_HAS_COALESCE | + FSL_GIANFAR_DEV_HAS_RMON | + FSL_GIANFAR_DEV_HAS_MULTI_INTR; + if (model && !strcasecmp(model, "eTSEC")) + priv->device_flags = + FSL_GIANFAR_DEV_HAS_GIGABIT | + FSL_GIANFAR_DEV_HAS_COALESCE | + FSL_GIANFAR_DEV_HAS_RMON | + FSL_GIANFAR_DEV_HAS_MULTI_INTR | + FSL_GIANFAR_DEV_HAS_PADDING | + FSL_GIANFAR_DEV_HAS_CSUM | + FSL_GIANFAR_DEV_HAS_VLAN | + FSL_GIANFAR_DEV_HAS_MAGIC_PACKET | + FSL_GIANFAR_DEV_HAS_EXTENDED_HASH; + + ctype = of_get_property(np, "phy-connection-type", NULL); + + /* We only care about rgmii-id. The rest are autodetected */ + if (ctype && !strcmp(ctype, "rgmii-id")) + priv->interface = PHY_INTERFACE_MODE_RGMII_ID; + else + priv->interface = PHY_INTERFACE_MODE_MII; + + if (of_get_property(np, "fsl,magic-packet", NULL)) + priv->device_flags |= FSL_GIANFAR_DEV_HAS_MAGIC_PACKET; + + ph = of_get_property(np, "phy-handle", NULL); + if (ph == NULL) { + u32 *fixed_link; + + fixed_link = (u32 *)of_get_property(np, "fixed-link", NULL); + if (!fixed_link) { + err = -ENODEV; + goto err_out; + } + + snprintf(priv->phy_bus_id, BUS_ID_SIZE, PHY_ID_FMT, "0", + fixed_link[0]); + } else { + phy = of_find_node_by_phandle(*ph); + + if (phy == NULL) { + err = -ENODEV; + goto err_out; + } + + mdio = of_get_parent(phy); + + id = of_get_property(phy, "reg", NULL); + + of_node_put(phy); + of_node_put(mdio); + + gfar_mdio_bus_name(bus_name, mdio); + snprintf(priv->phy_bus_id, BUS_ID_SIZE, "%s:%02x", + bus_name, *id); + } + + /* Find the TBI PHY. If it's not there, we don't support SGMII */ + ph = of_get_property(np, "tbi-handle", NULL); + if (ph) { + struct device_node *tbi = of_find_node_by_phandle(*ph); + struct of_device *ofdev; + struct mii_bus *bus; + + if (!tbi) + return 0; + + mdio = of_get_parent(tbi); + if (!mdio) + return 0; + + ofdev = of_find_device_by_node(mdio); + + of_node_put(mdio); + + id = of_get_property(tbi, "reg", NULL); + if (!id) + return 0; + + of_node_put(tbi); + + bus = dev_get_drvdata(&ofdev->dev); + + priv->tbiphy = bus->phy_map[*id]; + } + + return 0; + +err_out: + iounmap(priv->regs); + return err; } /* Set up the ethernet device structure, private data, * and anything else we need before we start */ -static int gfar_probe(struct platform_device *pdev) +static int gfar_probe(struct of_device *ofdev, + const struct of_device_id *match) { u32 tempval; struct net_device *dev = NULL; struct gfar_private *priv = NULL; - struct gianfar_platform_data *einfo; - struct resource *r; - int err = 0, irq; DECLARE_MAC_BUF(mac); - - einfo = (struct gianfar_platform_data *) pdev->dev.platform_data; - - if (NULL == einfo) { - printk(KERN_ERR "gfar %d: Missing additional data!\n", - pdev->id); - - return -ENODEV; - } + int err = 0; + int len_devname; /* Create an ethernet device instance */ dev = alloc_etherdev(sizeof (*priv)); @@ -181,64 +316,23 @@ static int gfar_probe(struct platform_device *pdev) priv = netdev_priv(dev); priv->dev = dev; + priv->node = ofdev->node; - /* Set the info in the priv to the current info */ - priv->einfo = einfo; - - /* fill out IRQ fields */ - if (einfo->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { - irq = platform_get_irq_byname(pdev, "tx"); - if (irq < 0) - goto regs_fail; - priv->interruptTransmit = irq; - - irq = platform_get_irq_byname(pdev, "rx"); - if (irq < 0) - goto regs_fail; - priv->interruptReceive = irq; - - irq = platform_get_irq_byname(pdev, "error"); - if (irq < 0) - goto regs_fail; - priv->interruptError = irq; - } else { - irq = platform_get_irq(pdev, 0); - if (irq < 0) - goto regs_fail; - priv->interruptTransmit = irq; - } - - /* get a pointer to the register memory */ - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->regs = ioremap(r->start, sizeof (struct gfar)); + err = gfar_of_init(dev); - if (NULL == priv->regs) { - err = -ENOMEM; + if (err) goto regs_fail; - } spin_lock_init(&priv->txlock); spin_lock_init(&priv->rxlock); spin_lock_init(&priv->bflock); INIT_WORK(&priv->reset_task, gfar_reset_task); - platform_set_drvdata(pdev, dev); + dev_set_drvdata(&ofdev->dev, priv); /* Stop the DMA engine now, in case it was running before */ /* (The firmware could have used it, and left it running). */ - /* To do this, we write Graceful Receive Stop and Graceful */ - /* Transmit Stop, and then wait until the corresponding bits */ - /* in IEVENT indicate the stops have completed. */ - tempval = gfar_read(&priv->regs->dmactrl); - tempval &= ~(DMACTRL_GRS | DMACTRL_GTS); - gfar_write(&priv->regs->dmactrl, tempval); - - tempval = gfar_read(&priv->regs->dmactrl); - tempval |= (DMACTRL_GRS | DMACTRL_GTS); - gfar_write(&priv->regs->dmactrl, tempval); - - while (!(gfar_read(&priv->regs->ievent) & (IEVENT_GRSC | IEVENT_GTSC))) - cpu_relax(); + gfar_halt(dev); /* Reset MAC layer */ gfar_write(&priv->regs->maccfg1, MACCFG1_SOFT_RESET); @@ -252,13 +346,10 @@ static int gfar_probe(struct platform_device *pdev) /* Initialize ECNTRL */ gfar_write(&priv->regs->ecntrl, ECNTRL_INIT_SETTINGS); - /* Copy the station address into the dev structure, */ - memcpy(dev->dev_addr, einfo->mac_addr, MAC_ADDR_LEN); - /* Set the dev->base_addr to the gfar reg region */ dev->base_addr = (unsigned long) (priv->regs); - SET_NETDEV_DEV(dev, &pdev->dev); + SET_NETDEV_DEV(dev, &ofdev->dev); /* Fill in the dev structure */ dev->open = gfar_enet_open; @@ -276,23 +367,21 @@ static int gfar_probe(struct platform_device *pdev) dev->ethtool_ops = &gfar_ethtool_ops; - if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) { + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) { priv->rx_csum_enable = 1; - dev->features |= NETIF_F_IP_CSUM; + dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_HIGHDMA; } else priv->rx_csum_enable = 0; priv->vlgrp = NULL; - if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_VLAN) { + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_VLAN) { dev->vlan_rx_register = gfar_vlan_rx_register; dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - - priv->vlan_enable = 1; } - if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_EXTENDED_HASH) { + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_EXTENDED_HASH) { priv->extended_hash = 1; priv->hash_width = 9; @@ -327,7 +416,7 @@ static int gfar_probe(struct platform_device *pdev) priv->hash_regs[7] = &priv->regs->gaddr7; } - if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_PADDING) + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_PADDING) priv->padding = DEFAULT_PADDING; else priv->padding = 0; @@ -338,13 +427,12 @@ static int gfar_probe(struct platform_device *pdev) priv->rx_buffer_size = DEFAULT_RX_BUFFER_SIZE; priv->tx_ring_size = DEFAULT_TX_RING_SIZE; priv->rx_ring_size = DEFAULT_RX_RING_SIZE; + priv->num_txbdfree = DEFAULT_TX_RING_SIZE; priv->txcoalescing = DEFAULT_TX_COALESCE; - priv->txcount = DEFAULT_TXCOUNT; - priv->txtime = DEFAULT_TXTIME; + priv->txic = DEFAULT_TXIC; priv->rxcoalescing = DEFAULT_RX_COALESCE; - priv->rxcount = DEFAULT_RXCOUNT; - priv->rxtime = DEFAULT_RXTIME; + priv->rxic = DEFAULT_RXIC; /* Enable most messages by default */ priv->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1; @@ -360,12 +448,28 @@ static int gfar_probe(struct platform_device *pdev) goto register_fail; } + /* fill out IRQ number and name fields */ + len_devname = strlen(dev->name); + strncpy(&priv->int_name_tx[0], dev->name, len_devname); + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { + strncpy(&priv->int_name_tx[len_devname], + "_tx", sizeof("_tx") + 1); + + strncpy(&priv->int_name_rx[0], dev->name, len_devname); + strncpy(&priv->int_name_rx[len_devname], + "_rx", sizeof("_rx") + 1); + + strncpy(&priv->int_name_er[0], dev->name, len_devname); + strncpy(&priv->int_name_er[len_devname], + "_er", sizeof("_er") + 1); + } else + priv->int_name_tx[len_devname] = '\0'; + /* Create all the sysfs files */ gfar_init_sysfs(dev); /* Print out the device info */ - printk(KERN_INFO DEVICE_NAME "%s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO DEVICE_NAME "%pM\n", dev->name, dev->dev_addr); /* Even more device info helps when determining which kernel */ /* provided which set of benchmarks. */ @@ -382,29 +486,28 @@ static int gfar_probe(struct platform_device *pdev) return err; } -static int gfar_remove(struct platform_device *pdev) +static int gfar_remove(struct of_device *ofdev) { - struct net_device *dev = platform_get_drvdata(pdev); - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = dev_get_drvdata(&ofdev->dev); - platform_set_drvdata(pdev, NULL); + dev_set_drvdata(&ofdev->dev, NULL); iounmap(priv->regs); - free_netdev(dev); + free_netdev(priv->dev); return 0; } #ifdef CONFIG_PM -static int gfar_suspend(struct platform_device *pdev, pm_message_t state) +static int gfar_suspend(struct of_device *ofdev, pm_message_t state) { - struct net_device *dev = platform_get_drvdata(pdev); - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = dev_get_drvdata(&ofdev->dev); + struct net_device *dev = priv->dev; unsigned long flags; u32 tempval; int magic_packet = priv->wol_en && - (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET); + (priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET); netif_device_detach(dev); @@ -445,14 +548,14 @@ static int gfar_suspend(struct platform_device *pdev, pm_message_t state) return 0; } -static int gfar_resume(struct platform_device *pdev) +static int gfar_resume(struct of_device *ofdev) { - struct net_device *dev = platform_get_drvdata(pdev); - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = dev_get_drvdata(&ofdev->dev); + struct net_device *dev = priv->dev; unsigned long flags; u32 tempval; int magic_packet = priv->wol_en && - (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET); + (priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET); if (!netif_running(dev)) { netif_device_attach(dev); @@ -511,7 +614,7 @@ static phy_interface_t gfar_get_interface(struct net_device *dev) if (ecntrl & ECNTRL_REDUCED_MII_MODE) return PHY_INTERFACE_MODE_RMII; else { - phy_interface_t interface = priv->einfo->interface; + phy_interface_t interface = priv->interface; /* * This isn't autodetected right now, so it must @@ -524,7 +627,7 @@ static phy_interface_t gfar_get_interface(struct net_device *dev) } } - if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT) + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT) return PHY_INTERFACE_MODE_GMII; return PHY_INTERFACE_MODE_MII; @@ -538,21 +641,18 @@ static int init_phy(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); uint gigabit_support = - priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT ? + priv->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT ? SUPPORTED_1000baseT_Full : 0; struct phy_device *phydev; - char phy_id[BUS_ID_SIZE]; phy_interface_t interface; priv->oldlink = 0; priv->oldspeed = 0; priv->oldduplex = -1; - snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, priv->einfo->bus_id, priv->einfo->phy_id); - interface = gfar_get_interface(dev); - phydev = phy_connect(dev, phy_id, &adjust_link, 0, interface); + phydev = phy_connect(dev, priv->phy_bus_id, &adjust_link, 0, interface); if (interface == PHY_INTERFACE_MODE_SGMII) gfar_configure_serdes(dev); @@ -583,35 +683,31 @@ static int init_phy(struct net_device *dev) static void gfar_configure_serdes(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); - struct gfar_mii __iomem *regs = - (void __iomem *)&priv->regs->gfar_mii_regs; - int tbipa = gfar_read(&priv->regs->tbipa); - struct mii_bus *bus = gfar_get_miibus(priv); - if (bus) - mutex_lock(&bus->mdio_lock); + if (!priv->tbiphy) { + printk(KERN_WARNING "SGMII mode requires that the device " + "tree specify a tbi-handle\n"); + return; + } - /* If the link is already up, we must already be ok, and don't need to + /* + * If the link is already up, we must already be ok, and don't need to * configure and reset the TBI<->SerDes link. Maybe U-Boot configured * everything for us? Resetting it takes the link down and requires * several seconds for it to come back. */ - if (gfar_local_mdio_read(regs, tbipa, MII_BMSR) & BMSR_LSTATUS) - goto done; + if (phy_read(priv->tbiphy, MII_BMSR) & BMSR_LSTATUS) + return; /* Single clk mode, mii mode off(for serdes communication) */ - gfar_local_mdio_write(regs, tbipa, MII_TBICON, TBICON_CLK_SELECT); + phy_write(priv->tbiphy, MII_TBICON, TBICON_CLK_SELECT); - gfar_local_mdio_write(regs, tbipa, MII_ADVERTISE, + phy_write(priv->tbiphy, MII_ADVERTISE, ADVERTISE_1000XFULL | ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM); - gfar_local_mdio_write(regs, tbipa, MII_BMCR, BMCR_ANENABLE | + phy_write(priv->tbiphy, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART | BMCR_FULLDPLX | BMCR_SPEED1000); - - done: - if (bus) - mutex_unlock(&bus->mdio_lock); } static void init_registers(struct net_device *dev) @@ -644,7 +740,7 @@ static void init_registers(struct net_device *dev) gfar_write(&priv->regs->gaddr7, 0); /* Zero out the rmon mib registers if it has them */ - if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON) { + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) { memset_io(&(priv->regs->rmon), 0, sizeof (struct rmon_mib)); /* Mask off the CAM interrupts */ @@ -719,7 +815,7 @@ void stop_gfar(struct net_device *dev) spin_unlock_irqrestore(&priv->txlock, flags); /* Free the IRQs */ - if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { free_irq(priv->interruptError, dev); free_irq(priv->interruptTransmit, dev); free_irq(priv->interruptReceive, dev); @@ -742,22 +838,26 @@ static void free_skb_resources(struct gfar_private *priv) { struct rxbd8 *rxbdp; struct txbd8 *txbdp; - int i; + int i, j; /* Go through all the buffer descriptors and free their data buffers */ txbdp = priv->tx_bd_base; for (i = 0; i < priv->tx_ring_size; i++) { - - if (priv->tx_skbuff[i]) { - dma_unmap_single(&priv->dev->dev, txbdp->bufPtr, - txbdp->length, - DMA_TO_DEVICE); - dev_kfree_skb_any(priv->tx_skbuff[i]); - priv->tx_skbuff[i] = NULL; + if (!priv->tx_skbuff[i]) + continue; + + dma_unmap_single(&priv->dev->dev, txbdp->bufPtr, + txbdp->length, DMA_TO_DEVICE); + txbdp->lstatus = 0; + for (j = 0; j < skb_shinfo(priv->tx_skbuff[i])->nr_frags; j++) { + txbdp++; + dma_unmap_page(&priv->dev->dev, txbdp->bufPtr, + txbdp->length, DMA_TO_DEVICE); } - txbdp++; + dev_kfree_skb_any(priv->tx_skbuff[i]); + priv->tx_skbuff[i] = NULL; } kfree(priv->tx_skbuff); @@ -777,8 +877,7 @@ static void free_skb_resources(struct gfar_private *priv) priv->rx_skbuff[i] = NULL; } - rxbdp->status = 0; - rxbdp->length = 0; + rxbdp->lstatus = 0; rxbdp->bufPtr = 0; rxbdp++; @@ -815,6 +914,8 @@ void gfar_start(struct net_device *dev) /* Unmask the interrupts we look for */ gfar_write(®s->imask, IMASK_DEFAULT); + + dev->trans_start = jiffies; } /* Bring the controller up and running */ @@ -889,6 +990,7 @@ int startup_gfar(struct net_device *dev) priv->rx_skbuff[i] = NULL; /* Initialize some variables in our dev structure */ + priv->num_txbdfree = priv->tx_ring_size; priv->dirty_tx = priv->cur_tx = priv->tx_bd_base; priv->cur_rx = priv->rx_bd_base; priv->skb_curtx = priv->skb_dirtytx = 0; @@ -897,8 +999,7 @@ int startup_gfar(struct net_device *dev) /* Initialize Transmit Descriptor Ring */ txbdp = priv->tx_bd_base; for (i = 0; i < priv->tx_ring_size; i++) { - txbdp->status = 0; - txbdp->length = 0; + txbdp->lstatus = 0; txbdp->bufPtr = 0; txbdp++; } @@ -933,11 +1034,11 @@ int startup_gfar(struct net_device *dev) /* If the device has multiple interrupts, register for * them. Otherwise, only register for the one */ - if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { /* Install our interrupt handlers for Error, * Transmit, and Receive */ if (request_irq(priv->interruptError, gfar_error, - 0, "enet_error", dev) < 0) { + 0, priv->int_name_er, dev) < 0) { if (netif_msg_intr(priv)) printk(KERN_ERR "%s: Can't get IRQ %d\n", dev->name, priv->interruptError); @@ -947,7 +1048,7 @@ int startup_gfar(struct net_device *dev) } if (request_irq(priv->interruptTransmit, gfar_transmit, - 0, "enet_tx", dev) < 0) { + 0, priv->int_name_tx, dev) < 0) { if (netif_msg_intr(priv)) printk(KERN_ERR "%s: Can't get IRQ %d\n", dev->name, priv->interruptTransmit); @@ -958,7 +1059,7 @@ int startup_gfar(struct net_device *dev) } if (request_irq(priv->interruptReceive, gfar_receive, - 0, "enet_rx", dev) < 0) { + 0, priv->int_name_rx, dev) < 0) { if (netif_msg_intr(priv)) printk(KERN_ERR "%s: Can't get IRQ %d (receive0)\n", dev->name, priv->interruptReceive); @@ -968,10 +1069,10 @@ int startup_gfar(struct net_device *dev) } } else { if (request_irq(priv->interruptTransmit, gfar_interrupt, - 0, "gfar_interrupt", dev) < 0) { + 0, priv->int_name_tx, dev) < 0) { if (netif_msg_intr(priv)) printk(KERN_ERR "%s: Can't get IRQ %d\n", - dev->name, priv->interruptError); + dev->name, priv->interruptTransmit); err = -1; goto err_irq_fail; @@ -981,17 +1082,13 @@ int startup_gfar(struct net_device *dev) phy_start(priv->phydev); /* Configure the coalescing support */ + gfar_write(®s->txic, 0); if (priv->txcoalescing) - gfar_write(®s->txic, - mk_ic_value(priv->txcount, priv->txtime)); - else - gfar_write(®s->txic, 0); + gfar_write(®s->txic, priv->txic); + gfar_write(®s->rxic, 0); if (priv->rxcoalescing) - gfar_write(®s->rxic, - mk_ic_value(priv->rxcount, priv->rxtime)); - else - gfar_write(®s->rxic, 0); + gfar_write(®s->rxic, priv->rxic); if (priv->rx_csum_enable) rctrl |= RCTRL_CHECKSUMMING; @@ -1003,9 +1100,6 @@ int startup_gfar(struct net_device *dev) rctrl |= RCTRL_EMEN; } - if (priv->vlan_enable) - rctrl |= RCTRL_VLAN; - if (priv->padding) { rctrl &= ~RCTRL_PAL_MASK; rctrl |= RCTRL_PADDING(priv->padding); @@ -1094,11 +1188,11 @@ static int gfar_enet_open(struct net_device *dev) return err; } -static inline struct txfcb *gfar_add_fcb(struct sk_buff *skb, struct txbd8 *bdp) +static inline struct txfcb *gfar_add_fcb(struct sk_buff *skb) { struct txfcb *fcb = (struct txfcb *)skb_push (skb, GMAC_FCB_LEN); - memset(fcb, 0, GMAC_FCB_LEN); + cacheable_memzero(fcb, GMAC_FCB_LEN); return fcb; } @@ -1137,96 +1231,140 @@ void inline gfar_tx_vlan(struct sk_buff *skb, struct txfcb *fcb) fcb->vlctl = vlan_tx_tag_get(skb); } +static inline struct txbd8 *skip_txbd(struct txbd8 *bdp, int stride, + struct txbd8 *base, int ring_size) +{ + struct txbd8 *new_bd = bdp + stride; + + return (new_bd >= (base + ring_size)) ? (new_bd - ring_size) : new_bd; +} + +static inline struct txbd8 *next_txbd(struct txbd8 *bdp, struct txbd8 *base, + int ring_size) +{ + return skip_txbd(bdp, 1, base, ring_size); +} + /* This is called by the kernel when a frame is ready for transmission. */ /* It is pointed to by the dev->hard_start_xmit function pointer */ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); struct txfcb *fcb = NULL; - struct txbd8 *txbdp; - u16 status; + struct txbd8 *txbdp, *txbdp_start, *base; + u32 lstatus; + int i; + u32 bufaddr; unsigned long flags; + unsigned int nr_frags, length; + + base = priv->tx_bd_base; + + /* total number of fragments in the SKB */ + nr_frags = skb_shinfo(skb)->nr_frags; + + spin_lock_irqsave(&priv->txlock, flags); + + /* check if there is space to queue this packet */ + if (nr_frags > priv->num_txbdfree) { + /* no space, stop the queue */ + netif_stop_queue(dev); + dev->stats.tx_fifo_errors++; + spin_unlock_irqrestore(&priv->txlock, flags); + return NETDEV_TX_BUSY; + } /* Update transmit stats */ dev->stats.tx_bytes += skb->len; - /* Lock priv now */ - spin_lock_irqsave(&priv->txlock, flags); + txbdp = txbdp_start = priv->cur_tx; - /* Point at the first free tx descriptor */ - txbdp = priv->cur_tx; + if (nr_frags == 0) { + lstatus = txbdp->lstatus | BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT); + } else { + /* Place the fragment addresses and lengths into the TxBDs */ + for (i = 0; i < nr_frags; i++) { + /* Point at the next BD, wrapping as needed */ + txbdp = next_txbd(txbdp, base, priv->tx_ring_size); + + length = skb_shinfo(skb)->frags[i].size; - /* Clear all but the WRAP status flags */ - status = txbdp->status & TXBD_WRAP; + lstatus = txbdp->lstatus | length | + BD_LFLAG(TXBD_READY); + + /* Handle the last BD specially */ + if (i == nr_frags - 1) + lstatus |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT); + + bufaddr = dma_map_page(&dev->dev, + skb_shinfo(skb)->frags[i].page, + skb_shinfo(skb)->frags[i].page_offset, + length, + DMA_TO_DEVICE); + + /* set the TxBD length and buffer pointer */ + txbdp->bufPtr = bufaddr; + txbdp->lstatus = lstatus; + } + + lstatus = txbdp_start->lstatus; + } /* Set up checksumming */ - if (likely((dev->features & NETIF_F_IP_CSUM) - && (CHECKSUM_PARTIAL == skb->ip_summed))) { - fcb = gfar_add_fcb(skb, txbdp); - status |= TXBD_TOE; + if (CHECKSUM_PARTIAL == skb->ip_summed) { + fcb = gfar_add_fcb(skb); + lstatus |= BD_LFLAG(TXBD_TOE); gfar_tx_checksum(skb, fcb); } - if (priv->vlan_enable && - unlikely(priv->vlgrp && vlan_tx_tag_present(skb))) { + if (priv->vlgrp && vlan_tx_tag_present(skb)) { if (unlikely(NULL == fcb)) { - fcb = gfar_add_fcb(skb, txbdp); - status |= TXBD_TOE; + fcb = gfar_add_fcb(skb); + lstatus |= BD_LFLAG(TXBD_TOE); } gfar_tx_vlan(skb, fcb); } - /* Set buffer length and pointer */ - txbdp->length = skb->len; - txbdp->bufPtr = dma_map_single(&dev->dev, skb->data, - skb->len, DMA_TO_DEVICE); - - /* Save the skb pointer so we can free it later */ + /* setup the TxBD length and buffer pointer for the first BD */ priv->tx_skbuff[priv->skb_curtx] = skb; + txbdp_start->bufPtr = dma_map_single(&dev->dev, skb->data, + skb_headlen(skb), DMA_TO_DEVICE); - /* Update the current skb pointer (wrapping if this was the last) */ - priv->skb_curtx = - (priv->skb_curtx + 1) & TX_RING_MOD_MASK(priv->tx_ring_size); - - /* Flag the BD as interrupt-causing */ - status |= TXBD_INTERRUPT; + lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | skb_headlen(skb); - /* Flag the BD as ready to go, last in frame, and */ - /* in need of CRC */ - status |= (TXBD_READY | TXBD_LAST | TXBD_CRC); - - dev->trans_start = jiffies; - - /* The powerpc-specific eieio() is used, as wmb() has too strong + /* + * The powerpc-specific eieio() is used, as wmb() has too strong * semantics (it requires synchronization between cacheable and * uncacheable mappings, which eieio doesn't provide and which we * don't need), thus requiring a more expensive sync instruction. At * some point, the set of architecture-independent barrier functions * should be expanded to include weaker barriers. */ - eieio(); - txbdp->status = status; - /* If this was the last BD in the ring, the next one */ - /* is at the beginning of the ring */ - if (txbdp->status & TXBD_WRAP) - txbdp = priv->tx_bd_base; - else - txbdp++; + txbdp_start->lstatus = lstatus; + + /* Update the current skb pointer to the next entry we will use + * (wrapping if necessary) */ + priv->skb_curtx = (priv->skb_curtx + 1) & + TX_RING_MOD_MASK(priv->tx_ring_size); + + priv->cur_tx = next_txbd(txbdp, base, priv->tx_ring_size); + + /* reduce TxBD free count */ + priv->num_txbdfree -= (nr_frags + 1); + + dev->trans_start = jiffies; /* If the next BD still needs to be cleaned up, then the bds are full. We need to tell the kernel to stop sending us stuff. */ - if (txbdp == priv->dirty_tx) { + if (!priv->num_txbdfree) { netif_stop_queue(dev); dev->stats.tx_fifo_errors++; } - /* Update the current txbd to the next one */ - priv->cur_tx = txbdp; - /* Tell the DMA to go go go */ gfar_write(&priv->regs->tstat, TSTAT_CLEAR_THALT); @@ -1270,11 +1408,15 @@ static void gfar_vlan_rx_register(struct net_device *dev, { struct gfar_private *priv = netdev_priv(dev); unsigned long flags; + struct vlan_group *old_grp; u32 tempval; spin_lock_irqsave(&priv->rxlock, flags); - priv->vlgrp = grp; + old_grp = priv->vlgrp; + + if (old_grp == grp) + return; if (grp) { /* Enable VLAN tag insertion */ @@ -1286,6 +1428,7 @@ static void gfar_vlan_rx_register(struct net_device *dev, /* Enable VLAN tag extraction */ tempval = gfar_read(&priv->regs->rctrl); tempval |= RCTRL_VLEX; + tempval |= (RCTRL_VLEX | RCTRL_PRSDEP_INIT); gfar_write(&priv->regs->rctrl, tempval); } else { /* Disable VLAN tag insertion */ @@ -1296,9 +1439,16 @@ static void gfar_vlan_rx_register(struct net_device *dev, /* Disable VLAN tag extraction */ tempval = gfar_read(&priv->regs->rctrl); tempval &= ~RCTRL_VLEX; + /* If parse is no longer required, then disable parser */ + if (tempval & RCTRL_REQ_PARSER) + tempval |= RCTRL_PRSDEP_INIT; + else + tempval &= ~RCTRL_PRSDEP_INIT; gfar_write(&priv->regs->rctrl, tempval); } + gfar_change_mtu(dev, dev->mtu); + spin_unlock_irqrestore(&priv->rxlock, flags); } @@ -1309,14 +1459,9 @@ static int gfar_change_mtu(struct net_device *dev, int new_mtu) int oldsize = priv->rx_buffer_size; int frame_size = new_mtu + ETH_HLEN; - if (priv->vlan_enable) + if (priv->vlgrp) frame_size += VLAN_HLEN; - if (gfar_uses_fcb(priv)) - frame_size += GMAC_FCB_LEN; - - frame_size += priv->padding; - if ((frame_size < 64) || (frame_size > JUMBO_FRAME_SIZE)) { if (netif_msg_drv(priv)) printk(KERN_ERR "%s: Invalid MTU setting\n", @@ -1324,6 +1469,11 @@ static int gfar_change_mtu(struct net_device *dev, int new_mtu) return -EINVAL; } + if (gfar_uses_fcb(priv)) + frame_size += GMAC_FCB_LEN; + + frame_size += priv->padding; + tempsize = (frame_size & ~(INCREMENTAL_BUFFER_SIZE - 1)) + INCREMENTAL_BUFFER_SIZE; @@ -1388,83 +1538,85 @@ static void gfar_timeout(struct net_device *dev) /* Interrupt Handler for Transmit complete */ static int gfar_clean_tx_ring(struct net_device *dev) { - struct txbd8 *bdp; struct gfar_private *priv = netdev_priv(dev); + struct txbd8 *bdp; + struct txbd8 *lbdp = NULL; + struct txbd8 *base = priv->tx_bd_base; + struct sk_buff *skb; + int skb_dirtytx; + int tx_ring_size = priv->tx_ring_size; + int frags = 0; + int i; int howmany = 0; + u32 lstatus; bdp = priv->dirty_tx; - while ((bdp->status & TXBD_READY) == 0) { - /* If dirty_tx and cur_tx are the same, then either the */ - /* ring is empty or full now (it could only be full in the beginning, */ - /* obviously). If it is empty, we are done. */ - if ((bdp == priv->cur_tx) && (netif_queue_stopped(dev) == 0)) - break; + skb_dirtytx = priv->skb_dirtytx; - howmany++; + while ((skb = priv->tx_skbuff[skb_dirtytx])) { + frags = skb_shinfo(skb)->nr_frags; + lbdp = skip_txbd(bdp, frags, base, tx_ring_size); - /* Deferred means some collisions occurred during transmit, */ - /* but we eventually sent the packet. */ - if (bdp->status & TXBD_DEF) - dev->stats.collisions++; + lstatus = lbdp->lstatus; - /* Unmap the DMA memory */ - dma_unmap_single(&priv->dev->dev, bdp->bufPtr, - bdp->length, DMA_TO_DEVICE); + /* Only clean completed frames */ + if ((lstatus & BD_LFLAG(TXBD_READY)) && + (lstatus & BD_LENGTH_MASK)) + break; + + dma_unmap_single(&dev->dev, + bdp->bufPtr, + bdp->length, + DMA_TO_DEVICE); - /* Free the sk buffer associated with this TxBD */ - dev_kfree_skb_irq(priv->tx_skbuff[priv->skb_dirtytx]); + bdp->lstatus &= BD_LFLAG(TXBD_WRAP); + bdp = next_txbd(bdp, base, tx_ring_size); - priv->tx_skbuff[priv->skb_dirtytx] = NULL; - priv->skb_dirtytx = - (priv->skb_dirtytx + - 1) & TX_RING_MOD_MASK(priv->tx_ring_size); + for (i = 0; i < frags; i++) { + dma_unmap_page(&dev->dev, + bdp->bufPtr, + bdp->length, + DMA_TO_DEVICE); + bdp->lstatus &= BD_LFLAG(TXBD_WRAP); + bdp = next_txbd(bdp, base, tx_ring_size); + } - /* Clean BD length for empty detection */ - bdp->length = 0; + dev_kfree_skb_any(skb); + priv->tx_skbuff[skb_dirtytx] = NULL; - /* update bdp to point at next bd in the ring (wrapping if necessary) */ - if (bdp->status & TXBD_WRAP) - bdp = priv->tx_bd_base; - else - bdp++; + skb_dirtytx = (skb_dirtytx + 1) & + TX_RING_MOD_MASK(tx_ring_size); - /* Move dirty_tx to be the next bd */ - priv->dirty_tx = bdp; + howmany++; + priv->num_txbdfree += frags + 1; + } + + /* If we freed a buffer, we can restart transmission, if necessary */ + if (netif_queue_stopped(dev) && priv->num_txbdfree) + netif_wake_queue(dev); - /* We freed a buffer, so now we can restart transmission */ - if (netif_queue_stopped(dev)) - netif_wake_queue(dev); - } /* while ((bdp->status & TXBD_READY) == 0) */ + /* Update dirty indicators */ + priv->skb_dirtytx = skb_dirtytx; + priv->dirty_tx = bdp; dev->stats.tx_packets += howmany; return howmany; } -/* Interrupt Handler for Transmit complete */ -static irqreturn_t gfar_transmit(int irq, void *dev_id) +static void gfar_schedule_cleanup(struct net_device *dev) { - struct net_device *dev = (struct net_device *) dev_id; struct gfar_private *priv = netdev_priv(dev); - - /* Clear IEVENT */ - gfar_write(&priv->regs->ievent, IEVENT_TX_MASK); - - /* Lock priv */ - spin_lock(&priv->txlock); - - gfar_clean_tx_ring(dev); - - /* If we are coalescing the interrupts, reset the timer */ - /* Otherwise, clear it */ - if (likely(priv->txcoalescing)) { - gfar_write(&priv->regs->txic, 0); - gfar_write(&priv->regs->txic, - mk_ic_value(priv->txcount, priv->txtime)); + if (netif_rx_schedule_prep(&priv->napi)) { + gfar_write(&priv->regs->imask, IMASK_RTX_DISABLED); + __netif_rx_schedule(&priv->napi); } +} - spin_unlock(&priv->txlock); - +/* Interrupt Handler for Transmit complete */ +static irqreturn_t gfar_transmit(int irq, void *dev_id) +{ + gfar_schedule_cleanup((struct net_device *)dev_id); return IRQ_HANDLED; } @@ -1472,20 +1624,19 @@ static void gfar_new_rxbdp(struct net_device *dev, struct rxbd8 *bdp, struct sk_buff *skb) { struct gfar_private *priv = netdev_priv(dev); - u32 * status_len = (u32 *)bdp; - u16 flags; + u32 lstatus; bdp->bufPtr = dma_map_single(&dev->dev, skb->data, priv->rx_buffer_size, DMA_FROM_DEVICE); - flags = RXBD_EMPTY | RXBD_INTERRUPT; + lstatus = BD_LFLAG(RXBD_EMPTY | RXBD_INTERRUPT); if (bdp == priv->rx_bd_base + priv->rx_ring_size - 1) - flags |= RXBD_WRAP; + lstatus |= BD_LFLAG(RXBD_WRAP); eieio(); - *status_len = (u32)flags << 16; + bdp->lstatus = lstatus; } @@ -1552,28 +1703,7 @@ static inline void count_errors(unsigned short status, struct net_device *dev) irqreturn_t gfar_receive(int irq, void *dev_id) { - struct net_device *dev = (struct net_device *) dev_id; - struct gfar_private *priv = netdev_priv(dev); - u32 tempval; - - /* support NAPI */ - /* Clear IEVENT, so interrupts aren't called again - * because of the packets that have already arrived */ - gfar_write(&priv->regs->ievent, IEVENT_RTX_MASK); - - if (netif_rx_schedule_prep(dev, &priv->napi)) { - tempval = gfar_read(&priv->regs->imask); - tempval &= IMASK_RTX_DISABLED; - gfar_write(&priv->regs->imask, tempval); - - __netif_rx_schedule(dev, &priv->napi); - } else { - if (netif_msg_rx_err(priv)) - printk(KERN_DEBUG "%s: receive called twice (%x)[%x]\n", - dev->name, gfar_read(&priv->regs->ievent), - gfar_read(&priv->regs->imask)); - } - + gfar_schedule_cleanup((struct net_device *)dev_id); return IRQ_HANDLED; } @@ -1589,59 +1719,38 @@ static inline void gfar_rx_checksum(struct sk_buff *skb, struct rxfcb *fcb) } -static inline struct rxfcb *gfar_get_fcb(struct sk_buff *skb) -{ - struct rxfcb *fcb = (struct rxfcb *)skb->data; - - /* Remove the FCB from the skb */ - skb_pull(skb, GMAC_FCB_LEN); - - return fcb; -} - /* gfar_process_frame() -- handle one incoming packet if skb * isn't NULL. */ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, - int length) + int amount_pull) { struct gfar_private *priv = netdev_priv(dev); struct rxfcb *fcb = NULL; - if (NULL == skb) { - if (netif_msg_rx_err(priv)) - printk(KERN_WARNING "%s: Missing skb!!.\n", dev->name); - dev->stats.rx_dropped++; - priv->extra_stats.rx_skbmissing++; - } else { - int ret; - - /* Prep the skb for the packet */ - skb_put(skb, length); + int ret; - /* Grab the FCB if there is one */ - if (gfar_uses_fcb(priv)) - fcb = gfar_get_fcb(skb); + /* fcb is at the beginning if exists */ + fcb = (struct rxfcb *)skb->data; - /* Remove the padded bytes, if there are any */ - if (priv->padding) - skb_pull(skb, priv->padding); + /* Remove the FCB from the skb */ + /* Remove the padded bytes, if there are any */ + if (amount_pull) + skb_pull(skb, amount_pull); - if (priv->rx_csum_enable) - gfar_rx_checksum(skb, fcb); + if (priv->rx_csum_enable) + gfar_rx_checksum(skb, fcb); - /* Tell the skb what kind of packet this is */ - skb->protocol = eth_type_trans(skb, dev); + /* Tell the skb what kind of packet this is */ + skb->protocol = eth_type_trans(skb, dev); - /* Send the packet up the stack */ - if (unlikely(priv->vlgrp && (fcb->flags & RXFCB_VLN))) { - ret = vlan_hwaccel_receive_skb(skb, priv->vlgrp, - fcb->vlctl); - } else - ret = netif_receive_skb(skb); + /* Send the packet up the stack */ + if (unlikely(priv->vlgrp && (fcb->flags & RXFCB_VLN))) + ret = vlan_hwaccel_receive_skb(skb, priv->vlgrp, fcb->vlctl); + else + ret = netif_receive_skb(skb); - if (NET_RX_DROP == ret) - priv->extra_stats.kernel_dropped++; - } + if (NET_RX_DROP == ret) + priv->extra_stats.kernel_dropped++; return 0; } @@ -1652,14 +1761,19 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, */ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit) { - struct rxbd8 *bdp; + struct rxbd8 *bdp, *base; struct sk_buff *skb; - u16 pkt_len; + int pkt_len; + int amount_pull; int howmany = 0; struct gfar_private *priv = netdev_priv(dev); /* Get the first full descriptor */ bdp = priv->cur_rx; + base = priv->rx_bd_base; + + amount_pull = (gfar_uses_fcb(priv) ? GMAC_FCB_LEN : 0) + + priv->padding; while (!((bdp->status & RXBD_EMPTY) || (--rx_work_limit < 0))) { struct sk_buff *newskb; @@ -1680,23 +1794,30 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit) if (unlikely(!newskb)) newskb = skb; - - if (skb) + else if (skb) dev_kfree_skb_any(skb); } else { /* Increment the number of packets */ dev->stats.rx_packets++; howmany++; - /* Remove the FCS from the packet length */ - pkt_len = bdp->length - 4; + if (likely(skb)) { + pkt_len = bdp->length - ETH_FCS_LEN; + /* Remove the FCS from the packet length */ + skb_put(skb, pkt_len); + dev->stats.rx_bytes += pkt_len; - gfar_process_frame(dev, skb, pkt_len); + gfar_process_frame(dev, skb, amount_pull); - dev->stats.rx_bytes += pkt_len; - } + } else { + if (netif_msg_rx_err(priv)) + printk(KERN_WARNING + "%s: Missing skb!\n", dev->name); + dev->stats.rx_dropped++; + priv->extra_stats.rx_skbmissing++; + } - dev->last_rx = jiffies; + } priv->rx_skbuff[priv->skb_currx] = newskb; @@ -1704,10 +1825,7 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit) gfar_new_rxbdp(dev, bdp, newskb); /* Update to the next pointer */ - if (bdp->status & RXBD_WRAP) - bdp = priv->rx_bd_base; - else - bdp++; + bdp = next_bd(bdp, base, priv->rx_ring_size); /* update to point at the next skb */ priv->skb_currx = @@ -1725,19 +1843,27 @@ static int gfar_poll(struct napi_struct *napi, int budget) { struct gfar_private *priv = container_of(napi, struct gfar_private, napi); struct net_device *dev = priv->dev; - int howmany; + int tx_cleaned = 0; + int rx_cleaned = 0; unsigned long flags; + /* Clear IEVENT, so interrupts aren't called again + * because of the packets that have already arrived */ + gfar_write(&priv->regs->ievent, IEVENT_RTX_MASK); + /* If we fail to get the lock, don't bother with the TX BDs */ if (spin_trylock_irqsave(&priv->txlock, flags)) { - gfar_clean_tx_ring(dev); + tx_cleaned = gfar_clean_tx_ring(dev); spin_unlock_irqrestore(&priv->txlock, flags); } - howmany = gfar_clean_rx_ring(dev, budget); + rx_cleaned = gfar_clean_rx_ring(dev, budget); + + if (tx_cleaned) + return budget; - if (howmany < budget) { - netif_rx_complete(dev, napi); + if (rx_cleaned < budget) { + netif_rx_complete(napi); /* Clear the halt bit in RSTAT */ gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT); @@ -1748,12 +1874,15 @@ static int gfar_poll(struct napi_struct *napi, int budget) /* Otherwise, clear it */ if (likely(priv->rxcoalescing)) { gfar_write(&priv->regs->rxic, 0); - gfar_write(&priv->regs->rxic, - mk_ic_value(priv->rxcount, priv->rxtime)); + gfar_write(&priv->regs->rxic, priv->rxic); + } + if (likely(priv->txcoalescing)) { + gfar_write(&priv->regs->txic, 0); + gfar_write(&priv->regs->txic, priv->txic); } } - return howmany; + return rx_cleaned; } #ifdef CONFIG_NET_POLL_CONTROLLER @@ -1767,7 +1896,7 @@ static void gfar_netpoll(struct net_device *dev) struct gfar_private *priv = netdev_priv(dev); /* If the device has multiple interrupts, run tx/rx */ - if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { disable_irq(priv->interruptTransmit); disable_irq(priv->interruptReceive); disable_irq(priv->interruptError); @@ -2061,7 +2190,7 @@ static irqreturn_t gfar_error(int irq, void *dev_id) gfar_write(&priv->regs->ievent, events & IEVENT_ERR_MASK); /* Magic Packet is not an error. */ - if ((priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET) && + if ((priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET) && (events & IEVENT_MAG)) events &= ~IEVENT_MAG; @@ -2127,16 +2256,24 @@ static irqreturn_t gfar_error(int irq, void *dev_id) /* work with hotplug and coldplug */ MODULE_ALIAS("platform:fsl-gianfar"); +static struct of_device_id gfar_match[] = +{ + { + .type = "network", + .compatible = "gianfar", + }, + {}, +}; + /* Structure for a device driver */ -static struct platform_driver gfar_driver = { +static struct of_platform_driver gfar_driver = { + .name = "fsl-gianfar", + .match_table = gfar_match, + .probe = gfar_probe, .remove = gfar_remove, .suspend = gfar_suspend, .resume = gfar_resume, - .driver = { - .name = "fsl-gianfar", - .owner = THIS_MODULE, - }, }; static int __init gfar_init(void) @@ -2146,7 +2283,7 @@ static int __init gfar_init(void) if (err) return err; - err = platform_driver_register(&gfar_driver); + err = of_register_platform_driver(&gfar_driver); if (err) gfar_mdio_exit(); @@ -2156,7 +2293,7 @@ static int __init gfar_init(void) static void __exit gfar_exit(void) { - platform_driver_unregister(&gfar_driver); + of_unregister_platform_driver(&gfar_driver); gfar_mdio_exit(); } diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index f46e9b63af134873bca42ec6622ad4701910cc01..b1a83344acc75de952a5b4ed3345448595875d33 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -189,6 +189,18 @@ extern const char gfar_driver_version[]; #define mk_ic_value(count, time) (IC_ICEN | \ mk_ic_icft(count) | \ mk_ic_ictt(time)) +#define get_icft_value(ic) (((unsigned long)ic & IC_ICFT_MASK) >> \ + IC_ICFT_SHIFT) +#define get_ictt_value(ic) ((unsigned long)ic & IC_ICTT_MASK) + +#define DEFAULT_TXIC mk_ic_value(DEFAULT_TXCOUNT, DEFAULT_TXTIME) +#define DEFAULT_RXIC mk_ic_value(DEFAULT_RXCOUNT, DEFAULT_RXTIME) + +#define skip_bd(bdp, stride, base, ring_size) ({ \ + typeof(bdp) new_bd = (bdp) + (stride); \ + (new_bd >= (base) + (ring_size)) ? (new_bd - (ring_size)) : new_bd; }) + +#define next_bd(bdp, base, ring_size) skip_bd(bdp, 1, base, ring_size) #define RCTRL_PAL_MASK 0x001f0000 #define RCTRL_VLEX 0x00002000 @@ -200,8 +212,10 @@ extern const char gfar_driver_version[]; #define RCTRL_PRSDEP_INIT 0x000000c0 #define RCTRL_PROM 0x00000008 #define RCTRL_EMEN 0x00000002 -#define RCTRL_CHECKSUMMING (RCTRL_IPCSEN \ - | RCTRL_TUCSEN | RCTRL_PRSDEP_INIT) +#define RCTRL_REQ_PARSER (RCTRL_VLEX | RCTRL_IPCSEN | \ + RCTRL_TUCSEN) +#define RCTRL_CHECKSUMMING (RCTRL_IPCSEN | RCTRL_TUCSEN | \ + RCTRL_PRSDEP_INIT) #define RCTRL_EXTHASH (RCTRL_GHTX) #define RCTRL_VLAN (RCTRL_PRSDEP_INIT) #define RCTRL_PADDING(x) ((x << 16) & RCTRL_PAL_MASK) @@ -237,7 +251,7 @@ extern const char gfar_driver_version[]; #define IEVENT_FIQ 0x00000004 #define IEVENT_DPE 0x00000002 #define IEVENT_PERR 0x00000001 -#define IEVENT_RX_MASK (IEVENT_RXB0 | IEVENT_RXF0) +#define IEVENT_RX_MASK (IEVENT_RXB0 | IEVENT_RXF0 | IEVENT_BSY) #define IEVENT_TX_MASK (IEVENT_TXB | IEVENT_TXF) #define IEVENT_RTX_MASK (IEVENT_RX_MASK | IEVENT_TX_MASK) #define IEVENT_ERR_MASK \ @@ -297,6 +311,8 @@ extern const char gfar_driver_version[]; #define ATTRELI_EI_MASK 0x00003fff #define ATTRELI_EI(x) (x) +#define BD_LFLAG(flags) ((flags) << 16) +#define BD_LENGTH_MASK 0x00ff /* TxBD status field bits */ #define TXBD_READY 0x8000 @@ -358,10 +374,17 @@ extern const char gfar_driver_version[]; #define RXFCB_PERR_MASK 0x000c #define RXFCB_PERR_BADL3 0x0008 +#define GFAR_INT_NAME_MAX IFNAMSIZ + 4 + struct txbd8 { - u16 status; /* Status Fields */ - u16 length; /* Buffer length */ + union { + struct { + u16 status; /* Status Fields */ + u16 length; /* Buffer length */ + }; + u32 lstatus; + }; u32 bufPtr; /* Buffer Pointer */ }; @@ -376,8 +399,13 @@ struct txfcb { struct rxbd8 { - u16 status; /* Status Fields */ - u16 length; /* Buffer Length */ + union { + struct { + u16 status; /* Status Fields */ + u16 length; /* Buffer Length */ + }; + u32 lstatus; + }; u32 bufPtr; /* Buffer Pointer */ }; @@ -657,6 +685,19 @@ struct gfar { }; +/* Flags related to gianfar device features */ +#define FSL_GIANFAR_DEV_HAS_GIGABIT 0x00000001 +#define FSL_GIANFAR_DEV_HAS_COALESCE 0x00000002 +#define FSL_GIANFAR_DEV_HAS_RMON 0x00000004 +#define FSL_GIANFAR_DEV_HAS_MULTI_INTR 0x00000008 +#define FSL_GIANFAR_DEV_HAS_CSUM 0x00000010 +#define FSL_GIANFAR_DEV_HAS_VLAN 0x00000020 +#define FSL_GIANFAR_DEV_HAS_EXTENDED_HASH 0x00000040 +#define FSL_GIANFAR_DEV_HAS_PADDING 0x00000080 +#define FSL_GIANFAR_DEV_HAS_MAGIC_PACKET 0x00000100 +#define FSL_GIANFAR_DEV_HAS_BD_STASHING 0x00000200 +#define FSL_GIANFAR_DEV_HAS_BUF_STASHING 0x00000400 + /* Struct stolen almost completely (and shamelessly) from the FCC enet source * (Ok, that's not so true anymore, but there is a family resemblence) * The GFAR buffer descriptors track the ring buffers. The rx_bd_base @@ -681,8 +722,7 @@ struct gfar_private { /* Configuration info for the coalescing features */ unsigned char txcoalescing; - unsigned short txcount; - unsigned short txtime; + unsigned long txic; /* Buffer descriptor pointers */ struct txbd8 *tx_bd_base; /* First tx buffer descriptor */ @@ -690,10 +730,12 @@ struct gfar_private { struct txbd8 *dirty_tx; /* First buffer in line to be transmitted */ unsigned int tx_ring_size; + unsigned int num_txbdfree; /* number of TxBDs free */ /* RX Locked fields */ spinlock_t rxlock; + struct device_node *node; struct net_device *dev; struct napi_struct napi; @@ -703,8 +745,7 @@ struct gfar_private { /* RX Coalescing values */ unsigned char rxcoalescing; - unsigned short rxcount; - unsigned short rxtime; + unsigned long rxic; struct rxbd8 *rx_bd_base; /* First Rx buffers */ struct rxbd8 *cur_rx; /* Next free rx ring entry */ @@ -733,8 +774,10 @@ struct gfar_private { /* Bitfield update lock */ spinlock_t bflock; - unsigned char vlan_enable:1, - rx_csum_enable:1, + phy_interface_t interface; + char phy_bus_id[BUS_ID_SIZE]; + u32 device_flags; + unsigned char rx_csum_enable:1, extended_hash:1, bd_stash_en:1, wol_en:1; /* Wake-on-LAN enabled */ @@ -744,11 +787,9 @@ struct gfar_private { unsigned int interruptReceive; unsigned int interruptError; - /* info structure initialized by platform code */ - struct gianfar_platform_data *einfo; - /* PHY stuff */ struct phy_device *phydev; + struct phy_device *tbiphy; struct mii_bus *mii_bus; int oldspeed; int oldduplex; @@ -757,6 +798,11 @@ struct gfar_private { uint32_t msg_enable; struct work_struct reset_task; + + char int_name_tx[GFAR_INT_NAME_MAX]; + char int_name_rx[GFAR_INT_NAME_MAX]; + char int_name_er[GFAR_INT_NAME_MAX]; + /* Network Statistics */ struct gfar_extra_stats extra_stats; }; diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c index fb7d3ccc0fdce8eec47cef3218e39c67746d662f..59b3b5d98efe5bcc746e687b766301e5c6b52720 100644 --- a/drivers/net/gianfar_ethtool.c +++ b/drivers/net/gianfar_ethtool.c @@ -121,7 +121,7 @@ static void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf) { struct gfar_private *priv = netdev_priv(dev); - if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON) + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) memcpy(buf, stat_gstrings, GFAR_STATS_LEN * ETH_GSTRING_LEN); else memcpy(buf, stat_gstrings, @@ -138,7 +138,7 @@ static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, struct gfar_private *priv = netdev_priv(dev); u64 *extra = (u64 *) & priv->extra_stats; - if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON) { + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) { u32 __iomem *rmon = (u32 __iomem *) & priv->regs->rmon; struct gfar_stats *stats = (struct gfar_stats *) buf; @@ -158,7 +158,7 @@ static int gfar_sset_count(struct net_device *dev, int sset) switch (sset) { case ETH_SS_STATS: - if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON) + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) return GFAR_STATS_LEN; else return GFAR_EXTRA_STATS_LEN; @@ -201,8 +201,8 @@ static int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd) if (NULL == phydev) return -ENODEV; - cmd->maxtxpkt = priv->txcount; - cmd->maxrxpkt = priv->rxcount; + cmd->maxtxpkt = get_icft_value(priv->txic); + cmd->maxrxpkt = get_icft_value(priv->rxic); return phy_ethtool_gset(phydev, cmd); } @@ -279,18 +279,26 @@ static unsigned int gfar_ticks2usecs(struct gfar_private *priv, unsigned int tic static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals) { struct gfar_private *priv = netdev_priv(dev); + unsigned long rxtime; + unsigned long rxcount; + unsigned long txtime; + unsigned long txcount; - if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE)) + if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE)) return -EOPNOTSUPP; if (NULL == priv->phydev) return -ENODEV; - cvals->rx_coalesce_usecs = gfar_ticks2usecs(priv, priv->rxtime); - cvals->rx_max_coalesced_frames = priv->rxcount; + rxtime = get_ictt_value(priv->rxic); + rxcount = get_icft_value(priv->rxic); + txtime = get_ictt_value(priv->txic); + txcount = get_icft_value(priv->txic);; + cvals->rx_coalesce_usecs = gfar_ticks2usecs(priv, rxtime); + cvals->rx_max_coalesced_frames = rxcount; - cvals->tx_coalesce_usecs = gfar_ticks2usecs(priv, priv->txtime); - cvals->tx_max_coalesced_frames = priv->txcount; + cvals->tx_coalesce_usecs = gfar_ticks2usecs(priv, txtime); + cvals->tx_max_coalesced_frames = txcount; cvals->use_adaptive_rx_coalesce = 0; cvals->use_adaptive_tx_coalesce = 0; @@ -332,7 +340,7 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals { struct gfar_private *priv = netdev_priv(dev); - if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE)) + if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE)) return -EOPNOTSUPP; /* Set up rx coalescing */ @@ -358,8 +366,9 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals return -EINVAL; } - priv->rxtime = gfar_usecs2ticks(priv, cvals->rx_coalesce_usecs); - priv->rxcount = cvals->rx_max_coalesced_frames; + priv->rxic = mk_ic_value( + gfar_usecs2ticks(priv, cvals->rx_coalesce_usecs), + cvals->rx_max_coalesced_frames); /* Set up tx coalescing */ if ((cvals->tx_coalesce_usecs == 0) || @@ -381,20 +390,17 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals return -EINVAL; } - priv->txtime = gfar_usecs2ticks(priv, cvals->tx_coalesce_usecs); - priv->txcount = cvals->tx_max_coalesced_frames; + priv->txic = mk_ic_value( + gfar_usecs2ticks(priv, cvals->tx_coalesce_usecs), + cvals->tx_max_coalesced_frames); + gfar_write(&priv->regs->rxic, 0); if (priv->rxcoalescing) - gfar_write(&priv->regs->rxic, - mk_ic_value(priv->rxcount, priv->rxtime)); - else - gfar_write(&priv->regs->rxic, 0); + gfar_write(&priv->regs->rxic, priv->rxic); + gfar_write(&priv->regs->txic, 0); if (priv->txcoalescing) - gfar_write(&priv->regs->txic, - mk_ic_value(priv->txcount, priv->txtime)); - else - gfar_write(&priv->regs->txic, 0); + gfar_write(&priv->regs->txic, priv->txic); return 0; } @@ -456,11 +462,12 @@ static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rva spin_lock(&priv->rxlock); gfar_halt(dev); - gfar_clean_rx_ring(dev, priv->rx_ring_size); spin_unlock(&priv->rxlock); spin_unlock_irqrestore(&priv->txlock, flags); + gfar_clean_rx_ring(dev, priv->rx_ring_size); + /* Now we take down the rings to rebuild them */ stop_gfar(dev); } @@ -468,11 +475,13 @@ static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rva /* Change the size */ priv->rx_ring_size = rvals->rx_pending; priv->tx_ring_size = rvals->tx_pending; + priv->num_txbdfree = priv->tx_ring_size; /* Rebuild the rings with the new size */ - if (dev->flags & IFF_UP) + if (dev->flags & IFF_UP) { err = startup_gfar(dev); - + netif_wake_queue(dev); + } return err; } @@ -482,7 +491,7 @@ static int gfar_set_rx_csum(struct net_device *dev, uint32_t data) unsigned long flags; int err = 0; - if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM)) + if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM)) return -EOPNOTSUPP; if (dev->flags & IFF_UP) { @@ -492,11 +501,12 @@ static int gfar_set_rx_csum(struct net_device *dev, uint32_t data) spin_lock(&priv->rxlock); gfar_halt(dev); - gfar_clean_rx_ring(dev, priv->rx_ring_size); spin_unlock(&priv->rxlock); spin_unlock_irqrestore(&priv->txlock, flags); + gfar_clean_rx_ring(dev, priv->rx_ring_size); + /* Now we take down the rings to rebuild them */ stop_gfar(dev); } @@ -505,9 +515,10 @@ static int gfar_set_rx_csum(struct net_device *dev, uint32_t data) priv->rx_csum_enable = data; spin_unlock_irqrestore(&priv->bflock, flags); - if (dev->flags & IFF_UP) + if (dev->flags & IFF_UP) { err = startup_gfar(dev); - + netif_wake_queue(dev); + } return err; } @@ -515,7 +526,7 @@ static uint32_t gfar_get_rx_csum(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); - if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM)) + if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM)) return 0; return priv->rx_csum_enable; @@ -523,22 +534,19 @@ static uint32_t gfar_get_rx_csum(struct net_device *dev) static int gfar_set_tx_csum(struct net_device *dev, uint32_t data) { - unsigned long flags; struct gfar_private *priv = netdev_priv(dev); - if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM)) + if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM)) return -EOPNOTSUPP; - spin_lock_irqsave(&priv->txlock, flags); - gfar_halt(dev); + netif_tx_lock_bh(dev); if (data) dev->features |= NETIF_F_IP_CSUM; else dev->features &= ~NETIF_F_IP_CSUM; - gfar_start(dev); - spin_unlock_irqrestore(&priv->txlock, flags); + netif_tx_unlock_bh(dev); return 0; } @@ -547,7 +555,7 @@ static uint32_t gfar_get_tx_csum(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); - if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM)) + if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM)) return 0; return (dev->features & NETIF_F_IP_CSUM) != 0; @@ -570,7 +578,7 @@ static void gfar_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { struct gfar_private *priv = netdev_priv(dev); - if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET) { + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET) { wol->supported = WAKE_MAGIC; wol->wolopts = priv->wol_en ? WAKE_MAGIC : 0; } else { @@ -583,7 +591,7 @@ static int gfar_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) struct gfar_private *priv = netdev_priv(dev); unsigned long flags; - if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET) && + if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET) && wol->wolopts != 0) return -EINVAL; @@ -616,6 +624,7 @@ const struct ethtool_ops gfar_ethtool_ops = { .get_tx_csum = gfar_get_tx_csum, .set_rx_csum = gfar_set_rx_csum, .set_tx_csum = gfar_set_tx_csum, + .set_sg = ethtool_op_set_sg, .get_msglevel = gfar_get_msglevel, .set_msglevel = gfar_set_msglevel, #ifdef CONFIG_PM diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c index 0e2595d24933cd8f6549153782d87010672ee2d7..f3706e415b45323e8de205581b6ed4a57e8ea51b 100644 --- a/drivers/net/gianfar_mii.c +++ b/drivers/net/gianfar_mii.c @@ -34,6 +34,8 @@ #include #include #include +#include +#include #include #include @@ -150,19 +152,83 @@ static int gfar_mdio_reset(struct mii_bus *bus) return 0; } +/* Allocate an array which provides irq #s for each PHY on the given bus */ +static int *create_irq_map(struct device_node *np) +{ + int *irqs; + int i; + struct device_node *child = NULL; + + irqs = kcalloc(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL); + + if (!irqs) + return NULL; + + for (i = 0; i < PHY_MAX_ADDR; i++) + irqs[i] = PHY_POLL; + + while ((child = of_get_next_child(np, child)) != NULL) { + int irq = irq_of_parse_and_map(child, 0); + const u32 *id; + + if (irq == NO_IRQ) + continue; + + id = of_get_property(child, "reg", NULL); + + if (!id) + continue; + + if (*id < PHY_MAX_ADDR && *id >= 0) + irqs[*id] = irq; + else + printk(KERN_WARNING "%s: " + "%d is not a valid PHY address\n", + np->full_name, *id); + } + + return irqs; +} + + +void gfar_mdio_bus_name(char *name, struct device_node *np) +{ + const u32 *reg; + + reg = of_get_property(np, "reg", NULL); -static int gfar_mdio_probe(struct device *dev) + snprintf(name, MII_BUS_ID_SIZE, "%s@%x", np->name, reg ? *reg : 0); +} + +/* Scan the bus in reverse, looking for an empty spot */ +static int gfar_mdio_find_free(struct mii_bus *new_bus) +{ + int i; + + for (i = PHY_MAX_ADDR; i > 0; i--) { + u32 phy_id; + + if (get_phy_id(new_bus, i, &phy_id)) + return -1; + + if (phy_id == 0xffffffff) + break; + } + + return i; +} + +static int gfar_mdio_probe(struct of_device *ofdev, + const struct of_device_id *match) { - struct platform_device *pdev = to_platform_device(dev); - struct gianfar_mdio_data *pdata; struct gfar_mii __iomem *regs; struct gfar __iomem *enet_regs; struct mii_bus *new_bus; - struct resource *r; - int i, err = 0; - - if (NULL == dev) - return -EINVAL; + int err = 0; + u64 addr, size; + struct device_node *np = ofdev->node; + struct device_node *tbi; + int tbiaddr = -1; new_bus = mdiobus_alloc(); if (NULL == new_bus) @@ -172,31 +238,28 @@ static int gfar_mdio_probe(struct device *dev) new_bus->read = &gfar_mdio_read, new_bus->write = &gfar_mdio_write, new_bus->reset = &gfar_mdio_reset, - snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", pdev->id); - - pdata = (struct gianfar_mdio_data *)pdev->dev.platform_data; - - if (NULL == pdata) { - printk(KERN_ERR "gfar mdio %d: Missing platform data!\n", pdev->id); - return -ENODEV; - } - - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + gfar_mdio_bus_name(new_bus->id, np); /* Set the PHY base address */ - regs = ioremap(r->start, sizeof (struct gfar_mii)); + addr = of_translate_address(np, of_get_address(np, 0, &size, NULL)); + regs = ioremap(addr, size); if (NULL == regs) { err = -ENOMEM; - goto reg_map_fail; + goto err_free_bus; } new_bus->priv = (void __force *)regs; - new_bus->irq = pdata->irq; + new_bus->irq = create_irq_map(np); + + if (new_bus->irq == NULL) { + err = -ENOMEM; + goto err_unmap_regs; + } - new_bus->parent = dev; - dev_set_drvdata(dev, new_bus); + new_bus->parent = &ofdev->dev; + dev_set_drvdata(&ofdev->dev, new_bus); /* * This is mildly evil, but so is our hardware for doing this. @@ -206,96 +269,109 @@ static int gfar_mdio_probe(struct device *dev) enet_regs = (struct gfar __iomem *) ((char *)regs - offsetof(struct gfar, gfar_mii_regs)); - /* Scan the bus, looking for an empty spot for TBIPA */ - gfar_write(&enet_regs->tbipa, 0); - for (i = PHY_MAX_ADDR; i > 0; i--) { - u32 phy_id; + for_each_child_of_node(np, tbi) { + if (!strncmp(tbi->type, "tbi-phy", 8)) + break; + } - err = get_phy_id(new_bus, i, &phy_id); - if (err) - goto bus_register_fail; + if (tbi) { + const u32 *prop = of_get_property(tbi, "reg", NULL); - if (phy_id == 0xffffffff) - break; + if (prop) + tbiaddr = *prop; } - /* The bus is full. We don't support using 31 PHYs, sorry */ - if (i == 0) { + if (tbiaddr == -1) { + gfar_write(&enet_regs->tbipa, 0); + + tbiaddr = gfar_mdio_find_free(new_bus); + } + + /* + * We define TBIPA at 0 to be illegal, opting to fail for boards that + * have PHYs at 1-31, rather than change tbipa and rescan. + */ + if (tbiaddr == 0) { err = -EBUSY; - goto bus_register_fail; + goto err_free_irqs; } - gfar_write(&enet_regs->tbipa, i); + gfar_write(&enet_regs->tbipa, tbiaddr); + + /* + * The TBIPHY-only buses will find PHYs at every address, + * so we mask them all but the TBI + */ + if (!of_device_is_compatible(np, "fsl,gianfar-mdio")) + new_bus->phy_mask = ~(1 << tbiaddr); err = mdiobus_register(new_bus); - if (0 != err) { + if (err != 0) { printk (KERN_ERR "%s: Cannot register as MDIO bus\n", new_bus->name); - goto bus_register_fail; + goto err_free_irqs; } return 0; -bus_register_fail: +err_free_irqs: + kfree(new_bus->irq); +err_unmap_regs: iounmap(regs); -reg_map_fail: +err_free_bus: mdiobus_free(new_bus); return err; } -static int gfar_mdio_remove(struct device *dev) +static int gfar_mdio_remove(struct of_device *ofdev) { - struct mii_bus *bus = dev_get_drvdata(dev); + struct mii_bus *bus = dev_get_drvdata(&ofdev->dev); mdiobus_unregister(bus); - dev_set_drvdata(dev, NULL); + dev_set_drvdata(&ofdev->dev, NULL); iounmap((void __iomem *)bus->priv); bus->priv = NULL; + kfree(bus->irq); mdiobus_free(bus); return 0; } -static struct device_driver gianfar_mdio_driver = { +static struct of_device_id gfar_mdio_match[] = +{ + { + .compatible = "fsl,gianfar-mdio", + }, + { + .compatible = "fsl,gianfar-tbi", + }, + { + .type = "mdio", + .compatible = "gianfar", + }, + {}, +}; + +static struct of_platform_driver gianfar_mdio_driver = { .name = "fsl-gianfar_mdio", - .bus = &platform_bus_type, + .match_table = gfar_mdio_match, + .probe = gfar_mdio_probe, .remove = gfar_mdio_remove, }; -static int match_mdio_bus(struct device *dev, void *data) -{ - const struct gfar_private *priv = data; - const struct platform_device *pdev = to_platform_device(dev); - - return !strcmp(pdev->name, gianfar_mdio_driver.name) && - pdev->id == priv->einfo->mdio_bus; -} - -/* Given a gfar_priv structure, find the mii_bus controlled by this device (not - * necessarily the same as the bus the gfar's PHY is on), if one exists. - * Normally only the first gianfar controls a mii_bus. */ -struct mii_bus *gfar_get_miibus(const struct gfar_private *priv) -{ - /*const*/ struct device *d; - - d = bus_find_device(gianfar_mdio_driver.bus, NULL, (void *)priv, - match_mdio_bus); - return d ? dev_get_drvdata(d) : NULL; -} - int __init gfar_mdio_init(void) { - return driver_register(&gianfar_mdio_driver); + return of_register_platform_driver(&gianfar_mdio_driver); } void gfar_mdio_exit(void) { - driver_unregister(&gianfar_mdio_driver); + of_unregister_platform_driver(&gianfar_mdio_driver); } diff --git a/drivers/net/gianfar_mii.h b/drivers/net/gianfar_mii.h index 02dc970ca1ffb25e79c63c6205a46c0fceafdcfa..65c242cd468aca22bed0dba1484a3f38d1d98a07 100644 --- a/drivers/net/gianfar_mii.h +++ b/drivers/net/gianfar_mii.h @@ -49,4 +49,6 @@ int gfar_local_mdio_read(struct gfar_mii __iomem *regs, int mii_id, int regnum); struct mii_bus *gfar_get_miibus(const struct gfar_private *priv); int __init gfar_mdio_init(void); void gfar_mdio_exit(void); + +void gfar_mdio_bus_name(char *name, struct device_node *np); #endif /* GIANFAR_PHY_H */ diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index 3199526bcecbab3f879f9cd56507c570305a8c2f..32200227c9236ea22fb791992531353ab0a729c4 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -568,6 +568,19 @@ static void set_rx_mode(struct net_device *dev); static const struct ethtool_ops ethtool_ops; static const struct ethtool_ops ethtool_ops_no_mii; +static const struct net_device_ops hamachi_netdev_ops = { + .ndo_open = hamachi_open, + .ndo_stop = hamachi_close, + .ndo_start_xmit = hamachi_start_xmit, + .ndo_get_stats = hamachi_get_stats, + .ndo_set_multicast_list = set_rx_mode, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_tx_timeout = hamachi_tx_timeout, + .ndo_do_ioctl = netdev_ioctl, +}; + + static int __devinit hamachi_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -582,7 +595,6 @@ static int __devinit hamachi_init_one (struct pci_dev *pdev, void *ring_space; dma_addr_t ring_dma; int ret = -ENOMEM; - DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -723,17 +735,11 @@ static int __devinit hamachi_init_one (struct pci_dev *pdev, /* The Hamachi-specific entries in the device structure. */ - dev->open = &hamachi_open; - dev->hard_start_xmit = &hamachi_start_xmit; - dev->stop = &hamachi_close; - dev->get_stats = &hamachi_get_stats; - dev->set_multicast_list = &set_rx_mode; - dev->do_ioctl = &netdev_ioctl; + dev->netdev_ops = &hamachi_netdev_ops; if (chip_tbl[hmp->chip_id].flags & CanHaveMII) SET_ETHTOOL_OPS(dev, ðtool_ops); else SET_ETHTOOL_OPS(dev, ðtool_ops_no_mii); - dev->tx_timeout = &hamachi_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; if (mtu) dev->mtu = mtu; @@ -744,9 +750,9 @@ static int __devinit hamachi_init_one (struct pci_dev *pdev, goto err_out_unmap_rx; } - printk(KERN_INFO "%s: %s type %x at %p, %s, IRQ %d.\n", + printk(KERN_INFO "%s: %s type %x at %p, %pM, IRQ %d.\n", dev->name, chip_tbl[chip_id].name, readl(ioaddr + ChipRev), - ioaddr, print_mac(mac, dev->dev_addr), irq); + ioaddr, dev->dev_addr, irq); i = readb(ioaddr + PCIClkMeas); printk(KERN_INFO "%s: %d-bit %d Mhz PCI bus (%d), Virtual Jumpers " "%2.2x, LPA %4.4x.\n", @@ -1646,7 +1652,6 @@ static int hamachi_rx(struct net_device *dev) #endif /* RX_CHECKSUM */ netif_rx(skb); - dev->last_rx = jiffies; hmp->stats.rx_packets++; } entry = (++hmp->cur_rx) % RX_RING_SIZE; diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 0f501d2ca93560553bed346b225cc53793b5e17a..50f1e172ee8f9556a09e7fbdb1ab05f69c09f74e 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -373,7 +373,6 @@ static void sp_bump(struct sixpack *sp, char cmd) memcpy(ptr, sp->cooked_buf + 1, count); skb->protocol = ax25_type_trans(skb, sp->dev); netif_rx(skb); - sp->dev->last_rx = jiffies; sp->dev->stats.rx_packets++; return; diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c index 00bc7fbb6b374687ebd45f79a84cee5ad472bcaa..81a65e3a1c053fe070e9a3c8985ef6f909439801 100644 --- a/drivers/net/hamradio/baycom_epp.c +++ b/drivers/net/hamradio/baycom_epp.c @@ -555,7 +555,6 @@ static void do_rxpacket(struct net_device *dev) memcpy(cp, bc->hdlcrx.buf, pktlen - 1); skb->protocol = ax25_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; bc->stats.rx_packets++; } diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index 58f4b1d7bf1fc303d5b962b9820aa423c943168b..46f8f3390e7d1806c038f791f0f103c744c09830 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -230,7 +230,6 @@ static int bpq_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_ty skb->protocol = ax25_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; unlock: rcu_read_unlock(); @@ -441,16 +440,15 @@ static int bpq_seq_show(struct seq_file *seq, void *v) "dev ether destination accept from\n"); else { const struct bpqdev *bpqdev = v; - DECLARE_MAC_BUF(mac); - seq_printf(seq, "%-5s %-10s %s ", + seq_printf(seq, "%-5s %-10s %pM ", bpqdev->axdev->name, bpqdev->ethdev->name, - print_mac(mac, bpqdev->dest_addr)); + bpqdev->dest_addr); if (is_multicast_ether_addr(bpqdev->acpt_addr)) seq_printf(seq, "*\n"); else - seq_printf(seq, "%s\n", print_mac(mac, bpqdev->acpt_addr)); + seq_printf(seq, "%pM\n", bpqdev->acpt_addr); } return 0; diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c index e8cfadefa4b6751dbb74bd663a0f101e76a98d54..e67103396ed7649b32a331e7f4d9fc341f6dc206 100644 --- a/drivers/net/hamradio/dmascc.c +++ b/drivers/net/hamradio/dmascc.c @@ -572,7 +572,7 @@ static int __init setup_adapter(int card_base, int type, int n) priv->param.persist = 256; priv->param.dma = -1; INIT_WORK(&priv->rx_work, rx_bh); - dev->priv = priv; + dev->ml_priv = priv; sprintf(dev->name, "dmascc%i", 2 * n + i); dev->base_addr = card_base; dev->irq = irq; @@ -720,7 +720,7 @@ static int read_scc_data(struct scc_priv *priv) static int scc_open(struct net_device *dev) { - struct scc_priv *priv = dev->priv; + struct scc_priv *priv = dev->ml_priv; struct scc_info *info = priv->info; int card_base = priv->card_base; @@ -862,7 +862,7 @@ static int scc_open(struct net_device *dev) static int scc_close(struct net_device *dev) { - struct scc_priv *priv = dev->priv; + struct scc_priv *priv = dev->ml_priv; struct scc_info *info = priv->info; int card_base = priv->card_base; @@ -891,7 +891,7 @@ static int scc_close(struct net_device *dev) static int scc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - struct scc_priv *priv = dev->priv; + struct scc_priv *priv = dev->ml_priv; switch (cmd) { case SIOCGSCCPARAM: @@ -918,7 +918,7 @@ static int scc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) static int scc_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct scc_priv *priv = dev->priv; + struct scc_priv *priv = dev->ml_priv; unsigned long flags; int i; @@ -963,7 +963,7 @@ static int scc_send_packet(struct sk_buff *skb, struct net_device *dev) static struct net_device_stats *scc_get_stats(struct net_device *dev) { - struct scc_priv *priv = dev->priv; + struct scc_priv *priv = dev->ml_priv; return &priv->stats; } @@ -1283,7 +1283,6 @@ static void rx_bh(struct work_struct *ugli_api) memcpy(&data[1], priv->rx_buf[i], cb); skb->protocol = ax25_type_trans(skb, priv->dev); netif_rx(skb); - priv->dev->last_rx = jiffies; priv->stats.rx_packets++; priv->stats.rx_bytes += cb; } diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c index c258a0586e611d641c134f53114c76df0025ec66..8eba61a1d4abc3ff7365b08d33f4d70c2d368819 100644 --- a/drivers/net/hamradio/hdlcdrv.c +++ b/drivers/net/hamradio/hdlcdrv.c @@ -162,7 +162,6 @@ static void hdlc_rx_flag(struct net_device *dev, struct hdlcdrv_state *s) memcpy(cp, s->hdlcrx.buffer, pkt_len - 1); skb->protocol = ax25_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; s->stats.rx_packets++; } diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index b8e25c4624d2c2db3d6e84bb90e7b7cd55261a6e..bbdb311b8420c6cd500a60d8293132d7e67b3059 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -303,7 +303,6 @@ static void ax_bump(struct mkiss *ax) memcpy(skb_put(skb,count), ax->rbuff, count); skb->protocol = ax25_type_trans(skb, ax->dev); netif_rx(skb); - ax->dev->last_rx = jiffies; ax->stats.rx_packets++; ax->stats.rx_bytes += count; spin_unlock_bh(&ax->buflock); @@ -847,12 +846,13 @@ static int mkiss_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { struct mkiss *ax = mkiss_get(tty); - struct net_device *dev = ax->dev; + struct net_device *dev; unsigned int tmp, err; /* First make sure we're connected. */ if (ax == NULL) return -ENXIO; + dev = ax->dev; switch (cmd) { case SIOCGIFNAME: diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index c17e39bc546007cda47673ead55580e4e6b22357..c011af7088ea41cfb06325c02b6847addafed2bd 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -1518,7 +1518,7 @@ static int scc_net_alloc(const char *name, struct scc_channel *scc) if (!dev) return -ENOMEM; - dev->priv = scc; + dev->ml_priv = scc; scc->dev = dev; spin_lock_init(&scc->lock); init_timer(&scc->tx_t); @@ -1575,7 +1575,7 @@ static void scc_net_setup(struct net_device *dev) static int scc_net_open(struct net_device *dev) { - struct scc_channel *scc = (struct scc_channel *) dev->priv; + struct scc_channel *scc = (struct scc_channel *) dev->ml_priv; if (!scc->init) return -EINVAL; @@ -1593,7 +1593,7 @@ static int scc_net_open(struct net_device *dev) static int scc_net_close(struct net_device *dev) { - struct scc_channel *scc = (struct scc_channel *) dev->priv; + struct scc_channel *scc = (struct scc_channel *) dev->ml_priv; unsigned long flags; netif_stop_queue(dev); @@ -1627,7 +1627,6 @@ static void scc_net_rx(struct scc_channel *scc, struct sk_buff *skb) skb->protocol = ax25_type_trans(skb, scc->dev); netif_rx(skb); - scc->dev->last_rx = jiffies; return; } @@ -1635,7 +1634,7 @@ static void scc_net_rx(struct scc_channel *scc, struct sk_buff *skb) static int scc_net_tx(struct sk_buff *skb, struct net_device *dev) { - struct scc_channel *scc = (struct scc_channel *) dev->priv; + struct scc_channel *scc = (struct scc_channel *) dev->ml_priv; unsigned long flags; char kisscmd; @@ -1705,7 +1704,7 @@ static int scc_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) struct scc_mem_config memcfg; struct scc_hw_config hwcfg; struct scc_calibrate cal; - struct scc_channel *scc = (struct scc_channel *) dev->priv; + struct scc_channel *scc = (struct scc_channel *) dev->ml_priv; int chan; unsigned char device_name[IFNAMSIZ]; void __user *arg = ifr->ifr_data; @@ -1952,7 +1951,7 @@ static int scc_net_set_mac_address(struct net_device *dev, void *addr) static struct net_device_stats *scc_net_get_stats(struct net_device *dev) { - struct scc_channel *scc = (struct scc_channel *) dev->priv; + struct scc_channel *scc = (struct scc_channel *) dev->ml_priv; scc->dev_stat.rx_errors = scc->stat.rxerrs + scc->stat.rx_over; scc->dev_stat.tx_errors = scc->stat.txerrs + scc->stat.tx_under; diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c index 1c942862a3f4944710de74c546cba66943b8b81a..5407f7486c9c00cdc310962e237284897eac9113 100644 --- a/drivers/net/hamradio/yam.c +++ b/drivers/net/hamradio/yam.c @@ -515,7 +515,6 @@ static inline void yam_rx_flag(struct net_device *dev, struct yam_port *yp) memcpy(cp, yp->rx_buf, pkt_len - 1); skb->protocol = ax25_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; ++yp->stats.rx_packets; } } diff --git a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c index c01e290d09d28b7e9c1fb240a26a9ba6f92e0900..b507dbc16e62adc5dfb8eaf3b8bfc66ed86b9a95 100644 --- a/drivers/net/hp-plus.c +++ b/drivers/net/hp-plus.c @@ -158,6 +158,21 @@ struct net_device * __init hp_plus_probe(int unit) } #endif +static const struct net_device_ops hpp_netdev_ops = { + .ndo_open = hpp_open, + .ndo_stop = hpp_close, + .ndo_start_xmit = eip_start_xmit, + .ndo_tx_timeout = eip_tx_timeout, + .ndo_get_stats = eip_get_stats, + .ndo_set_multicast_list = eip_set_multicast_list, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = eip_poll, +#endif +}; + + /* Do the interesting part of the probe at a single address. */ static int __init hpp_probe1(struct net_device *dev, int ioaddr) { @@ -166,7 +181,6 @@ static int __init hpp_probe1(struct net_device *dev, int ioaddr) const char name[] = "HP-PC-LAN+"; int mem_start; static unsigned version_printed; - DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, HP_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -193,7 +207,7 @@ static int __init hpp_probe1(struct net_device *dev, int ioaddr) } checksum += inb(ioaddr + 14); - printk("%s", print_mac(mac, dev->dev_addr)); + printk("%pM", dev->dev_addr); if (checksum != 0xff) { printk(" bad checksum %2.2x.\n", checksum); @@ -227,11 +241,7 @@ static int __init hpp_probe1(struct net_device *dev, int ioaddr) /* Set the base address to point to the NIC, not the "real" base! */ dev->base_addr = ioaddr + NIC_OFFSET; - dev->open = &hpp_open; - dev->stop = &hpp_close; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = eip_poll; -#endif + dev->netdev_ops = &hpp_netdev_ops; ei_status.name = name; ei_status.word16 = 0; /* Agggghhhhh! Debug time: 2 days! */ @@ -302,8 +312,7 @@ hpp_open(struct net_device *dev) /* Select the operational page. */ outw(Perf_Page, ioaddr + HP_PAGING); - eip_open(dev); - return 0; + return eip_open(dev); } static int diff --git a/drivers/net/hp.c b/drivers/net/hp.c index 0a8c64930ad305fc756d0dfb7addffff50d406a2..5c4d78c1ff42ae87db44d8dd5f72c32b9a6867e4 100644 --- a/drivers/net/hp.c +++ b/drivers/net/hp.c @@ -59,8 +59,6 @@ static unsigned int hppclan_portlist[] __initdata = static int hp_probe1(struct net_device *dev, int ioaddr); -static int hp_open(struct net_device *dev); -static int hp_close(struct net_device *dev); static void hp_reset_8390(struct net_device *dev); static void hp_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page); @@ -127,7 +125,6 @@ static int __init hp_probe1(struct net_device *dev, int ioaddr) int i, retval, board_id, wordmode; const char *name; static unsigned version_printed; - DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, HP_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -161,7 +158,7 @@ static int __init hp_probe1(struct net_device *dev, int ioaddr) for(i = 0; i < ETHER_ADDR_LEN; i++) dev->dev_addr[i] = inb(ioaddr + i); - printk(" %s", print_mac(mac, dev->dev_addr)); + printk(" %pM", dev->dev_addr); /* Snarf the interrupt now. Someday this could be moved to open(). */ if (dev->irq < 2) { @@ -199,11 +196,7 @@ static int __init hp_probe1(struct net_device *dev, int ioaddr) /* Set the base address to point to the NIC, not the "real" base! */ dev->base_addr = ioaddr + NIC_OFFSET; - dev->open = &hp_open; - dev->stop = &hp_close; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = eip_poll; -#endif + dev->netdev_ops = &eip_netdev_ops; ei_status.name = name; ei_status.word16 = wordmode; @@ -228,20 +221,6 @@ static int __init hp_probe1(struct net_device *dev, int ioaddr) return retval; } -static int -hp_open(struct net_device *dev) -{ - eip_open(dev); - return 0; -} - -static int -hp_close(struct net_device *dev) -{ - eip_close(dev); - return 0; -} - static void hp_reset_8390(struct net_device *dev) { diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index 571dd80fb85009910f6a49d3cda27baa085b54f1..ebe7651fcb863b6f560cd533fc0b09b97050fcf7 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -1212,7 +1212,7 @@ static int hp100_init_rxpdl(struct net_device *dev, *(pdlptr + 2) = (u_int) virt_to_whatever(dev, pdlptr); /* Address Frag 1 */ *(pdlptr + 3) = 4; /* Length Frag 1 */ - return ((((MAX_RX_FRAG * 2 + 2) + 3) / 4) * 4); + return roundup(MAX_RX_FRAG * 2 + 2, 4); } @@ -1227,7 +1227,7 @@ static int hp100_init_txpdl(struct net_device *dev, ringptr->pdl_paddr = virt_to_whatever(dev, pdlptr); /* +1 */ ringptr->skb = (void *) NULL; - return ((((MAX_TX_FRAG * 2 + 2) + 3) / 4) * 4); + return roundup(MAX_TX_FRAG * 2 + 2, 4); } /* @@ -1256,7 +1256,7 @@ static int hp100_build_rx_pdl(hp100_ring_t * ringptr, /* Note: This depends on the alloc_skb functions allocating more * space than requested, i.e. aligning to 16bytes */ - ringptr->skb = dev_alloc_skb(((MAX_ETHER_SIZE + 2 + 3) / 4) * 4); + ringptr->skb = dev_alloc_skb(roundup(MAX_ETHER_SIZE + 2, 4)); if (NULL != ringptr->skb) { /* @@ -1279,7 +1279,7 @@ static int hp100_build_rx_pdl(hp100_ring_t * ringptr, #ifdef HP100_DEBUG_BM printk("hp100: %s: build_rx_pdl: PDH@0x%x, skb->data (len %d) at 0x%x\n", dev->name, (u_int) ringptr->pdl, - ((MAX_ETHER_SIZE + 2 + 3) / 4) * 4, + roundup(MAX_ETHER_SIZE + 2, 4), (unsigned int) ringptr->skb->data); #endif @@ -1834,7 +1834,6 @@ static void hp100_rx(struct net_device *dev) ptr[9], ptr[10], ptr[11]); #endif netif_rx(skb); - dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes += pkt_len; } @@ -1925,7 +1924,6 @@ static void hp100_rx_bm(struct net_device *dev) netif_rx(ptr->skb); /* Up and away... */ - dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes += pkt_len; } @@ -2093,9 +2091,8 @@ static void hp100_set_multicast_list(struct net_device *dev) addrs = dmi->dmi_addr; if ((*addrs & 0x01) == 0x01) { /* multicast address? */ #ifdef HP100_DEBUG - DECLARE_MAC_BUF(mac); - printk("hp100: %s: multicast = %s, ", - dev->name, print_mac(mac, addrs)); + printk("hp100: %s: multicast = %pM, ", + dev->name, addrs); #endif for (j = idx = 0; j < 6; j++) { idx ^= *addrs++ & 0x3f; @@ -3057,12 +3054,3 @@ static void __exit hp100_module_exit(void) module_init(hp100_module_init) module_exit(hp100_module_exit) - - -/* - * Local variables: - * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c hp100.c" - * c-indent-level: 2 - * tab-width: 8 - * End: - */ diff --git a/drivers/net/hydra.c b/drivers/net/hydra.c index b96cf2dcb10932bf7a6758fcd399dba1385b50f1..9cb38a8d4387b8f20f213ebf3d6d9f15361c3a2d 100644 --- a/drivers/net/hydra.c +++ b/drivers/net/hydra.c @@ -94,6 +94,21 @@ static int __devinit hydra_init_one(struct zorro_dev *z, return 0; } +static const struct net_device_ops hydra_netdev_ops = { + .ndo_open = hydra_open, + .ndo_stop = hydra_close, + + .ndo_start_xmit = ei_start_xmit, + .ndo_tx_timeout = ei_tx_timeout, + .ndo_get_stats = ei_get_stats, + .ndo_set_multicast_list = ei_set_multicast_list, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = ei_poll, +#endif +}; + static int __devinit hydra_init(struct zorro_dev *z) { struct net_device *dev; @@ -103,14 +118,13 @@ static int __devinit hydra_init(struct zorro_dev *z) int start_page, stop_page; int j; int err; - DECLARE_MAC_BUF(mac); static u32 hydra_offsets[16] = { 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, }; - dev = ____alloc_ei_netdev(0); + dev = alloc_ei_netdev(); if (!dev) return -ENOMEM; @@ -145,12 +159,8 @@ static int __devinit hydra_init(struct zorro_dev *z) ei_status.block_output = &hydra_block_output; ei_status.get_8390_hdr = &hydra_get_8390_hdr; ei_status.reg_offset = hydra_offsets; - dev->open = &hydra_open; - dev->stop = &hydra_close; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = __ei_poll; -#endif + dev->netdev_ops = &hydra_netdev_ops; __NS8390_init(dev, 0); err = register_netdev(dev); @@ -163,8 +173,8 @@ static int __devinit hydra_init(struct zorro_dev *z) zorro_set_drvdata(z, dev); printk(KERN_INFO "%s: Hydra at 0x%08lx, address " - "%s (hydra.c " HYDRA_VERSION ")\n", - dev->name, z->resource.start, print_mac(mac, dev->dev_addr)); + "%pM (hydra.c " HYDRA_VERSION ")\n", + dev->name, z->resource.start, dev->dev_addr); return 0; } diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index 901212aa37cbf7a55be095d372b47865d9ebb1df..87a706694fb35f6519e4933944b06df429849d48 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c @@ -396,9 +396,7 @@ static void emac_hash_mc(struct emac_instance *dev) for (dmi = dev->ndev->mc_list; dmi; dmi = dmi->next) { int slot, reg, mask; - DBG2(dev, "mc %02x:%02x:%02x:%02x:%02x:%02x" NL, - dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2], - dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5]); + DBG2(dev, "mc %pM" NL, dmi->dmi_addr); slot = EMAC_XAHT_CRC_TO_SLOT(dev, ether_crc(ETH_ALEN, dmi->dmi_addr)); reg = EMAC_XAHT_SLOT_TO_REG(dev, slot); @@ -2865,11 +2863,8 @@ static int __devinit emac_probe(struct of_device *ofdev, wake_up_all(&emac_probe_wait); - printk(KERN_INFO - "%s: EMAC-%d %s, MAC %02x:%02x:%02x:%02x:%02x:%02x\n", - ndev->name, dev->cell_index, np->full_name, - ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2], - ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]); + printk(KERN_INFO "%s: EMAC-%d %s, MAC %pM\n", + ndev->name, dev->cell_index, np->full_name, ndev->dev_addr); if (dev->phy_mode == PHY_MODE_SGMII) printk(KERN_NOTICE "%s: in SGMII mode\n", ndev->name); diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c index f02764725a221fdde54b43ea9be1e7d65c8e8b75..5b5bf9f9861ac2f63ef8f9db6bca6cfd945fba34 100644 --- a/drivers/net/ibmlana.c +++ b/drivers/net/ibmlana.c @@ -605,7 +605,6 @@ static void irqrx_handler(struct net_device *dev) skb->ip_summed = CHECKSUM_NONE; /* bookkeeping */ - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += rda.length; @@ -914,7 +913,6 @@ static int __devinit ibmlana_init_one(struct device *kdev) int base = 0, irq = 0, iobase = 0, memlen = 0; ibmlana_priv *priv; ibmlana_medium medium; - DECLARE_MAC_BUF(mac); dev = alloc_etherdev(sizeof(ibmlana_priv)); if (!dev) @@ -990,10 +988,10 @@ static int __devinit ibmlana_init_one(struct device *kdev) /* print config */ printk(KERN_INFO "%s: IRQ %d, I/O %#lx, memory %#lx-%#lx, " - "MAC address %s.\n", + "MAC address %pM.\n", dev->name, priv->realirq, dev->base_addr, dev->mem_start, dev->mem_end - 1, - print_mac(mac, dev->dev_addr)); + dev->dev_addr); printk(KERN_INFO "%s: %s medium\n", dev->name, MediaNames[priv->medium]); /* reset board */ diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index c2d57f836088c4ba38955de02a5ecd9408f478f8..9bc0f178f24bfb9ff88e92ec937e19e5e9e2f47e 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -527,7 +527,7 @@ static int ibmveth_register_logical_lan(struct ibmveth_adapter *adapter, static int ibmveth_open(struct net_device *netdev) { - struct ibmveth_adapter *adapter = netdev->priv; + struct ibmveth_adapter *adapter = netdev_priv(netdev); u64 mac_address = 0; int rxq_entries = 1; unsigned long lpar_rc; @@ -666,7 +666,7 @@ static int ibmveth_open(struct net_device *netdev) static int ibmveth_close(struct net_device *netdev) { - struct ibmveth_adapter *adapter = netdev->priv; + struct ibmveth_adapter *adapter = netdev_priv(netdev); long lpar_rc; ibmveth_debug_printk("close starting\n"); @@ -722,7 +722,7 @@ static u32 netdev_get_link(struct net_device *dev) { static void ibmveth_set_rx_csum_flags(struct net_device *dev, u32 data) { - struct ibmveth_adapter *adapter = dev->priv; + struct ibmveth_adapter *adapter = netdev_priv(dev); if (data) adapter->rx_csum = 1; @@ -741,7 +741,7 @@ static void ibmveth_set_rx_csum_flags(struct net_device *dev, u32 data) static void ibmveth_set_tx_csum_flags(struct net_device *dev, u32 data) { - struct ibmveth_adapter *adapter = dev->priv; + struct ibmveth_adapter *adapter = netdev_priv(dev); if (data) { dev->features |= NETIF_F_IP_CSUM; @@ -753,7 +753,7 @@ static void ibmveth_set_tx_csum_flags(struct net_device *dev, u32 data) static int ibmveth_set_csum_offload(struct net_device *dev, u32 data, void (*done) (struct net_device *, u32)) { - struct ibmveth_adapter *adapter = dev->priv; + struct ibmveth_adapter *adapter = netdev_priv(dev); u64 set_attr, clr_attr, ret_attr; long ret; int rc1 = 0, rc2 = 0; @@ -805,7 +805,7 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data, static int ibmveth_set_rx_csum(struct net_device *dev, u32 data) { - struct ibmveth_adapter *adapter = dev->priv; + struct ibmveth_adapter *adapter = netdev_priv(dev); if ((data && adapter->rx_csum) || (!data && !adapter->rx_csum)) return 0; @@ -815,7 +815,7 @@ static int ibmveth_set_rx_csum(struct net_device *dev, u32 data) static int ibmveth_set_tx_csum(struct net_device *dev, u32 data) { - struct ibmveth_adapter *adapter = dev->priv; + struct ibmveth_adapter *adapter = netdev_priv(dev); int rc = 0; if (data && (dev->features & NETIF_F_IP_CSUM)) @@ -833,7 +833,7 @@ static int ibmveth_set_tx_csum(struct net_device *dev, u32 data) static u32 ibmveth_get_rx_csum(struct net_device *dev) { - struct ibmveth_adapter *adapter = dev->priv; + struct ibmveth_adapter *adapter = netdev_priv(dev); return adapter->rx_csum; } @@ -862,7 +862,7 @@ static void ibmveth_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data) { int i; - struct ibmveth_adapter *adapter = dev->priv; + struct ibmveth_adapter *adapter = netdev_priv(dev); for (i = 0; i < ARRAY_SIZE(ibmveth_stats); i++) data[i] = IBMVETH_GET_STAT(adapter, ibmveth_stats[i].offset); @@ -889,7 +889,7 @@ static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) { - struct ibmveth_adapter *adapter = netdev->priv; + struct ibmveth_adapter *adapter = netdev_priv(netdev); union ibmveth_buf_desc desc; unsigned long lpar_rc; unsigned long correlator; @@ -1014,7 +1014,6 @@ static int ibmveth_poll(struct napi_struct *napi, int budget) netdev->stats.rx_packets++; netdev->stats.rx_bytes += length; frames_processed++; - netdev->last_rx = jiffies; } } while (frames_processed < budget); @@ -1029,10 +1028,10 @@ static int ibmveth_poll(struct napi_struct *napi, int budget) ibmveth_assert(lpar_rc == H_SUCCESS); - netif_rx_complete(netdev, napi); + netif_rx_complete(napi); if (ibmveth_rxq_pending_buffer(adapter) && - netif_rx_reschedule(netdev, napi)) { + netif_rx_reschedule(napi)) { lpar_rc = h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_DISABLE); goto restart_poll; @@ -1045,21 +1044,21 @@ static int ibmveth_poll(struct napi_struct *napi, int budget) static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance) { struct net_device *netdev = dev_instance; - struct ibmveth_adapter *adapter = netdev->priv; + struct ibmveth_adapter *adapter = netdev_priv(netdev); unsigned long lpar_rc; - if (netif_rx_schedule_prep(netdev, &adapter->napi)) { + if (netif_rx_schedule_prep(&adapter->napi)) { lpar_rc = h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_DISABLE); ibmveth_assert(lpar_rc == H_SUCCESS); - __netif_rx_schedule(netdev, &adapter->napi); + __netif_rx_schedule(&adapter->napi); } return IRQ_HANDLED; } static void ibmveth_set_multicast_list(struct net_device *netdev) { - struct ibmveth_adapter *adapter = netdev->priv; + struct ibmveth_adapter *adapter = netdev_priv(netdev); unsigned long lpar_rc; if((netdev->flags & IFF_PROMISC) || (netdev->mc_count > adapter->mcastFilterSize)) { @@ -1107,7 +1106,7 @@ static void ibmveth_set_multicast_list(struct net_device *netdev) static int ibmveth_change_mtu(struct net_device *dev, int new_mtu) { - struct ibmveth_adapter *adapter = dev->priv; + struct ibmveth_adapter *adapter = netdev_priv(dev); struct vio_dev *viodev = adapter->vdev; int new_mtu_oh = new_mtu + IBMVETH_BUFF_OH; int i; @@ -1159,7 +1158,7 @@ static int ibmveth_change_mtu(struct net_device *dev, int new_mtu) #ifdef CONFIG_NET_POLL_CONTROLLER static void ibmveth_poll_controller(struct net_device *dev) { - ibmveth_replenish_task(dev->priv); + ibmveth_replenish_task(netdev_priv(dev)); ibmveth_interrupt(dev->irq, dev); } #endif @@ -1241,7 +1240,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ if(!netdev) return -ENOMEM; - adapter = netdev->priv; + adapter = netdev_priv(netdev); dev->dev.driver_data = netdev; adapter->vdev = dev; @@ -1337,7 +1336,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ static int __devexit ibmveth_remove(struct vio_dev *dev) { struct net_device *netdev = dev->dev.driver_data; - struct ibmveth_adapter *adapter = netdev->priv; + struct ibmveth_adapter *adapter = netdev_priv(netdev); int i; for(i = 0; iprivate; char *current_mac = ((char*) &adapter->netdev->dev_addr); char *firmware_mac = ((char*) &adapter->mac_addr) ; - DECLARE_MAC_BUF(mac); seq_printf(seq, "%s %s\n\n", ibmveth_driver_string, ibmveth_driver_version); seq_printf(seq, "Unit Address: 0x%x\n", adapter->vdev->unit_address); - seq_printf(seq, "Current MAC: %s\n", print_mac(mac, current_mac)); - seq_printf(seq, "Firmware MAC: %s\n", print_mac(mac, firmware_mac)); + seq_printf(seq, "Current MAC: %pM\n", current_mac); + seq_printf(seq, "Firmware MAC: %pM\n", firmware_mac); seq_printf(seq, "\nAdapter Statistics:\n"); seq_printf(seq, " TX: vio_map_single failres: %ld\n", adapter->tx_map_failed); @@ -1472,7 +1470,7 @@ const char * buf, size_t count) kobj); struct net_device *netdev = container_of(kobj->parent, struct device, kobj)->driver_data; - struct ibmveth_adapter *adapter = netdev->priv; + struct ibmveth_adapter *adapter = netdev_priv(netdev); long value = simple_strtol(buf, NULL, 10); long rc; diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index e4fbefc8c82f80797c5808efcadba2219aafb3c7..60a263001933a53e48e32d28f7adc7dc8914d437 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c @@ -137,18 +137,23 @@ static void ri_tasklet(unsigned long dev) } +static const struct net_device_ops ifb_netdev_ops = { + .ndo_open = ifb_open, + .ndo_stop = ifb_close, + .ndo_start_xmit = ifb_xmit, + .ndo_validate_addr = eth_validate_addr, +}; + static void ifb_setup(struct net_device *dev) { /* Initialize the device structure. */ - dev->hard_start_xmit = ifb_xmit; - dev->open = &ifb_open; - dev->stop = &ifb_close; dev->destructor = free_netdev; + dev->netdev_ops = &ifb_netdev_ops; /* Fill in device structure with ethernet-generic values. */ ether_setup(dev); dev->tx_queue_len = TX_Q_LIMIT; - dev->change_mtu = NULL; + dev->flags |= IFF_NOARP; dev->flags &= ~IFF_MULTICAST; random_ether_addr(dev->dev_addr); diff --git a/drivers/net/igb/e1000_defines.h b/drivers/net/igb/e1000_defines.h index ce700689fb57a0ecd09711de176dab632754856a..40d03426c1223f85639e6f03c2d61c6499144636 100644 --- a/drivers/net/igb/e1000_defines.h +++ b/drivers/net/igb/e1000_defines.h @@ -168,18 +168,12 @@ #define E1000_RCTL_RDMTS_HALF 0x00000000 /* rx desc min threshold size */ #define E1000_RCTL_MO_SHIFT 12 /* multicast offset shift */ #define E1000_RCTL_BAM 0x00008000 /* broadcast enable */ -/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */ #define E1000_RCTL_SZ_2048 0x00000000 /* rx buffer size 2048 */ #define E1000_RCTL_SZ_1024 0x00010000 /* rx buffer size 1024 */ #define E1000_RCTL_SZ_512 0x00020000 /* rx buffer size 512 */ #define E1000_RCTL_SZ_256 0x00030000 /* rx buffer size 256 */ -/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */ -#define E1000_RCTL_SZ_16384 0x00010000 /* rx buffer size 16384 */ -#define E1000_RCTL_SZ_8192 0x00020000 /* rx buffer size 8192 */ -#define E1000_RCTL_SZ_4096 0x00030000 /* rx buffer size 4096 */ #define E1000_RCTL_VFE 0x00040000 /* vlan filter enable */ #define E1000_RCTL_CFIEN 0x00080000 /* canonical form enable */ -#define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */ #define E1000_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */ /* @@ -329,6 +323,7 @@ #define E1000_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */ #define E1000_TXD_CMD_RS 0x08000000 /* Report Status */ #define E1000_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */ +#define E1000_TXD_STAT_DD 0x00000001 /* Descriptor Done */ /* Extended desc bits for Linksec and timesync */ /* Transmit Control */ diff --git a/drivers/net/igb/e1000_mac.c b/drivers/net/igb/e1000_mac.c index e18747c70becb6521b58f046d7e740e45f410408..97f0049a5d6b60cca24d390e300c4f5938169a1b 100644 --- a/drivers/net/igb/e1000_mac.c +++ b/drivers/net/igb/e1000_mac.c @@ -50,13 +50,6 @@ void igb_remove_device(struct e1000_hw *hw) kfree(hw->dev_spec); } -static void igb_read_pci_cfg(struct e1000_hw *hw, u32 reg, u16 *value) -{ - struct igb_adapter *adapter = hw->back; - - pci_read_config_word(adapter->pdev, reg, value); -} - static s32 igb_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value) { struct igb_adapter *adapter = hw->back; @@ -83,8 +76,8 @@ s32 igb_get_bus_info_pcie(struct e1000_hw *hw) { struct e1000_bus_info *bus = &hw->bus; s32 ret_val; - u32 status; - u16 pcie_link_status, pci_header_type; + u32 reg; + u16 pcie_link_status; bus->type = e1000_bus_type_pci_express; bus->speed = e1000_bus_speed_2500; @@ -99,14 +92,8 @@ s32 igb_get_bus_info_pcie(struct e1000_hw *hw) PCIE_LINK_WIDTH_MASK) >> PCIE_LINK_WIDTH_SHIFT); - igb_read_pci_cfg(hw, PCI_HEADER_TYPE_REGISTER, &pci_header_type); - if (pci_header_type & PCI_HEADER_TYPE_MULTIFUNC) { - status = rd32(E1000_STATUS); - bus->func = (status & E1000_STATUS_FUNC_MASK) - >> E1000_STATUS_FUNC_SHIFT; - } else { - bus->func = 0; - } + reg = rd32(E1000_STATUS); + bus->func = (reg & E1000_STATUS_FUNC_MASK) >> E1000_STATUS_FUNC_SHIFT; return 0; } @@ -229,8 +216,8 @@ void igb_rar_set(struct e1000_hw *hw, u8 *addr, u32 index) if (!hw->mac.disable_av) rar_high |= E1000_RAH_AV; - array_wr32(E1000_RA, (index << 1), rar_low); - array_wr32(E1000_RA, ((index << 1) + 1), rar_high); + wr32(E1000_RAL(index), rar_low); + wr32(E1000_RAH(index), rar_high); } /** diff --git a/drivers/net/igb/e1000_regs.h b/drivers/net/igb/e1000_regs.h index 95523af260562e2a915862b5f3d5049acafa6e78..bdf5d839c4bf96452b76f7eed848bfe0841484c2 100644 --- a/drivers/net/igb/e1000_regs.h +++ b/drivers/net/igb/e1000_regs.h @@ -221,6 +221,10 @@ #define E1000_MTA 0x05200 /* Multicast Table Array - RW Array */ #define E1000_RA 0x05400 /* Receive Address - RW Array */ #define E1000_RA2 0x054E0 /* 2nd half of receive address array - RW Array */ +#define E1000_RAL(_i) (((_i) <= 15) ? (0x05400 + ((_i) * 8)) : \ + (0x054E0 + ((_i - 16) * 8))) +#define E1000_RAH(_i) (((_i) <= 15) ? (0x05404 + ((_i) * 8)) : \ + (0x054E4 + ((_i - 16) * 8))) #define E1000_VFTA 0x05600 /* VLAN Filter Table Array - RW Array */ #define E1000_VMD_CTL 0x0581C /* VMDq Control - RW */ #define E1000_WUC 0x05800 /* Wakeup Control - RW */ diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h index 4ff6f0567f3f1184382712b3ee0c4bf9ac0fd2e0..5a27825cc48a3de22be22fdfd32bd455778549b7 100644 --- a/drivers/net/igb/igb.h +++ b/drivers/net/igb/igb.h @@ -43,8 +43,6 @@ struct igb_adapter; #endif /* Interrupt defines */ -#define IGB_MAX_TX_CLEAN 72 - #define IGB_MIN_DYN_ITR 3000 #define IGB_MAX_DYN_ITR 96000 @@ -127,7 +125,8 @@ struct igb_buffer { /* TX */ struct { unsigned long time_stamp; - u32 length; + u16 length; + u16 next_to_watch; }; /* RX */ struct { @@ -160,7 +159,8 @@ struct igb_ring { u16 itr_register; u16 cpu; - int queue_index; + u16 queue_index; + u16 reg_idx; unsigned int total_bytes; unsigned int total_packets; @@ -294,6 +294,8 @@ struct igb_adapter { unsigned int lro_flushed; unsigned int lro_no_desc; #endif + unsigned int tx_ring_count; + unsigned int rx_ring_count; }; #define IGB_FLAG_HAS_MSI (1 << 0) @@ -325,7 +327,41 @@ extern void igb_reset(struct igb_adapter *); extern int igb_set_spd_dplx(struct igb_adapter *, u16); extern int igb_setup_tx_resources(struct igb_adapter *, struct igb_ring *); extern int igb_setup_rx_resources(struct igb_adapter *, struct igb_ring *); +extern void igb_free_tx_resources(struct igb_ring *); +extern void igb_free_rx_resources(struct igb_ring *); extern void igb_update_stats(struct igb_adapter *); extern void igb_set_ethtool_ops(struct net_device *); +static inline s32 igb_reset_phy(struct e1000_hw *hw) +{ + if (hw->phy.ops.reset_phy) + return hw->phy.ops.reset_phy(hw); + + return 0; +} + +static inline s32 igb_read_phy_reg(struct e1000_hw *hw, u32 offset, u16 *data) +{ + if (hw->phy.ops.read_phy_reg) + return hw->phy.ops.read_phy_reg(hw, offset, data); + + return 0; +} + +static inline s32 igb_write_phy_reg(struct e1000_hw *hw, u32 offset, u16 data) +{ + if (hw->phy.ops.write_phy_reg) + return hw->phy.ops.write_phy_reg(hw, offset, data); + + return 0; +} + +static inline s32 igb_get_phy_info(struct e1000_hw *hw) +{ + if (hw->phy.ops.get_phy_info) + return hw->phy.ops.get_phy_info(hw); + + return 0; +} + #endif /* _IGB_H_ */ diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index 89964fa739a031bb2a778298a96a11e1a30e8ad3..3c831f1472adcbb6608f258e33900c8d6e91088a 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c @@ -101,8 +101,8 @@ static const struct igb_stats igb_gstrings_stats[] = { }; #define IGB_QUEUE_STATS_LEN \ - ((((struct igb_adapter *)netdev->priv)->num_rx_queues + \ - ((struct igb_adapter *)netdev->priv)->num_tx_queues) * \ + ((((struct igb_adapter *)netdev_priv(netdev))->num_rx_queues + \ + ((struct igb_adapter *)netdev_priv(netdev))->num_tx_queues) * \ (sizeof(struct igb_queue_stats) / sizeof(u64))) #define IGB_GLOBAL_STATS_LEN \ sizeof(igb_gstrings_stats) / sizeof(struct igb_stats) @@ -494,8 +494,6 @@ static void igb_get_regs(struct net_device *netdev, /* These should probably be added to e1000_regs.h instead */ #define E1000_PSRTYPE_REG(_i) (0x05480 + ((_i) * 4)) - #define E1000_RAL(_i) (0x05400 + ((_i) * 8)) - #define E1000_RAH(_i) (0x05404 + ((_i) * 8)) #define E1000_IP4AT_REG(_i) (0x05840 + ((_i) * 8)) #define E1000_IP6AT_REG(_i) (0x05880 + ((_i) * 4)) #define E1000_WUPM_REG(_i) (0x05A00 + ((_i) * 4)) @@ -714,15 +712,13 @@ static void igb_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) { struct igb_adapter *adapter = netdev_priv(netdev); - struct igb_ring *tx_ring = adapter->tx_ring; - struct igb_ring *rx_ring = adapter->rx_ring; ring->rx_max_pending = IGB_MAX_RXD; ring->tx_max_pending = IGB_MAX_TXD; ring->rx_mini_max_pending = 0; ring->rx_jumbo_max_pending = 0; - ring->rx_pending = rx_ring->count; - ring->tx_pending = tx_ring->count; + ring->rx_pending = adapter->rx_ring_count; + ring->tx_pending = adapter->tx_ring_count; ring->rx_mini_pending = 0; ring->rx_jumbo_pending = 0; } @@ -731,12 +727,9 @@ static int igb_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) { struct igb_adapter *adapter = netdev_priv(netdev); - struct igb_buffer *old_buf; - struct igb_buffer *old_rx_buf; - void *old_desc; + struct igb_ring *temp_ring; int i, err; - u32 new_rx_count, new_tx_count, old_size; - dma_addr_t old_dma; + u32 new_rx_count, new_tx_count; if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) return -EINVAL; @@ -749,12 +742,19 @@ static int igb_set_ringparam(struct net_device *netdev, new_tx_count = min(new_tx_count, (u32)IGB_MAX_TXD); new_tx_count = ALIGN(new_tx_count, REQ_TX_DESCRIPTOR_MULTIPLE); - if ((new_tx_count == adapter->tx_ring->count) && - (new_rx_count == adapter->rx_ring->count)) { + if ((new_tx_count == adapter->tx_ring_count) && + (new_rx_count == adapter->rx_ring_count)) { /* nothing to do */ return 0; } + if (adapter->num_tx_queues > adapter->num_rx_queues) + temp_ring = vmalloc(adapter->num_tx_queues * sizeof(struct igb_ring)); + else + temp_ring = vmalloc(adapter->num_rx_queues * sizeof(struct igb_ring)); + if (!temp_ring) + return -ENOMEM; + while (test_and_set_bit(__IGB_RESETTING, &adapter->state)) msleep(1); @@ -766,62 +766,55 @@ static int igb_set_ringparam(struct net_device *netdev, * because the ISRs in MSI-X mode get passed pointers * to the tx and rx ring structs. */ - if (new_tx_count != adapter->tx_ring->count) { + if (new_tx_count != adapter->tx_ring_count) { + memcpy(temp_ring, adapter->tx_ring, + adapter->num_tx_queues * sizeof(struct igb_ring)); + for (i = 0; i < adapter->num_tx_queues; i++) { - /* Save existing descriptor ring */ - old_buf = adapter->tx_ring[i].buffer_info; - old_desc = adapter->tx_ring[i].desc; - old_size = adapter->tx_ring[i].size; - old_dma = adapter->tx_ring[i].dma; - /* Try to allocate a new one */ - adapter->tx_ring[i].buffer_info = NULL; - adapter->tx_ring[i].desc = NULL; - adapter->tx_ring[i].count = new_tx_count; - err = igb_setup_tx_resources(adapter, - &adapter->tx_ring[i]); + temp_ring[i].count = new_tx_count; + err = igb_setup_tx_resources(adapter, &temp_ring[i]); if (err) { - /* Restore the old one so at least - the adapter still works, even if - we failed the request */ - adapter->tx_ring[i].buffer_info = old_buf; - adapter->tx_ring[i].desc = old_desc; - adapter->tx_ring[i].size = old_size; - adapter->tx_ring[i].dma = old_dma; + while (i) { + i--; + igb_free_tx_resources(&temp_ring[i]); + } goto err_setup; } - /* Free the old buffer manually */ - vfree(old_buf); - pci_free_consistent(adapter->pdev, old_size, - old_desc, old_dma); } + + for (i = 0; i < adapter->num_tx_queues; i++) + igb_free_tx_resources(&adapter->tx_ring[i]); + + memcpy(adapter->tx_ring, temp_ring, + adapter->num_tx_queues * sizeof(struct igb_ring)); + + adapter->tx_ring_count = new_tx_count; } if (new_rx_count != adapter->rx_ring->count) { - for (i = 0; i < adapter->num_rx_queues; i++) { + memcpy(temp_ring, adapter->rx_ring, + adapter->num_rx_queues * sizeof(struct igb_ring)); - old_rx_buf = adapter->rx_ring[i].buffer_info; - old_desc = adapter->rx_ring[i].desc; - old_size = adapter->rx_ring[i].size; - old_dma = adapter->rx_ring[i].dma; - - adapter->rx_ring[i].buffer_info = NULL; - adapter->rx_ring[i].desc = NULL; - adapter->rx_ring[i].dma = 0; - adapter->rx_ring[i].count = new_rx_count; - err = igb_setup_rx_resources(adapter, - &adapter->rx_ring[i]); + for (i = 0; i < adapter->num_rx_queues; i++) { + temp_ring[i].count = new_rx_count; + err = igb_setup_rx_resources(adapter, &temp_ring[i]); if (err) { - adapter->rx_ring[i].buffer_info = old_rx_buf; - adapter->rx_ring[i].desc = old_desc; - adapter->rx_ring[i].size = old_size; - adapter->rx_ring[i].dma = old_dma; + while (i) { + i--; + igb_free_rx_resources(&temp_ring[i]); + } goto err_setup; } - vfree(old_rx_buf); - pci_free_consistent(adapter->pdev, old_size, old_desc, - old_dma); } + + for (i = 0; i < adapter->num_rx_queues; i++) + igb_free_rx_resources(&adapter->rx_ring[i]); + + memcpy(adapter->rx_ring, temp_ring, + adapter->num_rx_queues * sizeof(struct igb_ring)); + + adapter->rx_ring_count = new_rx_count; } err = 0; @@ -830,6 +823,7 @@ static int igb_set_ringparam(struct net_device *netdev, igb_up(adapter); clear_bit(__IGB_RESETTING, &adapter->state); + vfree(temp_ring); return err; } @@ -1343,8 +1337,9 @@ static int igb_setup_desc_rings(struct igb_adapter *adapter) wr32(E1000_RDLEN(0), rx_ring->size); wr32(E1000_RDH(0), 0); wr32(E1000_RDT(0), 0); + rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC); rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_SZ_2048 | - E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF | + E1000_RCTL_RDMTS_HALF | (adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT); wr32(E1000_RCTL, rctl); wr32(E1000_SRRCTL(0), 0); @@ -1380,10 +1375,10 @@ static void igb_phy_disable_receiver(struct igb_adapter *adapter) struct e1000_hw *hw = &adapter->hw; /* Write out to PHY registers 29 and 30 to disable the Receiver. */ - hw->phy.ops.write_phy_reg(hw, 29, 0x001F); - hw->phy.ops.write_phy_reg(hw, 30, 0x8FFC); - hw->phy.ops.write_phy_reg(hw, 29, 0x001A); - hw->phy.ops.write_phy_reg(hw, 30, 0x8FF0); + igb_write_phy_reg(hw, 29, 0x001F); + igb_write_phy_reg(hw, 30, 0x8FFC); + igb_write_phy_reg(hw, 29, 0x001A); + igb_write_phy_reg(hw, 30, 0x8FF0); } static int igb_integrated_phy_loopback(struct igb_adapter *adapter) @@ -1396,17 +1391,17 @@ static int igb_integrated_phy_loopback(struct igb_adapter *adapter) if (hw->phy.type == e1000_phy_m88) { /* Auto-MDI/MDIX Off */ - hw->phy.ops.write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, 0x0808); + igb_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, 0x0808); /* reset to update Auto-MDI/MDIX */ - hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, 0x9140); + igb_write_phy_reg(hw, PHY_CONTROL, 0x9140); /* autoneg off */ - hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, 0x8140); + igb_write_phy_reg(hw, PHY_CONTROL, 0x8140); } ctrl_reg = rd32(E1000_CTRL); /* force 1000, set loopback */ - hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, 0x4140); + igb_write_phy_reg(hw, PHY_CONTROL, 0x4140); /* Now set up the MAC to the same speed/duplex as the PHY. */ ctrl_reg = rd32(E1000_CTRL); @@ -1500,10 +1495,10 @@ static void igb_loopback_cleanup(struct igb_adapter *adapter) wr32(E1000_RCTL, rctl); hw->mac.autoneg = true; - hw->phy.ops.read_phy_reg(hw, PHY_CONTROL, &phy_reg); + igb_read_phy_reg(hw, PHY_CONTROL, &phy_reg); if (phy_reg & MII_CR_LOOPBACK) { phy_reg &= ~MII_CR_LOOPBACK; - hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, phy_reg); + igb_write_phy_reg(hw, PHY_CONTROL, phy_reg); igb_phy_sw_reset(hw); } } diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 20d27e622ec10c1fabefdc24e85a67cb443d27a4..022794e579c7367f326aaa886128579d042b18d4 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -42,6 +42,7 @@ #include #include #include +#include #ifdef CONFIG_IGB_DCA #include #endif @@ -76,8 +77,6 @@ static int igb_setup_all_tx_resources(struct igb_adapter *); static int igb_setup_all_rx_resources(struct igb_adapter *); static void igb_free_all_tx_resources(struct igb_adapter *); static void igb_free_all_rx_resources(struct igb_adapter *); -static void igb_free_tx_resources(struct igb_ring *); -static void igb_free_rx_resources(struct igb_ring *); void igb_update_stats(struct igb_adapter *); static int igb_probe(struct pci_dev *, const struct pci_device_id *); static void __devexit igb_remove(struct pci_dev *pdev); @@ -232,6 +231,40 @@ static void __exit igb_exit_module(void) module_exit(igb_exit_module); +#define Q_IDX_82576(i) (((i & 0x1) << 3) + (i >> 1)) +/** + * igb_cache_ring_register - Descriptor ring to register mapping + * @adapter: board private structure to initialize + * + * Once we know the feature-set enabled for the device, we'll cache + * the register offset the descriptor ring is assigned to. + **/ +static void igb_cache_ring_register(struct igb_adapter *adapter) +{ + int i; + + switch (adapter->hw.mac.type) { + case e1000_82576: + /* The queues are allocated for virtualization such that VF 0 + * is allocated queues 0 and 8, VF 1 queues 1 and 9, etc. + * In order to avoid collision we start at the first free queue + * and continue consuming queues in the same sequence + */ + for (i = 0; i < adapter->num_rx_queues; i++) + adapter->rx_ring[i].reg_idx = Q_IDX_82576(i); + for (i = 0; i < adapter->num_tx_queues; i++) + adapter->tx_ring[i].reg_idx = Q_IDX_82576(i); + break; + case e1000_82575: + default: + for (i = 0; i < adapter->num_rx_queues; i++) + adapter->rx_ring[i].reg_idx = i; + for (i = 0; i < adapter->num_tx_queues; i++) + adapter->tx_ring[i].reg_idx = i; + break; + } +} + /** * igb_alloc_queues - Allocate memory for all rings * @adapter: board private structure to initialize @@ -259,11 +292,13 @@ static int igb_alloc_queues(struct igb_adapter *adapter) for (i = 0; i < adapter->num_tx_queues; i++) { struct igb_ring *ring = &(adapter->tx_ring[i]); + ring->count = adapter->tx_ring_count; ring->adapter = adapter; ring->queue_index = i; } for (i = 0; i < adapter->num_rx_queues; i++) { struct igb_ring *ring = &(adapter->rx_ring[i]); + ring->count = adapter->rx_ring_count; ring->adapter = adapter; ring->queue_index = i; ring->itr_register = E1000_ITR; @@ -271,6 +306,8 @@ static int igb_alloc_queues(struct igb_adapter *adapter) /* set a default napi handler for each rx_ring */ netif_napi_add(adapter->netdev, &ring->napi, igb_poll, 64); } + + igb_cache_ring_register(adapter); return 0; } @@ -311,36 +348,36 @@ static void igb_assign_vector(struct igb_adapter *adapter, int rx_queue, array_wr32(E1000_MSIXBM(0), msix_vector, msixbm); break; case e1000_82576: - /* The 82576 uses a table-based method for assigning vectors. + /* 82576 uses a table-based method for assigning vectors. Each queue has a single entry in the table to which we write a vector number along with a "valid" bit. Sadly, the layout of the table is somewhat counterintuitive. */ if (rx_queue > IGB_N0_QUEUE) { - index = (rx_queue & 0x7); + index = (rx_queue >> 1); ivar = array_rd32(E1000_IVAR0, index); - if (rx_queue < 8) { - /* vector goes into low byte of register */ - ivar = ivar & 0xFFFFFF00; - ivar |= msix_vector | E1000_IVAR_VALID; - } else { + if (rx_queue & 0x1) { /* vector goes into third byte of register */ ivar = ivar & 0xFF00FFFF; ivar |= (msix_vector | E1000_IVAR_VALID) << 16; + } else { + /* vector goes into low byte of register */ + ivar = ivar & 0xFFFFFF00; + ivar |= msix_vector | E1000_IVAR_VALID; } adapter->rx_ring[rx_queue].eims_value= 1 << msix_vector; array_wr32(E1000_IVAR0, index, ivar); } if (tx_queue > IGB_N0_QUEUE) { - index = (tx_queue & 0x7); + index = (tx_queue >> 1); ivar = array_rd32(E1000_IVAR0, index); - if (tx_queue < 8) { - /* vector goes into second byte of register */ - ivar = ivar & 0xFFFF00FF; - ivar |= (msix_vector | E1000_IVAR_VALID) << 8; - } else { + if (tx_queue & 0x1) { /* vector goes into high byte of register */ ivar = ivar & 0x00FFFFFF; ivar |= (msix_vector | E1000_IVAR_VALID) << 24; + } else { + /* vector goes into second byte of register */ + ivar = ivar & 0xFFFF00FF; + ivar |= (msix_vector | E1000_IVAR_VALID) << 8; } adapter->tx_ring[tx_queue].eims_value= 1 << msix_vector; array_wr32(E1000_IVAR0, index, ivar); @@ -445,7 +482,7 @@ static int igb_request_msix(struct igb_adapter *adapter) for (i = 0; i < adapter->num_tx_queues; i++) { struct igb_ring *ring = &(adapter->tx_ring[i]); - sprintf(ring->name, "%s-tx%d", netdev->name, i); + sprintf(ring->name, "%s-tx-%d", netdev->name, i); err = request_irq(adapter->msix_entries[vector].vector, &igb_msix_tx, 0, ring->name, &(adapter->tx_ring[i])); @@ -458,7 +495,7 @@ static int igb_request_msix(struct igb_adapter *adapter) for (i = 0; i < adapter->num_rx_queues; i++) { struct igb_ring *ring = &(adapter->rx_ring[i]); if (strlen(netdev->name) < (IFNAMSIZ - 5)) - sprintf(ring->name, "%s-rx%d", netdev->name, i); + sprintf(ring->name, "%s-rx-%d", netdev->name, i); else memcpy(ring->name, netdev->name, IFNAMSIZ); err = request_irq(adapter->msix_entries[vector].vector, @@ -931,8 +968,7 @@ void igb_reset(struct igb_adapter *adapter) wr32(E1000_VET, ETHERNET_IEEE_VLAN_TYPE); igb_reset_adaptive(&adapter->hw); - if (adapter->hw.phy.ops.get_phy_info) - adapter->hw.phy.ops.get_phy_info(&adapter->hw); + igb_get_phy_info(&adapter->hw); } /** @@ -950,6 +986,25 @@ static int igb_is_need_ioport(struct pci_dev *pdev) } } +static const struct net_device_ops igb_netdev_ops = { + .ndo_open = igb_open, + .ndo_stop = igb_close, + .ndo_start_xmit = igb_xmit_frame_adv, + .ndo_get_stats = igb_get_stats, + .ndo_set_multicast_list = igb_set_multi, + .ndo_set_mac_address = igb_set_mac, + .ndo_change_mtu = igb_change_mtu, + .ndo_do_ioctl = igb_ioctl, + .ndo_tx_timeout = igb_tx_timeout, + .ndo_validate_addr = eth_validate_addr, + .ndo_vlan_rx_register = igb_vlan_rx_register, + .ndo_vlan_rx_add_vid = igb_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = igb_vlan_rx_kill_vid, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = igb_netpoll, +#endif +}; + /** * igb_probe - Device Initialization Routine * @pdev: PCI device information struct @@ -1031,6 +1086,13 @@ static int __devinit igb_probe(struct pci_dev *pdev, if (err) goto err_pci_reg; + err = pci_enable_pcie_error_reporting(pdev); + if (err) { + dev_err(&pdev->dev, "pci_enable_pcie_error_reporting failed " + "0x%x\n", err); + /* non-fatal, continue */ + } + pci_set_master(pdev); pci_save_state(pdev); @@ -1059,23 +1121,9 @@ static int __devinit igb_probe(struct pci_dev *pdev, if (!adapter->hw.hw_addr) goto err_ioremap; - netdev->open = &igb_open; - netdev->stop = &igb_close; - netdev->get_stats = &igb_get_stats; - netdev->set_multicast_list = &igb_set_multi; - netdev->set_mac_address = &igb_set_mac; - netdev->change_mtu = &igb_change_mtu; - netdev->do_ioctl = &igb_ioctl; + netdev->netdev_ops = &igb_netdev_ops; igb_set_ethtool_ops(netdev); - netdev->tx_timeout = &igb_tx_timeout; netdev->watchdog_timeo = 5 * HZ; - netdev->vlan_rx_register = igb_vlan_rx_register; - netdev->vlan_rx_add_vid = igb_vlan_rx_add_vid; - netdev->vlan_rx_kill_vid = igb_vlan_rx_kill_vid; -#ifdef CONFIG_NET_POLL_CONTROLLER - netdev->poll_controller = igb_netpoll; -#endif - netdev->hard_start_xmit = &igb_xmit_frame_adv; strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1); @@ -1275,16 +1323,14 @@ static int __devinit igb_probe(struct pci_dev *pdev, dev_info(&pdev->dev, "Intel(R) Gigabit Ethernet Network Connection\n"); /* print bus type/speed/width info */ - dev_info(&pdev->dev, - "%s: (PCIe:%s:%s) %02x:%02x:%02x:%02x:%02x:%02x\n", + dev_info(&pdev->dev, "%s: (PCIe:%s:%s) %pM\n", netdev->name, ((hw->bus.speed == e1000_bus_speed_2500) ? "2.5Gb/s" : "unknown"), ((hw->bus.width == e1000_bus_width_pcie_x4) ? "Width x4" : (hw->bus.width == e1000_bus_width_pcie_x1) ? "Width x1" : "unknown"), - netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2], - netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]); + netdev->dev_addr); igb_read_part_num(hw, &part_num); dev_info(&pdev->dev, "%s: PBA No: %06x-%03x\n", netdev->name, @@ -1302,7 +1348,7 @@ static int __devinit igb_probe(struct pci_dev *pdev, igb_release_hw_control(adapter); err_eeprom: if (!igb_check_reset_block(hw)) - hw->phy.ops.reset_phy(hw); + igb_reset_phy(hw); if (hw->flash_address) iounmap(hw->flash_address); @@ -1338,6 +1384,7 @@ static void __devexit igb_remove(struct pci_dev *pdev) #ifdef CONFIG_IGB_DCA struct e1000_hw *hw = &adapter->hw; #endif + int err; /* flush_scheduled work may reschedule our watchdog task, so * explicitly disable watchdog tasks from being rescheduled */ @@ -1362,9 +1409,8 @@ static void __devexit igb_remove(struct pci_dev *pdev) unregister_netdev(netdev); - if (adapter->hw.phy.ops.reset_phy && - !igb_check_reset_block(&adapter->hw)) - adapter->hw.phy.ops.reset_phy(&adapter->hw); + if (!igb_check_reset_block(&adapter->hw)) + igb_reset_phy(&adapter->hw); igb_remove_device(&adapter->hw); igb_reset_interrupt_capability(adapter); @@ -1378,6 +1424,11 @@ static void __devexit igb_remove(struct pci_dev *pdev) free_netdev(netdev); + err = pci_disable_pcie_error_reporting(pdev); + if (err) + dev_err(&pdev->dev, + "pci_disable_pcie_error_reporting failed 0x%x\n", err); + pci_disable_device(pdev); } @@ -1397,6 +1448,8 @@ static int __devinit igb_sw_init(struct igb_adapter *adapter) pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word); + adapter->tx_ring_count = IGB_DEFAULT_TXD; + adapter->rx_ring_count = IGB_DEFAULT_RXD; adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE; adapter->rx_ps_hdr_size = 0; /* disable packet split */ adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN; @@ -1558,8 +1611,7 @@ int igb_setup_tx_resources(struct igb_adapter *adapter, memset(tx_ring->buffer_info, 0, size); /* round up to nearest 4K */ - tx_ring->size = tx_ring->count * sizeof(struct e1000_tx_desc) - + sizeof(u32); + tx_ring->size = tx_ring->count * sizeof(struct e1000_tx_desc); tx_ring->size = ALIGN(tx_ring->size, 4096); tx_ring->desc = pci_alloc_consistent(pdev, tx_ring->size, @@ -1618,43 +1670,37 @@ static int igb_setup_all_tx_resources(struct igb_adapter *adapter) **/ static void igb_configure_tx(struct igb_adapter *adapter) { - u64 tdba, tdwba; + u64 tdba; struct e1000_hw *hw = &adapter->hw; u32 tctl; u32 txdctl, txctrl; - int i; + int i, j; for (i = 0; i < adapter->num_tx_queues; i++) { struct igb_ring *ring = &(adapter->tx_ring[i]); - - wr32(E1000_TDLEN(i), + j = ring->reg_idx; + wr32(E1000_TDLEN(j), ring->count * sizeof(struct e1000_tx_desc)); tdba = ring->dma; - wr32(E1000_TDBAL(i), + wr32(E1000_TDBAL(j), tdba & 0x00000000ffffffffULL); - wr32(E1000_TDBAH(i), tdba >> 32); - - tdwba = ring->dma + ring->count * sizeof(struct e1000_tx_desc); - tdwba |= 1; /* enable head wb */ - wr32(E1000_TDWBAL(i), - tdwba & 0x00000000ffffffffULL); - wr32(E1000_TDWBAH(i), tdwba >> 32); + wr32(E1000_TDBAH(j), tdba >> 32); - ring->head = E1000_TDH(i); - ring->tail = E1000_TDT(i); + ring->head = E1000_TDH(j); + ring->tail = E1000_TDT(j); writel(0, hw->hw_addr + ring->tail); writel(0, hw->hw_addr + ring->head); - txdctl = rd32(E1000_TXDCTL(i)); + txdctl = rd32(E1000_TXDCTL(j)); txdctl |= E1000_TXDCTL_QUEUE_ENABLE; - wr32(E1000_TXDCTL(i), txdctl); + wr32(E1000_TXDCTL(j), txdctl); /* Turn off Relaxed Ordering on head write-backs. The * writebacks MUST be delivered in order or it will * completely screw up our bookeeping. */ - txctrl = rd32(E1000_DCA_TXCTRL(i)); + txctrl = rd32(E1000_DCA_TXCTRL(j)); txctrl &= ~E1000_DCA_TXCTRL_TX_WB_RO_EN; - wr32(E1000_DCA_TXCTRL(i), txctrl); + wr32(E1000_DCA_TXCTRL(j), txctrl); } @@ -1771,14 +1817,14 @@ static void igb_setup_rctl(struct igb_adapter *adapter) struct e1000_hw *hw = &adapter->hw; u32 rctl; u32 srrctl = 0; - int i; + int i, j; rctl = rd32(E1000_RCTL); rctl &= ~(3 << E1000_RCTL_MO_SHIFT); + rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC); - rctl |= E1000_RCTL_EN | E1000_RCTL_BAM | - E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF | + rctl |= E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_RDMTS_HALF | (adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT); /* @@ -1788,38 +1834,26 @@ static void igb_setup_rctl(struct igb_adapter *adapter) */ rctl |= E1000_RCTL_SECRC; - rctl &= ~E1000_RCTL_SBP; + /* + * disable store bad packets, long packet enable, and clear size bits. + */ + rctl &= ~(E1000_RCTL_SBP | E1000_RCTL_LPE | E1000_RCTL_SZ_256); - if (adapter->netdev->mtu <= ETH_DATA_LEN) - rctl &= ~E1000_RCTL_LPE; - else + if (adapter->netdev->mtu > ETH_DATA_LEN) rctl |= E1000_RCTL_LPE; - if (adapter->rx_buffer_len <= IGB_RXBUFFER_2048) { - /* Setup buffer sizes */ - rctl &= ~E1000_RCTL_SZ_4096; - rctl |= E1000_RCTL_BSEX; - switch (adapter->rx_buffer_len) { - case IGB_RXBUFFER_256: - rctl |= E1000_RCTL_SZ_256; - rctl &= ~E1000_RCTL_BSEX; - break; - case IGB_RXBUFFER_512: - rctl |= E1000_RCTL_SZ_512; - rctl &= ~E1000_RCTL_BSEX; - break; - case IGB_RXBUFFER_1024: - rctl |= E1000_RCTL_SZ_1024; - rctl &= ~E1000_RCTL_BSEX; - break; - case IGB_RXBUFFER_2048: - default: - rctl |= E1000_RCTL_SZ_2048; - rctl &= ~E1000_RCTL_BSEX; - break; - } - } else { - rctl &= ~E1000_RCTL_BSEX; - srrctl = adapter->rx_buffer_len >> E1000_SRRCTL_BSIZEPKT_SHIFT; + + /* Setup buffer sizes */ + switch (adapter->rx_buffer_len) { + case IGB_RXBUFFER_256: + rctl |= E1000_RCTL_SZ_256; + break; + case IGB_RXBUFFER_512: + rctl |= E1000_RCTL_SZ_512; + break; + default: + srrctl = ALIGN(adapter->rx_buffer_len, 1024) + >> E1000_SRRCTL_BSIZEPKT_SHIFT; + break; } /* 82575 and greater support packet-split where the protocol @@ -1841,8 +1875,10 @@ static void igb_setup_rctl(struct igb_adapter *adapter) srrctl |= E1000_SRRCTL_DESCTYPE_ADV_ONEBUF; } - for (i = 0; i < adapter->num_rx_queues; i++) - wr32(E1000_SRRCTL(i), srrctl); + for (i = 0; i < adapter->num_rx_queues; i++) { + j = adapter->rx_ring[i].reg_idx; + wr32(E1000_SRRCTL(j), srrctl); + } wr32(E1000_RCTL, rctl); } @@ -1859,7 +1895,7 @@ static void igb_configure_rx(struct igb_adapter *adapter) struct e1000_hw *hw = &adapter->hw; u32 rctl, rxcsum; u32 rxdctl; - int i; + int i, j; /* disable receives while setting up the descriptors */ rctl = rd32(E1000_RCTL); @@ -1874,25 +1910,26 @@ static void igb_configure_rx(struct igb_adapter *adapter) * the Base and Length of the Rx Descriptor Ring */ for (i = 0; i < adapter->num_rx_queues; i++) { struct igb_ring *ring = &(adapter->rx_ring[i]); + j = ring->reg_idx; rdba = ring->dma; - wr32(E1000_RDBAL(i), + wr32(E1000_RDBAL(j), rdba & 0x00000000ffffffffULL); - wr32(E1000_RDBAH(i), rdba >> 32); - wr32(E1000_RDLEN(i), + wr32(E1000_RDBAH(j), rdba >> 32); + wr32(E1000_RDLEN(j), ring->count * sizeof(union e1000_adv_rx_desc)); - ring->head = E1000_RDH(i); - ring->tail = E1000_RDT(i); + ring->head = E1000_RDH(j); + ring->tail = E1000_RDT(j); writel(0, hw->hw_addr + ring->tail); writel(0, hw->hw_addr + ring->head); - rxdctl = rd32(E1000_RXDCTL(i)); + rxdctl = rd32(E1000_RXDCTL(j)); rxdctl |= E1000_RXDCTL_QUEUE_ENABLE; rxdctl &= 0xFFF00000; rxdctl |= IGB_RX_PTHRESH; rxdctl |= IGB_RX_HTHRESH << 8; rxdctl |= IGB_RX_WTHRESH << 16; - wr32(E1000_RXDCTL(i), rxdctl); + wr32(E1000_RXDCTL(j), rxdctl); #ifdef CONFIG_IGB_LRO /* Intitial LRO Settings */ ring->lro_mgr.max_aggr = MAX_LRO_AGGR; @@ -1922,7 +1959,7 @@ static void igb_configure_rx(struct igb_adapter *adapter) shift = 6; for (j = 0; j < (32 * 4); j++) { reta.bytes[j & 3] = - (j % adapter->num_rx_queues) << shift; + adapter->rx_ring[(j % adapter->num_rx_queues)].reg_idx << shift; if ((j & 3) == 3) writel(reta.dword, hw->hw_addr + E1000_RETA(0) + (j & ~3)); @@ -1984,7 +2021,7 @@ static void igb_configure_rx(struct igb_adapter *adapter) * * Free all transmit software resources **/ -static void igb_free_tx_resources(struct igb_ring *tx_ring) +void igb_free_tx_resources(struct igb_ring *tx_ring) { struct pci_dev *pdev = tx_ring->adapter->pdev; @@ -2082,7 +2119,7 @@ static void igb_clean_all_tx_rings(struct igb_adapter *adapter) * * Free all receive software resources **/ -static void igb_free_rx_resources(struct igb_ring *rx_ring) +void igb_free_rx_resources(struct igb_ring *rx_ring) { struct pci_dev *pdev = rx_ring->adapter->pdev; @@ -2274,8 +2311,7 @@ static void igb_set_multi(struct net_device *netdev) static void igb_update_phy_info(unsigned long data) { struct igb_adapter *adapter = (struct igb_adapter *) data; - if (adapter->hw.phy.ops.get_phy_info) - adapter->hw.phy.ops.get_phy_info(&adapter->hw); + igb_get_phy_info(&adapter->hw); } /** @@ -2330,9 +2366,10 @@ static void igb_watchdog_task(struct work_struct *work) &adapter->link_duplex); ctrl = rd32(E1000_CTRL); - dev_info(&adapter->pdev->dev, - "NIC Link is Up %d Mbps %s, " + /* Links status message must follow this format */ + printk(KERN_INFO "igb: %s NIC Link is Up %d Mbps %s, " "Flow Control: %s\n", + netdev->name, adapter->link_speed, adapter->link_duplex == FULL_DUPLEX ? "Full Duplex" : "Half Duplex", @@ -2367,7 +2404,9 @@ static void igb_watchdog_task(struct work_struct *work) if (netif_carrier_ok(netdev)) { adapter->link_speed = 0; adapter->link_duplex = 0; - dev_info(&adapter->pdev->dev, "NIC Link is Down\n"); + /* Links status message must follow this format */ + printk(KERN_INFO "igb: %s NIC Link is Down\n", + netdev->name); netif_carrier_off(netdev); netif_tx_stop_all_queues(netdev); if (!test_bit(__IGB_DOWN, &adapter->state)) @@ -2703,6 +2742,7 @@ static inline int igb_tso_adv(struct igb_adapter *adapter, context_desc->seqnum_seed = 0; buffer_info->time_stamp = jiffies; + buffer_info->next_to_watch = i; buffer_info->dma = 0; i++; if (i == tx_ring->count) @@ -2766,6 +2806,7 @@ static inline bool igb_tx_csum_adv(struct igb_adapter *adapter, cpu_to_le32(tx_ring->queue_index << 4); buffer_info->time_stamp = jiffies; + buffer_info->next_to_watch = i; buffer_info->dma = 0; i++; @@ -2784,8 +2825,8 @@ static inline bool igb_tx_csum_adv(struct igb_adapter *adapter, #define IGB_MAX_DATA_PER_TXD (1<length = len; /* set time_stamp *before* dma to help avoid a possible race */ buffer_info->time_stamp = jiffies; + buffer_info->next_to_watch = i; buffer_info->dma = pci_map_single(adapter->pdev, skb->data, len, PCI_DMA_TODEVICE); count++; @@ -2816,6 +2858,7 @@ static inline int igb_tx_map_adv(struct igb_adapter *adapter, BUG_ON(len >= IGB_MAX_DATA_PER_TXD); buffer_info->length = len; buffer_info->time_stamp = jiffies; + buffer_info->next_to_watch = i; buffer_info->dma = pci_map_page(adapter->pdev, frag->page, frag->page_offset, @@ -2828,8 +2871,9 @@ static inline int igb_tx_map_adv(struct igb_adapter *adapter, i = 0; } - i = (i == 0) ? tx_ring->count - 1 : i - 1; + i = ((i == 0) ? tx_ring->count - 1 : i - 1); tx_ring->buffer_info[i].skb = skb; + tx_ring->buffer_info[first].next_to_watch = i; return count; } @@ -2936,6 +2980,7 @@ static int igb_xmit_frame_ring_adv(struct sk_buff *skb, struct igb_ring *tx_ring) { struct igb_adapter *adapter = netdev_priv(netdev); + unsigned int first; unsigned int tx_flags = 0; unsigned int len; u8 hdr_len = 0; @@ -2972,6 +3017,8 @@ static int igb_xmit_frame_ring_adv(struct sk_buff *skb, if (skb->protocol == htons(ETH_P_IP)) tx_flags |= IGB_TX_FLAGS_IPV4; + first = tx_ring->next_to_use; + tso = skb_is_gso(skb) ? igb_tso_adv(adapter, tx_ring, skb, tx_flags, &hdr_len) : 0; @@ -2987,7 +3034,7 @@ static int igb_xmit_frame_ring_adv(struct sk_buff *skb, tx_flags |= IGB_TX_FLAGS_CSUM; igb_tx_queue_adv(adapter, tx_ring, tx_flags, - igb_tx_map_adv(adapter, tx_ring, skb), + igb_tx_map_adv(adapter, tx_ring, skb, first), skb->len, hdr_len); netdev->trans_start = jiffies; @@ -3249,7 +3296,7 @@ void igb_update_stats(struct igb_adapter *adapter) /* Phy Stats */ if (hw->phy.media_type == e1000_media_type_copper) { if ((adapter->link_speed == SPEED_1000) && - (!hw->phy.ops.read_phy_reg(hw, PHY_1000T_STATUS, + (!igb_read_phy_reg(hw, PHY_1000T_STATUS, &phy_tmp))) { phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK; adapter->phy_stats.idle_errors += phy_tmp; @@ -3332,7 +3379,6 @@ static void igb_write_itr(struct igb_ring *ring) static irqreturn_t igb_msix_rx(int irq, void *data) { struct igb_ring *rx_ring = data; - struct igb_adapter *adapter = rx_ring->adapter; /* Write the ITR value calculated at the end of the * previous interrupt. @@ -3340,11 +3386,11 @@ static irqreturn_t igb_msix_rx(int irq, void *data) igb_write_itr(rx_ring); - if (netif_rx_schedule_prep(adapter->netdev, &rx_ring->napi)) - __netif_rx_schedule(adapter->netdev, &rx_ring->napi); + if (netif_rx_schedule_prep(&rx_ring->napi)) + __netif_rx_schedule(&rx_ring->napi); #ifdef CONFIG_IGB_DCA - if (adapter->flags & IGB_FLAG_DCA_ENABLED) + if (rx_ring->adapter->flags & IGB_FLAG_DCA_ENABLED) igb_update_rx_dca(rx_ring); #endif return IRQ_HANDLED; @@ -3357,7 +3403,7 @@ static void igb_update_rx_dca(struct igb_ring *rx_ring) struct igb_adapter *adapter = rx_ring->adapter; struct e1000_hw *hw = &adapter->hw; int cpu = get_cpu(); - int q = rx_ring - adapter->rx_ring; + int q = rx_ring->reg_idx; if (rx_ring->cpu != cpu) { dca_rxctrl = rd32(E1000_DCA_RXCTRL(q)); @@ -3384,7 +3430,7 @@ static void igb_update_tx_dca(struct igb_ring *tx_ring) struct igb_adapter *adapter = tx_ring->adapter; struct e1000_hw *hw = &adapter->hw; int cpu = get_cpu(); - int q = tx_ring - adapter->tx_ring; + int q = tx_ring->reg_idx; if (tx_ring->cpu != cpu) { dca_txctrl = rd32(E1000_DCA_TXCTRL(q)); @@ -3493,7 +3539,7 @@ static irqreturn_t igb_intr_msi(int irq, void *data) mod_timer(&adapter->watchdog_timer, jiffies + 1); } - netif_rx_schedule(netdev, &adapter->rx_ring[0].napi); + netif_rx_schedule(&adapter->rx_ring[0].napi); return IRQ_HANDLED; } @@ -3531,7 +3577,7 @@ static irqreturn_t igb_intr(int irq, void *data) mod_timer(&adapter->watchdog_timer, jiffies + 1); } - netif_rx_schedule(netdev, &adapter->rx_ring[0].napi); + netif_rx_schedule(&adapter->rx_ring[0].napi); return IRQ_HANDLED; } @@ -3566,7 +3612,7 @@ static int igb_poll(struct napi_struct *napi, int budget) !netif_running(netdev)) { if (adapter->itr_setting & 3) igb_set_itr(adapter); - netif_rx_complete(netdev, napi); + netif_rx_complete(napi); if (!test_bit(__IGB_DOWN, &adapter->state)) igb_irq_enable(adapter); return 0; @@ -3592,7 +3638,7 @@ static int igb_clean_rx_ring_msix(struct napi_struct *napi, int budget) /* If not enough Rx work done, exit the polling mode */ if ((work_done == 0) || !netif_running(netdev)) { - netif_rx_complete(netdev, napi); + netif_rx_complete(napi); if (adapter->itr_setting & 3) { if (adapter->num_rx_queues == 1) @@ -3610,12 +3656,6 @@ static int igb_clean_rx_ring_msix(struct napi_struct *napi, int budget) return 1; } -static inline u32 get_head(struct igb_ring *tx_ring) -{ - void *end = (struct e1000_tx_desc *)tx_ring->desc + tx_ring->count; - return le32_to_cpu(*(volatile __le32 *)end); -} - /** * igb_clean_tx_irq - Reclaim resources after transmit completes * @adapter: board private structure @@ -3624,24 +3664,25 @@ static inline u32 get_head(struct igb_ring *tx_ring) static bool igb_clean_tx_irq(struct igb_ring *tx_ring) { struct igb_adapter *adapter = tx_ring->adapter; - struct e1000_hw *hw = &adapter->hw; struct net_device *netdev = adapter->netdev; - struct e1000_tx_desc *tx_desc; + struct e1000_hw *hw = &adapter->hw; struct igb_buffer *buffer_info; struct sk_buff *skb; - unsigned int i; - u32 head, oldhead; - unsigned int count = 0; + union e1000_adv_tx_desc *tx_desc, *eop_desc; unsigned int total_bytes = 0, total_packets = 0; - bool retval = true; + unsigned int i, eop, count = 0; + bool cleaned = false; - rmb(); - head = get_head(tx_ring); i = tx_ring->next_to_clean; - while (1) { - while (i != head) { - tx_desc = E1000_TX_DESC(*tx_ring, i); + eop = tx_ring->buffer_info[i].next_to_watch; + eop_desc = E1000_TX_DESC_ADV(*tx_ring, eop); + + while ((eop_desc->wb.status & cpu_to_le32(E1000_TXD_STAT_DD)) && + (count < tx_ring->count)) { + for (cleaned = false; !cleaned; count++) { + tx_desc = E1000_TX_DESC_ADV(*tx_ring, i); buffer_info = &tx_ring->buffer_info[i]; + cleaned = (i == eop); skb = buffer_info->skb; if (skb) { @@ -3656,25 +3697,17 @@ static bool igb_clean_tx_irq(struct igb_ring *tx_ring) } igb_unmap_and_free_tx_resource(adapter, buffer_info); + tx_desc->wb.status = 0; i++; if (i == tx_ring->count) i = 0; - - count++; - if (count == IGB_MAX_TX_CLEAN) { - retval = false; - goto done_cleaning; - } } - oldhead = head; - rmb(); - head = get_head(tx_ring); - if (head == oldhead) - goto done_cleaning; - } /* while (1) */ - -done_cleaning: + + eop = tx_ring->buffer_info[i].next_to_watch; + eop_desc = E1000_TX_DESC_ADV(*tx_ring, eop); + } + tx_ring->next_to_clean = i; if (unlikely(count && @@ -3701,7 +3734,6 @@ static bool igb_clean_tx_irq(struct igb_ring *tx_ring) && !(rd32(E1000_STATUS) & E1000_STATUS_TXOFF)) { - tx_desc = E1000_TX_DESC(*tx_ring, i); /* detected Tx unit hang */ dev_err(&adapter->pdev->dev, "Detected Tx Unit Hang\n" @@ -3710,9 +3742,9 @@ static bool igb_clean_tx_irq(struct igb_ring *tx_ring) " TDT <%x>\n" " next_to_use <%x>\n" " next_to_clean <%x>\n" - " head (WB) <%x>\n" "buffer_info[next_to_clean]\n" " time_stamp <%lx>\n" + " next_to_watch <%x>\n" " jiffies <%lx>\n" " desc.status <%x>\n", tx_ring->queue_index, @@ -3720,10 +3752,10 @@ static bool igb_clean_tx_irq(struct igb_ring *tx_ring) readl(adapter->hw.hw_addr + tx_ring->tail), tx_ring->next_to_use, tx_ring->next_to_clean, - head, tx_ring->buffer_info[i].time_stamp, + eop, jiffies, - tx_desc->upper.fields.status); + eop_desc->wb.status); netif_stop_subqueue(netdev, tx_ring->queue_index); } } @@ -3733,7 +3765,7 @@ static bool igb_clean_tx_irq(struct igb_ring *tx_ring) tx_ring->tx_stats.packets += total_packets; adapter->net_stats.tx_bytes += total_bytes; adapter->net_stats.tx_packets += total_packets; - return retval; + return (count < tx_ring->count); } #ifdef CONFIG_IGB_LRO @@ -3919,8 +3951,10 @@ static bool igb_clean_rx_irq_adv(struct igb_ring *rx_ring, next_buffer = &rx_ring->buffer_info[i]; if (!(staterr & E1000_RXD_STAT_EOP)) { - buffer_info->skb = xchg(&next_buffer->skb, skb); - buffer_info->dma = xchg(&next_buffer->dma, 0); + buffer_info->skb = next_buffer->skb; + buffer_info->dma = next_buffer->dma; + next_buffer->skb = skb; + next_buffer->dma = 0; goto next_desc; } @@ -3938,8 +3972,6 @@ static bool igb_clean_rx_irq_adv(struct igb_ring *rx_ring, igb_receive_skb(rx_ring, staterr, rx_desc, skb); - netdev->last_rx = jiffies; - next_desc: rx_desc->wb.upper.status_error = 0; @@ -4102,9 +4134,8 @@ static int igb_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) case SIOCGMIIREG: if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (adapter->hw.phy.ops.read_phy_reg(&adapter->hw, - data->reg_num - & 0x1F, &data->val_out)) + if (igb_read_phy_reg(&adapter->hw, data->reg_num & 0x1F, + &data->val_out)) return -EIO; break; case SIOCSMIIREG: @@ -4474,27 +4505,38 @@ static pci_ers_result_t igb_io_slot_reset(struct pci_dev *pdev) struct net_device *netdev = pci_get_drvdata(pdev); struct igb_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; + pci_ers_result_t result; int err; if (adapter->need_ioport) err = pci_enable_device(pdev); else err = pci_enable_device_mem(pdev); + if (err) { dev_err(&pdev->dev, "Cannot re-enable PCI device after reset.\n"); - return PCI_ERS_RESULT_DISCONNECT; - } - pci_set_master(pdev); - pci_restore_state(pdev); + result = PCI_ERS_RESULT_DISCONNECT; + } else { + pci_set_master(pdev); + pci_restore_state(pdev); - pci_enable_wake(pdev, PCI_D3hot, 0); - pci_enable_wake(pdev, PCI_D3cold, 0); + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); - igb_reset(adapter); - wr32(E1000_WUS, ~0); + igb_reset(adapter); + wr32(E1000_WUS, ~0); + result = PCI_ERS_RESULT_RECOVERED; + } + + err = pci_cleanup_aer_uncorrect_error_status(pdev); + if (err) { + dev_err(&pdev->dev, "pci_cleanup_aer_uncorrect_error_status " + "failed 0x%0x\n", err); + /* non-fatal, continue */ + } - return PCI_ERS_RESULT_RECOVERED; + return result; } /** @@ -4522,7 +4564,6 @@ static void igb_io_resume(struct pci_dev *pdev) /* let the f/w know that the h/w is now under the control of the * driver. */ igb_get_hw_control(adapter); - } /* igb_main.c */ diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index 1f25263dc7ebb8f90066d7388bbd297bd8d82b26..170b12d1d70e49e2ab02918b41e1236bd9544a84 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c @@ -390,11 +390,8 @@ static int nic_init(struct ioc3 *ioc3) } printk("Found %s NIC", type); - if (type != unknown) { - printk (" registration number %02x:%02x:%02x:%02x:%02x:%02x," - " CRC %02x", serial[0], serial[1], serial[2], - serial[3], serial[4], serial[5], crc); - } + if (type != unknown) + printk (" registration number %pM, CRC %02x", serial, crc); printk(".\n"); return 0; @@ -443,12 +440,9 @@ static void ioc3_get_eaddr_nic(struct ioc3_private *ip) */ static void ioc3_get_eaddr(struct ioc3_private *ip) { - DECLARE_MAC_BUF(mac); - ioc3_get_eaddr_nic(ip); - printk("Ethernet address is %s.\n", - print_mac(mac, priv_netdev(ip)->dev_addr)); + printk("Ethernet address is %pM.\n", priv_netdev(ip)->dev_addr); } static void __ioc3_set_mac_address(struct net_device *dev) @@ -627,7 +621,6 @@ static inline void ioc3_rx(struct ioc3_private *ip) rxb = (struct ioc3_erxbuf *) new_skb->data; skb_reserve(new_skb, RX_OFFSET); - priv_netdev(ip)->last_rx = jiffies; ip->stats.rx_packets++; /* Statistics */ ip->stats.rx_bytes += len; } else { diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c index 059369885be1c71c96ea1cbf5807659c7fdba793..7b6d435a84680e487cdebe5953ee487ba4333f47 100644 --- a/drivers/net/ipg.c +++ b/drivers/net/ipg.c @@ -1222,7 +1222,6 @@ static void ipg_nic_rx_with_start_and_end(struct net_device *dev, skb->protocol = eth_type_trans(skb, dev); skb->ip_summed = CHECKSUM_NONE; netif_rx(skb); - dev->last_rx = jiffies; sp->rx_buff[entry] = NULL; } @@ -1256,7 +1255,6 @@ static void ipg_nic_rx_with_start(struct net_device *dev, jumbo->skb = skb; sp->rx_buff[entry] = NULL; - dev->last_rx = jiffies; } static void ipg_nic_rx_with_end(struct net_device *dev, @@ -1292,7 +1290,6 @@ static void ipg_nic_rx_with_end(struct net_device *dev, } } - dev->last_rx = jiffies; jumbo->found_start = 0; jumbo->current_size = 0; jumbo->skb = NULL; @@ -1325,7 +1322,6 @@ static void ipg_nic_rx_no_start_no_end(struct net_device *dev, skb->data, sp->rxfrag_size); } } - dev->last_rx = jiffies; ipg_nic_rx_free_skb(dev); } } else { @@ -1494,11 +1490,6 @@ static int ipg_nic_rx(struct net_device *dev) * when processing completes. */ netif_rx(skb); - - /* Record frame receive time (jiffies = Linux - * kernel current time stamp). - */ - dev->last_rx = jiffies; } /* Assure RX buffer is not reused by IPG. */ diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c index 2ff181861d2d05b51ccc9a1c8f8f55a5aa897027..3c58e67ef1e491c16af64cea5994cc4d88272bee 100644 --- a/drivers/net/irda/ali-ircc.c +++ b/drivers/net/irda/ali-ircc.c @@ -292,7 +292,7 @@ static int ali_ircc_open(int i, chipio_t *info) return -ENOMEM; } - self = dev->priv; + self = netdev_priv(dev); self->netdev = dev; spin_lock_init(&self->lock); @@ -665,7 +665,7 @@ static irqreturn_t ali_ircc_interrupt(int irq, void *dev_id) IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__); - self = dev->priv; + self = netdev_priv(dev); spin_lock(&self->lock); @@ -1333,7 +1333,7 @@ static int ali_ircc_net_open(struct net_device *dev) IRDA_ASSERT(dev != NULL, return -1;); - self = (struct ali_ircc_cb *) dev->priv; + self = netdev_priv(dev); IRDA_ASSERT(self != NULL, return 0;); @@ -1396,7 +1396,7 @@ static int ali_ircc_net_close(struct net_device *dev) IRDA_ASSERT(dev != NULL, return -1;); - self = (struct ali_ircc_cb *) dev->priv; + self = netdev_priv(dev); IRDA_ASSERT(self != NULL, return 0;); /* Stop device */ @@ -1436,7 +1436,7 @@ static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev) IRDA_DEBUG(1, "%s(), ---------------- Start -----------------\n", __func__ ); - self = (struct ali_ircc_cb *) dev->priv; + self = netdev_priv(dev); iobase = self->io.fir_base; netif_stop_queue(dev); @@ -1931,7 +1931,6 @@ static int ali_ircc_dma_receive_complete(struct ali_ircc_cb *self) skb_reset_mac_header(skb); skb->protocol = htons(ETH_P_IRDA); netif_rx(skb); - self->netdev->last_rx = jiffies; } } @@ -1960,7 +1959,7 @@ static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev) IRDA_ASSERT(dev != NULL, return 0;); - self = (struct ali_ircc_cb *) dev->priv; + self = netdev_priv(dev); IRDA_ASSERT(self != NULL, return 0;); iobase = self->io.sir_base; @@ -2028,7 +2027,7 @@ static int ali_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) IRDA_ASSERT(dev != NULL, return -1;); - self = dev->priv; + self = netdev_priv(dev); IRDA_ASSERT(self != NULL, return -1;); @@ -2114,7 +2113,7 @@ static int ali_ircc_is_receiving(struct ali_ircc_cb *self) static struct net_device_stats *ali_ircc_net_get_stats(struct net_device *dev) { - struct ali_ircc_cb *self = (struct ali_ircc_cb *) dev->priv; + struct ali_ircc_cb *self = netdev_priv(dev); IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__ ); diff --git a/drivers/net/irda/au1k_ir.c b/drivers/net/irda/au1k_ir.c index a1e4508717c8743bfa8f8d15c77a1383318e8884..6c4b53ffbcaccf453067a4e58b99d96df887fe8a 100644 --- a/drivers/net/irda/au1k_ir.c +++ b/drivers/net/irda/au1k_ir.c @@ -620,7 +620,6 @@ static int au1k_irda_rx(struct net_device *dev) /* next descriptor */ prxd = aup->rx_ring[aup->rx_head]; flags = prxd->flags; - dev->last_rx = jiffies; } return 0; diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c index 69d16b30323b8fca6ecb974c2e66967e115f15bc..687c2d53d4d2135a244c5be1c9438601dd8687c6 100644 --- a/drivers/net/irda/donauboe.c +++ b/drivers/net/irda/donauboe.c @@ -979,7 +979,7 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev) unsigned long flags; struct irda_skb_cb *cb = (struct irda_skb_cb *) skb->cb; - self = (struct toshoboe_cb *) dev->priv; + self = netdev_priv(dev); IRDA_ASSERT (self != NULL, return 0; ); @@ -1384,7 +1384,7 @@ toshoboe_net_close (struct net_device *dev) IRDA_DEBUG (4, "%s()\n", __func__); IRDA_ASSERT (dev != NULL, return -1; ); - self = (struct toshoboe_cb *) dev->priv; + self = netdev_priv(dev); /* Stop device */ netif_stop_queue(dev); @@ -1422,7 +1422,7 @@ toshoboe_net_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) IRDA_ASSERT (dev != NULL, return -1; ); - self = dev->priv; + self = netdev_priv(dev); IRDA_ASSERT (self != NULL, return -1; ); @@ -1546,7 +1546,7 @@ toshoboe_open (struct pci_dev *pci_dev, const struct pci_device_id *pdid) return -ENOMEM; } - self = dev->priv; + self = netdev_priv(dev); self->netdev = dev; self->pdev = pci_dev; self->base = pci_resource_start(pci_dev,0); diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index b5d6b9ac162ae813ca4f74955c32187f31fa6053..205e4e825a97639320d1898995e2de52368aefb2 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -384,7 +384,7 @@ static void speed_bulk_callback(struct urb *urb) */ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev) { - struct irda_usb_cb *self = netdev->priv; + struct irda_usb_cb *self = netdev_priv(netdev); struct urb *urb = self->tx_urb; unsigned long flags; s32 speed; @@ -628,7 +628,7 @@ static void write_bulk_callback(struct urb *urb) static void irda_usb_net_timeout(struct net_device *netdev) { unsigned long flags; - struct irda_usb_cb *self = netdev->priv; + struct irda_usb_cb *self = netdev_priv(netdev); struct urb *urb; int done = 0; /* If we have made any progress */ @@ -929,7 +929,6 @@ static void irda_usb_receive(struct urb *urb) /* Keep stats up to date */ self->stats.rx_bytes += len; self->stats.rx_packets++; - self->netdev->last_rx = jiffies; done: /* Note : at this point, the URB we've just received (urb) @@ -1175,7 +1174,7 @@ static int irda_usb_net_open(struct net_device *netdev) IRDA_DEBUG(1, "%s()\n", __func__); IRDA_ASSERT(netdev != NULL, return -1;); - self = (struct irda_usb_cb *) netdev->priv; + self = netdev_priv(netdev); IRDA_ASSERT(self != NULL, return -1;); spin_lock_irqsave(&self->lock, flags); @@ -1257,7 +1256,7 @@ static int irda_usb_net_close(struct net_device *netdev) IRDA_DEBUG(1, "%s()\n", __func__); IRDA_ASSERT(netdev != NULL, return -1;); - self = (struct irda_usb_cb *) netdev->priv; + self = netdev_priv(netdev); IRDA_ASSERT(self != NULL, return -1;); /* Clear this flag *before* unlinking the urbs and *before* @@ -1306,7 +1305,7 @@ static int irda_usb_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) int ret = 0; IRDA_ASSERT(dev != NULL, return -1;); - self = dev->priv; + self = netdev_priv(dev); IRDA_ASSERT(self != NULL, return -1;); IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __func__, dev->name, cmd); @@ -1348,7 +1347,7 @@ static int irda_usb_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) */ static struct net_device_stats *irda_usb_net_get_stats(struct net_device *dev) { - struct irda_usb_cb *self = dev->priv; + struct irda_usb_cb *self = netdev_priv(dev); return &self->stats; } @@ -1641,7 +1640,7 @@ static int irda_usb_probe(struct usb_interface *intf, goto err_out; SET_NETDEV_DEV(net, &intf->dev); - self = net->priv; + self = netdev_priv(net); self->netdev = net; spin_lock_init(&self->lock); init_timer(&self->rx_defer_timer); diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c index 6bcee01c684cd4bb3aea00abb6e2dd00ff0e8d3b..d53aa9582137d241f0cdf22e092de488ec81efb9 100644 --- a/drivers/net/irda/irtty-sir.c +++ b/drivers/net/irda/irtty-sir.c @@ -191,7 +191,7 @@ static int irtty_do_write(struct sir_dev *dev, const unsigned char *ptr, size_t tty = priv->tty; if (!tty->ops->write) return 0; - tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); + set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); writelen = tty_write_room(tty); if (writelen > len) writelen = len; @@ -263,8 +263,7 @@ static void irtty_write_wakeup(struct tty_struct *tty) IRDA_ASSERT(priv != NULL, return;); IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;); - tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); - + clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); if (priv->dev) sirdev_write_complete(priv->dev); } @@ -522,7 +521,7 @@ static void irtty_close(struct tty_struct *tty) /* Stop tty */ irtty_stop_receiver(tty, TRUE); - tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); if (tty->ops->stop) tty->ops->stop(tty); diff --git a/drivers/net/irda/kingsun-sir.c b/drivers/net/irda/kingsun-sir.c index e1429fc6d05036abc63f34d22009f850d455d7da..c747c874d44d8388acaf199ab6373761e27a0f4d 100644 --- a/drivers/net/irda/kingsun-sir.c +++ b/drivers/net/irda/kingsun-sir.c @@ -235,7 +235,6 @@ static void kingsun_rcv_irq(struct urb *urb) &kingsun->stats, &kingsun->rx_buff, bytes[i]); } - kingsun->netdev->last_rx = jiffies; do_gettimeofday(&kingsun->rx_time); kingsun->receiving = (kingsun->rx_buff.state != OUTSIDE_FRAME) diff --git a/drivers/net/irda/ks959-sir.c b/drivers/net/irda/ks959-sir.c index 2e67ae015d916eae51ca1a2ceb666b7b6905e5a7..600d96f9cdb7408d619bb78c7481c645c24caa4e 100644 --- a/drivers/net/irda/ks959-sir.c +++ b/drivers/net/irda/ks959-sir.c @@ -474,7 +474,6 @@ static void ks959_rcv_irq(struct urb *urb) bytes[i]); } } - kingsun->netdev->last_rx = jiffies; do_gettimeofday(&kingsun->rx_time); kingsun->receiving = (kingsun->rx_unwrap_buff.state != OUTSIDE_FRAME) ? 1 : 0; diff --git a/drivers/net/irda/ksdazzle-sir.c b/drivers/net/irda/ksdazzle-sir.c index 3843b5faba8b5da67a7463c02cba196b6a8b6105..0e7f89337b25791ec137eb0d910cb548fa75152e 100644 --- a/drivers/net/irda/ksdazzle-sir.c +++ b/drivers/net/irda/ksdazzle-sir.c @@ -371,7 +371,6 @@ static void ksdazzle_rcv_irq(struct urb *urb) async_unwrap_char(kingsun->netdev, &kingsun->stats, &kingsun->rx_unwrap_buff, bytes[i]); } - kingsun->netdev->last_rx = jiffies; kingsun->receiving = (kingsun->rx_unwrap_buff.state != OUTSIDE_FRAME) ? 1 : 0; } diff --git a/drivers/net/irda/ma600-sir.c b/drivers/net/irda/ma600-sir.c index 1ceed9cfb7c4fc5ba7af1ad41a847e71f24a44f3..e91216452379f318d53b2c953555593d7c796eae 100644 --- a/drivers/net/irda/ma600-sir.c +++ b/drivers/net/irda/ma600-sir.c @@ -236,7 +236,7 @@ static int ma600_change_speed(struct sir_dev *dev, unsigned speed) * avoid the state machine complexity before we get things working */ -int ma600_reset(struct sir_dev *dev) +static int ma600_reset(struct sir_dev *dev) { IRDA_DEBUG(2, "%s()\n", __func__); diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c index ad92d3ff1c4093ff6ea8281c430374ab26ff3ac2..904c9610c0dd61a5d1de949aaadc2d3a87f8bb3e 100644 --- a/drivers/net/irda/mcs7780.c +++ b/drivers/net/irda/mcs7780.c @@ -806,7 +806,6 @@ static void mcs_receive_irq(struct urb *urb) mcs_unwrap_fir(mcs, urb->transfer_buffer, urb->actual_length); } - mcs->netdev->last_rx = jiffies; do_gettimeofday(&mcs->rx_time); } diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index 8583d951a6ad15529fb4c8ec2169865582e5aa6f..2c6bf2d11bb13451d422f465110e69edd6e695a4 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c @@ -373,7 +373,7 @@ static int __init nsc_ircc_open(chipio_t *info) return -ENOMEM; } - self = dev->priv; + self = netdev_priv(dev); self->netdev = dev; spin_lock_init(&self->lock); @@ -1354,7 +1354,7 @@ static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) __s32 speed; __u8 bank; - self = (struct nsc_ircc_cb *) dev->priv; + self = netdev_priv(dev); IRDA_ASSERT(self != NULL, return 0;); @@ -1427,7 +1427,7 @@ static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) __u8 bank; int mtt, diff; - self = (struct nsc_ircc_cb *) dev->priv; + self = netdev_priv(dev); iobase = self->io.fir_base; netif_stop_queue(dev); @@ -1896,7 +1896,6 @@ static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase) skb_reset_mac_header(skb); skb->protocol = htons(ETH_P_IRDA); netif_rx(skb); - self->netdev->last_rx = jiffies; } } /* Restore bank register */ @@ -2085,7 +2084,7 @@ static irqreturn_t nsc_ircc_interrupt(int irq, void *dev_id) __u8 bsr, eir; int iobase; - self = dev->priv; + self = netdev_priv(dev); spin_lock(&self->lock); @@ -2166,7 +2165,7 @@ static int nsc_ircc_net_open(struct net_device *dev) IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(dev != NULL, return -1;); - self = (struct nsc_ircc_cb *) dev->priv; + self = netdev_priv(dev); IRDA_ASSERT(self != NULL, return 0;); @@ -2229,7 +2228,7 @@ static int nsc_ircc_net_close(struct net_device *dev) IRDA_ASSERT(dev != NULL, return -1;); - self = (struct nsc_ircc_cb *) dev->priv; + self = netdev_priv(dev); IRDA_ASSERT(self != NULL, return 0;); /* Stop device */ @@ -2275,7 +2274,7 @@ static int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) IRDA_ASSERT(dev != NULL, return -1;); - self = dev->priv; + self = netdev_priv(dev); IRDA_ASSERT(self != NULL, return -1;); @@ -2310,7 +2309,7 @@ static int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev) { - struct nsc_ircc_cb *self = (struct nsc_ircc_cb *) dev->priv; + struct nsc_ircc_cb *self = netdev_priv(dev); return &self->stats; } diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c index c5b02b66f7560a570210f075e6d72eda219e97df..a0ee053181556bd4b600f5f001ae2eba236f901e 100644 --- a/drivers/net/irda/pxaficp_ir.c +++ b/drivers/net/irda/pxaficp_ir.c @@ -225,7 +225,6 @@ static irqreturn_t pxa_irda_sir_irq(int irq, void *dev_id) } lsr = STLSR; } - dev->last_rx = jiffies; si->last_oscr = OSCR; break; @@ -237,7 +236,6 @@ static irqreturn_t pxa_irda_sir_irq(int irq, void *dev_id) si->stats.rx_bytes++; async_unwrap_char(dev, &si->stats, &si->rx_buff, STRBR); } while (STLSR & LSR_DR); - dev->last_rx = jiffies; si->last_oscr = OSCR; break; @@ -397,8 +395,6 @@ static void pxa_irda_fir_irq_eif(struct pxa_irda *si, struct net_device *dev, in si->stats.rx_packets++; si->stats.rx_bytes += len; - - dev->last_rx = jiffies; } } diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index a95188948de7b80a385ddeab5fe7b437e898aa33..ccde5829ba21139b6947e4218c9c00492487e0a1 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -298,7 +298,7 @@ static int sa1100_irda_suspend(struct platform_device *pdev, pm_message_t state) if (!dev) return 0; - si = dev->priv; + si = netdev_priv(dev); if (si->open) { /* * Stop the transmit queue @@ -323,7 +323,7 @@ static int sa1100_irda_resume(struct platform_device *pdev) if (!dev) return 0; - si = dev->priv; + si = netdev_priv(dev); if (si->open) { /* * If we missed a speed change, initialise at the new speed @@ -359,7 +359,7 @@ static int sa1100_irda_resume(struct platform_device *pdev) */ static void sa1100_irda_hpsir_irq(struct net_device *dev) { - struct sa1100_irda *si = dev->priv; + struct sa1100_irda *si = netdev_priv(dev); int status; status = Ser2UTSR0; @@ -410,7 +410,6 @@ static void sa1100_irda_hpsir_irq(struct net_device *dev) Ser2UTDR); } while (Ser2UTSR1 & UTSR1_RNE); - dev->last_rx = jiffies; } if (status & UTSR0_TFS && si->tx_buff.len) { @@ -515,7 +514,6 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev sa1100_irda_rx_alloc(si); netif_rx(skb); - dev->last_rx = jiffies; } else { /* * Remap the buffer. @@ -534,7 +532,7 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev */ static void sa1100_irda_fir_irq(struct net_device *dev) { - struct sa1100_irda *si = dev->priv; + struct sa1100_irda *si = netdev_priv(dev); /* * Stop RX DMA @@ -582,7 +580,7 @@ static void sa1100_irda_fir_irq(struct net_device *dev) static irqreturn_t sa1100_irda_irq(int irq, void *dev_id) { struct net_device *dev = dev_id; - if (IS_FIR(((struct sa1100_irda *)dev->priv))) + if (IS_FIR(((struct sa1100_irda *)netdev_priv(dev)))) sa1100_irda_fir_irq(dev); else sa1100_irda_hpsir_irq(dev); @@ -595,7 +593,7 @@ static irqreturn_t sa1100_irda_irq(int irq, void *dev_id) static void sa1100_irda_txdma_irq(void *id) { struct net_device *dev = id; - struct sa1100_irda *si = dev->priv; + struct sa1100_irda *si = netdev_priv(dev); struct sk_buff *skb = si->txskb; si->txskb = NULL; @@ -649,7 +647,7 @@ static void sa1100_irda_txdma_irq(void *id) static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) { - struct sa1100_irda *si = dev->priv; + struct sa1100_irda *si = netdev_priv(dev); int speed = irda_get_next_speed(skb); /* @@ -724,7 +722,7 @@ static int sa1100_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) { struct if_irda_req *rq = (struct if_irda_req *)ifreq; - struct sa1100_irda *si = dev->priv; + struct sa1100_irda *si = netdev_priv(dev); int ret = -EOPNOTSUPP; switch (cmd) { @@ -766,13 +764,13 @@ sa1100_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) static struct net_device_stats *sa1100_irda_stats(struct net_device *dev) { - struct sa1100_irda *si = dev->priv; + struct sa1100_irda *si = netdev_priv(dev); return &si->stats; } static int sa1100_irda_start(struct net_device *dev) { - struct sa1100_irda *si = dev->priv; + struct sa1100_irda *si = netdev_priv(dev); int err; si->speed = 9600; @@ -835,7 +833,7 @@ static int sa1100_irda_start(struct net_device *dev) static int sa1100_irda_stop(struct net_device *dev) { - struct sa1100_irda *si = dev->priv; + struct sa1100_irda *si = netdev_priv(dev); disable_irq(dev->irq); sa1100_irda_shutdown(si); @@ -908,7 +906,7 @@ static int sa1100_irda_probe(struct platform_device *pdev) if (!dev) goto err_mem_4; - si = dev->priv; + si = netdev_priv(dev); si->dev = &pdev->dev; si->pdata = pdev->dev.platform_data; @@ -987,7 +985,7 @@ static int sa1100_irda_remove(struct platform_device *pdev) struct net_device *dev = platform_get_drvdata(pdev); if (dev) { - struct sa1100_irda *si = dev->priv; + struct sa1100_irda *si = netdev_priv(dev); unregister_netdev(dev); kfree(si->tx_buff.head); kfree(si->rx_buff.head); diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c index 3f32909c24c81ff61307bd7cb37f03937221aa33..ceef040aa76d2a63c9ad579a5eb463c9a98e8bd0 100644 --- a/drivers/net/irda/sir_dev.c +++ b/drivers/net/irda/sir_dev.c @@ -584,14 +584,14 @@ EXPORT_SYMBOL(sirdev_receive); static struct net_device_stats *sirdev_get_stats(struct net_device *ndev) { - struct sir_dev *dev = ndev->priv; + struct sir_dev *dev = netdev_priv(ndev); return (dev) ? &dev->stats : NULL; } static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev) { - struct sir_dev *dev = ndev->priv; + struct sir_dev *dev = netdev_priv(ndev); unsigned long flags; int actual = 0; int err; @@ -683,7 +683,7 @@ static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev) static int sirdev_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) { struct if_irda_req *irq = (struct if_irda_req *) rq; - struct sir_dev *dev = ndev->priv; + struct sir_dev *dev = netdev_priv(ndev); int ret = 0; IRDA_ASSERT(dev != NULL, return -1;); @@ -795,7 +795,7 @@ static void sirdev_free_buffers(struct sir_dev *dev) static int sirdev_open(struct net_device *ndev) { - struct sir_dev *dev = ndev->priv; + struct sir_dev *dev = netdev_priv(ndev); const struct sir_driver *drv = dev->drv; if (!drv) @@ -840,7 +840,7 @@ static int sirdev_open(struct net_device *ndev) static int sirdev_close(struct net_device *ndev) { - struct sir_dev *dev = ndev->priv; + struct sir_dev *dev = netdev_priv(ndev); const struct sir_driver *drv; // IRDA_DEBUG(0, "%s\n", __func__); @@ -896,7 +896,7 @@ struct sir_dev * sirdev_get_instance(const struct sir_driver *drv, const char *n IRDA_ERROR("%s - Can't allocate memory for IrDA control block!\n", __func__); goto out; } - dev = ndev->priv; + dev = netdev_priv(ndev); irda_init_max_qos_capabilies(&dev->qos); dev->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index b5360fe99d3a5669b89180f96462dc8340d065f5..5d09e157e15bc1fa890b5f9c94cec44465d66352 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -872,7 +872,7 @@ static void smsc_ircc_timeout(struct net_device *dev) * waits until the next transmit interrupt, and continues until the * frame is transmitted. */ -int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) +static int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) { struct smsc_ircc_cb *self; unsigned long flags; @@ -1128,7 +1128,7 @@ static void smsc_ircc_change_speed(struct smsc_ircc_cb *self, u32 speed) * Set speed of IrDA port to specified baudrate * */ -void smsc_ircc_set_sir_speed(struct smsc_ircc_cb *self, __u32 speed) +static void smsc_ircc_set_sir_speed(struct smsc_ircc_cb *self, __u32 speed) { int iobase; int fcr; /* FIFO control reg */ @@ -1894,7 +1894,7 @@ static void __exit smsc_ircc_cleanup(void) * This function *must* be called with spinlock held, because it may * be called from the irq handler (via smsc_ircc_change_speed()). - Jean II */ -void smsc_ircc_sir_start(struct smsc_ircc_cb *self) +static void smsc_ircc_sir_start(struct smsc_ircc_cb *self) { struct net_device *dev; int fir_base, sir_base; diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c index 3575804fd7c644b4fe5202a289b80eb20b59a799..ca4cd9266e55ef45c97d77e0afada0eb67a8677e 100644 --- a/drivers/net/irda/stir4200.c +++ b/drivers/net/irda/stir4200.c @@ -824,7 +824,6 @@ static void stir_rcv_irq(struct urb *urb) unwrap_chars(stir, urb->transfer_buffer, urb->actual_length); - stir->netdev->last_rx = jiffies; do_gettimeofday(&stir->rx_time); } diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c index 84e609ea5fbbc1a5e1a25d72a60b9aa369ea9a73..74c78cf7a333c95b49ea7c2ecd0f2703266c3044 100644 --- a/drivers/net/irda/via-ircc.c +++ b/drivers/net/irda/via-ircc.c @@ -334,7 +334,7 @@ static __devinit int via_ircc_open(int i, chipio_t * info, unsigned int id) if (dev == NULL) return -ENOMEM; - self = dev->priv; + self = netdev_priv(dev); self->netdev = dev; spin_lock_init(&self->lock); @@ -824,7 +824,7 @@ static int via_ircc_hard_xmit_sir(struct sk_buff *skb, u16 iobase; __u32 speed; - self = (struct via_ircc_cb *) dev->priv; + self = netdev_priv(dev); IRDA_ASSERT(self != NULL, return 0;); iobase = self->io.fir_base; @@ -896,7 +896,7 @@ static int via_ircc_hard_xmit_fir(struct sk_buff *skb, __u32 speed; unsigned long flags; - self = (struct via_ircc_cb *) dev->priv; + self = netdev_priv(dev); iobase = self->io.fir_base; if (self->st_fifo.len) @@ -1349,7 +1349,7 @@ static int RxTimerHandler(struct via_ircc_cb *self, int iobase) static irqreturn_t via_ircc_interrupt(int dummy, void *dev_id) { struct net_device *dev = dev_id; - struct via_ircc_cb *self = dev->priv; + struct via_ircc_cb *self = netdev_priv(dev); int iobase; u8 iHostIntType, iRxIntType, iTxIntType; @@ -1522,7 +1522,7 @@ static int via_ircc_net_open(struct net_device *dev) IRDA_DEBUG(3, "%s()\n", __func__); IRDA_ASSERT(dev != NULL, return -1;); - self = (struct via_ircc_cb *) dev->priv; + self = netdev_priv(dev); self->stats.rx_packets = 0; IRDA_ASSERT(self != NULL, return 0;); iobase = self->io.fir_base; @@ -1589,7 +1589,7 @@ static int via_ircc_net_close(struct net_device *dev) IRDA_DEBUG(3, "%s()\n", __func__); IRDA_ASSERT(dev != NULL, return -1;); - self = (struct via_ircc_cb *) dev->priv; + self = netdev_priv(dev); IRDA_ASSERT(self != NULL, return 0;); /* Stop device */ @@ -1628,7 +1628,7 @@ static int via_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int ret = 0; IRDA_ASSERT(dev != NULL, return -1;); - self = dev->priv; + self = netdev_priv(dev); IRDA_ASSERT(self != NULL, return -1;); IRDA_DEBUG(1, "%s(), %s, (cmd=0x%X)\n", __func__, dev->name, cmd); @@ -1663,7 +1663,7 @@ static int via_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, static struct net_device_stats *via_ircc_net_get_stats(struct net_device *dev) { - struct via_ircc_cb *self = (struct via_ircc_cb *) dev->priv; + struct via_ircc_cb *self = netdev_priv(dev); return &self->stats; } diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c index 9c926d205de971d69ee7873522ec4a657dfc8cfb..0d30f8d659a1995b083eb4e507833dd7fa92f0d7 100644 --- a/drivers/net/irda/vlsi_ir.c +++ b/drivers/net/irda/vlsi_ir.c @@ -178,7 +178,7 @@ static void vlsi_proc_pdev(struct seq_file *seq, struct pci_dev *pdev) static void vlsi_proc_ndev(struct seq_file *seq, struct net_device *ndev) { - vlsi_irda_dev_t *idev = ndev->priv; + vlsi_irda_dev_t *idev = netdev_priv(ndev); u8 byte; u16 word; unsigned delta1, delta2; @@ -346,7 +346,7 @@ static void vlsi_proc_ring(struct seq_file *seq, struct vlsi_ring *r) static int vlsi_seq_show(struct seq_file *seq, void *v) { struct net_device *ndev = seq->private; - vlsi_irda_dev_t *idev = ndev->priv; + vlsi_irda_dev_t *idev = netdev_priv(ndev); unsigned long flags; seq_printf(seq, "\n%s %s\n\n", DRIVER_NAME, DRIVER_VERSION); @@ -543,7 +543,7 @@ static int vlsi_process_rx(struct vlsi_ring *r, struct ring_descr *rd) struct sk_buff *skb; int ret = 0; struct net_device *ndev = (struct net_device *)pci_get_drvdata(r->pdev); - vlsi_irda_dev_t *idev = ndev->priv; + vlsi_irda_dev_t *idev = netdev_priv(ndev); pci_dma_sync_single_for_cpu(r->pdev, rd_get_addr(rd), r->len, r->dir); /* dma buffer now owned by the CPU */ @@ -600,7 +600,6 @@ static int vlsi_process_rx(struct vlsi_ring *r, struct ring_descr *rd) netif_rx(skb); else netif_rx_ni(skb); - ndev->last_rx = jiffies; done: rd_set_status(rd, 0); @@ -638,7 +637,7 @@ static void vlsi_fill_rx(struct vlsi_ring *r) static void vlsi_rx_interrupt(struct net_device *ndev) { - vlsi_irda_dev_t *idev = ndev->priv; + vlsi_irda_dev_t *idev = netdev_priv(ndev); struct vlsi_ring *r = idev->rx_ring; struct ring_descr *rd; int ret; @@ -856,7 +855,7 @@ static int vlsi_set_baud(vlsi_irda_dev_t *idev, unsigned iobase) static int vlsi_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) { - vlsi_irda_dev_t *idev = ndev->priv; + vlsi_irda_dev_t *idev = netdev_priv(ndev); struct vlsi_ring *r = idev->tx_ring; struct ring_descr *rd; unsigned long flags; @@ -1063,7 +1062,7 @@ static int vlsi_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) static void vlsi_tx_interrupt(struct net_device *ndev) { - vlsi_irda_dev_t *idev = ndev->priv; + vlsi_irda_dev_t *idev = netdev_priv(ndev); struct vlsi_ring *r = idev->tx_ring; struct ring_descr *rd; unsigned iobase; @@ -1262,7 +1261,7 @@ static inline void vlsi_clear_regs(unsigned iobase) static int vlsi_init_chip(struct pci_dev *pdev) { struct net_device *ndev = pci_get_drvdata(pdev); - vlsi_irda_dev_t *idev = ndev->priv; + vlsi_irda_dev_t *idev = netdev_priv(ndev); unsigned iobase; u16 ptr; @@ -1376,14 +1375,14 @@ static int vlsi_stop_hw(vlsi_irda_dev_t *idev) static struct net_device_stats * vlsi_get_stats(struct net_device *ndev) { - vlsi_irda_dev_t *idev = ndev->priv; + vlsi_irda_dev_t *idev = netdev_priv(ndev); return &idev->stats; } static void vlsi_tx_timeout(struct net_device *ndev) { - vlsi_irda_dev_t *idev = ndev->priv; + vlsi_irda_dev_t *idev = netdev_priv(ndev); vlsi_reg_debug(ndev->base_addr, __func__); @@ -1408,7 +1407,7 @@ static void vlsi_tx_timeout(struct net_device *ndev) static int vlsi_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) { - vlsi_irda_dev_t *idev = ndev->priv; + vlsi_irda_dev_t *idev = netdev_priv(ndev); struct if_irda_req *irq = (struct if_irda_req *) rq; unsigned long flags; u16 fifocnt; @@ -1458,7 +1457,7 @@ static int vlsi_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) static irqreturn_t vlsi_interrupt(int irq, void *dev_instance) { struct net_device *ndev = dev_instance; - vlsi_irda_dev_t *idev = ndev->priv; + vlsi_irda_dev_t *idev = netdev_priv(ndev); unsigned iobase; u8 irintr; int boguscount = 5; @@ -1499,7 +1498,7 @@ static irqreturn_t vlsi_interrupt(int irq, void *dev_instance) static int vlsi_open(struct net_device *ndev) { - vlsi_irda_dev_t *idev = ndev->priv; + vlsi_irda_dev_t *idev = netdev_priv(ndev); int err = -EAGAIN; char hwname[32]; @@ -1558,7 +1557,7 @@ static int vlsi_open(struct net_device *ndev) static int vlsi_close(struct net_device *ndev) { - vlsi_irda_dev_t *idev = ndev->priv; + vlsi_irda_dev_t *idev = netdev_priv(ndev); netif_stop_queue(ndev); @@ -1581,7 +1580,7 @@ static int vlsi_close(struct net_device *ndev) static int vlsi_irda_init(struct net_device *ndev) { - vlsi_irda_dev_t *idev = ndev->priv; + vlsi_irda_dev_t *idev = netdev_priv(ndev); struct pci_dev *pdev = idev->pdev; ndev->irq = pdev->irq; @@ -1656,7 +1655,7 @@ vlsi_irda_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto out_disable; } - idev = ndev->priv; + idev = netdev_priv(ndev); spin_lock_init(&idev->lock); mutex_init(&idev->mtx); @@ -1713,7 +1712,7 @@ static void __devexit vlsi_irda_remove(struct pci_dev *pdev) unregister_netdev(ndev); - idev = ndev->priv; + idev = netdev_priv(ndev); mutex_lock(&idev->mtx); if (idev->proc_entry) { remove_proc_entry(ndev->name, vlsi_proc_root); @@ -1748,7 +1747,7 @@ static int vlsi_irda_suspend(struct pci_dev *pdev, pm_message_t state) __func__, pci_name(pdev)); return 0; } - idev = ndev->priv; + idev = netdev_priv(ndev); mutex_lock(&idev->mtx); if (pdev->current_state != 0) { /* already suspended */ if (state.event > pdev->current_state) { /* simply go deeper */ @@ -1787,7 +1786,7 @@ static int vlsi_irda_resume(struct pci_dev *pdev) __func__, pci_name(pdev)); return 0; } - idev = ndev->priv; + idev = netdev_priv(ndev); mutex_lock(&idev->mtx); if (pdev->current_state == 0) { mutex_unlock(&idev->mtx); diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c index 002a6d769f21f244912b6584c33e9e6a4cc92615..30ec9131c5ce2cf41849dcb2040cc9eb500a33cd 100644 --- a/drivers/net/irda/w83977af_ir.c +++ b/drivers/net/irda/w83977af_ir.c @@ -147,8 +147,8 @@ static void __exit w83977af_cleanup(void) * Open driver instance * */ -int w83977af_open(int i, unsigned int iobase, unsigned int irq, - unsigned int dma) +static int w83977af_open(int i, unsigned int iobase, unsigned int irq, + unsigned int dma) { struct net_device *dev; struct w83977af_ir *self; @@ -178,7 +178,7 @@ int w83977af_open(int i, unsigned int iobase, unsigned int irq, goto err_out; } - self = dev->priv; + self = netdev_priv(dev); spin_lock_init(&self->lock); @@ -310,7 +310,7 @@ static int w83977af_close(struct w83977af_ir *self) return 0; } -int w83977af_probe( int iobase, int irq, int dma) +static int w83977af_probe(int iobase, int irq, int dma) { int version; int i; @@ -409,7 +409,7 @@ int w83977af_probe( int iobase, int irq, int dma) return -1; } -void w83977af_change_speed(struct w83977af_ir *self, __u32 speed) +static void w83977af_change_speed(struct w83977af_ir *self, __u32 speed) { int ir_mode = HCR_SIR; int iobase; @@ -489,7 +489,7 @@ void w83977af_change_speed(struct w83977af_ir *self, __u32 speed) * Sets up a DMA transfer to send the current frame. * */ -int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev) +static int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev) { struct w83977af_ir *self; __s32 speed; @@ -497,7 +497,7 @@ int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev) __u8 set; int mtt; - self = (struct w83977af_ir *) dev->priv; + self = netdev_priv(dev); iobase = self->io.fir_base; @@ -731,7 +731,7 @@ static void w83977af_dma_xmit_complete(struct w83977af_ir *self) * if it starts to receive a frame. * */ -int w83977af_dma_receive(struct w83977af_ir *self) +static int w83977af_dma_receive(struct w83977af_ir *self) { int iobase; __u8 set; @@ -803,7 +803,7 @@ int w83977af_dma_receive(struct w83977af_ir *self) * Finished with receiving a frame * */ -int w83977af_dma_receive_complete(struct w83977af_ir *self) +static int w83977af_dma_receive_complete(struct w83977af_ir *self) { struct sk_buff *skb; struct st_fifo *st_fifo; @@ -923,7 +923,6 @@ int w83977af_dma_receive_complete(struct w83977af_ir *self) skb_reset_mac_header(skb); skb->protocol = htons(ETH_P_IRDA); netif_rx(skb); - self->netdev->last_rx = jiffies; } } /* Restore set register */ @@ -1119,7 +1118,7 @@ static irqreturn_t w83977af_interrupt(int irq, void *dev_id) __u8 set, icr, isr; int iobase; - self = dev->priv; + self = netdev_priv(dev); iobase = self->io.fir_base; @@ -1192,7 +1191,7 @@ static int w83977af_net_open(struct net_device *dev) IRDA_DEBUG(0, "%s()\n", __func__ ); IRDA_ASSERT(dev != NULL, return -1;); - self = (struct w83977af_ir *) dev->priv; + self = netdev_priv(dev); IRDA_ASSERT(self != NULL, return 0;); @@ -1256,7 +1255,7 @@ static int w83977af_net_close(struct net_device *dev) IRDA_ASSERT(dev != NULL, return -1;); - self = (struct w83977af_ir *) dev->priv; + self = netdev_priv(dev); IRDA_ASSERT(self != NULL, return 0;); @@ -1303,7 +1302,7 @@ static int w83977af_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) IRDA_ASSERT(dev != NULL, return -1;); - self = dev->priv; + self = netdev_priv(dev); IRDA_ASSERT(self != NULL, return -1;); @@ -1339,7 +1338,7 @@ static int w83977af_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) static struct net_device_stats *w83977af_net_get_stats(struct net_device *dev) { - struct w83977af_ir *self = (struct w83977af_ir *) dev->priv; + struct w83977af_ir *self = netdev_priv(dev); return &self->stats; } diff --git a/drivers/net/isa-skeleton.c b/drivers/net/isa-skeleton.c index d6ff26af37b3e5c1dc5a60d5c979819855389e1b..3126678bdd3c593f6035fb62ce864ef6d4d02d39 100644 --- a/drivers/net/isa-skeleton.c +++ b/drivers/net/isa-skeleton.c @@ -192,7 +192,6 @@ static int __init netcard_probe1(struct net_device *dev, int ioaddr) static unsigned version_printed; int i; int err = -ENODEV; - DECLARE_MAC_BUF(mac); /* Grab the region so that no one else tries to probe our ioports. */ if (!request_region(ioaddr, NETCARD_IO_EXTENT, cardname)) @@ -220,7 +219,7 @@ static int __init netcard_probe1(struct net_device *dev, int ioaddr) for (i = 0; i < 6; i++) dev->dev_addr[i] = inb(ioaddr + i); - printk("%s", print_mac(mac, dev->dev_addr)); + printk("%pM", dev->dev_addr); err = -EAGAIN; #ifdef jumpered_interrupts @@ -584,7 +583,6 @@ net_rx(struct net_device *dev) insw(ioaddr, skb->data, (pkt_len + 1) >> 1); netif_rx(skb); - dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes += pkt_len; } @@ -711,15 +709,3 @@ cleanup_module(void) } #endif /* MODULE */ - -/* - * Local variables: - * compile-command: - * gcc -D__KERNEL__ -Wall -Wstrict-prototypes -Wwrite-strings - * -Wredundant-decls -O2 -m486 -c skeleton.c - * version-control: t - * kept-new-versions: 5 - * tab-width: 4 - * c-indent-level: 4 - * End: - */ diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c index c46864d626b28e44b7e25669ea319d1f74a2dd53..c7457f97259d9ad9d60226b76f22d45108206d60 100644 --- a/drivers/net/iseries_veth.c +++ b/drivers/net/iseries_veth.c @@ -952,7 +952,7 @@ static int veth_change_mtu(struct net_device *dev, int new_mtu) static void veth_set_multicast_list(struct net_device *dev) { - struct veth_port *port = (struct veth_port *) dev->priv; + struct veth_port *port = netdev_priv(dev); unsigned long flags; write_lock_irqsave(&port->mcast_gate, flags); @@ -1044,7 +1044,7 @@ static struct net_device *veth_probe_one(int vlan, return NULL; } - port = (struct veth_port *) dev->priv; + port = netdev_priv(dev); spin_lock_init(&port->queue_lock); rwlock_init(&port->mcast_gate); @@ -1102,7 +1102,7 @@ static int veth_transmit_to_one(struct sk_buff *skb, HvLpIndex rlp, struct net_device *dev) { struct veth_lpar_connection *cnx = veth_cnx[rlp]; - struct veth_port *port = (struct veth_port *) dev->priv; + struct veth_port *port = netdev_priv(dev); HvLpEvent_Rc rc; struct veth_msg *msg = NULL; unsigned long flags; @@ -1191,7 +1191,7 @@ static void veth_transmit_to_many(struct sk_buff *skb, static int veth_start_xmit(struct sk_buff *skb, struct net_device *dev) { unsigned char *frame = skb->data; - struct veth_port *port = (struct veth_port *) dev->priv; + struct veth_port *port = netdev_priv(dev); HvLpIndexMap lpmask; if (! (frame[0] & 0x01)) { @@ -1255,7 +1255,7 @@ static void veth_wake_queues(struct veth_lpar_connection *cnx) if (! dev) continue; - port = (struct veth_port *)dev->priv; + port = netdev_priv(dev); if (! (port->lpar_map & (1<remote_lp))) continue; @@ -1284,7 +1284,7 @@ static void veth_stop_queues(struct veth_lpar_connection *cnx) if (! dev) continue; - port = (struct veth_port *)dev->priv; + port = netdev_priv(dev); /* If this cnx is not on the vlan for this port, continue */ if (! (port->lpar_map & (1 << cnx->remote_lp))) @@ -1506,7 +1506,7 @@ static void veth_receive(struct veth_lpar_connection *cnx, continue; } - port = (struct veth_port *)dev->priv; + port = netdev_priv(dev); dest = *((u64 *) skb->data) & 0xFFFFFFFFFFFF0000; if ((vlan > HVMAXARCHITECTEDVIRTUALLANS) || !port) { diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index be3c7dc96f633d2842d6394abd72a469b27e6dab..eee28d3956827cb8dcb3951df9738ab6c9cd54e6 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -321,6 +321,24 @@ ixgb_reset(struct ixgb_adapter *adapter) } } +static const struct net_device_ops ixgb_netdev_ops = { + .ndo_open = ixgb_open, + .ndo_stop = ixgb_close, + .ndo_start_xmit = ixgb_xmit_frame, + .ndo_get_stats = ixgb_get_stats, + .ndo_set_multicast_list = ixgb_set_multi, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = ixgb_set_mac, + .ndo_change_mtu = ixgb_change_mtu, + .ndo_tx_timeout = ixgb_tx_timeout, + .ndo_vlan_rx_register = ixgb_vlan_rx_register, + .ndo_vlan_rx_add_vid = ixgb_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = ixgb_vlan_rx_kill_vid, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = ixgb_netpoll, +#endif +}; + /** * ixgb_probe - Device Initialization Routine * @pdev: PCI device information struct @@ -381,8 +399,7 @@ ixgb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) adapter->hw.back = adapter; adapter->msg_enable = netif_msg_init(debug, DEFAULT_DEBUG_LEVEL_SHIFT); - adapter->hw.hw_addr = ioremap(pci_resource_start(pdev, BAR_0), - pci_resource_len(pdev, BAR_0)); + adapter->hw.hw_addr = pci_ioremap_bar(pdev, BAR_0); if (!adapter->hw.hw_addr) { err = -EIO; goto err_ioremap; @@ -397,23 +414,10 @@ ixgb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } } - netdev->open = &ixgb_open; - netdev->stop = &ixgb_close; - netdev->hard_start_xmit = &ixgb_xmit_frame; - netdev->get_stats = &ixgb_get_stats; - netdev->set_multicast_list = &ixgb_set_multi; - netdev->set_mac_address = &ixgb_set_mac; - netdev->change_mtu = &ixgb_change_mtu; + netdev->netdev_ops = &ixgb_netdev_ops; ixgb_set_ethtool_ops(netdev); - netdev->tx_timeout = &ixgb_tx_timeout; netdev->watchdog_timeo = 5 * HZ; netif_napi_add(netdev, &adapter->napi, ixgb_clean, 64); - netdev->vlan_rx_register = ixgb_vlan_rx_register; - netdev->vlan_rx_add_vid = ixgb_vlan_rx_add_vid; - netdev->vlan_rx_kill_vid = ixgb_vlan_rx_kill_vid; -#ifdef CONFIG_NET_POLL_CONTROLLER - netdev->poll_controller = ixgb_netpoll; -#endif strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1); @@ -1106,8 +1110,15 @@ ixgb_watchdog(unsigned long data) if (adapter->hw.link_up) { if (!netif_carrier_ok(netdev)) { - DPRINTK(LINK, INFO, - "NIC Link is Up 10000 Mbps Full Duplex\n"); + printk(KERN_INFO "ixgb: %s NIC Link is Up 10 Gbps " + "Full Duplex, Flow Control: %s\n", + netdev->name, + (adapter->hw.fc.type == ixgb_fc_full) ? + "RX/TX" : + ((adapter->hw.fc.type == ixgb_fc_rx_pause) ? + "RX" : + ((adapter->hw.fc.type == ixgb_fc_tx_pause) ? + "TX" : "None"))); adapter->link_speed = 10000; adapter->link_duplex = FULL_DUPLEX; netif_carrier_on(netdev); @@ -1117,7 +1128,8 @@ ixgb_watchdog(unsigned long data) if (netif_carrier_ok(netdev)) { adapter->link_speed = 0; adapter->link_duplex = 0; - DPRINTK(LINK, INFO, "NIC Link is Down\n"); + printk(KERN_INFO "ixgb: %s NIC Link is Down\n", + netdev->name); netif_carrier_off(netdev); netif_stop_queue(netdev); @@ -1709,14 +1721,14 @@ ixgb_intr(int irq, void *data) if (!test_bit(__IXGB_DOWN, &adapter->flags)) mod_timer(&adapter->watchdog_timer, jiffies); - if (netif_rx_schedule_prep(netdev, &adapter->napi)) { + if (netif_rx_schedule_prep(&adapter->napi)) { /* Disable interrupts and register for poll. The flush of the posted write is intentionally left out. */ IXGB_WRITE_REG(&adapter->hw, IMC, ~0); - __netif_rx_schedule(netdev, &adapter->napi); + __netif_rx_schedule(&adapter->napi); } return IRQ_HANDLED; } @@ -1730,7 +1742,6 @@ static int ixgb_clean(struct napi_struct *napi, int budget) { struct ixgb_adapter *adapter = container_of(napi, struct ixgb_adapter, napi); - struct net_device *netdev = adapter->netdev; int work_done = 0; ixgb_clean_tx_irq(adapter); @@ -1738,7 +1749,7 @@ ixgb_clean(struct napi_struct *napi, int budget) /* If budget not fully consumed, exit the polling mode */ if (work_done < budget) { - netif_rx_complete(netdev, napi); + netif_rx_complete(napi); if (!test_bit(__IXGB_DOWN, &adapter->flags)) ixgb_irq_enable(adapter); } @@ -1981,7 +1992,6 @@ ixgb_clean_rx_irq(struct ixgb_adapter *adapter, int *work_done, int work_to_do) } else { netif_receive_skb(skb); } - netdev->last_rx = jiffies; rxdesc_done: /* clean up descriptor, might be written over by hw */ diff --git a/drivers/net/ixgbe/Makefile b/drivers/net/ixgbe/Makefile index ccd83d9f579ef48cff32d3586535faea655e17fa..6e7ef765bcd882ec2257dcd5c244f0352846f36c 100644 --- a/drivers/net/ixgbe/Makefile +++ b/drivers/net/ixgbe/Makefile @@ -34,3 +34,5 @@ obj-$(CONFIG_IXGBE) += ixgbe.o ixgbe-objs := ixgbe_main.o ixgbe_common.o ixgbe_ethtool.o \ ixgbe_82598.o ixgbe_phy.o + +ixgbe-$(CONFIG_IXGBE_DCB) += ixgbe_dcb.o ixgbe_dcb_82598.o ixgbe_dcb_nl.o diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index e116d340dcc6e158b35160f43ccd76d92feaa796..e112008f39c1dc889a73e4b9c0af5a4ceb7b95f1 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -32,10 +32,11 @@ #include #include #include +#include #include "ixgbe_type.h" #include "ixgbe_common.h" - +#include "ixgbe_dcb.h" #ifdef CONFIG_IXGBE_DCA #include #endif @@ -84,6 +85,7 @@ #define IXGBE_TX_FLAGS_TSO (u32)(1 << 2) #define IXGBE_TX_FLAGS_IPV4 (u32)(1 << 3) #define IXGBE_TX_FLAGS_VLAN_MASK 0xffff0000 +#define IXGBE_TX_FLAGS_VLAN_PRIO_MASK 0x0000e000 #define IXGBE_TX_FLAGS_VLAN_SHIFT 16 #define IXGBE_MAX_LRO_DESCRIPTORS 8 @@ -134,7 +136,7 @@ struct ixgbe_ring { u16 reg_idx; /* holds the special value that gets the hardware register * offset associated with this ring, which is different - * for DCE and RSS modes */ + * for DCB and RSS modes */ #ifdef CONFIG_IXGBE_DCA /* cpu for tx queue */ @@ -152,8 +154,10 @@ struct ixgbe_ring { u16 rx_buf_len; }; +#define RING_F_DCB 0 #define RING_F_VMDQ 1 #define RING_F_RSS 2 +#define IXGBE_MAX_DCB_INDICES 8 #define IXGBE_MAX_RSS_INDICES 16 #define IXGBE_MAX_VMDQ_INDICES 16 struct ixgbe_ring_feature { @@ -164,6 +168,10 @@ struct ixgbe_ring_feature { #define MAX_RX_QUEUES 64 #define MAX_TX_QUEUES 32 +#define MAX_RX_PACKET_BUFFERS ((adapter->flags & IXGBE_FLAG_DCB_ENABLED) \ + ? 8 : 1) +#define MAX_TX_PACKET_BUFFERS MAX_RX_PACKET_BUFFERS + /* MAX_MSIX_Q_VECTORS of these are allocated, * but we only use one per queue-specific vector. */ @@ -215,6 +223,9 @@ struct ixgbe_adapter { struct work_struct reset_task; struct ixgbe_q_vector q_vector[MAX_MSIX_Q_VECTORS]; char name[MAX_MSIX_COUNT][IFNAMSIZ + 5]; + struct ixgbe_dcb_config dcb_cfg; + struct ixgbe_dcb_config temp_dcb_cfg; + u8 dcb_set_bitmap; /* Interrupt Throttle Rate */ u32 itr_setting; @@ -267,8 +278,10 @@ struct ixgbe_adapter { #define IXGBE_FLAG_RSS_CAPABLE (u32)(1 << 17) #define IXGBE_FLAG_VMDQ_CAPABLE (u32)(1 << 18) #define IXGBE_FLAG_VMDQ_ENABLED (u32)(1 << 19) +#define IXGBE_FLAG_FAN_FAIL_CAPABLE (u32)(1 << 20) #define IXGBE_FLAG_NEED_LINK_UPDATE (u32)(1 << 22) #define IXGBE_FLAG_IN_WATCHDOG_TASK (u32)(1 << 23) +#define IXGBE_FLAG_DCB_ENABLED (u32)(1 << 24) /* default to trying for four seconds */ #define IXGBE_TRY_LINK_TIMEOUT (4 * HZ) @@ -299,12 +312,15 @@ struct ixgbe_adapter { unsigned long link_check_timeout; struct work_struct watchdog_task; + struct work_struct sfp_task; + struct timer_list sfp_timer; }; enum ixbge_state_t { __IXGBE_TESTING, __IXGBE_RESETTING, - __IXGBE_DOWN + __IXGBE_DOWN, + __IXGBE_SFP_MODULE_NOT_FOUND }; enum ixgbe_boards { @@ -312,6 +328,12 @@ enum ixgbe_boards { }; extern struct ixgbe_info ixgbe_82598_info; +#ifdef CONFIG_IXGBE_DCB +extern struct dcbnl_rtnl_ops dcbnl_ops; +extern int ixgbe_copy_dcb_cfg(struct ixgbe_dcb_config *src_dcb_cfg, + struct ixgbe_dcb_config *dst_dcb_cfg, + int tc_max); +#endif extern char ixgbe_driver_name[]; extern const char ixgbe_driver_version[]; @@ -326,5 +348,9 @@ extern int ixgbe_setup_tx_resources(struct ixgbe_adapter *, struct ixgbe_ring *) extern void ixgbe_free_rx_resources(struct ixgbe_adapter *, struct ixgbe_ring *); extern void ixgbe_free_tx_resources(struct ixgbe_adapter *, struct ixgbe_ring *); extern void ixgbe_update_stats(struct ixgbe_adapter *adapter); +extern void ixgbe_reset_interrupt_capability(struct ixgbe_adapter *adapter); +extern int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter); +void ixgbe_napi_add_all(struct ixgbe_adapter *adapter); +void ixgbe_napi_del_all(struct ixgbe_adapter *adapter); #endif /* _IXGBE_H_ */ diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c index 7cddcfba809e73bbd86a6ae108951de1f21376d3..ad5699d9ab0dacaaecf5fd6069b1268ff07d5e9c 100644 --- a/drivers/net/ixgbe/ixgbe_82598.c +++ b/drivers/net/ixgbe/ixgbe_82598.c @@ -46,6 +46,8 @@ static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg, bool autoneg_wait_to_complete); +static s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset, + u8 *eeprom_data); /** */ @@ -53,12 +55,40 @@ static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw) { struct ixgbe_mac_info *mac = &hw->mac; struct ixgbe_phy_info *phy = &hw->phy; + s32 ret_val = 0; + u16 list_offset, data_offset; /* Call PHY identify routine to get the phy type */ ixgbe_identify_phy_generic(hw); /* PHY Init */ switch (phy->type) { + case ixgbe_phy_tn: + phy->ops.check_link = &ixgbe_check_phy_link_tnx; + phy->ops.get_firmware_version = + &ixgbe_get_phy_firmware_version_tnx; + break; + case ixgbe_phy_nl: + phy->ops.reset = &ixgbe_reset_phy_nl; + + /* Call SFP+ identify routine to get the SFP+ module type */ + ret_val = phy->ops.identify_sfp(hw); + if (ret_val != 0) + goto out; + else if (hw->phy.sfp_type == ixgbe_sfp_type_unknown) { + ret_val = IXGBE_ERR_SFP_NOT_SUPPORTED; + goto out; + } + + /* Check to see if SFP+ module is supported */ + ret_val = ixgbe_get_sfp_init_sequence_offsets(hw, + &list_offset, + &data_offset); + if (ret_val != 0) { + ret_val = IXGBE_ERR_SFP_NOT_SUPPORTED; + goto out; + } + break; default: break; } @@ -77,7 +107,8 @@ static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw) mac->max_rx_queues = IXGBE_82598_MAX_RX_QUEUES; mac->max_tx_queues = IXGBE_82598_MAX_TX_QUEUES; - return 0; +out: + return ret_val; } /** @@ -146,9 +177,9 @@ static s32 ixgbe_get_link_capabilities_82598(struct ixgbe_hw *hw, * * Determines the link capabilities by reading the AUTOC register. **/ -s32 ixgbe_get_copper_link_capabilities_82598(struct ixgbe_hw *hw, - ixgbe_link_speed *speed, - bool *autoneg) +static s32 ixgbe_get_copper_link_capabilities_82598(struct ixgbe_hw *hw, + ixgbe_link_speed *speed, + bool *autoneg) { s32 status = IXGBE_ERR_LINK_SETUP; u16 speed_ability; @@ -186,9 +217,15 @@ static enum ixgbe_media_type ixgbe_get_media_type_82598(struct ixgbe_hw *hw) case IXGBE_DEV_ID_82598AF_SINGLE_PORT: case IXGBE_DEV_ID_82598EB_CX4: case IXGBE_DEV_ID_82598_CX4_DUAL_PORT: + case IXGBE_DEV_ID_82598_DA_DUAL_PORT: + case IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM: case IXGBE_DEV_ID_82598EB_XF_LR: + case IXGBE_DEV_ID_82598EB_SFP_LOM: media_type = ixgbe_media_type_fiber; break; + case IXGBE_DEV_ID_82598AT: + media_type = ixgbe_media_type_copper; + break; default: media_type = ixgbe_media_type_unknown; break; @@ -205,7 +242,7 @@ static enum ixgbe_media_type ixgbe_get_media_type_82598(struct ixgbe_hw *hw) * Configures the flow control settings based on SW configuration. This * function is used for 802.3x flow control configuration only. **/ -s32 ixgbe_setup_fc_82598(struct ixgbe_hw *hw, s32 packetbuf_num) +static s32 ixgbe_setup_fc_82598(struct ixgbe_hw *hw, s32 packetbuf_num) { u32 frctl_reg; u32 rmcs_reg; @@ -391,6 +428,46 @@ static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, { u32 links_reg; u32 i; + u16 link_reg, adapt_comp_reg; + + /* + * SERDES PHY requires us to read link status from register 0xC79F. + * Bit 0 set indicates link is up/ready; clear indicates link down. + * 0xC00C is read to check that the XAUI lanes are active. Bit 0 + * clear indicates active; set indicates inactive. + */ + if (hw->phy.type == ixgbe_phy_nl) { + hw->phy.ops.read_reg(hw, 0xC79F, IXGBE_TWINAX_DEV, &link_reg); + hw->phy.ops.read_reg(hw, 0xC79F, IXGBE_TWINAX_DEV, &link_reg); + hw->phy.ops.read_reg(hw, 0xC00C, IXGBE_TWINAX_DEV, + &adapt_comp_reg); + if (link_up_wait_to_complete) { + for (i = 0; i < IXGBE_LINK_UP_TIME; i++) { + if ((link_reg & 1) && + ((adapt_comp_reg & 1) == 0)) { + *link_up = true; + break; + } else { + *link_up = false; + } + msleep(100); + hw->phy.ops.read_reg(hw, 0xC79F, + IXGBE_TWINAX_DEV, + &link_reg); + hw->phy.ops.read_reg(hw, 0xC00C, + IXGBE_TWINAX_DEV, + &adapt_comp_reg); + } + } else { + if ((link_reg & 1) && ((adapt_comp_reg & 1) == 0)) + *link_up = true; + else + *link_up = false; + } + + if (*link_up == false) + goto out; + } links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS); if (link_up_wait_to_complete) { @@ -416,6 +493,7 @@ static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, else *speed = IXGBE_LINK_SPEED_1GB_FULL; +out: return 0; } @@ -648,7 +726,7 @@ static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw) * @rar: receive address register index to associate with a VMDq index * @vmdq: VMDq set index **/ -s32 ixgbe_set_vmdq_82598(struct ixgbe_hw *hw, u32 rar, u32 vmdq) +static s32 ixgbe_set_vmdq_82598(struct ixgbe_hw *hw, u32 rar, u32 vmdq) { u32 rar_high; @@ -692,8 +770,8 @@ static s32 ixgbe_clear_vmdq_82598(struct ixgbe_hw *hw, u32 rar, u32 vmdq) * * Turn on/off specified VLAN in the VLAN filter table. **/ -s32 ixgbe_set_vfta_82598(struct ixgbe_hw *hw, u32 vlan, u32 vind, - bool vlan_on) +static s32 ixgbe_set_vfta_82598(struct ixgbe_hw *hw, u32 vlan, u32 vind, + bool vlan_on) { u32 regindex; u32 bitindex; @@ -816,7 +894,7 @@ static s32 ixgbe_blink_led_stop_82598(struct ixgbe_hw *hw, u32 index) * * Performs read operation to Atlas analog register specified. **/ -s32 ixgbe_read_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 *val) +static s32 ixgbe_read_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 *val) { u32 atlas_ctl; @@ -838,7 +916,7 @@ s32 ixgbe_read_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 *val) * * Performs write operation to Atlas analog register specified. **/ -s32 ixgbe_write_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 val) +static s32 ixgbe_write_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 val) { u32 atlas_ctl; @@ -850,13 +928,76 @@ s32 ixgbe_write_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 val) return 0; } +/** + * ixgbe_read_i2c_eeprom_82598 - Read 8 bit EEPROM word of an SFP+ module + * over I2C interface through an intermediate phy. + * @hw: pointer to hardware structure + * @byte_offset: EEPROM byte offset to read + * @eeprom_data: value read + * + * Performs byte read operation to SFP module's EEPROM over I2C interface. + **/ +static s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset, + u8 *eeprom_data) +{ + s32 status = 0; + u16 sfp_addr = 0; + u16 sfp_data = 0; + u16 sfp_stat = 0; + u32 i; + + if (hw->phy.type == ixgbe_phy_nl) { + /* + * phy SDA/SCL registers are at addresses 0xC30A to + * 0xC30D. These registers are used to talk to the SFP+ + * module's EEPROM through the SDA/SCL (I2C) interface. + */ + sfp_addr = (IXGBE_I2C_EEPROM_DEV_ADDR << 8) + byte_offset; + sfp_addr = (sfp_addr | IXGBE_I2C_EEPROM_READ_MASK); + hw->phy.ops.write_reg(hw, + IXGBE_MDIO_PMA_PMD_SDA_SCL_ADDR, + IXGBE_MDIO_PMA_PMD_DEV_TYPE, + sfp_addr); + + /* Poll status */ + for (i = 0; i < 100; i++) { + hw->phy.ops.read_reg(hw, + IXGBE_MDIO_PMA_PMD_SDA_SCL_STAT, + IXGBE_MDIO_PMA_PMD_DEV_TYPE, + &sfp_stat); + sfp_stat = sfp_stat & IXGBE_I2C_EEPROM_STATUS_MASK; + if (sfp_stat != IXGBE_I2C_EEPROM_STATUS_IN_PROGRESS) + break; + msleep(10); + } + + if (sfp_stat != IXGBE_I2C_EEPROM_STATUS_PASS) { + hw_dbg(hw, "EEPROM read did not pass.\n"); + status = IXGBE_ERR_SFP_NOT_PRESENT; + goto out; + } + + /* Read data */ + hw->phy.ops.read_reg(hw, IXGBE_MDIO_PMA_PMD_SDA_SCL_DATA, + IXGBE_MDIO_PMA_PMD_DEV_TYPE, &sfp_data); + + *eeprom_data = (u8)(sfp_data >> 8); + } else { + status = IXGBE_ERR_PHY; + goto out; + } + +out: + return status; +} + /** * ixgbe_get_supported_physical_layer_82598 - Returns physical layer type * @hw: pointer to hardware structure * * Determines physical layer capabilities of the current configuration. **/ -s32 ixgbe_get_supported_physical_layer_82598(struct ixgbe_hw *hw) +static s32 ixgbe_get_supported_physical_layer_82598(struct ixgbe_hw *hw) { s32 physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; @@ -865,13 +1006,39 @@ s32 ixgbe_get_supported_physical_layer_82598(struct ixgbe_hw *hw) case IXGBE_DEV_ID_82598_CX4_DUAL_PORT: physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_CX4; break; + case IXGBE_DEV_ID_82598_DA_DUAL_PORT: + physical_layer = IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU; + break; case IXGBE_DEV_ID_82598AF_DUAL_PORT: case IXGBE_DEV_ID_82598AF_SINGLE_PORT: + case IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM: physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_SR; break; case IXGBE_DEV_ID_82598EB_XF_LR: physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_LR; break; + case IXGBE_DEV_ID_82598AT: + physical_layer = (IXGBE_PHYSICAL_LAYER_10GBASE_T | + IXGBE_PHYSICAL_LAYER_1000BASE_T); + break; + case IXGBE_DEV_ID_82598EB_SFP_LOM: + hw->phy.ops.identify_sfp(hw); + + switch (hw->phy.sfp_type) { + case ixgbe_sfp_type_da_cu: + physical_layer = IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU; + break; + case ixgbe_sfp_type_sr: + physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_SR; + break; + case ixgbe_sfp_type_lr: + physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_LR; + break; + default: + physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; + break; + } + break; default: physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; @@ -923,12 +1090,13 @@ static struct ixgbe_eeprom_operations eeprom_ops_82598 = { static struct ixgbe_phy_operations phy_ops_82598 = { .identify = &ixgbe_identify_phy_generic, - /* .identify_sfp = &ixgbe_identify_sfp_module_generic, */ + .identify_sfp = &ixgbe_identify_sfp_module_generic, .reset = &ixgbe_reset_phy_generic, .read_reg = &ixgbe_read_phy_reg_generic, .write_reg = &ixgbe_write_phy_reg_generic, .setup_link = &ixgbe_setup_phy_link_generic, .setup_link_speed = &ixgbe_setup_phy_link_speed_generic, + .read_i2c_eeprom = &ixgbe_read_i2c_eeprom_82598, }; struct ixgbe_info ixgbe_82598_info = { diff --git a/drivers/net/ixgbe/ixgbe_dcb.c b/drivers/net/ixgbe/ixgbe_dcb.c new file mode 100644 index 0000000000000000000000000000000000000000..e2e28ac63deca37eb752b1da2a8d7f1239d11e12 --- /dev/null +++ b/drivers/net/ixgbe/ixgbe_dcb.c @@ -0,0 +1,332 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + + +#include "ixgbe.h" +#include "ixgbe_type.h" +#include "ixgbe_dcb.h" +#include "ixgbe_dcb_82598.h" + +/** + * ixgbe_dcb_config - Struct containing DCB settings. + * @dcb_config: Pointer to DCB config structure + * + * This function checks DCB rules for DCB settings. + * The following rules are checked: + * 1. The sum of bandwidth percentages of all Bandwidth Groups must total 100%. + * 2. The sum of bandwidth percentages of all Traffic Classes within a Bandwidth + * Group must total 100. + * 3. A Traffic Class should not be set to both Link Strict Priority + * and Group Strict Priority. + * 4. Link strict Bandwidth Groups can only have link strict traffic classes + * with zero bandwidth. + */ +s32 ixgbe_dcb_check_config(struct ixgbe_dcb_config *dcb_config) +{ + struct tc_bw_alloc *p; + s32 ret_val = 0; + u8 i, j, bw = 0, bw_id; + u8 bw_sum[2][MAX_BW_GROUP]; + bool link_strict[2][MAX_BW_GROUP]; + + memset(bw_sum, 0, sizeof(bw_sum)); + memset(link_strict, 0, sizeof(link_strict)); + + /* First Tx, then Rx */ + for (i = 0; i < 2; i++) { + /* Check each traffic class for rule violation */ + for (j = 0; j < MAX_TRAFFIC_CLASS; j++) { + p = &dcb_config->tc_config[j].path[i]; + + bw = p->bwg_percent; + bw_id = p->bwg_id; + + if (bw_id >= MAX_BW_GROUP) { + ret_val = DCB_ERR_CONFIG; + goto err_config; + } + if (p->prio_type == prio_link) { + link_strict[i][bw_id] = true; + /* Link strict should have zero bandwidth */ + if (bw) { + ret_val = DCB_ERR_LS_BW_NONZERO; + goto err_config; + } + } else if (!bw) { + /* + * Traffic classes without link strict + * should have non-zero bandwidth. + */ + ret_val = DCB_ERR_TC_BW_ZERO; + goto err_config; + } + bw_sum[i][bw_id] += bw; + } + + bw = 0; + + /* Check each bandwidth group for rule violation */ + for (j = 0; j < MAX_BW_GROUP; j++) { + bw += dcb_config->bw_percentage[i][j]; + /* + * Sum of bandwidth percentages of all traffic classes + * within a Bandwidth Group must total 100 except for + * link strict group (zero bandwidth). + */ + if (link_strict[i][j]) { + if (bw_sum[i][j]) { + /* + * Link strict group should have zero + * bandwidth. + */ + ret_val = DCB_ERR_LS_BWG_NONZERO; + goto err_config; + } + } else if (bw_sum[i][j] != BW_PERCENT && + bw_sum[i][j] != 0) { + ret_val = DCB_ERR_TC_BW; + goto err_config; + } + } + + if (bw != BW_PERCENT) { + ret_val = DCB_ERR_BW_GROUP; + goto err_config; + } + } + +err_config: + return ret_val; +} + +/** + * ixgbe_dcb_calculate_tc_credits - Calculates traffic class credits + * @ixgbe_dcb_config: Struct containing DCB settings. + * @direction: Configuring either Tx or Rx. + * + * This function calculates the credits allocated to each traffic class. + * It should be called only after the rules are checked by + * ixgbe_dcb_check_config(). + */ +s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_dcb_config *dcb_config, + u8 direction) +{ + struct tc_bw_alloc *p; + s32 ret_val = 0; + /* Initialization values default for Tx settings */ + u32 credit_refill = 0; + u32 credit_max = 0; + u16 link_percentage = 0; + u8 bw_percent = 0; + u8 i; + + if (dcb_config == NULL) { + ret_val = DCB_ERR_CONFIG; + goto out; + } + + /* Find out the link percentage for each TC first */ + for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { + p = &dcb_config->tc_config[i].path[direction]; + bw_percent = dcb_config->bw_percentage[direction][p->bwg_id]; + + link_percentage = p->bwg_percent; + /* Must be careful of integer division for very small nums */ + link_percentage = (link_percentage * bw_percent) / 100; + if (p->bwg_percent > 0 && link_percentage == 0) + link_percentage = 1; + + /* Save link_percentage for reference */ + p->link_percent = (u8)link_percentage; + + /* Calculate credit refill and save it */ + credit_refill = link_percentage * MINIMUM_CREDIT_REFILL; + p->data_credits_refill = (u16)credit_refill; + + /* Calculate maximum credit for the TC */ + credit_max = (link_percentage * MAX_CREDIT) / 100; + + /* + * Adjustment based on rule checking, if the percentage + * of a TC is too small, the maximum credit may not be + * enough to send out a jumbo frame in data plane arbitration. + */ + if (credit_max && (credit_max < MINIMUM_CREDIT_FOR_JUMBO)) + credit_max = MINIMUM_CREDIT_FOR_JUMBO; + + if (direction == DCB_TX_CONFIG) { + /* + * Adjustment based on rule checking, if the + * percentage of a TC is too small, the maximum + * credit may not be enough to send out a TSO + * packet in descriptor plane arbitration. + */ + if (credit_max && + (credit_max < MINIMUM_CREDIT_FOR_TSO)) + credit_max = MINIMUM_CREDIT_FOR_TSO; + + dcb_config->tc_config[i].desc_credits_max = + (u16)credit_max; + } + + p->data_credits_max = (u16)credit_max; + } + +out: + return ret_val; +} + +/** + * ixgbe_dcb_get_tc_stats - Returns status of each traffic class + * @hw: pointer to hardware structure + * @stats: pointer to statistics structure + * @tc_count: Number of elements in bwg_array. + * + * This function returns the status data for each of the Traffic Classes in use. + */ +s32 ixgbe_dcb_get_tc_stats(struct ixgbe_hw *hw, struct ixgbe_hw_stats *stats, + u8 tc_count) +{ + s32 ret = 0; + if (hw->mac.type == ixgbe_mac_82598EB) + ret = ixgbe_dcb_get_tc_stats_82598(hw, stats, tc_count); + return ret; +} + +/** + * ixgbe_dcb_get_pfc_stats - Returns CBFC status of each traffic class + * hw - pointer to hardware structure + * stats - pointer to statistics structure + * tc_count - Number of elements in bwg_array. + * + * This function returns the CBFC status data for each of the Traffic Classes. + */ +s32 ixgbe_dcb_get_pfc_stats(struct ixgbe_hw *hw, struct ixgbe_hw_stats *stats, + u8 tc_count) +{ + s32 ret = 0; + if (hw->mac.type == ixgbe_mac_82598EB) + ret = ixgbe_dcb_get_pfc_stats_82598(hw, stats, tc_count); + return ret; +} + +/** + * ixgbe_dcb_config_rx_arbiter - Config Rx arbiter + * @hw: pointer to hardware structure + * @dcb_config: pointer to ixgbe_dcb_config structure + * + * Configure Rx Data Arbiter and credits for each traffic class. + */ +s32 ixgbe_dcb_config_rx_arbiter(struct ixgbe_hw *hw, + struct ixgbe_dcb_config *dcb_config) +{ + s32 ret = 0; + if (hw->mac.type == ixgbe_mac_82598EB) + ret = ixgbe_dcb_config_rx_arbiter_82598(hw, dcb_config); + return ret; +} + +/** + * ixgbe_dcb_config_tx_desc_arbiter - Config Tx Desc arbiter + * @hw: pointer to hardware structure + * @dcb_config: pointer to ixgbe_dcb_config structure + * + * Configure Tx Descriptor Arbiter and credits for each traffic class. + */ +s32 ixgbe_dcb_config_tx_desc_arbiter(struct ixgbe_hw *hw, + struct ixgbe_dcb_config *dcb_config) +{ + s32 ret = 0; + if (hw->mac.type == ixgbe_mac_82598EB) + ret = ixgbe_dcb_config_tx_desc_arbiter_82598(hw, dcb_config); + return ret; +} + +/** + * ixgbe_dcb_config_tx_data_arbiter - Config Tx data arbiter + * @hw: pointer to hardware structure + * @dcb_config: pointer to ixgbe_dcb_config structure + * + * Configure Tx Data Arbiter and credits for each traffic class. + */ +s32 ixgbe_dcb_config_tx_data_arbiter(struct ixgbe_hw *hw, + struct ixgbe_dcb_config *dcb_config) +{ + s32 ret = 0; + if (hw->mac.type == ixgbe_mac_82598EB) + ret = ixgbe_dcb_config_tx_data_arbiter_82598(hw, dcb_config); + return ret; +} + +/** + * ixgbe_dcb_config_pfc - Config priority flow control + * @hw: pointer to hardware structure + * @dcb_config: pointer to ixgbe_dcb_config structure + * + * Configure Priority Flow Control for each traffic class. + */ +s32 ixgbe_dcb_config_pfc(struct ixgbe_hw *hw, + struct ixgbe_dcb_config *dcb_config) +{ + s32 ret = 0; + if (hw->mac.type == ixgbe_mac_82598EB) + ret = ixgbe_dcb_config_pfc_82598(hw, dcb_config); + return ret; +} + +/** + * ixgbe_dcb_config_tc_stats - Config traffic class statistics + * @hw: pointer to hardware structure + * + * Configure queue statistics registers, all queues belonging to same traffic + * class uses a single set of queue statistics counters. + */ +s32 ixgbe_dcb_config_tc_stats(struct ixgbe_hw *hw) +{ + s32 ret = 0; + if (hw->mac.type == ixgbe_mac_82598EB) + ret = ixgbe_dcb_config_tc_stats_82598(hw); + return ret; +} + +/** + * ixgbe_dcb_hw_config - Config and enable DCB + * @hw: pointer to hardware structure + * @dcb_config: pointer to ixgbe_dcb_config structure + * + * Configure dcb settings and enable dcb mode. + */ +s32 ixgbe_dcb_hw_config(struct ixgbe_hw *hw, + struct ixgbe_dcb_config *dcb_config) +{ + s32 ret = 0; + if (hw->mac.type == ixgbe_mac_82598EB) + ret = ixgbe_dcb_hw_config_82598(hw, dcb_config); + return ret; +} + diff --git a/drivers/net/ixgbe/ixgbe_dcb.h b/drivers/net/ixgbe/ixgbe_dcb.h new file mode 100644 index 0000000000000000000000000000000000000000..75f6efe1e36920a9fba4c1f4859ec701f0a2549a --- /dev/null +++ b/drivers/net/ixgbe/ixgbe_dcb.h @@ -0,0 +1,184 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _DCB_CONFIG_H_ +#define _DCB_CONFIG_H_ + +#include "ixgbe_type.h" + +/* DCB data structures */ + +#define IXGBE_MAX_PACKET_BUFFERS 8 +#define MAX_USER_PRIORITY 8 +#define MAX_TRAFFIC_CLASS 8 +#define MAX_BW_GROUP 8 +#define BW_PERCENT 100 + +#define DCB_TX_CONFIG 0 +#define DCB_RX_CONFIG 1 + +/* DCB error Codes */ +#define DCB_SUCCESS 0 +#define DCB_ERR_CONFIG -1 +#define DCB_ERR_PARAM -2 + +/* Transmit and receive Errors */ +/* Error in bandwidth group allocation */ +#define DCB_ERR_BW_GROUP -3 +/* Error in traffic class bandwidth allocation */ +#define DCB_ERR_TC_BW -4 +/* Traffic class has both link strict and group strict enabled */ +#define DCB_ERR_LS_GS -5 +/* Link strict traffic class has non zero bandwidth */ +#define DCB_ERR_LS_BW_NONZERO -6 +/* Link strict bandwidth group has non zero bandwidth */ +#define DCB_ERR_LS_BWG_NONZERO -7 +/* Traffic class has zero bandwidth */ +#define DCB_ERR_TC_BW_ZERO -8 + +#define DCB_NOT_IMPLEMENTED 0x7FFFFFFF + +struct dcb_pfc_tc_debug { + u8 tc; + u8 pause_status; + u64 pause_quanta; +}; + +enum strict_prio_type { + prio_none = 0, + prio_group, + prio_link +}; + +/* Traffic class bandwidth allocation per direction */ +struct tc_bw_alloc { + u8 bwg_id; /* Bandwidth Group (BWG) ID */ + u8 bwg_percent; /* % of BWG's bandwidth */ + u8 link_percent; /* % of link bandwidth */ + u8 up_to_tc_bitmap; /* User Priority to Traffic Class mapping */ + u16 data_credits_refill; /* Credit refill amount in 64B granularity */ + u16 data_credits_max; /* Max credits for a configured packet buffer + * in 64B granularity.*/ + enum strict_prio_type prio_type; /* Link or Group Strict Priority */ +}; + +enum dcb_pfc_type { + pfc_disabled = 0, + pfc_enabled_full, + pfc_enabled_tx, + pfc_enabled_rx +}; + +/* Traffic class configuration */ +struct tc_configuration { + struct tc_bw_alloc path[2]; /* One each for Tx/Rx */ + enum dcb_pfc_type dcb_pfc; /* Class based flow control setting */ + + u16 desc_credits_max; /* For Tx Descriptor arbitration */ + u8 tc; /* Traffic class (TC) */ +}; + +enum dcb_rx_pba_cfg { + pba_equal, /* PBA[0-7] each use 64KB FIFO */ + pba_80_48 /* PBA[0-3] each use 80KB, PBA[4-7] each use 48KB */ +}; + +/* + * This structure contains many values encoded as fixed-point + * numbers, meaning that some of bits are dedicated to the + * magnitude and others to the fraction part. In the comments + * this is shown as f=n, where n is the number of fraction bits. + * These fraction bits are always the low-order bits. The size + * of the magnitude is not specified. + */ +struct bcn_config { + u32 rp_admin_mode[MAX_TRAFFIC_CLASS]; /* BCN enabled, per TC */ + u32 bcna_option[2]; /* BCNA Port + MAC Addr */ + u32 rp_w; /* Derivative Weight, f=3 */ + u32 rp_gi; /* Increase Gain, f=12 */ + u32 rp_gd; /* Decrease Gain, f=12 */ + u32 rp_ru; /* Rate Unit */ + u32 rp_alpha; /* Max Decrease Factor, f=12 */ + u32 rp_beta; /* Max Increase Factor, f=12 */ + u32 rp_ri; /* Initial Rate */ + u32 rp_td; /* Drift Interval Timer */ + u32 rp_rd; /* Drift Increase */ + u32 rp_tmax; /* Severe Congestion Backoff Timer Range */ + u32 rp_rmin; /* Severe Congestion Restart Rate */ + u32 rp_wrtt; /* RTT Moving Average Weight */ +}; + +struct ixgbe_dcb_config { + struct bcn_config bcn; + + struct tc_configuration tc_config[MAX_TRAFFIC_CLASS]; + u8 bw_percentage[2][MAX_BW_GROUP]; /* One each for Tx/Rx */ + + bool round_robin_enable; + + enum dcb_rx_pba_cfg rx_pba_cfg; + + u32 dcb_cfg_version; /* Not used...OS-specific? */ + u32 link_speed; /* For bandwidth allocation validation purpose */ +}; + +/* DCB driver APIs */ + +/* DCB rule checking function.*/ +s32 ixgbe_dcb_check_config(struct ixgbe_dcb_config *config); + +/* DCB credits calculation */ +s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_dcb_config *, u8); + +/* DCB PFC functions */ +s32 ixgbe_dcb_config_pfc(struct ixgbe_hw *, struct ixgbe_dcb_config *g); +s32 ixgbe_dcb_get_pfc_stats(struct ixgbe_hw *, struct ixgbe_hw_stats *, u8); + +/* DCB traffic class stats */ +s32 ixgbe_dcb_config_tc_stats(struct ixgbe_hw *); +s32 ixgbe_dcb_get_tc_stats(struct ixgbe_hw *, struct ixgbe_hw_stats *, u8); + +/* DCB config arbiters */ +s32 ixgbe_dcb_config_tx_desc_arbiter(struct ixgbe_hw *, + struct ixgbe_dcb_config *); +s32 ixgbe_dcb_config_tx_data_arbiter(struct ixgbe_hw *, + struct ixgbe_dcb_config *); +s32 ixgbe_dcb_config_rx_arbiter(struct ixgbe_hw *, struct ixgbe_dcb_config *); + +/* DCB hw initialization */ +s32 ixgbe_dcb_hw_config(struct ixgbe_hw *, struct ixgbe_dcb_config *); + +/* DCB definitions for credit calculation */ +#define MAX_CREDIT_REFILL 511 /* 0x1FF * 64B = 32704B */ +#define MINIMUM_CREDIT_REFILL 5 /* 5*64B = 320B */ +#define MINIMUM_CREDIT_FOR_JUMBO 145 /* 145= UpperBound((9*1024+54)/64B) for 9KB jumbo frame */ +#define DCB_MAX_TSO_SIZE (32*1024) /* MAX TSO packet size supported in DCB mode */ +#define MINIMUM_CREDIT_FOR_TSO (DCB_MAX_TSO_SIZE/64 + 1) /* 513 for 32KB TSO packet */ +#define MAX_CREDIT 4095 /* Maximum credit supported: 256KB * 1204 / 64B */ + +#endif /* _DCB_CONFIG_H */ diff --git a/drivers/net/ixgbe/ixgbe_dcb_82598.c b/drivers/net/ixgbe/ixgbe_dcb_82598.c new file mode 100644 index 0000000000000000000000000000000000000000..2c046b0b5d2806507178e5a2ff948cf9217f4d61 --- /dev/null +++ b/drivers/net/ixgbe/ixgbe_dcb_82598.c @@ -0,0 +1,398 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include "ixgbe.h" +#include "ixgbe_type.h" +#include "ixgbe_dcb.h" +#include "ixgbe_dcb_82598.h" + +/** + * ixgbe_dcb_get_tc_stats_82598 - Return status data for each traffic class + * @hw: pointer to hardware structure + * @stats: pointer to statistics structure + * @tc_count: Number of elements in bwg_array. + * + * This function returns the status data for each of the Traffic Classes in use. + */ +s32 ixgbe_dcb_get_tc_stats_82598(struct ixgbe_hw *hw, + struct ixgbe_hw_stats *stats, + u8 tc_count) +{ + int tc; + + if (tc_count > MAX_TRAFFIC_CLASS) + return DCB_ERR_PARAM; + + /* Statistics pertaining to each traffic class */ + for (tc = 0; tc < tc_count; tc++) { + /* Transmitted Packets */ + stats->qptc[tc] += IXGBE_READ_REG(hw, IXGBE_QPTC(tc)); + /* Transmitted Bytes */ + stats->qbtc[tc] += IXGBE_READ_REG(hw, IXGBE_QBTC(tc)); + /* Received Packets */ + stats->qprc[tc] += IXGBE_READ_REG(hw, IXGBE_QPRC(tc)); + /* Received Bytes */ + stats->qbrc[tc] += IXGBE_READ_REG(hw, IXGBE_QBRC(tc)); + } + + return 0; +} + +/** + * ixgbe_dcb_get_pfc_stats_82598 - Returns CBFC status data + * @hw: pointer to hardware structure + * @stats: pointer to statistics structure + * @tc_count: Number of elements in bwg_array. + * + * This function returns the CBFC status data for each of the Traffic Classes. + */ +s32 ixgbe_dcb_get_pfc_stats_82598(struct ixgbe_hw *hw, + struct ixgbe_hw_stats *stats, + u8 tc_count) +{ + int tc; + + if (tc_count > MAX_TRAFFIC_CLASS) + return DCB_ERR_PARAM; + + for (tc = 0; tc < tc_count; tc++) { + /* Priority XOFF Transmitted */ + stats->pxofftxc[tc] += IXGBE_READ_REG(hw, IXGBE_PXOFFTXC(tc)); + /* Priority XOFF Received */ + stats->pxoffrxc[tc] += IXGBE_READ_REG(hw, IXGBE_PXOFFRXC(tc)); + } + + return 0; +} + +/** + * ixgbe_dcb_config_packet_buffers_82598 - Configure packet buffers + * @hw: pointer to hardware structure + * @dcb_config: pointer to ixgbe_dcb_config structure + * + * Configure packet buffers for DCB mode. + */ +static s32 ixgbe_dcb_config_packet_buffers_82598(struct ixgbe_hw *hw, + struct ixgbe_dcb_config *dcb_config) +{ + s32 ret_val = 0; + u32 value = IXGBE_RXPBSIZE_64KB; + u8 i = 0; + + /* Setup Rx packet buffer sizes */ + switch (dcb_config->rx_pba_cfg) { + case pba_80_48: + /* Setup the first four at 80KB */ + value = IXGBE_RXPBSIZE_80KB; + for (; i < 4; i++) + IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), value); + /* Setup the last four at 48KB...don't re-init i */ + value = IXGBE_RXPBSIZE_48KB; + /* Fall Through */ + case pba_equal: + default: + for (; i < IXGBE_MAX_PACKET_BUFFERS; i++) + IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), value); + + /* Setup Tx packet buffer sizes */ + for (i = 0; i < IXGBE_MAX_PACKET_BUFFERS; i++) { + IXGBE_WRITE_REG(hw, IXGBE_TXPBSIZE(i), + IXGBE_TXPBSIZE_40KB); + } + break; + } + + return ret_val; +} + +/** + * ixgbe_dcb_config_rx_arbiter_82598 - Config Rx data arbiter + * @hw: pointer to hardware structure + * @dcb_config: pointer to ixgbe_dcb_config structure + * + * Configure Rx Data Arbiter and credits for each traffic class. + */ +s32 ixgbe_dcb_config_rx_arbiter_82598(struct ixgbe_hw *hw, + struct ixgbe_dcb_config *dcb_config) +{ + struct tc_bw_alloc *p; + u32 reg = 0; + u32 credit_refill = 0; + u32 credit_max = 0; + u8 i = 0; + + reg = IXGBE_READ_REG(hw, IXGBE_RUPPBMR) | IXGBE_RUPPBMR_MQA; + IXGBE_WRITE_REG(hw, IXGBE_RUPPBMR, reg); + + reg = IXGBE_READ_REG(hw, IXGBE_RMCS); + /* Enable Arbiter */ + reg &= ~IXGBE_RMCS_ARBDIS; + /* Enable Receive Recycle within the BWG */ + reg |= IXGBE_RMCS_RRM; + /* Enable Deficit Fixed Priority arbitration*/ + reg |= IXGBE_RMCS_DFP; + + IXGBE_WRITE_REG(hw, IXGBE_RMCS, reg); + + /* Configure traffic class credits and priority */ + for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { + p = &dcb_config->tc_config[i].path[DCB_RX_CONFIG]; + credit_refill = p->data_credits_refill; + credit_max = p->data_credits_max; + + reg = credit_refill | (credit_max << IXGBE_RT2CR_MCL_SHIFT); + + if (p->prio_type == prio_link) + reg |= IXGBE_RT2CR_LSP; + + IXGBE_WRITE_REG(hw, IXGBE_RT2CR(i), reg); + } + + reg = IXGBE_READ_REG(hw, IXGBE_RDRXCTL); + reg |= IXGBE_RDRXCTL_RDMTS_1_2; + reg |= IXGBE_RDRXCTL_MPBEN; + reg |= IXGBE_RDRXCTL_MCEN; + IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, reg); + + reg = IXGBE_READ_REG(hw, IXGBE_RXCTRL); + /* Make sure there is enough descriptors before arbitration */ + reg &= ~IXGBE_RXCTRL_DMBYPS; + IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, reg); + + return 0; +} + +/** + * ixgbe_dcb_config_tx_desc_arbiter_82598 - Config Tx Desc. arbiter + * @hw: pointer to hardware structure + * @dcb_config: pointer to ixgbe_dcb_config structure + * + * Configure Tx Descriptor Arbiter and credits for each traffic class. + */ +s32 ixgbe_dcb_config_tx_desc_arbiter_82598(struct ixgbe_hw *hw, + struct ixgbe_dcb_config *dcb_config) +{ + struct tc_bw_alloc *p; + u32 reg, max_credits; + u8 i; + + reg = IXGBE_READ_REG(hw, IXGBE_DPMCS); + + /* Enable arbiter */ + reg &= ~IXGBE_DPMCS_ARBDIS; + if (!(dcb_config->round_robin_enable)) { + /* Enable DFP and Recycle mode */ + reg |= (IXGBE_DPMCS_TDPAC | IXGBE_DPMCS_TRM); + } + reg |= IXGBE_DPMCS_TSOEF; + /* Configure Max TSO packet size 34KB including payload and headers */ + reg |= (0x4 << IXGBE_DPMCS_MTSOS_SHIFT); + + IXGBE_WRITE_REG(hw, IXGBE_DPMCS, reg); + + /* Configure traffic class credits and priority */ + for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { + p = &dcb_config->tc_config[i].path[DCB_TX_CONFIG]; + max_credits = dcb_config->tc_config[i].desc_credits_max; + reg = max_credits << IXGBE_TDTQ2TCCR_MCL_SHIFT; + reg |= p->data_credits_refill; + reg |= (u32)(p->bwg_id) << IXGBE_TDTQ2TCCR_BWG_SHIFT; + + if (p->prio_type == prio_group) + reg |= IXGBE_TDTQ2TCCR_GSP; + + if (p->prio_type == prio_link) + reg |= IXGBE_TDTQ2TCCR_LSP; + + IXGBE_WRITE_REG(hw, IXGBE_TDTQ2TCCR(i), reg); + } + + return 0; +} + +/** + * ixgbe_dcb_config_tx_data_arbiter_82598 - Config Tx data arbiter + * @hw: pointer to hardware structure + * @dcb_config: pointer to ixgbe_dcb_config structure + * + * Configure Tx Data Arbiter and credits for each traffic class. + */ +s32 ixgbe_dcb_config_tx_data_arbiter_82598(struct ixgbe_hw *hw, + struct ixgbe_dcb_config *dcb_config) +{ + struct tc_bw_alloc *p; + u32 reg; + u8 i; + + reg = IXGBE_READ_REG(hw, IXGBE_PDPMCS); + /* Enable Data Plane Arbiter */ + reg &= ~IXGBE_PDPMCS_ARBDIS; + /* Enable DFP and Transmit Recycle Mode */ + reg |= (IXGBE_PDPMCS_TPPAC | IXGBE_PDPMCS_TRM); + + IXGBE_WRITE_REG(hw, IXGBE_PDPMCS, reg); + + /* Configure traffic class credits and priority */ + for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { + p = &dcb_config->tc_config[i].path[DCB_TX_CONFIG]; + reg = p->data_credits_refill; + reg |= (u32)(p->data_credits_max) << IXGBE_TDPT2TCCR_MCL_SHIFT; + reg |= (u32)(p->bwg_id) << IXGBE_TDPT2TCCR_BWG_SHIFT; + + if (p->prio_type == prio_group) + reg |= IXGBE_TDPT2TCCR_GSP; + + if (p->prio_type == prio_link) + reg |= IXGBE_TDPT2TCCR_LSP; + + IXGBE_WRITE_REG(hw, IXGBE_TDPT2TCCR(i), reg); + } + + /* Enable Tx packet buffer division */ + reg = IXGBE_READ_REG(hw, IXGBE_DTXCTL); + reg |= IXGBE_DTXCTL_ENDBUBD; + IXGBE_WRITE_REG(hw, IXGBE_DTXCTL, reg); + + return 0; +} + +/** + * ixgbe_dcb_config_pfc_82598 - Config priority flow control + * @hw: pointer to hardware structure + * @dcb_config: pointer to ixgbe_dcb_config structure + * + * Configure Priority Flow Control for each traffic class. + */ +s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *hw, + struct ixgbe_dcb_config *dcb_config) +{ + u32 reg, rx_pba_size; + u8 i; + + /* Enable Transmit Priority Flow Control */ + reg = IXGBE_READ_REG(hw, IXGBE_RMCS); + reg &= ~IXGBE_RMCS_TFCE_802_3X; + /* correct the reporting of our flow control status */ + hw->fc.type = ixgbe_fc_none; + reg |= IXGBE_RMCS_TFCE_PRIORITY; + IXGBE_WRITE_REG(hw, IXGBE_RMCS, reg); + + /* Enable Receive Priority Flow Control */ + reg = IXGBE_READ_REG(hw, IXGBE_FCTRL); + reg &= ~IXGBE_FCTRL_RFCE; + reg |= IXGBE_FCTRL_RPFCE; + IXGBE_WRITE_REG(hw, IXGBE_FCTRL, reg); + + /* + * Configure flow control thresholds and enable priority flow control + * for each traffic class. + */ + for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { + if (dcb_config->rx_pba_cfg == pba_equal) { + rx_pba_size = IXGBE_RXPBSIZE_64KB; + } else { + rx_pba_size = (i < 4) ? IXGBE_RXPBSIZE_80KB + : IXGBE_RXPBSIZE_48KB; + } + + reg = ((rx_pba_size >> 5) & 0xFFF0); + if (dcb_config->tc_config[i].dcb_pfc == pfc_enabled_tx || + dcb_config->tc_config[i].dcb_pfc == pfc_enabled_full) + reg |= IXGBE_FCRTL_XONE; + + IXGBE_WRITE_REG(hw, IXGBE_FCRTL(i), reg); + + reg = ((rx_pba_size >> 2) & 0xFFF0); + if (dcb_config->tc_config[i].dcb_pfc == pfc_enabled_tx || + dcb_config->tc_config[i].dcb_pfc == pfc_enabled_full) + reg |= IXGBE_FCRTH_FCEN; + + IXGBE_WRITE_REG(hw, IXGBE_FCRTH(i), reg); + } + + /* Configure pause time */ + for (i = 0; i < (MAX_TRAFFIC_CLASS >> 1); i++) + IXGBE_WRITE_REG(hw, IXGBE_FCTTV(i), 0x68006800); + + /* Configure flow control refresh threshold value */ + IXGBE_WRITE_REG(hw, IXGBE_FCRTV, 0x3400); + + return 0; +} + +/** + * ixgbe_dcb_config_tc_stats_82598 - Configure traffic class statistics + * @hw: pointer to hardware structure + * + * Configure queue statistics registers, all queues belonging to same traffic + * class uses a single set of queue statistics counters. + */ +s32 ixgbe_dcb_config_tc_stats_82598(struct ixgbe_hw *hw) +{ + u32 reg = 0; + u8 i = 0; + u8 j = 0; + + /* Receive Queues stats setting - 8 queues per statistics reg */ + for (i = 0, j = 0; i < 15 && j < 8; i = i + 2, j++) { + reg = IXGBE_READ_REG(hw, IXGBE_RQSMR(i)); + reg |= ((0x1010101) * j); + IXGBE_WRITE_REG(hw, IXGBE_RQSMR(i), reg); + reg = IXGBE_READ_REG(hw, IXGBE_RQSMR(i + 1)); + reg |= ((0x1010101) * j); + IXGBE_WRITE_REG(hw, IXGBE_RQSMR(i + 1), reg); + } + /* Transmit Queues stats setting - 4 queues per statistics reg */ + for (i = 0; i < 8; i++) { + reg = IXGBE_READ_REG(hw, IXGBE_TQSMR(i)); + reg |= ((0x1010101) * i); + IXGBE_WRITE_REG(hw, IXGBE_TQSMR(i), reg); + } + + return 0; +} + +/** + * ixgbe_dcb_hw_config_82598 - Config and enable DCB + * @hw: pointer to hardware structure + * @dcb_config: pointer to ixgbe_dcb_config structure + * + * Configure dcb settings and enable dcb mode. + */ +s32 ixgbe_dcb_hw_config_82598(struct ixgbe_hw *hw, + struct ixgbe_dcb_config *dcb_config) +{ + ixgbe_dcb_config_packet_buffers_82598(hw, dcb_config); + ixgbe_dcb_config_rx_arbiter_82598(hw, dcb_config); + ixgbe_dcb_config_tx_desc_arbiter_82598(hw, dcb_config); + ixgbe_dcb_config_tx_data_arbiter_82598(hw, dcb_config); + ixgbe_dcb_config_pfc_82598(hw, dcb_config); + ixgbe_dcb_config_tc_stats_82598(hw); + + return 0; +} diff --git a/drivers/net/ixgbe/ixgbe_dcb_82598.h b/drivers/net/ixgbe/ixgbe_dcb_82598.h new file mode 100644 index 0000000000000000000000000000000000000000..1e6a313719d7e2a0237896aa997c8871b8ee25bf --- /dev/null +++ b/drivers/net/ixgbe/ixgbe_dcb_82598.h @@ -0,0 +1,94 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _DCB_82598_CONFIG_H_ +#define _DCB_82598_CONFIG_H_ + +/* DCB register definitions */ + +#define IXGBE_DPMCS_MTSOS_SHIFT 16 +#define IXGBE_DPMCS_TDPAC 0x00000001 /* 0 Round Robin, 1 DFP - Deficit Fixed Priority */ +#define IXGBE_DPMCS_TRM 0x00000010 /* Transmit Recycle Mode */ +#define IXGBE_DPMCS_ARBDIS 0x00000040 /* DCB arbiter disable */ +#define IXGBE_DPMCS_TSOEF 0x00080000 /* TSO Expand Factor: 0=x4, 1=x2 */ + +#define IXGBE_RUPPBMR_MQA 0x80000000 /* Enable UP to queue mapping */ + +#define IXGBE_RT2CR_MCL_SHIFT 12 /* Offset to Max Credit Limit setting */ +#define IXGBE_RT2CR_LSP 0x80000000 /* LSP enable bit */ + +#define IXGBE_RDRXCTL_MPBEN 0x00000010 /* DMA config for multiple packet buffers enable */ +#define IXGBE_RDRXCTL_MCEN 0x00000040 /* DMA config for multiple cores (RSS) enable */ + +#define IXGBE_TDTQ2TCCR_MCL_SHIFT 12 +#define IXGBE_TDTQ2TCCR_BWG_SHIFT 9 +#define IXGBE_TDTQ2TCCR_GSP 0x40000000 +#define IXGBE_TDTQ2TCCR_LSP 0x80000000 + +#define IXGBE_TDPT2TCCR_MCL_SHIFT 12 +#define IXGBE_TDPT2TCCR_BWG_SHIFT 9 +#define IXGBE_TDPT2TCCR_GSP 0x40000000 +#define IXGBE_TDPT2TCCR_LSP 0x80000000 + +#define IXGBE_PDPMCS_TPPAC 0x00000020 /* 0 Round Robin, 1 for DFP - Deficit Fixed Priority */ +#define IXGBE_PDPMCS_ARBDIS 0x00000040 /* Arbiter disable */ +#define IXGBE_PDPMCS_TRM 0x00000100 /* Transmit Recycle Mode enable */ + +#define IXGBE_DTXCTL_ENDBUBD 0x00000004 /* Enable DBU buffer division */ + +#define IXGBE_TXPBSIZE_40KB 0x0000A000 /* 40KB Packet Buffer */ +#define IXGBE_RXPBSIZE_48KB 0x0000C000 /* 48KB Packet Buffer */ +#define IXGBE_RXPBSIZE_64KB 0x00010000 /* 64KB Packet Buffer */ +#define IXGBE_RXPBSIZE_80KB 0x00014000 /* 80KB Packet Buffer */ + +#define IXGBE_RDRXCTL_RDMTS_1_2 0x00000000 + +/* DCB hardware-specific driver APIs */ + +/* DCB PFC functions */ +s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *, struct ixgbe_dcb_config *); +s32 ixgbe_dcb_get_pfc_stats_82598(struct ixgbe_hw *, struct ixgbe_hw_stats *, + u8); + +/* DCB traffic class stats */ +s32 ixgbe_dcb_config_tc_stats_82598(struct ixgbe_hw *); +s32 ixgbe_dcb_get_tc_stats_82598(struct ixgbe_hw *, struct ixgbe_hw_stats *, + u8); + +/* DCB config arbiters */ +s32 ixgbe_dcb_config_tx_desc_arbiter_82598(struct ixgbe_hw *, + struct ixgbe_dcb_config *); +s32 ixgbe_dcb_config_tx_data_arbiter_82598(struct ixgbe_hw *, + struct ixgbe_dcb_config *); +s32 ixgbe_dcb_config_rx_arbiter_82598(struct ixgbe_hw *, + struct ixgbe_dcb_config *); + +/* DCB hw initialization */ +s32 ixgbe_dcb_hw_config_82598(struct ixgbe_hw *, struct ixgbe_dcb_config *); + +#endif /* _DCB_82598_CONFIG_H */ diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c new file mode 100644 index 0000000000000000000000000000000000000000..4129976953f5609f58c4f442b22f58095c8a54f7 --- /dev/null +++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c @@ -0,0 +1,641 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2008 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include "ixgbe.h" +#include + +/* Callbacks for DCB netlink in the kernel */ +#define BIT_DCB_MODE 0x01 +#define BIT_PFC 0x02 +#define BIT_PG_RX 0x04 +#define BIT_PG_TX 0x08 +#define BIT_BCN 0x10 + +int ixgbe_copy_dcb_cfg(struct ixgbe_dcb_config *src_dcb_cfg, + struct ixgbe_dcb_config *dst_dcb_cfg, int tc_max) +{ + struct tc_configuration *src_tc_cfg = NULL; + struct tc_configuration *dst_tc_cfg = NULL; + int i; + + if (!src_dcb_cfg || !dst_dcb_cfg) + return -EINVAL; + + for (i = DCB_PG_ATTR_TC_0; i < tc_max + DCB_PG_ATTR_TC_0; i++) { + src_tc_cfg = &src_dcb_cfg->tc_config[i - DCB_PG_ATTR_TC_0]; + dst_tc_cfg = &dst_dcb_cfg->tc_config[i - DCB_PG_ATTR_TC_0]; + + dst_tc_cfg->path[DCB_TX_CONFIG].prio_type = + src_tc_cfg->path[DCB_TX_CONFIG].prio_type; + + dst_tc_cfg->path[DCB_TX_CONFIG].bwg_id = + src_tc_cfg->path[DCB_TX_CONFIG].bwg_id; + + dst_tc_cfg->path[DCB_TX_CONFIG].bwg_percent = + src_tc_cfg->path[DCB_TX_CONFIG].bwg_percent; + + dst_tc_cfg->path[DCB_TX_CONFIG].up_to_tc_bitmap = + src_tc_cfg->path[DCB_TX_CONFIG].up_to_tc_bitmap; + + dst_tc_cfg->path[DCB_RX_CONFIG].prio_type = + src_tc_cfg->path[DCB_RX_CONFIG].prio_type; + + dst_tc_cfg->path[DCB_RX_CONFIG].bwg_id = + src_tc_cfg->path[DCB_RX_CONFIG].bwg_id; + + dst_tc_cfg->path[DCB_RX_CONFIG].bwg_percent = + src_tc_cfg->path[DCB_RX_CONFIG].bwg_percent; + + dst_tc_cfg->path[DCB_RX_CONFIG].up_to_tc_bitmap = + src_tc_cfg->path[DCB_RX_CONFIG].up_to_tc_bitmap; + } + + for (i = DCB_PG_ATTR_BW_ID_0; i < DCB_PG_ATTR_BW_ID_MAX; i++) { + dst_dcb_cfg->bw_percentage[DCB_TX_CONFIG] + [i-DCB_PG_ATTR_BW_ID_0] = src_dcb_cfg->bw_percentage + [DCB_TX_CONFIG][i-DCB_PG_ATTR_BW_ID_0]; + dst_dcb_cfg->bw_percentage[DCB_RX_CONFIG] + [i-DCB_PG_ATTR_BW_ID_0] = src_dcb_cfg->bw_percentage + [DCB_RX_CONFIG][i-DCB_PG_ATTR_BW_ID_0]; + } + + for (i = DCB_PFC_UP_ATTR_0; i < DCB_PFC_UP_ATTR_MAX; i++) { + dst_dcb_cfg->tc_config[i - DCB_PFC_UP_ATTR_0].dcb_pfc = + src_dcb_cfg->tc_config[i - DCB_PFC_UP_ATTR_0].dcb_pfc; + } + + for (i = DCB_BCN_ATTR_RP_0; i < DCB_BCN_ATTR_RP_ALL; i++) { + dst_dcb_cfg->bcn.rp_admin_mode[i - DCB_BCN_ATTR_RP_0] = + src_dcb_cfg->bcn.rp_admin_mode[i - DCB_BCN_ATTR_RP_0]; + } + dst_dcb_cfg->bcn.bcna_option[0] = src_dcb_cfg->bcn.bcna_option[0]; + dst_dcb_cfg->bcn.bcna_option[1] = src_dcb_cfg->bcn.bcna_option[1]; + dst_dcb_cfg->bcn.rp_alpha = src_dcb_cfg->bcn.rp_alpha; + dst_dcb_cfg->bcn.rp_beta = src_dcb_cfg->bcn.rp_beta; + dst_dcb_cfg->bcn.rp_gd = src_dcb_cfg->bcn.rp_gd; + dst_dcb_cfg->bcn.rp_gi = src_dcb_cfg->bcn.rp_gi; + dst_dcb_cfg->bcn.rp_tmax = src_dcb_cfg->bcn.rp_tmax; + dst_dcb_cfg->bcn.rp_td = src_dcb_cfg->bcn.rp_td; + dst_dcb_cfg->bcn.rp_rmin = src_dcb_cfg->bcn.rp_rmin; + dst_dcb_cfg->bcn.rp_w = src_dcb_cfg->bcn.rp_w; + dst_dcb_cfg->bcn.rp_rd = src_dcb_cfg->bcn.rp_rd; + dst_dcb_cfg->bcn.rp_ru = src_dcb_cfg->bcn.rp_ru; + dst_dcb_cfg->bcn.rp_wrtt = src_dcb_cfg->bcn.rp_wrtt; + dst_dcb_cfg->bcn.rp_ri = src_dcb_cfg->bcn.rp_ri; + + return 0; +} + +static u8 ixgbe_dcbnl_get_state(struct net_device *netdev) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + DPRINTK(DRV, INFO, "Get DCB Admin Mode.\n"); + + return !!(adapter->flags & IXGBE_FLAG_DCB_ENABLED); +} + +static u16 ixgbe_dcb_select_queue(struct net_device *dev, struct sk_buff *skb) +{ + /* All traffic should default to class 0 */ + return 0; +} + +static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state) +{ + u8 err = 0; + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + DPRINTK(DRV, INFO, "Set DCB Admin Mode.\n"); + + if (state > 0) { + /* Turn on DCB */ + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) + goto out; + + if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED)) { + DPRINTK(DRV, ERR, "Enable failed, needs MSI-X\n"); + err = 1; + goto out; + } + + if (netif_running(netdev)) + netdev->netdev_ops->ndo_stop(netdev); + ixgbe_reset_interrupt_capability(adapter); + ixgbe_napi_del_all(adapter); + INIT_LIST_HEAD(&netdev->napi_list); + kfree(adapter->tx_ring); + kfree(adapter->rx_ring); + adapter->tx_ring = NULL; + adapter->rx_ring = NULL; + netdev->select_queue = &ixgbe_dcb_select_queue; + + adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED; + adapter->flags |= IXGBE_FLAG_DCB_ENABLED; + ixgbe_init_interrupt_scheme(adapter); + if (netif_running(netdev)) + netdev->netdev_ops->ndo_open(netdev); + } else { + /* Turn off DCB */ + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { + if (netif_running(netdev)) + netdev->netdev_ops->ndo_stop(netdev); + ixgbe_reset_interrupt_capability(adapter); + ixgbe_napi_del_all(adapter); + INIT_LIST_HEAD(&netdev->napi_list); + kfree(adapter->tx_ring); + kfree(adapter->rx_ring); + adapter->tx_ring = NULL; + adapter->rx_ring = NULL; + netdev->select_queue = NULL; + + adapter->flags &= ~IXGBE_FLAG_DCB_ENABLED; + adapter->flags |= IXGBE_FLAG_RSS_ENABLED; + ixgbe_init_interrupt_scheme(adapter); + if (netif_running(netdev)) + netdev->netdev_ops->ndo_open(netdev); + } + } +out: + return err; +} + +static void ixgbe_dcbnl_get_perm_hw_addr(struct net_device *netdev, + u8 *perm_addr) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + int i; + + for (i = 0; i < netdev->addr_len; i++) + perm_addr[i] = adapter->hw.mac.perm_addr[i]; +} + +static void ixgbe_dcbnl_set_pg_tc_cfg_tx(struct net_device *netdev, int tc, + u8 prio, u8 bwg_id, u8 bw_pct, + u8 up_map) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + if (prio != DCB_ATTR_VALUE_UNDEFINED) + adapter->temp_dcb_cfg.tc_config[tc].path[0].prio_type = prio; + if (bwg_id != DCB_ATTR_VALUE_UNDEFINED) + adapter->temp_dcb_cfg.tc_config[tc].path[0].bwg_id = bwg_id; + if (bw_pct != DCB_ATTR_VALUE_UNDEFINED) + adapter->temp_dcb_cfg.tc_config[tc].path[0].bwg_percent = + bw_pct; + if (up_map != DCB_ATTR_VALUE_UNDEFINED) + adapter->temp_dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap = + up_map; + + if ((adapter->temp_dcb_cfg.tc_config[tc].path[0].prio_type != + adapter->dcb_cfg.tc_config[tc].path[0].prio_type) || + (adapter->temp_dcb_cfg.tc_config[tc].path[0].bwg_id != + adapter->dcb_cfg.tc_config[tc].path[0].bwg_id) || + (adapter->temp_dcb_cfg.tc_config[tc].path[0].bwg_percent != + adapter->dcb_cfg.tc_config[tc].path[0].bwg_percent) || + (adapter->temp_dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap != + adapter->dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap)) + adapter->dcb_set_bitmap |= BIT_PG_TX; +} + +static void ixgbe_dcbnl_set_pg_bwg_cfg_tx(struct net_device *netdev, int bwg_id, + u8 bw_pct) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + adapter->temp_dcb_cfg.bw_percentage[0][bwg_id] = bw_pct; + + if (adapter->temp_dcb_cfg.bw_percentage[0][bwg_id] != + adapter->dcb_cfg.bw_percentage[0][bwg_id]) + adapter->dcb_set_bitmap |= BIT_PG_RX; +} + +static void ixgbe_dcbnl_set_pg_tc_cfg_rx(struct net_device *netdev, int tc, + u8 prio, u8 bwg_id, u8 bw_pct, + u8 up_map) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + if (prio != DCB_ATTR_VALUE_UNDEFINED) + adapter->temp_dcb_cfg.tc_config[tc].path[1].prio_type = prio; + if (bwg_id != DCB_ATTR_VALUE_UNDEFINED) + adapter->temp_dcb_cfg.tc_config[tc].path[1].bwg_id = bwg_id; + if (bw_pct != DCB_ATTR_VALUE_UNDEFINED) + adapter->temp_dcb_cfg.tc_config[tc].path[1].bwg_percent = + bw_pct; + if (up_map != DCB_ATTR_VALUE_UNDEFINED) + adapter->temp_dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap = + up_map; + + if ((adapter->temp_dcb_cfg.tc_config[tc].path[1].prio_type != + adapter->dcb_cfg.tc_config[tc].path[1].prio_type) || + (adapter->temp_dcb_cfg.tc_config[tc].path[1].bwg_id != + adapter->dcb_cfg.tc_config[tc].path[1].bwg_id) || + (adapter->temp_dcb_cfg.tc_config[tc].path[1].bwg_percent != + adapter->dcb_cfg.tc_config[tc].path[1].bwg_percent) || + (adapter->temp_dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap != + adapter->dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap)) + adapter->dcb_set_bitmap |= BIT_PG_RX; +} + +static void ixgbe_dcbnl_set_pg_bwg_cfg_rx(struct net_device *netdev, int bwg_id, + u8 bw_pct) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + adapter->temp_dcb_cfg.bw_percentage[1][bwg_id] = bw_pct; + + if (adapter->temp_dcb_cfg.bw_percentage[1][bwg_id] != + adapter->dcb_cfg.bw_percentage[1][bwg_id]) + adapter->dcb_set_bitmap |= BIT_PG_RX; +} + +static void ixgbe_dcbnl_get_pg_tc_cfg_tx(struct net_device *netdev, int tc, + u8 *prio, u8 *bwg_id, u8 *bw_pct, + u8 *up_map) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + *prio = adapter->dcb_cfg.tc_config[tc].path[0].prio_type; + *bwg_id = adapter->dcb_cfg.tc_config[tc].path[0].bwg_id; + *bw_pct = adapter->dcb_cfg.tc_config[tc].path[0].bwg_percent; + *up_map = adapter->dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap; +} + +static void ixgbe_dcbnl_get_pg_bwg_cfg_tx(struct net_device *netdev, int bwg_id, + u8 *bw_pct) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + *bw_pct = adapter->dcb_cfg.bw_percentage[0][bwg_id]; +} + +static void ixgbe_dcbnl_get_pg_tc_cfg_rx(struct net_device *netdev, int tc, + u8 *prio, u8 *bwg_id, u8 *bw_pct, + u8 *up_map) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + *prio = adapter->dcb_cfg.tc_config[tc].path[1].prio_type; + *bwg_id = adapter->dcb_cfg.tc_config[tc].path[1].bwg_id; + *bw_pct = adapter->dcb_cfg.tc_config[tc].path[1].bwg_percent; + *up_map = adapter->dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap; +} + +static void ixgbe_dcbnl_get_pg_bwg_cfg_rx(struct net_device *netdev, int bwg_id, + u8 *bw_pct) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + *bw_pct = adapter->dcb_cfg.bw_percentage[1][bwg_id]; +} + +static void ixgbe_dcbnl_set_pfc_cfg(struct net_device *netdev, int priority, + u8 setting) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + adapter->temp_dcb_cfg.tc_config[priority].dcb_pfc = setting; + if (adapter->temp_dcb_cfg.tc_config[priority].dcb_pfc != + adapter->dcb_cfg.tc_config[priority].dcb_pfc) + adapter->dcb_set_bitmap |= BIT_PFC; +} + +static void ixgbe_dcbnl_get_pfc_cfg(struct net_device *netdev, int priority, + u8 *setting) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + *setting = adapter->dcb_cfg.tc_config[priority].dcb_pfc; +} + +static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + int ret; + + adapter->dcb_set_bitmap &= ~BIT_BCN; /* no set for BCN */ + if (!adapter->dcb_set_bitmap) + return 1; + + while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) + msleep(1); + + if (netif_running(netdev)) + ixgbe_down(adapter); + + ret = ixgbe_copy_dcb_cfg(&adapter->temp_dcb_cfg, &adapter->dcb_cfg, + adapter->ring_feature[RING_F_DCB].indices); + if (ret) { + clear_bit(__IXGBE_RESETTING, &adapter->state); + return ret; + } + + if (netif_running(netdev)) + ixgbe_up(adapter); + + adapter->dcb_set_bitmap = 0x00; + clear_bit(__IXGBE_RESETTING, &adapter->state); + return ret; +} + +static u8 ixgbe_dcbnl_getcap(struct net_device *netdev, int capid, u8 *cap) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + u8 rval = 0; + + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { + switch (capid) { + case DCB_CAP_ATTR_PG: + *cap = true; + break; + case DCB_CAP_ATTR_PFC: + *cap = true; + break; + case DCB_CAP_ATTR_UP2TC: + *cap = false; + break; + case DCB_CAP_ATTR_PG_TCS: + *cap = 0x80; + break; + case DCB_CAP_ATTR_PFC_TCS: + *cap = 0x80; + break; + case DCB_CAP_ATTR_GSP: + *cap = true; + break; + case DCB_CAP_ATTR_BCN: + *cap = false; + break; + default: + rval = -EINVAL; + break; + } + } else { + rval = -EINVAL; + } + + return rval; +} + +static u8 ixgbe_dcbnl_getnumtcs(struct net_device *netdev, int tcid, u8 *num) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + u8 rval = 0; + + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { + switch (tcid) { + case DCB_NUMTCS_ATTR_PG: + *num = MAX_TRAFFIC_CLASS; + break; + case DCB_NUMTCS_ATTR_PFC: + *num = MAX_TRAFFIC_CLASS; + break; + default: + rval = -EINVAL; + break; + } + } else { + rval = -EINVAL; + } + + return rval; +} + +static u8 ixgbe_dcbnl_setnumtcs(struct net_device *netdev, int tcid, u8 num) +{ + return -EINVAL; +} + +static u8 ixgbe_dcbnl_getpfcstate(struct net_device *netdev) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + return !!(adapter->flags & IXGBE_FLAG_DCB_ENABLED); +} + +static void ixgbe_dcbnl_setpfcstate(struct net_device *netdev, u8 state) +{ + return; +} + +static void ixgbe_dcbnl_getbcnrp(struct net_device *netdev, int priority, + u8 *setting) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + *setting = adapter->dcb_cfg.bcn.rp_admin_mode[priority]; +} + + +static void ixgbe_dcbnl_getbcncfg(struct net_device *netdev, int enum_index, + u32 *setting) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + switch (enum_index) { + case DCB_BCN_ATTR_BCNA_0: + *setting = adapter->dcb_cfg.bcn.bcna_option[0]; + break; + case DCB_BCN_ATTR_BCNA_1: + *setting = adapter->dcb_cfg.bcn.bcna_option[1]; + break; + case DCB_BCN_ATTR_ALPHA: + *setting = adapter->dcb_cfg.bcn.rp_alpha; + break; + case DCB_BCN_ATTR_BETA: + *setting = adapter->dcb_cfg.bcn.rp_beta; + break; + case DCB_BCN_ATTR_GD: + *setting = adapter->dcb_cfg.bcn.rp_gd; + break; + case DCB_BCN_ATTR_GI: + *setting = adapter->dcb_cfg.bcn.rp_gi; + break; + case DCB_BCN_ATTR_TMAX: + *setting = adapter->dcb_cfg.bcn.rp_tmax; + break; + case DCB_BCN_ATTR_TD: + *setting = adapter->dcb_cfg.bcn.rp_td; + break; + case DCB_BCN_ATTR_RMIN: + *setting = adapter->dcb_cfg.bcn.rp_rmin; + break; + case DCB_BCN_ATTR_W: + *setting = adapter->dcb_cfg.bcn.rp_w; + break; + case DCB_BCN_ATTR_RD: + *setting = adapter->dcb_cfg.bcn.rp_rd; + break; + case DCB_BCN_ATTR_RU: + *setting = adapter->dcb_cfg.bcn.rp_ru; + break; + case DCB_BCN_ATTR_WRTT: + *setting = adapter->dcb_cfg.bcn.rp_wrtt; + break; + case DCB_BCN_ATTR_RI: + *setting = adapter->dcb_cfg.bcn.rp_ri; + break; + default: + *setting = -1; + } +} + +static void ixgbe_dcbnl_setbcnrp(struct net_device *netdev, int priority, + u8 setting) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + adapter->temp_dcb_cfg.bcn.rp_admin_mode[priority] = setting; + + if (adapter->temp_dcb_cfg.bcn.rp_admin_mode[priority] != + adapter->dcb_cfg.bcn.rp_admin_mode[priority]) + adapter->dcb_set_bitmap |= BIT_BCN; +} + +static void ixgbe_dcbnl_setbcncfg(struct net_device *netdev, int enum_index, + u32 setting) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + switch (enum_index) { + case DCB_BCN_ATTR_BCNA_0: + adapter->temp_dcb_cfg.bcn.bcna_option[0] = setting; + if (adapter->temp_dcb_cfg.bcn.bcna_option[0] != + adapter->dcb_cfg.bcn.bcna_option[0]) + adapter->dcb_set_bitmap |= BIT_BCN; + break; + case DCB_BCN_ATTR_BCNA_1: + adapter->temp_dcb_cfg.bcn.bcna_option[1] = setting; + if (adapter->temp_dcb_cfg.bcn.bcna_option[1] != + adapter->dcb_cfg.bcn.bcna_option[1]) + adapter->dcb_set_bitmap |= BIT_BCN; + break; + case DCB_BCN_ATTR_ALPHA: + adapter->temp_dcb_cfg.bcn.rp_alpha = setting; + if (adapter->temp_dcb_cfg.bcn.rp_alpha != + adapter->dcb_cfg.bcn.rp_alpha) + adapter->dcb_set_bitmap |= BIT_BCN; + break; + case DCB_BCN_ATTR_BETA: + adapter->temp_dcb_cfg.bcn.rp_beta = setting; + if (adapter->temp_dcb_cfg.bcn.rp_beta != + adapter->dcb_cfg.bcn.rp_beta) + adapter->dcb_set_bitmap |= BIT_BCN; + break; + case DCB_BCN_ATTR_GD: + adapter->temp_dcb_cfg.bcn.rp_gd = setting; + if (adapter->temp_dcb_cfg.bcn.rp_gd != + adapter->dcb_cfg.bcn.rp_gd) + adapter->dcb_set_bitmap |= BIT_BCN; + break; + case DCB_BCN_ATTR_GI: + adapter->temp_dcb_cfg.bcn.rp_gi = setting; + if (adapter->temp_dcb_cfg.bcn.rp_gi != + adapter->dcb_cfg.bcn.rp_gi) + adapter->dcb_set_bitmap |= BIT_BCN; + break; + case DCB_BCN_ATTR_TMAX: + adapter->temp_dcb_cfg.bcn.rp_tmax = setting; + if (adapter->temp_dcb_cfg.bcn.rp_tmax != + adapter->dcb_cfg.bcn.rp_tmax) + adapter->dcb_set_bitmap |= BIT_BCN; + break; + case DCB_BCN_ATTR_TD: + adapter->temp_dcb_cfg.bcn.rp_td = setting; + if (adapter->temp_dcb_cfg.bcn.rp_td != + adapter->dcb_cfg.bcn.rp_td) + adapter->dcb_set_bitmap |= BIT_BCN; + break; + case DCB_BCN_ATTR_RMIN: + adapter->temp_dcb_cfg.bcn.rp_rmin = setting; + if (adapter->temp_dcb_cfg.bcn.rp_rmin != + adapter->dcb_cfg.bcn.rp_rmin) + adapter->dcb_set_bitmap |= BIT_BCN; + break; + case DCB_BCN_ATTR_W: + adapter->temp_dcb_cfg.bcn.rp_w = setting; + if (adapter->temp_dcb_cfg.bcn.rp_w != + adapter->dcb_cfg.bcn.rp_w) + adapter->dcb_set_bitmap |= BIT_BCN; + break; + case DCB_BCN_ATTR_RD: + adapter->temp_dcb_cfg.bcn.rp_rd = setting; + if (adapter->temp_dcb_cfg.bcn.rp_rd != + adapter->dcb_cfg.bcn.rp_rd) + adapter->dcb_set_bitmap |= BIT_BCN; + break; + case DCB_BCN_ATTR_RU: + adapter->temp_dcb_cfg.bcn.rp_ru = setting; + if (adapter->temp_dcb_cfg.bcn.rp_ru != + adapter->dcb_cfg.bcn.rp_ru) + adapter->dcb_set_bitmap |= BIT_BCN; + break; + case DCB_BCN_ATTR_WRTT: + adapter->temp_dcb_cfg.bcn.rp_wrtt = setting; + if (adapter->temp_dcb_cfg.bcn.rp_wrtt != + adapter->dcb_cfg.bcn.rp_wrtt) + adapter->dcb_set_bitmap |= BIT_BCN; + break; + case DCB_BCN_ATTR_RI: + adapter->temp_dcb_cfg.bcn.rp_ri = setting; + if (adapter->temp_dcb_cfg.bcn.rp_ri != + adapter->dcb_cfg.bcn.rp_ri) + adapter->dcb_set_bitmap |= BIT_BCN; + break; + default: + break; + } +} + +struct dcbnl_rtnl_ops dcbnl_ops = { + .getstate = ixgbe_dcbnl_get_state, + .setstate = ixgbe_dcbnl_set_state, + .getpermhwaddr = ixgbe_dcbnl_get_perm_hw_addr, + .setpgtccfgtx = ixgbe_dcbnl_set_pg_tc_cfg_tx, + .setpgbwgcfgtx = ixgbe_dcbnl_set_pg_bwg_cfg_tx, + .setpgtccfgrx = ixgbe_dcbnl_set_pg_tc_cfg_rx, + .setpgbwgcfgrx = ixgbe_dcbnl_set_pg_bwg_cfg_rx, + .getpgtccfgtx = ixgbe_dcbnl_get_pg_tc_cfg_tx, + .getpgbwgcfgtx = ixgbe_dcbnl_get_pg_bwg_cfg_tx, + .getpgtccfgrx = ixgbe_dcbnl_get_pg_tc_cfg_rx, + .getpgbwgcfgrx = ixgbe_dcbnl_get_pg_bwg_cfg_rx, + .setpfccfg = ixgbe_dcbnl_set_pfc_cfg, + .getpfccfg = ixgbe_dcbnl_get_pfc_cfg, + .setall = ixgbe_dcbnl_set_all, + .getcap = ixgbe_dcbnl_getcap, + .getnumtcs = ixgbe_dcbnl_getnumtcs, + .setnumtcs = ixgbe_dcbnl_setnumtcs, + .getpfcstate = ixgbe_dcbnl_getpfcstate, + .setpfcstate = ixgbe_dcbnl_setpfcstate, + .getbcncfg = ixgbe_dcbnl_getbcncfg, + .getbcnrp = ixgbe_dcbnl_getbcnrp, + .setbcncfg = ixgbe_dcbnl_setbcncfg, + .setbcnrp = ixgbe_dcbnl_setbcnrp +}; + diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 81a9c4b8672683a8033ef5e73e3a4096e5e7a724..67f87a79154dbff3f88ab64bddaa7ab2577b7099 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -94,12 +94,21 @@ static struct ixgbe_stats ixgbe_gstrings_stats[] = { }; #define IXGBE_QUEUE_STATS_LEN \ - ((((struct ixgbe_adapter *)netdev->priv)->num_tx_queues + \ - ((struct ixgbe_adapter *)netdev->priv)->num_rx_queues) * \ - (sizeof(struct ixgbe_queue_stats) / sizeof(u64))) -#define IXGBE_STATS_LEN (IXGBE_GLOBAL_STATS_LEN + IXGBE_QUEUE_STATS_LEN) + ((((struct ixgbe_adapter *)netdev_priv(netdev))->num_tx_queues + \ + ((struct ixgbe_adapter *)netdev_priv(netdev))->num_rx_queues) * \ + (sizeof(struct ixgbe_queue_stats) / sizeof(u64))) #define IXGBE_GLOBAL_STATS_LEN ARRAY_SIZE(ixgbe_gstrings_stats) -#define IXGBE_STATS_LEN (IXGBE_GLOBAL_STATS_LEN + IXGBE_QUEUE_STATS_LEN) +#define IXGBE_PB_STATS_LEN ( \ + (((struct ixgbe_adapter *)netdev_priv(netdev))->flags & \ + IXGBE_FLAG_DCB_ENABLED) ? \ + (sizeof(((struct ixgbe_adapter *)0)->stats.pxonrxc) + \ + sizeof(((struct ixgbe_adapter *)0)->stats.pxontxc) + \ + sizeof(((struct ixgbe_adapter *)0)->stats.pxoffrxc) + \ + sizeof(((struct ixgbe_adapter *)0)->stats.pxofftxc)) \ + / sizeof(u64) : 0) +#define IXGBE_STATS_LEN (IXGBE_GLOBAL_STATS_LEN + \ + IXGBE_PB_STATS_LEN + \ + IXGBE_QUEUE_STATS_LEN) static int ixgbe_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) @@ -149,6 +158,8 @@ static int ixgbe_set_settings(struct net_device *netdev, { struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; + u32 advertised, old; + s32 err; switch (hw->phy.media_type) { case ixgbe_media_type_fiber: @@ -157,6 +168,31 @@ static int ixgbe_set_settings(struct net_device *netdev, return -EINVAL; /* in this case we currently only support 10Gb/FULL */ break; + case ixgbe_media_type_copper: + /* 10000/copper and 1000/copper must autoneg + * this function does not support any duplex forcing, but can + * limit the advertising of the adapter to only 10000 or 1000 */ + if (ecmd->autoneg == AUTONEG_DISABLE) + return -EINVAL; + + old = hw->phy.autoneg_advertised; + advertised = 0; + if (ecmd->advertising & ADVERTISED_10000baseT_Full) + advertised |= IXGBE_LINK_SPEED_10GB_FULL; + + if (ecmd->advertising & ADVERTISED_1000baseT_Full) + advertised |= IXGBE_LINK_SPEED_1GB_FULL; + + if (old == advertised) + break; + /* this sets the link speed and restarts auto-neg */ + err = hw->mac.ops.setup_link_speed(hw, advertised, true, true); + if (err) { + DPRINTK(PROBE, INFO, + "setup link failed with code %d\n", err); + hw->mac.ops.setup_link_speed(hw, old, true, true); + } + break; default: break; } @@ -676,30 +712,15 @@ static int ixgbe_set_ringparam(struct net_device *netdev, return 0; } - if (adapter->num_tx_queues > adapter->num_rx_queues) - temp_ring = vmalloc(adapter->num_tx_queues * - sizeof(struct ixgbe_ring)); - else - temp_ring = vmalloc(adapter->num_rx_queues * - sizeof(struct ixgbe_ring)); + temp_ring = kcalloc(adapter->num_tx_queues, + sizeof(struct ixgbe_ring), GFP_KERNEL); if (!temp_ring) return -ENOMEM; while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) msleep(1); - if (netif_running(netdev)) - ixgbe_down(adapter); - - /* - * We can't just free everything and then setup again, - * because the ISRs in MSI-X mode get passed pointers - * to the tx and rx ring structs. - */ if (new_tx_count != adapter->tx_ring->count) { - memcpy(temp_ring, adapter->tx_ring, - adapter->num_tx_queues * sizeof(struct ixgbe_ring)); - for (i = 0; i < adapter->num_tx_queues; i++) { temp_ring[i].count = new_tx_count; err = ixgbe_setup_tx_resources(adapter, &temp_ring[i]); @@ -711,21 +732,28 @@ static int ixgbe_set_ringparam(struct net_device *netdev, } goto err_setup; } + temp_ring[i].v_idx = adapter->tx_ring[i].v_idx; } - - for (i = 0; i < adapter->num_tx_queues; i++) - ixgbe_free_tx_resources(adapter, &adapter->tx_ring[i]); - - memcpy(adapter->tx_ring, temp_ring, - adapter->num_tx_queues * sizeof(struct ixgbe_ring)); - + if (netif_running(netdev)) + netdev->netdev_ops->ndo_stop(netdev); + ixgbe_reset_interrupt_capability(adapter); + ixgbe_napi_del_all(adapter); + INIT_LIST_HEAD(&netdev->napi_list); + kfree(adapter->tx_ring); + adapter->tx_ring = temp_ring; + temp_ring = NULL; adapter->tx_ring_count = new_tx_count; } - if (new_rx_count != adapter->rx_ring->count) { - memcpy(temp_ring, adapter->rx_ring, - adapter->num_rx_queues * sizeof(struct ixgbe_ring)); + temp_ring = kcalloc(adapter->num_rx_queues, + sizeof(struct ixgbe_ring), GFP_KERNEL); + if (!temp_ring) { + if (netif_running(netdev)) + netdev->netdev_ops->ndo_open(netdev); + return -ENOMEM; + } + if (new_rx_count != adapter->rx_ring->count) { for (i = 0; i < adapter->num_rx_queues; i++) { temp_ring[i].count = new_rx_count; err = ixgbe_setup_rx_resources(adapter, &temp_ring[i]); @@ -737,13 +765,16 @@ static int ixgbe_set_ringparam(struct net_device *netdev, } goto err_setup; } + temp_ring[i].v_idx = adapter->rx_ring[i].v_idx; } - - for (i = 0; i < adapter->num_rx_queues; i++) - ixgbe_free_rx_resources(adapter, &adapter->rx_ring[i]); - - memcpy(adapter->rx_ring, temp_ring, - adapter->num_rx_queues * sizeof(struct ixgbe_ring)); + if (netif_running(netdev)) + netdev->netdev_ops->ndo_stop(netdev); + ixgbe_reset_interrupt_capability(adapter); + ixgbe_napi_del_all(adapter); + INIT_LIST_HEAD(&netdev->napi_list); + kfree(adapter->rx_ring); + adapter->rx_ring = temp_ring; + temp_ring = NULL; adapter->rx_ring_count = new_rx_count; } @@ -751,8 +782,9 @@ static int ixgbe_set_ringparam(struct net_device *netdev, /* success! */ err = 0; err_setup: + ixgbe_init_interrupt_scheme(adapter); if (netif_running(netdev)) - ixgbe_up(adapter); + netdev->netdev_ops->ndo_open(netdev); clear_bit(__IXGBE_RESETTING, &adapter->state); return err; @@ -804,6 +836,16 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev, data[i + k] = queue_stat[k]; i += k; } + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { + for (j = 0; j < MAX_TX_PACKET_BUFFERS; j++) { + data[i++] = adapter->stats.pxontxc[j]; + data[i++] = adapter->stats.pxofftxc[j]; + } + for (j = 0; j < MAX_RX_PACKET_BUFFERS; j++) { + data[i++] = adapter->stats.pxonrxc[j]; + data[i++] = adapter->stats.pxoffrxc[j]; + } + } } static void ixgbe_get_strings(struct net_device *netdev, u32 stringset, @@ -832,6 +874,20 @@ static void ixgbe_get_strings(struct net_device *netdev, u32 stringset, sprintf(p, "rx_queue_%u_bytes", i); p += ETH_GSTRING_LEN; } + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { + for (i = 0; i < MAX_TX_PACKET_BUFFERS; i++) { + sprintf(p, "tx_pb_%u_pxon", i); + p += ETH_GSTRING_LEN; + sprintf(p, "tx_pb_%u_pxoff", i); + p += ETH_GSTRING_LEN; + } + for (i = 0; i < MAX_RX_PACKET_BUFFERS; i++) { + sprintf(p, "rx_pb_%u_pxon", i); + p += ETH_GSTRING_LEN; + sprintf(p, "rx_pb_%u_pxoff", i); + p += ETH_GSTRING_LEN; + } + } /* BUG_ON(p - data != IXGBE_STATS_LEN * ETH_GSTRING_LEN); */ break; } diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 5236f633ee36e3361af138cf3e2c2ae3033e1b53..acef3c65cd2c4c2d3ba463c10f5f5cf0b3a725ff 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -68,12 +68,20 @@ static struct pci_device_id ixgbe_pci_tbl[] = { board_82598 }, {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AF_SINGLE_PORT), board_82598 }, + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AT), + board_82598 }, {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_CX4), board_82598 }, {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_CX4_DUAL_PORT), board_82598 }, + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_DA_DUAL_PORT), + board_82598 }, + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM), + board_82598 }, {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_XF_LR), board_82598 }, + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_SFP_LOM), + board_82598 }, /* required last entry */ {0, } @@ -402,7 +410,7 @@ static void ixgbe_receive_skb(struct ixgbe_adapter *adapter, if (adapter->netdev->features & NETIF_F_LRO && skb->ip_summed == CHECKSUM_UNNECESSARY) { - if (adapter->vlgrp && is_vlan) + if (adapter->vlgrp && is_vlan && (tag != 0)) lro_vlan_hwaccel_receive_skb(&ring->lro_mgr, skb, adapter->vlgrp, tag, rx_desc); @@ -411,12 +419,12 @@ static void ixgbe_receive_skb(struct ixgbe_adapter *adapter, ring->lro_used = true; } else { if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) { - if (adapter->vlgrp && is_vlan) + if (adapter->vlgrp && is_vlan && (tag != 0)) vlan_hwaccel_receive_skb(skb, adapter->vlgrp, tag); else netif_receive_skb(skb); } else { - if (adapter->vlgrp && is_vlan) + if (adapter->vlgrp && is_vlan && (tag != 0)) vlan_hwaccel_rx(skb, adapter->vlgrp, tag); else netif_rx(skb); @@ -471,7 +479,6 @@ static void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter, union ixgbe_adv_rx_desc *rx_desc; struct ixgbe_rx_buffer *bi; unsigned int i; - unsigned int bufsz = rx_ring->rx_buf_len + NET_IP_ALIGN; i = rx_ring->next_to_use; bi = &rx_ring->rx_buffer_info[i]; @@ -500,8 +507,10 @@ static void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter, } if (!bi->skb) { - struct sk_buff *skb = netdev_alloc_skb(adapter->netdev, - bufsz); + struct sk_buff *skb; + skb = netdev_alloc_skb(adapter->netdev, + (rx_ring->rx_buf_len + + NET_IP_ALIGN)); if (!skb) { adapter->alloc_rx_buff_failed++; @@ -516,7 +525,8 @@ static void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter, skb_reserve(skb, NET_IP_ALIGN); bi->skb = skb; - bi->dma = pci_map_single(pdev, skb->data, bufsz, + bi->dma = pci_map_single(pdev, skb->data, + rx_ring->rx_buf_len, PCI_DMA_FROMDEVICE); } /* Refresh the desc even if buffer_addrs didn't change because @@ -607,7 +617,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter, if (len && !skb_shinfo(skb)->nr_frags) { pci_unmap_single(pdev, rx_buffer_info->dma, - rx_ring->rx_buf_len + NET_IP_ALIGN, + rx_ring->rx_buf_len, PCI_DMA_FROMDEVICE); skb_put(skb, len); } @@ -666,7 +676,6 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter, skb->protocol = eth_type_trans(skb, adapter->netdev); ixgbe_receive_skb(adapter, skb, staterr, rx_ring, rx_desc); - adapter->netdev->last_rx = jiffies; next_desc: rx_desc->wb.upper.status_error = 0; @@ -904,6 +913,17 @@ static void ixgbe_set_itr_msix(struct ixgbe_q_vector *q_vector) return; } +static void ixgbe_check_fan_failure(struct ixgbe_adapter *adapter, u32 eicr) +{ + struct ixgbe_hw *hw = &adapter->hw; + + if ((adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) && + (eicr & IXGBE_EICR_GPI_SDP1)) { + DPRINTK(PROBE, CRIT, "Fan has stopped, replace the adapter\n"); + /* write to clear the interrupt */ + IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1); + } +} static void ixgbe_check_lsc(struct ixgbe_adapter *adapter) { @@ -928,6 +948,8 @@ static irqreturn_t ixgbe_msix_lsc(int irq, void *data) if (eicr & IXGBE_EICR_LSC) ixgbe_check_lsc(adapter); + ixgbe_check_fan_failure(adapter, eicr); + if (!test_bit(__IXGBE_DOWN, &adapter->state)) IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_OTHER); @@ -990,7 +1012,7 @@ static irqreturn_t ixgbe_msix_clean_rx(int irq, void *data) rx_ring = &(adapter->rx_ring[r_idx]); /* disable interrupts on this vector only */ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, rx_ring->v_idx); - netif_rx_schedule(adapter->netdev, &q_vector->napi); + netif_rx_schedule(&q_vector->napi); return IRQ_HANDLED; } @@ -1031,7 +1053,7 @@ static int ixgbe_clean_rxonly(struct napi_struct *napi, int budget) /* If all Rx work done, exit the polling mode */ if (work_done < budget) { - netif_rx_complete(adapter->netdev, napi); + netif_rx_complete(napi); if (adapter->itr_setting & 3) ixgbe_set_itr_msix(q_vector); if (!test_bit(__IXGBE_DOWN, &adapter->state)) @@ -1080,7 +1102,7 @@ static int ixgbe_clean_rxonly_many(struct napi_struct *napi, int budget) rx_ring = &(adapter->rx_ring[r_idx]); /* If all Rx work done, exit the polling mode */ if (work_done < budget) { - netif_rx_complete(adapter->netdev, napi); + netif_rx_complete(napi); if (adapter->itr_setting & 3) ixgbe_set_itr_msix(q_vector); if (!test_bit(__IXGBE_DOWN, &adapter->state)) @@ -1187,6 +1209,7 @@ static int ixgbe_request_msix_irqs(struct ixgbe_adapter *adapter) struct net_device *netdev = adapter->netdev; irqreturn_t (*handler)(int, void *); int i, vector, q_vectors, err; + int ri=0, ti=0; /* Decrement for Other and TCP Timer vectors */ q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; @@ -1201,10 +1224,19 @@ static int ixgbe_request_msix_irqs(struct ixgbe_adapter *adapter) &ixgbe_msix_clean_many) for (vector = 0; vector < q_vectors; vector++) { handler = SET_HANDLER(&adapter->q_vector[vector]); - sprintf(adapter->name[vector], "%s:v%d-%s", - netdev->name, vector, - (handler == &ixgbe_msix_clean_rx) ? "Rx" : - ((handler == &ixgbe_msix_clean_tx) ? "Tx" : "TxRx")); + + if(handler == &ixgbe_msix_clean_rx) { + sprintf(adapter->name[vector], "%s-%s-%d", + netdev->name, "rx", ri++); + } + else if(handler == &ixgbe_msix_clean_tx) { + sprintf(adapter->name[vector], "%s-%s-%d", + netdev->name, "tx", ti++); + } + else + sprintf(adapter->name[vector], "%s-%s-%d", + netdev->name, "TxRx", vector); + err = request_irq(adapter->msix_entries[vector].vector, handler, 0, adapter->name[vector], &(adapter->q_vector[vector])); @@ -1312,6 +1344,8 @@ static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter) { u32 mask; mask = IXGBE_EIMS_ENABLE_MASK; + if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) + mask |= IXGBE_EIMS_GPI_SDP1; IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask); IXGBE_WRITE_FLUSH(&adapter->hw); } @@ -1342,13 +1376,15 @@ static irqreturn_t ixgbe_intr(int irq, void *data) if (eicr & IXGBE_EICR_LSC) ixgbe_check_lsc(adapter); - if (netif_rx_schedule_prep(netdev, &adapter->q_vector[0].napi)) { + ixgbe_check_fan_failure(adapter, eicr); + + if (netif_rx_schedule_prep(&adapter->q_vector[0].napi)) { adapter->tx_ring[0].total_packets = 0; adapter->tx_ring[0].total_bytes = 0; adapter->rx_ring[0].total_packets = 0; adapter->rx_ring[0].total_bytes = 0; /* would disable interrupts here but EIAM disabled it */ - __netif_rx_schedule(netdev, &adapter->q_vector[0].napi); + __netif_rx_schedule(&adapter->q_vector[0].napi); } return IRQ_HANDLED; @@ -1651,10 +1687,12 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) * effects of setting this bit are only that SRRCTL must be * fully programmed [0..15] */ - rdrxctl = IXGBE_READ_REG(hw, IXGBE_RDRXCTL); - rdrxctl |= IXGBE_RDRXCTL_MVMEN; - IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl); - + if (adapter->flags & + (IXGBE_FLAG_RSS_ENABLED | IXGBE_FLAG_VMDQ_ENABLED)) { + rdrxctl = IXGBE_READ_REG(hw, IXGBE_RDRXCTL); + rdrxctl |= IXGBE_RDRXCTL_MVMEN; + IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl); + } if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) { /* Fill out redirection table */ @@ -1713,6 +1751,16 @@ static void ixgbe_vlan_rx_register(struct net_device *netdev, ixgbe_irq_disable(adapter); adapter->vlgrp = grp; + /* + * For a DCB driver, always enable VLAN tag stripping so we can + * still receive traffic from a DCB-enabled host even if we're + * not in DCB mode. + */ + ctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_VLNCTRL); + ctrl |= IXGBE_VLNCTRL_VME; + ctrl &= ~IXGBE_VLNCTRL_CFIEN; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_VLNCTRL, ctrl); + if (grp) { /* enable VLAN tag insert/strip */ ctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_VLNCTRL); @@ -1877,6 +1925,44 @@ static void ixgbe_napi_disable_all(struct ixgbe_adapter *adapter) } } +#ifdef CONFIG_IXGBE_DCB +/* + * ixgbe_configure_dcb - Configure DCB hardware + * @adapter: ixgbe adapter struct + * + * This is called by the driver on open to configure the DCB hardware. + * This is also called by the gennetlink interface when reconfiguring + * the DCB state. + */ +static void ixgbe_configure_dcb(struct ixgbe_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + u32 txdctl, vlnctrl; + int i, j; + + ixgbe_dcb_check_config(&adapter->dcb_cfg); + ixgbe_dcb_calculate_tc_credits(&adapter->dcb_cfg, DCB_TX_CONFIG); + ixgbe_dcb_calculate_tc_credits(&adapter->dcb_cfg, DCB_RX_CONFIG); + + /* reconfigure the hardware */ + ixgbe_dcb_hw_config(&adapter->hw, &adapter->dcb_cfg); + + for (i = 0; i < adapter->num_tx_queues; i++) { + j = adapter->tx_ring[i].reg_idx; + txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j)); + /* PThresh workaround for Tx hang with DFP enabled. */ + txdctl |= 32; + IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j), txdctl); + } + /* Enable VLAN tag insert/strip */ + vlnctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL); + vlnctrl |= IXGBE_VLNCTRL_VME | IXGBE_VLNCTRL_VFE; + vlnctrl &= ~IXGBE_VLNCTRL_CFIEN; + IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl); + hw->mac.ops.set_vfta(&adapter->hw, 0, 0, true); +} + +#endif static void ixgbe_configure(struct ixgbe_adapter *adapter) { struct net_device *netdev = adapter->netdev; @@ -1885,6 +1971,16 @@ static void ixgbe_configure(struct ixgbe_adapter *adapter) ixgbe_set_rx_mode(netdev); ixgbe_restore_vlan(adapter); +#ifdef CONFIG_IXGBE_DCB + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { + netif_set_gso_max_size(netdev, 32768); + ixgbe_configure_dcb(adapter); + } else { + netif_set_gso_max_size(netdev, 65536); + } +#else + netif_set_gso_max_size(netdev, 65536); +#endif ixgbe_configure_tx(adapter); ixgbe_configure_rx(adapter); @@ -1924,6 +2020,13 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE); } + /* Enable fan failure interrupt if media type is copper */ + if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) { + gpie = IXGBE_READ_REG(hw, IXGBE_GPIE); + gpie |= IXGBE_SDP1_GPIEN; + IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie); + } + mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD); if (max_frame != (mhadd >> IXGBE_MHADD_MFS_SHIFT)) { mhadd &= ~IXGBE_MHADD_MFS_MASK; @@ -1961,6 +2064,8 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) else ixgbe_configure_msi_and_legacy(adapter); + ixgbe_napi_add_all(adapter); + clear_bit(__IXGBE_DOWN, &adapter->state); ixgbe_napi_enable_all(adapter); @@ -2205,7 +2310,7 @@ static int ixgbe_poll(struct napi_struct *napi, int budget) /* If budget not fully consumed, exit the polling mode */ if (work_done < budget) { - netif_rx_complete(adapter->netdev, napi); + netif_rx_complete(napi); if (adapter->itr_setting & 3) ixgbe_set_itr(adapter); if (!test_bit(__IXGBE_DOWN, &adapter->state)) @@ -2231,6 +2336,11 @@ static void ixgbe_reset_task(struct work_struct *work) struct ixgbe_adapter *adapter; adapter = container_of(work, struct ixgbe_adapter, reset_task); + /* If we're already down or resetting, just bail */ + if (test_bit(__IXGBE_DOWN, &adapter->state) || + test_bit(__IXGBE_RESETTING, &adapter->state)) + return; + adapter->tx_timeout_count++; ixgbe_reinit_locked(adapter); @@ -2240,15 +2350,31 @@ static void ixgbe_set_num_queues(struct ixgbe_adapter *adapter) { int nrq = 1, ntq = 1; int feature_mask = 0, rss_i, rss_m; + int dcb_i, dcb_m; /* Number of supported queues */ switch (adapter->hw.mac.type) { case ixgbe_mac_82598EB: + dcb_i = adapter->ring_feature[RING_F_DCB].indices; + dcb_m = 0; rss_i = adapter->ring_feature[RING_F_RSS].indices; rss_m = 0; feature_mask |= IXGBE_FLAG_RSS_ENABLED; + feature_mask |= IXGBE_FLAG_DCB_ENABLED; switch (adapter->flags & feature_mask) { + case (IXGBE_FLAG_RSS_ENABLED | IXGBE_FLAG_DCB_ENABLED): + dcb_m = 0x7 << 3; + rss_i = min(8, rss_i); + rss_m = 0x7; + nrq = dcb_i * rss_i; + ntq = min(MAX_TX_QUEUES, dcb_i * rss_i); + break; + case (IXGBE_FLAG_DCB_ENABLED): + dcb_m = 0x7 << 3; + nrq = dcb_i; + ntq = dcb_i; + break; case (IXGBE_FLAG_RSS_ENABLED): rss_m = 0xF; nrq = rss_i; @@ -2256,6 +2382,8 @@ static void ixgbe_set_num_queues(struct ixgbe_adapter *adapter) break; case 0: default: + dcb_i = 0; + dcb_m = 0; rss_i = 0; rss_m = 0; nrq = 1; @@ -2263,6 +2391,12 @@ static void ixgbe_set_num_queues(struct ixgbe_adapter *adapter) break; } + /* Sanity check, we should never have zero queues */ + nrq = (nrq ?:1); + ntq = (ntq ?:1); + + adapter->ring_feature[RING_F_DCB].indices = dcb_i; + adapter->ring_feature[RING_F_DCB].mask = dcb_m; adapter->ring_feature[RING_F_RSS].indices = rss_i; adapter->ring_feature[RING_F_RSS].mask = rss_m; break; @@ -2314,6 +2448,7 @@ static void ixgbe_acquire_msix_vectors(struct ixgbe_adapter *adapter, adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED; kfree(adapter->msix_entries); adapter->msix_entries = NULL; + adapter->flags &= ~IXGBE_FLAG_DCB_ENABLED; adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED; ixgbe_set_num_queues(adapter); } else { @@ -2333,15 +2468,42 @@ static void ixgbe_cache_ring_register(struct ixgbe_adapter *adapter) { int feature_mask = 0, rss_i; int i, txr_idx, rxr_idx; + int dcb_i; /* Number of supported queues */ switch (adapter->hw.mac.type) { case ixgbe_mac_82598EB: + dcb_i = adapter->ring_feature[RING_F_DCB].indices; rss_i = adapter->ring_feature[RING_F_RSS].indices; txr_idx = 0; rxr_idx = 0; + feature_mask |= IXGBE_FLAG_DCB_ENABLED; feature_mask |= IXGBE_FLAG_RSS_ENABLED; switch (adapter->flags & feature_mask) { + case (IXGBE_FLAG_RSS_ENABLED | IXGBE_FLAG_DCB_ENABLED): + for (i = 0; i < dcb_i; i++) { + int j; + /* Rx first */ + for (j = 0; j < adapter->num_rx_queues; j++) { + adapter->rx_ring[rxr_idx].reg_idx = + i << 3 | j; + rxr_idx++; + } + /* Tx now */ + for (j = 0; j < adapter->num_tx_queues; j++) { + adapter->tx_ring[txr_idx].reg_idx = + i << 2 | (j >> 1); + if (j & 1) + txr_idx++; + } + } + case (IXGBE_FLAG_DCB_ENABLED): + /* the number of queues is assumed to be symmetric */ + for (i = 0; i < dcb_i; i++) { + adapter->rx_ring[i].reg_idx = i << 3; + adapter->tx_ring[i].reg_idx = i << 2; + } + break; case (IXGBE_FLAG_RSS_ENABLED): for (i = 0; i < adapter->num_rx_queues; i++) adapter->rx_ring[i].reg_idx = i; @@ -2363,8 +2525,7 @@ static void ixgbe_cache_ring_register(struct ixgbe_adapter *adapter) * @adapter: board private structure to initialize * * We allocate one ring per queue at run-time since we don't know the - * number of queues at compile-time. The polling_netdev array is - * intended for Multiqueue, but should work fine with a single queue. + * number of queues at compile-time. **/ static int ixgbe_alloc_queues(struct ixgbe_adapter *adapter) { @@ -2435,6 +2596,7 @@ static int ixgbe_set_interrupt_capability(struct ixgbe_adapter *adapter) adapter->msix_entries = kcalloc(v_budget, sizeof(struct msix_entry), GFP_KERNEL); if (!adapter->msix_entries) { + adapter->flags &= ~IXGBE_FLAG_DCB_ENABLED; adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED; ixgbe_set_num_queues(adapter); kfree(adapter->tx_ring); @@ -2475,7 +2637,7 @@ static int ixgbe_set_interrupt_capability(struct ixgbe_adapter *adapter) return err; } -static void ixgbe_reset_interrupt_capability(struct ixgbe_adapter *adapter) +void ixgbe_reset_interrupt_capability(struct ixgbe_adapter *adapter) { if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED; @@ -2499,7 +2661,7 @@ static void ixgbe_reset_interrupt_capability(struct ixgbe_adapter *adapter) * - Hardware queue count (num_*_queues) * - defined by miscellaneous hardware support/features (RSS, etc.) **/ -static int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter) +int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter) { int err; @@ -2534,6 +2696,57 @@ static int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter) return err; } +/** + * ixgbe_sfp_timer - worker thread to find a missing module + * @data: pointer to our adapter struct + **/ +static void ixgbe_sfp_timer(unsigned long data) +{ + struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data; + + /* Do the sfp_timer outside of interrupt context due to the + * delays that sfp+ detection requires + */ + schedule_work(&adapter->sfp_task); +} + +/** + * ixgbe_sfp_task - worker thread to find a missing module + * @work: pointer to work_struct containing our data + **/ +static void ixgbe_sfp_task(struct work_struct *work) +{ + struct ixgbe_adapter *adapter = container_of(work, + struct ixgbe_adapter, + sfp_task); + struct ixgbe_hw *hw = &adapter->hw; + + if ((hw->phy.type == ixgbe_phy_nl) && + (hw->phy.sfp_type == ixgbe_sfp_type_not_present)) { + s32 ret = hw->phy.ops.identify_sfp(hw); + if (ret) + goto reschedule; + ret = hw->phy.ops.reset(hw); + if (ret == IXGBE_ERR_SFP_NOT_SUPPORTED) { + DPRINTK(PROBE, ERR, "failed to initialize because an " + "unsupported SFP+ module type was detected.\n" + "Reload the driver after installing a " + "supported module.\n"); + unregister_netdev(adapter->netdev); + } else { + DPRINTK(PROBE, INFO, "detected SFP+: %d\n", + hw->phy.sfp_type); + } + /* don't need this routine any more */ + clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); + } + return; +reschedule: + if (test_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state)) + mod_timer(&adapter->sfp_timer, + round_jiffies(jiffies + (2 * HZ))); +} + /** * ixgbe_sw_init - Initialize general software structures (struct ixgbe_adapter) * @adapter: board private structure to initialize @@ -2547,6 +2760,10 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter) struct ixgbe_hw *hw = &adapter->hw; struct pci_dev *pdev = adapter->pdev; unsigned int rss; +#ifdef CONFIG_IXGBE_DCB + int j; + struct tc_configuration *tc; +#endif /* PCI config space info */ @@ -2560,6 +2777,30 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter) rss = min(IXGBE_MAX_RSS_INDICES, (int)num_online_cpus()); adapter->ring_feature[RING_F_RSS].indices = rss; adapter->flags |= IXGBE_FLAG_RSS_ENABLED; + adapter->ring_feature[RING_F_DCB].indices = IXGBE_MAX_DCB_INDICES; + +#ifdef CONFIG_IXGBE_DCB + /* Configure DCB traffic classes */ + for (j = 0; j < MAX_TRAFFIC_CLASS; j++) { + tc = &adapter->dcb_cfg.tc_config[j]; + tc->path[DCB_TX_CONFIG].bwg_id = 0; + tc->path[DCB_TX_CONFIG].bwg_percent = 12 + (j & 1); + tc->path[DCB_RX_CONFIG].bwg_id = 0; + tc->path[DCB_RX_CONFIG].bwg_percent = 12 + (j & 1); + tc->dcb_pfc = pfc_disabled; + } + adapter->dcb_cfg.bw_percentage[DCB_TX_CONFIG][0] = 100; + adapter->dcb_cfg.bw_percentage[DCB_RX_CONFIG][0] = 100; + adapter->dcb_cfg.rx_pba_cfg = pba_equal; + adapter->dcb_cfg.round_robin_enable = false; + adapter->dcb_set_bitmap = 0x00; + ixgbe_copy_dcb_cfg(&adapter->dcb_cfg, &adapter->temp_dcb_cfg, + adapter->ring_feature[RING_F_DCB].indices); + +#endif + if (hw->mac.ops.get_media_type && + (hw->mac.ops.get_media_type(hw) == ixgbe_media_type_copper)) + adapter->flags |= IXGBE_FLAG_FAN_FAIL_CAPABLE; /* default flow control settings */ hw->fc.original_type = ixgbe_fc_none; @@ -2934,11 +3175,16 @@ static int ixgbe_close(struct net_device *netdev) * @adapter: private struct * helper function to napi_add each possible q_vector->napi */ -static void ixgbe_napi_add_all(struct ixgbe_adapter *adapter) +void ixgbe_napi_add_all(struct ixgbe_adapter *adapter) { int q_idx, q_vectors; + struct net_device *netdev = adapter->netdev; int (*poll)(struct napi_struct *, int); + /* check if we already have our netdev->napi_list populated */ + if (&netdev->napi_list != netdev->napi_list.next) + return; + if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { poll = &ixgbe_clean_rxonly; /* Only enable as many vectors as we have rx queues. */ @@ -2955,7 +3201,7 @@ static void ixgbe_napi_add_all(struct ixgbe_adapter *adapter) } } -static void ixgbe_napi_del_all(struct ixgbe_adapter *adapter) +void ixgbe_napi_del_all(struct ixgbe_adapter *adapter) { int q_idx; int q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; @@ -3032,6 +3278,7 @@ static int ixgbe_suspend(struct pci_dev *pdev, pm_message_t state) } ixgbe_reset_interrupt_capability(adapter); ixgbe_napi_del_all(adapter); + INIT_LIST_HEAD(&netdev->napi_list); kfree(adapter->tx_ring); kfree(adapter->rx_ring); @@ -3076,6 +3323,18 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter) adapter->stats.mpc[i] += mpc; total_mpc += adapter->stats.mpc[i]; adapter->stats.rnbc[i] += IXGBE_READ_REG(hw, IXGBE_RNBC(i)); + adapter->stats.qptc[i] += IXGBE_READ_REG(hw, IXGBE_QPTC(i)); + adapter->stats.qbtc[i] += IXGBE_READ_REG(hw, IXGBE_QBTC(i)); + adapter->stats.qprc[i] += IXGBE_READ_REG(hw, IXGBE_QPRC(i)); + adapter->stats.qbrc[i] += IXGBE_READ_REG(hw, IXGBE_QBRC(i)); + adapter->stats.pxonrxc[i] += IXGBE_READ_REG(hw, + IXGBE_PXONRXC(i)); + adapter->stats.pxontxc[i] += IXGBE_READ_REG(hw, + IXGBE_PXONTXC(i)); + adapter->stats.pxoffrxc[i] += IXGBE_READ_REG(hw, + IXGBE_PXOFFRXC(i)); + adapter->stats.pxofftxc[i] += IXGBE_READ_REG(hw, + IXGBE_PXOFFTXC(i)); } adapter->stats.gprc += IXGBE_READ_REG(hw, IXGBE_GPRC); /* work around hardware counting issue */ @@ -3204,15 +3463,16 @@ static void ixgbe_watchdog_task(struct work_struct *work) u32 rmcs = IXGBE_READ_REG(hw, IXGBE_RMCS); #define FLOW_RX (frctl & IXGBE_FCTRL_RFCE) #define FLOW_TX (rmcs & IXGBE_RMCS_TFCE_802_3X) - DPRINTK(LINK, INFO, "NIC Link is Up %s, " - "Flow Control: %s\n", - (link_speed == IXGBE_LINK_SPEED_10GB_FULL ? - "10 Gbps" : - (link_speed == IXGBE_LINK_SPEED_1GB_FULL ? - "1 Gbps" : "unknown speed")), - ((FLOW_RX && FLOW_TX) ? "RX/TX" : - (FLOW_RX ? "RX" : - (FLOW_TX ? "TX" : "None")))); + printk(KERN_INFO "ixgbe: %s NIC Link is Up %s, " + "Flow Control: %s\n", + netdev->name, + (link_speed == IXGBE_LINK_SPEED_10GB_FULL ? + "10 Gbps" : + (link_speed == IXGBE_LINK_SPEED_1GB_FULL ? + "1 Gbps" : "unknown speed")), + ((FLOW_RX && FLOW_TX) ? "RX/TX" : + (FLOW_RX ? "RX" : + (FLOW_TX ? "TX" : "None")))); netif_carrier_on(netdev); netif_tx_wake_all_queues(netdev); @@ -3224,7 +3484,8 @@ static void ixgbe_watchdog_task(struct work_struct *work) adapter->link_up = false; adapter->link_speed = 0; if (netif_carrier_ok(netdev)) { - DPRINTK(LINK, INFO, "NIC Link is Down\n"); + printk(KERN_INFO "ixgbe: %s NIC Link is Down\n", + netdev->name); netif_carrier_off(netdev); netif_tx_stop_all_queues(netdev); } @@ -3573,6 +3834,14 @@ static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if (adapter->vlgrp && vlan_tx_tag_present(skb)) { tx_flags |= vlan_tx_tag_get(skb); + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { + tx_flags &= ~IXGBE_TX_FLAGS_VLAN_PRIO_MASK; + tx_flags |= (skb->queue_mapping << 13); + } + tx_flags <<= IXGBE_TX_FLAGS_VLAN_SHIFT; + tx_flags |= IXGBE_TX_FLAGS_VLAN; + } else if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { + tx_flags |= (skb->queue_mapping << 13); tx_flags <<= IXGBE_TX_FLAGS_VLAN_SHIFT; tx_flags |= IXGBE_TX_FLAGS_VLAN; } @@ -3687,9 +3956,31 @@ static int ixgbe_link_config(struct ixgbe_hw *hw) /* must always autoneg for both 1G and 10G link */ hw->mac.autoneg = true; + if ((hw->mac.type == ixgbe_mac_82598EB) && + (hw->phy.media_type == ixgbe_media_type_copper)) + autoneg = IXGBE_LINK_SPEED_82598_AUTONEG; + return hw->mac.ops.setup_link_speed(hw, autoneg, true, true); } +static const struct net_device_ops ixgbe_netdev_ops = { + .ndo_open = ixgbe_open, + .ndo_stop = ixgbe_close, + .ndo_start_xmit = ixgbe_xmit_frame, + .ndo_get_stats = ixgbe_get_stats, + .ndo_set_multicast_list = ixgbe_set_rx_mode, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = ixgbe_set_mac, + .ndo_change_mtu = ixgbe_change_mtu, + .ndo_tx_timeout = ixgbe_tx_timeout, + .ndo_vlan_rx_register = ixgbe_vlan_rx_register, + .ndo_vlan_rx_add_vid = ixgbe_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = ixgbe_vlan_rx_kill_vid, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = ixgbe_netpoll, +#endif +}; + /** * ixgbe_probe - Device Initialization Routine * @pdev: PCI device information struct @@ -3739,6 +4030,13 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, goto err_pci_reg; } + err = pci_enable_pcie_error_reporting(pdev); + if (err) { + dev_err(&pdev->dev, "pci_enable_pcie_error_reporting failed " + "0x%x\n", err); + /* non-fatal, continue */ + } + pci_set_master(pdev); pci_save_state(pdev); @@ -3771,23 +4069,9 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, continue; } - netdev->open = &ixgbe_open; - netdev->stop = &ixgbe_close; - netdev->hard_start_xmit = &ixgbe_xmit_frame; - netdev->get_stats = &ixgbe_get_stats; - netdev->set_rx_mode = &ixgbe_set_rx_mode; - netdev->set_multicast_list = &ixgbe_set_rx_mode; - netdev->set_mac_address = &ixgbe_set_mac; - netdev->change_mtu = &ixgbe_change_mtu; + netdev->netdev_ops = &ixgbe_netdev_ops; ixgbe_set_ethtool_ops(netdev); - netdev->tx_timeout = &ixgbe_tx_timeout; netdev->watchdog_timeo = 5 * HZ; - netdev->vlan_rx_register = ixgbe_vlan_rx_register; - netdev->vlan_rx_add_vid = ixgbe_vlan_rx_add_vid; - netdev->vlan_rx_kill_vid = ixgbe_vlan_rx_kill_vid; -#ifdef CONFIG_NET_POLL_CONTROLLER - netdev->poll_controller = ixgbe_netpoll; -#endif strcpy(netdev->name, pci_name(pdev)); adapter->bd_number = cards_found; @@ -3805,11 +4089,31 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, /* PHY */ memcpy(&hw->phy.ops, ii->phy_ops, sizeof(hw->phy.ops)); - /* phy->sfp_type = ixgbe_sfp_type_unknown; */ + hw->phy.sfp_type = ixgbe_sfp_type_unknown; + + /* set up this timer and work struct before calling get_invariants + * which might start the timer + */ + init_timer(&adapter->sfp_timer); + adapter->sfp_timer.function = &ixgbe_sfp_timer; + adapter->sfp_timer.data = (unsigned long) adapter; + + INIT_WORK(&adapter->sfp_task, ixgbe_sfp_task); err = ii->get_invariants(hw); - if (err) + if (err == IXGBE_ERR_SFP_NOT_PRESENT) { + /* start a kernel thread to watch for a module to arrive */ + set_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); + mod_timer(&adapter->sfp_timer, + round_jiffies(jiffies + (2 * HZ))); + err = 0; + } else if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { + DPRINTK(PROBE, ERR, "failed to load because an " + "unsupported SFP+ module type was detected.\n"); goto err_hw_init; + } else if (err) { + goto err_hw_init; + } /* setup the private structure */ err = ixgbe_sw_init(adapter); @@ -3839,6 +4143,13 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, netdev->vlan_features |= NETIF_F_IP_CSUM; netdev->vlan_features |= NETIF_F_SG; + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) + adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED; + +#ifdef CONFIG_IXGBE_DCB + netdev->dcbnl_ops = &dcbnl_ops; +#endif + if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; @@ -3873,8 +4184,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, pci_read_config_word(pdev, IXGBE_PCI_LINK_STATUS, &link_status); link_speed = link_status & IXGBE_PCI_LINK_SPEED; link_width = link_status & IXGBE_PCI_LINK_WIDTH; - dev_info(&pdev->dev, "(PCI Express:%s:%s) " - "%02x:%02x:%02x:%02x:%02x:%02x\n", + dev_info(&pdev->dev, "(PCI Express:%s:%s) %pM\n", ((link_speed == IXGBE_PCI_LINK_SPEED_5000) ? "5.0Gb/s" : (link_speed == IXGBE_PCI_LINK_SPEED_2500) ? "2.5Gb/s" : "Unknown"), @@ -3883,8 +4193,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, (link_width == IXGBE_PCI_LINK_WIDTH_2) ? "Width x2" : (link_width == IXGBE_PCI_LINK_WIDTH_1) ? "Width x1" : "Unknown"), - netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2], - netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]); + netdev->dev_addr); ixgbe_read_pba_num_generic(hw, &part_num); dev_info(&pdev->dev, "MAC: %d, PHY: %d, PBA No: %06x-%03x\n", hw->mac.type, hw->phy.type, @@ -3911,8 +4220,6 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, netif_carrier_off(netdev); netif_tx_stop_all_queues(netdev); - ixgbe_napi_add_all(adapter); - strcpy(netdev->name, "eth%d"); err = register_netdev(netdev); if (err) @@ -3938,6 +4245,9 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, err_sw_init: ixgbe_reset_interrupt_capability(adapter); err_eeprom: + clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); + del_timer_sync(&adapter->sfp_timer); + cancel_work_sync(&adapter->sfp_task); iounmap(hw->hw_addr); err_ioremap: free_netdev(netdev); @@ -3962,10 +4272,18 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); struct ixgbe_adapter *adapter = netdev_priv(netdev); + int err; set_bit(__IXGBE_DOWN, &adapter->state); + /* clear the module not found bit to make sure the worker won't + * reschedule + */ + clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); del_timer_sync(&adapter->watchdog_timer); + del_timer_sync(&adapter->sfp_timer); + cancel_work_sync(&adapter->watchdog_task); + cancel_work_sync(&adapter->sfp_task); flush_scheduled_work(); #ifdef CONFIG_IXGBE_DCA @@ -3976,7 +4294,8 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev) } #endif - unregister_netdev(netdev); + if (netdev->reg_state == NETREG_REGISTERED) + unregister_netdev(netdev); ixgbe_reset_interrupt_capability(adapter); @@ -3986,12 +4305,16 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev) pci_release_regions(pdev); DPRINTK(PROBE, INFO, "complete\n"); - ixgbe_napi_del_all(adapter); kfree(adapter->tx_ring); kfree(adapter->rx_ring); free_netdev(netdev); + err = pci_disable_pcie_error_reporting(pdev); + if (err) + dev_err(&pdev->dev, + "pci_disable_pcie_error_reporting failed 0x%x\n", err); + pci_disable_device(pdev); } @@ -4007,7 +4330,7 @@ static pci_ers_result_t ixgbe_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state) { struct net_device *netdev = pci_get_drvdata(pdev); - struct ixgbe_adapter *adapter = netdev->priv; + struct ixgbe_adapter *adapter = netdev_priv(netdev); netif_device_detach(netdev); @@ -4028,22 +4351,34 @@ static pci_ers_result_t ixgbe_io_error_detected(struct pci_dev *pdev, static pci_ers_result_t ixgbe_io_slot_reset(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); - struct ixgbe_adapter *adapter = netdev->priv; + struct ixgbe_adapter *adapter = netdev_priv(netdev); + pci_ers_result_t result; + int err; if (pci_enable_device(pdev)) { DPRINTK(PROBE, ERR, "Cannot re-enable PCI device after reset.\n"); - return PCI_ERS_RESULT_DISCONNECT; - } - pci_set_master(pdev); - pci_restore_state(pdev); + result = PCI_ERS_RESULT_DISCONNECT; + } else { + pci_set_master(pdev); + pci_restore_state(pdev); - pci_enable_wake(pdev, PCI_D3hot, 0); - pci_enable_wake(pdev, PCI_D3cold, 0); + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); - ixgbe_reset(adapter); + ixgbe_reset(adapter); + + result = PCI_ERS_RESULT_RECOVERED; + } - return PCI_ERS_RESULT_RECOVERED; + err = pci_cleanup_aer_uncorrect_error_status(pdev); + if (err) { + dev_err(&pdev->dev, + "pci_cleanup_aer_uncorrect_error_status failed 0x%0x\n", err); + /* non-fatal, continue */ + } + + return result; } /** @@ -4056,7 +4391,7 @@ static pci_ers_result_t ixgbe_io_slot_reset(struct pci_dev *pdev) static void ixgbe_io_resume(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); - struct ixgbe_adapter *adapter = netdev->priv; + struct ixgbe_adapter *adapter = netdev_priv(netdev); if (netif_running(netdev)) { if (ixgbe_up(adapter)) { diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c index 764035a8c9a16b0d0ea99864899747ca2cb8c233..5a8669aedf6417a244b0b4908f91e1913b530a11 100644 --- a/drivers/net/ixgbe/ixgbe_phy.c +++ b/drivers/net/ixgbe/ixgbe_phy.c @@ -121,9 +121,15 @@ static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id) enum ixgbe_phy_type phy_type; switch (phy_id) { + case TN1010_PHY_ID: + phy_type = ixgbe_phy_tn; + break; case QT2022_PHY_ID: phy_type = ixgbe_phy_qt; break; + case ATH_PHY_ID: + phy_type = ixgbe_phy_nl; + break; default: phy_type = ixgbe_phy_unknown; break; @@ -426,3 +432,323 @@ s32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw, return 0; } +/** + * ixgbe_reset_phy_nl - Performs a PHY reset + * @hw: pointer to hardware structure + **/ +s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw) +{ + u16 phy_offset, control, eword, edata, block_crc; + bool end_data = false; + u16 list_offset, data_offset; + u16 phy_data = 0; + s32 ret_val = 0; + u32 i; + + hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, + IXGBE_MDIO_PHY_XS_DEV_TYPE, &phy_data); + + /* reset the PHY and poll for completion */ + hw->phy.ops.write_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, + IXGBE_MDIO_PHY_XS_DEV_TYPE, + (phy_data | IXGBE_MDIO_PHY_XS_RESET)); + + for (i = 0; i < 100; i++) { + hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, + IXGBE_MDIO_PHY_XS_DEV_TYPE, &phy_data); + if ((phy_data & IXGBE_MDIO_PHY_XS_RESET) == 0) + break; + msleep(10); + } + + if ((phy_data & IXGBE_MDIO_PHY_XS_RESET) != 0) { + hw_dbg(hw, "PHY reset did not complete.\n"); + ret_val = IXGBE_ERR_PHY; + goto out; + } + + /* Get init offsets */ + ret_val = ixgbe_get_sfp_init_sequence_offsets(hw, &list_offset, + &data_offset); + if (ret_val != 0) + goto out; + + ret_val = hw->eeprom.ops.read(hw, data_offset, &block_crc); + data_offset++; + while (!end_data) { + /* + * Read control word from PHY init contents offset + */ + ret_val = hw->eeprom.ops.read(hw, data_offset, &eword); + control = (eword & IXGBE_CONTROL_MASK_NL) >> + IXGBE_CONTROL_SHIFT_NL; + edata = eword & IXGBE_DATA_MASK_NL; + switch (control) { + case IXGBE_DELAY_NL: + data_offset++; + hw_dbg(hw, "DELAY: %d MS\n", edata); + msleep(edata); + break; + case IXGBE_DATA_NL: + hw_dbg(hw, "DATA: \n"); + data_offset++; + hw->eeprom.ops.read(hw, data_offset++, + &phy_offset); + for (i = 0; i < edata; i++) { + hw->eeprom.ops.read(hw, data_offset, &eword); + hw->phy.ops.write_reg(hw, phy_offset, + IXGBE_TWINAX_DEV, eword); + hw_dbg(hw, "Wrote %4.4x to %4.4x\n", eword, + phy_offset); + data_offset++; + phy_offset++; + } + break; + case IXGBE_CONTROL_NL: + data_offset++; + hw_dbg(hw, "CONTROL: \n"); + if (edata == IXGBE_CONTROL_EOL_NL) { + hw_dbg(hw, "EOL\n"); + end_data = true; + } else if (edata == IXGBE_CONTROL_SOL_NL) { + hw_dbg(hw, "SOL\n"); + } else { + hw_dbg(hw, "Bad control value\n"); + ret_val = IXGBE_ERR_PHY; + goto out; + } + break; + default: + hw_dbg(hw, "Bad control type\n"); + ret_val = IXGBE_ERR_PHY; + goto out; + } + } + +out: + return ret_val; +} + +/** + * ixgbe_identify_sfp_module_generic - Identifies SFP module and assigns + * the PHY type. + * @hw: pointer to hardware structure + * + * Searches for and indentifies the SFP module. Assings appropriate PHY type. + **/ +s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) +{ + s32 status = IXGBE_ERR_PHY_ADDR_INVALID; + u32 vendor_oui = 0; + u8 identifier = 0; + u8 comp_codes_1g = 0; + u8 comp_codes_10g = 0; + u8 oui_bytes[4] = {0, 0, 0, 0}; + u8 transmission_media = 0; + + status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_IDENTIFIER, + &identifier); + + if (status == IXGBE_ERR_SFP_NOT_PRESENT) { + hw->phy.sfp_type = ixgbe_sfp_type_not_present; + goto out; + } + + if (identifier == IXGBE_SFF_IDENTIFIER_SFP) { + hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_1GBE_COMP_CODES, + &comp_codes_1g); + hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_10GBE_COMP_CODES, + &comp_codes_10g); + hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_TRANSMISSION_MEDIA, + &transmission_media); + + /* ID Module + * ========= + * 0 SFP_DA_CU + * 1 SFP_SR + * 2 SFP_LR + */ + if (transmission_media & IXGBE_SFF_TWIN_AX_CAPABLE) + hw->phy.sfp_type = ixgbe_sfp_type_da_cu; + else if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE) + hw->phy.sfp_type = ixgbe_sfp_type_sr; + else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE) + hw->phy.sfp_type = ixgbe_sfp_type_lr; + else + hw->phy.sfp_type = ixgbe_sfp_type_unknown; + + /* Determine PHY vendor */ + if (hw->phy.type == ixgbe_phy_unknown) { + hw->phy.id = identifier; + hw->phy.ops.read_i2c_eeprom(hw, + IXGBE_SFF_VENDOR_OUI_BYTE0, + &oui_bytes[0]); + hw->phy.ops.read_i2c_eeprom(hw, + IXGBE_SFF_VENDOR_OUI_BYTE1, + &oui_bytes[1]); + hw->phy.ops.read_i2c_eeprom(hw, + IXGBE_SFF_VENDOR_OUI_BYTE2, + &oui_bytes[2]); + + vendor_oui = + ((oui_bytes[0] << IXGBE_SFF_VENDOR_OUI_BYTE0_SHIFT) | + (oui_bytes[1] << IXGBE_SFF_VENDOR_OUI_BYTE1_SHIFT) | + (oui_bytes[2] << IXGBE_SFF_VENDOR_OUI_BYTE2_SHIFT)); + + switch (vendor_oui) { + case IXGBE_SFF_VENDOR_OUI_TYCO: + if (transmission_media & + IXGBE_SFF_TWIN_AX_CAPABLE) + hw->phy.type = ixgbe_phy_tw_tyco; + break; + case IXGBE_SFF_VENDOR_OUI_FTL: + hw->phy.type = ixgbe_phy_sfp_ftl; + break; + case IXGBE_SFF_VENDOR_OUI_AVAGO: + hw->phy.type = ixgbe_phy_sfp_avago; + break; + default: + if (transmission_media & + IXGBE_SFF_TWIN_AX_CAPABLE) + hw->phy.type = ixgbe_phy_tw_unknown; + else + hw->phy.type = ixgbe_phy_sfp_unknown; + break; + } + } + status = 0; + } + +out: + return status; +} + +/** + * ixgbe_get_sfp_init_sequence_offsets - Checks the MAC's EEPROM to see + * if it supports a given SFP+ module type, if so it returns the offsets to the + * phy init sequence block. + * @hw: pointer to hardware structure + * @list_offset: offset to the SFP ID list + * @data_offset: offset to the SFP data block + **/ +s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw, + u16 *list_offset, + u16 *data_offset) +{ + u16 sfp_id; + + if (hw->phy.sfp_type == ixgbe_sfp_type_unknown) + return IXGBE_ERR_SFP_NOT_SUPPORTED; + + if (hw->phy.sfp_type == ixgbe_sfp_type_not_present) + return IXGBE_ERR_SFP_NOT_PRESENT; + + if ((hw->device_id == IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM) && + (hw->phy.sfp_type == ixgbe_sfp_type_da_cu)) + return IXGBE_ERR_SFP_NOT_SUPPORTED; + + /* Read offset to PHY init contents */ + hw->eeprom.ops.read(hw, IXGBE_PHY_INIT_OFFSET_NL, list_offset); + + if ((!*list_offset) || (*list_offset == 0xFFFF)) + return IXGBE_ERR_PHY; + + /* Shift offset to first ID word */ + (*list_offset)++; + + /* + * Find the matching SFP ID in the EEPROM + * and program the init sequence + */ + hw->eeprom.ops.read(hw, *list_offset, &sfp_id); + + while (sfp_id != IXGBE_PHY_INIT_END_NL) { + if (sfp_id == hw->phy.sfp_type) { + (*list_offset)++; + hw->eeprom.ops.read(hw, *list_offset, data_offset); + if ((!*data_offset) || (*data_offset == 0xFFFF)) { + hw_dbg(hw, "SFP+ module not supported\n"); + return IXGBE_ERR_SFP_NOT_SUPPORTED; + } else { + break; + } + } else { + (*list_offset) += 2; + if (hw->eeprom.ops.read(hw, *list_offset, &sfp_id)) + return IXGBE_ERR_PHY; + } + } + + if (sfp_id == IXGBE_PHY_INIT_END_NL) { + hw_dbg(hw, "No matching SFP+ module found\n"); + return IXGBE_ERR_SFP_NOT_SUPPORTED; + } + + return 0; +} + +/** + * ixgbe_check_phy_link_tnx - Determine link and speed status + * @hw: pointer to hardware structure + * + * Reads the VS1 register to determine if link is up and the current speed for + * the PHY. + **/ +s32 ixgbe_check_phy_link_tnx(struct ixgbe_hw *hw, ixgbe_link_speed *speed, + bool *link_up) +{ + s32 status = 0; + u32 time_out; + u32 max_time_out = 10; + u16 phy_link = 0; + u16 phy_speed = 0; + u16 phy_data = 0; + + /* Initialize speed and link to default case */ + *link_up = false; + *speed = IXGBE_LINK_SPEED_10GB_FULL; + + /* + * Check current speed and link status of the PHY register. + * This is a vendor specific register and may have to + * be changed for other copper PHYs. + */ + for (time_out = 0; time_out < max_time_out; time_out++) { + udelay(10); + status = hw->phy.ops.read_reg(hw, + IXGBE_MDIO_VENDOR_SPECIFIC_1_STATUS, + IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, + &phy_data); + phy_link = phy_data & + IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS; + phy_speed = phy_data & + IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS; + if (phy_link == IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS) { + *link_up = true; + if (phy_speed == + IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS) + *speed = IXGBE_LINK_SPEED_1GB_FULL; + break; + } + } + + return status; +} + +/** + * ixgbe_get_phy_firmware_version_tnx - Gets the PHY Firmware Version + * @hw: pointer to hardware structure + * @firmware_version: pointer to the PHY Firmware Version + **/ +s32 ixgbe_get_phy_firmware_version_tnx(struct ixgbe_hw *hw, + u16 *firmware_version) +{ + s32 status = 0; + + status = hw->phy.ops.read_reg(hw, TNX_FW_REV, + IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, + firmware_version); + + return status; +} + diff --git a/drivers/net/ixgbe/ixgbe_phy.h b/drivers/net/ixgbe/ixgbe_phy.h index 9bfe3f2b1d8f499f743890a846790150b9c5757a..43a97bc420f54c0dbda983bdcbb214aad955f94b 100644 --- a/drivers/net/ixgbe/ixgbe_phy.h +++ b/drivers/net/ixgbe/ixgbe_phy.h @@ -63,6 +63,18 @@ #define IXGBE_SFF_VENDOR_OUI_FTL 0x00906500 #define IXGBE_SFF_VENDOR_OUI_AVAGO 0x00176A00 +/* I2C SDA and SCL timing parameters for standard mode */ +#define IXGBE_I2C_T_HD_STA 4 +#define IXGBE_I2C_T_LOW 5 +#define IXGBE_I2C_T_HIGH 4 +#define IXGBE_I2C_T_SU_STA 5 +#define IXGBE_I2C_T_HD_DATA 5 +#define IXGBE_I2C_T_SU_DATA 1 +#define IXGBE_I2C_T_RISE 1 +#define IXGBE_I2C_T_FALL 1 +#define IXGBE_I2C_T_SU_STO 4 +#define IXGBE_I2C_T_BUF 5 + s32 ixgbe_init_phy_ops_generic(struct ixgbe_hw *hw); s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw); @@ -77,4 +89,17 @@ s32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw, bool autoneg, bool autoneg_wait_to_complete); +/* PHY specific */ +s32 ixgbe_check_phy_link_tnx(struct ixgbe_hw *hw, + ixgbe_link_speed *speed, + bool *link_up); +s32 ixgbe_get_phy_firmware_version_tnx(struct ixgbe_hw *hw, + u16 *firmware_version); + +s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw); +s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw); +s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw, + u16 *list_offset, + u16 *data_offset); + #endif /* _IXGBE_PHY_H_ */ diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index c6f8fa1c4e597909065c6189958af703ccfb26b3..83a11ff9ffd190f8aa2ec0db65c63f39d9349aba 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -36,8 +36,12 @@ /* Device IDs */ #define IXGBE_DEV_ID_82598AF_DUAL_PORT 0x10C6 #define IXGBE_DEV_ID_82598AF_SINGLE_PORT 0x10C7 +#define IXGBE_DEV_ID_82598EB_SFP_LOM 0x10DB +#define IXGBE_DEV_ID_82598AT 0x10C8 #define IXGBE_DEV_ID_82598EB_CX4 0x10DD #define IXGBE_DEV_ID_82598_CX4_DUAL_PORT 0x10EC +#define IXGBE_DEV_ID_82598_DA_DUAL_PORT 0x10F1 +#define IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM 0x10E1 #define IXGBE_DEV_ID_82598EB_XF_LR 0x10F4 /* General Registers */ @@ -452,6 +456,7 @@ #define IXGBE_MDIO_PHY_XS_DEV_TYPE 0x4 #define IXGBE_MDIO_AUTO_NEG_DEV_TYPE 0x7 #define IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE 0x1E /* Device 30 */ +#define IXGBE_TWINAX_DEV 1 #define IXGBE_MDIO_COMMAND_TIMEOUT 100 /* PHY Timeout for 1 GB mode */ @@ -487,12 +492,27 @@ #define IXGBE_PHY_REVISION_MASK 0xFFFFFFF0 #define IXGBE_MAX_PHY_ADDR 32 -/* PHY IDs*/ +/* PHY IDs */ +#define TN1010_PHY_ID 0x00A19410 +#define TNX_FW_REV 0xB #define QT2022_PHY_ID 0x0043A400 +#define ATH_PHY_ID 0x03429050 /* PHY Types */ #define IXGBE_M88E1145_E_PHY_ID 0x01410CD0 +/* Special PHY Init Routine */ +#define IXGBE_PHY_INIT_OFFSET_NL 0x002B +#define IXGBE_PHY_INIT_END_NL 0xFFFF +#define IXGBE_CONTROL_MASK_NL 0xF000 +#define IXGBE_DATA_MASK_NL 0x0FFF +#define IXGBE_CONTROL_SHIFT_NL 12 +#define IXGBE_DELAY_NL 0 +#define IXGBE_DATA_NL 1 +#define IXGBE_CONTROL_NL 0x000F +#define IXGBE_CONTROL_EOL_NL 0x0FFF +#define IXGBE_CONTROL_SOL_NL 0x0000 + /* General purpose Interrupt Enable */ #define IXGBE_SDP0_GPIEN 0x00000001 /* SDP0 */ #define IXGBE_SDP1_GPIEN 0x00000002 /* SDP1 */ @@ -1202,8 +1222,10 @@ enum ixgbe_mac_type { enum ixgbe_phy_type { ixgbe_phy_unknown = 0, + ixgbe_phy_tn, ixgbe_phy_qt, ixgbe_phy_xaui, + ixgbe_phy_nl, ixgbe_phy_tw_tyco, ixgbe_phy_tw_unknown, ixgbe_phy_sfp_avago, @@ -1225,6 +1247,7 @@ enum ixgbe_sfp_type { ixgbe_sfp_type_da_cu = 0, ixgbe_sfp_type_sr = 1, ixgbe_sfp_type_lr = 2, + ixgbe_sfp_type_not_present = 0xFFFE, ixgbe_sfp_type_unknown = 0xFFFF }; @@ -1396,6 +1419,8 @@ struct ixgbe_phy_operations { s32 (*setup_link)(struct ixgbe_hw *); s32 (*setup_link_speed)(struct ixgbe_hw *, ixgbe_link_speed, bool, bool); + s32 (*check_link)(struct ixgbe_hw *, ixgbe_link_speed *, bool *); + s32 (*get_firmware_version)(struct ixgbe_hw *, u16 *); s32 (*read_i2c_byte)(struct ixgbe_hw *, u8, u8, u8 *); s32 (*write_i2c_byte)(struct ixgbe_hw *, u8, u8, u8); s32 (*read_i2c_eeprom)(struct ixgbe_hw *, u8 , u8 *); @@ -1486,6 +1511,7 @@ struct ixgbe_info { #define IXGBE_ERR_PHY_ADDR_INVALID -17 #define IXGBE_ERR_I2C -18 #define IXGBE_ERR_SFP_NOT_SUPPORTED -19 +#define IXGBE_ERR_SFP_NOT_PRESENT -20 #define IXGBE_NOT_IMPLEMENTED 0x7FFFFFFF #endif /* _IXGBE_TYPE_H_ */ diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ixp2000/ixpdev.c index 7b70c66504a04fde3f177d92b085034486294349..014745720560df448b6654c0f051093505838e46 100644 --- a/drivers/net/ixp2000/ixpdev.c +++ b/drivers/net/ixp2000/ixpdev.c @@ -114,8 +114,6 @@ static int ixpdev_rx(struct net_device *dev, int processed, int budget) skb_put(skb, desc->pkt_length); skb->protocol = eth_type_trans(skb, nds[desc->channel]); - dev->last_rx = jiffies; - netif_receive_skb(skb); } @@ -143,7 +141,7 @@ static int ixpdev_poll(struct napi_struct *napi, int budget) break; } while (ixp2000_reg_read(IXP2000_IRQ_THD_RAW_STATUS_A_0) & 0x00ff); - netif_rx_complete(dev, napi); + netif_rx_complete(napi); ixp2000_reg_write(IXP2000_IRQ_THD_ENABLE_SET_A_0, 0x00ff); return rx; @@ -206,7 +204,7 @@ static irqreturn_t ixpdev_interrupt(int irq, void *dev_id) ixp2000_reg_wrb(IXP2000_IRQ_THD_ENABLE_CLEAR_A_0, 0x00ff); if (likely(napi_schedule_prep(&ip->napi))) { - __netif_rx_schedule(dev, &ip->napi); + __netif_rx_schedule(&ip->napi); } else { printk(KERN_CRIT "ixp2000: irq while polling!!\n"); } diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c index 07944820f74582b5230c4a362acac0b81eccbec6..334ff9e12cdd25c5aa131ce98e10fd485a435189 100644 --- a/drivers/net/jazzsonic.c +++ b/drivers/net/jazzsonic.c @@ -208,7 +208,6 @@ static int __init jazz_sonic_probe(struct platform_device *pdev) struct sonic_local *lp; struct resource *res; int err = 0; - DECLARE_MAC_BUF(mac); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) @@ -233,8 +232,7 @@ static int __init jazz_sonic_probe(struct platform_device *pdev) if (err) goto out1; - printk("%s: MAC %s IRQ %d\n", - dev->name, print_mac(mac, dev->dev_addr), dev->irq); + printk("%s: MAC %pM IRQ %d\n", dev->name, dev->dev_addr, dev->irq); return 0; diff --git a/drivers/net/jme.c b/drivers/net/jme.c index 665e70d620fc3cc6b7337c825a7e41f6d422c4b6..08b34051c646d6e4028bb30847ad793c84aedd00 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -435,15 +435,18 @@ jme_check_link(struct net_device *netdev, int testonly) GHC_DPX); switch (phylink & PHY_LINK_SPEED_MASK) { case PHY_LINK_SPEED_10M: - ghc |= GHC_SPEED_10M; + ghc |= GHC_SPEED_10M | + GHC_TO_CLK_PCIE | GHC_TXMAC_CLK_PCIE; strcat(linkmsg, "10 Mbps, "); break; case PHY_LINK_SPEED_100M: - ghc |= GHC_SPEED_100M; + ghc |= GHC_SPEED_100M | + GHC_TO_CLK_PCIE | GHC_TXMAC_CLK_PCIE; strcat(linkmsg, "100 Mbps, "); break; case PHY_LINK_SPEED_1000M: - ghc |= GHC_SPEED_1000M; + ghc |= GHC_SPEED_1000M | + GHC_TO_CLK_GPHY | GHC_TXMAC_CLK_GPHY; strcat(linkmsg, "1000 Mbps, "); break; default: @@ -463,14 +466,6 @@ jme_check_link(struct net_device *netdev, int testonly) TXTRHD_TXREN | ((8 << TXTRHD_TXRL_SHIFT) & TXTRHD_TXRL)); } - strcat(linkmsg, (phylink & PHY_LINK_DUPLEX) ? - "Full-Duplex, " : - "Half-Duplex, "); - - if (phylink & PHY_LINK_MDI_STAT) - strcat(linkmsg, "MDI-X"); - else - strcat(linkmsg, "MDI"); gpreg1 = GPREG1_DEFAULT; if (is_buggy250(jme->pdev->device, jme->chiprev)) { @@ -492,11 +487,17 @@ jme_check_link(struct net_device *netdev, int testonly) break; } } - jwrite32(jme, JME_GPREG1, gpreg1); - jme->reg_ghc = ghc; + jwrite32(jme, JME_GPREG1, gpreg1); jwrite32(jme, JME_GHC, ghc); + jme->reg_ghc = ghc; + strcat(linkmsg, (phylink & PHY_LINK_DUPLEX) ? + "Full-Duplex, " : + "Half-Duplex, "); + strcat(linkmsg, (phylink & PHY_LINK_MDI_STAT) ? + "MDI-X" : + "MDI"); msg_link(jme, "Link is up at %s.\n", linkmsg); netif_carrier_on(netdev); } else { @@ -931,7 +932,6 @@ jme_alloc_and_feed_skb(struct jme_adapter *jme, int idx) cpu_to_le16(RXWBFLAG_DEST_MUL)) ++(NET_STAT(jme).multicast); - jme->dev->last_rx = jiffies; NET_STAT(jme).rx_bytes += framesize; ++(NET_STAT(jme).rx_packets); } @@ -1250,7 +1250,6 @@ static int jme_poll(JME_NAPI_HOLDER(holder), JME_NAPI_WEIGHT(budget)) { struct jme_adapter *jme = jme_napi_priv(holder); - struct net_device *netdev = jme->dev; int rest; rest = jme_process_receive(jme, JME_NAPI_WEIGHT_VAL(budget)); @@ -2591,14 +2590,6 @@ static const struct ethtool_ops jme_ethtool_ops = { static int jme_pci_dma64(struct pci_dev *pdev) { - if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) - if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) - return 1; - - if (!pci_set_dma_mask(pdev, DMA_40BIT_MASK)) - if (!pci_set_consistent_dma_mask(pdev, DMA_40BIT_MASK)) - return 1; - if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)) if (!pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) return 0; @@ -2626,6 +2617,18 @@ jme_check_hw_ver(struct jme_adapter *jme) jme->chiprev = (chipmode & CM_CHIPREV_MASK) >> CM_CHIPREV_SHIFT; } +static const struct net_device_ops jme_netdev_ops = { + .ndo_open = jme_open, + .ndo_stop = jme_close, + .ndo_validate_addr = eth_validate_addr, + .ndo_start_xmit = jme_start_xmit, + .ndo_set_mac_address = jme_set_macaddr, + .ndo_set_multicast_list = jme_set_multi, + .ndo_change_mtu = jme_change_mtu, + .ndo_tx_timeout = jme_tx_timeout, + .ndo_vlan_rx_register = jme_vlan_rx_register, +}; + static int __devinit jme_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -2675,17 +2678,9 @@ jme_init_one(struct pci_dev *pdev, rc = -ENOMEM; goto err_out_release_regions; } - netdev->open = jme_open; - netdev->stop = jme_close; - netdev->hard_start_xmit = jme_start_xmit; - netdev->set_mac_address = jme_set_macaddr; - netdev->set_multicast_list = jme_set_multi; - netdev->change_mtu = jme_change_mtu; + netdev->netdev_ops = &jme_netdev_ops; netdev->ethtool_ops = &jme_ethtool_ops; - netdev->tx_timeout = jme_tx_timeout; netdev->watchdog_timeo = TX_TIMEOUT; - netdev->vlan_rx_register = jme_vlan_rx_register; - NETDEV_GET_STATS(netdev, &jme_get_stats); netdev->features = NETIF_F_HW_CSUM | NETIF_F_SG | NETIF_F_TSO | @@ -2861,18 +2856,10 @@ jme_init_one(struct pci_dev *pdev, goto err_out_free_shadow; } - msg_probe(jme, - "JMC250 gigabit%s ver:%x rev:%x " - "macaddr:%02x:%02x:%02x:%02x:%02x:%02x\n", + msg_probe(jme, "JMC250 gigabit%s ver:%x rev:%x macaddr:%pM\n", (jme->fpgaver != 0) ? " (FPGA)" : "", (jme->fpgaver != 0) ? jme->fpgaver : jme->chiprev, - jme->rev, - netdev->dev_addr[0], - netdev->dev_addr[1], - netdev->dev_addr[2], - netdev->dev_addr[3], - netdev->dev_addr[4], - netdev->dev_addr[5]); + jme->rev, netdev->dev_addr); return 0; diff --git a/drivers/net/jme.h b/drivers/net/jme.h index 3f5d91543246c88936d8fc086abf37c2cd3f6686..5154411b5e6b0821054cdefef093947bf99a8333 100644 --- a/drivers/net/jme.h +++ b/drivers/net/jme.h @@ -398,15 +398,15 @@ struct jme_ring { #define JME_NAPI_WEIGHT(w) int w #define JME_NAPI_WEIGHT_VAL(w) w #define JME_NAPI_WEIGHT_SET(w, r) -#define JME_RX_COMPLETE(dev, napis) netif_rx_complete(dev, napis) +#define JME_RX_COMPLETE(dev, napis) netif_rx_complete(napis) #define JME_NAPI_ENABLE(priv) napi_enable(&priv->napi); #define JME_NAPI_DISABLE(priv) \ if (!napi_disable_pending(&priv->napi)) \ napi_disable(&priv->napi); #define JME_RX_SCHEDULE_PREP(priv) \ - netif_rx_schedule_prep(priv->dev, &priv->napi) + netif_rx_schedule_prep(&priv->napi) #define JME_RX_SCHEDULE(priv) \ - __netif_rx_schedule(priv->dev, &priv->napi); + __netif_rx_schedule(&priv->napi); /* * Jmac Adapter Private data @@ -815,16 +815,30 @@ static inline u32 smi_phy_addr(int x) * Global Host Control */ enum jme_ghc_bit_mask { - GHC_SWRST = 0x40000000, - GHC_DPX = 0x00000040, - GHC_SPEED = 0x00000030, - GHC_LINK_POLL = 0x00000001, + GHC_SWRST = 0x40000000, + GHC_DPX = 0x00000040, + GHC_SPEED = 0x00000030, + GHC_LINK_POLL = 0x00000001, }; enum jme_ghc_speed_val { - GHC_SPEED_10M = 0x00000010, - GHC_SPEED_100M = 0x00000020, - GHC_SPEED_1000M = 0x00000030, + GHC_SPEED_10M = 0x00000010, + GHC_SPEED_100M = 0x00000020, + GHC_SPEED_1000M = 0x00000030, +}; + +enum jme_ghc_to_clk { + GHC_TO_CLK_OFF = 0x00000000, + GHC_TO_CLK_GPHY = 0x00400000, + GHC_TO_CLK_PCIE = 0x00800000, + GHC_TO_CLK_INVALID = 0x00C00000, +}; + +enum jme_ghc_txmac_clk { + GHC_TXMAC_CLK_OFF = 0x00000000, + GHC_TXMAC_CLK_GPHY = 0x00100000, + GHC_TXMAC_CLK_PCIE = 0x00200000, + GHC_TXMAC_CLK_INVALID = 0x00300000, }; /* diff --git a/drivers/net/korina.c b/drivers/net/korina.c index e18576316bda93050cdd5849da80ef67cd85333a..4a5580c1126a00b383e4588b4ab6a2fa5376845e 100644 --- a/drivers/net/korina.c +++ b/drivers/net/korina.c @@ -327,7 +327,7 @@ static irqreturn_t korina_rx_dma_interrupt(int irq, void *dev_id) dmas = readl(&lp->rx_dma_regs->dmas); if (dmas & (DMA_STAT_DONE | DMA_STAT_HALT | DMA_STAT_ERR)) { - netif_rx_schedule_prep(dev, &lp->napi); + netif_rx_schedule_prep(&lp->napi); dmasm = readl(&lp->rx_dma_regs->dmasm); writel(dmasm | (DMA_STAT_DONE | @@ -409,7 +409,6 @@ static int korina_rx(struct net_device *dev, int limit) /* Pass the packet to upper layers */ netif_receive_skb(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; @@ -467,7 +466,7 @@ static int korina_poll(struct napi_struct *napi, int budget) work_done = korina_rx(dev, budget); if (work_done < budget) { - netif_rx_complete(dev, napi); + netif_rx_complete(napi); writel(readl(&lp->rx_dma_regs->dmasm) & ~(DMA_STAT_DONE | DMA_STAT_HALT | DMA_STAT_ERR), diff --git a/drivers/net/lance.c b/drivers/net/lance.c index 977ed3401bb34cd97d688800ba89340381d39e9e..d7afb938ea626ae3bdf2c3c005dfacab258f2696 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -359,7 +359,7 @@ int __init init_module(void) static void cleanup_card(struct net_device *dev) { - struct lance_private *lp = dev->priv; + struct lance_private *lp = dev->ml_priv; if (dev->dma != 4) free_dma(dev->dma); release_region(dev->base_addr, LANCE_TOTAL_SIZE); @@ -418,7 +418,7 @@ static int __init do_lance_probe(struct net_device *dev) if (card < NUM_CARDS) { /*Signature OK*/ result = lance_probe1(dev, ioaddr, 0, 0); if (!result) { - struct lance_private *lp = dev->priv; + struct lance_private *lp = dev->ml_priv; int ver = lp->chip_version; r->name = chip_table[ver].name; @@ -466,7 +466,6 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int unsigned long flags; int err = -ENOMEM; void __iomem *bios; - DECLARE_MAC_BUF(mac); /* First we look for special cases. Check for HP's on-board ethernet by looking for 'HP' in the BIOS. @@ -520,7 +519,7 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int } } - /* We can't allocate dev->priv from alloc_etherdev() because it must + /* We can't allocate private data from alloc_etherdev() because it must a ISA DMA-able region. */ chipname = chip_table[lance_version].name; printk("%s: %s at %#3x, ", dev->name, chipname, ioaddr); @@ -529,7 +528,7 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int The first six bytes are the station address. */ for (i = 0; i < 6; i++) dev->dev_addr[i] = inb(ioaddr + i); - printk("%s", print_mac(mac, dev->dev_addr)); + printk("%pM", dev->dev_addr); dev->base_addr = ioaddr; /* Make certain the data structures used by the LANCE are aligned and DMAble. */ @@ -538,7 +537,7 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int if(lp==NULL) return -ENODEV; if (lance_debug > 6) printk(" (#0x%05lx)", (unsigned long)lp); - dev->priv = lp; + dev->ml_priv = lp; lp->name = chipname; lp->rx_buffs = (unsigned long)kmalloc(PKT_BUF_SZ*RX_RING_SIZE, GFP_DMA | GFP_KERNEL); @@ -742,7 +741,7 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int static int lance_open(struct net_device *dev) { - struct lance_private *lp = dev->priv; + struct lance_private *lp = dev->ml_priv; int ioaddr = dev->base_addr; int i; @@ -830,7 +829,7 @@ lance_open(struct net_device *dev) static void lance_purge_ring(struct net_device *dev) { - struct lance_private *lp = dev->priv; + struct lance_private *lp = dev->ml_priv; int i; /* Free all the skbuffs in the Rx and Tx queues. */ @@ -854,7 +853,7 @@ lance_purge_ring(struct net_device *dev) static void lance_init_ring(struct net_device *dev, gfp_t gfp) { - struct lance_private *lp = dev->priv; + struct lance_private *lp = dev->ml_priv; int i; lp->cur_rx = lp->cur_tx = 0; @@ -896,7 +895,7 @@ lance_init_ring(struct net_device *dev, gfp_t gfp) static void lance_restart(struct net_device *dev, unsigned int csr0_bits, int must_reinit) { - struct lance_private *lp = dev->priv; + struct lance_private *lp = dev->ml_priv; if (must_reinit || (chip_table[lp->chip_version].flags & LANCE_MUST_REINIT_RING)) { @@ -910,7 +909,7 @@ lance_restart(struct net_device *dev, unsigned int csr0_bits, int must_reinit) static void lance_tx_timeout (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = (struct lance_private *) dev->ml_priv; int ioaddr = dev->base_addr; outw (0, ioaddr + LANCE_ADDR); @@ -944,7 +943,7 @@ static void lance_tx_timeout (struct net_device *dev) static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct lance_private *lp = dev->priv; + struct lance_private *lp = dev->ml_priv; int ioaddr = dev->base_addr; int entry; unsigned long flags; @@ -1021,7 +1020,7 @@ static irqreturn_t lance_interrupt(int irq, void *dev_id) int must_restart; ioaddr = dev->base_addr; - lp = dev->priv; + lp = dev->ml_priv; spin_lock (&lp->devlock); @@ -1134,7 +1133,7 @@ static irqreturn_t lance_interrupt(int irq, void *dev_id) static int lance_rx(struct net_device *dev) { - struct lance_private *lp = dev->priv; + struct lance_private *lp = dev->ml_priv; int entry = lp->cur_rx & RX_RING_MOD_MASK; int i; @@ -1191,7 +1190,6 @@ lance_rx(struct net_device *dev) pkt_len); skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); - dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes+=pkt_len; } @@ -1213,7 +1211,7 @@ static int lance_close(struct net_device *dev) { int ioaddr = dev->base_addr; - struct lance_private *lp = dev->priv; + struct lance_private *lp = dev->ml_priv; netif_stop_queue (dev); @@ -1246,7 +1244,7 @@ lance_close(struct net_device *dev) static struct net_device_stats *lance_get_stats(struct net_device *dev) { - struct lance_private *lp = dev->priv; + struct lance_private *lp = dev->ml_priv; if (chip_table[lp->chip_version].flags & LANCE_HAS_MISSED_FRAME) { short ioaddr = dev->base_addr; diff --git a/drivers/net/lib82596.c b/drivers/net/lib82596.c index b59f442bbf36e38885e6bf35570fe7a5b9138104..7415f517491d73a6bfb7817e7f07c14f842a1923 100644 --- a/drivers/net/lib82596.c +++ b/drivers/net/lib82596.c @@ -739,7 +739,6 @@ static inline int i596_rx(struct net_device *dev) skb->len = pkt_len; skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } @@ -1034,12 +1033,8 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) static void print_eth(unsigned char *add, char *str) { - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); - - printk(KERN_DEBUG "i596 0x%p, %s --> %s %02X%02X, %s\n", - add, print_mac(mac, add + 6), print_mac(mac2, add), - add[12], add[13], str); + printk(KERN_DEBUG "i596 0x%p, %pM --> %pM %02X%02X, %s\n", + add, add + 6, add, add[12], add[13], str); } static int __devinit i82596_probe(struct net_device *dev) @@ -1343,7 +1338,6 @@ static void set_multicast_list(struct net_device *dev) struct i596_private *lp = netdev_priv(dev); struct i596_dma *dma = lp->dma; int config = 0, cnt; - DECLARE_MAC_BUF(mac); DEB(DEB_MULTI, printk(KERN_DEBUG @@ -1407,8 +1401,8 @@ static void set_multicast_list(struct net_device *dev) if (i596_debug > 1) DEB(DEB_MULTI, printk(KERN_DEBUG - "%s: Adding address %s\n", - dev->name, print_mac(mac, cp))); + "%s: Adding address %pM\n", + dev->name, cp)); } DMA_WBACK_INV(dev, &dma->mc_cmd, sizeof(struct mc_cmd)); i596_add_cmd(dev, &cmd->cmd); diff --git a/drivers/net/lib8390.c b/drivers/net/lib8390.c index f80dcc11fe26bad7f594fff1407d0e036fc84935..789b6cb744b284ee08d4c749ab9fa210dc34170e 100644 --- a/drivers/net/lib8390.c +++ b/drivers/net/lib8390.c @@ -108,14 +108,13 @@ int ei_debug = 1; /* Index to functions. */ static void ei_tx_intr(struct net_device *dev); static void ei_tx_err(struct net_device *dev); -static void ei_tx_timeout(struct net_device *dev); +void ei_tx_timeout(struct net_device *dev); static void ei_receive(struct net_device *dev); static void ei_rx_overrun(struct net_device *dev); /* Routines generic to NS8390-based boards. */ static void NS8390_trigger_send(struct net_device *dev, unsigned int length, int start_page); -static void set_multicast_list(struct net_device *dev); static void do_set_multicast_list(struct net_device *dev); static void __NS8390_init(struct net_device *dev, int startp); @@ -206,10 +205,6 @@ static int __ei_open(struct net_device *dev) unsigned long flags; struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); - /* The card I/O part of the driver (e.g. 3c503) can hook a Tx timeout - wrapper that does e.g. media check & then calls ei_tx_timeout. */ - if (dev->tx_timeout == NULL) - dev->tx_timeout = ei_tx_timeout; if (dev->watchdog_timeo <= 0) dev->watchdog_timeo = TX_TIMEOUT; @@ -258,7 +253,7 @@ static int __ei_close(struct net_device *dev) * completed (or failed) - i.e. never posted a Tx related interrupt. */ -static void ei_tx_timeout(struct net_device *dev) +static void __ei_tx_timeout(struct net_device *dev) { unsigned long e8390_base = dev->base_addr; struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); @@ -304,7 +299,7 @@ static void ei_tx_timeout(struct net_device *dev) * Sends a packet to an 8390 network device. */ -static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) +static int __ei_start_xmit(struct sk_buff *skb, struct net_device *dev) { unsigned long e8390_base = dev->base_addr; struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); @@ -764,7 +759,6 @@ static void ei_receive(struct net_device *dev) ei_block_input(dev, pkt_len, skb, current_offset + sizeof(rx_frame)); skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; if (pkt_stat & ENRSR_PHY) @@ -883,7 +877,7 @@ static void ei_rx_overrun(struct net_device *dev) * Collect the stats. This is called unlocked and from several contexts. */ -static struct net_device_stats *get_stats(struct net_device *dev) +static struct net_device_stats *__ei_get_stats(struct net_device *dev) { unsigned long ioaddr = dev->base_addr; struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); @@ -992,7 +986,7 @@ static void do_set_multicast_list(struct net_device *dev) * not called too often. Must protect against both bh and irq users */ -static void set_multicast_list(struct net_device *dev) +static void __ei_set_multicast_list(struct net_device *dev) { unsigned long flags; struct ei_device *ei_local = (struct ei_device*)netdev_priv(dev); @@ -1016,10 +1010,6 @@ static void ethdev_setup(struct net_device *dev) if (ei_debug > 1) printk(version); - dev->hard_start_xmit = &ei_start_xmit; - dev->get_stats = get_stats; - dev->set_multicast_list = &set_multicast_list; - ether_setup(dev); spin_lock_init(&ei_local->page_lock); diff --git a/drivers/net/lne390.c b/drivers/net/lne390.c index b36989097883bc7b800bfd00269dd245b55323ff..41cbaaef06548da3f8357afafea280807dfe24f5 100644 --- a/drivers/net/lne390.c +++ b/drivers/net/lne390.c @@ -53,9 +53,6 @@ static const char *version = static int lne390_probe1(struct net_device *dev, int ioaddr); -static int lne390_open(struct net_device *dev); -static int lne390_close(struct net_device *dev); - static void lne390_reset_8390(struct net_device *dev); static void lne390_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page); @@ -169,7 +166,6 @@ static int __init lne390_probe1(struct net_device *dev, int ioaddr) { int i, revision, ret; unsigned long eisa_id; - DECLARE_MAC_BUF(mac); if (inb_p(ioaddr + LNE390_ID_PORT) == 0xff) return -ENODEV; @@ -203,8 +199,8 @@ static int __init lne390_probe1(struct net_device *dev, int ioaddr) for(i = 0; i < ETHER_ADDR_LEN; i++) dev->dev_addr[i] = inb(ioaddr + LNE390_SA_PROM + i); - printk("lne390.c: LNE390%X in EISA slot %d, address %s.\n", - 0xa+revision, ioaddr/0x1000, print_mac(mac, dev->dev_addr)); + printk("lne390.c: LNE390%X in EISA slot %d, address %pM.\n", + 0xa+revision, ioaddr/0x1000, dev->dev_addr); printk("lne390.c: "); @@ -279,11 +275,7 @@ static int __init lne390_probe1(struct net_device *dev, int ioaddr) ei_status.block_output = &lne390_block_output; ei_status.get_8390_hdr = &lne390_get_8390_hdr; - dev->open = &lne390_open; - dev->stop = &lne390_close; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = ei_poll; -#endif + dev->netdev_ops = &ei_netdev_ops; NS8390_init(dev, 0); ret = register_netdev(dev); @@ -375,21 +367,6 @@ static void lne390_block_output(struct net_device *dev, int count, memcpy_toio(shmem, buf, count); } -static int lne390_open(struct net_device *dev) -{ - ei_open(dev); - return 0; -} - -static int lne390_close(struct net_device *dev) -{ - - if (ei_debug > 1) - printk("%s: Shutting down ethercard.\n", dev->name); - - ei_close(dev); - return 0; -} #ifdef MODULE #define MAX_LNE_CARDS 4 /* Max number of LNE390 cards per module */ diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index b1ac63ab8c16052abd00affc855e4971f0417066..b7d438a367f36c15c495f1ff51ebb5b984cad5dc 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -76,8 +76,6 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) skb->protocol = eth_type_trans(skb,dev); - dev->last_rx = jiffies; - /* it's OK to use per_cpu_ptr() because BHs are off */ pcpu_lstats = dev->ml_priv; lb_stats = per_cpu_ptr(pcpu_lstats, smp_processor_id()); @@ -89,7 +87,7 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) return 0; } -static struct net_device_stats *get_stats(struct net_device *dev) +static struct net_device_stats *loopback_get_stats(struct net_device *dev) { const struct pcpu_lstats *pcpu_lstats; struct net_device_stats *stats = &dev->stats; @@ -145,15 +143,19 @@ static void loopback_dev_free(struct net_device *dev) free_netdev(dev); } +static const struct net_device_ops loopback_ops = { + .ndo_init = loopback_dev_init, + .ndo_start_xmit= loopback_xmit, + .ndo_get_stats = loopback_get_stats, +}; + /* * The loopback device is special. There is only one instance * per network namespace. */ static void loopback_setup(struct net_device *dev) { - dev->get_stats = &get_stats; dev->mtu = (16 * 1024) + 20 + 20 + 12; - dev->hard_start_xmit = loopback_xmit; dev->hard_header_len = ETH_HLEN; /* 14 */ dev->addr_len = ETH_ALEN; /* 6 */ dev->tx_queue_len = 0; @@ -167,8 +169,8 @@ static void loopback_setup(struct net_device *dev) | NETIF_F_NETNS_LOCAL; dev->ethtool_ops = &loopback_ethtool_ops; dev->header_ops = ð_header_ops; - dev->init = loopback_dev_init; - dev->destructor = loopback_dev_free; + dev->netdev_ops = &loopback_ops; + dev->destructor = loopback_dev_free; } /* Setup and register the loopback device. */ @@ -206,17 +208,8 @@ static __net_exit void loopback_net_exit(struct net *net) unregister_netdev(dev); } -static struct pernet_operations __net_initdata loopback_net_ops = { +/* Registered in net/core/dev.c */ +struct pernet_operations __net_initdata loopback_net_ops = { .init = loopback_net_init, .exit = loopback_net_exit, }; - -static int __init loopback_init(void) -{ - return register_pernet_device(&loopback_net_ops); -} - -/* Loopback is special. It should be initialized before any other network - * device and network subsystem. - */ -fs_initcall(loopback_init); diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c index 83fa9d82a004830cecad296d2403cc1dce70c767..4d1a059921c6413d419257327cc382207298a9e7 100644 --- a/drivers/net/lp486e.c +++ b/drivers/net/lp486e.c @@ -390,7 +390,7 @@ i596_timeout(struct net_device *dev, char *msg, int ct) { struct i596_private *lp; int boguscnt = ct; - lp = (struct i596_private *) dev->priv; + lp = netdev_priv(dev); while (lp->scb.command) { if (--boguscnt == 0) { printk("%s: %s timed out - stat %4.4x, cmd %4.4x\n", @@ -411,7 +411,7 @@ init_rx_bufs(struct net_device *dev, int num) { int i; // struct i596_rbd *rbd; - lp = (struct i596_private *) dev->priv; + lp = netdev_priv(dev); lp->scb.pa_rfd = I596_NULL; for (i = 0; i < num; i++) { @@ -468,7 +468,7 @@ remove_rx_bufs(struct net_device *dev) { struct i596_private *lp; struct i596_rfd *rfd; - lp = (struct i596_private *) dev->priv; + lp = netdev_priv(dev); lp->rx_tail->pa_next = I596_NULL; do { @@ -517,7 +517,7 @@ CLEAR_INT(void) { /* selftest or dump */ static void i596_port_do(struct net_device *dev, int portcmd, char *cmdname) { - struct i596_private *lp = dev->priv; + struct i596_private *lp = netdev_priv(dev); u16 *outp; int i, m; @@ -541,7 +541,7 @@ i596_port_do(struct net_device *dev, int portcmd, char *cmdname) { static int i596_scp_setup(struct net_device *dev) { - struct i596_private *lp = dev->priv; + struct i596_private *lp = netdev_priv(dev); int boguscnt; /* Setup SCP, ISCP, SCB */ @@ -622,7 +622,7 @@ init_i596(struct net_device *dev) { if (i596_scp_setup(dev)) return 1; - lp = (struct i596_private *) dev->priv; + lp = netdev_priv(dev); lp->scb.command = 0; memcpy ((void *)lp->i596_config, init_setup, 14); @@ -676,7 +676,6 @@ i596_rx_one(struct net_device *dev, struct i596_private *lp, skb->protocol = eth_type_trans(skb,dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; } else { #if 0 @@ -705,7 +704,7 @@ i596_rx_one(struct net_device *dev, struct i596_private *lp, static int i596_rx(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = netdev_priv(dev); struct i596_rfd *rfd; int frames = 0; @@ -738,7 +737,7 @@ i596_cleanup_cmd(struct net_device *dev) { struct i596_private *lp; struct i596_cmd *cmd; - lp = (struct i596_private *) dev->priv; + lp = netdev_priv(dev); while (lp->cmd_head) { cmd = (struct i596_cmd *)lp->cmd_head; @@ -806,7 +805,7 @@ static void i596_reset(struct net_device *dev, struct i596_private *lp, int ioad } static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd) { - struct i596_private *lp = dev->priv; + struct i596_private *lp = netdev_priv(dev); int ioaddr = dev->base_addr; unsigned long flags; @@ -912,7 +911,7 @@ static int i596_start_xmit (struct sk_buff *skb, struct net_device *dev) { static void i596_tx_timeout (struct net_device *dev) { - struct i596_private *lp = dev->priv; + struct i596_private *lp = netdev_priv(dev); int ioaddr = dev->base_addr; /* Transmitter timeout, serious problems. */ @@ -970,7 +969,7 @@ static int __init lp486e_probe(struct net_device *dev) { return -EBUSY; } - lp = (struct i596_private *) dev->priv; + lp = netdev_priv(dev); spin_lock_init(&lp->cmd_lock); /* @@ -1147,7 +1146,7 @@ static irqreturn_t i596_interrupt(int irq, void *dev_instance) { struct net_device *dev = dev_instance; - struct i596_private *lp = dev->priv; + struct i596_private *lp = netdev_priv(dev); unsigned short status, ack_cmd = 0; int frames_in = 0; @@ -1215,7 +1214,7 @@ i596_interrupt(int irq, void *dev_instance) } static int i596_close(struct net_device *dev) { - struct i596_private *lp = dev->priv; + struct i596_private *lp = netdev_priv(dev); netif_stop_queue(dev); @@ -1242,7 +1241,7 @@ static int i596_close(struct net_device *dev) { */ static void set_multicast_list(struct net_device *dev) { - struct i596_private *lp = dev->priv; + struct i596_private *lp = netdev_priv(dev); struct i596_cmd *cmd; if (i596_debug > 1) diff --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c index 98e3eb2697c9b65a70adb0d9183efc3e6bf3e9be..57716e22660cc6091f7f99620bf5ee08e2624ede 100644 --- a/drivers/net/mac8390.c +++ b/drivers/net/mac8390.c @@ -304,7 +304,7 @@ struct net_device * __init mac8390_probe(int unit) if (!MACH_IS_MAC) return ERR_PTR(-ENODEV); - dev = ____alloc_ei_netdev(0); + dev = alloc_ei_netdev(); if (!dev) return ERR_PTR(-ENOMEM); @@ -478,6 +478,20 @@ void cleanup_module(void) #endif /* MODULE */ +static const struct net_device_ops mac8390_netdev_ops = { + .ndo_open = mac8390_open, + .ndo_stop = mac8390_close, + .ndo_start_xmit = ei_start_xmit, + .ndo_tx_timeout = ei_tx_timeout, + .ndo_get_stats = ei_get_stats, + .ndo_set_multicast_list = ei_set_multicast_list, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = ei_poll, +#endif +}; + static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * ndev, enum mac8390_type type) { @@ -503,11 +517,7 @@ static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * nd int access_bitmode = 0; /* Now fill in our stuff */ - dev->open = &mac8390_open; - dev->stop = &mac8390_close; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = __ei_poll; -#endif + dev->netdev_ops = &mac8390_netdev_ops; /* GAR, ei_status is actually a macro even though it looks global */ ei_status.name = cardname[type]; diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c index 4ce8afd481c3f13bd75caa570c5597c28b2a68cb..380a1a54d5301f1f3e95eb536423eb122bf84487 100644 --- a/drivers/net/mac89x0.c +++ b/drivers/net/mac89x0.c @@ -181,7 +181,6 @@ struct net_device * __init mac89x0_probe(int unit) unsigned long ioaddr; unsigned short sig; int err = -ENODEV; - DECLARE_MAC_BUF(mac); if (!MACH_IS_MAC) return ERR_PTR(-ENODEV); @@ -279,8 +278,7 @@ struct net_device * __init mac89x0_probe(int unit) /* print the IRQ and ethernet address. */ - printk(" IRQ %d ADDR %s\n", - dev->irq, print_mac(mac, dev->dev_addr)); + printk(" IRQ %d ADDR %pM\n", dev->irq, dev->dev_addr); dev->open = net_open; dev->stop = net_close; @@ -518,7 +516,6 @@ net_rx(struct net_device *dev) skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); - dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes += length; } @@ -628,14 +625,3 @@ cleanup_module(void) free_netdev(dev_cs89x0); } #endif /* MODULE */ - -/* - * Local variables: - * compile-command: "m68k-linux-gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -ffixed-a2 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c -o mac89x0.o mac89x0.c" - * version-control: t - * kept-new-versions: 5 - * c-indent-level: 8 - * tab-width: 8 - * End: - * - */ diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 01f7a31bac764134f623352a3894456c7192b205..a04da4ecaa8811a8be09450389e33288ebe2d80e 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -435,7 +435,6 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag, bp->stats.rx_packets++; bp->stats.rx_bytes += len; - bp->dev->last_rx = jiffies; dev_dbg(&bp->pdev->dev, "received skb of length %u, csum: %08x\n", skb->len, skb->csum); netif_receive_skb(skb); @@ -520,7 +519,7 @@ static int macb_poll(struct napi_struct *napi, int budget) * this function was called last time, and no packets * have been received since. */ - netif_rx_complete(dev, napi); + netif_rx_complete(napi); goto out; } @@ -531,13 +530,13 @@ static int macb_poll(struct napi_struct *napi, int budget) dev_warn(&bp->pdev->dev, "No RX buffers complete, status = %02lx\n", (unsigned long)status); - netif_rx_complete(dev, napi); + netif_rx_complete(napi); goto out; } work_done = macb_rx(bp, budget); if (work_done < budget) - netif_rx_complete(dev, napi); + netif_rx_complete(napi); /* * We've done what we can to clean the buffers. Make sure we @@ -572,7 +571,7 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id) } if (status & MACB_RX_INT_FLAGS) { - if (netif_rx_schedule_prep(dev, &bp->napi)) { + if (netif_rx_schedule_prep(&bp->napi)) { /* * There's no point taking any more interrupts * until we have processed the buffers @@ -580,7 +579,7 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id) macb_writel(bp, IDR, MACB_RX_INT_FLAGS); dev_dbg(&bp->pdev->dev, "scheduling RX softirq\n"); - __netif_rx_schedule(dev, &bp->napi); + __netif_rx_schedule(&bp->napi); } } @@ -1104,7 +1103,6 @@ static int __init macb_probe(struct platform_device *pdev) unsigned long pclk_hz; u32 config; int err = -ENXIO; - DECLARE_MAC_BUF(mac); regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!regs) { @@ -1223,10 +1221,8 @@ static int __init macb_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dev); - printk(KERN_INFO "%s: Atmel MACB at 0x%08lx irq %d " - "(%s)\n", - dev->name, dev->base_addr, dev->irq, - print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: Atmel MACB at 0x%08lx irq %d (%pM)\n", + dev->name, dev->base_addr, dev->irq, dev->dev_addr); phydev = bp->phy_dev; printk(KERN_INFO "%s: attached PHY driver [%s] " diff --git a/drivers/net/mace.c b/drivers/net/mace.c index 451acdca2a214a97068b46f597930b25d2e05f87..feebbd92aff2d3202d8e877cf31a6c6f13117140 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -101,7 +101,6 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i struct mace_data *mp; const unsigned char *addr; int j, rev, rc = -EBUSY; - DECLARE_MAC_BUF(mac); if (macio_resource_count(mdev) != 3 || macio_irq_count(mdev) != 3) { printk(KERN_ERR "can't use MACE %s: need 3 addrs and 3 irqs\n", @@ -144,7 +143,7 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i } SET_NETDEV_DEV(dev, &mdev->ofdev.dev); - mp = dev->priv; + mp = netdev_priv(dev); mp->mdev = mdev; macio_set_drvdata(mdev, dev); @@ -165,7 +164,7 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i in_8(&mp->mace->chipid_lo); - mp = (struct mace_data *) dev->priv; + mp = netdev_priv(dev); mp->maccc = ENXMT | ENRCV; mp->tx_dma = ioremap(macio_resource_start(mdev, 1), 0x1000); @@ -241,8 +240,8 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i goto err_free_rx_irq; } - printk(KERN_INFO "%s: MACE at %s, chip revision %d.%d\n", - dev->name, print_mac(mac, dev->dev_addr), + printk(KERN_INFO "%s: MACE at %pM, chip revision %d.%d\n", + dev->name, dev->dev_addr, mp->chipid >> 8, mp->chipid & 0xff); return 0; @@ -276,7 +275,7 @@ static int __devexit mace_remove(struct macio_dev *mdev) macio_set_drvdata(mdev, NULL); - mp = dev->priv; + mp = netdev_priv(dev); unregister_netdev(dev); @@ -312,7 +311,7 @@ static void dbdma_reset(volatile struct dbdma_regs __iomem *dma) static void mace_reset(struct net_device *dev) { - struct mace_data *mp = (struct mace_data *) dev->priv; + struct mace_data *mp = netdev_priv(dev); volatile struct mace __iomem *mb = mp->mace; int i; @@ -367,7 +366,7 @@ static void mace_reset(struct net_device *dev) static void __mace_set_address(struct net_device *dev, void *addr) { - struct mace_data *mp = (struct mace_data *) dev->priv; + struct mace_data *mp = netdev_priv(dev); volatile struct mace __iomem *mb = mp->mace; unsigned char *p = addr; int i; @@ -388,7 +387,7 @@ static void __mace_set_address(struct net_device *dev, void *addr) static int mace_set_address(struct net_device *dev, void *addr) { - struct mace_data *mp = (struct mace_data *) dev->priv; + struct mace_data *mp = netdev_priv(dev); volatile struct mace __iomem *mb = mp->mace; unsigned long flags; @@ -423,7 +422,7 @@ static inline void mace_clean_rings(struct mace_data *mp) static int mace_open(struct net_device *dev) { - struct mace_data *mp = (struct mace_data *) dev->priv; + struct mace_data *mp = netdev_priv(dev); volatile struct mace __iomem *mb = mp->mace; volatile struct dbdma_regs __iomem *rd = mp->rx_dma; volatile struct dbdma_regs __iomem *td = mp->tx_dma; @@ -493,7 +492,7 @@ static int mace_open(struct net_device *dev) static int mace_close(struct net_device *dev) { - struct mace_data *mp = (struct mace_data *) dev->priv; + struct mace_data *mp = netdev_priv(dev); volatile struct mace __iomem *mb = mp->mace; volatile struct dbdma_regs __iomem *rd = mp->rx_dma; volatile struct dbdma_regs __iomem *td = mp->tx_dma; @@ -513,7 +512,7 @@ static int mace_close(struct net_device *dev) static inline void mace_set_timeout(struct net_device *dev) { - struct mace_data *mp = (struct mace_data *) dev->priv; + struct mace_data *mp = netdev_priv(dev); if (mp->timeout_active) del_timer(&mp->tx_timeout); @@ -526,7 +525,7 @@ static inline void mace_set_timeout(struct net_device *dev) static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev) { - struct mace_data *mp = (struct mace_data *) dev->priv; + struct mace_data *mp = netdev_priv(dev); volatile struct dbdma_regs __iomem *td = mp->tx_dma; volatile struct dbdma_cmd *cp, *np; unsigned long flags; @@ -581,7 +580,7 @@ static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev) static void mace_set_multicast(struct net_device *dev) { - struct mace_data *mp = (struct mace_data *) dev->priv; + struct mace_data *mp = netdev_priv(dev); volatile struct mace __iomem *mb = mp->mace; int i, j; u32 crc; @@ -656,7 +655,7 @@ static void mace_handle_misc_intrs(struct mace_data *mp, int intr, struct net_de static irqreturn_t mace_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; - struct mace_data *mp = (struct mace_data *) dev->priv; + struct mace_data *mp = netdev_priv(dev); volatile struct mace __iomem *mb = mp->mace; volatile struct dbdma_regs __iomem *td = mp->tx_dma; volatile struct dbdma_cmd *cp; @@ -802,7 +801,7 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id) static void mace_tx_timeout(unsigned long data) { struct net_device *dev = (struct net_device *) data; - struct mace_data *mp = (struct mace_data *) dev->priv; + struct mace_data *mp = netdev_priv(dev); volatile struct mace __iomem *mb = mp->mace; volatile struct dbdma_regs __iomem *td = mp->tx_dma; volatile struct dbdma_regs __iomem *rd = mp->rx_dma; @@ -873,7 +872,7 @@ static irqreturn_t mace_txdma_intr(int irq, void *dev_id) static irqreturn_t mace_rxdma_intr(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; - struct mace_data *mp = (struct mace_data *) dev->priv; + struct mace_data *mp = netdev_priv(dev); volatile struct dbdma_regs __iomem *rd = mp->rx_dma; volatile struct dbdma_cmd *cp, *np; int i, nb, stat, next; @@ -929,7 +928,6 @@ static irqreturn_t mace_rxdma_intr(int irq, void *dev_id) skb->protocol = eth_type_trans(skb, dev); dev->stats.rx_bytes += skb->len; netif_rx(skb); - dev->last_rx = jiffies; mp->rx_bufs[i] = NULL; ++dev->stats.rx_packets; } diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c index 85587a6667b9f170d3b55686a6474c20754a4c15..274e99bb63ac28857b568e339a46088065ecf6e2 100644 --- a/drivers/net/macmace.c +++ b/drivers/net/macmace.c @@ -194,7 +194,6 @@ static int __devinit mace_probe(struct platform_device *pdev) unsigned char checksum = 0; static int found = 0; int err; - DECLARE_MAC_BUF(mac); if (found || macintosh_config->ether_type != MAC_ETHER_MACE) return -ENODEV; @@ -249,8 +248,8 @@ static int __devinit mace_probe(struct platform_device *pdev) dev->set_multicast_list = mace_set_multicast; dev->set_mac_address = mace_set_address; - printk(KERN_INFO "%s: 68K MACE, hardware address %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: 68K MACE, hardware address %pM\n", + dev->name, dev->dev_addr); err = register_netdev(dev); if (!err) @@ -674,7 +673,6 @@ static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf) skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += frame_length; } diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c index e64c2086d33c7ea9fcd8834b408a34f46de79c67..205bb05c25d6f41a2eec0abfdb958348179d0e93 100644 --- a/drivers/net/macsonic.c +++ b/drivers/net/macsonic.c @@ -220,7 +220,6 @@ static int __init mac_onboard_sonic_ethernet_addr(struct net_device *dev) struct sonic_local *lp = netdev_priv(dev); const int prom_addr = ONBOARD_SONIC_PROM_BASE; int i; - DECLARE_MAC_BUF(mac); /* On NuBus boards we can sometimes look in the ROM resources. No such luck for comm-slot/onboard. */ @@ -264,8 +263,8 @@ static int __init mac_onboard_sonic_ethernet_addr(struct net_device *dev) dev->dev_addr[1] = val >> 8; dev->dev_addr[0] = val & 0xff; - printk(KERN_INFO "HW Address from CAM 15: %s\n", - print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "HW Address from CAM 15: %pM\n", + dev->dev_addr); } else return 0; if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) && @@ -560,7 +559,6 @@ static int __init mac_sonic_probe(struct platform_device *pdev) struct net_device *dev; struct sonic_local *lp; int err; - DECLARE_MAC_BUF(mac); dev = alloc_etherdev(sizeof(struct sonic_local)); if (!dev) @@ -584,8 +582,7 @@ static int __init mac_sonic_probe(struct platform_device *pdev) if (err) goto out; - printk("%s: MAC %s IRQ %d\n", - dev->name, print_mac(mac, dev->dev_addr), dev->irq); + printk("%s: MAC %pM IRQ %d\n", dev->name, dev->dev_addr, dev->irq); return 0; diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 590039cbb146f5a42b888055cc836ea576f23726..7e24b50486869c8295e19d8b7339b7d56d6ef909 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -87,7 +87,6 @@ static void macvlan_broadcast(struct sk_buff *skb, dev->stats.rx_bytes += skb->len + ETH_HLEN; dev->stats.rx_packets++; dev->stats.multicast++; - dev->last_rx = jiffies; nskb->dev = dev; if (!compare_ether_addr(eth->h_dest, dev->broadcast)) @@ -136,7 +135,6 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb) dev->stats.rx_bytes += skb->len + ETH_HLEN; dev->stats.rx_packets++; - dev->last_rx = jiffies; skb->dev = dev; skb->pkt_type = PACKET_HOST; @@ -145,7 +143,7 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb) return NULL; } -static int macvlan_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +static int macvlan_start_xmit(struct sk_buff *skb, struct net_device *dev) { const struct macvlan_dev *vlan = netdev_priv(dev); unsigned int len = skb->len; @@ -336,24 +334,53 @@ static u32 macvlan_ethtool_get_rx_csum(struct net_device *dev) return lowerdev->ethtool_ops->get_rx_csum(lowerdev); } +static int macvlan_ethtool_get_settings(struct net_device *dev, + struct ethtool_cmd *cmd) +{ + const struct macvlan_dev *vlan = netdev_priv(dev); + struct net_device *lowerdev = vlan->lowerdev; + + if (!lowerdev->ethtool_ops->get_settings) + return -EOPNOTSUPP; + + return lowerdev->ethtool_ops->get_settings(lowerdev, cmd); +} + +static u32 macvlan_ethtool_get_flags(struct net_device *dev) +{ + const struct macvlan_dev *vlan = netdev_priv(dev); + struct net_device *lowerdev = vlan->lowerdev; + + if (!lowerdev->ethtool_ops->get_flags) + return 0; + return lowerdev->ethtool_ops->get_flags(lowerdev); +} + static const struct ethtool_ops macvlan_ethtool_ops = { .get_link = ethtool_op_get_link, + .get_settings = macvlan_ethtool_get_settings, .get_rx_csum = macvlan_ethtool_get_rx_csum, .get_drvinfo = macvlan_ethtool_get_drvinfo, + .get_flags = macvlan_ethtool_get_flags, +}; + +static const struct net_device_ops macvlan_netdev_ops = { + .ndo_init = macvlan_init, + .ndo_open = macvlan_open, + .ndo_stop = macvlan_stop, + .ndo_start_xmit = macvlan_start_xmit, + .ndo_change_mtu = macvlan_change_mtu, + .ndo_change_rx_flags = macvlan_change_rx_flags, + .ndo_set_mac_address = macvlan_set_mac_address, + .ndo_set_multicast_list = macvlan_set_multicast_list, + .ndo_validate_addr = eth_validate_addr, }; static void macvlan_setup(struct net_device *dev) { ether_setup(dev); - dev->init = macvlan_init; - dev->open = macvlan_open; - dev->stop = macvlan_stop; - dev->change_mtu = macvlan_change_mtu; - dev->change_rx_flags = macvlan_change_rx_flags; - dev->set_mac_address = macvlan_set_mac_address; - dev->set_multicast_list = macvlan_set_multicast_list; - dev->hard_start_xmit = macvlan_hard_start_xmit; + dev->netdev_ops = &macvlan_netdev_ops; dev->destructor = free_netdev; dev->header_ops = &macvlan_hard_header_ops, dev->ethtool_ops = &macvlan_ethtool_ops; diff --git a/drivers/net/meth.c b/drivers/net/meth.c index a1e22ed1f6ee5616ce9d88bde8a55940dc66fa16..c336a1f42510c09d5c9e690cc46c207f9f6880e3 100644 --- a/drivers/net/meth.c +++ b/drivers/net/meth.c @@ -94,10 +94,9 @@ char o2meth_eaddr[8]={0,0,0,0,0,0,0,0}; static inline void load_eaddr(struct net_device *dev) { int i; - DECLARE_MAC_BUF(mac); u64 macaddr; - DPRINTK("Loading MAC Address: %s\n", print_mac(mac, dev->dev_addr)); + DPRINTK("Loading MAC Address: %pM\n", dev->dev_addr); macaddr = 0; for (i = 0; i < 6; i++) macaddr |= (u64)dev->dev_addr[i] << ((5 - i) * 8); @@ -421,7 +420,6 @@ static void meth_rx(struct net_device* dev, unsigned long int_status) skb_put(skb_c, len); priv->rx_skbs[priv->rx_write] = skb; skb_c->protocol = eth_type_trans(skb_c, dev); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += len; netif_rx(skb_c); diff --git a/drivers/net/mlx4/cq.c b/drivers/net/mlx4/cq.c index b7ad2829d67ecbe608422658b16f79ac890fd526..ac57b6a42c6ee8791fcca7f385a2c703b4e96799 100644 --- a/drivers/net/mlx4/cq.c +++ b/drivers/net/mlx4/cq.c @@ -189,7 +189,7 @@ EXPORT_SYMBOL_GPL(mlx4_cq_resize); int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt, struct mlx4_uar *uar, u64 db_rec, struct mlx4_cq *cq, - int collapsed) + unsigned vector, int collapsed) { struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_cq_table *cq_table = &priv->cq_table; @@ -198,6 +198,11 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt, u64 mtt_addr; int err; + if (vector >= dev->caps.num_comp_vectors) + return -EINVAL; + + cq->vector = vector; + cq->cqn = mlx4_bitmap_alloc(&cq_table->bitmap); if (cq->cqn == -1) return -ENOMEM; @@ -227,7 +232,7 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt, cq_context->flags = cpu_to_be32(!!collapsed << 18); cq_context->logsize_usrpage = cpu_to_be32((ilog2(nent) << 24) | uar->index); - cq_context->comp_eqn = priv->eq_table.eq[MLX4_EQ_COMP].eqn; + cq_context->comp_eqn = priv->eq_table.eq[vector].eqn; cq_context->log_page_size = mtt->page_shift - MLX4_ICM_PAGE_SHIFT; mtt_addr = mlx4_mtt_addr(dev, mtt); @@ -276,7 +281,7 @@ void mlx4_cq_free(struct mlx4_dev *dev, struct mlx4_cq *cq) if (err) mlx4_warn(dev, "HW2SW_CQ failed (%d) for CQN %06x\n", err, cq->cqn); - synchronize_irq(priv->eq_table.eq[MLX4_EQ_COMP].irq); + synchronize_irq(priv->eq_table.eq[cq->vector].irq); spin_lock_irq(&cq_table->lock); radix_tree_delete(&cq_table->tree, cq->cqn); diff --git a/drivers/net/mlx4/en_cq.c b/drivers/net/mlx4/en_cq.c index 1368a8010af4e98169923388dd216ea29c5e0673..91f50de84be9053422699e0856e6d6f003508ba7 100644 --- a/drivers/net/mlx4/en_cq.c +++ b/drivers/net/mlx4/en_cq.c @@ -51,10 +51,13 @@ int mlx4_en_create_cq(struct mlx4_en_priv *priv, int err; cq->size = entries; - if (mode == RX) + if (mode == RX) { cq->buf_size = cq->size * sizeof(struct mlx4_cqe); - else + cq->vector = ring % mdev->dev->caps.num_comp_vectors; + } else { cq->buf_size = sizeof(struct mlx4_cqe); + cq->vector = 0; + } cq->ring = ring; cq->is_tx = mode; @@ -68,6 +71,8 @@ int mlx4_en_create_cq(struct mlx4_en_priv *priv, err = mlx4_en_map_buffer(&cq->wqres.buf); if (err) mlx4_free_hwq_res(mdev->dev, &cq->wqres, cq->buf_size); + else + cq->buf = (struct mlx4_cqe *) cq->wqres.buf.direct.buf; return err; } @@ -82,11 +87,10 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) cq->mcq.arm_db = cq->wqres.db.db + 1; *cq->mcq.set_ci_db = 0; *cq->mcq.arm_db = 0; - cq->buf = (struct mlx4_cqe *) cq->wqres.buf.direct.buf; memset(cq->buf, 0, cq->buf_size); err = mlx4_cq_alloc(mdev->dev, cq->size, &cq->wqres.mtt, &mdev->priv_uar, - cq->wqres.db.dma, &cq->mcq, cq->is_tx); + cq->wqres.db.dma, &cq->mcq, cq->vector, cq->is_tx); if (err) return err; @@ -136,7 +140,6 @@ int mlx4_en_set_cq_moder(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) int mlx4_en_arm_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) { - cq->armed = 1; mlx4_cq_arm(&cq->mcq, MLX4_CQ_DB_REQ_NOT, priv->mdev->uar_map, &priv->mdev->uar_lock); diff --git a/drivers/net/mlx4/en_main.c b/drivers/net/mlx4/en_main.c index 4b9794e97a79fdcfac53ace0654305bd43381d7c..c1c05852a95ebf34e357f86a6b0465758e5458f9 100644 --- a/drivers/net/mlx4/en_main.c +++ b/drivers/net/mlx4/en_main.c @@ -170,9 +170,9 @@ static void *mlx4_en_add(struct mlx4_dev *dev) mlx4_info(mdev, "Using %d tx rings for port:%d\n", mdev->profile.prof[i].tx_ring_num, i); if (!mdev->profile.prof[i].rx_ring_num) { - mdev->profile.prof[i].rx_ring_num = 1; + mdev->profile.prof[i].rx_ring_num = dev->caps.num_comp_vectors; mlx4_info(mdev, "Defaulting to %d rx rings for port:%d\n", - 1, i); + mdev->profile.prof[i].rx_ring_num, i); } else mlx4_info(mdev, "Using %d rx rings for port:%d\n", mdev->profile.prof[i].rx_ring_num, i); diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c index 96e709d6440a459866b7d5d461113408031d7c23..ebada3c7aff2aee26ed5acbc306733be6e126bf6 100644 --- a/drivers/net/mlx4/en_netdev.c +++ b/drivers/net/mlx4/en_netdev.c @@ -369,7 +369,6 @@ static struct net_device_stats *mlx4_en_get_stats(struct net_device *dev) static void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv) { - struct mlx4_en_dev *mdev = priv->mdev; struct mlx4_en_cq *cq; int i; @@ -379,15 +378,8 @@ static void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv) * satisfy our coelsing target. * - moder_time is set to a fixed value. */ - priv->rx_frames = (mdev->profile.rx_moder_cnt == - MLX4_EN_AUTO_CONF) ? - MLX4_EN_RX_COAL_TARGET / - priv->dev->mtu + 1 : - mdev->profile.rx_moder_cnt; - priv->rx_usecs = (mdev->profile.rx_moder_time == - MLX4_EN_AUTO_CONF) ? - MLX4_EN_RX_COAL_TIME : - mdev->profile.rx_moder_time; + priv->rx_frames = MLX4_EN_RX_COAL_TARGET / priv->dev->mtu + 1; + priv->rx_usecs = MLX4_EN_RX_COAL_TIME; mlx4_dbg(INTR, priv, "Default coalesing params for mtu:%d - " "rx_frames:%d rx_usecs:%d\n", priv->dev->mtu, priv->rx_frames, priv->rx_usecs); @@ -411,7 +403,7 @@ static void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv) priv->pkt_rate_high = MLX4_EN_RX_RATE_HIGH; priv->rx_usecs_high = MLX4_EN_RX_COAL_TIME_HIGH; priv->sample_interval = MLX4_EN_SAMPLE_INTERVAL; - priv->adaptive_rx_coal = mdev->profile.auto_moder; + priv->adaptive_rx_coal = 1; priv->last_moder_time = MLX4_EN_AUTO_CONF; priv->last_moder_jiffies = 0; priv->last_moder_packets = 0; @@ -953,6 +945,23 @@ static int mlx4_en_change_mtu(struct net_device *dev, int new_mtu) return 0; } +static const struct net_device_ops mlx4_netdev_ops = { + .ndo_open = mlx4_en_open, + .ndo_stop = mlx4_en_close, + .ndo_start_xmit = mlx4_en_xmit, + .ndo_get_stats = mlx4_en_get_stats, + .ndo_set_multicast_list = mlx4_en_set_multicast, + .ndo_set_mac_address = mlx4_en_set_mac, + .ndo_change_mtu = mlx4_en_change_mtu, + .ndo_tx_timeout = mlx4_en_tx_timeout, + .ndo_vlan_rx_register = mlx4_en_vlan_rx_register, + .ndo_vlan_rx_add_vid = mlx4_en_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = mlx4_en_vlan_rx_kill_vid, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = mlx4_en_netpoll, +#endif +}; + int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, struct mlx4_en_port_profile *prof) { @@ -1029,22 +1038,9 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, /* * Initialize netdev entry points */ - - dev->open = &mlx4_en_open; - dev->stop = &mlx4_en_close; - dev->hard_start_xmit = &mlx4_en_xmit; - dev->get_stats = &mlx4_en_get_stats; - dev->set_multicast_list = &mlx4_en_set_multicast; - dev->set_mac_address = &mlx4_en_set_mac; - dev->change_mtu = &mlx4_en_change_mtu; - dev->tx_timeout = &mlx4_en_tx_timeout; + dev->netdev_ops = &mlx4_netdev_ops; dev->watchdog_timeo = MLX4_EN_WATCHDOG_TIMEOUT; - dev->vlan_rx_register = mlx4_en_vlan_rx_register; - dev->vlan_rx_add_vid = mlx4_en_vlan_rx_add_vid; - dev->vlan_rx_kill_vid = mlx4_en_vlan_rx_kill_vid; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = mlx4_en_netpoll; -#endif + SET_ETHTOOL_OPS(dev, &mlx4_en_ethtool_ops); /* Set defualt MAC */ diff --git a/drivers/net/mlx4/en_params.c b/drivers/net/mlx4/en_params.c index 95706ee1c01996898a255b210a7cf8efd14e5ab4..047b37f5a7474cc8137753590e3d85858e712ce6 100644 --- a/drivers/net/mlx4/en_params.c +++ b/drivers/net/mlx4/en_params.c @@ -60,24 +60,11 @@ MLX4_EN_PARM_INT(num_lro, MLX4_EN_MAX_LRO_DESCRIPTORS, "Number of LRO sessions per ring or disabled (0)"); /* Priority pausing */ -MLX4_EN_PARM_INT(pptx, MLX4_EN_DEF_TX_PAUSE, - "Pause policy on TX: 0 never generate pause frames " - "1 generate pause frames according to RX buffer threshold"); -MLX4_EN_PARM_INT(pprx, MLX4_EN_DEF_RX_PAUSE, - "Pause policy on RX: 0 ignore received pause frames " - "1 respect received pause frames"); MLX4_EN_PARM_INT(pfctx, 0, "Priority based Flow Control policy on TX[7:0]." " Per priority bit mask"); MLX4_EN_PARM_INT(pfcrx, 0, "Priority based Flow Control policy on RX[7:0]." " Per priority bit mask"); -/* Interrupt moderation tunning */ -MLX4_EN_PARM_INT(rx_moder_cnt, MLX4_EN_AUTO_CONF, - "Max coalesced descriptors for Rx interrupt moderation"); -MLX4_EN_PARM_INT(rx_moder_time, MLX4_EN_AUTO_CONF, - "Timeout following last packet for Rx interrupt moderation"); -MLX4_EN_PARM_INT(auto_moder, 1, "Enable dynamic interrupt moderation"); - MLX4_EN_PARM_INT(rx_ring_num1, 0, "Number or Rx rings for port 1 (0 = #cores)"); MLX4_EN_PARM_INT(rx_ring_num2, 0, "Number or Rx rings for port 2 (0 = #cores)"); @@ -92,16 +79,13 @@ int mlx4_en_get_profile(struct mlx4_en_dev *mdev) struct mlx4_en_profile *params = &mdev->profile; int i; - params->rx_moder_cnt = min_t(int, rx_moder_cnt, MLX4_EN_AUTO_CONF); - params->rx_moder_time = min_t(int, rx_moder_time, MLX4_EN_AUTO_CONF); - params->auto_moder = auto_moder; params->rss_xor = (rss_xor != 0); params->rss_mask = rss_mask & 0x1f; params->num_lro = min_t(int, num_lro , MLX4_EN_MAX_LRO_DESCRIPTORS); for (i = 1; i <= MLX4_MAX_PORTS; i++) { - params->prof[i].rx_pause = pprx; + params->prof[i].rx_pause = 1; params->prof[i].rx_ppp = pfcrx; - params->prof[i].tx_pause = pptx; + params->prof[i].tx_pause = 1; params->prof[i].tx_ppp = pfctx; } if (pfcrx || pfctx) { diff --git a/drivers/net/mlx4/en_rx.c b/drivers/net/mlx4/en_rx.c index 6232227f56c33a8cfd66e59d3ffafe7589b74791..c61b0bdca1a433c33771784d88fb8f6eae3f092d 100644 --- a/drivers/net/mlx4/en_rx.c +++ b/drivers/net/mlx4/en_rx.c @@ -443,7 +443,8 @@ int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv) /* Fill Rx buffers */ ring->full = 0; } - if (mlx4_en_fill_rx_buffers(priv)) + err = mlx4_en_fill_rx_buffers(priv); + if (err) goto err_buffers; for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) { @@ -776,8 +777,6 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud } else netif_receive_skb(skb); - dev->last_rx = jiffies; - next: ++cq->mcq.cons_index; index = (cq->mcq.cons_index) & ring->size_mask; @@ -815,7 +814,7 @@ void mlx4_en_rx_irq(struct mlx4_cq *mcq) struct mlx4_en_priv *priv = netdev_priv(cq->dev); if (priv->port_up) - netif_rx_schedule(cq->dev, &cq->napi); + netif_rx_schedule(&cq->napi); else mlx4_en_arm_cq(priv, cq); } @@ -835,7 +834,7 @@ int mlx4_en_poll_rx_cq(struct napi_struct *napi, int budget) INC_PERF_COUNTER(priv->pstats.napi_quota); else { /* Done for now */ - netif_rx_complete(dev, napi); + netif_rx_complete(napi); mlx4_en_arm_cq(priv, cq); } return done; diff --git a/drivers/net/mlx4/en_tx.c b/drivers/net/mlx4/en_tx.c index 8592f8fb847577c42ed5b964ff50be35b1e6840a..ff4d75205c25bac5c6acb91fe216320c98fc568b 100644 --- a/drivers/net/mlx4/en_tx.c +++ b/drivers/net/mlx4/en_tx.c @@ -379,8 +379,8 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq) /* Wakeup Tx queue if this ring stopped it */ if (unlikely(ring->blocked)) { - if (((u32) (ring->prod - ring->cons) <= - ring->size - HEADROOM - MAX_DESC_TXBBS) && !cq->armed) { + if ((u32) (ring->prod - ring->cons) <= + ring->size - HEADROOM - MAX_DESC_TXBBS) { /* TODO: support multiqueue netdevs. Currently, we block * when *any* ring is full. Note that: @@ -404,14 +404,11 @@ void mlx4_en_tx_irq(struct mlx4_cq *mcq) struct mlx4_en_priv *priv = netdev_priv(cq->dev); struct mlx4_en_tx_ring *ring = &priv->tx_ring[cq->ring]; - spin_lock_irq(&ring->comp_lock); - cq->armed = 0; + if (!spin_trylock(&ring->comp_lock)) + return; mlx4_en_process_tx_cq(cq->dev, cq); - if (ring->blocked) - mlx4_en_arm_cq(priv, cq); - else - mod_timer(&cq->timer, jiffies + 1); - spin_unlock_irq(&ring->comp_lock); + mod_timer(&cq->timer, jiffies + 1); + spin_unlock(&ring->comp_lock); } @@ -424,8 +421,10 @@ void mlx4_en_poll_tx_cq(unsigned long data) INC_PERF_COUNTER(priv->pstats.tx_poll); - netif_tx_lock(priv->dev); - spin_lock_irq(&ring->comp_lock); + if (!spin_trylock(&ring->comp_lock)) { + mod_timer(&cq->timer, jiffies + MLX4_EN_TX_POLL_TIMEOUT); + return; + } mlx4_en_process_tx_cq(cq->dev, cq); inflight = (u32) (ring->prod - ring->cons - ring->last_nr_txbb); @@ -435,8 +434,7 @@ void mlx4_en_poll_tx_cq(unsigned long data) if (inflight && priv->port_up) mod_timer(&cq->timer, jiffies + MLX4_EN_TX_POLL_TIMEOUT); - spin_unlock_irq(&ring->comp_lock); - netif_tx_unlock(priv->dev); + spin_unlock(&ring->comp_lock); } static struct mlx4_en_tx_desc *mlx4_en_bounce_to_desc(struct mlx4_en_priv *priv, @@ -479,7 +477,10 @@ static inline void mlx4_en_xmit_poll(struct mlx4_en_priv *priv, int tx_ind) /* Poll the CQ every mlx4_en_TX_MODER_POLL packets */ if ((++ring->poll_cnt & (MLX4_EN_TX_POLL_MODER - 1)) == 0) - mlx4_en_process_tx_cq(priv->dev, cq); + if (spin_trylock(&ring->comp_lock)) { + mlx4_en_process_tx_cq(priv->dev, cq); + spin_unlock(&ring->comp_lock); + } } static void *get_frag_ptr(struct sk_buff *skb) diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c index de169338cd901a448fffc668ea083b2c8d5498e7..2c19bff7cbaba33efe3c10776c476594158c4b13 100644 --- a/drivers/net/mlx4/eq.c +++ b/drivers/net/mlx4/eq.c @@ -243,10 +243,6 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq) * least that often. */ if (unlikely(set_ci >= MLX4_NUM_SPARE_EQE)) { - /* - * Conditional on hca_type is OK here because - * this is a rare case, not the fast path. - */ eq_set_ci(eq, 0); set_ci = 0; } @@ -266,7 +262,7 @@ static irqreturn_t mlx4_interrupt(int irq, void *dev_ptr) writel(priv->eq_table.clr_mask, priv->eq_table.clr_int); - for (i = 0; i < MLX4_NUM_EQ; ++i) + for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) work |= mlx4_eq_int(dev, &priv->eq_table.eq[i]); return IRQ_RETVAL(work); @@ -304,6 +300,17 @@ static int mlx4_HW2SW_EQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, MLX4_CMD_TIME_CLASS_A); } +static int mlx4_num_eq_uar(struct mlx4_dev *dev) +{ + /* + * Each UAR holds 4 EQ doorbells. To figure out how many UARs + * we need to map, take the difference of highest index and + * the lowest index we'll use and add 1. + */ + return (dev->caps.num_comp_vectors + 1 + dev->caps.reserved_eqs) / 4 - + dev->caps.reserved_eqs / 4 + 1; +} + static void __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev, struct mlx4_eq *eq) { struct mlx4_priv *priv = mlx4_priv(dev); @@ -483,9 +490,11 @@ static void mlx4_free_irqs(struct mlx4_dev *dev) if (eq_table->have_irq) free_irq(dev->pdev->irq, dev); - for (i = 0; i < MLX4_NUM_EQ; ++i) + for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) if (eq_table->eq[i].have_irq) free_irq(eq_table->eq[i].irq, eq_table->eq + i); + + kfree(eq_table->irq_names); } static int mlx4_map_clr_int(struct mlx4_dev *dev) @@ -551,57 +560,93 @@ void mlx4_unmap_eq_icm(struct mlx4_dev *dev) __free_page(priv->eq_table.icm_page); } +int mlx4_alloc_eq_table(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + + priv->eq_table.eq = kcalloc(dev->caps.num_eqs - dev->caps.reserved_eqs, + sizeof *priv->eq_table.eq, GFP_KERNEL); + if (!priv->eq_table.eq) + return -ENOMEM; + + return 0; +} + +void mlx4_free_eq_table(struct mlx4_dev *dev) +{ + kfree(mlx4_priv(dev)->eq_table.eq); +} + int mlx4_init_eq_table(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); int err; int i; + priv->eq_table.uar_map = kcalloc(sizeof *priv->eq_table.uar_map, + mlx4_num_eq_uar(dev), GFP_KERNEL); + if (!priv->eq_table.uar_map) { + err = -ENOMEM; + goto err_out_free; + } + err = mlx4_bitmap_init(&priv->eq_table.bitmap, dev->caps.num_eqs, dev->caps.num_eqs - 1, dev->caps.reserved_eqs, 0); if (err) - return err; + goto err_out_free; - for (i = 0; i < ARRAY_SIZE(priv->eq_table.uar_map); ++i) + for (i = 0; i < mlx4_num_eq_uar(dev); ++i) priv->eq_table.uar_map[i] = NULL; err = mlx4_map_clr_int(dev); if (err) - goto err_out_free; + goto err_out_bitmap; priv->eq_table.clr_mask = swab32(1 << (priv->eq_table.inta_pin & 31)); priv->eq_table.clr_int = priv->clr_base + (priv->eq_table.inta_pin < 32 ? 4 : 0); - err = mlx4_create_eq(dev, dev->caps.num_cqs + MLX4_NUM_SPARE_EQE, - (dev->flags & MLX4_FLAG_MSI_X) ? MLX4_EQ_COMP : 0, - &priv->eq_table.eq[MLX4_EQ_COMP]); - if (err) - goto err_out_unmap; + priv->eq_table.irq_names = kmalloc(16 * dev->caps.num_comp_vectors, GFP_KERNEL); + if (!priv->eq_table.irq_names) { + err = -ENOMEM; + goto err_out_bitmap; + } + + for (i = 0; i < dev->caps.num_comp_vectors; ++i) { + err = mlx4_create_eq(dev, dev->caps.num_cqs + MLX4_NUM_SPARE_EQE, + (dev->flags & MLX4_FLAG_MSI_X) ? i : 0, + &priv->eq_table.eq[i]); + if (err) + goto err_out_unmap; + } err = mlx4_create_eq(dev, MLX4_NUM_ASYNC_EQE + MLX4_NUM_SPARE_EQE, - (dev->flags & MLX4_FLAG_MSI_X) ? MLX4_EQ_ASYNC : 0, - &priv->eq_table.eq[MLX4_EQ_ASYNC]); + (dev->flags & MLX4_FLAG_MSI_X) ? dev->caps.num_comp_vectors : 0, + &priv->eq_table.eq[dev->caps.num_comp_vectors]); if (err) goto err_out_comp; if (dev->flags & MLX4_FLAG_MSI_X) { - static const char *eq_name[] = { - [MLX4_EQ_COMP] = DRV_NAME " (comp)", - [MLX4_EQ_ASYNC] = DRV_NAME " (async)" - }; + static const char async_eq_name[] = "mlx4-async"; + const char *eq_name; + + for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) { + if (i < dev->caps.num_comp_vectors) { + snprintf(priv->eq_table.irq_names + i * 16, 16, + "mlx4-comp-%d", i); + eq_name = priv->eq_table.irq_names + i * 16; + } else + eq_name = async_eq_name; - for (i = 0; i < MLX4_NUM_EQ; ++i) { err = request_irq(priv->eq_table.eq[i].irq, - mlx4_msi_x_interrupt, - 0, eq_name[i], priv->eq_table.eq + i); + mlx4_msi_x_interrupt, 0, eq_name, + priv->eq_table.eq + i); if (err) goto err_out_async; priv->eq_table.eq[i].have_irq = 1; } - } else { err = request_irq(dev->pdev->irq, mlx4_interrupt, IRQF_SHARED, DRV_NAME, dev); @@ -612,28 +657,36 @@ int mlx4_init_eq_table(struct mlx4_dev *dev) } err = mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 0, - priv->eq_table.eq[MLX4_EQ_ASYNC].eqn); + priv->eq_table.eq[dev->caps.num_comp_vectors].eqn); if (err) mlx4_warn(dev, "MAP_EQ for async EQ %d failed (%d)\n", - priv->eq_table.eq[MLX4_EQ_ASYNC].eqn, err); + priv->eq_table.eq[dev->caps.num_comp_vectors].eqn, err); - for (i = 0; i < MLX4_NUM_EQ; ++i) + for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) eq_set_ci(&priv->eq_table.eq[i], 1); return 0; err_out_async: - mlx4_free_eq(dev, &priv->eq_table.eq[MLX4_EQ_ASYNC]); + mlx4_free_eq(dev, &priv->eq_table.eq[dev->caps.num_comp_vectors]); err_out_comp: - mlx4_free_eq(dev, &priv->eq_table.eq[MLX4_EQ_COMP]); + i = dev->caps.num_comp_vectors - 1; err_out_unmap: + while (i >= 0) { + mlx4_free_eq(dev, &priv->eq_table.eq[i]); + --i; + } mlx4_unmap_clr_int(dev); mlx4_free_irqs(dev); -err_out_free: +err_out_bitmap: mlx4_bitmap_cleanup(&priv->eq_table.bitmap); + +err_out_free: + kfree(priv->eq_table.uar_map); + return err; } @@ -643,18 +696,20 @@ void mlx4_cleanup_eq_table(struct mlx4_dev *dev) int i; mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 1, - priv->eq_table.eq[MLX4_EQ_ASYNC].eqn); + priv->eq_table.eq[dev->caps.num_comp_vectors].eqn); mlx4_free_irqs(dev); - for (i = 0; i < MLX4_NUM_EQ; ++i) + for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) mlx4_free_eq(dev, &priv->eq_table.eq[i]); mlx4_unmap_clr_int(dev); - for (i = 0; i < ARRAY_SIZE(priv->eq_table.uar_map); ++i) + for (i = 0; i < mlx4_num_eq_uar(dev); ++i) if (priv->eq_table.uar_map[i]) iounmap(priv->eq_table.uar_map[i]); mlx4_bitmap_cleanup(&priv->eq_table.bitmap); + + kfree(priv->eq_table.uar_map); } diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index 90a0281d15ea22d96ce788107dee88d0deb77aff..710c79e7a2db244b567b485db51abf0978f04253 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -421,9 +421,7 @@ static int mlx4_init_cmpt_table(struct mlx4_dev *dev, u64 cmpt_base, ((u64) (MLX4_CMPT_TYPE_EQ * cmpt_entry_sz) << MLX4_CMPT_SHIFT), cmpt_entry_sz, - roundup_pow_of_two(MLX4_NUM_EQ + - dev->caps.reserved_eqs), - MLX4_NUM_EQ + dev->caps.reserved_eqs, 0, 0); + dev->caps.num_eqs, dev->caps.num_eqs, 0, 0); if (err) goto err_cq; @@ -810,12 +808,12 @@ static int mlx4_setup_hca(struct mlx4_dev *dev) if (dev->flags & MLX4_FLAG_MSI_X) { mlx4_warn(dev, "NOP command failed to generate MSI-X " "interrupt IRQ %d).\n", - priv->eq_table.eq[MLX4_EQ_ASYNC].irq); + priv->eq_table.eq[dev->caps.num_comp_vectors].irq); mlx4_warn(dev, "Trying again without MSI-X.\n"); } else { mlx4_err(dev, "NOP command failed to generate interrupt " "(IRQ %d), aborting.\n", - priv->eq_table.eq[MLX4_EQ_ASYNC].irq); + priv->eq_table.eq[dev->caps.num_comp_vectors].irq); mlx4_err(dev, "BIOS or ACPI interrupt routing problem?\n"); } @@ -908,31 +906,50 @@ static int mlx4_setup_hca(struct mlx4_dev *dev) static void mlx4_enable_msi_x(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); - struct msix_entry entries[MLX4_NUM_EQ]; + struct msix_entry *entries; + int nreq; int err; int i; if (msi_x) { - for (i = 0; i < MLX4_NUM_EQ; ++i) + nreq = min(dev->caps.num_eqs - dev->caps.reserved_eqs, + num_possible_cpus() + 1); + entries = kcalloc(nreq, sizeof *entries, GFP_KERNEL); + if (!entries) + goto no_msi; + + for (i = 0; i < nreq; ++i) entries[i].entry = i; - err = pci_enable_msix(dev->pdev, entries, ARRAY_SIZE(entries)); + retry: + err = pci_enable_msix(dev->pdev, entries, nreq); if (err) { - if (err > 0) - mlx4_info(dev, "Only %d MSI-X vectors available, " - "not using MSI-X\n", err); + /* Try again if at least 2 vectors are available */ + if (err > 1) { + mlx4_info(dev, "Requested %d vectors, " + "but only %d MSI-X vectors available, " + "trying again\n", nreq, err); + nreq = err; + goto retry; + } + goto no_msi; } - for (i = 0; i < MLX4_NUM_EQ; ++i) + dev->caps.num_comp_vectors = nreq - 1; + for (i = 0; i < nreq; ++i) priv->eq_table.eq[i].irq = entries[i].vector; dev->flags |= MLX4_FLAG_MSI_X; + + kfree(entries); return; } no_msi: - for (i = 0; i < MLX4_NUM_EQ; ++i) + dev->caps.num_comp_vectors = 1; + + for (i = 0; i < 2; ++i) priv->eq_table.eq[i].irq = dev->pdev->irq; } @@ -1074,6 +1091,10 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) if (err) goto err_cmd; + err = mlx4_alloc_eq_table(dev); + if (err) + goto err_close; + mlx4_enable_msi_x(dev); err = mlx4_setup_hca(dev); @@ -1084,7 +1105,7 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) } if (err) - goto err_close; + goto err_free_eq; for (port = 1; port <= dev->caps.num_ports; port++) { err = mlx4_init_port_info(dev, port); @@ -1114,6 +1135,9 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) mlx4_cleanup_pd_table(dev); mlx4_cleanup_uar_table(dev); +err_free_eq: + mlx4_free_eq_table(dev); + err_close: if (dev->flags & MLX4_FLAG_MSI_X) pci_disable_msix(pdev); @@ -1177,6 +1201,7 @@ static void mlx4_remove_one(struct pci_dev *pdev) iounmap(priv->kar); mlx4_uar_free(dev, &priv->driver_uar); mlx4_cleanup_uar_table(dev); + mlx4_free_eq_table(dev); mlx4_close_hca(dev); mlx4_cmd_cleanup(dev); diff --git a/drivers/net/mlx4/mcg.c b/drivers/net/mlx4/mcg.c index 592c01ae2c5dc119f6c6e213126099bf0557228e..6053c357a470c27bdc1cf827d24388269f413774 100644 --- a/drivers/net/mlx4/mcg.c +++ b/drivers/net/mlx4/mcg.c @@ -118,17 +118,7 @@ static int find_mgm(struct mlx4_dev *dev, return err; if (0) - mlx4_dbg(dev, "Hash for %04x:%04x:%04x:%04x:" - "%04x:%04x:%04x:%04x is %04x\n", - be16_to_cpu(((__be16 *) gid)[0]), - be16_to_cpu(((__be16 *) gid)[1]), - be16_to_cpu(((__be16 *) gid)[2]), - be16_to_cpu(((__be16 *) gid)[3]), - be16_to_cpu(((__be16 *) gid)[4]), - be16_to_cpu(((__be16 *) gid)[5]), - be16_to_cpu(((__be16 *) gid)[6]), - be16_to_cpu(((__be16 *) gid)[7]), - *hash); + mlx4_dbg(dev, "Hash for %pI6 is %04x\n", gid, *hash); *index = *hash; *prev = -1; @@ -215,7 +205,7 @@ int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], if (block_mcast_loopback) mgm->qp[members_count++] = cpu_to_be32((qp->qpn & MGM_QPN_MASK) | - (1 << MGM_BLCK_LB_BIT)); + (1U << MGM_BLCK_LB_BIT)); else mgm->qp[members_count++] = cpu_to_be32(qp->qpn & MGM_QPN_MASK); @@ -277,16 +267,7 @@ int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16]) goto out; if (index == -1) { - mlx4_err(dev, "MGID %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x " - "not found\n", - be16_to_cpu(((__be16 *) gid)[0]), - be16_to_cpu(((__be16 *) gid)[1]), - be16_to_cpu(((__be16 *) gid)[2]), - be16_to_cpu(((__be16 *) gid)[3]), - be16_to_cpu(((__be16 *) gid)[4]), - be16_to_cpu(((__be16 *) gid)[5]), - be16_to_cpu(((__be16 *) gid)[6]), - be16_to_cpu(((__be16 *) gid)[7])); + mlx4_err(dev, "MGID %pI6 not found\n", gid); err = -EINVAL; goto out; } diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h index 34c909deaff325e9e90573065fa4d4efb45044b8..e0213bad61c7c6a7be36bcf8d93cda3d7878be37 100644 --- a/drivers/net/mlx4/mlx4.h +++ b/drivers/net/mlx4/mlx4.h @@ -62,12 +62,6 @@ enum { MLX4_MTT_ENTRY_PER_SEG = 8 }; -enum { - MLX4_EQ_ASYNC, - MLX4_EQ_COMP, - MLX4_NUM_EQ -}; - enum { MLX4_NUM_PDS = 1 << 15 }; @@ -205,10 +199,11 @@ struct mlx4_cq_table { struct mlx4_eq_table { struct mlx4_bitmap bitmap; + char *irq_names; void __iomem *clr_int; - void __iomem *uar_map[(MLX4_NUM_EQ + 6) / 4]; + void __iomem **uar_map; u32 clr_mask; - struct mlx4_eq eq[MLX4_NUM_EQ]; + struct mlx4_eq *eq; u64 icm_virt; struct page *icm_page; dma_addr_t icm_dma; @@ -328,6 +323,9 @@ void mlx4_bitmap_cleanup(struct mlx4_bitmap *bitmap); int mlx4_reset(struct mlx4_dev *dev); +int mlx4_alloc_eq_table(struct mlx4_dev *dev); +void mlx4_free_eq_table(struct mlx4_dev *dev); + int mlx4_init_pd_table(struct mlx4_dev *dev); int mlx4_init_uar_table(struct mlx4_dev *dev); int mlx4_init_mr_table(struct mlx4_dev *dev); diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h index 98ddc0811f93e78b13bd37303dd2a3c572610c67..e78209768def3d757547facacc79568cdb4a7c90 100644 --- a/drivers/net/mlx4/mlx4_en.h +++ b/drivers/net/mlx4/mlx4_en.h @@ -58,17 +58,17 @@ #define mlx4_dbg(mlevel, priv, format, arg...) \ if (NETIF_MSG_##mlevel & priv->msg_enable) \ printk(KERN_DEBUG "%s %s: " format , DRV_NAME ,\ - (&priv->mdev->pdev->dev)->bus_id , ## arg) + (dev_name(&priv->mdev->pdev->dev)) , ## arg) #define mlx4_err(mdev, format, arg...) \ printk(KERN_ERR "%s %s: " format , DRV_NAME ,\ - (&mdev->pdev->dev)->bus_id , ## arg) + (dev_name(&mdev->pdev->dev)) , ## arg) #define mlx4_info(mdev, format, arg...) \ printk(KERN_INFO "%s %s: " format , DRV_NAME ,\ - (&mdev->pdev->dev)->bus_id , ## arg) + (dev_name(&mdev->pdev->dev)) , ## arg) #define mlx4_warn(mdev, format, arg...) \ printk(KERN_WARNING "%s %s: " format , DRV_NAME ,\ - (&mdev->pdev->dev)->bus_id , ## arg) + (dev_name(&mdev->pdev->dev)) , ## arg) /* * Device constants @@ -311,7 +311,6 @@ struct mlx4_en_cq { enum cq_type is_tx; u16 moder_time; u16 moder_cnt; - int armed; struct mlx4_cqe *buf; #define MLX4_EN_OPCODE_ERROR 0x1e }; @@ -334,9 +333,6 @@ struct mlx4_en_profile { u8 rss_mask; u32 active_ports; u32 small_pkt_int; - int rx_moder_cnt; - int rx_moder_time; - int auto_moder; u8 no_reset; struct mlx4_en_port_profile prof[MLX4_MAX_PORTS + 1]; }; diff --git a/drivers/net/mlx4/profile.c b/drivers/net/mlx4/profile.c index 9ca42b213d54edf7adae086d578abd3b7ea913b8..919fb9eb1b624af90e696b8a0c67418eec3c43f0 100644 --- a/drivers/net/mlx4/profile.c +++ b/drivers/net/mlx4/profile.c @@ -107,7 +107,9 @@ u64 mlx4_make_profile(struct mlx4_dev *dev, profile[MLX4_RES_AUXC].num = request->num_qp; profile[MLX4_RES_SRQ].num = request->num_srq; profile[MLX4_RES_CQ].num = request->num_cq; - profile[MLX4_RES_EQ].num = MLX4_NUM_EQ + dev_cap->reserved_eqs; + profile[MLX4_RES_EQ].num = min(dev_cap->max_eqs, + dev_cap->reserved_eqs + + num_possible_cpus() + 1); profile[MLX4_RES_DMPT].num = request->num_mpt; profile[MLX4_RES_CMPT].num = MLX4_NUM_CMPTS; profile[MLX4_RES_MTT].num = request->num_mtt; diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index e513f76f2a9f6d1cd55cc8d190d679b36f5872da..7253a499d9c86f3ec9832c3b0190fff6d0c0e24d 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -51,8 +51,8 @@ #include #include #include -#include -#include +#include +#include #include static char mv643xx_eth_driver_name[] = "mv643xx_eth"; @@ -78,16 +78,17 @@ static char mv643xx_eth_driver_version[] = "1.4"; #define WINDOW_PROTECT(w) (0x0294 + ((w) << 4)) /* - * Per-port registers. + * Main per-port registers. These live at offset 0x0400 for + * port #0, 0x0800 for port #1, and 0x0c00 for port #2. */ -#define PORT_CONFIG(p) (0x0400 + ((p) << 10)) +#define PORT_CONFIG 0x0000 #define UNICAST_PROMISCUOUS_MODE 0x00000001 -#define PORT_CONFIG_EXT(p) (0x0404 + ((p) << 10)) -#define MAC_ADDR_LOW(p) (0x0414 + ((p) << 10)) -#define MAC_ADDR_HIGH(p) (0x0418 + ((p) << 10)) -#define SDMA_CONFIG(p) (0x041c + ((p) << 10)) -#define PORT_SERIAL_CONTROL(p) (0x043c + ((p) << 10)) -#define PORT_STATUS(p) (0x0444 + ((p) << 10)) +#define PORT_CONFIG_EXT 0x0004 +#define MAC_ADDR_LOW 0x0014 +#define MAC_ADDR_HIGH 0x0018 +#define SDMA_CONFIG 0x001c +#define PORT_SERIAL_CONTROL 0x003c +#define PORT_STATUS 0x0044 #define TX_FIFO_EMPTY 0x00000400 #define TX_IN_PROGRESS 0x00000080 #define PORT_SPEED_MASK 0x00000030 @@ -97,31 +98,35 @@ static char mv643xx_eth_driver_version[] = "1.4"; #define FLOW_CONTROL_ENABLED 0x00000008 #define FULL_DUPLEX 0x00000004 #define LINK_UP 0x00000002 -#define TXQ_COMMAND(p) (0x0448 + ((p) << 10)) -#define TXQ_FIX_PRIO_CONF(p) (0x044c + ((p) << 10)) -#define TX_BW_RATE(p) (0x0450 + ((p) << 10)) -#define TX_BW_MTU(p) (0x0458 + ((p) << 10)) -#define TX_BW_BURST(p) (0x045c + ((p) << 10)) -#define INT_CAUSE(p) (0x0460 + ((p) << 10)) +#define TXQ_COMMAND 0x0048 +#define TXQ_FIX_PRIO_CONF 0x004c +#define TX_BW_RATE 0x0050 +#define TX_BW_MTU 0x0058 +#define TX_BW_BURST 0x005c +#define INT_CAUSE 0x0060 #define INT_TX_END 0x07f80000 #define INT_RX 0x000003fc #define INT_EXT 0x00000002 -#define INT_CAUSE_EXT(p) (0x0464 + ((p) << 10)) +#define INT_CAUSE_EXT 0x0064 #define INT_EXT_LINK_PHY 0x00110000 #define INT_EXT_TX 0x000000ff -#define INT_MASK(p) (0x0468 + ((p) << 10)) -#define INT_MASK_EXT(p) (0x046c + ((p) << 10)) -#define TX_FIFO_URGENT_THRESHOLD(p) (0x0474 + ((p) << 10)) -#define TXQ_FIX_PRIO_CONF_MOVED(p) (0x04dc + ((p) << 10)) -#define TX_BW_RATE_MOVED(p) (0x04e0 + ((p) << 10)) -#define TX_BW_MTU_MOVED(p) (0x04e8 + ((p) << 10)) -#define TX_BW_BURST_MOVED(p) (0x04ec + ((p) << 10)) -#define RXQ_CURRENT_DESC_PTR(p, q) (0x060c + ((p) << 10) + ((q) << 4)) -#define RXQ_COMMAND(p) (0x0680 + ((p) << 10)) -#define TXQ_CURRENT_DESC_PTR(p, q) (0x06c0 + ((p) << 10) + ((q) << 2)) -#define TXQ_BW_TOKENS(p, q) (0x0700 + ((p) << 10) + ((q) << 4)) -#define TXQ_BW_CONF(p, q) (0x0704 + ((p) << 10) + ((q) << 4)) -#define TXQ_BW_WRR_CONF(p, q) (0x0708 + ((p) << 10) + ((q) << 4)) +#define INT_MASK 0x0068 +#define INT_MASK_EXT 0x006c +#define TX_FIFO_URGENT_THRESHOLD 0x0074 +#define TXQ_FIX_PRIO_CONF_MOVED 0x00dc +#define TX_BW_RATE_MOVED 0x00e0 +#define TX_BW_MTU_MOVED 0x00e8 +#define TX_BW_BURST_MOVED 0x00ec +#define RXQ_CURRENT_DESC_PTR(q) (0x020c + ((q) << 4)) +#define RXQ_COMMAND 0x0280 +#define TXQ_CURRENT_DESC_PTR(q) (0x02c0 + ((q) << 2)) +#define TXQ_BW_TOKENS(q) (0x0300 + ((q) << 4)) +#define TXQ_BW_CONF(q) (0x0304 + ((q) << 4)) +#define TXQ_BW_WRR_CONF(q) (0x0308 + ((q) << 4)) + +/* + * Misc per-port registers. + */ #define MIB_COUNTERS(p) (0x1000 + ((p) << 7)) #define SPECIAL_MCAST_TABLE(p) (0x1400 + ((p) << 10)) #define OTHER_MCAST_TABLE(p) (0x1500 + ((p) << 10)) @@ -138,14 +143,14 @@ static char mv643xx_eth_driver_version[] = "1.4"; #if defined(__BIG_ENDIAN) #define PORT_SDMA_CONFIG_DEFAULT_VALUE \ - RX_BURST_SIZE_16_64BIT | \ - TX_BURST_SIZE_16_64BIT + (RX_BURST_SIZE_16_64BIT | \ + TX_BURST_SIZE_16_64BIT) #elif defined(__LITTLE_ENDIAN) #define PORT_SDMA_CONFIG_DEFAULT_VALUE \ - RX_BURST_SIZE_16_64BIT | \ + (RX_BURST_SIZE_16_64BIT | \ BLM_RX_NO_SWAP | \ BLM_TX_NO_SWAP | \ - TX_BURST_SIZE_16_64BIT + TX_BURST_SIZE_16_64BIT) #else #error One of __BIG_ENDIAN or __LITTLE_ENDIAN must be defined #endif @@ -351,6 +356,7 @@ struct tx_queue { struct mv643xx_eth_private { struct mv643xx_eth_shared_private *shared; + void __iomem *base; int port_num; struct net_device *dev; @@ -401,11 +407,21 @@ static inline u32 rdl(struct mv643xx_eth_private *mp, int offset) return readl(mp->shared->base + offset); } +static inline u32 rdlp(struct mv643xx_eth_private *mp, int offset) +{ + return readl(mp->base + offset); +} + static inline void wrl(struct mv643xx_eth_private *mp, int offset, u32 data) { writel(data, mp->shared->base + offset); } +static inline void wrlp(struct mv643xx_eth_private *mp, int offset, u32 data) +{ + writel(data, mp->base + offset); +} + /* rxq/txq helper functions *************************************************/ static struct mv643xx_eth_private *rxq_to_mp(struct rx_queue *rxq) @@ -421,7 +437,7 @@ static struct mv643xx_eth_private *txq_to_mp(struct tx_queue *txq) static void rxq_enable(struct rx_queue *rxq) { struct mv643xx_eth_private *mp = rxq_to_mp(rxq); - wrl(mp, RXQ_COMMAND(mp->port_num), 1 << rxq->index); + wrlp(mp, RXQ_COMMAND, 1 << rxq->index); } static void rxq_disable(struct rx_queue *rxq) @@ -429,26 +445,25 @@ static void rxq_disable(struct rx_queue *rxq) struct mv643xx_eth_private *mp = rxq_to_mp(rxq); u8 mask = 1 << rxq->index; - wrl(mp, RXQ_COMMAND(mp->port_num), mask << 8); - while (rdl(mp, RXQ_COMMAND(mp->port_num)) & mask) + wrlp(mp, RXQ_COMMAND, mask << 8); + while (rdlp(mp, RXQ_COMMAND) & mask) udelay(10); } static void txq_reset_hw_ptr(struct tx_queue *txq) { struct mv643xx_eth_private *mp = txq_to_mp(txq); - int off = TXQ_CURRENT_DESC_PTR(mp->port_num, txq->index); u32 addr; addr = (u32)txq->tx_desc_dma; addr += txq->tx_curr_desc * sizeof(struct tx_desc); - wrl(mp, off, addr); + wrlp(mp, TXQ_CURRENT_DESC_PTR(txq->index), addr); } static void txq_enable(struct tx_queue *txq) { struct mv643xx_eth_private *mp = txq_to_mp(txq); - wrl(mp, TXQ_COMMAND(mp->port_num), 1 << txq->index); + wrlp(mp, TXQ_COMMAND, 1 << txq->index); } static void txq_disable(struct tx_queue *txq) @@ -456,8 +471,8 @@ static void txq_disable(struct tx_queue *txq) struct mv643xx_eth_private *mp = txq_to_mp(txq); u8 mask = 1 << txq->index; - wrl(mp, TXQ_COMMAND(mp->port_num), mask << 8); - while (rdl(mp, TXQ_COMMAND(mp->port_num)) & mask) + wrlp(mp, TXQ_COMMAND, mask << 8); + while (rdlp(mp, TXQ_COMMAND) & mask) udelay(10); } @@ -528,37 +543,38 @@ static int rxq_process(struct rx_queue *rxq, int budget) * on, or the error summary bit is set, the packet needs * to be dropped. */ - if (((cmd_sts & (RX_FIRST_DESC | RX_LAST_DESC)) != - (RX_FIRST_DESC | RX_LAST_DESC)) - || (cmd_sts & ERROR_SUMMARY)) { - stats->rx_dropped++; - - if ((cmd_sts & (RX_FIRST_DESC | RX_LAST_DESC)) != - (RX_FIRST_DESC | RX_LAST_DESC)) { - if (net_ratelimit()) - dev_printk(KERN_ERR, &mp->dev->dev, - "received packet spanning " - "multiple descriptors\n"); - } + if ((cmd_sts & (RX_FIRST_DESC | RX_LAST_DESC | ERROR_SUMMARY)) + != (RX_FIRST_DESC | RX_LAST_DESC)) + goto err; - if (cmd_sts & ERROR_SUMMARY) - stats->rx_errors++; + /* + * The -4 is for the CRC in the trailer of the + * received packet + */ + skb_put(skb, byte_cnt - 2 - 4); - dev_kfree_skb(skb); - } else { - /* - * The -4 is for the CRC in the trailer of the - * received packet - */ - skb_put(skb, byte_cnt - 2 - 4); - - if (cmd_sts & LAYER_4_CHECKSUM_OK) - skb->ip_summed = CHECKSUM_UNNECESSARY; - skb->protocol = eth_type_trans(skb, mp->dev); - netif_receive_skb(skb); + if (cmd_sts & LAYER_4_CHECKSUM_OK) + skb->ip_summed = CHECKSUM_UNNECESSARY; + skb->protocol = eth_type_trans(skb, mp->dev); + netif_receive_skb(skb); + + continue; + +err: + stats->rx_dropped++; + + if ((cmd_sts & (RX_FIRST_DESC | RX_LAST_DESC)) != + (RX_FIRST_DESC | RX_LAST_DESC)) { + if (net_ratelimit()) + dev_printk(KERN_ERR, &mp->dev->dev, + "received packet spanning " + "multiple descriptors\n"); } - mp->dev->last_rx = jiffies; + if (cmd_sts & ERROR_SUMMARY) + stats->rx_errors++; + + dev_kfree_skb(skb); } if (rx < budget) @@ -577,6 +593,7 @@ static int rxq_refill(struct rx_queue *rxq, int budget) struct sk_buff *skb; int unaligned; int rx; + struct rx_desc *rx_desc; skb = __skb_dequeue(&mp->rx_recycle); if (skb == NULL) @@ -599,13 +616,14 @@ static int rxq_refill(struct rx_queue *rxq, int budget) if (rxq->rx_used_desc == rxq->rx_ring_size) rxq->rx_used_desc = 0; - rxq->rx_desc_area[rx].buf_ptr = dma_map_single(NULL, skb->data, - mp->skb_size, DMA_FROM_DEVICE); - rxq->rx_desc_area[rx].buf_size = mp->skb_size; + rx_desc = rxq->rx_desc_area + rx; + + rx_desc->buf_ptr = dma_map_single(NULL, skb->data, + mp->skb_size, DMA_FROM_DEVICE); + rx_desc->buf_size = mp->skb_size; rxq->rx_skb[rx] = skb; wmb(); - rxq->rx_desc_area[rx].cmd_sts = BUFFER_OWNED_BY_DMA | - RX_ENABLE_INTERRUPT; + rx_desc->cmd_sts = BUFFER_OWNED_BY_DMA | RX_ENABLE_INTERRUPT; wmb(); /* @@ -638,21 +656,6 @@ static inline unsigned int has_tiny_unaligned_frags(struct sk_buff *skb) return 0; } -static int txq_alloc_desc_index(struct tx_queue *txq) -{ - int tx_desc_curr; - - BUG_ON(txq->tx_desc_count >= txq->tx_ring_size); - - tx_desc_curr = txq->tx_curr_desc++; - if (txq->tx_curr_desc == txq->tx_ring_size) - txq->tx_curr_desc = 0; - - BUG_ON(txq->tx_curr_desc == txq->tx_used_desc); - - return tx_desc_curr; -} - static void txq_submit_frag_skb(struct tx_queue *txq, struct sk_buff *skb) { int nr_frags = skb_shinfo(skb)->nr_frags; @@ -664,7 +667,9 @@ static void txq_submit_frag_skb(struct tx_queue *txq, struct sk_buff *skb) struct tx_desc *desc; this_frag = &skb_shinfo(skb)->frags[frag]; - tx_index = txq_alloc_desc_index(txq); + tx_index = txq->tx_curr_desc++; + if (txq->tx_curr_desc == txq->tx_ring_size) + txq->tx_curr_desc = 0; desc = &txq->tx_desc_area[tx_index]; /* @@ -746,7 +751,9 @@ static int txq_submit_skb(struct tx_queue *txq, struct sk_buff *skb) cmd_sts |= 5 << TX_IHL_SHIFT; } - tx_index = txq_alloc_desc_index(txq); + tx_index = txq->tx_curr_desc++; + if (txq->tx_curr_desc == txq->tx_ring_size) + txq->tx_curr_desc = 0; desc = &txq->tx_desc_area[tx_index]; if (nr_frags) { @@ -831,10 +838,10 @@ static void txq_kick(struct tx_queue *txq) __netif_tx_lock(nq, smp_processor_id()); - if (rdl(mp, TXQ_COMMAND(mp->port_num)) & (1 << txq->index)) + if (rdlp(mp, TXQ_COMMAND) & (1 << txq->index)) goto out; - hw_desc_ptr = rdl(mp, TXQ_CURRENT_DESC_PTR(mp->port_num, txq->index)); + hw_desc_ptr = rdlp(mp, TXQ_CURRENT_DESC_PTR(txq->index)); expected_ptr = (u32)txq->tx_desc_dma + txq->tx_curr_desc * sizeof(struct tx_desc); @@ -941,14 +948,14 @@ static void tx_set_rate(struct mv643xx_eth_private *mp, int rate, int burst) switch (mp->shared->tx_bw_control) { case TX_BW_CONTROL_OLD_LAYOUT: - wrl(mp, TX_BW_RATE(mp->port_num), token_rate); - wrl(mp, TX_BW_MTU(mp->port_num), mtu); - wrl(mp, TX_BW_BURST(mp->port_num), bucket_size); + wrlp(mp, TX_BW_RATE, token_rate); + wrlp(mp, TX_BW_MTU, mtu); + wrlp(mp, TX_BW_BURST, bucket_size); break; case TX_BW_CONTROL_NEW_LAYOUT: - wrl(mp, TX_BW_RATE_MOVED(mp->port_num), token_rate); - wrl(mp, TX_BW_MTU_MOVED(mp->port_num), mtu); - wrl(mp, TX_BW_BURST_MOVED(mp->port_num), bucket_size); + wrlp(mp, TX_BW_RATE_MOVED, token_rate); + wrlp(mp, TX_BW_MTU_MOVED, mtu); + wrlp(mp, TX_BW_BURST_MOVED, bucket_size); break; } } @@ -967,9 +974,8 @@ static void txq_set_rate(struct tx_queue *txq, int rate, int burst) if (bucket_size > 65535) bucket_size = 65535; - wrl(mp, TXQ_BW_TOKENS(mp->port_num, txq->index), token_rate << 14); - wrl(mp, TXQ_BW_CONF(mp->port_num, txq->index), - (bucket_size << 10) | token_rate); + wrlp(mp, TXQ_BW_TOKENS(txq->index), token_rate << 14); + wrlp(mp, TXQ_BW_CONF(txq->index), (bucket_size << 10) | token_rate); } static void txq_set_fixed_prio_mode(struct tx_queue *txq) @@ -984,17 +990,17 @@ static void txq_set_fixed_prio_mode(struct tx_queue *txq) off = 0; switch (mp->shared->tx_bw_control) { case TX_BW_CONTROL_OLD_LAYOUT: - off = TXQ_FIX_PRIO_CONF(mp->port_num); + off = TXQ_FIX_PRIO_CONF; break; case TX_BW_CONTROL_NEW_LAYOUT: - off = TXQ_FIX_PRIO_CONF_MOVED(mp->port_num); + off = TXQ_FIX_PRIO_CONF_MOVED; break; } if (off) { - val = rdl(mp, off); + val = rdlp(mp, off); val |= 1 << txq->index; - wrl(mp, off, val); + wrlp(mp, off, val); } } @@ -1010,26 +1016,25 @@ static void txq_set_wrr(struct tx_queue *txq, int weight) off = 0; switch (mp->shared->tx_bw_control) { case TX_BW_CONTROL_OLD_LAYOUT: - off = TXQ_FIX_PRIO_CONF(mp->port_num); + off = TXQ_FIX_PRIO_CONF; break; case TX_BW_CONTROL_NEW_LAYOUT: - off = TXQ_FIX_PRIO_CONF_MOVED(mp->port_num); + off = TXQ_FIX_PRIO_CONF_MOVED; break; } if (off) { - val = rdl(mp, off); + val = rdlp(mp, off); val &= ~(1 << txq->index); - wrl(mp, off, val); + wrlp(mp, off, val); /* * Configure WRR weight for this queue. */ - off = TXQ_BW_WRR_CONF(mp->port_num, txq->index); - val = rdl(mp, off); + val = rdlp(mp, off); val = (val & ~0xff) | (weight & 0xff); - wrl(mp, off, val); + wrlp(mp, TXQ_BW_WRR_CONF(txq->index), val); } } @@ -1084,20 +1089,20 @@ static int smi_bus_read(struct mii_bus *bus, int addr, int reg) int ret; if (smi_wait_ready(msp)) { - printk("mv643xx_eth: SMI bus busy timeout\n"); + printk(KERN_WARNING "mv643xx_eth: SMI bus busy timeout\n"); return -ETIMEDOUT; } writel(SMI_OPCODE_READ | (reg << 21) | (addr << 16), smi_reg); if (smi_wait_ready(msp)) { - printk("mv643xx_eth: SMI bus busy timeout\n"); + printk(KERN_WARNING "mv643xx_eth: SMI bus busy timeout\n"); return -ETIMEDOUT; } ret = readl(smi_reg); if (!(ret & SMI_READ_VALID)) { - printk("mv643xx_eth: SMI bus read not valid\n"); + printk(KERN_WARNING "mv643xx_eth: SMI bus read not valid\n"); return -ENODEV; } @@ -1110,7 +1115,7 @@ static int smi_bus_write(struct mii_bus *bus, int addr, int reg, u16 val) void __iomem *smi_reg = msp->base + SMI_REG; if (smi_wait_ready(msp)) { - printk("mv643xx_eth: SMI bus busy timeout\n"); + printk(KERN_WARNING "mv643xx_eth: SMI bus busy timeout\n"); return -ETIMEDOUT; } @@ -1118,7 +1123,7 @@ static int smi_bus_write(struct mii_bus *bus, int addr, int reg, u16 val) (addr << 16) | (val & 0xffff), smi_reg); if (smi_wait_ready(msp)) { - printk("mv643xx_eth: SMI bus busy timeout\n"); + printk(KERN_WARNING "mv643xx_eth: SMI bus busy timeout\n"); return -ETIMEDOUT; } @@ -1271,7 +1276,8 @@ static const struct mv643xx_eth_stats mv643xx_eth_stats[] = { MIBSTAT(late_collision), }; -static int mv643xx_eth_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +static int +mv643xx_eth_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct mv643xx_eth_private *mp = netdev_priv(dev); int err; @@ -1289,12 +1295,14 @@ static int mv643xx_eth_get_settings(struct net_device *dev, struct ethtool_cmd * return err; } -static int mv643xx_eth_get_settings_phyless(struct net_device *dev, struct ethtool_cmd *cmd) +static int +mv643xx_eth_get_settings_phyless(struct net_device *dev, + struct ethtool_cmd *cmd) { struct mv643xx_eth_private *mp = netdev_priv(dev); u32 port_status; - port_status = rdl(mp, PORT_STATUS(mp->port_num)); + port_status = rdlp(mp, PORT_STATUS); cmd->supported = SUPPORTED_MII; cmd->advertising = ADVERTISED_MII; @@ -1323,7 +1331,8 @@ static int mv643xx_eth_get_settings_phyless(struct net_device *dev, struct ethto return 0; } -static int mv643xx_eth_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +static int +mv643xx_eth_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct mv643xx_eth_private *mp = netdev_priv(dev); @@ -1335,7 +1344,9 @@ static int mv643xx_eth_set_settings(struct net_device *dev, struct ethtool_cmd * return phy_ethtool_sset(mp->phy, cmd); } -static int mv643xx_eth_set_settings_phyless(struct net_device *dev, struct ethtool_cmd *cmd) +static int +mv643xx_eth_set_settings_phyless(struct net_device *dev, + struct ethtool_cmd *cmd) { return -EINVAL; } @@ -1443,11 +1454,8 @@ static const struct ethtool_ops mv643xx_eth_ethtool_ops_phyless = { /* address handling *********************************************************/ static void uc_addr_get(struct mv643xx_eth_private *mp, unsigned char *addr) { - unsigned int mac_h; - unsigned int mac_l; - - mac_h = rdl(mp, MAC_ADDR_HIGH(mp->port_num)); - mac_l = rdl(mp, MAC_ADDR_LOW(mp->port_num)); + unsigned int mac_h = rdlp(mp, MAC_ADDR_HIGH); + unsigned int mac_l = rdlp(mp, MAC_ADDR_LOW); addr[0] = (mac_h >> 24) & 0xff; addr[1] = (mac_h >> 16) & 0xff; @@ -1457,57 +1465,71 @@ static void uc_addr_get(struct mv643xx_eth_private *mp, unsigned char *addr) addr[5] = mac_l & 0xff; } -static void init_mac_tables(struct mv643xx_eth_private *mp) +static void uc_addr_set(struct mv643xx_eth_private *mp, unsigned char *addr) { - int i; - - for (i = 0; i < 0x100; i += 4) { - wrl(mp, SPECIAL_MCAST_TABLE(mp->port_num) + i, 0); - wrl(mp, OTHER_MCAST_TABLE(mp->port_num) + i, 0); - } - - for (i = 0; i < 0x10; i += 4) - wrl(mp, UNICAST_TABLE(mp->port_num) + i, 0); + wrlp(mp, MAC_ADDR_HIGH, + (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3]); + wrlp(mp, MAC_ADDR_LOW, (addr[4] << 8) | addr[5]); } -static void set_filter_table_entry(struct mv643xx_eth_private *mp, - int table, unsigned char entry) +static u32 uc_addr_filter_mask(struct net_device *dev) { - unsigned int table_reg; - - /* Set "accepts frame bit" at specified table entry */ - table_reg = rdl(mp, table + (entry & 0xfc)); - table_reg |= 0x01 << (8 * (entry & 3)); - wrl(mp, table + (entry & 0xfc), table_reg); -} + struct dev_addr_list *uc_ptr; + u32 nibbles; -static void uc_addr_set(struct mv643xx_eth_private *mp, unsigned char *addr) -{ - unsigned int mac_h; - unsigned int mac_l; - int table; + if (dev->flags & IFF_PROMISC) + return 0; - mac_l = (addr[4] << 8) | addr[5]; - mac_h = (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3]; + nibbles = 1 << (dev->dev_addr[5] & 0x0f); + for (uc_ptr = dev->uc_list; uc_ptr != NULL; uc_ptr = uc_ptr->next) { + if (memcmp(dev->dev_addr, uc_ptr->da_addr, 5)) + return 0; + if ((dev->dev_addr[5] ^ uc_ptr->da_addr[5]) & 0xf0) + return 0; - wrl(mp, MAC_ADDR_LOW(mp->port_num), mac_l); - wrl(mp, MAC_ADDR_HIGH(mp->port_num), mac_h); + nibbles |= 1 << (uc_ptr->da_addr[5] & 0x0f); + } - table = UNICAST_TABLE(mp->port_num); - set_filter_table_entry(mp, table, addr[5] & 0x0f); + return nibbles; } -static int mv643xx_eth_set_mac_address(struct net_device *dev, void *addr) +static void mv643xx_eth_program_unicast_filter(struct net_device *dev) { struct mv643xx_eth_private *mp = netdev_priv(dev); + u32 port_config; + u32 nibbles; + int i; - /* +2 is for the offset of the HW addr type */ - memcpy(dev->dev_addr, addr + 2, 6); - - init_mac_tables(mp); uc_addr_set(mp, dev->dev_addr); - return 0; + port_config = rdlp(mp, PORT_CONFIG); + nibbles = uc_addr_filter_mask(dev); + if (!nibbles) { + port_config |= UNICAST_PROMISCUOUS_MODE; + wrlp(mp, PORT_CONFIG, port_config); + return; + } + + for (i = 0; i < 16; i += 4) { + int off = UNICAST_TABLE(mp->port_num) + i; + u32 v; + + v = 0; + if (nibbles & 1) + v |= 0x00000001; + if (nibbles & 2) + v |= 0x00000100; + if (nibbles & 4) + v |= 0x00010000; + if (nibbles & 8) + v |= 0x01000000; + nibbles >>= 4; + + wrl(mp, off, v); + } + + port_config &= ~UNICAST_PROMISCUOUS_MODE; + wrlp(mp, PORT_CONFIG, port_config); } static int addr_crc(unsigned char *addr) @@ -1528,24 +1550,22 @@ static int addr_crc(unsigned char *addr) return crc; } -static void mv643xx_eth_set_rx_mode(struct net_device *dev) +static void mv643xx_eth_program_multicast_filter(struct net_device *dev) { struct mv643xx_eth_private *mp = netdev_priv(dev); - u32 port_config; + u32 *mc_spec; + u32 *mc_other; struct dev_addr_list *addr; int i; - port_config = rdl(mp, PORT_CONFIG(mp->port_num)); - if (dev->flags & IFF_PROMISC) - port_config |= UNICAST_PROMISCUOUS_MODE; - else - port_config &= ~UNICAST_PROMISCUOUS_MODE; - wrl(mp, PORT_CONFIG(mp->port_num), port_config); - if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) { - int port_num = mp->port_num; - u32 accept = 0x01010101; + int port_num; + u32 accept; + int i; +oom: + port_num = mp->port_num; + accept = 0x01010101; for (i = 0; i < 0x100; i += 4) { wrl(mp, SPECIAL_MCAST_TABLE(port_num) + i, accept); wrl(mp, OTHER_MCAST_TABLE(port_num) + i, accept); @@ -1553,28 +1573,55 @@ static void mv643xx_eth_set_rx_mode(struct net_device *dev) return; } - for (i = 0; i < 0x100; i += 4) { - wrl(mp, SPECIAL_MCAST_TABLE(mp->port_num) + i, 0); - wrl(mp, OTHER_MCAST_TABLE(mp->port_num) + i, 0); - } + mc_spec = kmalloc(0x200, GFP_KERNEL); + if (mc_spec == NULL) + goto oom; + mc_other = mc_spec + (0x100 >> 2); + + memset(mc_spec, 0, 0x100); + memset(mc_other, 0, 0x100); for (addr = dev->mc_list; addr != NULL; addr = addr->next) { u8 *a = addr->da_addr; - int table; - - if (addr->da_addrlen != 6) - continue; + u32 *table; + int entry; if (memcmp(a, "\x01\x00\x5e\x00\x00", 5) == 0) { - table = SPECIAL_MCAST_TABLE(mp->port_num); - set_filter_table_entry(mp, table, a[5]); + table = mc_spec; + entry = a[5]; } else { - int crc = addr_crc(a); - - table = OTHER_MCAST_TABLE(mp->port_num); - set_filter_table_entry(mp, table, crc); + table = mc_other; + entry = addr_crc(a); } + + table[entry >> 2] |= 1 << (entry & 3); } + + for (i = 0; i < 0x100; i += 4) { + wrl(mp, SPECIAL_MCAST_TABLE(mp->port_num) + i, mc_spec[i >> 2]); + wrl(mp, OTHER_MCAST_TABLE(mp->port_num) + i, mc_other[i >> 2]); + } + + kfree(mc_spec); +} + +static void mv643xx_eth_set_rx_mode(struct net_device *dev) +{ + mv643xx_eth_program_unicast_filter(dev); + mv643xx_eth_program_multicast_filter(dev); +} + +static int mv643xx_eth_set_mac_address(struct net_device *dev, void *addr) +{ + struct sockaddr *sa = addr; + + memcpy(dev->dev_addr, sa->sa_data, ETH_ALEN); + + netif_addr_lock_bh(dev); + mv643xx_eth_program_unicast_filter(dev); + netif_addr_unlock_bh(dev); + + return 0; } @@ -1758,26 +1805,25 @@ static int mv643xx_eth_collect_events(struct mv643xx_eth_private *mp) u32 int_cause; u32 int_cause_ext; - int_cause = rdl(mp, INT_CAUSE(mp->port_num)) & - (INT_TX_END | INT_RX | INT_EXT); + int_cause = rdlp(mp, INT_CAUSE) & (INT_TX_END | INT_RX | INT_EXT); if (int_cause == 0) return 0; int_cause_ext = 0; if (int_cause & INT_EXT) - int_cause_ext = rdl(mp, INT_CAUSE_EXT(mp->port_num)); + int_cause_ext = rdlp(mp, INT_CAUSE_EXT); int_cause &= INT_TX_END | INT_RX; if (int_cause) { - wrl(mp, INT_CAUSE(mp->port_num), ~int_cause); + wrlp(mp, INT_CAUSE, ~int_cause); mp->work_tx_end |= ((int_cause & INT_TX_END) >> 19) & - ~(rdl(mp, TXQ_COMMAND(mp->port_num)) & 0xff); + ~(rdlp(mp, TXQ_COMMAND) & 0xff); mp->work_rx |= (int_cause & INT_RX) >> 2; } int_cause_ext &= INT_EXT_LINK_PHY | INT_EXT_TX; if (int_cause_ext) { - wrl(mp, INT_CAUSE_EXT(mp->port_num), ~int_cause_ext); + wrlp(mp, INT_CAUSE_EXT, ~int_cause_ext); if (int_cause_ext & INT_EXT_LINK_PHY) mp->work_link = 1; mp->work_tx |= int_cause_ext & INT_EXT_TX; @@ -1794,7 +1840,7 @@ static irqreturn_t mv643xx_eth_irq(int irq, void *dev_id) if (unlikely(!mv643xx_eth_collect_events(mp))) return IRQ_NONE; - wrl(mp, INT_MASK(mp->port_num), 0); + wrlp(mp, INT_MASK, 0); napi_schedule(&mp->napi); return IRQ_HANDLED; @@ -1808,7 +1854,7 @@ static void handle_link_event(struct mv643xx_eth_private *mp) int duplex; int fc; - port_status = rdl(mp, PORT_STATUS(mp->port_num)); + port_status = rdlp(mp, PORT_STATUS); if (!(port_status & LINK_UP)) { if (netif_carrier_ok(dev)) { int i; @@ -1908,7 +1954,7 @@ static int mv643xx_eth_poll(struct napi_struct *napi, int budget) if (mp->work_rx_oom) mod_timer(&mp->rx_oom, jiffies + (HZ / 10)); napi_complete(napi); - wrl(mp, INT_MASK(mp->port_num), INT_TX_END | INT_RX | INT_EXT); + wrlp(mp, INT_MASK, INT_TX_END | INT_RX | INT_EXT); } return work_done; @@ -1957,17 +2003,17 @@ static void port_start(struct mv643xx_eth_private *mp) /* * Configure basic link parameters. */ - pscr = rdl(mp, PORT_SERIAL_CONTROL(mp->port_num)); + pscr = rdlp(mp, PORT_SERIAL_CONTROL); pscr |= SERIAL_PORT_ENABLE; - wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr); + wrlp(mp, PORT_SERIAL_CONTROL, pscr); pscr |= DO_NOT_FORCE_LINK_FAIL; if (mp->phy == NULL) pscr |= FORCE_LINK_PASS; - wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr); + wrlp(mp, PORT_SERIAL_CONTROL, pscr); - wrl(mp, SDMA_CONFIG(mp->port_num), PORT_SDMA_CONFIG_DEFAULT_VALUE); + wrlp(mp, SDMA_CONFIG, PORT_SDMA_CONFIG_DEFAULT_VALUE); /* * Configure TX path and queues. @@ -1984,31 +2030,30 @@ static void port_start(struct mv643xx_eth_private *mp) /* * Add configured unicast address to address filter table. */ - uc_addr_set(mp, mp->dev->dev_addr); + mv643xx_eth_program_unicast_filter(mp->dev); /* * Receive all unmatched unicast, TCP, UDP, BPDU and broadcast * frames to RX queue #0, and include the pseudo-header when * calculating receive checksums. */ - wrl(mp, PORT_CONFIG(mp->port_num), 0x02000000); + wrlp(mp, PORT_CONFIG, 0x02000000); /* * Treat BPDUs as normal multicasts, and disable partition mode. */ - wrl(mp, PORT_CONFIG_EXT(mp->port_num), 0x00000000); + wrlp(mp, PORT_CONFIG_EXT, 0x00000000); /* * Enable the receive queues. */ for (i = 0; i < mp->rxq_count; i++) { struct rx_queue *rxq = mp->rxq + i; - int off = RXQ_CURRENT_DESC_PTR(mp->port_num, i); u32 addr; addr = (u32)rxq->rx_desc_dma; addr += rxq->rx_curr_desc * sizeof(struct rx_desc); - wrl(mp, off, addr); + wrlp(mp, RXQ_CURRENT_DESC_PTR(i), addr); rxq_enable(rxq); } @@ -2019,7 +2064,7 @@ static void set_rx_coal(struct mv643xx_eth_private *mp, unsigned int delay) unsigned int coal = ((mp->shared->t_clk / 1000000) * delay) / 64; u32 val; - val = rdl(mp, SDMA_CONFIG(mp->port_num)); + val = rdlp(mp, SDMA_CONFIG); if (mp->shared->extended_rx_coal_limit) { if (coal > 0xffff) coal = 0xffff; @@ -2032,7 +2077,7 @@ static void set_rx_coal(struct mv643xx_eth_private *mp, unsigned int delay) val &= ~0x003fff00; val |= (coal & 0x3fff) << 8; } - wrl(mp, SDMA_CONFIG(mp->port_num), val); + wrlp(mp, SDMA_CONFIG, val); } static void set_tx_coal(struct mv643xx_eth_private *mp, unsigned int delay) @@ -2041,7 +2086,7 @@ static void set_tx_coal(struct mv643xx_eth_private *mp, unsigned int delay) if (coal > 0x3fff) coal = 0x3fff; - wrl(mp, TX_FIFO_URGENT_THRESHOLD(mp->port_num), (coal & 0x3fff) << 4); + wrlp(mp, TX_FIFO_URGENT_THRESHOLD, (coal & 0x3fff) << 4); } static void mv643xx_eth_recalc_skb_size(struct mv643xx_eth_private *mp) @@ -2070,9 +2115,9 @@ static int mv643xx_eth_open(struct net_device *dev) int err; int i; - wrl(mp, INT_CAUSE(mp->port_num), 0); - wrl(mp, INT_CAUSE_EXT(mp->port_num), 0); - rdl(mp, INT_CAUSE_EXT(mp->port_num)); + wrlp(mp, INT_CAUSE, 0); + wrlp(mp, INT_CAUSE_EXT, 0); + rdlp(mp, INT_CAUSE_EXT); err = request_irq(dev->irq, mv643xx_eth_irq, IRQF_SHARED, dev->name, dev); @@ -2081,8 +2126,6 @@ static int mv643xx_eth_open(struct net_device *dev) return -EAGAIN; } - init_mac_tables(mp); - mv643xx_eth_recalc_skb_size(mp); napi_enable(&mp->napi); @@ -2121,8 +2164,8 @@ static int mv643xx_eth_open(struct net_device *dev) set_rx_coal(mp, 0); set_tx_coal(mp, 0); - wrl(mp, INT_MASK_EXT(mp->port_num), INT_EXT_LINK_PHY | INT_EXT_TX); - wrl(mp, INT_MASK(mp->port_num), INT_TX_END | INT_RX | INT_EXT); + wrlp(mp, INT_MASK_EXT, INT_EXT_LINK_PHY | INT_EXT_TX); + wrlp(mp, INT_MASK, INT_TX_END | INT_RX | INT_EXT); return 0; @@ -2147,7 +2190,7 @@ static void port_reset(struct mv643xx_eth_private *mp) txq_disable(mp->txq + i); while (1) { - u32 ps = rdl(mp, PORT_STATUS(mp->port_num)); + u32 ps = rdlp(mp, PORT_STATUS); if ((ps & (TX_IN_PROGRESS | TX_FIFO_EMPTY)) == TX_FIFO_EMPTY) break; @@ -2155,11 +2198,11 @@ static void port_reset(struct mv643xx_eth_private *mp) } /* Reset the Enable bit in the Configuration Register */ - data = rdl(mp, PORT_SERIAL_CONTROL(mp->port_num)); + data = rdlp(mp, PORT_SERIAL_CONTROL); data &= ~(SERIAL_PORT_ENABLE | DO_NOT_FORCE_LINK_FAIL | FORCE_LINK_PASS); - wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), data); + wrlp(mp, PORT_SERIAL_CONTROL, data); } static int mv643xx_eth_stop(struct net_device *dev) @@ -2167,8 +2210,8 @@ static int mv643xx_eth_stop(struct net_device *dev) struct mv643xx_eth_private *mp = netdev_priv(dev); int i; - wrl(mp, INT_MASK(mp->port_num), 0x00000000); - rdl(mp, INT_MASK(mp->port_num)); + wrlp(mp, INT_MASK, 0x00000000); + rdlp(mp, INT_MASK); del_timer_sync(&mp->mib_counters_timer); @@ -2261,12 +2304,12 @@ static void mv643xx_eth_netpoll(struct net_device *dev) { struct mv643xx_eth_private *mp = netdev_priv(dev); - wrl(mp, INT_MASK(mp->port_num), 0x00000000); - rdl(mp, INT_MASK(mp->port_num)); + wrlp(mp, INT_MASK, 0x00000000); + rdlp(mp, INT_MASK); mv643xx_eth_irq(dev->irq, dev); - wrl(mp, INT_MASK(mp->port_num), INT_TX_END | INT_RX | INT_EXT); + wrlp(mp, INT_MASK, INT_TX_END | INT_RX | INT_EXT); } #endif @@ -2314,8 +2357,8 @@ static void infer_hw_params(struct mv643xx_eth_shared_private *msp) * [21:8], or a 16-bit coal limit in bits [25,21:7] of the * SDMA config register. */ - writel(0x02000000, msp->base + SDMA_CONFIG(0)); - if (readl(msp->base + SDMA_CONFIG(0)) & 0x02000000) + writel(0x02000000, msp->base + 0x0400 + SDMA_CONFIG); + if (readl(msp->base + 0x0400 + SDMA_CONFIG) & 0x02000000) msp->extended_rx_coal_limit = 1; else msp->extended_rx_coal_limit = 0; @@ -2325,12 +2368,12 @@ static void infer_hw_params(struct mv643xx_eth_shared_private *msp) * yes, whether its associated registers are in the old or * the new place. */ - writel(1, msp->base + TX_BW_MTU_MOVED(0)); - if (readl(msp->base + TX_BW_MTU_MOVED(0)) & 1) { + writel(1, msp->base + 0x0400 + TX_BW_MTU_MOVED); + if (readl(msp->base + 0x0400 + TX_BW_MTU_MOVED) & 1) { msp->tx_bw_control = TX_BW_CONTROL_NEW_LAYOUT; } else { - writel(7, msp->base + TX_BW_RATE(0)); - if (readl(msp->base + TX_BW_RATE(0)) & 7) + writel(7, msp->base + 0x0400 + TX_BW_RATE); + if (readl(msp->base + 0x0400 + TX_BW_RATE) & 7) msp->tx_bw_control = TX_BW_CONTROL_OLD_LAYOUT; else msp->tx_bw_control = TX_BW_CONTROL_ABSENT; @@ -2339,7 +2382,7 @@ static void infer_hw_params(struct mv643xx_eth_shared_private *msp) static int mv643xx_eth_shared_probe(struct platform_device *pdev) { - static int mv643xx_eth_version_printed = 0; + static int mv643xx_eth_version_printed; struct mv643xx_eth_shared_platform_data *pd = pdev->dev.platform_data; struct mv643xx_eth_shared_private *msp; struct resource *res; @@ -2563,10 +2606,10 @@ static void init_pscr(struct mv643xx_eth_private *mp, int speed, int duplex) { u32 pscr; - pscr = rdl(mp, PORT_SERIAL_CONTROL(mp->port_num)); + pscr = rdlp(mp, PORT_SERIAL_CONTROL); if (pscr & SERIAL_PORT_ENABLE) { pscr &= ~SERIAL_PORT_ENABLE; - wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr); + wrlp(mp, PORT_SERIAL_CONTROL, pscr); } pscr = MAX_RX_PACKET_9700BYTE | SERIAL_PORT_CONTROL_RESERVED; @@ -2584,7 +2627,7 @@ static void init_pscr(struct mv643xx_eth_private *mp, int speed, int duplex) pscr |= SET_FULL_DUPLEX_MODE; } - wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr); + wrlp(mp, PORT_SERIAL_CONTROL, pscr); } static int mv643xx_eth_probe(struct platform_device *pdev) @@ -2593,7 +2636,6 @@ static int mv643xx_eth_probe(struct platform_device *pdev) struct mv643xx_eth_private *mp; struct net_device *dev; struct resource *res; - DECLARE_MAC_BUF(mac); int err; pd = pdev->dev.platform_data; @@ -2617,6 +2659,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev) platform_set_drvdata(pdev, mp); mp->shared = platform_get_drvdata(pd->shared); + mp->base = mp->shared->base + 0x0400 + (pd->port_number << 10); mp->port_num = pd->port_number; mp->dev = dev; @@ -2664,7 +2707,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev) dev->hard_start_xmit = mv643xx_eth_xmit; dev->open = mv643xx_eth_open; dev->stop = mv643xx_eth_stop; - dev->set_multicast_list = mv643xx_eth_set_rx_mode; + dev->set_rx_mode = mv643xx_eth_set_rx_mode; dev->set_mac_address = mv643xx_eth_set_mac_address; dev->do_ioctl = mv643xx_eth_ioctl; dev->change_mtu = mv643xx_eth_change_mtu; @@ -2687,8 +2730,8 @@ static int mv643xx_eth_probe(struct platform_device *pdev) if (err) goto out; - dev_printk(KERN_NOTICE, &dev->dev, "port %d with MAC address %s\n", - mp->port_num, print_mac(mac, dev->dev_addr)); + dev_printk(KERN_NOTICE, &dev->dev, "port %d with MAC address %pM\n", + mp->port_num, dev->dev_addr); if (mp->tx_desc_sram_size > 0) dev_printk(KERN_NOTICE, &dev->dev, "configured with sram\n"); @@ -2721,8 +2764,8 @@ static void mv643xx_eth_shutdown(struct platform_device *pdev) struct mv643xx_eth_private *mp = platform_get_drvdata(pdev); /* Mask all interrupts on ethernet port */ - wrl(mp, INT_MASK(mp->port_num), 0); - rdl(mp, INT_MASK(mp->port_num)); + wrlp(mp, INT_MASK, 0); + rdlp(mp, INT_MASK); if (netif_running(mp->dev)) port_reset(mp); diff --git a/drivers/net/mvme147.c b/drivers/net/mvme147.c index 06ca4252155f40920902acae2900b76516533f0d..435e5a847c43c972cc24e9c5ab179191c113dc43 100644 --- a/drivers/net/mvme147.c +++ b/drivers/net/mvme147.c @@ -67,7 +67,6 @@ struct net_device * __init mvme147lance_probe(int unit) u_long *addr; u_long address; int err; - DECLARE_MAC_BUF(mac); if (!MACH_IS_MVME147 || called) return ERR_PTR(-ENODEV); @@ -102,11 +101,11 @@ struct net_device * __init mvme147lance_probe(int unit) dev->dev_addr[3]=address&0xff; printk("%s: MVME147 at 0x%08lx, irq %d, " - "Hardware Address %s\n", + "Hardware Address %pM\n", dev->name, dev->base_addr, MVME147_LANCE_IRQ, - print_mac(mac, dev->dev_addr)); + dev->dev_addr); - lp = (struct m147lance_private *)dev->priv; + lp = netdev_priv(dev); lp->ram = __get_dma_pages(GFP_ATOMIC, 3); /* 16K */ if (!lp->ram) { @@ -190,7 +189,7 @@ int __init init_module(void) void __exit cleanup_module(void) { - struct m147lance_private *lp = dev_mvme147_lance->priv; + struct m147lance_private *lp = netdev_priv(dev_mvme147_lance); unregister_netdev(dev_mvme147_lance); free_pages(lp->ram, 3); free_netdev(dev_mvme147_lance); diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index b3786709730811c2b6467cabda06c55d2203ddb1..5e70180bf5693bdf0096164c8bb26b9bf23d3634 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -75,7 +75,7 @@ #include "myri10ge_mcp.h" #include "myri10ge_mcp_gen_header.h" -#define MYRI10GE_VERSION_STR "1.4.3-1.378" +#define MYRI10GE_VERSION_STR "1.4.4-1.395" MODULE_DESCRIPTION("Myricom 10G driver (10GbE)"); MODULE_AUTHOR("Maintainer: help@myri.com"); @@ -1024,7 +1024,7 @@ static int myri10ge_reset(struct myri10ge_priv *mgp) ss->dca_tag = NULL; } } -#endif /* CONFIG_DCA */ +#endif /* CONFIG_MYRI10GE_DCA */ /* reset mcp/driver shared state back to 0 */ @@ -1121,7 +1121,7 @@ static int myri10ge_notify_dca_device(struct device *dev, void *data) myri10ge_teardown_dca(mgp); return 0; } -#endif /* CONFIG_DCA */ +#endif /* CONFIG_MYRI10GE_DCA */ static inline void myri10ge_submit_8rx(struct mcp_kreq_ether_recv __iomem * dst, @@ -1309,7 +1309,7 @@ myri10ge_rx_done(struct myri10ge_slice_state *ss, struct myri10ge_rx_buf *rx, skb = netdev_alloc_skb(dev, MYRI10GE_HLEN + 16); if (unlikely(skb == NULL)) { - mgp->stats.rx_dropped++; + ss->stats.rx_dropped++; do { i--; put_page(rx_frags[i].page); @@ -1334,7 +1334,6 @@ myri10ge_rx_done(struct myri10ge_slice_state *ss, struct myri10ge_rx_buf *rx, myri10ge_vlan_ip_csum(skb, csum); } netif_receive_skb(skb); - dev->last_rx = jiffies; return 1; } @@ -1504,7 +1503,6 @@ static int myri10ge_poll(struct napi_struct *napi, int budget) { struct myri10ge_slice_state *ss = container_of(napi, struct myri10ge_slice_state, napi); - struct net_device *netdev = ss->mgp->dev; int work_done; #ifdef CONFIG_MYRI10GE_DCA @@ -1516,7 +1514,7 @@ static int myri10ge_poll(struct napi_struct *napi, int budget) work_done = myri10ge_clean_rx_done(ss, budget); if (work_done < budget) { - netif_rx_complete(netdev, napi); + netif_rx_complete(napi); put_be32(htonl(3), ss->irq_claim); } return work_done; @@ -1534,7 +1532,7 @@ static irqreturn_t myri10ge_intr(int irq, void *arg) /* an interrupt on a non-zero receive-only slice is implicitly * valid since MSI-X irqs are not shared */ if ((mgp->dev->real_num_tx_queues == 1) && (ss != mgp->ss)) { - netif_rx_schedule(ss->dev, &ss->napi); + netif_rx_schedule(&ss->napi); return (IRQ_HANDLED); } @@ -1545,7 +1543,7 @@ static irqreturn_t myri10ge_intr(int irq, void *arg) /* low bit indicates receives are present, so schedule * napi poll handler */ if (stats->valid & 1) - netif_rx_schedule(ss->dev, &ss->napi); + netif_rx_schedule(&ss->napi); if (!mgp->msi_enabled && !mgp->msix_enabled) { put_be32(0, mgp->irq_deassert); @@ -2230,6 +2228,8 @@ myri10ge_get_frag_header(struct skb_frag_struct *frag, void **mac_hdr, *ip_hdr = iph; if (iph->protocol != IPPROTO_TCP) return -1; + if (iph->frag_off & htons(IP_MF | IP_OFFSET)) + return -1; *hdr_flags |= LRO_TCP; *tcpudp_hdr = (u8 *) (*ip_hdr) + (iph->ihl << 2); @@ -2927,6 +2927,7 @@ static int myri10ge_sw_tso(struct sk_buff *skb, struct net_device *dev) { struct sk_buff *segs, *curr; struct myri10ge_priv *mgp = netdev_priv(dev); + struct myri10ge_slice_state *ss; int status; segs = skb_gso_segment(skb, dev->features & ~NETIF_F_TSO6); @@ -2953,8 +2954,9 @@ static int myri10ge_sw_tso(struct sk_buff *skb, struct net_device *dev) return 0; drop: + ss = &mgp->ss[skb_get_queue_mapping(skb)]; dev_kfree_skb_any(skb); - mgp->stats.tx_dropped += 1; + ss->stats.tx_dropped += 1; return 0; } @@ -2985,7 +2987,6 @@ static void myri10ge_set_multicast_list(struct net_device *dev) struct dev_mc_list *mc_list; __be32 data[2] = { 0, 0 }; int err; - DECLARE_MAC_BUF(mac); /* can be called from atomic contexts, * pass 1 to force atomicity in myri10ge_send_cmd() */ @@ -3032,8 +3033,7 @@ static void myri10ge_set_multicast_list(struct net_device *dev) printk(KERN_ERR "myri10ge: %s: Failed " "MXGEFW_JOIN_MULTICAST_GROUP, error status:" "%d\t", dev->name, err); - printk(KERN_ERR "MAC %s\n", - print_mac(mac, mc_list->dmi_addr)); + printk(KERN_ERR "MAC %pM\n", mc_list->dmi_addr); goto abort; } } @@ -3732,6 +3732,17 @@ static void myri10ge_probe_slices(struct myri10ge_priv *mgp) myri10ge_load_firmware(mgp, 0); } +static const struct net_device_ops myri10ge_netdev_ops = { + .ndo_open = myri10ge_open, + .ndo_stop = myri10ge_close, + .ndo_start_xmit = myri10ge_xmit, + .ndo_get_stats = myri10ge_get_stats, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = myri10ge_change_mtu, + .ndo_set_multicast_list = myri10ge_set_multicast_list, + .ndo_set_mac_address = myri10ge_set_mac_address, +}; + static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct net_device *netdev; @@ -3740,6 +3751,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) int i; int status = -ENXIO; int dac_enabled; + unsigned hdr_offset, ss_offset; netdev = alloc_etherdev_mq(sizeof(*mgp), MYRI10GE_MAX_SLICES); if (netdev == NULL) { @@ -3807,14 +3819,6 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (mgp->mtrr >= 0) mgp->wc_enabled = 1; #endif - /* Hack. need to get rid of these magic numbers */ - mgp->sram_size = - 2 * 1024 * 1024 - (2 * (48 * 1024) + (32 * 1024)) - 0x100; - if (mgp->sram_size > mgp->board_span) { - dev_err(&pdev->dev, "board span %ld bytes too small\n", - mgp->board_span); - goto abort_with_mtrr; - } mgp->sram = ioremap_wc(mgp->iomem_base, mgp->board_span); if (mgp->sram == NULL) { dev_err(&pdev->dev, "ioremap failed for %ld bytes at 0x%lx\n", @@ -3822,9 +3826,19 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) status = -ENXIO; goto abort_with_mtrr; } + hdr_offset = + ntohl(__raw_readl(mgp->sram + MCP_HEADER_PTR_OFFSET)) & 0xffffc; + ss_offset = hdr_offset + offsetof(struct mcp_gen_header, string_specs); + mgp->sram_size = ntohl(__raw_readl(mgp->sram + ss_offset)); + if (mgp->sram_size > mgp->board_span || + mgp->sram_size <= MYRI10GE_FW_OFFSET) { + dev_err(&pdev->dev, + "invalid sram_size %dB or board span %ldB\n", + mgp->sram_size, mgp->board_span); + goto abort_with_ioremap; + } memcpy_fromio(mgp->eeprom_strings, - mgp->sram + mgp->sram_size - MYRI10GE_EEPROM_STRINGS_SIZE, - MYRI10GE_EEPROM_STRINGS_SIZE); + mgp->sram + mgp->sram_size, MYRI10GE_EEPROM_STRINGS_SIZE); memset(mgp->eeprom_strings + MYRI10GE_EEPROM_STRINGS_SIZE - 2, 0, 2); status = myri10ge_read_mac_addr(mgp); if (status) @@ -3860,15 +3874,10 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) myri10ge_initial_mtu = MYRI10GE_MAX_ETHER_MTU - ETH_HLEN; if ((myri10ge_initial_mtu + ETH_HLEN) < 68) myri10ge_initial_mtu = 68; + + netdev->netdev_ops = &myri10ge_netdev_ops; netdev->mtu = myri10ge_initial_mtu; - netdev->open = myri10ge_open; - netdev->stop = myri10ge_close; - netdev->hard_start_xmit = myri10ge_xmit; - netdev->get_stats = myri10ge_get_stats; netdev->base_addr = mgp->iomem_base; - netdev->change_mtu = myri10ge_change_mtu; - netdev->set_multicast_list = myri10ge_set_multicast_list; - netdev->set_mac_address = myri10ge_set_mac_address; netdev->features = mgp->features; if (dac_enabled) @@ -4019,7 +4028,7 @@ static struct notifier_block myri10ge_dca_notifier = { .next = NULL, .priority = 0, }; -#endif /* CONFIG_DCA */ +#endif /* CONFIG_MYRI10GE_DCA */ static __init int myri10ge_init_module(void) { diff --git a/drivers/net/myri10ge/myri10ge_mcp.h b/drivers/net/myri10ge/myri10ge_mcp.h index 993721090777d62004b20686a6136095f6169f2f..11be150e4d67fc1cb70906535a9356dd38051ee6 100644 --- a/drivers/net/myri10ge/myri10ge_mcp.h +++ b/drivers/net/myri10ge/myri10ge_mcp.h @@ -111,61 +111,61 @@ enum myri10ge_mcp_cmd_type { MXGEFW_CMD_NONE = 0, /* Reset the mcp, it is left in a safe state, waiting * for the driver to set all its parameters */ - MXGEFW_CMD_RESET, + MXGEFW_CMD_RESET = 1, /* get the version number of the current firmware.. * (may be available in the eeprom strings..? */ - MXGEFW_GET_MCP_VERSION, + MXGEFW_GET_MCP_VERSION = 2, /* Parameters which must be set by the driver before it can * issue MXGEFW_CMD_ETHERNET_UP. They persist until the next * MXGEFW_CMD_RESET is issued */ - MXGEFW_CMD_SET_INTRQ_DMA, + MXGEFW_CMD_SET_INTRQ_DMA = 3, /* data0 = LSW of the host address * data1 = MSW of the host address * data2 = slice number if multiple slices are used */ - MXGEFW_CMD_SET_BIG_BUFFER_SIZE, /* in bytes, power of 2 */ - MXGEFW_CMD_SET_SMALL_BUFFER_SIZE, /* in bytes */ + MXGEFW_CMD_SET_BIG_BUFFER_SIZE = 4, /* in bytes, power of 2 */ + MXGEFW_CMD_SET_SMALL_BUFFER_SIZE = 5, /* in bytes */ /* Parameters which refer to lanai SRAM addresses where the * driver must issue PIO writes for various things */ - MXGEFW_CMD_GET_SEND_OFFSET, - MXGEFW_CMD_GET_SMALL_RX_OFFSET, - MXGEFW_CMD_GET_BIG_RX_OFFSET, + MXGEFW_CMD_GET_SEND_OFFSET = 6, + MXGEFW_CMD_GET_SMALL_RX_OFFSET = 7, + MXGEFW_CMD_GET_BIG_RX_OFFSET = 8, /* data0 = slice number if multiple slices are used */ - MXGEFW_CMD_GET_IRQ_ACK_OFFSET, - MXGEFW_CMD_GET_IRQ_DEASSERT_OFFSET, + MXGEFW_CMD_GET_IRQ_ACK_OFFSET = 9, + MXGEFW_CMD_GET_IRQ_DEASSERT_OFFSET = 10, /* Parameters which refer to rings stored on the MCP, * and whose size is controlled by the mcp */ - MXGEFW_CMD_GET_SEND_RING_SIZE, /* in bytes */ - MXGEFW_CMD_GET_RX_RING_SIZE, /* in bytes */ + MXGEFW_CMD_GET_SEND_RING_SIZE = 11, /* in bytes */ + MXGEFW_CMD_GET_RX_RING_SIZE = 12, /* in bytes */ /* Parameters which refer to rings stored in the host, * and whose size is controlled by the host. Note that * all must be physically contiguous and must contain * a power of 2 number of entries. */ - MXGEFW_CMD_SET_INTRQ_SIZE, /* in bytes */ + MXGEFW_CMD_SET_INTRQ_SIZE = 13, /* in bytes */ #define MXGEFW_CMD_SET_INTRQ_SIZE_FLAG_NO_STRICT_SIZE_CHECK (1 << 31) /* command to bring ethernet interface up. Above parameters * (plus mtu & mac address) must have been exchanged prior * to issuing this command */ - MXGEFW_CMD_ETHERNET_UP, + MXGEFW_CMD_ETHERNET_UP = 14, /* command to bring ethernet interface down. No further sends * or receives may be processed until an MXGEFW_CMD_ETHERNET_UP * is issued, and all interrupt queues must be flushed prior * to ack'ing this command */ - MXGEFW_CMD_ETHERNET_DOWN, + MXGEFW_CMD_ETHERNET_DOWN = 15, /* commands the driver may issue live, without resetting * the nic. Note that increasing the mtu "live" should @@ -173,40 +173,40 @@ enum myri10ge_mcp_cmd_type { * sufficiently large to handle the new mtu. Decreasing * the mtu live is safe */ - MXGEFW_CMD_SET_MTU, - MXGEFW_CMD_GET_INTR_COAL_DELAY_OFFSET, /* in microseconds */ - MXGEFW_CMD_SET_STATS_INTERVAL, /* in microseconds */ - MXGEFW_CMD_SET_STATS_DMA_OBSOLETE, /* replaced by SET_STATS_DMA_V2 */ + MXGEFW_CMD_SET_MTU = 16, + MXGEFW_CMD_GET_INTR_COAL_DELAY_OFFSET = 17, /* in microseconds */ + MXGEFW_CMD_SET_STATS_INTERVAL = 18, /* in microseconds */ + MXGEFW_CMD_SET_STATS_DMA_OBSOLETE = 19, /* replaced by SET_STATS_DMA_V2 */ - MXGEFW_ENABLE_PROMISC, - MXGEFW_DISABLE_PROMISC, - MXGEFW_SET_MAC_ADDRESS, + MXGEFW_ENABLE_PROMISC = 20, + MXGEFW_DISABLE_PROMISC = 21, + MXGEFW_SET_MAC_ADDRESS = 22, - MXGEFW_ENABLE_FLOW_CONTROL, - MXGEFW_DISABLE_FLOW_CONTROL, + MXGEFW_ENABLE_FLOW_CONTROL = 23, + MXGEFW_DISABLE_FLOW_CONTROL = 24, /* do a DMA test * data0,data1 = DMA address * data2 = RDMA length (MSH), WDMA length (LSH) * command return data = repetitions (MSH), 0.5-ms ticks (LSH) */ - MXGEFW_DMA_TEST, + MXGEFW_DMA_TEST = 25, - MXGEFW_ENABLE_ALLMULTI, - MXGEFW_DISABLE_ALLMULTI, + MXGEFW_ENABLE_ALLMULTI = 26, + MXGEFW_DISABLE_ALLMULTI = 27, /* returns MXGEFW_CMD_ERROR_MULTICAST * if there is no room in the cache * data0,MSH(data1) = multicast group address */ - MXGEFW_JOIN_MULTICAST_GROUP, + MXGEFW_JOIN_MULTICAST_GROUP = 28, /* returns MXGEFW_CMD_ERROR_MULTICAST * if the address is not in the cache, * or is equal to FF-FF-FF-FF-FF-FF * data0,MSH(data1) = multicast group address */ - MXGEFW_LEAVE_MULTICAST_GROUP, - MXGEFW_LEAVE_ALL_MULTICAST_GROUPS, + MXGEFW_LEAVE_MULTICAST_GROUP = 29, + MXGEFW_LEAVE_ALL_MULTICAST_GROUPS = 30, - MXGEFW_CMD_SET_STATS_DMA_V2, + MXGEFW_CMD_SET_STATS_DMA_V2 = 31, /* data0, data1 = bus addr, * data2 = sizeof(struct mcp_irq_data) from driver point of view, allows * adding new stuff to mcp_irq_data without changing the ABI @@ -216,14 +216,14 @@ enum myri10ge_mcp_cmd_type { * (in the upper 16 bits). */ - MXGEFW_CMD_UNALIGNED_TEST, + MXGEFW_CMD_UNALIGNED_TEST = 32, /* same than DMA_TEST (same args) but abort with UNALIGNED on unaligned * chipset */ - MXGEFW_CMD_UNALIGNED_STATUS, + MXGEFW_CMD_UNALIGNED_STATUS = 33, /* return data = boolean, true if the chipset is known to be unaligned */ - MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS, + MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS = 34, /* data0 = number of big buffers to use. It must be 0 or a power of 2. * 0 indicates that the NIC consumes as many buffers as they are required * for packet. This is the default behavior. @@ -233,8 +233,8 @@ enum myri10ge_mcp_cmd_type { * the NIC to be able to receive maximum-sized packets. */ - MXGEFW_CMD_GET_MAX_RSS_QUEUES, - MXGEFW_CMD_ENABLE_RSS_QUEUES, + MXGEFW_CMD_GET_MAX_RSS_QUEUES = 35, + MXGEFW_CMD_ENABLE_RSS_QUEUES = 36, /* data0 = number of slices n (0, 1, ..., n-1) to enable * data1 = interrupt mode | use of multiple transmit queues. * 0=share one INTx/MSI. @@ -249,18 +249,18 @@ enum myri10ge_mcp_cmd_type { #define MXGEFW_SLICE_INTR_MODE_ONE_PER_SLICE 0x1 #define MXGEFW_SLICE_ENABLE_MULTIPLE_TX_QUEUES 0x2 - MXGEFW_CMD_GET_RSS_SHARED_INTERRUPT_MASK_OFFSET, - MXGEFW_CMD_SET_RSS_SHARED_INTERRUPT_DMA, + MXGEFW_CMD_GET_RSS_SHARED_INTERRUPT_MASK_OFFSET = 37, + MXGEFW_CMD_SET_RSS_SHARED_INTERRUPT_DMA = 38, /* data0, data1 = bus address lsw, msw */ - MXGEFW_CMD_GET_RSS_TABLE_OFFSET, + MXGEFW_CMD_GET_RSS_TABLE_OFFSET = 39, /* get the offset of the indirection table */ - MXGEFW_CMD_SET_RSS_TABLE_SIZE, + MXGEFW_CMD_SET_RSS_TABLE_SIZE = 40, /* set the size of the indirection table */ - MXGEFW_CMD_GET_RSS_KEY_OFFSET, + MXGEFW_CMD_GET_RSS_KEY_OFFSET = 41, /* get the offset of the secret key */ - MXGEFW_CMD_RSS_KEY_UPDATED, + MXGEFW_CMD_RSS_KEY_UPDATED = 42, /* tell nic that the secret key's been updated */ - MXGEFW_CMD_SET_RSS_ENABLE, + MXGEFW_CMD_SET_RSS_ENABLE = 43, /* data0 = enable/disable rss * 0: disable rss. nic does not distribute receive packets. * 1: enable rss. nic distributes receive packets among queues. @@ -277,7 +277,7 @@ enum myri10ge_mcp_cmd_type { #define MXGEFW_RSS_HASH_TYPE_SRC_DST_PORT 0x5 #define MXGEFW_RSS_HASH_TYPE_MAX 0x5 - MXGEFW_CMD_GET_MAX_TSO6_HDR_SIZE, + MXGEFW_CMD_GET_MAX_TSO6_HDR_SIZE = 44, /* Return data = the max. size of the entire headers of a IPv6 TSO packet. * If the header size of a IPv6 TSO packet is larger than the specified * value, then the driver must not use TSO. @@ -286,7 +286,7 @@ enum myri10ge_mcp_cmd_type { * always has enough header buffer to store maximum-sized headers. */ - MXGEFW_CMD_SET_TSO_MODE, + MXGEFW_CMD_SET_TSO_MODE = 45, /* data0 = TSO mode. * 0: Linux/FreeBSD style (NIC default) * 1: NDIS/NetBSD style @@ -294,33 +294,37 @@ enum myri10ge_mcp_cmd_type { #define MXGEFW_TSO_MODE_LINUX 0 #define MXGEFW_TSO_MODE_NDIS 1 - MXGEFW_CMD_MDIO_READ, + MXGEFW_CMD_MDIO_READ = 46, /* data0 = dev_addr (PMA/PMD or PCS ...), data1 = register/addr */ - MXGEFW_CMD_MDIO_WRITE, + MXGEFW_CMD_MDIO_WRITE = 47, /* data0 = dev_addr, data1 = register/addr, data2 = value */ - MXGEFW_CMD_XFP_I2C_READ, - /* Starts to get a fresh copy of one byte or of the whole xfp i2c table, the + MXGEFW_CMD_I2C_READ = 48, + /* Starts to get a fresh copy of one byte or of the module i2c table, the * obtained data is cached inside the xaui-xfi chip : - * data0 : "all" flag : 0 => get one byte, 1=> get 256 bytes, - * data1 : if (data0 == 0): index of byte to refresh [ not used otherwise ] + * data0 : 0 => get one byte, 1=> get 256 bytes + * data1 : If data0 == 0: location to refresh + * bit 7:0 register location + * bit 8:15 is the i2c slave addr (0 is interpreted as 0xA1) + * bit 23:16 is the i2c bus number (for multi-port NICs) + * If data0 == 1: unused * The operation might take ~1ms for a single byte or ~65ms when refreshing all 256 bytes - * During the i2c operation, MXGEFW_CMD_XFP_I2C_READ or MXGEFW_CMD_XFP_BYTE attempts + * During the i2c operation, MXGEFW_CMD_I2C_READ or MXGEFW_CMD_I2C_BYTE attempts * will return MXGEFW_CMD_ERROR_BUSY */ - MXGEFW_CMD_XFP_BYTE, + MXGEFW_CMD_I2C_BYTE = 49, /* Return the last obtained copy of a given byte in the xfp i2c table - * (copy cached during the last relevant MXGEFW_CMD_XFP_I2C_READ) + * (copy cached during the last relevant MXGEFW_CMD_I2C_READ) * data0 : index of the desired table entry * Return data = the byte stored at the requested index in the table */ - MXGEFW_CMD_GET_VPUMP_OFFSET, + MXGEFW_CMD_GET_VPUMP_OFFSET = 50, /* Return data = NIC memory offset of mcp_vpump_public_global */ - MXGEFW_CMD_RESET_VPUMP, + MXGEFW_CMD_RESET_VPUMP = 51, /* Resets the VPUMP state */ - MXGEFW_CMD_SET_RSS_MCP_SLOT_TYPE, + MXGEFW_CMD_SET_RSS_MCP_SLOT_TYPE = 52, /* data0 = mcp_slot type to use. * 0 = the default 4B mcp_slot * 1 = 8B mcp_slot_8 @@ -328,7 +332,7 @@ enum myri10ge_mcp_cmd_type { #define MXGEFW_RSS_MCP_SLOT_TYPE_MIN 0 #define MXGEFW_RSS_MCP_SLOT_TYPE_WITH_HASH 1 - MXGEFW_CMD_SET_THROTTLE_FACTOR, + MXGEFW_CMD_SET_THROTTLE_FACTOR = 53, /* set the throttle factor for ethp_z8e * data0 = throttle_factor * throttle_factor = 256 * pcie-raw-speed / tx_speed @@ -344,45 +348,50 @@ enum myri10ge_mcp_cmd_type { * with tx_boundary == 4096, max-throttle-factor == 4095 => min-speed == 1Gb/s */ - MXGEFW_CMD_VPUMP_UP, + MXGEFW_CMD_VPUMP_UP = 54, /* Allocates VPump Connection, Send Request and Zero copy buffer address tables */ - MXGEFW_CMD_GET_VPUMP_CLK, + MXGEFW_CMD_GET_VPUMP_CLK = 55, /* Get the lanai clock */ - MXGEFW_CMD_GET_DCA_OFFSET, + MXGEFW_CMD_GET_DCA_OFFSET = 56, /* offset of dca control for WDMAs */ /* VMWare NetQueue commands */ - MXGEFW_CMD_NETQ_GET_FILTERS_PER_QUEUE, - MXGEFW_CMD_NETQ_ADD_FILTER, + MXGEFW_CMD_NETQ_GET_FILTERS_PER_QUEUE = 57, + MXGEFW_CMD_NETQ_ADD_FILTER = 58, /* data0 = filter_id << 16 | queue << 8 | type */ /* data1 = MS4 of MAC Addr */ /* data2 = LS2_MAC << 16 | VLAN_tag */ - MXGEFW_CMD_NETQ_DEL_FILTER, + MXGEFW_CMD_NETQ_DEL_FILTER = 59, /* data0 = filter_id */ - MXGEFW_CMD_NETQ_QUERY1, - MXGEFW_CMD_NETQ_QUERY2, - MXGEFW_CMD_NETQ_QUERY3, - MXGEFW_CMD_NETQ_QUERY4, - + MXGEFW_CMD_NETQ_QUERY1 = 60, + MXGEFW_CMD_NETQ_QUERY2 = 61, + MXGEFW_CMD_NETQ_QUERY3 = 62, + MXGEFW_CMD_NETQ_QUERY4 = 63, + + MXGEFW_CMD_RELAX_RXBUFFER_ALIGNMENT = 64, + /* When set, small receive buffers can cross page boundaries. + * Both small and big receive buffers may start at any address. + * This option has performance implications, so use with caution. + */ }; enum myri10ge_mcp_cmd_status { MXGEFW_CMD_OK = 0, - MXGEFW_CMD_UNKNOWN, - MXGEFW_CMD_ERROR_RANGE, - MXGEFW_CMD_ERROR_BUSY, - MXGEFW_CMD_ERROR_EMPTY, - MXGEFW_CMD_ERROR_CLOSED, - MXGEFW_CMD_ERROR_HASH_ERROR, - MXGEFW_CMD_ERROR_BAD_PORT, - MXGEFW_CMD_ERROR_RESOURCES, - MXGEFW_CMD_ERROR_MULTICAST, - MXGEFW_CMD_ERROR_UNALIGNED, - MXGEFW_CMD_ERROR_NO_MDIO, - MXGEFW_CMD_ERROR_XFP_FAILURE, - MXGEFW_CMD_ERROR_XFP_ABSENT, - MXGEFW_CMD_ERROR_BAD_PCIE_LINK + MXGEFW_CMD_UNKNOWN = 1, + MXGEFW_CMD_ERROR_RANGE = 2, + MXGEFW_CMD_ERROR_BUSY = 3, + MXGEFW_CMD_ERROR_EMPTY = 4, + MXGEFW_CMD_ERROR_CLOSED = 5, + MXGEFW_CMD_ERROR_HASH_ERROR = 6, + MXGEFW_CMD_ERROR_BAD_PORT = 7, + MXGEFW_CMD_ERROR_RESOURCES = 8, + MXGEFW_CMD_ERROR_MULTICAST = 9, + MXGEFW_CMD_ERROR_UNALIGNED = 10, + MXGEFW_CMD_ERROR_NO_MDIO = 11, + MXGEFW_CMD_ERROR_I2C_FAILURE = 12, + MXGEFW_CMD_ERROR_I2C_ABSENT = 13, + MXGEFW_CMD_ERROR_BAD_PCIE_LINK = 14 }; #define MXGEFW_OLD_IRQ_DATA_LEN 40 diff --git a/drivers/net/myri10ge/myri10ge_mcp_gen_header.h b/drivers/net/myri10ge/myri10ge_mcp_gen_header.h index a8662ea8079a6fdebc44a28d9b22ee5702e7c578..caa6cbbb631e557fa4074be08b4dac212f00a1aa 100644 --- a/drivers/net/myri10ge/myri10ge_mcp_gen_header.h +++ b/drivers/net/myri10ge/myri10ge_mcp_gen_header.h @@ -41,6 +41,8 @@ struct mcp_gen_header { unsigned short handoff_id_major; /* must be equal */ unsigned short handoff_id_caps; /* bitfield: new mcp must have superset */ unsigned msix_table_addr; /* start address of msix table in firmware */ + unsigned bss_addr; /* start of bss */ + unsigned features; /* 8 */ }; diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index 3ad7589d6a1c36b341920e6a2c4548d34de3ff92..899ed065a1478dc7ef4303b445285954776eb282 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -318,13 +318,10 @@ static void myri_is_not_so_happy(struct myri_eth *mp) #ifdef DEBUG_HEADER static void dump_ehdr(struct ethhdr *ehdr) { - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); - printk("ehdr[h_dst(%s)" - "h_source(%s)" + printk("ehdr[h_dst(%pM)" + "h_source(%pM)" "h_proto(%04x)]\n", - print_mac(mac, ehdr->h_dest), print_mac(mac2, ehdr->h_source), - ehdr->h_proto); + ehdr->h_dest, ehdr->h_source, ehdr->h_proto); } static void dump_ehdr_and_myripad(unsigned char *stuff) @@ -528,7 +525,6 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev) DRX(("prot[%04x] netif_rx ", skb->protocol)); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += len; next: @@ -540,7 +536,7 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev) static irqreturn_t myri_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; - struct myri_eth *mp = (struct myri_eth *) dev->priv; + struct myri_eth *mp = netdev_priv(dev); void __iomem *lregs = mp->lregs; struct myri_channel __iomem *chan = &mp->shmem->channel; unsigned long flags; @@ -579,14 +575,14 @@ static irqreturn_t myri_interrupt(int irq, void *dev_id) static int myri_open(struct net_device *dev) { - struct myri_eth *mp = (struct myri_eth *) dev->priv; + struct myri_eth *mp = netdev_priv(dev); return myri_init(mp, in_interrupt()); } static int myri_close(struct net_device *dev) { - struct myri_eth *mp = (struct myri_eth *) dev->priv; + struct myri_eth *mp = netdev_priv(dev); myri_clean_rings(mp); return 0; @@ -594,7 +590,7 @@ static int myri_close(struct net_device *dev) static void myri_tx_timeout(struct net_device *dev) { - struct myri_eth *mp = (struct myri_eth *) dev->priv; + struct myri_eth *mp = netdev_priv(dev); printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name); @@ -605,7 +601,7 @@ static void myri_tx_timeout(struct net_device *dev) static int myri_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct myri_eth *mp = (struct myri_eth *) dev->priv; + struct myri_eth *mp = netdev_priv(dev); struct sendq __iomem *sq = mp->sq; struct myri_txd __iomem *txd; unsigned long flags; @@ -905,7 +901,6 @@ static int __devinit myri_sbus_probe(struct of_device *op, const struct of_devic struct device_node *dp = op->node; static unsigned version_printed; struct net_device *dev; - DECLARE_MAC_BUF(mac); struct myri_eth *mp; const void *prop; static int num; @@ -1088,15 +1083,15 @@ static int __devinit myri_sbus_probe(struct of_device *op, const struct of_devic num++; - printk("%s: MyriCOM MyriNET Ethernet %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk("%s: MyriCOM MyriNET Ethernet %pM\n", + dev->name, dev->dev_addr); return 0; err_free_irq: free_irq(dev->irq, dev); err: - /* This will also free the co-allocated 'dev->priv' */ + /* This will also free the co-allocated private data*/ free_netdev(dev); return -ENODEV; } diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index f7fa3944659bab47cac4e516c104dad5fd58890d..478edb92bca35581509f80a7709354c00a2f3d17 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -792,7 +792,6 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, const int pcibar = 1; /* PCI base address register */ int prev_eedata; u32 tmp; - DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -948,10 +947,10 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, if (netif_msg_drv(np)) { printk(KERN_INFO "natsemi %s: %s at %#08llx " - "(%s), %s, IRQ %d", + "(%s), %pM, IRQ %d", dev->name, natsemi_pci_info[chip_idx].name, (unsigned long long)iostart, pci_name(np->pci_dev), - print_mac(mac, dev->dev_addr), irq); + dev->dev_addr, irq); if (dev->if_port == PORT_TP) printk(", port TP.\n"); else if (np->ignore_phy) @@ -2194,10 +2193,10 @@ static irqreturn_t intr_handler(int irq, void *dev_instance) prefetch(&np->rx_skbuff[np->cur_rx % RX_RING_SIZE]); - if (netif_rx_schedule_prep(dev, &np->napi)) { + if (netif_rx_schedule_prep(&np->napi)) { /* Disable interrupts and register for poll */ natsemi_irq_disable(dev); - __netif_rx_schedule(dev, &np->napi); + __netif_rx_schedule(&np->napi); } else printk(KERN_WARNING "%s: Ignoring interrupt, status %#08x, mask %#08x.\n", @@ -2249,7 +2248,7 @@ static int natsemi_poll(struct napi_struct *napi, int budget) np->intr_status = readl(ioaddr + IntrStatus); } while (np->intr_status); - netif_rx_complete(dev, napi); + netif_rx_complete(napi); /* Reenable interrupts providing nothing is trying to shut * the chip down. */ @@ -2362,7 +2361,6 @@ static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do) } skb->protocol = eth_type_trans(skb, dev); netif_receive_skb(skb); - dev->last_rx = jiffies; np->stats.rx_packets++; np->stats.rx_bytes += pkt_len; } diff --git a/drivers/net/ne-h8300.c b/drivers/net/ne-h8300.c index fbc7531d3c7d8aed647056c905e4aa74a476b0e8..b57239171046a50cc04ff11d3682af1a42990e34 100644 --- a/drivers/net/ne-h8300.c +++ b/drivers/net/ne-h8300.c @@ -167,7 +167,7 @@ static void cleanup_card(struct net_device *dev) #ifndef MODULE struct net_device * __init ne_probe(int unit) { - struct net_device *dev = ____alloc_ei_netdev(0); + struct net_device *dev = alloc_ei_netdev(); int err; if (!dev) @@ -193,6 +193,21 @@ struct net_device * __init ne_probe(int unit) } #endif +static const struct net_device_ops ne_netdev_ops = { + .ndo_open = ne_open, + .ndo_stop = ne_close, + + .ndo_start_xmit = ei_start_xmit, + .ndo_tx_timeout = ei_tx_timeout, + .ndo_get_stats = ei_get_stats, + .ndo_set_multicast_list = ei_set_multicast_list, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = ei_poll, +#endif +}; + static int __init ne_probe1(struct net_device *dev, int ioaddr) { int i; @@ -204,7 +219,6 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr) static unsigned version_printed; struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); unsigned char bus_width; - DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, NE_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -299,7 +313,7 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr) for(i = 0; i < ETHER_ADDR_LEN; i++) dev->dev_addr[i] = SA_prom[i]; - printk(" %s\n", print_mac(mac, dev->dev_addr)); + printk(" %pM\n", dev->dev_addr); printk("%s: %s found at %#x, using IRQ %d.\n", dev->name, name, ioaddr, dev->irq); @@ -320,11 +334,9 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr) ei_status.block_output = &ne_block_output; ei_status.get_8390_hdr = &ne_get_8390_hdr; ei_status.priv = 0; - dev->open = &ne_open; - dev->stop = &ne_close; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = __ei_poll; -#endif + + dev->netdev_ops = &ne_netdev_ops; + __NS8390_init(dev, 0); ret = register_netdev(dev); @@ -625,7 +637,7 @@ int init_module(void) int err; for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { - struct net_device *dev = ____alloc_ei_netdev(0); + struct net_device *dev = alloc_ei_netdev(); if (!dev) break; if (io[this_dev]) { diff --git a/drivers/net/ne.c b/drivers/net/ne.c index eb681c0d51ba1ef61b7537bd6974a9413eabf66e..5c3e242428f11a1b5ff2e98a782614031d00a9cf 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -174,9 +174,6 @@ bad_clone_list[] __initdata = { static int ne_probe1(struct net_device *dev, unsigned long ioaddr); static int ne_probe_isapnp(struct net_device *dev); -static int ne_open(struct net_device *dev); -static int ne_close(struct net_device *dev); - static void ne_reset_8390(struct net_device *dev); static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page); @@ -297,7 +294,6 @@ static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr) int neX000, ctron, copam, bad_card; int reg0, ret; static unsigned version_printed; - DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, NE_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -517,7 +513,7 @@ static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr) } #endif - printk("%s\n", print_mac(mac, dev->dev_addr)); + printk("%pM\n", dev->dev_addr); ei_status.name = name; ei_status.tx_start_page = start_page; @@ -537,11 +533,8 @@ static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr) ei_status.block_output = &ne_block_output; ei_status.get_8390_hdr = &ne_get_8390_hdr; ei_status.priv = 0; - dev->open = &ne_open; - dev->stop = &ne_close; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = eip_poll; -#endif + + dev->netdev_ops = &eip_netdev_ops; NS8390p_init(dev, 0); ret = register_netdev(dev); @@ -558,20 +551,6 @@ static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr) return ret; } -static int ne_open(struct net_device *dev) -{ - eip_open(dev); - return 0; -} - -static int ne_close(struct net_device *dev) -{ - if (ei_debug > 1) - printk(KERN_DEBUG "%s: Shutting down ethercard.\n", dev->name); - eip_close(dev); - return 0; -} - /* Hard reset the card. This used to pause for the same period that a 8390 reset command required, but that shouldn't be necessary. */ @@ -950,7 +929,7 @@ static void __init ne_add_devices(void) } #ifdef MODULE -int __init init_module() +int __init init_module(void) { int retval; ne_add_devices(); diff --git a/drivers/net/ne2.c b/drivers/net/ne2.c index 332df75a9ab66a06eb150ede9662d2f843807c0f..a53bb201d3c7612f92ba6015fbfd4ae15726ae32 100644 --- a/drivers/net/ne2.c +++ b/drivers/net/ne2.c @@ -137,9 +137,6 @@ extern int netcard_probe(struct net_device *dev); static int ne2_probe1(struct net_device *dev, int slot); -static int ne_open(struct net_device *dev); -static int ne_close(struct net_device *dev); - static void ne_reset_8390(struct net_device *dev); static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page); @@ -302,7 +299,6 @@ struct net_device * __init ne2_probe(int unit) static int ne2_procinfo(char *buf, int slot, struct net_device *dev) { int len=0; - DECLARE_MAC_BUF(mac); len += sprintf(buf+len, "The NE/2 Ethernet Adapter\n" ); len += sprintf(buf+len, "Driver written by Wim Dumon "); @@ -313,7 +309,7 @@ static int ne2_procinfo(char *buf, int slot, struct net_device *dev) len += sprintf(buf+len, "Based on the original NE2000 drivers\n" ); len += sprintf(buf+len, "Base IO: %#x\n", (unsigned int)dev->base_addr); len += sprintf(buf+len, "IRQ : %d\n", dev->irq); - len += sprintf(buf+len, "HW addr : %s\n", print_mac(mac, dev->dev_addr)); + len += sprintf(buf+len, "HW addr : %pM\n", dev->dev_addr); return len; } @@ -326,7 +322,6 @@ static int __init ne2_probe1(struct net_device *dev, int slot) const char *name = "NE/2"; int start_page, stop_page; static unsigned version_printed; - DECLARE_MAC_BUF(mac); if (ei_debug && version_printed++ == 0) printk(version); @@ -469,7 +464,7 @@ static int __init ne2_probe1(struct net_device *dev, int slot) for(i = 0; i < ETHER_ADDR_LEN; i++) dev->dev_addr[i] = SA_prom[i]; - printk(" %s\n", print_mac(mac, dev->dev_addr)); + printk(" %pM\n", dev->dev_addr); printk("%s: %s found at %#x, using IRQ %d.\n", dev->name, name, base_addr, dev->irq); @@ -494,11 +489,7 @@ static int __init ne2_probe1(struct net_device *dev, int slot) ei_status.priv = slot; - dev->open = &ne_open; - dev->stop = &ne_close; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = eip_poll; -#endif + dev->netdev_ops = &eip_netdev_ops; NS8390p_init(dev, 0); retval = register_netdev(dev); @@ -513,20 +504,6 @@ static int __init ne2_probe1(struct net_device *dev, int slot) return retval; } -static int ne_open(struct net_device *dev) -{ - eip_open(dev); - return 0; -} - -static int ne_close(struct net_device *dev) -{ - if (ei_debug > 1) - printk("%s: Shutting down ethercard.\n", dev->name); - eip_close(dev); - return 0; -} - /* Hard reset the card. This used to pause for the same period that a 8390 reset command required, but that shouldn't be necessary. */ static void ne_reset_8390(struct net_device *dev) diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c index de0de744a8fa4e1fe961cc89e301046b862a8e51..62f20ba211cb7d0b98f78df1c8cea83166e152a7 100644 --- a/drivers/net/ne2k-pci.c +++ b/drivers/net/ne2k-pci.c @@ -200,6 +200,19 @@ struct ne2k_pci_card { in the 'dev' and 'ei_status' structures. */ +static const struct net_device_ops ne2k_netdev_ops = { + .ndo_open = ne2k_pci_open, + .ndo_stop = ne2k_pci_close, + .ndo_start_xmit = ei_start_xmit, + .ndo_tx_timeout = ei_tx_timeout, + .ndo_get_stats = ei_get_stats, + .ndo_set_multicast_list = ei_set_multicast_list, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = ei_poll, +#endif +}; static int __devinit ne2k_pci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) @@ -212,7 +225,6 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev, static unsigned int fnd_cnt; long ioaddr; int flags = pci_clone_list[chip_idx].flags; - DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -266,6 +278,8 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev, dev_err(&pdev->dev, "cannot allocate ethernet device\n"); goto err_out_free_res; } + dev->netdev_ops = &ne2k_netdev_ops; + SET_NETDEV_DEV(dev, &pdev->dev); /* Reset card. Who knows what dain-bramaged state it was left in. */ @@ -354,12 +368,8 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev, ei_status.block_output = &ne2k_pci_block_output; ei_status.get_8390_hdr = &ne2k_pci_get_8390_hdr; ei_status.priv = (unsigned long) pdev; - dev->open = &ne2k_pci_open; - dev->stop = &ne2k_pci_close; + dev->ethtool_ops = &ne2k_pci_ethtool_ops; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = ei_poll; -#endif NS8390_init(dev, 0); i = register_netdev(dev); @@ -368,9 +378,9 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev, for(i = 0; i < 6; i++) dev->dev_addr[i] = SA_prom[i]; - printk("%s: %s found at %#lx, IRQ %d, %s.\n", + printk("%s: %s found at %#lx, IRQ %d, %pM.\n", dev->name, pci_clone_list[chip_idx].name, ioaddr, dev->irq, - print_mac(mac, dev->dev_addr)); + dev->dev_addr); memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); @@ -626,7 +636,7 @@ static void ne2k_pci_block_output(struct net_device *dev, int count, static void ne2k_pci_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct ei_device *ei = dev->priv; + struct ei_device *ei = netdev_priv(dev); struct pci_dev *pci_dev = (struct pci_dev *) ei->priv; strcpy(info->driver, DRV_NAME); diff --git a/drivers/net/ne3210.c b/drivers/net/ne3210.c index 425043a88db9e9409d958006a30fafddcd200fbe..fac43fd6fc87782a42455b852cec62a56333849f 100644 --- a/drivers/net/ne3210.c +++ b/drivers/net/ne3210.c @@ -45,9 +45,6 @@ #define DRV_NAME "ne3210" -static int ne3210_open(struct net_device *dev); -static int ne3210_close(struct net_device *dev); - static void ne3210_reset_8390(struct net_device *dev); static void ne3210_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page); @@ -99,7 +96,6 @@ static int __init ne3210_eisa_probe (struct device *device) int i, retval, port_index; struct eisa_device *edev = to_eisa_device (device); struct net_device *dev; - DECLARE_MAC_BUF(mac); /* Allocate dev->priv and fill in 8390 specific dev fields. */ if (!(dev = alloc_ei_netdev ())) { @@ -131,8 +127,8 @@ static int __init ne3210_eisa_probe (struct device *device) port_index = inb(ioaddr + NE3210_CFG2) >> 6; for(i = 0; i < ETHER_ADDR_LEN; i++) dev->dev_addr[i] = inb(ioaddr + NE3210_SA_PROM + i); - printk("ne3210.c: NE3210 in EISA slot %d, media: %s, addr: %s.\n", - edev->slot, ifmap[port_index], print_mac(mac, dev->dev_addr)); + printk("ne3210.c: NE3210 in EISA slot %d, media: %s, addr: %pM.\n", + edev->slot, ifmap[port_index], dev->dev_addr); /* Snarf the interrupt now. CFG file has them all listed as `edge' with share=NO */ dev->irq = irq_map[(inb(ioaddr + NE3210_CFG2) >> 3) & 0x07]; @@ -200,11 +196,8 @@ static int __init ne3210_eisa_probe (struct device *device) ei_status.block_output = &ne3210_block_output; ei_status.get_8390_hdr = &ne3210_get_8390_hdr; - dev->open = &ne3210_open; - dev->stop = &ne3210_close; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = ei_poll; -#endif + dev->netdev_ops = &ei_netdev_ops; + dev->if_port = ifmap_val[port_index]; if ((retval = register_netdev (dev))) @@ -321,22 +314,6 @@ static void ne3210_block_output(struct net_device *dev, int count, memcpy_toio(shmem, buf, count); } -static int ne3210_open(struct net_device *dev) -{ - ei_open(dev); - return 0; -} - -static int ne3210_close(struct net_device *dev) -{ - - if (ei_debug > 1) - printk("%s: Shutting down ethercard.\n", dev->name); - - ei_close(dev); - return 0; -} - static struct eisa_device_id ne3210_ids[] = { { "EGL0101" }, { "NVL1801" }, diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 9681618c32321912c522e9953cd71eac4db06443..d304d38cd5d1728c45587efa0a986ca207d21240 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -307,17 +307,14 @@ static ssize_t show_remote_ip(struct netconsole_target *nt, char *buf) static ssize_t show_local_mac(struct netconsole_target *nt, char *buf) { struct net_device *dev = nt->np.dev; + static const u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - DECLARE_MAC_BUF(mac); - return snprintf(buf, PAGE_SIZE, "%s\n", dev ? - print_mac(mac, dev->dev_addr) : "ff:ff:ff:ff:ff:ff"); + return snprintf(buf, PAGE_SIZE, "%pM\n", dev ? dev->dev_addr : bcast); } static ssize_t show_remote_mac(struct netconsole_target *nt, char *buf) { - DECLARE_MAC_BUF(mac); - return snprintf(buf, PAGE_SIZE, "%s\n", - print_mac(mac, nt->np.remote_mac)); + return snprintf(buf, PAGE_SIZE, "%pM\n", nt->np.remote_mac); } /* diff --git a/drivers/net/netx-eth.c b/drivers/net/netx-eth.c index b289a0a2b94563ea37b910c05deef15b6b61d0b6..1861d5bbd96ba01764a8ab6462a5ae1aaf5422c8 100644 --- a/drivers/net/netx-eth.c +++ b/drivers/net/netx-eth.c @@ -165,7 +165,6 @@ static void netx_eth_receive(struct net_device *ndev) pfifo_push(EMPTY_PTR_FIFO(priv->id), FIFO_PTR_SEGMENT(seg) | FIFO_PTR_FRAMENO(frameno)); - ndev->last_rx = jiffies; skb->protocol = eth_type_trans(skb, ndev); netif_rx(skb); ndev->stats.rx_packets++; diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index b974ca0fc530a45babd8962ec47a0f70c2820f9a..e45ce29517299a140ff4c8ee6dfb9c66768ef177 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -275,11 +275,11 @@ netxen_nic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) } else return -EOPNOTSUPP; - if (netif_running(dev)) { - dev->stop(dev); - dev->open(dev); - } - return 0; + if (!netif_running(dev)) + return 0; + + dev->netdev_ops->ndo_stop(dev); + return dev->netdev_ops->ndo_open(dev); } static int netxen_nic_get_regs_len(struct net_device *dev) diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 84978f80f396e681eefa0e8cc76bac57e1ea232c..aa6e603bfcbf701e9a95b504ff00ea67f7afd04b 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -537,7 +537,7 @@ netxen_send_cmd_descs(struct netxen_adapter *adapter, static int nx_p3_sre_macaddr_change(struct net_device *dev, u8 *addr, unsigned op) { - struct netxen_adapter *adapter = (struct netxen_adapter *)dev->priv; + struct netxen_adapter *adapter = netdev_priv(dev); nx_nic_req_t req; nx_mac_req_t mac_req; int rv; @@ -1459,7 +1459,7 @@ static int netxen_nic_pci_mem_read_direct(struct netxen_adapter *adapter, mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE * 2); else mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE); - if (mem_ptr == 0UL) { + if (mem_ptr == NULL) { *(uint8_t *)data = 0; return -1; } @@ -1533,7 +1533,7 @@ netxen_nic_pci_mem_write_direct(struct netxen_adapter *adapter, u64 off, mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE*2); else mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE); - if (mem_ptr == 0UL) + if (mem_ptr == NULL) return -1; addr = mem_ptr; addr += start & (PAGE_SIZE - 1); diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 5bba675d0504594fc340ab3223956d167d4ef0ea..d924468e506eb48af997a075ad3b51d69800b876 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -1285,9 +1285,7 @@ static void netxen_process_rcv(struct netxen_adapter *adapter, int ctxid, } adapter->stats.rxdropped++; } else { - netif_receive_skb(skb); - netdev->last_rx = jiffies; adapter->stats.no_rcv++; adapter->stats.rxbytes += length; diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 6ef3f0d84bcf45e8704aaf21958508086df52ee1..ba01524b5531a46d7ced8efd6470ad825601c23e 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -439,7 +439,6 @@ netxen_read_mac_addr(struct netxen_adapter *adapter) int i; unsigned char *p; __le64 mac_addr; - DECLARE_MAC_BUF(mac); struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; @@ -462,15 +461,39 @@ netxen_read_mac_addr(struct netxen_adapter *adapter) /* set station address */ - if (!is_valid_ether_addr(netdev->perm_addr)) { - dev_warn(&pdev->dev, "Bad MAC address %s.\n", - print_mac(mac, netdev->dev_addr)); - } else + if (!is_valid_ether_addr(netdev->perm_addr)) + dev_warn(&pdev->dev, "Bad MAC address %pM.\n", netdev->dev_addr); + else adapter->macaddr_set(adapter, netdev->dev_addr); return 0; } +static void netxen_set_multicast_list(struct net_device *dev) +{ + struct netxen_adapter *adapter = netdev_priv(dev); + + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) + netxen_p3_nic_set_multi(dev); + else + netxen_p2_nic_set_multi(dev); +} + +static const struct net_device_ops netxen_netdev_ops = { + .ndo_open = netxen_nic_open, + .ndo_stop = netxen_nic_close, + .ndo_start_xmit = netxen_nic_xmit_frame, + .ndo_get_stats = netxen_nic_get_stats, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = netxen_set_multicast_list, + .ndo_set_mac_address = netxen_nic_set_mac, + .ndo_change_mtu = netxen_nic_change_mtu, + .ndo_tx_timeout = netxen_tx_timeout, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = netxen_nic_poll_controller, +#endif +}; + /* * netxen_nic_probe() * @@ -543,7 +566,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) SET_NETDEV_DEV(netdev, &pdev->dev); - adapter = netdev->priv; + adapter = netdev_priv(netdev); adapter->netdev = netdev; adapter->pdev = pdev; adapter->ahw.pci_func = pci_func_id; @@ -682,25 +705,13 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) else adapter->max_mc_count = 16; - netdev->open = netxen_nic_open; - netdev->stop = netxen_nic_close; - netdev->hard_start_xmit = netxen_nic_xmit_frame; - netdev->get_stats = netxen_nic_get_stats; - if (NX_IS_REVISION_P3(revision_id)) - netdev->set_multicast_list = netxen_p3_nic_set_multi; - else - netdev->set_multicast_list = netxen_p2_nic_set_multi; - netdev->set_mac_address = netxen_nic_set_mac; - netdev->change_mtu = netxen_nic_change_mtu; - netdev->tx_timeout = netxen_tx_timeout; + netdev->netdev_ops = &netxen_netdev_ops; netdev->watchdog_timeo = 2*HZ; netxen_nic_change_mtu(netdev, netdev->mtu); SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops); -#ifdef CONFIG_NET_POLL_CONTROLLER - netdev->poll_controller = netxen_nic_poll_controller; -#endif + /* ScatterGather support */ netdev->features = NETIF_F_SG; netdev->features |= NETIF_F_IP_CSUM; @@ -988,7 +999,7 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev) */ static int netxen_nic_open(struct net_device *netdev) { - struct netxen_adapter *adapter = (struct netxen_adapter *)netdev->priv; + struct netxen_adapter *adapter = netdev_priv(netdev); int err = 0; int ctx, ring; irq_handler_t handler; @@ -1077,7 +1088,7 @@ static int netxen_nic_open(struct net_device *netdev) netxen_nic_set_link_parameters(adapter); - netdev->set_multicast_list(netdev); + netxen_set_multicast_list(netdev); if (adapter->set_mtu) adapter->set_mtu(adapter, netdev->mtu); @@ -1572,7 +1583,7 @@ static int netxen_nic_poll(struct napi_struct *napi, int budget) } if ((work_done < budget) && tx_complete) { - netif_rx_complete(adapter->netdev, &adapter->napi); + netif_rx_complete(&adapter->napi); netxen_nic_enable_int(adapter); } diff --git a/drivers/net/netxen/netxen_nic_niu.c b/drivers/net/netxen/netxen_nic_niu.c index 27f07f6a45b1229f8a53afd8c4026f59bbcdb055..c3b9c83b32fe5205925a4686e0874c2f4aa7e96b 100644 --- a/drivers/net/netxen/netxen_nic_niu.c +++ b/drivers/net/netxen/netxen_nic_niu.c @@ -608,7 +608,6 @@ int netxen_niu_macaddr_set(struct netxen_adapter *adapter, int phy = adapter->physical_port; unsigned char mac_addr[6]; int i; - DECLARE_MAC_BUF(mac); if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) return 0; @@ -636,10 +635,8 @@ int netxen_niu_macaddr_set(struct netxen_adapter *adapter, if (i == 10) { printk(KERN_ERR "%s: cannot set Mac addr for %s\n", netxen_nic_driver_name, adapter->netdev->name); - printk(KERN_ERR "MAC address set: %s.\n", - print_mac(mac, addr)); - printk(KERN_ERR "MAC address get: %s.\n", - print_mac(mac, mac_addr)); + printk(KERN_ERR "MAC address set: %pM.\n", addr); + printk(KERN_ERR "MAC address get: %pM.\n", mac_addr); } return 0; } diff --git a/drivers/net/ni5010.c b/drivers/net/ni5010.c index 8e0ca9f4e40479f3fa6ff43c429d45cb69da1b52..539e18ab485cd5da15f1efe17061a5600b48baad 100644 --- a/drivers/net/ni5010.c +++ b/drivers/net/ni5010.c @@ -203,7 +203,6 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr) unsigned int data = 0; int boguscount = 40; int err = -ENODEV; - DECLARE_MAC_BUF(mac); dev->base_addr = ioaddr; dev->irq = irq; @@ -271,7 +270,7 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr) outw(i, IE_GP); dev->dev_addr[i] = inb(IE_SAPROM); } - printk("%s ", print_mac(mac, dev->dev_addr)); + printk("%pM ", dev->dev_addr); PRINTK2((KERN_DEBUG "%s: I/O #4 passed!\n", dev->name)); @@ -329,7 +328,7 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr) outb(0, IE_RBUF); /* set buffer byte 0 to 0 again */ } printk("-> bufsize rcv/xmt=%d/%d\n", bufsize_rcv, NI5010_BUFSIZE); - memset(dev->priv, 0, sizeof(struct ni5010_local)); + memset(netdev_priv(dev), 0, sizeof(struct ni5010_local)); dev->open = ni5010_open; dev->stop = ni5010_close; @@ -570,7 +569,6 @@ static void ni5010_rx(struct net_device *dev) skb->protocol = eth_type_trans(skb,dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += i_pkt_size; @@ -768,12 +766,3 @@ module_init(ni5010_init_module); module_exit(ni5010_cleanup_module); #endif /* MODULE */ MODULE_LICENSE("GPL"); - -/* - * Local variables: - * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c ni5010.c" - * version-control: t - * kept-new-versions: 5 - * tab-width: 4 - * End: - */ diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c index b9a882d362da1f7bdbc34c76be0958815fc2c684..a8bcc00c3302bcb0a1b35cf9eba82a92dafb75a5 100644 --- a/drivers/net/ni52.c +++ b/drivers/net/ni52.c @@ -9,8 +9,6 @@ * [feel free to mail ....] * * when using as module: (no autoprobing!) - * compile with: - * gcc -O2 -fomit-frame-pointer -m486 -D__KERNEL__ -DMODULE -c ni52.c * run with e.g: * insmod ni52.o io=0x360 irq=9 memstart=0xd0000 memend=0xd4000 * @@ -214,7 +212,7 @@ struct priv { /* wait for command with timeout: */ static void wait_for_scb_cmd(struct net_device *dev) { - struct priv *p = dev->priv; + struct priv *p = netdev_priv(dev); int i; for (i = 0; i < 16384; i++) { if (readb(&p->scb->cmd_cuc) == 0) @@ -233,7 +231,7 @@ static void wait_for_scb_cmd(struct net_device *dev) static void wait_for_scb_cmd_ruc(struct net_device *dev) { - struct priv *p = dev->priv; + struct priv *p = netdev_priv(dev); int i; for (i = 0; i < 16384; i++) { if (readb(&p->scb->cmd_ruc) == 0) @@ -298,7 +296,7 @@ static int ni52_open(struct net_device *dev) static int check_iscp(struct net_device *dev, void __iomem *addr) { struct iscp_struct __iomem *iscp = addr; - struct priv *p = dev->priv; + struct priv *p = netdev_priv(dev); memset_io(iscp, 0, sizeof(struct iscp_struct)); writel(make24(iscp), &p->scp->iscp); @@ -318,7 +316,7 @@ static int check_iscp(struct net_device *dev, void __iomem *addr) */ static int check586(struct net_device *dev, unsigned size) { - struct priv *p = dev->priv; + struct priv *p = netdev_priv(dev); int i; p->mapped = ioremap(dev->mem_start, size); @@ -354,7 +352,7 @@ static int check586(struct net_device *dev, unsigned size) */ static void alloc586(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); ni_reset586(); mdelay(32); @@ -400,7 +398,7 @@ struct net_device * __init ni52_probe(int unit) if (!dev) return ERR_PTR(-ENOMEM); - p = dev->priv; + p = netdev_priv(dev); if (unit >= 0) { sprintf(dev->name, "eth%d", unit); @@ -446,7 +444,7 @@ struct net_device * __init ni52_probe(int unit) static int __init ni52_probe1(struct net_device *dev, int ioaddr) { int i, size, retval; - struct priv *priv = dev->priv; + struct priv *priv = netdev_priv(dev); dev->base_addr = ioaddr; dev->irq = irq; @@ -588,7 +586,7 @@ static int init586(struct net_device *dev) { void __iomem *ptr; int i, result = 0; - struct priv *p = (struct priv *)dev->priv; + struct priv *p = netdev_priv(dev); struct configure_cmd_struct __iomem *cfg_cmd; struct iasetup_cmd_struct __iomem *ias_cmd; struct tdr_cmd_struct __iomem *tdr_cmd; @@ -829,7 +827,7 @@ static void __iomem *alloc_rfa(struct net_device *dev, void __iomem *ptr) struct rfd_struct __iomem *rfd = ptr; struct rbd_struct __iomem *rbd; int i; - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); memset_io(rfd, 0, sizeof(struct rfd_struct) * (p->num_recv_buffs + rfdadd)); @@ -878,7 +876,7 @@ static irqreturn_t ni52_interrupt(int irq, void *dev_id) int cnt = 0; struct priv *p; - p = (struct priv *) dev->priv; + p = netdev_priv(dev); if (debuglevel > 1) printk("I"); @@ -950,7 +948,7 @@ static void ni52_rcv_int(struct net_device *dev) unsigned short totlen; struct sk_buff *skb; struct rbd_struct __iomem *rbd; - struct priv *p = (struct priv *)dev->priv; + struct priv *p = netdev_priv(dev); if (debuglevel > 0) printk("R"); @@ -970,7 +968,6 @@ static void ni52_rcv_int(struct net_device *dev) memcpy_fromio(skb->data, p->base + readl(&rbd->buffer), totlen); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; p->stats.rx_packets++; p->stats.rx_bytes += totlen; } else @@ -1040,7 +1037,7 @@ static void ni52_rcv_int(struct net_device *dev) static void ni52_rnr_int(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); p->stats.rx_errors++; @@ -1065,7 +1062,7 @@ static void ni52_rnr_int(struct net_device *dev) static void ni52_xmt_int(struct net_device *dev) { int status; - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); if (debuglevel > 0) printk("X"); @@ -1113,7 +1110,7 @@ static void ni52_xmt_int(struct net_device *dev) static void startrecv586(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); wait_for_scb_cmd(dev); wait_for_scb_cmd_ruc(dev); @@ -1126,7 +1123,7 @@ static void startrecv586(struct net_device *dev) static void ni52_timeout(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); #ifndef NO_NOPCOMMANDS if (readb(&p->scb->cus) & CU_ACTIVE) { /* COMMAND-UNIT active? */ netif_wake_queue(dev); @@ -1177,7 +1174,7 @@ static int ni52_send_packet(struct sk_buff *skb, struct net_device *dev) #ifndef NO_NOPCOMMANDS int next_nop; #endif - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); if (skb->len > XMIT_BUFF_SIZE) { printk(KERN_ERR "%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n", dev->name, XMIT_BUFF_SIZE, skb->len); @@ -1274,7 +1271,7 @@ static int ni52_send_packet(struct sk_buff *skb, struct net_device *dev) static struct net_device_stats *ni52_get_stats(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); unsigned short crc, aln, rsc, ovrn; /* Get error-statistics from the ni82586 */ @@ -1337,7 +1334,7 @@ int __init init_module(void) void __exit cleanup_module(void) { - struct priv *p = dev_ni52->priv; + struct priv *p = netdev_priv(dev_ni52); unregister_netdev(dev_ni52); iounmap(p->mapped); release_region(dev_ni52->base_addr, NI52_TOTAL_SIZE); @@ -1346,7 +1343,3 @@ void __exit cleanup_module(void) #endif /* MODULE */ MODULE_LICENSE("GPL"); - -/* - * END: linux/drivers/net/ni52.c - */ diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c index 3edc971d0ecabfba1ecfdee18af52bc5e1204682..254057275e0e32eccb17bd1c26cad8b5754e125a 100644 --- a/drivers/net/ni65.c +++ b/drivers/net/ni65.c @@ -7,8 +7,6 @@ * EtherBlaster. (probably it also works with every full NE2100 * compatible card) * - * To compile as module, type: - * gcc -O2 -fomit-frame-pointer -m486 -D__KERNEL__ -DMODULE -c ni65.c * driver probes: io: 0x360,0x300,0x320,0x340 / dma: 3,5,6,7 * * This is an extension to the Linux operating system, and is covered by the @@ -295,7 +293,7 @@ static void ni65_set_performance(struct priv *p) */ static int ni65_open(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = dev->ml_priv; int irqval = request_irq(dev->irq, &ni65_interrupt,0, cards[p->cardno].cardname,dev); if (irqval) { @@ -321,7 +319,7 @@ static int ni65_open(struct net_device *dev) */ static int ni65_close(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = dev->ml_priv; netif_stop_queue(dev); @@ -345,7 +343,7 @@ static int ni65_close(struct net_device *dev) static void cleanup_card(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = dev->ml_priv; disable_dma(dev->dma); free_dma(dev->dma); release_region(dev->base_addr, cards[p->cardno].total_size); @@ -444,7 +442,7 @@ static int __init ni65_probe1(struct net_device *dev,int ioaddr) release_region(ioaddr, cards[i].total_size); return j; } - p = (struct priv *) dev->priv; + p = dev->ml_priv; p->cmdr_addr = ioaddr + cards[i].cmd_offset; p->cardno = i; spin_lock_init(&p->ring_lock); @@ -647,8 +645,8 @@ static int ni65_alloc_buffer(struct net_device *dev) if(!ptr) return -ENOMEM; - p = dev->priv = (struct priv *) (((unsigned long) ptr + 7) & ~0x7); - memset((char *) dev->priv,0,sizeof(struct priv)); + p = dev->ml_priv = (struct priv *) (((unsigned long) ptr + 7) & ~0x7); + memset((char *)p, 0, sizeof(struct priv)); p->self = ptr; for(i=0;ipriv; + struct priv *p = dev->ml_priv; unsigned long flags; p->lock = 0; @@ -876,7 +874,7 @@ static irqreturn_t ni65_interrupt(int irq, void * dev_id) struct priv *p; int bcnt = 32; - p = (struct priv *) dev->priv; + p = dev->ml_priv; spin_lock(&p->ring_lock); @@ -899,7 +897,7 @@ static irqreturn_t ni65_interrupt(int irq, void * dev_id) if(csr0 & CSR0_ERR) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = dev->ml_priv; if(debuglevel > 1) printk(KERN_ERR "%s: general error: %04x.\n",dev->name,csr0); if(csr0 & CSR0_BABL) @@ -924,7 +922,7 @@ static irqreturn_t ni65_interrupt(int irq, void * dev_id) int j; for(j=0;jpriv; + struct priv *p = dev->ml_priv; int i,k,num1,num2; for(i=RMDNUM-1;i>0;i--) { num2 = (p->rmdnum + i) & (RMDNUM-1); @@ -982,7 +980,7 @@ static irqreturn_t ni65_interrupt(int irq, void * dev_id) */ static void ni65_xmit_intr(struct net_device *dev,int csr0) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = dev->ml_priv; while(p->xmit_queued) { @@ -1049,7 +1047,7 @@ static void ni65_recv_intr(struct net_device *dev,int csr0) struct rmd *rmdp; int rmdstat,len; int cnt=0; - struct priv *p = (struct priv *) dev->priv; + struct priv *p = dev->ml_priv; rmdp = p->rmdhead + p->rmdnum; while(!( (rmdstat = rmdp->u.s.status) & RCV_OWN)) @@ -1113,7 +1111,6 @@ static void ni65_recv_intr(struct net_device *dev,int csr0) p->stats.rx_bytes += len; skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); - dev->last_rx = jiffies; } else { @@ -1140,7 +1137,7 @@ static void ni65_recv_intr(struct net_device *dev,int csr0) static void ni65_timeout(struct net_device *dev) { int i; - struct priv *p = (struct priv *) dev->priv; + struct priv *p = dev->ml_priv; printk(KERN_ERR "%s: xmitter timed out, try to restart!\n",dev->name); for(i=0;ipriv; + struct priv *p = dev->ml_priv; netif_stop_queue(dev); @@ -1222,7 +1219,7 @@ static struct net_device_stats *ni65_get_stats(struct net_device *dev) #if 0 int i; - struct priv *p = (struct priv *) dev->priv; + struct priv *p = dev->ml_priv; for(i=0;irmdhead + ((p->rmdnum + i) & (RMDNUM-1)); @@ -1231,7 +1228,7 @@ static struct net_device_stats *ni65_get_stats(struct net_device *dev) printk("\n"); #endif - return &((struct priv *) dev->priv)->stats; + return &((struct priv *)dev->ml_priv)->stats; } static void set_multicast_list(struct net_device *dev) @@ -1266,7 +1263,3 @@ void __exit cleanup_module(void) #endif /* MODULE */ MODULE_LICENSE("GPL"); - -/* - * END of ni65.c - */ diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 1b6f548c4411203a7666e0f1703de8fcec4aabf5..0c0b752315cae844c6944b912d8605032070e93c 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -448,7 +448,7 @@ static int serdes_init_niu_1g_serdes(struct niu *np) struct niu_link_config *lp = &np->link_config; u16 pll_cfg, pll_sts; int max_retry = 100; - u64 sig, mask, val; + u64 uninitialized_var(sig), mask, val; u32 tx_cfg, rx_cfg; unsigned long i; int err; @@ -547,7 +547,7 @@ static int serdes_init_niu_10g_serdes(struct niu *np) struct niu_link_config *lp = &np->link_config; u32 tx_cfg, rx_cfg, pll_cfg, pll_sts; int max_retry = 100; - u64 sig, mask, val; + u64 uninitialized_var(sig), mask, val; unsigned long i; int err; @@ -738,7 +738,7 @@ static int esr_write_glue0(struct niu *np, unsigned long chan, u32 val) static int esr_reset(struct niu *np) { - u32 reset; + u32 uninitialized_var(reset); int err; err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR, @@ -3392,8 +3392,6 @@ static int niu_process_rx_pkt(struct niu *np, struct rx_ring_info *rp) skb->protocol = eth_type_trans(skb, np->dev); netif_receive_skb(skb); - np->dev->last_rx = jiffies; - return num_rcr; } @@ -3529,6 +3527,57 @@ static void niu_tx_work(struct niu *np, struct tx_ring_info *rp) } } +static inline void niu_sync_rx_discard_stats(struct niu *np, + struct rx_ring_info *rp, + const int limit) +{ + /* This elaborate scheme is needed for reading the RX discard + * counters, as they are only 16-bit and can overflow quickly, + * and because the overflow indication bit is not usable as + * the counter value does not wrap, but remains at max value + * 0xFFFF. + * + * In theory and in practice counters can be lost in between + * reading nr64() and clearing the counter nw64(). For this + * reason, the number of counter clearings nw64() is + * limited/reduced though the limit parameter. + */ + int rx_channel = rp->rx_channel; + u32 misc, wred; + + /* RXMISC (Receive Miscellaneous Discard Count), covers the + * following discard events: IPP (Input Port Process), + * FFLP/TCAM, Full RCR (Receive Completion Ring) RBR (Receive + * Block Ring) prefetch buffer is empty. + */ + misc = nr64(RXMISC(rx_channel)); + if (unlikely((misc & RXMISC_COUNT) > limit)) { + nw64(RXMISC(rx_channel), 0); + rp->rx_errors += misc & RXMISC_COUNT; + + if (unlikely(misc & RXMISC_OFLOW)) + dev_err(np->device, "rx-%d: Counter overflow " + "RXMISC discard\n", rx_channel); + + niudbg(RX_ERR, "%s-rx-%d: MISC drop=%u over=%u\n", + np->dev->name, rx_channel, misc, misc-limit); + } + + /* WRED (Weighted Random Early Discard) by hardware */ + wred = nr64(RED_DIS_CNT(rx_channel)); + if (unlikely((wred & RED_DIS_CNT_COUNT) > limit)) { + nw64(RED_DIS_CNT(rx_channel), 0); + rp->rx_dropped += wred & RED_DIS_CNT_COUNT; + + if (unlikely(wred & RED_DIS_CNT_OFLOW)) + dev_err(np->device, "rx-%d: Counter overflow " + "WRED discard\n", rx_channel); + + niudbg(RX_ERR, "%s-rx-%d: WRED drop=%u over=%u\n", + np->dev->name, rx_channel, wred, wred-limit); + } +} + static int niu_rx_work(struct niu *np, struct rx_ring_info *rp, int budget) { int qlen, rcr_done = 0, work_done = 0; @@ -3569,6 +3618,10 @@ static int niu_rx_work(struct niu *np, struct rx_ring_info *rp, int budget) nw64(RX_DMA_CTL_STAT(rp->rx_channel), stat); + /* Only sync discards stats when qlen indicate potential for drops */ + if (qlen > 10) + niu_sync_rx_discard_stats(np, rp, 0x7FFF); + return work_done; } @@ -3616,7 +3669,7 @@ static int niu_poll(struct napi_struct *napi, int budget) work_done = niu_poll_core(np, lp, budget); if (work_done < budget) { - netif_rx_complete(np->dev, napi); + netif_rx_complete(napi); niu_ldg_rearm(np, lp, 1); } return work_done; @@ -4035,12 +4088,12 @@ static void __niu_fastpath_interrupt(struct niu *np, int ldg, u64 v0) static void niu_schedule_napi(struct niu *np, struct niu_ldg *lp, u64 v0, u64 v1, u64 v2) { - if (likely(netif_rx_schedule_prep(np->dev, &lp->napi))) { + if (likely(netif_rx_schedule_prep(&lp->napi))) { lp->v0 = v0; lp->v1 = v1; lp->v2 = v2; __niu_fastpath_interrupt(np, lp->ldg_num, v0); - __netif_rx_schedule(np->dev, &lp->napi); + __netif_rx_schedule(&lp->napi); } } @@ -5849,17 +5902,42 @@ static void niu_stop_hw(struct niu *np) niu_reset_rx_channels(np); } +static void niu_set_irq_name(struct niu *np) +{ + int port = np->port; + int i, j = 1; + + sprintf(np->irq_name[0], "%s:MAC", np->dev->name); + + if (port == 0) { + sprintf(np->irq_name[1], "%s:MIF", np->dev->name); + sprintf(np->irq_name[2], "%s:SYSERR", np->dev->name); + j = 3; + } + + for (i = 0; i < np->num_ldg - j; i++) { + if (i < np->num_rx_rings) + sprintf(np->irq_name[i+j], "%s-rx-%d", + np->dev->name, i); + else if (i < np->num_tx_rings + np->num_rx_rings) + sprintf(np->irq_name[i+j], "%s-tx-%d", np->dev->name, + i - np->num_rx_rings); + } +} + static int niu_request_irq(struct niu *np) { int i, j, err; + niu_set_irq_name(np); + err = 0; for (i = 0; i < np->num_ldg; i++) { struct niu_ldg *lp = &np->ldg[i]; err = request_irq(lp->irq, niu_interrupt, IRQF_SHARED | IRQF_SAMPLE_RANDOM, - np->dev->name, lp); + np->irq_name[i], lp); if (err) goto out_free_irqs; @@ -6050,15 +6128,17 @@ static void niu_get_rx_stats(struct niu *np) for (i = 0; i < np->num_rx_rings; i++) { struct rx_ring_info *rp = &np->rx_rings[i]; + niu_sync_rx_discard_stats(np, rp, 0); + pkts += rp->rx_packets; bytes += rp->rx_bytes; dropped += rp->rx_dropped; errors += rp->rx_errors; } - np->net_stats.rx_packets = pkts; - np->net_stats.rx_bytes = bytes; - np->net_stats.rx_dropped = dropped; - np->net_stats.rx_errors = errors; + np->dev->stats.rx_packets = pkts; + np->dev->stats.rx_bytes = bytes; + np->dev->stats.rx_dropped = dropped; + np->dev->stats.rx_errors = errors; } static void niu_get_tx_stats(struct niu *np) @@ -6074,9 +6154,9 @@ static void niu_get_tx_stats(struct niu *np) bytes += rp->tx_bytes; errors += rp->tx_errors; } - np->net_stats.tx_packets = pkts; - np->net_stats.tx_bytes = bytes; - np->net_stats.tx_errors = errors; + np->dev->stats.tx_packets = pkts; + np->dev->stats.tx_bytes = bytes; + np->dev->stats.tx_errors = errors; } static struct net_device_stats *niu_get_stats(struct net_device *dev) @@ -6086,7 +6166,7 @@ static struct net_device_stats *niu_get_stats(struct net_device *dev) niu_get_rx_stats(np); niu_get_tx_stats(np); - return &np->net_stats; + return &dev->stats; } static void niu_load_hash_xmac(struct niu *np, u16 *hash) @@ -6991,6 +7071,8 @@ static void niu_get_ethtool_stats(struct net_device *dev, for (i = 0; i < np->num_rx_rings; i++) { struct rx_ring_info *rp = &np->rx_rings[i]; + niu_sync_rx_discard_stats(np, rp, 0); + data[0] = rp->rx_channel; data[1] = rp->rx_packets; data[2] = rp->rx_bytes; @@ -8824,7 +8906,7 @@ static u64 niu_pci_map_page(struct device *dev, struct page *page, static void niu_pci_unmap_page(struct device *dev, u64 dma_address, size_t size, enum dma_data_direction direction) { - return dma_unmap_page(dev, dma_address, size, direction); + dma_unmap_page(dev, dma_address, size, direction); } static u64 niu_pci_map_single(struct device *dev, void *cpu_addr, @@ -8891,28 +8973,31 @@ static struct net_device * __devinit niu_alloc_and_init( return dev; } +static const struct net_device_ops niu_netdev_ops = { + .ndo_open = niu_open, + .ndo_stop = niu_close, + .ndo_start_xmit = niu_start_xmit, + .ndo_get_stats = niu_get_stats, + .ndo_set_multicast_list = niu_set_rx_mode, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = niu_set_mac_addr, + .ndo_do_ioctl = niu_ioctl, + .ndo_tx_timeout = niu_tx_timeout, + .ndo_change_mtu = niu_change_mtu, +}; + static void __devinit niu_assign_netdev_ops(struct net_device *dev) { - dev->open = niu_open; - dev->stop = niu_close; - dev->get_stats = niu_get_stats; - dev->set_multicast_list = niu_set_rx_mode; - dev->set_mac_address = niu_set_mac_addr; - dev->do_ioctl = niu_ioctl; - dev->tx_timeout = niu_tx_timeout; - dev->hard_start_xmit = niu_start_xmit; + dev->netdev_ops = &niu_netdev_ops; dev->ethtool_ops = &niu_ethtool_ops; dev->watchdog_timeo = NIU_TX_TIMEOUT; - dev->change_mtu = niu_change_mtu; } static void __devinit niu_device_announce(struct niu *np) { struct net_device *dev = np->dev; - DECLARE_MAC_BUF(mac); - pr_info("%s: NIU Ethernet %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + pr_info("%s: NIU Ethernet %pM\n", dev->name, dev->dev_addr); if (np->parent->plat_type == PLAT_TYPE_ATCA_CP3220) { pr_info("%s: Port type[%s] mode[%s:%s] XCVR[%s] phy[%s]\n", diff --git a/drivers/net/niu.h b/drivers/net/niu.h index 180ca8ae93deabab7a6ddf201e4e2fb296487a2d..e1a7392e8d70a61bb7b4c6703f3e74bb9b0cd44e 100644 --- a/drivers/net/niu.h +++ b/drivers/net/niu.h @@ -3243,12 +3243,12 @@ struct niu { #define NIU_FLAGS_XMAC 0x00010000 /* 0=BMAC 1=XMAC */ u32 msg_enable; + char irq_name[NIU_NUM_RXCHAN+NIU_NUM_TXCHAN+3][IFNAMSIZ + 6]; /* Protects hw programming, and ring state. */ spinlock_t lock; const struct niu_ops *ops; - struct net_device_stats net_stats; union niu_mac_stats mac_stats; struct rx_ring_info *rx_rings; diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index ff449619f047e57fd36be41805b33bf6b66ec113..46b0772489e4d92b6298c6fcfdb51b95b8ac7c40 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -1948,14 +1948,25 @@ static void ns83820_probe_phy(struct net_device *ndev) } #endif -static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_device_id *id) +static const struct net_device_ops netdev_ops = { + .ndo_open = ns83820_open, + .ndo_stop = ns83820_stop, + .ndo_start_xmit = ns83820_hard_start_xmit, + .ndo_get_stats = ns83820_get_stats, + .ndo_change_mtu = ns83820_change_mtu, + .ndo_set_multicast_list = ns83820_set_multicast, + .ndo_validate_addr = eth_validate_addr, + .ndo_tx_timeout = ns83820_tx_timeout, +}; + +static int __devinit ns83820_init_one(struct pci_dev *pci_dev, + const struct pci_device_id *id) { struct net_device *ndev; struct ns83820 *dev; long addr; int err; int using_dac = 0; - DECLARE_MAC_BUF(mac); /* See if we can set the dma mask early on; failure is fatal. */ if (sizeof(dma_addr_t) == 8 && @@ -2041,14 +2052,8 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_ ndev->name, le32_to_cpu(readl(dev->base + 0x22c)), pci_dev->subsystem_vendor, pci_dev->subsystem_device); - ndev->open = ns83820_open; - ndev->stop = ns83820_stop; - ndev->hard_start_xmit = ns83820_hard_start_xmit; - ndev->get_stats = ns83820_get_stats; - ndev->change_mtu = ns83820_change_mtu; - ndev->set_multicast_list = ns83820_set_multicast; + ndev->netdev_ops = &netdev_ops; SET_ETHTOOL_OPS(ndev, &ops); - ndev->tx_timeout = ns83820_tx_timeout; ndev->watchdog_timeo = 5 * HZ; pci_set_drvdata(pci_dev, ndev); @@ -2220,12 +2225,11 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_ ndev->features |= NETIF_F_HIGHDMA; } - printk(KERN_INFO "%s: ns83820 v" VERSION ": DP83820 v%u.%u: %s io=0x%08lx irq=%d f=%s\n", + printk(KERN_INFO "%s: ns83820 v" VERSION ": DP83820 v%u.%u: %pM io=0x%08lx irq=%d f=%s\n", ndev->name, (unsigned)readl(dev->base + SRR) >> 8, (unsigned)readl(dev->base + SRR) & 0xff, - print_mac(mac, ndev->dev_addr), - addr, pci_dev->irq, + ndev->dev_addr, addr, pci_dev->irq, (ndev->features & NETIF_F_HIGHDMA) ? "h,sg" : "sg" ); diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index edc0fd588985f51da906e325398ae36bac2f715c..dcd199045613f3bbc4921ae2bee71d92f743ff62 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -971,7 +971,7 @@ static irqreturn_t pasemi_mac_rx_intr(int irq, void *data) if (*chan->status & PAS_STATUS_ERROR) reg |= PAS_IOB_DMA_RXCH_RESET_DINTC; - netif_rx_schedule(dev, &mac->napi); + netif_rx_schedule(&mac->napi); write_iob_reg(PAS_IOB_DMA_RXCH_RESET(chan->chno), reg); @@ -1011,7 +1011,7 @@ static irqreturn_t pasemi_mac_tx_intr(int irq, void *data) mod_timer(&txring->clean_timer, jiffies + (TX_CLEAN_INTERVAL)*2); - netif_rx_schedule(mac->netdev, &mac->napi); + netif_rx_schedule(&mac->napi); if (reg) write_iob_reg(PAS_IOB_DMA_TXCH_RESET(chan->chno), reg); @@ -1105,7 +1105,8 @@ static int pasemi_mac_phy_init(struct net_device *dev) goto err; phy_id = *prop; - snprintf(mac->phy_id, BUS_ID_SIZE, "%x:%02x", (int)r.start, phy_id); + snprintf(mac->phy_id, sizeof(mac->phy_id), "%x:%02x", + (int)r.start, phy_id); of_node_put(phy_dn); @@ -1640,7 +1641,7 @@ static int pasemi_mac_poll(struct napi_struct *napi, int budget) pkts = pasemi_mac_clean_rx(rx_ring(mac), budget); if (pkts < budget) { /* all done, no more packets present */ - netif_rx_complete(dev, napi); + netif_rx_complete(napi); pasemi_mac_restart_rx_intr(mac); pasemi_mac_restart_tx_intr(mac); @@ -1742,7 +1743,6 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct net_device *dev; struct pasemi_mac *mac; int err; - DECLARE_MAC_BUF(mac_buf); err = pci_enable_device(pdev); if (err) @@ -1849,9 +1849,9 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err); goto out; } else if netif_msg_probe(mac) - printk(KERN_INFO "%s: PA Semi %s: intf %d, hw addr %s\n", + printk(KERN_INFO "%s: PA Semi %s: intf %d, hw addr %pM\n", dev->name, mac->type == MAC_TYPE_GMAC ? "GMAC" : "XAUI", - mac->dma_if, print_mac(mac_buf, dev->dev_addr)); + mac->dma_if, dev->dev_addr); return err; diff --git a/drivers/net/pasemi_mac_ethtool.c b/drivers/net/pasemi_mac_ethtool.c index 5e8df3afea64e9fedaa15333910d970365bffd87..064a4fe1dd90efcee86a805ed6e94e1037385c2b 100644 --- a/drivers/net/pasemi_mac_ethtool.c +++ b/drivers/net/pasemi_mac_ethtool.c @@ -109,7 +109,7 @@ static void pasemi_mac_ethtool_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ering) { - struct pasemi_mac *mac = netdev->priv; + struct pasemi_mac *mac = netdev_priv(netdev); ering->tx_max_pending = TX_RING_SIZE/2; ering->tx_pending = RING_USED(mac->tx)/2; @@ -130,7 +130,7 @@ static int pasemi_mac_get_sset_count(struct net_device *netdev, int sset) static void pasemi_mac_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, u64 *data) { - struct pasemi_mac *mac = netdev->priv; + struct pasemi_mac *mac = netdev_priv(netdev); int i; data[0] = pasemi_read_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if)) diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c index 0a575fef29e64521b727ce231ae0cd7510589795..c95fd72c3bb96886a9862d27533ef20d650e32be 100644 --- a/drivers/net/pci-skeleton.c +++ b/drivers/net/pci-skeleton.c @@ -737,7 +737,6 @@ static int __devinit netdrv_init_one (struct pci_dev *pdev, int i, addr_len, option; void *ioaddr = NULL; static int board_idx = -1; - DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -782,7 +781,7 @@ static int __devinit netdrv_init_one (struct pci_dev *pdev, dev->irq = pdev->irq; dev->base_addr = (unsigned long) ioaddr; - /* dev->priv/tp zeroed and aligned in alloc_etherdev */ + /* netdev_priv()/tp zeroed and aligned in alloc_etherdev */ tp = netdev_priv(dev); /* note: tp->chipset set in netdrv_init_board */ @@ -797,11 +796,11 @@ static int __devinit netdrv_init_one (struct pci_dev *pdev, tp->phys[0] = 32; - printk (KERN_INFO "%s: %s at 0x%lx, %sIRQ %d\n", + printk (KERN_INFO "%s: %s at 0x%lx, %pM IRQ %d\n", dev->name, board_info[ent->driver_data].name, dev->base_addr, - print_mac(mac, dev->dev_addr), + dev->dev_addr, dev->irq); printk (KERN_DEBUG "%s: Identified 8139 chip type '%s'\n", @@ -1566,7 +1565,6 @@ static void netdrv_rx_interrupt (struct net_device *dev, skb->protocol = eth_type_trans (skb, dev); netif_rx (skb); - dev->last_rx = jiffies; dev->stats.rx_bytes += pkt_size; dev->stats.rx_packets++; } else { diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index 08c4dd896077b7199762821264c522cc721b065a..e5cb6b1f0ebd8be1aada0898403e79cb3a25d40f 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -345,7 +345,6 @@ static int tc574_config(struct pcmcia_device *link) __be16 *phys_addr; char *cardname; __u32 config; - DECLARE_MAC_BUF(mac); phys_addr = (__be16 *)dev->dev_addr; @@ -463,9 +462,9 @@ static int tc574_config(struct pcmcia_device *link) strcpy(lp->node.dev_name, dev->name); printk(KERN_INFO "%s: %s at io %#3lx, irq %d, " - "hw_addr %s.\n", + "hw_addr %pM.\n", dev->name, cardname, dev->base_addr, dev->irq, - print_mac(mac, dev->dev_addr)); + dev->dev_addr); printk(" %dK FIFO split %s Rx:Tx, %sMII interface.\n", 8 << config & Ram_size, ram_split[(config & Ram_split) >> Ram_split_shift], @@ -1062,7 +1061,6 @@ static int el3_rx(struct net_device *dev, int worklimit) ((pkt_len+3)>>2)); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } else { diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index c235cdba69c6384d11b83ace2b2a1aac2f4a1905..73ecc657999d69e899e4ddb2537e6aa1db376b1d 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -255,7 +255,6 @@ static int tc589_config(struct pcmcia_device *link) int last_fn, last_ret, i, j, multi = 0, fifo; unsigned int ioaddr; char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; - DECLARE_MAC_BUF(mac); DEBUG(0, "3c589_config(0x%p)\n", link); @@ -333,9 +332,9 @@ static int tc589_config(struct pcmcia_device *link) strcpy(lp->node.dev_name, dev->name); printk(KERN_INFO "%s: 3Com 3c%s, io %#3lx, irq %d, " - "hw_addr %s\n", + "hw_addr %pM\n", dev->name, (multi ? "562" : "589"), dev->base_addr, dev->irq, - print_mac(mac, dev->dev_addr)); + dev->dev_addr); printk(KERN_INFO " %dK FIFO split %s Rx:Tx, %s xcvr\n", (fifo & 7) ? 32 : 8, ram_split[(fifo >> 16) & 3], if_names[dev->if_port]); @@ -884,7 +883,6 @@ static int el3_rx(struct net_device *dev) (pkt_len+3)>>2); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } else { diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 0418045166c348f15431b94fbfa06af894bf6820..0afa72095810e0f9ace213d48f5858bcbf5c5cf7 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -321,7 +321,6 @@ static int axnet_config(struct pcmcia_device *link) struct net_device *dev = link->priv; axnet_dev_t *info = PRIV(dev); int i, j, last_ret, last_fn; - DECLARE_MAC_BUF(mac); DEBUG(0, "axnet_config(0x%p)\n", link); @@ -397,10 +396,10 @@ static int axnet_config(struct pcmcia_device *link) strcpy(info->node.dev_name, dev->name); printk(KERN_INFO "%s: Asix AX88%d90: io %#3lx, irq %d, " - "hw_addr %s\n", + "hw_addr %pM\n", dev->name, ((info->flags & IS_AX88790) ? 7 : 1), dev->base_addr, dev->irq, - print_mac(mac, dev->dev_addr)); + dev->dev_addr); if (info->phy_id != -1) { DEBUG(0, " MII transceiver at index %d, status %x.\n", info->phy_id, j); } else { @@ -906,7 +905,7 @@ int ei_debug = 1; /* Index to functions. */ static void ei_tx_intr(struct net_device *dev); static void ei_tx_err(struct net_device *dev); -static void ei_tx_timeout(struct net_device *dev); +static void axnet_tx_timeout(struct net_device *dev); static void ei_receive(struct net_device *dev); static void ei_rx_overrun(struct net_device *dev); @@ -957,9 +956,9 @@ static int ax_open(struct net_device *dev) #ifdef HAVE_TX_TIMEOUT /* The card I/O part of the driver (e.g. 3c503) can hook a Tx timeout - wrapper that does e.g. media check & then calls ei_tx_timeout. */ + wrapper that does e.g. media check & then calls axnet_tx_timeout. */ if (dev->tx_timeout == NULL) - dev->tx_timeout = ei_tx_timeout; + dev->tx_timeout = axnet_tx_timeout; if (dev->watchdog_timeo <= 0) dev->watchdog_timeo = TX_TIMEOUT; #endif @@ -1003,14 +1002,14 @@ static int ax_close(struct net_device *dev) } /** - * ei_tx_timeout - handle transmit time out condition + * axnet_tx_timeout - handle transmit time out condition * @dev: network device which has apparently fallen asleep * * Called by kernel when device never acknowledges a transmit has * completed (or failed) - i.e. never posted a Tx related interrupt. */ -static void ei_tx_timeout(struct net_device *dev) +static void axnet_tx_timeout(struct net_device *dev) { long e8390_base = dev->base_addr; struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); @@ -1047,14 +1046,14 @@ static void ei_tx_timeout(struct net_device *dev) } /** - * ei_start_xmit - begin packet transmission + * axnet_start_xmit - begin packet transmission * @skb: packet to be sent * @dev: network device to which packet is sent * * Sends a packet to an 8390 network device. */ -static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) +static int axnet_start_xmit(struct sk_buff *skb, struct net_device *dev) { long e8390_base = dev->base_addr; struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); @@ -1493,7 +1492,6 @@ static void ei_receive(struct net_device *dev) ei_block_input(dev, pkt_len, skb, current_offset + sizeof(rx_frame)); skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; if (pkt_stat & ENRSR_PHY) @@ -1720,7 +1718,7 @@ static void axdev_setup(struct net_device *dev) ei_local = (struct ei_device *)netdev_priv(dev); spin_lock_init(&ei_local->page_lock); - dev->hard_start_xmit = &ei_start_xmit; + dev->hard_start_xmit = &axnet_start_xmit; dev->get_stats = get_stats; dev->set_multicast_list = &set_multicast_list; diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c index 831090c756220fcc86743067d62eb36683517b57..7b5c77b7bd27ebc9185a99da37ac7bc0871c96fb 100644 --- a/drivers/net/pcmcia/com20020_cs.c +++ b/drivers/net/pcmcia/com20020_cs.c @@ -155,7 +155,7 @@ static int com20020_probe(struct pcmcia_device *p_dev) if (!dev) goto fail_alloc_dev; - lp = dev->priv; + lp = netdev_priv(dev); lp->timeout = timeout; lp->backplane = backplane; lp->clockp = clockp; @@ -303,7 +303,7 @@ static int com20020_config(struct pcmcia_device *link) goto failed; } - lp = dev->priv; + lp = netdev_priv(dev); lp->card_name = "PCMCIA COM20020"; lp->card_flags = ARC_CAN_10MBIT; /* pretend all of them can 10Mbit */ @@ -364,7 +364,7 @@ static int com20020_resume(struct pcmcia_device *link) if (link->open) { int ioaddr = dev->base_addr; - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); ARCRESET; } diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 69d916daa7bbb313440dbd4c2827a6779a715376..69dcfbbabe825229ca4f709315b9e29c9049cd76 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -125,6 +125,7 @@ typedef struct local_info_t { u_short tx_queue_len; cardtype_t cardtype; u_short sent; + u_char __iomem *base; } local_info_t; #define MC_FILTERBREAK 64 @@ -242,6 +243,7 @@ static int fmvj18x_probe(struct pcmcia_device *link) lp = netdev_priv(dev); link->priv = dev; lp->p_dev = link; + lp->base = NULL; /* The io structure describes IO port mapping */ link->io.NumPorts1 = 32; @@ -348,7 +350,6 @@ static int fmvj18x_config(struct pcmcia_device *link) cardtype_t cardtype; char *card_name = "unknown"; u_char *node_id; - DECLARE_MAC_BUF(mac); DEBUG(0, "fmvj18x_config(0x%p)\n", link); @@ -443,8 +444,10 @@ static int fmvj18x_config(struct pcmcia_device *link) dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; - if (link->io.BasePort2 != 0) - fmvj18x_setup_mfc(link); + if (link->io.BasePort2 != 0) { + ret = fmvj18x_setup_mfc(link); + if (ret != 0) goto failed; + } ioaddr = dev->base_addr; @@ -539,9 +542,9 @@ static int fmvj18x_config(struct pcmcia_device *link) /* print current configuration */ printk(KERN_INFO "%s: %s, sram %s, port %#3lx, irq %d, " - "hw_addr %s\n", + "hw_addr %pM\n", dev->name, card_name, sram_config == 0 ? "4K TX*2" : "8K TX*2", - dev->base_addr, dev->irq, print_mac(mac, dev->dev_addr)); + dev->base_addr, dev->irq, dev->dev_addr); return 0; @@ -611,10 +614,10 @@ static int fmvj18x_setup_mfc(struct pcmcia_device *link) { win_req_t req; memreq_t mem; - u_char __iomem *base; - int i, j; + int i; struct net_device *dev = link->priv; unsigned int ioaddr; + local_info_t *lp = netdev_priv(dev); /* Allocate a small memory window */ req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; @@ -626,25 +629,32 @@ static int fmvj18x_setup_mfc(struct pcmcia_device *link) return -1; } - base = ioremap(req.Base, req.Size); + lp->base = ioremap(req.Base, req.Size); + if (lp->base == NULL) { + printk(KERN_NOTICE "fmvj18x_cs: ioremap failed\n"); + return -1; + } + mem.Page = 0; mem.CardOffset = 0; - pcmcia_map_mem_page(link->win, &mem); - + i = pcmcia_map_mem_page(link->win, &mem); + if (i != 0) { + iounmap(lp->base); + lp->base = NULL; + cs_error(link, MapMemPage, i); + return -1; + } + ioaddr = dev->base_addr; - writeb(0x47, base+0x800); /* Config Option Register of LAN */ - writeb(0x0, base+0x802); /* Config and Status Register */ + writeb(0x47, lp->base+0x800); /* Config Option Register of LAN */ + writeb(0x0, lp->base+0x802); /* Config and Status Register */ - writeb(ioaddr & 0xff, base+0x80a); /* I/O Base(Low) of LAN */ - writeb((ioaddr >> 8) & 0xff, base+0x80c); /* I/O Base(High) of LAN */ + writeb(ioaddr & 0xff, lp->base+0x80a); /* I/O Base(Low) of LAN */ + writeb((ioaddr >> 8) & 0xff, lp->base+0x80c); /* I/O Base(High) of LAN */ - writeb(0x45, base+0x820); /* Config Option Register of Modem */ - writeb(0x8, base+0x822); /* Config and Status Register */ + writeb(0x45, lp->base+0x820); /* Config Option Register of Modem */ + writeb(0x8, lp->base+0x822); /* Config and Status Register */ - iounmap(base); - j = pcmcia_release_window(link->win); - if (j != 0) - cs_error(link, ReleaseWindow, j); return 0; } @@ -652,8 +662,25 @@ static int fmvj18x_setup_mfc(struct pcmcia_device *link) static void fmvj18x_release(struct pcmcia_device *link) { - DEBUG(0, "fmvj18x_release(0x%p)\n", link); - pcmcia_disable_device(link); + + struct net_device *dev = link->priv; + local_info_t *lp = netdev_priv(dev); + u_char __iomem *tmp; + int j; + + DEBUG(0, "fmvj18x_release(0x%p)\n", link); + + if (lp->base != NULL) { + tmp = lp->base; + lp->base = NULL; /* set NULL before iounmap */ + iounmap(tmp); + j = pcmcia_release_window(link->win); + if (j != 0) + cs_error(link, ReleaseWindow, j); + } + + pcmcia_disable_device(link); + } static int fmvj18x_suspend(struct pcmcia_device *link) @@ -784,6 +811,13 @@ static irqreturn_t fjn_interrupt(int dummy, void *dev_id) outb(D_TX_INTR, ioaddr + TX_INTR); outb(D_RX_INTR, ioaddr + RX_INTR); + + if (lp->base != NULL) { + /* Ack interrupt for multifunction card */ + writeb(0x01, lp->base+0x802); + writeb(0x09, lp->base+0x822); + } + return IRQ_HANDLED; } /* fjn_interrupt */ @@ -1036,7 +1070,6 @@ static void fjn_rx(struct net_device *dev) #endif netif_rx(skb); - dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes += pkt_len; } diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c index 448cd40aeba5ab37c2c913db34745ac87b2857fd..ec7c588c9ae5cf77eec416fa1c929a0f152a13af 100644 --- a/drivers/net/pcmcia/nmclan_cs.c +++ b/drivers/net/pcmcia/nmclan_cs.c @@ -659,7 +659,6 @@ static int nmclan_config(struct pcmcia_device *link) u_char buf[64]; int i, last_ret, last_fn; unsigned int ioaddr; - DECLARE_MAC_BUF(mac); DEBUG(0, "nmclan_config(0x%p)\n", link); @@ -719,9 +718,9 @@ static int nmclan_config(struct pcmcia_device *link) strcpy(lp->node.dev_name, dev->name); printk(KERN_INFO "%s: nmclan: port %#3lx, irq %d, %s port," - " hw_addr %s\n", + " hw_addr %pM\n", dev->name, dev->base_addr, dev->irq, if_names[dev->if_port], - print_mac(mac, dev->dev_addr)); + dev->dev_addr); return 0; cs_failed: @@ -1193,7 +1192,6 @@ static int mace_rx(struct net_device *dev, unsigned char RxCnt) netif_rx(skb); /* Send the packet to the upper (protocol) layers. */ - dev->last_rx = jiffies; lp->linux_stats.rx_packets++; lp->linux_stats.rx_bytes += pkt_len; outb(0xFF, ioaddr + AM2150_RCV_NEXT); /* skip to next frame */ diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index ce486f09449215dc08baec27aeb723dd0484b371..c38ed777f0a890a60f6092bea0ec0efb197b8e98 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -554,7 +554,6 @@ static int pcnet_config(struct pcmcia_device *link) int last_ret, last_fn, start_pg, stop_pg, cm_offset; int has_shmem = 0; hw_info_t *local_hw_info; - DECLARE_MAC_BUF(mac); DEBUG(0, "pcnet_config(0x%p)\n", link); @@ -675,7 +674,7 @@ static int pcnet_config(struct pcmcia_device *link) printk (" mem %#5lx,", dev->mem_start); if (info->flags & HAS_MISC_REG) printk(" %s xcvr,", if_names[dev->if_port]); - printk(" hw_addr %s\n", print_mac(mac, dev->dev_addr)); + printk(" hw_addr %pM\n", dev->dev_addr); return 0; cs_failed: diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index c74d6656d2662bcf5b2d91dcea374c062404b4b1..fccd53ef3c64738c2cb7d5141895f3c5e3251d30 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -949,7 +949,6 @@ static int smc91c92_config(struct pcmcia_device *link) int i, j, rev; unsigned int ioaddr; u_long mir; - DECLARE_MAC_BUF(mac); DEBUG(0, "smc91c92_config(0x%p)\n", link); @@ -1062,9 +1061,9 @@ static int smc91c92_config(struct pcmcia_device *link) strcpy(smc->node.dev_name, dev->name); printk(KERN_INFO "%s: smc91c%s rev %d: io %#3lx, irq %d, " - "hw_addr %s\n", + "hw_addr %pM\n", dev->name, name, (rev & 0x0f), dev->base_addr, dev->irq, - print_mac(mac, dev->dev_addr)); + dev->dev_addr); if (rev > 0) { if (mir & 0x3ff) diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index e1fd585e71315ea15ec07a6ed9b2e675db1df4d2..fef7e1861d6a3fbf25922e92ed68b7f4e8924138 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -772,7 +772,6 @@ xirc2ps_config(struct pcmcia_device * link) int err, i; u_char buf[64]; cistpl_lan_node_id_t *node_id = (cistpl_lan_node_id_t*)parse.funce.data; - DECLARE_MAC_BUF(mac); local->dingo_ccr = NULL; @@ -1051,9 +1050,9 @@ xirc2ps_config(struct pcmcia_device * link) strcpy(local->node.dev_name, dev->name); /* give some infos about the hardware */ - printk(KERN_INFO "%s: %s: port %#3lx, irq %d, hwaddr %s\n", + printk(KERN_INFO "%s: %s: port %#3lx, irq %d, hwaddr %pM\n", dev->name, local->manf_str,(u_long)dev->base_addr, (int)dev->irq, - print_mac(mac, dev->dev_addr)); + dev->dev_addr); return 0; @@ -1243,7 +1242,6 @@ xirc2ps_interrupt(int irq, void *dev_id) } skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes += pktlen; if (!(rsr & PhyPkt)) diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index ca8c0e03740027980ded217605ea394f5c5c3ca0..044b7b07f5f48cf83ebbb8c7adce3134a3470f04 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -1246,7 +1246,6 @@ static void pcnet32_rx_entry(struct net_device *dev, dev->stats.rx_bytes += skb->len; skb->protocol = eth_type_trans(skb, dev); netif_receive_skb(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; return; } @@ -1398,7 +1397,7 @@ static int pcnet32_poll(struct napi_struct *napi, int budget) if (work_done < budget) { spin_lock_irqsave(&lp->lock, flags); - __netif_rx_complete(dev, napi); + __netif_rx_complete(napi); /* clear interrupt masks */ val = lp->a.read_csr(ioaddr, CSR3); @@ -1747,8 +1746,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) memset(dev->dev_addr, 0, sizeof(dev->dev_addr)); if (pcnet32_debug & NETIF_MSG_PROBE) { - DECLARE_MAC_BUF(mac); - printk(" %s", print_mac(mac, dev->dev_addr)); + printk(" %pM", dev->dev_addr); /* Version 0x2623 and 0x2624 */ if (((chip_version + 1) & 0xfffe) == 0x2624) { @@ -2588,14 +2586,14 @@ pcnet32_interrupt(int irq, void *dev_id) dev->name, csr0); /* unlike for the lance, there is no restart needed */ } - if (netif_rx_schedule_prep(dev, &lp->napi)) { + if (netif_rx_schedule_prep(&lp->napi)) { u16 val; /* set interrupt masks */ val = lp->a.read_csr(ioaddr, CSR3); val |= 0x5f00; lp->a.write_csr(ioaddr, CSR3, val); mmiowb(); - __netif_rx_schedule(dev, &lp->napi); + __netif_rx_schedule(&lp->napi); break; } csr0 = lp->a.read_csr(ioaddr, CSR0); diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index d55932acd887fc3b41c32a359c92077e9dfbd7b8..de9cf5136fdcc4367aa981d8fbb517f54270c00e 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -66,6 +66,22 @@ config REALTEK_PHY ---help--- Supports the Realtek 821x PHY. +config NATIONAL_PHY + tristate "Drivers for National Semiconductor PHYs" + ---help--- + Currently supports the DP83865 PHY. + +config STE10XP + depends on PHYLIB + tristate "Driver for STMicroelectronics STe10Xp PHYs" + ---help--- + This is the driver for the STe100p and STe101p PHYs. + +config LSI_ET1011C_PHY + tristate "Driver for LSI ET1011C PHY" + ---help--- + Supports the LSI ET1011C PHY. + config FIXED_PHY bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs" depends on PHYLIB=y @@ -84,10 +100,13 @@ config MDIO_BITBANG If in doubt, say N. -config MDIO_OF_GPIO +config MDIO_GPIO tristate "Support for GPIO lib-based bitbanged MDIO buses" - depends on MDIO_BITBANG && OF_GPIO + depends on MDIO_BITBANG && GENERIC_GPIO ---help--- Supports GPIO lib-based MDIO busses. + To compile this driver as a module, choose M here: the module + will be called mdio-gpio. + endif # PHYLIB diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index eee329fa6f5355dfa1ef0817aa6ebc080553f8c5..3a1bfefefbc3b5d795f9716c6c7f1a086b8b81fe 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -13,6 +13,9 @@ obj-$(CONFIG_VITESSE_PHY) += vitesse.o obj-$(CONFIG_BROADCOM_PHY) += broadcom.o obj-$(CONFIG_ICPLUS_PHY) += icplus.o obj-$(CONFIG_REALTEK_PHY) += realtek.o +obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o obj-$(CONFIG_FIXED_PHY) += fixed.o obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o -obj-$(CONFIG_MDIO_OF_GPIO) += mdio-ofgpio.o +obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o +obj-$(CONFIG_NATIONAL_PHY) += national.o +obj-$(CONFIG_STE10XP) += ste10Xp.o diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index 4b4dc98ad165df01b96dcd9753419d383132461d..190efc3301c6c4b815f47efe7013483a7b43e282 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -17,6 +17,8 @@ #include #include +#define PHY_ID_BCM50610 0x0143bd60 + #define MII_BCM54XX_ECR 0x10 /* BCM54xx extended control register */ #define MII_BCM54XX_ECR_IM 0x1000 /* Interrupt mask */ #define MII_BCM54XX_ECR_IF 0x0800 /* Interrupt force */ @@ -53,6 +55,21 @@ #define MII_BCM54XX_SHD_VAL(x) ((x & 0x1f) << 10) #define MII_BCM54XX_SHD_DATA(x) ((x & 0x3ff) << 0) +/* + * AUXILIARY CONTROL SHADOW ACCESS REGISTERS. (PHY REG 0x18) + */ +#define MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL 0x0000 +#define MII_BCM54XX_AUXCTL_ACTL_TX_6DB 0x0400 +#define MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA 0x0800 + +#define MII_BCM54XX_AUXCTL_MISC_WREN 0x8000 +#define MII_BCM54XX_AUXCTL_MISC_FORCE_AMDIX 0x0200 +#define MII_BCM54XX_AUXCTL_MISC_RDSEL_MISC 0x7000 +#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC 0x0007 + +#define MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL 0x0000 + + /* * Broadcom LED source encodings. These are used in BCM5461, BCM5481, * BCM5482, and possibly some others. @@ -87,6 +104,24 @@ #define BCM5482_SHD_MODE 0x1f /* 11111: Mode Control Register */ #define BCM5482_SHD_MODE_1000BX 0x0001 /* Enable 1000BASE-X registers */ +/* + * EXPANSION SHADOW ACCESS REGISTERS. (PHY REG 0x15, 0x16, and 0x17) + */ +#define MII_BCM54XX_EXP_AADJ1CH0 0x001f +#define MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN 0x0200 +#define MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF 0x0100 +#define MII_BCM54XX_EXP_AADJ1CH3 0x601f +#define MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ 0x0002 +#define MII_BCM54XX_EXP_EXP08 0x0F08 +#define MII_BCM54XX_EXP_EXP08_RJCT_2MHZ 0x0001 +#define MII_BCM54XX_EXP_EXP08_EARLY_DAC_WAKE 0x0200 +#define MII_BCM54XX_EXP_EXP75 0x0f75 +#define MII_BCM54XX_EXP_EXP75_VDACCTRL 0x003c +#define MII_BCM54XX_EXP_EXP96 0x0f96 +#define MII_BCM54XX_EXP_EXP96_MYST 0x0010 +#define MII_BCM54XX_EXP_EXP97 0x0f97 +#define MII_BCM54XX_EXP_EXP97_MYST 0x0c0c + /* * BCM5482: Secondary SerDes registers */ @@ -128,40 +163,93 @@ static int bcm54xx_shadow_write(struct phy_device *phydev, u16 shadow, u16 val) MII_BCM54XX_SHD_DATA(val)); } -/* - * Indirect register access functions for the Expansion Registers - * and Secondary SerDes registers (when sec_serdes=1). - */ -static int bcm54xx_exp_read(struct phy_device *phydev, - int sec_serdes, u8 regnum) +/* Indirect register access functions for the Expansion Registers */ +static int bcm54xx_exp_read(struct phy_device *phydev, u8 regnum) { int val; - phy_write(phydev, MII_BCM54XX_EXP_SEL, - (sec_serdes ? MII_BCM54XX_EXP_SEL_SSD : - MII_BCM54XX_EXP_SEL_ER) | - regnum); + val = phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum); + if (val < 0) + return val; + val = phy_read(phydev, MII_BCM54XX_EXP_DATA); - phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum); + + /* Restore default value. It's O.K. if this write fails. */ + phy_write(phydev, MII_BCM54XX_EXP_SEL, 0); return val; } -static int bcm54xx_exp_write(struct phy_device *phydev, - int sec_serdes, u8 regnum, u16 val) +static int bcm54xx_exp_write(struct phy_device *phydev, u16 regnum, u16 val) { int ret; - phy_write(phydev, MII_BCM54XX_EXP_SEL, - (sec_serdes ? MII_BCM54XX_EXP_SEL_SSD : - MII_BCM54XX_EXP_SEL_ER) | - regnum); + ret = phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum); + if (ret < 0) + return ret; + ret = phy_write(phydev, MII_BCM54XX_EXP_DATA, val); - phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum); + + /* Restore default value. It's O.K. if this write fails. */ + phy_write(phydev, MII_BCM54XX_EXP_SEL, 0); return ret; } +static int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val) +{ + return phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum | val); +} + +static int bcm50610_a0_workaround(struct phy_device *phydev) +{ + int err; + + err = bcm54xx_auxctl_write(phydev, + MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL, + MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA | + MII_BCM54XX_AUXCTL_ACTL_TX_6DB); + if (err < 0) + return err; + + err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP08, + MII_BCM54XX_EXP_EXP08_RJCT_2MHZ | + MII_BCM54XX_EXP_EXP08_EARLY_DAC_WAKE); + if (err < 0) + goto error; + + err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH0, + MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN | + MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF); + if (err < 0) + goto error; + + err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH3, + MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ); + if (err < 0) + goto error; + + err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP75, + MII_BCM54XX_EXP_EXP75_VDACCTRL); + if (err < 0) + goto error; + + err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP96, + MII_BCM54XX_EXP_EXP96_MYST); + if (err < 0) + goto error; + + err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP97, + MII_BCM54XX_EXP_EXP97_MYST); + +error: + bcm54xx_auxctl_write(phydev, + MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL, + MII_BCM54XX_AUXCTL_ACTL_TX_6DB); + + return err; +} + static int bcm54xx_config_init(struct phy_device *phydev) { int reg, err; @@ -183,6 +271,13 @@ static int bcm54xx_config_init(struct phy_device *phydev) err = phy_write(phydev, MII_BCM54XX_IMR, reg); if (err < 0) return err; + + if (phydev->drv->phy_id == PHY_ID_BCM50610) { + err = bcm50610_a0_workaround(phydev); + if (err < 0) + return err; + } + return 0; } @@ -205,18 +300,27 @@ static int bcm5482_config_init(struct phy_device *phydev) /* * Enable SGMII slave mode and auto-detection */ - reg = bcm54xx_exp_read(phydev, 1, BCM5482_SSD_SGMII_SLAVE); - bcm54xx_exp_write(phydev, 1, BCM5482_SSD_SGMII_SLAVE, - reg | - BCM5482_SSD_SGMII_SLAVE_EN | - BCM5482_SSD_SGMII_SLAVE_AD); + reg = BCM5482_SSD_SGMII_SLAVE | MII_BCM54XX_EXP_SEL_SSD; + err = bcm54xx_exp_read(phydev, reg); + if (err < 0) + return err; + err = bcm54xx_exp_write(phydev, reg, err | + BCM5482_SSD_SGMII_SLAVE_EN | + BCM5482_SSD_SGMII_SLAVE_AD); + if (err < 0) + return err; /* * Disable secondary SerDes powerdown */ - reg = bcm54xx_exp_read(phydev, 1, BCM5482_SSD_1000BX_CTL); - bcm54xx_exp_write(phydev, 1, BCM5482_SSD_1000BX_CTL, - reg & ~BCM5482_SSD_1000BX_CTL_PWRDOWN); + reg = BCM5482_SSD_1000BX_CTL | MII_BCM54XX_EXP_SEL_SSD; + err = bcm54xx_exp_read(phydev, reg); + if (err < 0) + return err; + err = bcm54xx_exp_write(phydev, reg, + err & ~BCM5482_SSD_1000BX_CTL_PWRDOWN); + if (err < 0) + return err; /* * Select 1000BASE-X register set (primary SerDes) @@ -335,7 +439,8 @@ static struct phy_driver bcm5411_driver = { .phy_id = 0x00206070, .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM5411", - .features = PHY_GBIT_FEATURES, + .features = PHY_GBIT_FEATURES | + SUPPORTED_Pause | SUPPORTED_Asym_Pause, .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, .config_init = bcm54xx_config_init, .config_aneg = genphy_config_aneg, @@ -349,7 +454,8 @@ static struct phy_driver bcm5421_driver = { .phy_id = 0x002060e0, .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM5421", - .features = PHY_GBIT_FEATURES, + .features = PHY_GBIT_FEATURES | + SUPPORTED_Pause | SUPPORTED_Asym_Pause, .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, .config_init = bcm54xx_config_init, .config_aneg = genphy_config_aneg, @@ -363,7 +469,8 @@ static struct phy_driver bcm5461_driver = { .phy_id = 0x002060c0, .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM5461", - .features = PHY_GBIT_FEATURES, + .features = PHY_GBIT_FEATURES | + SUPPORTED_Pause | SUPPORTED_Asym_Pause, .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, .config_init = bcm54xx_config_init, .config_aneg = genphy_config_aneg, @@ -377,7 +484,8 @@ static struct phy_driver bcm5464_driver = { .phy_id = 0x002060b0, .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM5464", - .features = PHY_GBIT_FEATURES, + .features = PHY_GBIT_FEATURES | + SUPPORTED_Pause | SUPPORTED_Asym_Pause, .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, .config_init = bcm54xx_config_init, .config_aneg = genphy_config_aneg, @@ -391,7 +499,8 @@ static struct phy_driver bcm5481_driver = { .phy_id = 0x0143bca0, .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM5481", - .features = PHY_GBIT_FEATURES, + .features = PHY_GBIT_FEATURES | + SUPPORTED_Pause | SUPPORTED_Asym_Pause, .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, .config_init = bcm54xx_config_init, .config_aneg = bcm5481_config_aneg, @@ -405,7 +514,8 @@ static struct phy_driver bcm5482_driver = { .phy_id = 0x0143bcb0, .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM5482", - .features = PHY_GBIT_FEATURES, + .features = PHY_GBIT_FEATURES | + SUPPORTED_Pause | SUPPORTED_Asym_Pause, .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, .config_init = bcm5482_config_init, .config_aneg = genphy_config_aneg, @@ -415,6 +525,36 @@ static struct phy_driver bcm5482_driver = { .driver = { .owner = THIS_MODULE }, }; +static struct phy_driver bcm50610_driver = { + .phy_id = PHY_ID_BCM50610, + .phy_id_mask = 0xfffffff0, + .name = "Broadcom BCM50610", + .features = PHY_GBIT_FEATURES | + SUPPORTED_Pause | SUPPORTED_Asym_Pause, + .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .config_init = bcm54xx_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .ack_interrupt = bcm54xx_ack_interrupt, + .config_intr = bcm54xx_config_intr, + .driver = { .owner = THIS_MODULE }, +}; + +static struct phy_driver bcm57780_driver = { + .phy_id = 0x03625d90, + .phy_id_mask = 0xfffffff0, + .name = "Broadcom BCM57780", + .features = PHY_GBIT_FEATURES | + SUPPORTED_Pause | SUPPORTED_Asym_Pause, + .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .config_init = bcm54xx_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .ack_interrupt = bcm54xx_ack_interrupt, + .config_intr = bcm54xx_config_intr, + .driver = { .owner = THIS_MODULE }, +}; + static int __init broadcom_init(void) { int ret; @@ -437,8 +577,18 @@ static int __init broadcom_init(void) ret = phy_driver_register(&bcm5482_driver); if (ret) goto out_5482; + ret = phy_driver_register(&bcm50610_driver); + if (ret) + goto out_50610; + ret = phy_driver_register(&bcm57780_driver); + if (ret) + goto out_57780; return ret; +out_57780: + phy_driver_unregister(&bcm50610_driver); +out_50610: + phy_driver_unregister(&bcm5482_driver); out_5482: phy_driver_unregister(&bcm5481_driver); out_5481: @@ -455,6 +605,8 @@ static int __init broadcom_init(void) static void __exit broadcom_exit(void) { + phy_driver_unregister(&bcm57780_driver); + phy_driver_unregister(&bcm50610_driver); phy_driver_unregister(&bcm5482_driver); phy_driver_unregister(&bcm5481_driver); phy_driver_unregister(&bcm5464_driver); diff --git a/drivers/net/phy/et1011c.c b/drivers/net/phy/et1011c.c new file mode 100644 index 0000000000000000000000000000000000000000..b031fa21f1aa0a6f4640e9a61099210ab0a88306 --- /dev/null +++ b/drivers/net/phy/et1011c.c @@ -0,0 +1,113 @@ +/* + * drivers/net/phy/et1011c.c + * + * Driver for LSI ET1011C PHYs + * + * Author: Chaithrika U S + * + * Copyright (c) 2008 Texas Instruments + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ET1011C_STATUS_REG (0x1A) +#define ET1011C_CONFIG_REG (0x16) +#define ET1011C_SPEED_MASK (0x0300) +#define ET1011C_GIGABIT_SPEED (0x0200) +#define ET1011C_TX_FIFO_MASK (0x3000) +#define ET1011C_TX_FIFO_DEPTH_8 (0x0000) +#define ET1011C_TX_FIFO_DEPTH_16 (0x1000) +#define ET1011C_INTERFACE_MASK (0x0007) +#define ET1011C_GMII_INTERFACE (0x0002) +#define ET1011C_SYS_CLK_EN (0x01 << 4) + + +MODULE_DESCRIPTION("LSI ET1011C PHY driver"); +MODULE_AUTHOR("Chaithrika U S"); +MODULE_LICENSE("GPL"); + +static int et1011c_config_aneg(struct phy_device *phydev) +{ + int ctl = 0; + ctl = phy_read(phydev, MII_BMCR); + if (ctl < 0) + return ctl; + ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | + BMCR_ANENABLE); + /* First clear the PHY */ + phy_write(phydev, MII_BMCR, ctl | BMCR_RESET); + + return genphy_config_aneg(phydev); +} + +static int et1011c_read_status(struct phy_device *phydev) +{ + int ret; + u32 val; + static int speed; + ret = genphy_read_status(phydev); + + if (speed != phydev->speed) { + speed = phydev->speed; + val = phy_read(phydev, ET1011C_STATUS_REG); + if ((val & ET1011C_SPEED_MASK) == + ET1011C_GIGABIT_SPEED) { + val = phy_read(phydev, ET1011C_CONFIG_REG); + val &= ~ET1011C_TX_FIFO_MASK; + phy_write(phydev, ET1011C_CONFIG_REG, val\ + | ET1011C_GMII_INTERFACE\ + | ET1011C_SYS_CLK_EN\ + | ET1011C_TX_FIFO_DEPTH_16); + + } + } + return ret; +} + +static struct phy_driver et1011c_driver = { + .phy_id = 0x0282f014, + .name = "ET1011C", + .phy_id_mask = 0xfffffff0, + .features = (PHY_BASIC_FEATURES | SUPPORTED_1000baseT_Full), + .flags = PHY_POLL, + .config_aneg = et1011c_config_aneg, + .read_status = et1011c_read_status, + .driver = { .owner = THIS_MODULE,}, +}; + +static int __init et1011c_init(void) +{ + return phy_driver_register(&et1011c_driver); +} + +static void __exit et1011c_exit(void) +{ + phy_driver_unregister(&et1011c_driver); +} + +module_init(et1011c_init); +module_exit(et1011c_exit); diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c new file mode 100644 index 0000000000000000000000000000000000000000..a439ebeb431926e7bec18d84dcd22a8bc30f5b53 --- /dev/null +++ b/drivers/net/phy/mdio-gpio.c @@ -0,0 +1,296 @@ +/* + * GPIO based MDIO bitbang driver. + * Supports OpenFirmware. + * + * Copyright (c) 2008 CSE Semaphore Belgium. + * by Laurent Pinchart + * + * Copyright (C) 2008, Paulius Zaleckas + * + * Based on earlier work by + * + * Copyright (c) 2003 Intracom S.A. + * by Pantelis Antoniou + * + * 2005 (c) MontaVista Software, Inc. + * Vitaly Bordug + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_OF_GPIO +#include +#include +#endif + +struct mdio_gpio_info { + struct mdiobb_ctrl ctrl; + int mdc, mdio; +}; + +static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir) +{ + struct mdio_gpio_info *bitbang = + container_of(ctrl, struct mdio_gpio_info, ctrl); + + if (dir) + gpio_direction_output(bitbang->mdio, 1); + else + gpio_direction_input(bitbang->mdio); +} + +static int mdio_get(struct mdiobb_ctrl *ctrl) +{ + struct mdio_gpio_info *bitbang = + container_of(ctrl, struct mdio_gpio_info, ctrl); + + return gpio_get_value(bitbang->mdio); +} + +static void mdio_set(struct mdiobb_ctrl *ctrl, int what) +{ + struct mdio_gpio_info *bitbang = + container_of(ctrl, struct mdio_gpio_info, ctrl); + + gpio_set_value(bitbang->mdio, what); +} + +static void mdc_set(struct mdiobb_ctrl *ctrl, int what) +{ + struct mdio_gpio_info *bitbang = + container_of(ctrl, struct mdio_gpio_info, ctrl); + + gpio_set_value(bitbang->mdc, what); +} + +static struct mdiobb_ops mdio_gpio_ops = { + .owner = THIS_MODULE, + .set_mdc = mdc_set, + .set_mdio_dir = mdio_dir, + .set_mdio_data = mdio_set, + .get_mdio_data = mdio_get, +}; + +static int __devinit mdio_gpio_bus_init(struct device *dev, + struct mdio_gpio_platform_data *pdata, + int bus_id) +{ + struct mii_bus *new_bus; + struct mdio_gpio_info *bitbang; + int ret = -ENOMEM; + int i; + + bitbang = kzalloc(sizeof(*bitbang), GFP_KERNEL); + if (!bitbang) + goto out; + + bitbang->ctrl.ops = &mdio_gpio_ops; + bitbang->mdc = pdata->mdc; + bitbang->mdio = pdata->mdio; + + new_bus = alloc_mdio_bitbang(&bitbang->ctrl); + if (!new_bus) + goto out_free_bitbang; + + new_bus->name = "GPIO Bitbanged MDIO", + + ret = -ENODEV; + + new_bus->phy_mask = pdata->phy_mask; + new_bus->irq = pdata->irqs; + new_bus->parent = dev; + + if (new_bus->phy_mask == ~0) + goto out_free_bus; + + for (i = 0; i < PHY_MAX_ADDR; i++) + if (!new_bus->irq[i]) + new_bus->irq[i] = PHY_POLL; + + snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", bus_id); + + if (gpio_request(bitbang->mdc, "mdc")) + goto out_free_bus; + + if (gpio_request(bitbang->mdio, "mdio")) + goto out_free_mdc; + + dev_set_drvdata(dev, new_bus); + + ret = mdiobus_register(new_bus); + if (ret) + goto out_free_all; + + return 0; + +out_free_all: + dev_set_drvdata(dev, NULL); + gpio_free(bitbang->mdio); +out_free_mdc: + gpio_free(bitbang->mdc); +out_free_bus: + free_mdio_bitbang(new_bus); +out_free_bitbang: + kfree(bitbang); +out: + return ret; +} + +static void __devexit mdio_gpio_bus_destroy(struct device *dev) +{ + struct mii_bus *bus = dev_get_drvdata(dev); + struct mdio_gpio_info *bitbang = bus->priv; + + mdiobus_unregister(bus); + free_mdio_bitbang(bus); + dev_set_drvdata(dev, NULL); + gpio_free(bitbang->mdc); + gpio_free(bitbang->mdio); + kfree(bitbang); +} + +static int __devinit mdio_gpio_probe(struct platform_device *pdev) +{ + struct mdio_gpio_platform_data *pdata = pdev->dev.platform_data; + + if (!pdata) + return -ENODEV; + + return mdio_gpio_bus_init(&pdev->dev, pdata, pdev->id); +} + +static int __devexit mdio_gpio_remove(struct platform_device *pdev) +{ + mdio_gpio_bus_destroy(&pdev->dev); + + return 0; +} + +#ifdef CONFIG_OF_GPIO +static void __devinit add_phy(struct mdio_gpio_platform_data *pdata, + struct device_node *np) +{ + const u32 *data; + int len, id, irq; + + data = of_get_property(np, "reg", &len); + if (!data || len != 4) + return; + + id = *data; + pdata->phy_mask &= ~(1 << id); + + irq = of_irq_to_resource(np, 0, NULL); + if (irq) + pdata->irqs[id] = irq; +} + +static int __devinit mdio_ofgpio_probe(struct of_device *ofdev, + const struct of_device_id *match) +{ + struct device_node *np = NULL; + struct mdio_gpio_platform_data *pdata; + + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + pdata->mdc = of_get_gpio(ofdev->node, 0); + pdata->mdio = of_get_gpio(ofdev->node, 1); + + if (pdata->mdc < 0 || pdata->mdio < 0) + goto out_free; + + while ((np = of_get_next_child(ofdev->node, np))) + if (!strcmp(np->type, "ethernet-phy")) + add_phy(pdata, np); + + return mdio_gpio_bus_init(&ofdev->dev, pdata, pdata->mdc); + +out_free: + kfree(pdata); + return -ENODEV; +} + +static int __devexit mdio_ofgpio_remove(struct of_device *ofdev) +{ + mdio_gpio_bus_destroy(&ofdev->dev); + kfree(ofdev->dev.platform_data); + + return 0; +} + +static struct of_device_id mdio_ofgpio_match[] = { + { + .compatible = "virtual,mdio-gpio", + }, + {}, +}; + +static struct of_platform_driver mdio_ofgpio_driver = { + .name = "mdio-gpio", + .match_table = mdio_ofgpio_match, + .probe = mdio_ofgpio_probe, + .remove = __devexit_p(mdio_ofgpio_remove), +}; + +static inline int __init mdio_ofgpio_init(void) +{ + return of_register_platform_driver(&mdio_ofgpio_driver); +} + +static inline void __exit mdio_ofgpio_exit(void) +{ + of_unregister_platform_driver(&mdio_ofgpio_driver); +} +#else +static inline int __init mdio_ofgpio_init(void) { return 0; } +static inline void __exit mdio_ofgpio_exit(void) { } +#endif /* CONFIG_OF_GPIO */ + +static struct platform_driver mdio_gpio_driver = { + .probe = mdio_gpio_probe, + .remove = __devexit_p(mdio_gpio_remove), + .driver = { + .name = "mdio-gpio", + .owner = THIS_MODULE, + }, +}; + +static int __init mdio_gpio_init(void) +{ + int ret; + + ret = mdio_ofgpio_init(); + if (ret) + return ret; + + ret = platform_driver_register(&mdio_gpio_driver); + if (ret) + mdio_ofgpio_exit(); + + return ret; +} +module_init(mdio_gpio_init); + +static void __exit mdio_gpio_exit(void) +{ + platform_driver_unregister(&mdio_gpio_driver); + mdio_ofgpio_exit(); +} +module_exit(mdio_gpio_exit); + +MODULE_ALIAS("platform:mdio-gpio"); +MODULE_AUTHOR("Laurent Pinchart, Paulius Zaleckas"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Generic driver for MDIO bus emulation using GPIO"); diff --git a/drivers/net/phy/mdio-ofgpio.c b/drivers/net/phy/mdio-ofgpio.c deleted file mode 100644 index 2ff97754e574cffec278cb3a7188ca875524fd24..0000000000000000000000000000000000000000 --- a/drivers/net/phy/mdio-ofgpio.c +++ /dev/null @@ -1,204 +0,0 @@ -/* - * OpenFirmware GPIO based MDIO bitbang driver. - * - * Copyright (c) 2008 CSE Semaphore Belgium. - * by Laurent Pinchart - * - * Based on earlier work by - * - * Copyright (c) 2003 Intracom S.A. - * by Pantelis Antoniou - * - * 2005 (c) MontaVista Software, Inc. - * Vitaly Bordug - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ - -#include -#include -#include -#include -#include -#include -#include - -struct mdio_gpio_info { - struct mdiobb_ctrl ctrl; - int mdc, mdio; -}; - -static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir) -{ - struct mdio_gpio_info *bitbang = - container_of(ctrl, struct mdio_gpio_info, ctrl); - - if (dir) - gpio_direction_output(bitbang->mdio, 1); - else - gpio_direction_input(bitbang->mdio); -} - -static int mdio_read(struct mdiobb_ctrl *ctrl) -{ - struct mdio_gpio_info *bitbang = - container_of(ctrl, struct mdio_gpio_info, ctrl); - - return gpio_get_value(bitbang->mdio); -} - -static void mdio(struct mdiobb_ctrl *ctrl, int what) -{ - struct mdio_gpio_info *bitbang = - container_of(ctrl, struct mdio_gpio_info, ctrl); - - gpio_set_value(bitbang->mdio, what); -} - -static void mdc(struct mdiobb_ctrl *ctrl, int what) -{ - struct mdio_gpio_info *bitbang = - container_of(ctrl, struct mdio_gpio_info, ctrl); - - gpio_set_value(bitbang->mdc, what); -} - -static struct mdiobb_ops mdio_gpio_ops = { - .owner = THIS_MODULE, - .set_mdc = mdc, - .set_mdio_dir = mdio_dir, - .set_mdio_data = mdio, - .get_mdio_data = mdio_read, -}; - -static int __devinit mdio_ofgpio_bitbang_init(struct mii_bus *bus, - struct device_node *np) -{ - struct mdio_gpio_info *bitbang = bus->priv; - - bitbang->mdc = of_get_gpio(np, 0); - bitbang->mdio = of_get_gpio(np, 1); - - if (bitbang->mdc < 0 || bitbang->mdio < 0) - return -ENODEV; - - snprintf(bus->id, MII_BUS_ID_SIZE, "%x", bitbang->mdc); - return 0; -} - -static void __devinit add_phy(struct mii_bus *bus, struct device_node *np) -{ - const u32 *data; - int len, id, irq; - - data = of_get_property(np, "reg", &len); - if (!data || len != 4) - return; - - id = *data; - bus->phy_mask &= ~(1 << id); - - irq = of_irq_to_resource(np, 0, NULL); - if (irq != NO_IRQ) - bus->irq[id] = irq; -} - -static int __devinit mdio_ofgpio_probe(struct of_device *ofdev, - const struct of_device_id *match) -{ - struct device_node *np = NULL; - struct mii_bus *new_bus; - struct mdio_gpio_info *bitbang; - int ret = -ENOMEM; - int i; - - bitbang = kzalloc(sizeof(struct mdio_gpio_info), GFP_KERNEL); - if (!bitbang) - goto out; - - bitbang->ctrl.ops = &mdio_gpio_ops; - - new_bus = alloc_mdio_bitbang(&bitbang->ctrl); - if (!new_bus) - goto out_free_bitbang; - - new_bus->name = "GPIO Bitbanged MII", - - ret = mdio_ofgpio_bitbang_init(new_bus, ofdev->node); - if (ret) - goto out_free_bus; - - new_bus->phy_mask = ~0; - new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); - if (!new_bus->irq) - goto out_free_bus; - - for (i = 0; i < PHY_MAX_ADDR; i++) - new_bus->irq[i] = -1; - - while ((np = of_get_next_child(ofdev->node, np))) - if (!strcmp(np->type, "ethernet-phy")) - add_phy(new_bus, np); - - new_bus->parent = &ofdev->dev; - dev_set_drvdata(&ofdev->dev, new_bus); - - ret = mdiobus_register(new_bus); - if (ret) - goto out_free_irqs; - - return 0; - -out_free_irqs: - dev_set_drvdata(&ofdev->dev, NULL); - kfree(new_bus->irq); -out_free_bus: - free_mdio_bitbang(new_bus); -out_free_bitbang: - kfree(bitbang); -out: - return ret; -} - -static int mdio_ofgpio_remove(struct of_device *ofdev) -{ - struct mii_bus *bus = dev_get_drvdata(&ofdev->dev); - struct mdio_gpio_info *bitbang = bus->priv; - - mdiobus_unregister(bus); - kfree(bus->irq); - free_mdio_bitbang(bus); - dev_set_drvdata(&ofdev->dev, NULL); - kfree(bitbang); - - return 0; -} - -static struct of_device_id mdio_ofgpio_match[] = { - { - .compatible = "virtual,mdio-gpio", - }, - {}, -}; - -static struct of_platform_driver mdio_ofgpio_driver = { - .name = "mdio-gpio", - .match_table = mdio_ofgpio_match, - .probe = mdio_ofgpio_probe, - .remove = mdio_ofgpio_remove, -}; - -static int mdio_ofgpio_init(void) -{ - return of_register_platform_driver(&mdio_ofgpio_driver); -} - -static void mdio_ofgpio_exit(void) -{ - of_unregister_platform_driver(&mdio_ofgpio_driver); -} - -module_init(mdio_ofgpio_init); -module_exit(mdio_ofgpio_exit); diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 289fc267edf30eb5094d24f416ca644c9494d401..11adf6ed46288cf1e48a329d555feda84d1d442b 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -63,7 +63,9 @@ EXPORT_SYMBOL(mdiobus_alloc); static void mdiobus_release(struct device *d) { struct mii_bus *bus = to_mii_bus(d); - BUG_ON(bus->state != MDIOBUS_RELEASED); + BUG_ON(bus->state != MDIOBUS_RELEASED && + /* for compatibility with error handling in drivers */ + bus->state != MDIOBUS_ALLOCATED); kfree(bus); } @@ -83,8 +85,7 @@ static struct class mdio_bus_class = { */ int mdiobus_register(struct mii_bus *bus) { - int i; - int err = 0; + int i, err; if (NULL == bus || NULL == bus->name || NULL == bus->read || @@ -97,7 +98,7 @@ int mdiobus_register(struct mii_bus *bus) bus->dev.parent = bus->parent; bus->dev.class = &mdio_bus_class; bus->dev.groups = NULL; - memcpy(bus->dev.bus_id, bus->id, MII_BUS_ID_SIZE); + dev_set_name(&bus->dev, bus->id); err = device_register(&bus->dev); if (err) { @@ -116,16 +117,23 @@ int mdiobus_register(struct mii_bus *bus) struct phy_device *phydev; phydev = mdiobus_scan(bus, i); - if (IS_ERR(phydev)) + if (IS_ERR(phydev)) { err = PTR_ERR(phydev); + goto error; + } } } - if (!err) - bus->state = MDIOBUS_REGISTERED; - + bus->state = MDIOBUS_REGISTERED; pr_info("%s: probed\n", bus->name); + return 0; +error: + while (--i >= 0) { + if (bus->phy_map[i]) + device_unregister(&bus->phy_map[i]->dev); + } + device_del(&bus->dev); return err; } EXPORT_SYMBOL(mdiobus_register); @@ -192,7 +200,7 @@ struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr) phydev->dev.parent = bus->parent; phydev->dev.bus = &mdio_bus_type; - snprintf(phydev->dev.bus_id, BUS_ID_SIZE, PHY_ID_FMT, bus->id, addr); + dev_set_name(&phydev->dev, PHY_ID_FMT, bus->id, addr); phydev->bus = bus; @@ -285,9 +293,12 @@ static int mdio_bus_suspend(struct device * dev, pm_message_t state) { int ret = 0; struct device_driver *drv = dev->driver; + struct phy_driver *phydrv = to_phy_driver(drv); + struct phy_device *phydev = to_phy_device(dev); - if (drv && drv->suspend) - ret = drv->suspend(dev, state); + if ((!device_may_wakeup(phydev->dev.parent)) && + (phydrv && phydrv->suspend)) + ret = phydrv->suspend(phydev); return ret; } @@ -296,9 +307,12 @@ static int mdio_bus_resume(struct device * dev) { int ret = 0; struct device_driver *drv = dev->driver; + struct phy_driver *phydrv = to_phy_driver(drv); + struct phy_device *phydev = to_phy_device(dev); - if (drv && drv->resume) - ret = drv->resume(dev); + if ((!device_may_wakeup(phydev->dev.parent)) && + (phydrv && phydrv->resume)) + ret = phydrv->resume(phydev); return ret; } diff --git a/drivers/net/phy/national.c b/drivers/net/phy/national.c new file mode 100644 index 0000000000000000000000000000000000000000..6c636eb720896c79b0be943e16c1f2b743c10d46 --- /dev/null +++ b/drivers/net/phy/national.c @@ -0,0 +1,155 @@ +/* + * drivers/net/phy/national.c + * + * Driver for National Semiconductor PHYs + * + * Author: Stuart Menefy + * Maintainer: Giuseppe Cavallaro + * + * Copyright (c) 2008 STMicroelectronics Limited + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include + +/* DP83865 phy identifier values */ +#define DP83865_PHY_ID 0x20005c7a + +#define DP83865_INT_MASK_REG 0x15 +#define DP83865_INT_MASK_STATUS 0x14 + +#define DP83865_INT_REMOTE_FAULT 0x0008 +#define DP83865_INT_ANE_COMPLETED 0x0010 +#define DP83865_INT_LINK_CHANGE 0xe000 +#define DP83865_INT_MASK_DEFAULT (DP83865_INT_REMOTE_FAULT | \ + DP83865_INT_ANE_COMPLETED | \ + DP83865_INT_LINK_CHANGE) + +/* Advanced proprietary configuration */ +#define NS_EXP_MEM_CTL 0x16 +#define NS_EXP_MEM_DATA 0x1d +#define NS_EXP_MEM_ADD 0x1e + +#define LED_CTRL_REG 0x13 +#define AN_FALLBACK_AN 0x0001 +#define AN_FALLBACK_CRC 0x0002 +#define AN_FALLBACK_IE 0x0004 +#define ALL_FALLBACK_ON (AN_FALLBACK_AN | AN_FALLBACK_CRC | AN_FALLBACK_IE) + +enum hdx_loopback { + hdx_loopback_on = 0, + hdx_loopback_off = 1, +}; + +static u8 ns_exp_read(struct phy_device *phydev, u16 reg) +{ + phy_write(phydev, NS_EXP_MEM_ADD, reg); + return phy_read(phydev, NS_EXP_MEM_DATA); +} + +static void ns_exp_write(struct phy_device *phydev, u16 reg, u8 data) +{ + phy_write(phydev, NS_EXP_MEM_ADD, reg); + phy_write(phydev, NS_EXP_MEM_DATA, data); +} + +static int ns_config_intr(struct phy_device *phydev) +{ + int err; + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) + err = phy_write(phydev, DP83865_INT_MASK_REG, + DP83865_INT_MASK_DEFAULT); + else + err = phy_write(phydev, DP83865_INT_MASK_REG, 0); + + return err; +} + +static int ns_ack_interrupt(struct phy_device *phydev) +{ + int ret = phy_read(phydev, DP83865_INT_MASK_STATUS); + if (ret < 0) + return ret; + + return 0; +} + +static void ns_giga_speed_fallback(struct phy_device *phydev, int mode) +{ + int bmcr = phy_read(phydev, MII_BMCR); + + phy_write(phydev, MII_BMCR, (bmcr | BMCR_PDOWN)); + + /* Enable 8 bit expended memory read/write (no auto increment) */ + phy_write(phydev, NS_EXP_MEM_CTL, 0); + phy_write(phydev, NS_EXP_MEM_ADD, 0x1C0); + phy_write(phydev, NS_EXP_MEM_DATA, 0x0008); + phy_write(phydev, MII_BMCR, (bmcr & ~BMCR_PDOWN)); + phy_write(phydev, LED_CTRL_REG, mode); + return; +} + +static void ns_10_base_t_hdx_loopack(struct phy_device *phydev, int disable) +{ + if (disable) + ns_exp_write(phydev, 0x1c0, ns_exp_read(phydev, 0x1c0) | 1); + else + ns_exp_write(phydev, 0x1c0, + ns_exp_read(phydev, 0x1c0) & 0xfffe); + + printk(KERN_DEBUG "DP83865 PHY: 10BASE-T HDX loopback %s\n", + (ns_exp_read(phydev, 0x1c0) & 0x0001) ? "off" : "on"); + + return; +} + +static int ns_config_init(struct phy_device *phydev) +{ + ns_giga_speed_fallback(phydev, ALL_FALLBACK_ON); + /* In the latest MAC or switches design, the 10 Mbps loopback + is desired to be turned off. */ + ns_10_base_t_hdx_loopack(phydev, hdx_loopback_off); + return ns_ack_interrupt(phydev); +} + +static struct phy_driver dp83865_driver = { + .phy_id = DP83865_PHY_ID, + .phy_id_mask = 0xfffffff0, + .name = "NatSemi DP83865", + .features = PHY_GBIT_FEATURES | SUPPORTED_Pause | SUPPORTED_Asym_Pause, + .flags = PHY_HAS_INTERRUPT, + .config_init = ns_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .ack_interrupt = ns_ack_interrupt, + .config_intr = ns_config_intr, + .driver = {.owner = THIS_MODULE,} +}; + +static int __init ns_init(void) +{ + return phy_driver_register(&dp83865_driver); +} + +static void __exit ns_exit(void) +{ + phy_driver_unregister(&dp83865_driver); +} + +MODULE_DESCRIPTION("NatSemi PHY driver"); +MODULE_AUTHOR("Stuart Menefy"); +MODULE_LICENSE("GPL"); + +module_init(ns_init); +module_exit(ns_exit); diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index df4e6257d4a77e3e9bba739db57dec8543315d79..e4ede6080c9dcd327acfa37530263c6382d050db 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -45,7 +45,7 @@ */ void phy_print_status(struct phy_device *phydev) { - pr_info("PHY: %s - Link is %s", phydev->dev.bus_id, + pr_info("PHY: %s - Link is %s", dev_name(&phydev->dev), phydev->link ? "Up" : "Down"); if (phydev->link) printk(" - %d/%s", phydev->speed, diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 25acbbde4a6009f9c34926c0e2f89ca4e8066d6e..e35460165bf76709211ffa16f969a3b1fb07dbe8 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -74,7 +74,7 @@ int phy_register_fixup(const char *bus_id, u32 phy_uid, u32 phy_uid_mask, if (!fixup) return -ENOMEM; - strncpy(fixup->bus_id, bus_id, BUS_ID_SIZE); + strlcpy(fixup->bus_id, bus_id, sizeof(fixup->bus_id)); fixup->phy_uid = phy_uid; fixup->phy_uid_mask = phy_uid_mask; fixup->run = run; @@ -109,7 +109,7 @@ EXPORT_SYMBOL(phy_register_fixup_for_id); */ static int phy_needs_fixup(struct phy_device *phydev, struct phy_fixup *fixup) { - if (strcmp(fixup->bus_id, phydev->dev.bus_id) != 0) + if (strcmp(fixup->bus_id, dev_name(&phydev->dev)) != 0) if (strcmp(fixup->bus_id, PHY_ANY_ID) != 0) return 0; @@ -232,7 +232,7 @@ struct phy_device * get_phy_device(struct mii_bus *bus, int addr) return NULL; /* - * Broken hardware is sometimes missing the pull down resistor on the + * Broken hardware is sometimes missing the pull-up resistor on the * MDIO line, which results in reads to non-existent devices returning * 0 rather than 0xffff. Catch this here and treat 0 as a non-existent * device as well. @@ -517,23 +517,6 @@ int genphy_setup_forced(struct phy_device *phydev) err = phy_write(phydev, MII_BMCR, ctl); - if (err < 0) - return err; - - /* - * Run the fixups on this PHY, just in case the - * board code needs to change something after a reset - */ - err = phy_scan_fixups(phydev); - - if (err < 0) - return err; - - /* We just reset the device, so we'd better configure any - * settings the PHY requires to operate */ - if (phydev->drv->config_init) - err = phydev->drv->config_init(phydev); - return err; } @@ -779,7 +762,35 @@ static int genphy_config_init(struct phy_device *phydev) return 0; } +int genphy_suspend(struct phy_device *phydev) +{ + int value; + mutex_lock(&phydev->lock); + + value = phy_read(phydev, MII_BMCR); + phy_write(phydev, MII_BMCR, (value | BMCR_PDOWN)); + + mutex_unlock(&phydev->lock); + + return 0; +} +EXPORT_SYMBOL(genphy_suspend); + +int genphy_resume(struct phy_device *phydev) +{ + int value; + + mutex_lock(&phydev->lock); + + value = phy_read(phydev, MII_BMCR); + phy_write(phydev, MII_BMCR, (value & ~BMCR_PDOWN)); + + mutex_unlock(&phydev->lock); + + return 0; +} +EXPORT_SYMBOL(genphy_resume); /** * phy_probe - probe and init a PHY device @@ -855,7 +866,6 @@ int phy_driver_register(struct phy_driver *new_driver) { int retval; - memset(&new_driver->driver, 0, sizeof(new_driver->driver)); new_driver->driver.name = new_driver->name; new_driver->driver.bus = &mdio_bus_type; new_driver->driver.probe = phy_probe; @@ -890,6 +900,8 @@ static struct phy_driver genphy_driver = { .features = 0, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, + .suspend = genphy_suspend, + .resume = genphy_resume, .driver = {.owner= THIS_MODULE, }, }; diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c index 73baa7a3bb0ee3c9d43e69bb01d45908ef3340f0..c05d38d4635042d539f50705becfa9149109a137 100644 --- a/drivers/net/phy/smsc.c +++ b/drivers/net/phy/smsc.c @@ -126,6 +126,27 @@ static struct phy_driver lan8700_driver = { .driver = { .owner = THIS_MODULE, } }; +static struct phy_driver lan911x_int_driver = { + .phy_id = 0x0007c0d0, /* OUI=0x00800f, Model#=0x0d */ + .phy_id_mask = 0xfffffff0, + .name = "SMSC LAN911x Internal PHY", + + .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause + | SUPPORTED_Asym_Pause), + .flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG, + + /* basic functions */ + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .config_init = smsc_phy_config_init, + + /* IRQ related */ + .ack_interrupt = smsc_phy_ack_interrupt, + .config_intr = smsc_phy_config_intr, + + .driver = { .owner = THIS_MODULE, } +}; + static int __init smsc_init(void) { int ret; @@ -142,8 +163,14 @@ static int __init smsc_init(void) if (ret) goto err3; + ret = phy_driver_register (&lan911x_int_driver); + if (ret) + goto err4; + return 0; +err4: + phy_driver_unregister (&lan8700_driver); err3: phy_driver_unregister (&lan8187_driver); err2: @@ -154,6 +181,7 @@ static int __init smsc_init(void) static void __exit smsc_exit(void) { + phy_driver_unregister (&lan911x_int_driver); phy_driver_unregister (&lan8700_driver); phy_driver_unregister (&lan8187_driver); phy_driver_unregister (&lan83c185_driver); diff --git a/drivers/net/phy/ste10Xp.c b/drivers/net/phy/ste10Xp.c new file mode 100644 index 0000000000000000000000000000000000000000..6bdb0d53aaf9e6b1434f1ee61ff95e211291f4d2 --- /dev/null +++ b/drivers/net/phy/ste10Xp.c @@ -0,0 +1,137 @@ +/* + * drivers/net/phy/ste10Xp.c + * + * Driver for STMicroelectronics STe10Xp PHYs + * + * Author: Giuseppe Cavallaro + * + * Copyright (c) 2008 STMicroelectronics Limited + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MII_XCIIS 0x11 /* Configuration Info IRQ & Status Reg */ +#define MII_XIE 0x12 /* Interrupt Enable Register */ +#define MII_XIE_DEFAULT_MASK 0x0070 /* ANE complete, Remote Fault, Link Down */ + +#define STE101P_PHY_ID 0x00061c50 +#define STE100P_PHY_ID 0x1c040011 + +static int ste10Xp_config_init(struct phy_device *phydev) +{ + int value, err; + + /* Software Reset PHY */ + value = phy_read(phydev, MII_BMCR); + if (value < 0) + return value; + + value |= BMCR_RESET; + err = phy_write(phydev, MII_BMCR, value); + if (err < 0) + return err; + + do { + value = phy_read(phydev, MII_BMCR); + } while (value & BMCR_RESET); + + return 0; +} + +static int ste10Xp_config_intr(struct phy_device *phydev) +{ + int err, value; + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { + /* Enable all STe101P interrupts (PR12) */ + err = phy_write(phydev, MII_XIE, MII_XIE_DEFAULT_MASK); + /* clear any pending interrupts */ + if (err == 0) { + value = phy_read(phydev, MII_XCIIS); + if (value < 0) + err = value; + } + } else + err = phy_write(phydev, MII_XIE, 0); + + return err; +} + +static int ste10Xp_ack_interrupt(struct phy_device *phydev) +{ + int err = phy_read(phydev, MII_XCIIS); + if (err < 0) + return err; + + return 0; +} + +static struct phy_driver ste101p_pdriver = { + .phy_id = STE101P_PHY_ID, + .phy_id_mask = 0xfffffff0, + .name = "STe101p", + .features = PHY_BASIC_FEATURES | SUPPORTED_Pause, + .flags = PHY_HAS_INTERRUPT, + .config_init = ste10Xp_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .ack_interrupt = ste10Xp_ack_interrupt, + .config_intr = ste10Xp_config_intr, + .suspend = genphy_suspend, + .resume = genphy_resume, + .driver = {.owner = THIS_MODULE,} +}; + +static struct phy_driver ste100p_pdriver = { + .phy_id = STE100P_PHY_ID, + .phy_id_mask = 0xffffffff, + .name = "STe100p", + .features = PHY_BASIC_FEATURES | SUPPORTED_Pause, + .flags = PHY_HAS_INTERRUPT, + .config_init = ste10Xp_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .ack_interrupt = ste10Xp_ack_interrupt, + .config_intr = ste10Xp_config_intr, + .suspend = genphy_suspend, + .resume = genphy_resume, + .driver = {.owner = THIS_MODULE,} +}; + +static int __init ste10Xp_init(void) +{ + int retval; + + retval = phy_driver_register(&ste100p_pdriver); + if (retval < 0) + return retval; + return phy_driver_register(&ste101p_pdriver); +} + +static void __exit ste10Xp_exit(void) +{ + phy_driver_unregister(&ste100p_pdriver); + phy_driver_unregister(&ste101p_pdriver); +} + +module_init(ste10Xp_init); +module_exit(ste10Xp_exit); + +MODULE_DESCRIPTION("STMicroelectronics STe10Xp PHY driver"); +MODULE_AUTHOR("Giuseppe Cavallaro "); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/plip.c b/drivers/net/plip.c index 1e965427b0e987faae6ae26bfe3d07e1aad8bfa7..0c46d603b8fe99985a558ec771e7d48924480709 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -229,7 +229,7 @@ static inline void enable_parport_interrupts (struct net_device *dev) if (dev->irq != -1) { struct parport *port = - ((struct net_local *)dev->priv)->pardev->port; + ((struct net_local *)netdev_priv(dev))->pardev->port; port->ops->enable_irq (port); } } @@ -239,7 +239,7 @@ static inline void disable_parport_interrupts (struct net_device *dev) if (dev->irq != -1) { struct parport *port = - ((struct net_local *)dev->priv)->pardev->port; + ((struct net_local *)netdev_priv(dev))->pardev->port; port->ops->disable_irq (port); } } @@ -247,7 +247,7 @@ static inline void disable_parport_interrupts (struct net_device *dev) static inline void write_data (struct net_device *dev, unsigned char data) { struct parport *port = - ((struct net_local *)dev->priv)->pardev->port; + ((struct net_local *)netdev_priv(dev))->pardev->port; port->ops->write_data (port, data); } @@ -255,7 +255,7 @@ static inline void write_data (struct net_device *dev, unsigned char data) static inline unsigned char read_status (struct net_device *dev) { struct parport *port = - ((struct net_local *)dev->priv)->pardev->port; + ((struct net_local *)netdev_priv(dev))->pardev->port; return port->ops->read_status (port); } @@ -638,14 +638,14 @@ plip_receive_packet(struct net_device *dev, struct net_local *nl, case PLIP_PK_DATA: lbuf = rcv->skb->data; - do + do { if (plip_receive(nibble_timeout, dev, &rcv->nibble, &lbuf[rcv->byte])) return TIMEOUT; - while (++rcv->byte < rcv->length.h); - do + } while (++rcv->byte < rcv->length.h); + do { rcv->checksum += lbuf[--rcv->byte]; - while (rcv->byte); + } while (rcv->byte); rcv->state = PLIP_PK_CHECKSUM; case PLIP_PK_CHECKSUM: @@ -664,7 +664,6 @@ plip_receive_packet(struct net_device *dev, struct net_local *nl, /* Inform the upper layer for the arrival of a packet. */ rcv->skb->protocol=plip_type_trans(rcv->skb, dev); netif_rx_ni(rcv->skb); - dev->last_rx = jiffies; dev->stats.rx_bytes += rcv->length.h; dev->stats.rx_packets++; rcv->skb = NULL; @@ -817,14 +816,14 @@ plip_send_packet(struct net_device *dev, struct net_local *nl, snd->checksum = 0; case PLIP_PK_DATA: - do + do { if (plip_send(nibble_timeout, dev, &snd->nibble, lbuf[snd->byte])) return TIMEOUT; - while (++snd->byte < snd->length.h); - do + } while (++snd->byte < snd->length.h); + do { snd->checksum += lbuf[--snd->byte]; - while (snd->byte); + } while (snd->byte); snd->state = PLIP_PK_CHECKSUM; case PLIP_PK_CHECKSUM: @@ -1018,8 +1017,8 @@ plip_hard_header(struct sk_buff *skb, struct net_device *dev, return ret; } -int plip_hard_header_cache(const struct neighbour *neigh, - struct hh_cache *hh) +static int plip_hard_header_cache(const struct neighbour *neigh, + struct hh_cache *hh) { int ret; @@ -1397,9 +1396,3 @@ static int __init plip_init (void) module_init(plip_init); module_exit(plip_cleanup_module); MODULE_LICENSE("GPL"); - -/* - * Local variables: - * compile-command: "gcc -DMODULE -DMODVERSIONS -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -g -fomit-frame-pointer -pipe -c plip.c" - * End: - */ diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c index 451bdb57d6fc98b5389a9067e52c49fff9df37c9..6567fabd2e132a4ab4296a8283d32632b299c9d0 100644 --- a/drivers/net/ppp_async.c +++ b/drivers/net/ppp_async.c @@ -293,9 +293,6 @@ ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file, err = -EFAULT; switch (cmd) { case PPPIOCGCHAN: - err = -ENXIO; - if (!ap) - break; err = -EFAULT; if (put_user(ppp_channel_index(&ap->chan), p)) break; @@ -303,9 +300,6 @@ ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file, break; case PPPIOCGUNIT: - err = -ENXIO; - if (!ap) - break; err = -EFAULT; if (put_user(ppp_unit_number(&ap->chan), p)) break; diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 7e857e938adb582ae432b26d35114e8099d51eb2..06b448285eb5d0783c104383c12b0e4add6309ea 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -116,6 +117,7 @@ struct ppp { unsigned long last_xmit; /* jiffies when last pkt sent 9c */ unsigned long last_recv; /* jiffies when last pkt rcvd a0 */ struct net_device *dev; /* network interface device a4 */ + int closing; /* is device closing down? a8 */ #ifdef CONFIG_PPP_MULTILINK int nxchan; /* next channel to send something on */ u32 nxseq; /* next sequence number to send */ @@ -171,36 +173,14 @@ struct channel { * channel.downl. */ -/* - * A cardmap represents a mapping from unsigned integers to pointers, - * and provides a fast "find lowest unused number" operation. - * It uses a broad (32-way) tree with a bitmap at each level. - * It is designed to be space-efficient for small numbers of entries - * and time-efficient for large numbers of entries. - */ -#define CARDMAP_ORDER 5 -#define CARDMAP_WIDTH (1U << CARDMAP_ORDER) -#define CARDMAP_MASK (CARDMAP_WIDTH - 1) - -struct cardmap { - int shift; - unsigned long inuse; - struct cardmap *parent; - void *ptr[CARDMAP_WIDTH]; -}; -static void *cardmap_get(struct cardmap *map, unsigned int nr); -static int cardmap_set(struct cardmap **map, unsigned int nr, void *ptr); -static unsigned int cardmap_find_first_free(struct cardmap *map); -static void cardmap_destroy(struct cardmap **map); - /* * all_ppp_mutex protects the all_ppp_units mapping. * It also ensures that finding a ppp unit in the all_ppp_units map * and updating its file.refcnt field is atomic. */ static DEFINE_MUTEX(all_ppp_mutex); -static struct cardmap *all_ppp_units; static atomic_t ppp_unit_count = ATOMIC_INIT(0); +static DEFINE_IDR(ppp_units_idr); /* * all_channels_lock protects all_channels and last_channel_index, @@ -269,6 +249,9 @@ static struct channel *ppp_find_channel(int unit); static int ppp_connect_channel(struct channel *pch, int unit); static int ppp_disconnect_channel(struct channel *pch); static void ppp_destroy_channel(struct channel *pch); +static int unit_get(struct idr *p, void *ptr); +static void unit_put(struct idr *p, int n); +static void *unit_find(struct idr *p, int n); static struct class *ppp_class; @@ -886,7 +869,7 @@ static int __init ppp_init(void) static int ppp_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct ppp *ppp = (struct ppp *) dev->priv; + struct ppp *ppp = netdev_priv(dev); int npi, proto; unsigned char *pp; @@ -931,7 +914,7 @@ ppp_start_xmit(struct sk_buff *skb, struct net_device *dev) static int ppp_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - struct ppp *ppp = dev->priv; + struct ppp *ppp = netdev_priv(dev); int err = -EFAULT; void __user *addr = (void __user *) ifr->ifr_ifru.ifru_data; struct ppp_stats stats; @@ -971,8 +954,14 @@ ppp_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return err; } +static const struct net_device_ops ppp_netdev_ops = { + .ndo_start_xmit = ppp_start_xmit, + .ndo_do_ioctl = ppp_net_ioctl, +}; + static void ppp_setup(struct net_device *dev) { + dev->netdev_ops = &ppp_netdev_ops; dev->hard_header_len = PPP_HDRLEN; dev->mtu = PPP_MTU; dev->addr_len = 0; @@ -995,7 +984,7 @@ ppp_xmit_process(struct ppp *ppp) struct sk_buff *skb; ppp_xmit_lock(ppp); - if (ppp->dev) { + if (!ppp->closing) { ppp_push(ppp); while (!ppp->xmit_pending && (skb = skb_dequeue(&ppp->file.xq))) @@ -1463,8 +1452,7 @@ static inline void ppp_do_recv(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) { ppp_recv_lock(ppp); - /* ppp->dev == 0 means interface is closing down */ - if (ppp->dev) + if (!ppp->closing) ppp_receive_frame(ppp, skb, pch); else kfree_skb(skb); @@ -1684,7 +1672,6 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) skb->protocol = htons(npindex_to_ethertype[npi]); skb_reset_mac_header(skb); netif_rx(skb); - ppp->dev->last_rx = jiffies; } } return; @@ -2414,13 +2401,12 @@ ppp_create_interface(int unit, int *retp) int ret = -ENOMEM; int i; - ppp = kzalloc(sizeof(struct ppp), GFP_KERNEL); - if (!ppp) - goto out; - dev = alloc_netdev(0, "", ppp_setup); + dev = alloc_netdev(sizeof(struct ppp), "", ppp_setup); if (!dev) goto out1; + ppp = netdev_priv(dev); + ppp->dev = dev; ppp->mru = PPP_MRU; init_ppp_file(&ppp->file, INTERFACE); ppp->file.hdrlen = PPP_HDRLEN - 2; /* don't count proto bytes */ @@ -2433,18 +2419,25 @@ ppp_create_interface(int unit, int *retp) ppp->minseq = -1; skb_queue_head_init(&ppp->mrq); #endif /* CONFIG_PPP_MULTILINK */ - ppp->dev = dev; - dev->priv = ppp; - - dev->hard_start_xmit = ppp_start_xmit; - dev->do_ioctl = ppp_net_ioctl; ret = -EEXIST; mutex_lock(&all_ppp_mutex); - if (unit < 0) - unit = cardmap_find_first_free(all_ppp_units); - else if (cardmap_get(all_ppp_units, unit) != NULL) - goto out2; /* unit already exists */ + + if (unit < 0) { + unit = unit_get(&ppp_units_idr, ppp); + if (unit < 0) { + *retp = unit; + goto out2; + } + } else { + if (unit_find(&ppp_units_idr, unit)) + goto out2; /* unit already exists */ + else { + /* darn, someone is cheating us? */ + *retp = -EINVAL; + goto out2; + } + } /* Initialize the new ppp unit */ ppp->file.index = unit; @@ -2452,29 +2445,22 @@ ppp_create_interface(int unit, int *retp) ret = register_netdev(dev); if (ret != 0) { + unit_put(&ppp_units_idr, unit); printk(KERN_ERR "PPP: couldn't register device %s (%d)\n", dev->name, ret); goto out2; } atomic_inc(&ppp_unit_count); - ret = cardmap_set(&all_ppp_units, unit, ppp); - if (ret != 0) - goto out3; - mutex_unlock(&all_ppp_mutex); + *retp = 0; return ppp; -out3: - atomic_dec(&ppp_unit_count); - unregister_netdev(dev); out2: mutex_unlock(&all_ppp_mutex); free_netdev(dev); out1: - kfree(ppp); -out: *retp = ret; return NULL; } @@ -2498,19 +2484,17 @@ init_ppp_file(struct ppp_file *pf, int kind) */ static void ppp_shutdown_interface(struct ppp *ppp) { - struct net_device *dev; - mutex_lock(&all_ppp_mutex); - ppp_lock(ppp); - dev = ppp->dev; - ppp->dev = NULL; - ppp_unlock(ppp); /* This will call dev_close() for us. */ - if (dev) { - unregister_netdev(dev); - free_netdev(dev); - } - cardmap_set(&all_ppp_units, ppp->file.index, NULL); + ppp_lock(ppp); + if (!ppp->closing) { + ppp->closing = 1; + ppp_unlock(ppp); + unregister_netdev(ppp->dev); + } else + ppp_unlock(ppp); + + unit_put(&ppp_units_idr, ppp->file.index); ppp->file.dead = 1; ppp->owner = NULL; wake_up_interruptible(&ppp->file.rwait); @@ -2554,7 +2538,7 @@ static void ppp_destroy_interface(struct ppp *ppp) if (ppp->xmit_pending) kfree_skb(ppp->xmit_pending); - kfree(ppp); + free_netdev(ppp->dev); } /* @@ -2564,7 +2548,7 @@ static void ppp_destroy_interface(struct ppp *ppp) static struct ppp * ppp_find_unit(int unit) { - return cardmap_get(all_ppp_units, unit); + return unit_find(&ppp_units_idr, unit); } /* @@ -2616,7 +2600,7 @@ ppp_connect_channel(struct channel *pch, int unit) if (pch->file.hdrlen > ppp->file.hdrlen) ppp->file.hdrlen = pch->file.hdrlen; hdrlen = pch->file.hdrlen + 2; /* for protocol bytes */ - if (ppp->dev && hdrlen > ppp->dev->hard_header_len) + if (hdrlen > ppp->dev->hard_header_len) ppp->dev->hard_header_len = hdrlen; list_add_tail(&pch->clist, &ppp->channels); ++ppp->n_channels; @@ -2682,123 +2666,45 @@ static void __exit ppp_cleanup(void) /* should never happen */ if (atomic_read(&ppp_unit_count) || atomic_read(&channel_count)) printk(KERN_ERR "PPP: removing module but units remain!\n"); - cardmap_destroy(&all_ppp_units); unregister_chrdev(PPP_MAJOR, "ppp"); device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0)); class_destroy(ppp_class); + idr_destroy(&ppp_units_idr); } /* - * Cardmap implementation. + * Units handling. Caller must protect concurrent access + * by holding all_ppp_mutex */ -static void *cardmap_get(struct cardmap *map, unsigned int nr) + +/* get new free unit number and associate pointer with it */ +static int unit_get(struct idr *p, void *ptr) { - struct cardmap *p; - int i; + int unit, err; - for (p = map; p != NULL; ) { - if ((i = nr >> p->shift) >= CARDMAP_WIDTH) - return NULL; - if (p->shift == 0) - return p->ptr[i]; - nr &= ~(CARDMAP_MASK << p->shift); - p = p->ptr[i]; +again: + if (idr_pre_get(p, GFP_KERNEL) == 0) { + printk(KERN_ERR "Out of memory expanding drawable idr\n"); + return -ENOMEM; } - return NULL; -} -static int cardmap_set(struct cardmap **pmap, unsigned int nr, void *ptr) -{ - struct cardmap *p; - int i; + err = idr_get_new_above(p, ptr, 0, &unit); + if (err == -EAGAIN) + goto again; - p = *pmap; - if (p == NULL || (nr >> p->shift) >= CARDMAP_WIDTH) { - do { - /* need a new top level */ - struct cardmap *np = kzalloc(sizeof(*np), GFP_KERNEL); - if (!np) - goto enomem; - np->ptr[0] = p; - if (p != NULL) { - np->shift = p->shift + CARDMAP_ORDER; - p->parent = np; - } else - np->shift = 0; - p = np; - } while ((nr >> p->shift) >= CARDMAP_WIDTH); - *pmap = p; - } - while (p->shift > 0) { - i = (nr >> p->shift) & CARDMAP_MASK; - if (p->ptr[i] == NULL) { - struct cardmap *np = kzalloc(sizeof(*np), GFP_KERNEL); - if (!np) - goto enomem; - np->shift = p->shift - CARDMAP_ORDER; - np->parent = p; - p->ptr[i] = np; - } - if (ptr == NULL) - clear_bit(i, &p->inuse); - p = p->ptr[i]; - } - i = nr & CARDMAP_MASK; - p->ptr[i] = ptr; - if (ptr != NULL) - set_bit(i, &p->inuse); - else - clear_bit(i, &p->inuse); - return 0; - enomem: - return -ENOMEM; + return unit; } -static unsigned int cardmap_find_first_free(struct cardmap *map) +/* put unit number back to a pool */ +static void unit_put(struct idr *p, int n) { - struct cardmap *p; - unsigned int nr = 0; - int i; - - if ((p = map) == NULL) - return 0; - for (;;) { - i = find_first_zero_bit(&p->inuse, CARDMAP_WIDTH); - if (i >= CARDMAP_WIDTH) { - if (p->parent == NULL) - return CARDMAP_WIDTH << p->shift; - p = p->parent; - i = (nr >> p->shift) & CARDMAP_MASK; - set_bit(i, &p->inuse); - continue; - } - nr = (nr & (~CARDMAP_MASK << p->shift)) | (i << p->shift); - if (p->shift == 0 || p->ptr[i] == NULL) - return nr; - p = p->ptr[i]; - } + idr_remove(p, n); } -static void cardmap_destroy(struct cardmap **pmap) +/* get pointer associated with the number */ +static void *unit_find(struct idr *p, int n) { - struct cardmap *p, *np; - int i; - - for (p = *pmap; p != NULL; p = np) { - if (p->shift != 0) { - for (i = 0; i < CARDMAP_WIDTH; ++i) - if (p->ptr[i] != NULL) - break; - if (i < CARDMAP_WIDTH) { - np = p->ptr[i]; - p->ptr[i] = NULL; - continue; - } - } - np = p->parent; - kfree(p); - } - *pmap = NULL; + return idr_find(p, n); } /* Module/initialization stuff */ diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c index 801d8f99d4714155e2f3b3f9c0879ec15d2de8ba..1e892b7b1f8cf997764e7a29ffe09bbf745f69ff 100644 --- a/drivers/net/ppp_synctty.c +++ b/drivers/net/ppp_synctty.c @@ -333,9 +333,6 @@ ppp_synctty_ioctl(struct tty_struct *tty, struct file *file, err = -EFAULT; switch (cmd) { case PPPIOCGCHAN: - err = -ENXIO; - if (!ap) - break; err = -EFAULT; if (put_user(ppp_channel_index(&ap->chan), p)) break; @@ -343,9 +340,6 @@ ppp_synctty_ioctl(struct tty_struct *tty, struct file *file, break; case PPPIOCGUNIT: - err = -ENXIO; - if (!ap) - break; err = -EFAULT; if (put_user(ppp_unit_number(&ap->chan), p)) break; diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index b646e92134dc79a6bbfe6e55f7c80fd0ea19d3f1..c22b30533a14cb89eeeda69a83317f80e8c383b3 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -958,7 +958,6 @@ static int pppoe_seq_show(struct seq_file *seq, void *v) { struct pppox_sock *po; char *dev_name; - DECLARE_MAC_BUF(mac); if (v == SEQ_START_TOKEN) { seq_puts(seq, "Id Address Device\n"); @@ -968,8 +967,8 @@ static int pppoe_seq_show(struct seq_file *seq, void *v) po = v; dev_name = po->pppoe_pa.dev; - seq_printf(seq, "%08X %s %8s\n", - po->pppoe_pa.sid, print_mac(mac, po->pppoe_pa.remote), dev_name); + seq_printf(seq, "%08X %pM %8s\n", + po->pppoe_pa.sid, po->pppoe_pa.remote, dev_name); out: return 0; } diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c index e98d9773158d287ba1ae35052dca968fc6cf5735..f1a946785c6aee3bf580ad6015d9b825318c6566 100644 --- a/drivers/net/pppol2tp.c +++ b/drivers/net/pppol2tp.c @@ -489,6 +489,30 @@ static void pppol2tp_recv_dequeue(struct pppol2tp_session *session) spin_unlock_bh(&session->reorder_q.lock); } +static inline int pppol2tp_verify_udp_checksum(struct sock *sk, + struct sk_buff *skb) +{ + struct udphdr *uh = udp_hdr(skb); + u16 ulen = ntohs(uh->len); + struct inet_sock *inet; + __wsum psum; + + if (sk->sk_no_check || skb_csum_unnecessary(skb) || !uh->check) + return 0; + + inet = inet_sk(sk); + psum = csum_tcpudp_nofold(inet->saddr, inet->daddr, ulen, + IPPROTO_UDP, 0); + + if ((skb->ip_summed == CHECKSUM_COMPLETE) && + !csum_fold(csum_add(psum, skb->csum))) + return 0; + + skb->csum = psum; + + return __skb_checksum_complete(skb); +} + /* Internal receive frame. Do the real work of receiving an L2TP data frame * here. The skb is not on a list when we get here. * Returns 0 if the packet was a data packet and was successfully passed on. @@ -509,6 +533,9 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) if (tunnel == NULL) goto no_tunnel; + if (tunnel->sock && pppol2tp_verify_udp_checksum(tunnel->sock, skb)) + goto discard_bad_csum; + /* UDP always verifies the packet length. */ __skb_pull(skb, sizeof(struct udphdr)); @@ -725,6 +752,14 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) return 0; +discard_bad_csum: + LIMIT_NETDEBUG("%s: UDP: bad checksum\n", tunnel->name); + UDP_INC_STATS_USER(&init_net, UDP_MIB_INERRORS, 0); + tunnel->stats.rx_errors++; + kfree_skb(skb); + + return 0; + error: /* Put UDP header back */ __skb_push(skb, sizeof(struct udphdr)); @@ -851,7 +886,7 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh static const unsigned char ppph[2] = { 0xff, 0x03 }; struct sock *sk = sock->sk; struct inet_sock *inet; - __wsum csum = 0; + __wsum csum; struct sk_buff *skb; int error; int hdr_len; @@ -859,6 +894,8 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh struct pppol2tp_tunnel *tunnel; struct udphdr *uh; unsigned int len; + struct sock *sk_tun; + u16 udp_len; error = -ENOTCONN; if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED)) @@ -870,7 +907,8 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh if (session == NULL) goto error; - tunnel = pppol2tp_sock_to_tunnel(session->tunnel_sock); + sk_tun = session->tunnel_sock; + tunnel = pppol2tp_sock_to_tunnel(sk_tun); if (tunnel == NULL) goto error_put_sess; @@ -893,11 +931,12 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh skb_reset_transport_header(skb); /* Build UDP header */ - inet = inet_sk(session->tunnel_sock); + inet = inet_sk(sk_tun); + udp_len = hdr_len + sizeof(ppph) + total_len; uh = (struct udphdr *) skb->data; uh->source = inet->sport; uh->dest = inet->dport; - uh->len = htons(hdr_len + sizeof(ppph) + total_len); + uh->len = htons(udp_len); uh->check = 0; skb_put(skb, sizeof(struct udphdr)); @@ -919,8 +958,22 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh skb_put(skb, total_len); /* Calculate UDP checksum if configured to do so */ - if (session->tunnel_sock->sk_no_check != UDP_CSUM_NOXMIT) - csum = udp_csum_outgoing(sk, skb); + if (sk_tun->sk_no_check == UDP_CSUM_NOXMIT) + skb->ip_summed = CHECKSUM_NONE; + else if (!(skb->dst->dev->features & NETIF_F_V4_CSUM)) { + skb->ip_summed = CHECKSUM_COMPLETE; + csum = skb_checksum(skb, 0, udp_len, 0); + uh->check = csum_tcpudp_magic(inet->saddr, inet->daddr, + udp_len, IPPROTO_UDP, csum); + if (uh->check == 0) + uh->check = CSUM_MANGLED_0; + } else { + skb->ip_summed = CHECKSUM_PARTIAL; + skb->csum_start = skb_transport_header(skb) - skb->head; + skb->csum_offset = offsetof(struct udphdr, check); + uh->check = ~csum_tcpudp_magic(inet->saddr, inet->daddr, + udp_len, IPPROTO_UDP, 0); + } /* Debug */ if (session->send_seq) @@ -1008,13 +1061,14 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) struct sock *sk = (struct sock *) chan->private; struct sock *sk_tun; int hdr_len; + u16 udp_len; struct pppol2tp_session *session; struct pppol2tp_tunnel *tunnel; int rc; int headroom; int data_len = skb->len; struct inet_sock *inet; - __wsum csum = 0; + __wsum csum; struct udphdr *uh; unsigned int len; int old_headroom; @@ -1060,6 +1114,8 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) /* Setup L2TP header */ pppol2tp_build_l2tp_header(session, __skb_push(skb, hdr_len)); + udp_len = sizeof(struct udphdr) + hdr_len + sizeof(ppph) + data_len; + /* Setup UDP header */ inet = inet_sk(sk_tun); __skb_push(skb, sizeof(*uh)); @@ -1067,13 +1123,9 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) uh = udp_hdr(skb); uh->source = inet->sport; uh->dest = inet->dport; - uh->len = htons(sizeof(struct udphdr) + hdr_len + sizeof(ppph) + data_len); + uh->len = htons(udp_len); uh->check = 0; - /* *BROKEN* Calculate UDP checksum if configured to do so */ - if (sk_tun->sk_no_check != UDP_CSUM_NOXMIT) - csum = udp_csum_outgoing(sk_tun, skb); - /* Debug */ if (session->send_seq) PRINTK(session->debug, PPPOL2TP_MSG_DATA, KERN_DEBUG, @@ -1108,6 +1160,24 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) skb->dst = dst_clone(__sk_dst_get(sk_tun)); pppol2tp_skb_set_owner_w(skb, sk_tun); + /* Calculate UDP checksum if configured to do so */ + if (sk_tun->sk_no_check == UDP_CSUM_NOXMIT) + skb->ip_summed = CHECKSUM_NONE; + else if (!(skb->dst->dev->features & NETIF_F_V4_CSUM)) { + skb->ip_summed = CHECKSUM_COMPLETE; + csum = skb_checksum(skb, 0, udp_len, 0); + uh->check = csum_tcpudp_magic(inet->saddr, inet->daddr, + udp_len, IPPROTO_UDP, csum); + if (uh->check == 0) + uh->check = CSUM_MANGLED_0; + } else { + skb->ip_summed = CHECKSUM_PARTIAL; + skb->csum_start = skb_transport_header(skb) - skb->head; + skb->csum_offset = offsetof(struct udphdr, check); + uh->check = ~csum_tcpudp_magic(inet->saddr, inet->daddr, + udp_len, IPPROTO_UDP, 0); + } + /* Queue the packet to IP for output */ len = skb->len; rc = ip_queue_xmit(skb, 1); diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index 2eb54fd7bed532153f4aafef049a97f5459caa02..4b564eda5bd932ef67f8b850c4b947761da31628 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c @@ -1443,7 +1443,6 @@ int gelic_net_setup_netdev(struct net_device *netdev, struct gelic_card *card) { int status; u64 v1, v2; - DECLARE_MAC_BUF(mac); netdev->features = NETIF_F_IP_CSUM; @@ -1474,9 +1473,8 @@ int gelic_net_setup_netdev(struct net_device *netdev, struct gelic_card *card) __func__, netdev->name, status); return status; } - dev_info(ctodev(card), "%s: MAC addr %s\n", - netdev->name, - print_mac(mac, netdev->dev_addr)); + dev_info(ctodev(card), "%s: MAC addr %pM\n", + netdev->name, netdev->dev_addr); return 0; } diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c index a834b52a6a2c4019a36bb752b812566ae89c57c9..ec2314246682af0946bbe97475b3947670401383 100644 --- a/drivers/net/ps3_gelic_wireless.c +++ b/drivers/net/ps3_gelic_wireless.c @@ -30,10 +30,11 @@ #include #include #include +#include +#include #include #include #include -#include #include #include @@ -449,9 +450,9 @@ static size_t gelic_wl_synthesize_ie(u8 *buf, /* element id */ if (rsn) - *buf++ = MFIE_TYPE_RSN; + *buf++ = WLAN_EID_RSN; else - *buf++ = MFIE_TYPE_GENERIC; + *buf++ = WLAN_EID_GENERIC; /* length filed; set later */ buf++; @@ -539,7 +540,7 @@ static void gelic_wl_parse_ie(u8 *data, size_t len, break; switch (item_id) { - case MFIE_TYPE_GENERIC: + case WLAN_EID_GENERIC: if ((OUI_LEN + 1 <= item_len) && !memcmp(pos, wpa_oui, OUI_LEN) && pos[OUI_LEN] == 0x01) { @@ -547,7 +548,7 @@ static void gelic_wl_parse_ie(u8 *data, size_t len, ie_info->wpa.len = item_len + 2; } break; - case MFIE_TYPE_RSN: + case WLAN_EID_RSN: ie_info->rsn.data = pos - 2; /* length includes the header */ ie_info->rsn.len = item_len + 2; @@ -581,7 +582,7 @@ static char *gelic_wl_translate_scan(struct net_device *netdev, char *tmp; u8 rate; unsigned int i, j, len; - u8 buf[MAX_WPA_IE_LEN]; + u8 buf[64]; /* arbitrary size large enough */ pr_debug("%s: <-\n", __func__); @@ -763,7 +764,6 @@ static void scan_list_dump(struct gelic_wl_info *wl) { struct gelic_wl_scan_info *scan_info; int i; - DECLARE_MAC_BUF(mac); i = 0; list_for_each_entry(scan_info, &wl->network_list, list) { @@ -775,8 +775,7 @@ static void scan_list_dump(struct gelic_wl_info *wl) scan_info->rate_len, scan_info->rate_ext_len, scan_info->essid_len); /* -- */ - pr_debug("bssid=%s\n", - print_mac(mac, &scan_info->hwinfo->bssid[2])); + pr_debug("bssid=%pM\n", &scan_info->hwinfo->bssid[2]); pr_debug("essid=%s\n", scan_info->hwinfo->essid); } } @@ -1167,11 +1166,7 @@ static int gelic_wl_set_ap(struct net_device *netdev, ETH_ALEN); set_bit(GELIC_WL_STAT_BSSID_SET, &wl->stat); set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat); - pr_debug("%s: bss=%02x:%02x:%02x:%02x:%02x:%02x\n", - __func__, - wl->bssid[0], wl->bssid[1], - wl->bssid[2], wl->bssid[3], - wl->bssid[4], wl->bssid[5]); + pr_debug("%s: bss=%pM\n", __func__, wl->bssid); } else { pr_debug("%s: clear bssid\n", __func__); clear_bit(GELIC_WL_STAT_BSSID_SET, &wl->stat); @@ -1632,7 +1627,6 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl) unsigned long this_time = jiffies; unsigned int data_len, i, found, r; void *buf; - DECLARE_MAC_BUF(mac); pr_debug("%s:start\n", __func__); mutex_lock(&wl->scan_lock); @@ -1684,9 +1678,9 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl) scan_info_size < data_len; i++, scan_info_size += be16_to_cpu(scan_info->size), scan_info = (void *)scan_info + be16_to_cpu(scan_info->size)) { - pr_debug("%s:size=%d bssid=%s scan_info=%p\n", __func__, + pr_debug("%s:size=%d bssid=%pM scan_info=%p\n", __func__, be16_to_cpu(scan_info->size), - print_mac(mac, &scan_info->bssid[2]), scan_info); + &scan_info->bssid[2], scan_info); /* * The wireless firmware may return invalid channel 0 and/or @@ -1741,14 +1735,14 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl) target->essid_len = strnlen(scan_info->essid, sizeof(scan_info->essid)); target->rate_len = 0; - for (r = 0; r < MAX_RATES_LENGTH; r++) + for (r = 0; r < 12; r++) if (scan_info->rate[r]) target->rate_len++; if (8 < target->rate_len) pr_info("%s: AP returns %d rates\n", __func__, target->rate_len); target->rate_ext_len = 0; - for (r = 0; r < MAX_RATES_EX_LENGTH; r++) + for (r = 0; r < 16; r++) if (scan_info->ext_rate[r]) target->rate_ext_len++; list_move_tail(&target->list, &wl->network_list); @@ -1787,7 +1781,6 @@ struct gelic_wl_scan_info *gelic_wl_find_best_bss(struct gelic_wl_info *wl) struct gelic_wl_scan_info *best_bss; int weight, best_weight; u16 security; - DECLARE_MAC_BUF(mac); pr_debug("%s: <-\n", __func__); @@ -1857,8 +1850,8 @@ struct gelic_wl_scan_info *gelic_wl_find_best_bss(struct gelic_wl_info *wl) #ifdef DEBUG pr_debug("%s: -> bss=%p\n", __func__, best_bss); if (best_bss) { - pr_debug("%s:addr=%s\n", __func__, - print_mac(mac, &best_bss->hwinfo->bssid[2])); + pr_debug("%s:addr=%pM\n", __func__, + &best_bss->hwinfo->bssid[2]); } #endif return best_bss; diff --git a/drivers/net/ps3_gelic_wireless.h b/drivers/net/ps3_gelic_wireless.h index 5339e0078d180a885f53a622dddac4c4743c50ee..5b631c6c97759ec36f4d2296549f10b979a89158 100644 --- a/drivers/net/ps3_gelic_wireless.h +++ b/drivers/net/ps3_gelic_wireless.h @@ -164,8 +164,8 @@ struct gelic_eurus_scan_info { __be16 security; u8 bssid[8]; /* last ETH_ALEN are valid. bssid[0],[1] are unused */ u8 essid[32]; /* IW_ESSID_MAX_SIZE */ - u8 rate[16]; /* first MAX_RATES_LENGTH(12) are valid */ - u8 ext_rate[16]; /* first MAX_RATES_EX_LENGTH(16) are valid */ + u8 rate[16]; /* first 12 are valid */ + u8 ext_rate[16]; /* first 16 are valid */ __be32 reserved1; __be32 reserved2; __be32 reserved3; diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index 508452c0215144343a2aacbe37f44d20caedfbf3..189ec29ac7a40678787ed8eb3706257268a28e6f 100644 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -2127,7 +2127,6 @@ static void ql_process_mac_rx_intr(struct ql3_adapter *qdev, skb->protocol = eth_type_trans(skb, qdev->ndev); netif_receive_skb(skb); - qdev->ndev->last_rx = jiffies; lrg_buf_cb2->skb = NULL; if (qdev->device_id == QL3022_DEVICE_ID) @@ -2201,7 +2200,6 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev, netif_receive_skb(skb2); ndev->stats.rx_packets++; ndev->stats.rx_bytes += length; - ndev->last_rx = jiffies; lrg_buf_cb2->skb = NULL; if (qdev->device_id == QL3022_DEVICE_ID) @@ -2286,7 +2284,6 @@ static int ql_tx_rx_clean(struct ql3_adapter *qdev, static int ql_poll(struct napi_struct *napi, int budget) { struct ql3_adapter *qdev = container_of(napi, struct ql3_adapter, napi); - struct net_device *ndev = qdev->ndev; int rx_cleaned = 0, tx_cleaned = 0; unsigned long hw_flags; struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers; @@ -2295,7 +2292,7 @@ static int ql_poll(struct napi_struct *napi, int budget) if (tx_cleaned + rx_cleaned != budget) { spin_lock_irqsave(&qdev->hw_lock, hw_flags); - __netif_rx_complete(ndev, napi); + __netif_rx_complete(napi); ql_update_small_bufq_prod_index(qdev); ql_update_lrg_bufq_prod_index(qdev); writel(qdev->rsp_consumer_index, @@ -2354,8 +2351,8 @@ static irqreturn_t ql3xxx_isr(int irq, void *dev_id) spin_unlock(&qdev->adapter_lock); } else if (value & ISP_IMR_DISABLE_CMPL_INT) { ql_disable_interrupts(qdev); - if (likely(netif_rx_schedule_prep(ndev, &qdev->napi))) { - __netif_rx_schedule(ndev, &qdev->napi); + if (likely(netif_rx_schedule_prep(&qdev->napi))) { + __netif_rx_schedule(&qdev->napi); } } else { return IRQ_NONE; @@ -3520,7 +3517,6 @@ static void ql_display_dev_info(struct net_device *ndev) { struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev); struct pci_dev *pdev = qdev->pdev; - DECLARE_MAC_BUF(mac); printk(KERN_INFO PFX "\n%s Adapter %d RevisionID %d found %s on PCI slot %d.\n", @@ -3546,8 +3542,8 @@ static void ql_display_dev_info(struct net_device *ndev) if (netif_msg_probe(qdev)) printk(KERN_INFO PFX - "%s: MAC address %s\n", - ndev->name, print_mac(mac, ndev->dev_addr)); + "%s: MAC address %pM\n", + ndev->name, ndev->dev_addr); } static int ql_adapter_down(struct ql3_adapter *qdev, int do_reset) @@ -3903,13 +3899,24 @@ static void ql3xxx_timer(unsigned long ptr) queue_delayed_work(qdev->workqueue, &qdev->link_state_work, 0); } +static const struct net_device_ops ql3xxx_netdev_ops = { + .ndo_open = ql3xxx_open, + .ndo_start_xmit = ql3xxx_send, + .ndo_stop = ql3xxx_close, + .ndo_set_multicast_list = NULL, /* not allowed on NIC side */ + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = ql3xxx_set_mac_address, + .ndo_tx_timeout = ql3xxx_tx_timeout, +}; + static int __devinit ql3xxx_probe(struct pci_dev *pdev, const struct pci_device_id *pci_entry) { struct net_device *ndev = NULL; struct ql3_adapter *qdev = NULL; static int cards_found = 0; - int pci_using_dac, err; + int uninitialized_var(pci_using_dac), err; err = pci_enable_device(pdev); if (err) { @@ -3969,9 +3976,7 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev, if (qdev->device_id == QL3032_DEVICE_ID) ndev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; - qdev->mem_map_registers = - ioremap_nocache(pci_resource_start(pdev, 1), - pci_resource_len(qdev->pdev, 1)); + qdev->mem_map_registers = pci_ioremap_bar(pdev, 1); if (!qdev->mem_map_registers) { printk(KERN_ERR PFX "%s: cannot map device registers\n", pci_name(pdev)); @@ -3983,17 +3988,8 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev, spin_lock_init(&qdev->hw_lock); /* Set driver entry points */ - ndev->open = ql3xxx_open; - ndev->hard_start_xmit = ql3xxx_send; - ndev->stop = ql3xxx_close; - /* ndev->set_multicast_list - * This device is one side of a two-function adapter - * (NIC and iSCSI). Promiscuous mode setting/clearing is - * not allowed from the NIC side. - */ + ndev->netdev_ops = &ql3xxx_netdev_ops; SET_ETHTOOL_OPS(ndev, &ql3xxx_ethtool_ops); - ndev->set_mac_address = ql3xxx_set_mac_address; - ndev->tx_timeout = ql3xxx_tx_timeout; ndev->watchdog_timeo = 5 * HZ; netif_napi_add(ndev, &qdev->napi, ql_poll, 64); diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/qlge/qlge_ethtool.c index b62fbd4bf00f5821fd2e2c81b9e2b5b76eb792b4..eefb81b137588d4b61ad94b568f811c4fb5f9382 100644 --- a/drivers/net/qlge/qlge_ethtool.c +++ b/drivers/net/qlge/qlge_ethtool.c @@ -97,7 +97,7 @@ static int ql_update_ring_coalescing(struct ql_adapter *qdev) return status; } -void ql_update_stats(struct ql_adapter *qdev) +static void ql_update_stats(struct ql_adapter *qdev) { u32 i; u64 data; diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index b83a9c9b6a9799e73d2cd3efdf4c5177734baa80..718a7bd0cd1a207f90a6aaf92ffe894fd5163d79 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -336,12 +336,11 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type, (addr[5]); QPRINTK(qdev, IFUP, INFO, - "Adding %s address %02x:%02x:%02x:%02x:%02x:%02x" + "Adding %s address %pM" " at index %d in the CAM.\n", ((type == MAC_ADDR_TYPE_MULTI_MAC) ? "MULTICAST" : - "UNICAST"), addr[0], addr[1], addr[2], addr[3], - addr[4], addr[5], index); + "UNICAST"), addr, index); status = ql_wait_reg_rdy(qdev, @@ -643,7 +642,7 @@ static void ql_enable_all_completion_interrupts(struct ql_adapter *qdev) } -int ql_read_flash_word(struct ql_adapter *qdev, int offset, u32 *data) +static int ql_read_flash_word(struct ql_adapter *qdev, int offset, u32 *data) { int status = 0; /* wait for reg to come ready */ @@ -833,7 +832,7 @@ static int ql_port_initialize(struct ql_adapter *qdev) } /* Get the next large buffer. */ -struct bq_desc *ql_get_curr_lbuf(struct rx_ring *rx_ring) +static struct bq_desc *ql_get_curr_lbuf(struct rx_ring *rx_ring) { struct bq_desc *lbq_desc = &rx_ring->lbq[rx_ring->lbq_curr_idx]; rx_ring->lbq_curr_idx++; @@ -844,7 +843,7 @@ struct bq_desc *ql_get_curr_lbuf(struct rx_ring *rx_ring) } /* Get the next small buffer. */ -struct bq_desc *ql_get_curr_sbuf(struct rx_ring *rx_ring) +static struct bq_desc *ql_get_curr_sbuf(struct rx_ring *rx_ring) { struct bq_desc *sbq_desc = &rx_ring->sbq[rx_ring->sbq_curr_idx]; rx_ring->sbq_curr_idx++; @@ -1167,7 +1166,7 @@ static int ql_map_send(struct ql_adapter *qdev, return NETDEV_TX_BUSY; } -void ql_realign_skb(struct sk_buff *skb, int len) +static void ql_realign_skb(struct sk_buff *skb, int len) { void *temp_addr = skb->data; @@ -1452,7 +1451,6 @@ static void ql_process_mac_rx_intr(struct ql_adapter *qdev, "Passing a normal packet upstream.\n"); netif_rx(skb); } - ndev->last_rx = jiffies; } /* Process an outbound completion from an rx ring. */ @@ -1649,7 +1647,7 @@ static int ql_napi_poll_msix(struct napi_struct *napi, int budget) rx_ring->cq_id); if (work_done < budget) { - __netif_rx_complete(qdev->ndev, napi); + __netif_rx_complete(napi); ql_enable_completion_interrupt(qdev, rx_ring->irq); } return work_done; @@ -1734,8 +1732,7 @@ static irqreturn_t qlge_msix_tx_isr(int irq, void *dev_id) static irqreturn_t qlge_msix_rx_isr(int irq, void *dev_id) { struct rx_ring *rx_ring = dev_id; - struct ql_adapter *qdev = rx_ring->qdev; - netif_rx_schedule(qdev->ndev, &rx_ring->napi); + netif_rx_schedule(&rx_ring->napi); return IRQ_HANDLED; } @@ -1821,8 +1818,7 @@ static irqreturn_t qlge_isr(int irq, void *dev_id) &rx_ring->rx_work, 0); else - netif_rx_schedule(qdev->ndev, - &rx_ring->napi); + netif_rx_schedule(&rx_ring->napi); work_done++; } } @@ -2071,7 +2067,7 @@ static int ql_alloc_tx_resources(struct ql_adapter *qdev, return -ENOMEM; } -void ql_free_lbq_buffers(struct ql_adapter *qdev, struct rx_ring *rx_ring) +static void ql_free_lbq_buffers(struct ql_adapter *qdev, struct rx_ring *rx_ring) { int i; struct bq_desc *lbq_desc; @@ -2134,7 +2130,7 @@ static int ql_alloc_lbq_buffers(struct ql_adapter *qdev, return -ENOMEM; } -void ql_free_sbq_buffers(struct ql_adapter *qdev, struct rx_ring *rx_ring) +static void ql_free_sbq_buffers(struct ql_adapter *qdev, struct rx_ring *rx_ring) { int i; struct bq_desc *sbq_desc; @@ -2469,7 +2465,7 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) rx_ring->sbq_base_indirect_dma = shadow_reg_dma; /* PCI doorbell mem area + 0x00 for consumer index register */ - rx_ring->cnsmr_idx_db_reg = (u32 *) doorbell_area; + rx_ring->cnsmr_idx_db_reg = (u32 __iomem *) doorbell_area; rx_ring->cnsmr_idx = 0; rx_ring->curr_entry = rx_ring->cq_base; @@ -2477,10 +2473,10 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) rx_ring->valid_db_reg = doorbell_area + 0x04; /* PCI doorbell mem area + 0x18 for large buffer consumer */ - rx_ring->lbq_prod_idx_db_reg = (u32 *) (doorbell_area + 0x18); + rx_ring->lbq_prod_idx_db_reg = (u32 __iomem *) (doorbell_area + 0x18); /* PCI doorbell mem area + 0x1c */ - rx_ring->sbq_prod_idx_db_reg = (u32 *) (doorbell_area + 0x1c); + rx_ring->sbq_prod_idx_db_reg = (u32 __iomem *) (doorbell_area + 0x1c); memset((void *)cqicb, 0, sizeof(struct cqicb)); cqicb->msix_vect = rx_ring->irq; @@ -2611,7 +2607,7 @@ static int ql_start_tx_ring(struct ql_adapter *qdev, struct tx_ring *tx_ring) * Assign doorbell registers for this tx_ring. */ /* TX PCI doorbell mem area for tx producer index */ - tx_ring->prod_idx_db_reg = (u32 *) doorbell_area; + tx_ring->prod_idx_db_reg = (u32 __iomem *) doorbell_area; tx_ring->prod_idx = 0; /* TX PCI doorbell mem area + 0x04 */ tx_ring->valid_db_reg = doorbell_area + 0x04; @@ -3127,11 +3123,7 @@ static void ql_display_dev_info(struct net_device *ndev) qdev->chip_rev_id >> 4 & 0x0000000f, qdev->chip_rev_id >> 8 & 0x0000000f, qdev->chip_rev_id >> 12 & 0x0000000f); - QPRINTK(qdev, PROBE, INFO, - "MAC address %02x:%02x:%02x:%02x:%02x:%02x\n", - ndev->dev_addr[0], ndev->dev_addr[1], - ndev->dev_addr[2], ndev->dev_addr[3], ndev->dev_addr[4], - ndev->dev_addr[5]); + QPRINTK(qdev, PROBE, INFO, "MAC address %pM\n", ndev->dev_addr); } static int ql_adapter_down(struct ql_adapter *qdev) @@ -3156,7 +3148,7 @@ static int ql_adapter_down(struct ql_adapter *qdev) * a workqueue only if it's a single interrupt * environment (MSI/Legacy). */ - for (i = 1; i > qdev->rx_ring_count; i++) { + for (i = 1; i < qdev->rx_ring_count; i++) { rx_ring = &qdev->rx_ring[i]; /* Only the RSS rings use NAPI on multi irq * environment. Outbound completion processing @@ -3526,6 +3518,7 @@ static int qlge_set_mac_address(struct net_device *ndev, void *p) { struct ql_adapter *qdev = (struct ql_adapter *)netdev_priv(ndev); struct sockaddr *addr = p; + int ret = 0; if (netif_running(ndev)) return -EBUSY; @@ -3538,11 +3531,11 @@ static int qlge_set_mac_address(struct net_device *ndev, void *p) if (ql_set_mac_addr_reg(qdev, (u8 *) ndev->dev_addr, MAC_ADDR_TYPE_CAM_MAC, qdev->func)) {/* Unicast */ QPRINTK(qdev, HW, ERR, "Failed to load MAC address.\n"); - return -1; + ret = -1; } spin_unlock(&qdev->hw_lock); - return 0; + return ret; } static void qlge_tx_timeout(struct net_device *ndev) @@ -3592,7 +3585,7 @@ static void ql_release_all(struct pci_dev *pdev) qdev->q_workqueue = NULL; } if (qdev->reg_base) - iounmap((void *)qdev->reg_base); + iounmap(qdev->reg_base); if (qdev->doorbell_area) iounmap(qdev->doorbell_area); pci_release_regions(pdev); @@ -3721,6 +3714,22 @@ static int __devinit ql_init_device(struct pci_dev *pdev, return err; } + +static const struct net_device_ops qlge_netdev_ops = { + .ndo_open = qlge_open, + .ndo_stop = qlge_close, + .ndo_start_xmit = qlge_send, + .ndo_change_mtu = qlge_change_mtu, + .ndo_get_stats = qlge_get_stats, + .ndo_set_multicast_list = qlge_set_multicast_list, + .ndo_set_mac_address = qlge_set_mac_address, + .ndo_validate_addr = eth_validate_addr, + .ndo_tx_timeout = qlge_tx_timeout, + .ndo_vlan_rx_register = ql_vlan_rx_register, + .ndo_vlan_rx_add_vid = ql_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = ql_vlan_rx_kill_vid, +}; + static int __devinit qlge_probe(struct pci_dev *pdev, const struct pci_device_id *pci_entry) { @@ -3758,19 +3767,11 @@ static int __devinit qlge_probe(struct pci_dev *pdev, */ ndev->tx_queue_len = qdev->tx_ring_size; ndev->irq = pdev->irq; - ndev->open = qlge_open; - ndev->stop = qlge_close; - ndev->hard_start_xmit = qlge_send; + + ndev->netdev_ops = &qlge_netdev_ops; SET_ETHTOOL_OPS(ndev, &qlge_ethtool_ops); - ndev->change_mtu = qlge_change_mtu; - ndev->get_stats = qlge_get_stats; - ndev->set_multicast_list = qlge_set_multicast_list; - ndev->set_mac_address = qlge_set_mac_address; - ndev->tx_timeout = qlge_tx_timeout; ndev->watchdog_timeo = 10 * HZ; - ndev->vlan_rx_register = ql_vlan_rx_register; - ndev->vlan_rx_add_vid = ql_vlan_rx_add_vid; - ndev->vlan_rx_kill_vid = ql_vlan_rx_kill_vid; + err = register_netdev(ndev); if (err) { dev_err(&pdev->dev, "net device registration failed.\n"); diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c index 24fe344bcf1f9ef48ce39672f5bbe1cfd0a65d0d..fa31891b6e624bf00c47c78a4d9e986804c4728c 100644 --- a/drivers/net/qlge/qlge_mpi.c +++ b/drivers/net/qlge/qlge_mpi.c @@ -19,7 +19,7 @@ static int ql_read_mbox_reg(struct ql_adapter *qdev, u32 reg, u32 *data) return status; } -int ql_get_mb_sts(struct ql_adapter *qdev, struct mbox_params *mbcp) +static int ql_get_mb_sts(struct ql_adapter *qdev, struct mbox_params *mbcp) { int i, status; diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c index 34fe7ef8e5edf637c1f3c5f301c944e08f598076..53bbddfc8c954ec17381230a4a491374f4a7404e 100644 --- a/drivers/net/r6040.c +++ b/drivers/net/r6040.c @@ -49,8 +49,8 @@ #include #define DRV_NAME "r6040" -#define DRV_VERSION "0.18" -#define DRV_RELDATE "13Jul2008" +#define DRV_VERSION "0.19" +#define DRV_RELDATE "18Dec2008" /* PHY CHIP Address */ #define PHY1_ADDR 1 /* For MAC1 */ @@ -214,7 +214,7 @@ static int r6040_phy_read(void __iomem *ioaddr, int phy_addr, int reg) /* Wait for the read bit to be cleared */ while (limit--) { cmd = ioread16(ioaddr + MMDIO); - if (cmd & MDIO_READ) + if (!(cmd & MDIO_READ)) break; } @@ -233,7 +233,7 @@ static void r6040_phy_write(void __iomem *ioaddr, int phy_addr, int reg, u16 val /* Wait for the write bit to be cleared */ while (limit--) { cmd = ioread16(ioaddr + MMDIO); - if (cmd & MDIO_WRITE) + if (!(cmd & MDIO_WRITE)) break; } } @@ -598,7 +598,6 @@ static int r6040_rx(struct net_device *dev, int limit) /* Send to upper layer */ netif_receive_skb(skb_ptr); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += descptr->len - 4; @@ -668,7 +667,7 @@ static int r6040_poll(struct napi_struct *napi, int budget) work_done = r6040_rx(dev, budget); if (work_done < budget) { - netif_rx_complete(dev, napi); + netif_rx_complete(napi); /* Enable RX interrupt */ iowrite16(ioread16(ioaddr + MIER) | RX_INTS, ioaddr + MIER); } @@ -681,8 +680,10 @@ static irqreturn_t r6040_interrupt(int irq, void *dev_id) struct net_device *dev = dev_id; struct r6040_private *lp = netdev_priv(dev); void __iomem *ioaddr = lp->base; - u16 status; + u16 misr, status; + /* Save MIER */ + misr = ioread16(ioaddr + MIER); /* Mask off RDC MAC interrupt */ iowrite16(MSK_INT, ioaddr + MIER); /* Read MISR status and clear */ @@ -702,14 +703,17 @@ static irqreturn_t r6040_interrupt(int irq, void *dev_id) dev->stats.rx_fifo_errors++; /* Mask off RX interrupt */ - iowrite16(ioread16(ioaddr + MIER) & ~RX_INTS, ioaddr + MIER); - netif_rx_schedule(dev, &lp->napi); + misr &= ~RX_INTS; + netif_rx_schedule(&lp->napi); } /* TX interrupt request */ if (status & TX_INTS) r6040_tx(dev); + /* Restore RDC MAC interrupt */ + iowrite16(misr, ioaddr + MIER); + return IRQ_HANDLED; } @@ -1030,13 +1034,28 @@ static u32 netdev_get_link(struct net_device *dev) return mii_link_ok(&rp->mii_if); } -static struct ethtool_ops netdev_ethtool_ops = { +static const struct ethtool_ops netdev_ethtool_ops = { .get_drvinfo = netdev_get_drvinfo, .get_settings = netdev_get_settings, .set_settings = netdev_set_settings, .get_link = netdev_get_link, }; +static const struct net_device_ops r6040_netdev_ops = { + .ndo_open = r6040_open, + .ndo_stop = r6040_close, + .ndo_start_xmit = r6040_start_xmit, + .ndo_get_stats = r6040_get_stats, + .ndo_set_multicast_list = r6040_multicast_list, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_do_ioctl = r6040_ioctl, + .ndo_tx_timeout = r6040_tx_timeout, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = r6040_poll_controller, +#endif +}; + static int __devinit r6040_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -1128,18 +1147,10 @@ static int __devinit r6040_init_one(struct pci_dev *pdev, lp->switch_sig = 0; /* The RDC-specific entries in the device structure. */ - dev->open = &r6040_open; - dev->hard_start_xmit = &r6040_start_xmit; - dev->stop = &r6040_close; - dev->get_stats = r6040_get_stats; - dev->set_multicast_list = &r6040_multicast_list; - dev->do_ioctl = &r6040_ioctl; + dev->netdev_ops = &r6040_netdev_ops; dev->ethtool_ops = &netdev_ethtool_ops; - dev->tx_timeout = &r6040_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = r6040_poll_controller; -#endif + netif_napi_add(dev, &lp->napi, r6040_poll, 64); lp->mii_if.dev = dev; lp->mii_if.mdio_read = r6040_mdio_read; diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 4b7cb389dc4989edaf2f70ce9da55420484767bd..2c73ca606b35e0942e31a033791f550ed4db481c 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -474,6 +474,7 @@ struct rtl8169_private { void (*hw_start)(struct net_device *); unsigned int (*phy_reset_pending)(void __iomem *); unsigned int (*link_ok)(void __iomem *); + int (*do_ioctl)(struct rtl8169_private *tp, struct mii_ioctl_data *data, int cmd); int pcie_cap; struct delayed_work task; unsigned features; @@ -1829,9 +1830,11 @@ static int rtl8169_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) struct rtl8169_private *tp = netdev_priv(dev); struct mii_ioctl_data *data = if_mii(ifr); - if (!netif_running(dev)) - return -ENODEV; + return netif_running(dev) ? tp->do_ioctl(tp, data, cmd) : -ENODEV; +} +static int rtl_xmii_ioctl(struct rtl8169_private *tp, struct mii_ioctl_data *data, int cmd) +{ switch (cmd) { case SIOCGMIIPHY: data->phy_id = 32; /* Internal PHY */ @@ -1850,6 +1853,11 @@ static int rtl8169_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return -EOPNOTSUPP; } +static int rtl_tbi_ioctl(struct rtl8169_private *tp, struct mii_ioctl_data *data, int cmd) +{ + return -EOPNOTSUPP; +} + static const struct rtl_cfg_info { void (*hw_start)(struct net_device *); unsigned int region; @@ -1915,6 +1923,26 @@ static void rtl_disable_msi(struct pci_dev *pdev, struct rtl8169_private *tp) } } +static const struct net_device_ops rtl8169_netdev_ops = { + .ndo_open = rtl8169_open, + .ndo_stop = rtl8169_close, + .ndo_get_stats = rtl8169_get_stats, + .ndo_start_xmit = rtl8169_start_xmit, + .ndo_tx_timeout = rtl8169_tx_timeout, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = rtl8169_change_mtu, + .ndo_set_mac_address = rtl_set_mac_address, + .ndo_do_ioctl = rtl8169_ioctl, + .ndo_set_multicast_list = rtl_set_rx_mode, +#ifdef CONFIG_R8169_VLAN + .ndo_vlan_rx_register = rtl8169_vlan_rx_register, +#endif +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = rtl8169_netpoll, +#endif + +}; + static int __devinit rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -1941,6 +1969,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) } SET_NETDEV_DEV(dev, &pdev->dev); + dev->netdev_ops = &rtl8169_netdev_ops; tp = netdev_priv(dev); tp->dev = dev; tp->pci_dev = pdev; @@ -2076,6 +2105,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->phy_reset_enable = rtl8169_tbi_reset_enable; tp->phy_reset_pending = rtl8169_tbi_reset_pending; tp->link_ok = rtl8169_tbi_link_ok; + tp->do_ioctl = rtl_tbi_ioctl; tp->phy_1000_ctrl_reg = ADVERTISE_1000FULL; /* Implied by TBI */ } else { @@ -2084,8 +2114,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->phy_reset_enable = rtl8169_xmii_reset_enable; tp->phy_reset_pending = rtl8169_xmii_reset_pending; tp->link_ok = rtl8169_xmii_link_ok; - - dev->do_ioctl = rtl8169_ioctl; + tp->do_ioctl = rtl_xmii_ioctl; } spin_lock_init(&tp->lock); @@ -2097,28 +2126,15 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev->dev_addr[i] = RTL_R8(MAC0 + i); memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); - dev->open = rtl8169_open; - dev->hard_start_xmit = rtl8169_start_xmit; - dev->get_stats = rtl8169_get_stats; SET_ETHTOOL_OPS(dev, &rtl8169_ethtool_ops); - dev->stop = rtl8169_close; - dev->tx_timeout = rtl8169_tx_timeout; - dev->set_multicast_list = rtl_set_rx_mode; dev->watchdog_timeo = RTL8169_TX_TIMEOUT; dev->irq = pdev->irq; dev->base_addr = (unsigned long) ioaddr; - dev->change_mtu = rtl8169_change_mtu; - dev->set_mac_address = rtl_set_mac_address; netif_napi_add(dev, &tp->napi, rtl8169_poll, R8169_NAPI_WEIGHT); #ifdef CONFIG_R8169_VLAN dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - dev->vlan_rx_register = rtl8169_vlan_rx_register; -#endif - -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = rtl8169_netpoll; #endif tp->intr_mask = 0xffff; @@ -3484,7 +3500,6 @@ static int rtl8169_rx_interrupt(struct net_device *dev, if (rtl8169_rx_vlan_skb(tp, desc, skb) < 0) netif_receive_skb(skb); - dev->last_rx = jiffies; dev->stats.rx_bytes += pkt_size; dev->stats.rx_packets++; } @@ -3566,8 +3581,8 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance) RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event); tp->intr_mask = ~tp->napi_event; - if (likely(netif_rx_schedule_prep(dev, &tp->napi))) - __netif_rx_schedule(dev, &tp->napi); + if (likely(netif_rx_schedule_prep(&tp->napi))) + __netif_rx_schedule(&tp->napi); else if (netif_msg_intr(tp)) { printk(KERN_INFO "%s: interrupt %04x in poll\n", dev->name, status); @@ -3588,7 +3603,7 @@ static int rtl8169_poll(struct napi_struct *napi, int budget) rtl8169_tx_interrupt(dev, tp, ioaddr); if (work_done < budget) { - netif_rx_complete(dev, napi); + netif_rx_complete(napi); tp->intr_mask = 0xffff; /* * 20040426: the barrier is not strictly required but the diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c index 2b8fd68bc5163b49a09b373fb1913d6793bc051e..a6fd27a2cc3d25b4808ae5c85ba8c7a8e6e9da4b 100644 --- a/drivers/net/rionet.c +++ b/drivers/net/rionet.c @@ -94,7 +94,7 @@ static int rionet_rx_clean(struct net_device *ndev) { int i; int error = 0; - struct rionet_private *rnet = ndev->priv; + struct rionet_private *rnet = netdev_priv(ndev); void *data; i = rnet->rx_slot; @@ -132,7 +132,7 @@ static int rionet_rx_clean(struct net_device *ndev) static void rionet_rx_fill(struct net_device *ndev, int end) { int i; - struct rionet_private *rnet = ndev->priv; + struct rionet_private *rnet = netdev_priv(ndev); i = rnet->rx_slot; do { @@ -151,7 +151,7 @@ static void rionet_rx_fill(struct net_device *ndev, int end) static int rionet_queue_tx_msg(struct sk_buff *skb, struct net_device *ndev, struct rio_dev *rdev) { - struct rionet_private *rnet = ndev->priv; + struct rionet_private *rnet = netdev_priv(ndev); rio_add_outb_message(rnet->mport, rdev, 0, skb->data, skb->len); rnet->tx_skb[rnet->tx_slot] = skb; @@ -175,7 +175,7 @@ static int rionet_queue_tx_msg(struct sk_buff *skb, struct net_device *ndev, static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev) { int i; - struct rionet_private *rnet = ndev->priv; + struct rionet_private *rnet = netdev_priv(ndev); struct ethhdr *eth = (struct ethhdr *)skb->data; u16 destid; unsigned long flags; @@ -215,7 +215,7 @@ static void rionet_dbell_event(struct rio_mport *mport, void *dev_id, u16 sid, u u16 info) { struct net_device *ndev = dev_id; - struct rionet_private *rnet = ndev->priv; + struct rionet_private *rnet = netdev_priv(ndev); struct rionet_peer *peer; if (netif_msg_intr(rnet)) @@ -243,7 +243,7 @@ static void rionet_inb_msg_event(struct rio_mport *mport, void *dev_id, int mbox { int n; struct net_device *ndev = dev_id; - struct rionet_private *rnet = (struct rionet_private *)ndev->priv; + struct rionet_private *rnet = netdev_priv(ndev); if (netif_msg_intr(rnet)) printk(KERN_INFO "%s: inbound message event, mbox %d slot %d\n", @@ -258,7 +258,7 @@ static void rionet_inb_msg_event(struct rio_mport *mport, void *dev_id, int mbox static void rionet_outb_msg_event(struct rio_mport *mport, void *dev_id, int mbox, int slot) { struct net_device *ndev = dev_id; - struct rionet_private *rnet = ndev->priv; + struct rionet_private *rnet = netdev_priv(ndev); spin_lock(&rnet->lock); @@ -287,7 +287,7 @@ static int rionet_open(struct net_device *ndev) int i, rc = 0; struct rionet_peer *peer, *tmp; u32 pwdcsr; - struct rionet_private *rnet = ndev->priv; + struct rionet_private *rnet = netdev_priv(ndev); if (netif_msg_ifup(rnet)) printk(KERN_INFO "%s: open\n", DRV_NAME); @@ -351,7 +351,7 @@ static int rionet_open(struct net_device *ndev) static int rionet_close(struct net_device *ndev) { - struct rionet_private *rnet = (struct rionet_private *)ndev->priv; + struct rionet_private *rnet = netdev_priv(ndev); struct rionet_peer *peer, *tmp; int i; @@ -400,7 +400,7 @@ static void rionet_remove(struct rio_dev *rdev) static void rionet_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info) { - struct rionet_private *rnet = ndev->priv; + struct rionet_private *rnet = netdev_priv(ndev); strcpy(info->driver, DRV_NAME); strcpy(info->version, DRV_VERSION); @@ -410,14 +410,14 @@ static void rionet_get_drvinfo(struct net_device *ndev, static u32 rionet_get_msglevel(struct net_device *ndev) { - struct rionet_private *rnet = ndev->priv; + struct rionet_private *rnet = netdev_priv(ndev); return rnet->msg_enable; } static void rionet_set_msglevel(struct net_device *ndev, u32 value) { - struct rionet_private *rnet = ndev->priv; + struct rionet_private *rnet = netdev_priv(ndev); rnet->msg_enable = value; } @@ -435,7 +435,6 @@ static int rionet_setup_netdev(struct rio_mport *mport) struct net_device *ndev = NULL; struct rionet_private *rnet; u16 device_id; - DECLARE_MAC_BUF(mac); /* Allocate our net_device structure */ ndev = alloc_etherdev(sizeof(struct rionet_private)); @@ -456,7 +455,7 @@ static int rionet_setup_netdev(struct rio_mport *mport) RIO_MAX_ROUTE_ENTRIES(mport->sys_size)); /* Set up private area */ - rnet = (struct rionet_private *)ndev->priv; + rnet = netdev_priv(ndev); rnet->mport = mport; /* Set the default MAC address */ @@ -485,12 +484,12 @@ static int rionet_setup_netdev(struct rio_mport *mport) if (rc != 0) goto out; - printk("%s: %s %s Version %s, MAC %s\n", + printk("%s: %s %s Version %s, MAC %pM\n", ndev->name, DRV_NAME, DRV_DESC, DRV_VERSION, - print_mac(mac, ndev->dev_addr)); + ndev->dev_addr); out: return rc; diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c index 3dd8f1342f70c58eb83ffb01cbb0f40576666076..d890829a9acc61f678e06c273a031976603f010f 100644 --- a/drivers/net/rrunner.c +++ b/drivers/net/rrunner.c @@ -63,6 +63,16 @@ MODULE_LICENSE("GPL"); static char version[] __devinitdata = "rrunner.c: v0.50 11/11/2002 Jes Sorensen (jes@wildopensource.com)\n"; + +static const struct net_device_ops rr_netdev_ops = { + .ndo_open = rr_open, + .ndo_stop = rr_close, + .ndo_do_ioctl = rr_ioctl, + .ndo_start_xmit = rr_start_xmit, + .ndo_change_mtu = hippi_change_mtu, + .ndo_set_mac_address = hippi_mac_addr, +}; + /* * Implementation notes: * @@ -115,10 +125,7 @@ static int __devinit rr_init_one(struct pci_dev *pdev, spin_lock_init(&rrpriv->lock); dev->irq = pdev->irq; - dev->open = &rr_open; - dev->hard_start_xmit = &rr_start_xmit; - dev->stop = &rr_close; - dev->do_ioctl = &rr_ioctl; + dev->netdev_ops = &rr_netdev_ops; dev->base_addr = pci_resource_start(pdev, 0); @@ -511,7 +518,6 @@ static int __devinit rr_init(struct net_device *dev) struct rr_private *rrpriv; struct rr_regs __iomem *regs; u32 sram_size, rev; - DECLARE_MAC_BUF(mac); rrpriv = netdev_priv(dev); regs = rrpriv->regs; @@ -549,7 +555,7 @@ static int __devinit rr_init(struct net_device *dev) *(__be32 *)(dev->dev_addr+2) = htonl(rr_read_eeprom_word(rrpriv, offsetof(struct eeprom, manf.BoardULA[4]))); - printk(" MAC: %s\n", print_mac(mac, dev->dev_addr)); + printk(" MAC: %pM\n", dev->dev_addr); sram_size = rr_read_eeprom_word(rrpriv, 8); printk(" SRAM size 0x%06x\n", sram_size); @@ -1006,7 +1012,6 @@ static void rx_int(struct net_device *dev, u32 rxlimit, u32 index) netif_rx(skb); /* send it up */ - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } @@ -1708,9 +1713,3 @@ static void __exit rr_cleanup_module(void) module_init(rr_init_module); module_exit(rr_cleanup_module); - -/* - * Local variables: - * compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c rrunner.c" - * End: - */ diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 6a1375f9cbb81e2c627f2fe1f6606839b9c0c16c..f5c57c059bca15c7d9e35f0b26c39fb0551bc718 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -352,12 +352,13 @@ static void do_s2io_copy_mac_addr(struct s2io_nic *sp, int offset, u64 mac_addr) sp->def_mac_addr[offset].mac_addr[1] = (u8) (mac_addr >> 32); sp->def_mac_addr[offset].mac_addr[0] = (u8) (mac_addr >> 40); } + /* Add the vlan */ static void s2io_vlan_rx_register(struct net_device *dev, - struct vlan_group *grp) + struct vlan_group *grp) { int i; - struct s2io_nic *nic = dev->priv; + struct s2io_nic *nic = netdev_priv(dev); unsigned long flags[MAX_TX_FIFOS]; struct mac_info *mac_control = &nic->mac_control; struct config_param *config = &nic->config; @@ -372,10 +373,10 @@ static void s2io_vlan_rx_register(struct net_device *dev, } /* Unregister the vlan */ -static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid) +static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) { int i; - struct s2io_nic *nic = dev->priv; + struct s2io_nic *nic = netdev_priv(dev); unsigned long flags[MAX_TX_FIFOS]; struct mac_info *mac_control = &nic->mac_control; struct config_param *config = &nic->config; @@ -2837,7 +2838,7 @@ static int s2io_poll_msix(struct napi_struct *napi, int budget) int pkts_processed = 0; u8 __iomem *addr = NULL; u8 val8 = 0; - struct s2io_nic *nic = dev->priv; + struct s2io_nic *nic = netdev_priv(dev); struct XENA_dev_config __iomem *bar0 = nic->bar0; int budget_org = budget; @@ -2851,7 +2852,7 @@ static int s2io_poll_msix(struct napi_struct *napi, int budget) s2io_chk_rx_buffers(nic, ring); if (pkts_processed < budget_org) { - netif_rx_complete(dev, napi); + netif_rx_complete(napi); /*Re Enable MSI-Rx Vector*/ addr = (u8 __iomem *)&bar0->xmsi_mask_reg; addr += 7 - ring->ring_no; @@ -2865,7 +2866,6 @@ static int s2io_poll_inta(struct napi_struct *napi, int budget) { struct s2io_nic *nic = container_of(napi, struct s2io_nic, napi); struct ring_info *ring; - struct net_device *dev = nic->dev; struct config_param *config; struct mac_info *mac_control; int pkts_processed = 0; @@ -2889,7 +2889,7 @@ static int s2io_poll_inta(struct napi_struct *napi, int budget) break; } if (pkts_processed < budget_org) { - netif_rx_complete(dev, napi); + netif_rx_complete(napi); /* Re enable the Rx interrupts for the ring */ writeq(0, &bar0->rx_traffic_mask); readl(&bar0->rx_traffic_mask); @@ -2909,7 +2909,7 @@ static int s2io_poll_inta(struct napi_struct *napi, int budget) */ static void s2io_netpoll(struct net_device *dev) { - struct s2io_nic *nic = dev->priv; + struct s2io_nic *nic = netdev_priv(dev); struct mac_info *mac_control; struct config_param *config; struct XENA_dev_config __iomem *bar0 = nic->bar0; @@ -3171,7 +3171,7 @@ static void tx_intr_handler(struct fifo_info *fifo_data) static void s2io_mdio_write(u32 mmd_type, u64 addr, u16 value, struct net_device *dev) { u64 val64 = 0x0; - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); struct XENA_dev_config __iomem *bar0 = sp->bar0; //address transaction @@ -3220,7 +3220,7 @@ static u64 s2io_mdio_read(u32 mmd_type, u64 addr, struct net_device *dev) { u64 val64 = 0x0; u64 rval64 = 0x0; - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); struct XENA_dev_config __iomem *bar0 = sp->bar0; /* address transaction */ @@ -3324,7 +3324,7 @@ static void s2io_updt_xpak_counter(struct net_device *dev) u64 val64 = 0x0; u64 addr = 0x0; - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); struct stat_block *stat_info = sp->mac_control.stats_info; /* Check the communication with the MDIO slave */ @@ -3990,7 +3990,7 @@ static void remove_inta_isr(struct s2io_nic *sp) static int s2io_open(struct net_device *dev) { - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); int err = 0; /* @@ -4048,7 +4048,7 @@ static int s2io_open(struct net_device *dev) static int s2io_close(struct net_device *dev) { - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); struct config_param *config = &sp->config; u64 tmp64; int offset; @@ -4087,7 +4087,7 @@ static int s2io_close(struct net_device *dev) static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) { - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); u16 frg_cnt, frg_len, i, queue, queue_len, put_off, get_off; register u64 val64; struct TxD *txdp; @@ -4329,7 +4329,6 @@ static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id) struct ring_info *ring = (struct ring_info *)dev_id; struct s2io_nic *sp = ring->nic; struct XENA_dev_config __iomem *bar0 = sp->bar0; - struct net_device *dev = sp->dev; if (unlikely(!is_s2io_card_up(sp))) return IRQ_HANDLED; @@ -4343,7 +4342,7 @@ static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id) val8 = (ring->ring_no == 0) ? 0x7f : 0xff; writeb(val8, addr); val8 = readb(addr); - netif_rx_schedule(dev, &ring->napi); + netif_rx_schedule(&ring->napi); } else { rx_intr_handler(ring, 0); s2io_chk_rx_buffers(sp, ring); @@ -4485,7 +4484,7 @@ static int do_s2io_chk_alarm_bit(u64 value, void __iomem * addr, static void s2io_handle_errors(void * dev_id) { struct net_device *dev = (struct net_device *) dev_id; - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 temp64 = 0,val64=0; int i = 0; @@ -4752,7 +4751,7 @@ static void s2io_handle_errors(void * dev_id) static irqreturn_t s2io_isr(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); struct XENA_dev_config __iomem *bar0 = sp->bar0; int i; u64 reason = 0; @@ -4790,7 +4789,7 @@ static irqreturn_t s2io_isr(int irq, void *dev_id) if (config->napi) { if (reason & GEN_INTR_RXTRAFFIC) { - netif_rx_schedule(dev, &sp->napi); + netif_rx_schedule(&sp->napi); writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_mask); writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int); readl(&bar0->rx_traffic_int); @@ -4881,7 +4880,7 @@ static void s2io_updt_stats(struct s2io_nic *sp) static struct net_device_stats *s2io_get_stats(struct net_device *dev) { - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); struct mac_info *mac_control; struct config_param *config; int i; @@ -4948,7 +4947,7 @@ static void s2io_set_multicast(struct net_device *dev) { int i, j, prev_cnt; struct dev_mc_list *mclist; - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64 = 0, multi_mac = 0x010203040506ULL, mask = 0xfeffffffffffULL; @@ -5112,7 +5111,7 @@ static void s2io_set_multicast(struct net_device *dev) /* read from CAM unicast & multicast addresses and store it in * def_mac_addr structure */ -void do_s2io_store_unicast_mc(struct s2io_nic *sp) +static void do_s2io_store_unicast_mc(struct s2io_nic *sp) { int offset; u64 mac_addr = 0x0; @@ -5277,7 +5276,7 @@ static int s2io_set_mac_addr(struct net_device *dev, void *p) static int do_s2io_prog_unicast(struct net_device *dev, u8 *addr) { - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); register u64 mac_addr = 0, perm_addr = 0; int i; u64 tmp64; @@ -5336,7 +5335,7 @@ static int do_s2io_prog_unicast(struct net_device *dev, u8 *addr) static int s2io_ethtool_sset(struct net_device *dev, struct ethtool_cmd *info) { - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); if ((info->autoneg == AUTONEG_ENABLE) || (info->speed != SPEED_10000) || (info->duplex != DUPLEX_FULL)) return -EINVAL; @@ -5362,7 +5361,7 @@ static int s2io_ethtool_sset(struct net_device *dev, static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info) { - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); info->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); info->advertising = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); info->port = PORT_FIBRE; @@ -5397,7 +5396,7 @@ static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info) static void s2io_ethtool_gdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); strncpy(info->driver, s2io_driver_name, sizeof(info->driver)); strncpy(info->version, s2io_driver_version, sizeof(info->version)); @@ -5427,7 +5426,7 @@ static void s2io_ethtool_gregs(struct net_device *dev, int i; u64 reg; u8 *reg_space = (u8 *) space; - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); regs->len = XENA_REG_SPACE; regs->version = sp->pdev->subsystem_device; @@ -5487,7 +5486,7 @@ static void s2io_phy_id(unsigned long data) static int s2io_ethtool_idnic(struct net_device *dev, u32 data) { u64 val64 = 0, last_gpio_ctrl_val; - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); struct XENA_dev_config __iomem *bar0 = sp->bar0; u16 subid; @@ -5525,7 +5524,7 @@ static int s2io_ethtool_idnic(struct net_device *dev, u32 data) static void s2io_ethtool_gringparam(struct net_device *dev, struct ethtool_ringparam *ering) { - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); int i,tx_desc_count=0,rx_desc_count=0; if (sp->rxd_mode == RXD_MODE_1) @@ -5568,7 +5567,7 @@ static void s2io_ethtool_getpause_data(struct net_device *dev, struct ethtool_pauseparam *ep) { u64 val64; - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); struct XENA_dev_config __iomem *bar0 = sp->bar0; val64 = readq(&bar0->rmac_pause_cfg); @@ -5595,7 +5594,7 @@ static int s2io_ethtool_setpause_data(struct net_device *dev, struct ethtool_pauseparam *ep) { u64 val64; - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); struct XENA_dev_config __iomem *bar0 = sp->bar0; val64 = readq(&bar0->rmac_pause_cfg); @@ -5825,7 +5824,7 @@ static int s2io_ethtool_geeprom(struct net_device *dev, { u32 i, valid; u64 data; - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); eeprom->magic = sp->pdev->vendor | (sp->pdev->device << 16); @@ -5863,7 +5862,7 @@ static int s2io_ethtool_seeprom(struct net_device *dev, { int len = eeprom->len, cnt = 0; u64 valid = 0, data; - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); if (eeprom->magic != (sp->pdev->vendor | (sp->pdev->device << 16))) { DBG_PRINT(ERR_DBG, @@ -6243,7 +6242,7 @@ static void s2io_ethtool_test(struct net_device *dev, struct ethtool_test *ethtest, uint64_t * data) { - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); int orig_state = netif_running(sp->dev); if (ethtest->flags == ETH_TEST_FL_OFFLINE) { @@ -6299,7 +6298,7 @@ static void s2io_get_ethtool_stats(struct net_device *dev, u64 * tmp_stats) { int i = 0, k; - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); struct stat_block *stat_info = sp->mac_control.stats_info; s2io_updt_stats(sp); @@ -6578,14 +6577,14 @@ static int s2io_ethtool_get_regs_len(struct net_device *dev) static u32 s2io_ethtool_get_rx_csum(struct net_device * dev) { - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); return (sp->rx_csum); } static int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data) { - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); if (data) sp->rx_csum = 1; @@ -6602,7 +6601,7 @@ static int s2io_get_eeprom_len(struct net_device *dev) static int s2io_get_sset_count(struct net_device *dev, int sset) { - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); switch (sset) { case ETH_SS_TEST: @@ -6625,7 +6624,7 @@ static void s2io_ethtool_get_strings(struct net_device *dev, u32 stringset, u8 * data) { int stat_size = 0; - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); switch (stringset) { case ETH_SS_TEST: @@ -6727,7 +6726,7 @@ static int s2io_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) static int s2io_change_mtu(struct net_device *dev, int new_mtu) { - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); int ret = 0; if ((new_mtu < MIN_MTU) || (new_mtu > S2IO_JUMBO_SIZE)) { @@ -7331,7 +7330,7 @@ static void s2io_restart_nic(struct work_struct *work) static void s2io_tx_watchdog(struct net_device *dev) { - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); if (netif_carrier_ok(dev)) { sp->mac_control.stats_info->sw_stat.watchdog_timer_cnt++; @@ -7366,7 +7365,7 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) int ring_no = ring_data->ring_no; u16 l3_csum, l4_csum; unsigned long long err = rxdp->Control_1 & RXD_T_CODE; - struct lro *lro; + struct lro *uninitialized_var(lro); u8 err_mask; skb->dev = dev; @@ -7544,7 +7543,6 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) sp->mac_control.stats_info->sw_stat.mem_freed += skb->truesize; send_up: queue_rx_frame(skb, RXD_GET_VLAN_TAG(rxdp->Control_2)); - dev->last_rx = jiffies; aggregate: sp->mac_control.rings[ring_no].rx_bufs_left -= 1; return SUCCESS; @@ -7718,6 +7716,24 @@ static int rts_ds_steer(struct s2io_nic *nic, u8 ds_codepoint, u8 ring) S2IO_BIT_RESET); } +static const struct net_device_ops s2io_netdev_ops = { + .ndo_open = s2io_open, + .ndo_stop = s2io_close, + .ndo_get_stats = s2io_get_stats, + .ndo_start_xmit = s2io_xmit, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = s2io_set_multicast, + .ndo_do_ioctl = s2io_ioctl, + .ndo_set_mac_address = s2io_set_mac_addr, + .ndo_change_mtu = s2io_change_mtu, + .ndo_vlan_rx_register = s2io_vlan_rx_register, + .ndo_vlan_rx_kill_vid = s2io_vlan_rx_kill_vid, + .ndo_tx_timeout = s2io_tx_watchdog, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = s2io_netpoll, +#endif +}; + /** * s2io_init_nic - Initialization of the adapter . * @pdev : structure containing the PCI related information of the device. @@ -7748,7 +7764,6 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) int mode; u8 dev_intr_type = intr_type; u8 dev_multiq = 0; - DECLARE_MAC_BUF(mac); ret = s2io_verify_parm(pdev, &dev_intr_type, &dev_multiq); if (ret) @@ -7798,7 +7813,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) SET_NETDEV_DEV(dev, &pdev->dev); /* Private member variable initialized to s2io NIC structure */ - sp = dev->priv; + sp = netdev_priv(dev); memset(sp, 0, sizeof(struct s2io_nic)); sp->dev = dev; sp->pdev = pdev; @@ -7918,8 +7933,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) goto mem_alloc_failed; } - sp->bar0 = ioremap(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); + sp->bar0 = pci_ioremap_bar(pdev, 0); if (!sp->bar0) { DBG_PRINT(ERR_DBG, "%s: Neterion: cannot remap io mem1\n", dev->name); @@ -7927,8 +7941,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) goto bar0_remap_failed; } - sp->bar1 = ioremap(pci_resource_start(pdev, 2), - pci_resource_len(pdev, 2)); + sp->bar1 = pci_ioremap_bar(pdev, 2); if (!sp->bar1) { DBG_PRINT(ERR_DBG, "%s: Neterion: cannot remap io mem2\n", dev->name); @@ -7946,26 +7959,9 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) } /* Driver entry points */ - dev->open = &s2io_open; - dev->stop = &s2io_close; - dev->hard_start_xmit = &s2io_xmit; - dev->get_stats = &s2io_get_stats; - dev->set_multicast_list = &s2io_set_multicast; - dev->do_ioctl = &s2io_ioctl; - dev->set_mac_address = &s2io_set_mac_addr; - dev->change_mtu = &s2io_change_mtu; + dev->netdev_ops = &s2io_netdev_ops; SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - dev->vlan_rx_register = s2io_vlan_rx_register; - dev->vlan_rx_kill_vid = (void *)s2io_vlan_rx_kill_vid; - - /* - * will use eth_mac_addr() for dev->set_mac_address - * mac address will be set every time dev->open() is called - */ -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = s2io_netpoll; -#endif dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; if (sp->high_dma_flag == TRUE) @@ -7976,7 +7972,6 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) dev->features |= NETIF_F_UFO; dev->features |= NETIF_F_HW_CSUM; } - dev->tx_timeout = &s2io_tx_watchdog; dev->watchdog_timeo = WATCH_DOG_TIMEOUT; INIT_WORK(&sp->rst_timer_task, s2io_restart_nic); INIT_WORK(&sp->set_link_task, s2io_set_link); @@ -8125,8 +8120,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) sp->product_name, pdev->revision); DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name, s2io_driver_version); - DBG_PRINT(ERR_DBG, "%s: MAC ADDR: %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + DBG_PRINT(ERR_DBG, "%s: MAC ADDR: %pM\n", dev->name, dev->dev_addr); DBG_PRINT(ERR_DBG, "SERIAL NUMBER: %s\n", sp->serial_num); if (sp->device_type & XFRAME_II_DEVICE) { mode = s2io_print_pci_mode(sp); @@ -8255,7 +8249,7 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev) flush_scheduled_work(); - sp = dev->priv; + sp = netdev_priv(dev); unregister_netdev(dev); free_shared_mem(sp); @@ -8590,7 +8584,7 @@ static void clear_lro_session(struct lro *lro) static void queue_rx_frame(struct sk_buff *skb, u16 vlan_tag) { struct net_device *dev = skb->dev; - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); skb->protocol = eth_type_trans(skb, dev); if (sp->vlgrp && vlan_tag @@ -8639,7 +8633,7 @@ static pci_ers_result_t s2io_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state) { struct net_device *netdev = pci_get_drvdata(pdev); - struct s2io_nic *sp = netdev->priv; + struct s2io_nic *sp = netdev_priv(netdev); netif_device_detach(netdev); @@ -8664,7 +8658,7 @@ static pci_ers_result_t s2io_io_error_detected(struct pci_dev *pdev, static pci_ers_result_t s2io_io_slot_reset(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); - struct s2io_nic *sp = netdev->priv; + struct s2io_nic *sp = netdev_priv(netdev); if (pci_enable_device(pdev)) { printk(KERN_ERR "s2io: " @@ -8688,7 +8682,7 @@ static pci_ers_result_t s2io_io_slot_reset(struct pci_dev *pdev) static void s2io_io_resume(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); - struct s2io_nic *sp = netdev->priv; + struct s2io_nic *sp = netdev_priv(netdev); if (netif_running(netdev)) { if (s2io_card_up(sp)) { diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c index 5986cec17f19eff6b3aa06ba9f4d500ef953b8bd..be3025310e90c1eb3e3c2f15316b24fda8d8cd42 100644 --- a/drivers/net/sb1000.c +++ b/drivers/net/sb1000.c @@ -869,7 +869,6 @@ printk("cm0: IP identification: %02x%02x fragment offset: %02x%02x\n", buffer[3 /* datagram completed: send to upper level */ skb_trim(skb, dlen); netif_rx(skb); - dev->last_rx = jiffies; stats->rx_bytes+=dlen; stats->rx_packets++; lp->rx_skb[ns] = NULL; diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index 2615d46e6e503c08fdcdbad4fcb1b8a3873d16e8..31e38fae017f8def7273d568089914599a1b54d6 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -2039,9 +2039,9 @@ static irqreturn_t sbmac_intr(int irq,void *dev_instance) sbdma_tx_process(sc,&(sc->sbm_txdma), 0); if (isr & (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)) { - if (netif_rx_schedule_prep(dev, &sc->napi)) { + if (netif_rx_schedule_prep(&sc->napi)) { __raw_writeq(0, sc->sbm_imr); - __netif_rx_schedule(dev, &sc->napi); + __netif_rx_schedule(&sc->napi); /* Depend on the exit from poll to reenable intr */ } else { @@ -2292,7 +2292,6 @@ static int sbmac_init(struct platform_device *pldev, long long base) uint64_t ea_reg; int i; int err; - DECLARE_MAC_BUF(mac); sc->sbm_dev = dev; sc->sbe_idx = idx; @@ -2373,8 +2372,8 @@ static int sbmac_init(struct platform_device *pldev, long long base) * process so we need to finish off the config message that * was being displayed) */ - pr_info("%s: SiByte Ethernet at 0x%08Lx, address: %s\n", - dev->name, base, print_mac(mac, eaddr)); + pr_info("%s: SiByte Ethernet at 0x%08Lx, address: %pM\n", + dev->name, base, eaddr); sc->mii_bus->name = sbmac_mdio_string; snprintf(sc->mii_bus->id, MII_BUS_ID_SIZE, "%x", idx); @@ -2668,7 +2667,7 @@ static int sbmac_poll(struct napi_struct *napi, int budget) sbdma_tx_process(sc, &(sc->sbm_txdma), 1); if (work_done < budget) { - netif_rx_complete(dev, napi); + netif_rx_complete(napi); #ifdef CONFIG_SBMAC_COALESCE __raw_writeq(((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) | diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c index 61955f8d80119705806b9fd8ab9714cd56bcff2c..42fd31276602a6b15c90ea405238cf26bb97a345 100644 --- a/drivers/net/sc92031.c +++ b/drivers/net/sc92031.c @@ -816,7 +816,6 @@ static void _sc92031_rx_tasklet(struct net_device *dev) } skb->protocol = eth_type_trans(skb, dev); - dev->last_rx = jiffies; netif_rx(skb); dev->stats.rx_bytes += pkt_size; @@ -1387,7 +1386,7 @@ static void sc92031_ethtool_get_ethtool_stats(struct net_device *dev, spin_unlock_bh(&priv->lock); } -static struct ethtool_ops sc92031_ethtool_ops = { +static const struct ethtool_ops sc92031_ethtool_ops = { .get_settings = sc92031_ethtool_get_settings, .set_settings = sc92031_ethtool_set_settings, .get_drvinfo = sc92031_ethtool_get_drvinfo, @@ -1400,6 +1399,21 @@ static struct ethtool_ops sc92031_ethtool_ops = { .get_ethtool_stats = sc92031_ethtool_get_ethtool_stats, }; + +static const struct net_device_ops sc92031_netdev_ops = { + .ndo_get_stats = sc92031_get_stats, + .ndo_start_xmit = sc92031_start_xmit, + .ndo_open = sc92031_open, + .ndo_stop = sc92031_stop, + .ndo_set_multicast_list = sc92031_set_multicast_list, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_tx_timeout = sc92031_tx_timeout, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = sc92031_poll_controller, +#endif +}; + static int __devinit sc92031_probe(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -1453,17 +1467,9 @@ static int __devinit sc92031_probe(struct pci_dev *pdev, /* faked with skb_copy_and_csum_dev */ dev->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HIGHDMA; - dev->get_stats = sc92031_get_stats; - dev->ethtool_ops = &sc92031_ethtool_ops; - dev->hard_start_xmit = sc92031_start_xmit; + dev->netdev_ops = &sc92031_netdev_ops; dev->watchdog_timeo = TX_TIMEOUT; - dev->open = sc92031_open; - dev->stop = sc92031_stop; - dev->set_multicast_list = sc92031_set_multicast_list; - dev->tx_timeout = sc92031_tx_timeout; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = sc92031_poll_controller; -#endif + dev->ethtool_ops = &sc92031_ethtool_ops; priv = netdev_priv(dev); spin_lock_init(&priv->lock); diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c index 48c64fb20eecf164b9022aae727e6dc86e8f5290..12a8ffffeb03d3e448c8cab167f80c7d42a3dbf9 100644 --- a/drivers/net/seeq8005.c +++ b/drivers/net/seeq8005.c @@ -158,7 +158,6 @@ static int __init seeq8005_probe1(struct net_device *dev, int ioaddr) int old_dmaar; int old_rear; int retval; - DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, SEEQ8005_IO_EXTENT, "seeq8005")) return -ENODEV; @@ -303,7 +302,7 @@ static int __init seeq8005_probe1(struct net_device *dev, int ioaddr) /* Retrieve and print the ethernet address. */ for (i = 0; i < 6; i++) dev->dev_addr[i] = SA_prom[i+6]; - printk("%s", print_mac(mac, dev->dev_addr)); + printk("%pM", dev->dev_addr); if (dev->irq == 0xff) ; /* Do nothing: a user-level program will set it. */ @@ -564,7 +563,6 @@ static void seeq8005_rx(struct net_device *dev) skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } @@ -746,12 +744,3 @@ void __exit cleanup_module(void) } #endif /* MODULE */ - -/* - * Local variables: - * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c skeleton.c" - * version-control: t - * kept-new-versions: 5 - * tab-width: 4 - * End: - */ diff --git a/drivers/net/sfc/Kconfig b/drivers/net/sfc/Kconfig index 3be13b592b4dbb0f7c1382ec745d8684f57c8cb6..c535408ad6bef520262118f0283c0d004ee6cc56 100644 --- a/drivers/net/sfc/Kconfig +++ b/drivers/net/sfc/Kconfig @@ -12,3 +12,11 @@ config SFC To compile this driver as a module, choose M here. The module will be called sfc. +config SFC_MTD + bool "Solarflare Solarstorm SFC4000 flash MTD support" + depends on SFC && MTD && !(SFC=y && MTD=m) + default y + help + This exposes the on-board flash memory as an MTD device (e.g. + /dev/mtd1). This makes it possible to upload new boot code + to the NIC. diff --git a/drivers/net/sfc/Makefile b/drivers/net/sfc/Makefile index c8f5704c8fb18adf946e8b1bc66afea50c76a12b..b89f9be3cb1308c5f9b1c940e9177940171d219a 100644 --- a/drivers/net/sfc/Makefile +++ b/drivers/net/sfc/Makefile @@ -1,5 +1,6 @@ -sfc-y += efx.o falcon.o tx.o rx.o falcon_xmac.o \ - selftest.o ethtool.o xfp_phy.o \ +sfc-y += efx.o falcon.o tx.o rx.o falcon_gmac.o \ + falcon_xmac.o selftest.o ethtool.o xfp_phy.o \ mdio_10g.o tenxpress.o boards.o sfe4001.o +sfc-$(CONFIG_SFC_MTD) += mtd.o obj-$(CONFIG_SFC) += sfc.o diff --git a/drivers/net/sfc/boards.c b/drivers/net/sfc/boards.c index 99e6023732691c08cf6060abff318b2331201b35..64903496aa9af1b256f0fcc062007f2cd8842472 100644 --- a/drivers/net/sfc/boards.c +++ b/drivers/net/sfc/boards.c @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2007 Solarflare Communications Inc. + * Copyright 2007-2008 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published @@ -11,6 +11,7 @@ #include "phy.h" #include "boards.h" #include "efx.h" +#include "workarounds.h" /* Macros for unpacking the board revision */ /* The revision info is in host byte order. */ @@ -51,10 +52,129 @@ static void board_blink(struct efx_nic *efx, bool blink) } } +/***************************************************************************** + * Support for LM87 sensor chip used on several boards + */ +#define LM87_REG_ALARMS1 0x41 +#define LM87_REG_ALARMS2 0x42 +#define LM87_IN_LIMITS(nr, _min, _max) \ + 0x2B + (nr) * 2, _max, 0x2C + (nr) * 2, _min +#define LM87_AIN_LIMITS(nr, _min, _max) \ + 0x3B + (nr), _max, 0x1A + (nr), _min +#define LM87_TEMP_INT_LIMITS(_min, _max) \ + 0x39, _max, 0x3A, _min +#define LM87_TEMP_EXT1_LIMITS(_min, _max) \ + 0x37, _max, 0x38, _min + +#define LM87_ALARM_TEMP_INT 0x10 +#define LM87_ALARM_TEMP_EXT1 0x20 + +#if defined(CONFIG_SENSORS_LM87) || defined(CONFIG_SENSORS_LM87_MODULE) + +static int efx_init_lm87(struct efx_nic *efx, struct i2c_board_info *info, + const u8 *reg_values) +{ + struct i2c_client *client = i2c_new_device(&efx->i2c_adap, info); + int rc; + + if (!client) + return -EIO; + + while (*reg_values) { + u8 reg = *reg_values++; + u8 value = *reg_values++; + rc = i2c_smbus_write_byte_data(client, reg, value); + if (rc) + goto err; + } + + efx->board_info.hwmon_client = client; + return 0; + +err: + i2c_unregister_device(client); + return rc; +} + +static void efx_fini_lm87(struct efx_nic *efx) +{ + i2c_unregister_device(efx->board_info.hwmon_client); +} + +static int efx_check_lm87(struct efx_nic *efx, unsigned mask) +{ + struct i2c_client *client = efx->board_info.hwmon_client; + s32 alarms1, alarms2; + + /* If link is up then do not monitor temperature */ + if (EFX_WORKAROUND_7884(efx) && efx->link_up) + return 0; + + alarms1 = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS1); + alarms2 = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS2); + if (alarms1 < 0) + return alarms1; + if (alarms2 < 0) + return alarms2; + alarms1 &= mask; + alarms2 &= mask >> 8; + if (alarms1 || alarms2) { + EFX_ERR(efx, + "LM87 detected a hardware failure (status %02x:%02x)" + "%s%s\n", + alarms1, alarms2, + (alarms1 & LM87_ALARM_TEMP_INT) ? " INTERNAL" : "", + (alarms1 & LM87_ALARM_TEMP_EXT1) ? " EXTERNAL" : ""); + return -ERANGE; + } + + return 0; +} + +#else /* !CONFIG_SENSORS_LM87 */ + +static inline int +efx_init_lm87(struct efx_nic *efx, struct i2c_board_info *info, + const u8 *reg_values) +{ + return 0; +} +static inline void efx_fini_lm87(struct efx_nic *efx) +{ +} +static inline int efx_check_lm87(struct efx_nic *efx, unsigned mask) +{ + return 0; +} + +#endif /* CONFIG_SENSORS_LM87 */ + /***************************************************************************** * Support for the SFE4002 * */ +static u8 sfe4002_lm87_channel = 0x03; /* use AIN not FAN inputs */ + +static const u8 sfe4002_lm87_regs[] = { + LM87_IN_LIMITS(0, 0x83, 0x91), /* 2.5V: 1.8V +/- 5% */ + LM87_IN_LIMITS(1, 0x51, 0x5a), /* Vccp1: 1.2V +/- 5% */ + LM87_IN_LIMITS(2, 0xb6, 0xca), /* 3.3V: 3.3V +/- 5% */ + LM87_IN_LIMITS(3, 0xb0, 0xc9), /* 5V: 4.6-5.2V */ + LM87_IN_LIMITS(4, 0xb0, 0xe0), /* 12V: 11-14V */ + LM87_IN_LIMITS(5, 0x44, 0x4b), /* Vccp2: 1.0V +/- 5% */ + LM87_AIN_LIMITS(0, 0xa0, 0xb2), /* AIN1: 1.66V +/- 5% */ + LM87_AIN_LIMITS(1, 0x91, 0xa1), /* AIN2: 1.5V +/- 5% */ + LM87_TEMP_INT_LIMITS(10, 60), /* board */ + LM87_TEMP_EXT1_LIMITS(10, 70), /* Falcon */ + 0 +}; + +static struct i2c_board_info sfe4002_hwmon_info = { + I2C_BOARD_INFO("lm87", 0x2e), + .platform_data = &sfe4002_lm87_channel, + .irq = -1, +}; + /****************************************************************************/ /* LED allocations. Note that on rev A0 boards the schematic and the reality * differ: red and green are swapped. Below is the fixed (A1) layout (there @@ -84,81 +204,67 @@ static void sfe4002_fault_led(struct efx_nic *efx, bool state) QUAKE_LED_OFF); } +static int sfe4002_check_hw(struct efx_nic *efx) +{ + /* A0 board rev. 4002s report a temperature fault the whole time + * (bad sensor) so we mask it out. */ + unsigned alarm_mask = + (efx->board_info.major == 0 && efx->board_info.minor == 0) ? + ~LM87_ALARM_TEMP_EXT1 : ~0; + + return efx_check_lm87(efx, alarm_mask); +} + static int sfe4002_init(struct efx_nic *efx) { + int rc = efx_init_lm87(efx, &sfe4002_hwmon_info, sfe4002_lm87_regs); + if (rc) + return rc; + efx->board_info.monitor = sfe4002_check_hw; efx->board_info.init_leds = sfe4002_init_leds; efx->board_info.set_fault_led = sfe4002_fault_led; efx->board_info.blink = board_blink; + efx->board_info.fini = efx_fini_lm87; return 0; } /* This will get expanded as board-specific details get moved out of the * PHY drivers. */ struct efx_board_data { + enum efx_board_type type; const char *ref_model; const char *gen_type; int (*init) (struct efx_nic *nic); }; -static int dummy_init(struct efx_nic *nic) -{ - return 0; -} static struct efx_board_data board_data[] = { - [EFX_BOARD_INVALID] = - {NULL, NULL, dummy_init}, - [EFX_BOARD_SFE4001] = - {"SFE4001", "10GBASE-T adapter", sfe4001_init}, - [EFX_BOARD_SFE4002] = - {"SFE4002", "XFP adapter", sfe4002_init}, + { EFX_BOARD_SFE4001, "SFE4001", "10GBASE-T adapter", sfe4001_init }, + { EFX_BOARD_SFE4002, "SFE4002", "XFP adapter", sfe4002_init }, + { EFX_BOARD_SFN4111T, "SFN4111T", "100/1000/10GBASE-T adapter", + sfn4111t_init }, }; -int efx_set_board_info(struct efx_nic *efx, u16 revision_info) +void efx_set_board_info(struct efx_nic *efx, u16 revision_info) { - int rc = 0; - struct efx_board_data *data; - - if (BOARD_TYPE(revision_info) >= EFX_BOARD_MAX) { - EFX_ERR(efx, "squashing unknown board type %d\n", - BOARD_TYPE(revision_info)); - revision_info = 0; - } + struct efx_board_data *data = NULL; + int i; - if (BOARD_TYPE(revision_info) == 0) { - efx->board_info.major = 0; - efx->board_info.minor = 0; - /* For early boards that don't have revision info. there is - * only 1 board for each PHY type, so we can work it out, with - * the exception of the PHY-less boards. */ - switch (efx->phy_type) { - case PHY_TYPE_10XPRESS: - efx->board_info.type = EFX_BOARD_SFE4001; - break; - case PHY_TYPE_XFP: - efx->board_info.type = EFX_BOARD_SFE4002; - break; - default: - efx->board_info.type = 0; - break; - } - } else { - efx->board_info.type = BOARD_TYPE(revision_info); - efx->board_info.major = BOARD_MAJOR(revision_info); - efx->board_info.minor = BOARD_MINOR(revision_info); - } + efx->board_info.type = BOARD_TYPE(revision_info); + efx->board_info.major = BOARD_MAJOR(revision_info); + efx->board_info.minor = BOARD_MINOR(revision_info); - data = &board_data[efx->board_info.type]; + for (i = 0; i < ARRAY_SIZE(board_data); i++) + if (board_data[i].type == efx->board_info.type) + data = &board_data[i]; - /* Report the board model number or generic type for recognisable - * boards. */ - if (efx->board_info.type != 0) + if (data) { EFX_INFO(efx, "board is %s rev %c%d\n", (efx->pci_dev->subsystem_vendor == EFX_VENDID_SFC) ? data->ref_model : data->gen_type, 'A' + efx->board_info.major, efx->board_info.minor); - - efx->board_info.init = data->init; - - return rc; + efx->board_info.init = data->init; + } else { + EFX_ERR(efx, "unknown board type %d\n", efx->board_info.type); + } } diff --git a/drivers/net/sfc/boards.h b/drivers/net/sfc/boards.h index c6e01b64bfb471ff57ce99cc33c0ef3622771d7f..d93c6c6a754864bfef4b80326b6086a8947fe350 100644 --- a/drivers/net/sfc/boards.h +++ b/drivers/net/sfc/boards.h @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2007 Solarflare Communications Inc. + * Copyright 2007-2008 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published @@ -12,14 +12,16 @@ /* Board IDs (must fit in 8 bits) */ enum efx_board_type { - EFX_BOARD_INVALID = 0, - EFX_BOARD_SFE4001 = 1, /* SFE4001 (10GBASE-T) */ + EFX_BOARD_SFE4001 = 1, EFX_BOARD_SFE4002 = 2, - /* Insert new types before here */ - EFX_BOARD_MAX + EFX_BOARD_SFN4111T = 0x51, }; -extern int efx_set_board_info(struct efx_nic *efx, u16 revision_info); +extern void efx_set_board_info(struct efx_nic *efx, u16 revision_info); + +/* SFE4001 (10GBASE-T) */ extern int sfe4001_init(struct efx_nic *efx); +/* SFN4111T (100/1000/10GBASE-T) */ +extern int sfn4111t_init(struct efx_nic *efx); #endif diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 06ea71c7e34ecb58bd117781eab7c09360381294..7673fd92eaf5f15f413ecd50d56f914d5de078c7 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -21,14 +21,12 @@ #include #include #include "net_driver.h" -#include "gmii.h" #include "ethtool.h" #include "tx.h" #include "rx.h" #include "efx.h" #include "mdio_10g.h" #include "falcon.h" -#include "mac.h" #define EFX_MAX_MTU (9 * 1024) @@ -39,6 +37,12 @@ */ static struct workqueue_struct *refill_workqueue; +/* Reset workqueue. If any NIC has a hardware failure then a reset will be + * queued onto this work queue. This is not a per-nic work queue, because + * efx_reset_work() acquires the rtnl lock, so resets are naturally serialised. + */ +static struct workqueue_struct *reset_workqueue; + /************************************************************************** * * Configurable values @@ -58,13 +62,15 @@ MODULE_PARM_DESC(lro, "Large receive offload acceleration"); /* * Use separate channels for TX and RX events * - * Set this to 1 to use separate channels for TX and RX. It allows us to - * apply a higher level of interrupt moderation to TX events. + * Set this to 1 to use separate channels for TX and RX. It allows us + * to control interrupt affinity separately for TX and RX. * - * This is forced to 0 for MSI interrupt mode as the interrupt vector - * is not written + * This is only used in MSI-X interrupt mode */ -static unsigned int separate_tx_and_rx_channels = true; +static unsigned int separate_tx_channels; +module_param(separate_tx_channels, uint, 0644); +MODULE_PARM_DESC(separate_tx_channels, + "Use separate channels for TX and RX"); /* This is the weight assigned to each of the (per-channel) virtual * NAPI devices. @@ -77,11 +83,6 @@ static int napi_weight = 64; */ unsigned int efx_monitor_interval = 1 * HZ; -/* This controls whether or not the hardware monitor will trigger a - * reset when it detects an error condition. - */ -static unsigned int monitor_reset = true; - /* This controls whether or not the driver will initialise devices * with invalid MAC addresses stored in the EEPROM or flash. If true, * such devices will be initialised with a random locally-generated @@ -128,6 +129,10 @@ static unsigned int rss_cpus; module_param(rss_cpus, uint, 0444); MODULE_PARM_DESC(rss_cpus, "Number of CPUs to use for Receive-Side Scaling"); +static int phy_flash_cfg; +module_param(phy_flash_cfg, int, 0644); +MODULE_PARM_DESC(phy_flash_cfg, "Set PHYs into reflash mode initially"); + /************************************************************************** * * Utility functions and prototypes @@ -211,7 +216,6 @@ static int efx_poll(struct napi_struct *napi, int budget) { struct efx_channel *channel = container_of(napi, struct efx_channel, napi_str); - struct net_device *napi_dev = channel->napi_dev; int rx_packets; EFX_TRACE(channel->efx, "channel %d NAPI poll executing on CPU %d\n", @@ -225,7 +229,7 @@ static int efx_poll(struct napi_struct *napi, int budget) * since efx_channel_processed() will have no effect if * interrupts have already been disabled. */ - netif_rx_complete(napi_dev, napi); + netif_rx_complete(napi); efx_channel_processed(channel); } @@ -349,6 +353,27 @@ static int efx_probe_channel(struct efx_channel *channel) } +static void efx_set_channel_names(struct efx_nic *efx) +{ + struct efx_channel *channel; + const char *type = ""; + int number; + + efx_for_each_channel(channel, efx) { + number = channel->channel; + if (efx->n_channels > efx->n_rx_queues) { + if (channel->channel < efx->n_rx_queues) { + type = "-rx"; + } else { + type = "-tx"; + number -= efx->n_rx_queues; + } + } + snprintf(channel->name, sizeof(channel->name), + "%s%s-%d", efx->name, type, number); + } +} + /* Channels are shutdown and reinitialised whilst the NIC is running * to propagate configuration changes (mtu, checksum offload), or * to clear hardware error conditions @@ -523,26 +548,8 @@ static void efx_link_status_changed(struct efx_nic *efx) /* Status message for kernel log */ if (efx->link_up) { - struct mii_if_info *gmii = &efx->mii; - unsigned adv, lpa; - /* NONE here means direct XAUI from the controller, with no - * MDIO-attached device we can query. */ - if (efx->phy_type != PHY_TYPE_NONE) { - adv = gmii_advertised(gmii); - lpa = gmii_lpa(gmii); - } else { - lpa = GM_LPA_10000 | LPA_DUPLEX; - adv = lpa; - } - EFX_INFO(efx, "link up at %dMbps %s-duplex " - "(adv %04x lpa %04x) (MTU %d)%s\n", - (efx->link_options & GM_LPA_10000 ? 10000 : - (efx->link_options & GM_LPA_1000 ? 1000 : - (efx->link_options & GM_LPA_100 ? 100 : - 10))), - (efx->link_options & GM_LPA_DUPLEX ? - "full" : "half"), - adv, lpa, + EFX_INFO(efx, "link up at %uMbps %s-duplex (MTU %d)%s\n", + efx->link_speed, efx->link_fd ? "full" : "half", efx->net_dev->mtu, (efx->promiscuous ? " [PROMISC]" : "")); } else { @@ -566,10 +573,28 @@ void __efx_reconfigure_port(struct efx_nic *efx) netif_addr_unlock_bh(efx->net_dev); } - falcon_reconfigure_xmac(efx); + falcon_deconfigure_mac_wrapper(efx); + + /* Reconfigure the PHY, disabling transmit in mac level loopback. */ + if (LOOPBACK_INTERNAL(efx)) + efx->phy_mode |= PHY_MODE_TX_DISABLED; + else + efx->phy_mode &= ~PHY_MODE_TX_DISABLED; + efx->phy_op->reconfigure(efx); + + if (falcon_switch_mac(efx)) + goto fail; + + efx->mac_op->reconfigure(efx); /* Inform kernel of loss/gain of carrier */ efx_link_status_changed(efx); + return; + +fail: + EFX_ERR(efx, "failed to reconfigure MAC\n"); + efx->phy_op->fini(efx); + efx->port_initialized = false; } /* Reinitialise the MAC to pick up new PHY settings, even if the port is @@ -586,10 +611,9 @@ void efx_reconfigure_port(struct efx_nic *efx) /* Asynchronous efx_reconfigure_port work item. To speed up efx_flush_all() * we don't efx_reconfigure_port() if the port is disabled. Care is taken * in efx_stop_all() and efx_start_port() to prevent PHY events being lost */ -static void efx_reconfigure_work(struct work_struct *data) +static void efx_phy_work(struct work_struct *data) { - struct efx_nic *efx = container_of(data, struct efx_nic, - reconfigure_work); + struct efx_nic *efx = container_of(data, struct efx_nic, phy_work); mutex_lock(&efx->mac_lock); if (efx->port_enabled) @@ -597,6 +621,16 @@ static void efx_reconfigure_work(struct work_struct *data) mutex_unlock(&efx->mac_lock); } +static void efx_mac_work(struct work_struct *data) +{ + struct efx_nic *efx = container_of(data, struct efx_nic, mac_work); + + mutex_lock(&efx->mac_lock); + if (efx->port_enabled) + efx->mac_op->irq(efx); + mutex_unlock(&efx->mac_lock); +} + static int efx_probe_port(struct efx_nic *efx) { int rc; @@ -608,21 +642,22 @@ static int efx_probe_port(struct efx_nic *efx) if (rc) goto err; + if (phy_flash_cfg) + efx->phy_mode = PHY_MODE_SPECIAL; + /* Sanity check MAC address */ if (is_valid_ether_addr(efx->mac_address)) { memcpy(efx->net_dev->dev_addr, efx->mac_address, ETH_ALEN); } else { - DECLARE_MAC_BUF(mac); - - EFX_ERR(efx, "invalid MAC address %s\n", - print_mac(mac, efx->mac_address)); + EFX_ERR(efx, "invalid MAC address %pM\n", + efx->mac_address); if (!allow_bad_hwaddr) { rc = -EINVAL; goto err; } random_ether_addr(efx->net_dev->dev_addr); - EFX_INFO(efx, "using locally-generated MAC %s\n", - print_mac(mac, efx->net_dev->dev_addr)); + EFX_INFO(efx, "using locally-generated MAC %pM\n", + efx->net_dev->dev_addr); } return 0; @@ -638,23 +673,30 @@ static int efx_init_port(struct efx_nic *efx) EFX_LOG(efx, "init port\n"); - /* Initialise the MAC and PHY */ - rc = falcon_init_xmac(efx); + rc = efx->phy_op->init(efx); if (rc) return rc; + efx->phy_op->reconfigure(efx); + + mutex_lock(&efx->mac_lock); + rc = falcon_switch_mac(efx); + mutex_unlock(&efx->mac_lock); + if (rc) + goto fail; + efx->mac_op->reconfigure(efx); efx->port_initialized = true; efx->stats_enabled = true; - - /* Reconfigure port to program MAC registers */ - falcon_reconfigure_xmac(efx); - return 0; + +fail: + efx->phy_op->fini(efx); + return rc; } /* Allow efx_reconfigure_port() to be scheduled, and close the window * between efx_stop_port and efx_flush_all whereby a previously scheduled - * efx_reconfigure_port() may have been cancelled */ + * efx_phy_work()/efx_mac_work() may have been cancelled */ static void efx_start_port(struct efx_nic *efx) { EFX_LOG(efx, "start port\n"); @@ -663,13 +705,14 @@ static void efx_start_port(struct efx_nic *efx) mutex_lock(&efx->mac_lock); efx->port_enabled = true; __efx_reconfigure_port(efx); + efx->mac_op->irq(efx); mutex_unlock(&efx->mac_lock); } -/* Prevent efx_reconfigure_work and efx_monitor() from executing, and - * efx_set_multicast_list() from scheduling efx_reconfigure_work. - * efx_reconfigure_work can still be scheduled via NAPI processing - * until efx_flush_all() is called */ +/* Prevent efx_phy_work, efx_mac_work, and efx_monitor() from executing, + * and efx_set_multicast_list() from scheduling efx_phy_work. efx_phy_work + * and efx_mac_work may still be scheduled via NAPI processing until + * efx_flush_all() is called */ static void efx_stop_port(struct efx_nic *efx) { EFX_LOG(efx, "stop port\n"); @@ -692,7 +735,7 @@ static void efx_fini_port(struct efx_nic *efx) if (!efx->port_initialized) return; - falcon_fini_xmac(efx); + efx->phy_op->fini(efx); efx->port_initialized = false; efx->link_up = false; @@ -840,26 +883,33 @@ static void efx_probe_interrupts(struct efx_nic *efx) if (efx->interrupt_mode == EFX_INT_MODE_MSIX) { struct msix_entry xentries[EFX_MAX_CHANNELS]; int wanted_ints; + int rx_queues; /* We want one RX queue and interrupt per CPU package * (or as specified by the rss_cpus module parameter). * We will need one channel per interrupt. */ - wanted_ints = rss_cpus ? rss_cpus : efx_wanted_rx_queues(); - efx->n_rx_queues = min(wanted_ints, max_channels); + rx_queues = rss_cpus ? rss_cpus : efx_wanted_rx_queues(); + wanted_ints = rx_queues + (separate_tx_channels ? 1 : 0); + wanted_ints = min(wanted_ints, max_channels); - for (i = 0; i < efx->n_rx_queues; i++) + for (i = 0; i < wanted_ints; i++) xentries[i].entry = i; - rc = pci_enable_msix(efx->pci_dev, xentries, efx->n_rx_queues); + rc = pci_enable_msix(efx->pci_dev, xentries, wanted_ints); if (rc > 0) { - EFX_BUG_ON_PARANOID(rc >= efx->n_rx_queues); - efx->n_rx_queues = rc; + EFX_ERR(efx, "WARNING: Insufficient MSI-X vectors" + " available (%d < %d).\n", rc, wanted_ints); + EFX_ERR(efx, "WARNING: Performance may be reduced.\n"); + EFX_BUG_ON_PARANOID(rc >= wanted_ints); + wanted_ints = rc; rc = pci_enable_msix(efx->pci_dev, xentries, - efx->n_rx_queues); + wanted_ints); } if (rc == 0) { - for (i = 0; i < efx->n_rx_queues; i++) + efx->n_rx_queues = min(rx_queues, wanted_ints); + efx->n_channels = wanted_ints; + for (i = 0; i < wanted_ints; i++) efx->channel[i].irq = xentries[i].vector; } else { /* Fall back to single channel MSI */ @@ -871,6 +921,7 @@ static void efx_probe_interrupts(struct efx_nic *efx) /* Try single interrupt MSI */ if (efx->interrupt_mode == EFX_INT_MODE_MSI) { efx->n_rx_queues = 1; + efx->n_channels = 1; rc = pci_enable_msi(efx->pci_dev); if (rc == 0) { efx->channel[0].irq = efx->pci_dev->irq; @@ -883,6 +934,7 @@ static void efx_probe_interrupts(struct efx_nic *efx) /* Assume legacy interrupts */ if (efx->interrupt_mode == EFX_INT_MODE_LEGACY) { efx->n_rx_queues = 1; + efx->n_channels = 1 + (separate_tx_channels ? 1 : 0); efx->legacy_irq = efx->pci_dev->irq; } } @@ -907,8 +959,8 @@ static void efx_set_channels(struct efx_nic *efx) struct efx_rx_queue *rx_queue; efx_for_each_tx_queue(tx_queue, efx) { - if (!EFX_INT_MODE_USE_MSI(efx) && separate_tx_and_rx_channels) - tx_queue->channel = &efx->channel[1]; + if (separate_tx_channels) + tx_queue->channel = &efx->channel[efx->n_channels-1]; else tx_queue->channel = &efx->channel[0]; tx_queue->channel->used_flags |= EFX_USED_BY_TX; @@ -985,6 +1037,7 @@ static int efx_probe_all(struct efx_nic *efx) goto fail3; } } + efx_set_channel_names(efx); return 0; @@ -1050,7 +1103,8 @@ static void efx_flush_all(struct efx_nic *efx) cancel_delayed_work_sync(&rx_queue->work); /* Stop scheduled port reconfigurations */ - cancel_work_sync(&efx->reconfigure_work); + cancel_work_sync(&efx->mac_work); + cancel_work_sync(&efx->phy_work); } @@ -1087,7 +1141,7 @@ static void efx_stop_all(struct efx_nic *efx) * window to loose phy events */ efx_stop_port(efx); - /* Flush reconfigure_work, refill_workqueue, monitor_work */ + /* Flush efx_phy_work, efx_mac_work, refill_workqueue, monitor_work */ efx_flush_all(efx); /* Isolate the MAC from the TX and RX engines, so that queue @@ -1159,36 +1213,31 @@ static void efx_monitor(struct work_struct *data) { struct efx_nic *efx = container_of(data, struct efx_nic, monitor_work.work); - int rc = 0; + int rc; EFX_TRACE(efx, "hardware monitor executing on CPU %d\n", raw_smp_processor_id()); - /* If the mac_lock is already held then it is likely a port * reconfiguration is already in place, which will likely do * most of the work of check_hw() anyway. */ - if (!mutex_trylock(&efx->mac_lock)) { - queue_delayed_work(efx->workqueue, &efx->monitor_work, - efx_monitor_interval); - return; - } - - if (efx->port_enabled) - rc = falcon_check_xmac(efx); - mutex_unlock(&efx->mac_lock); - + if (!mutex_trylock(&efx->mac_lock)) + goto out_requeue; + if (!efx->port_enabled) + goto out_unlock; + rc = efx->board_info.monitor(efx); if (rc) { - if (monitor_reset) { - EFX_ERR(efx, "hardware monitor detected a fault: " - "triggering reset\n"); - efx_schedule_reset(efx, RESET_TYPE_MONITOR); - } else { - EFX_ERR(efx, "hardware monitor detected a fault, " - "skipping reset\n"); - } + EFX_ERR(efx, "Board sensor %s; shutting down PHY\n", + (rc == -ERANGE) ? "reported fault" : "failed"); + efx->phy_mode |= PHY_MODE_LOW_POWER; + falcon_sim_phy_event(efx); } + efx->phy_op->poll(efx); + efx->mac_op->poll(efx); +out_unlock: + mutex_unlock(&efx->mac_lock); +out_requeue: queue_delayed_work(efx->workqueue, &efx->monitor_work, efx_monitor_interval); } @@ -1282,6 +1331,8 @@ static int efx_net_open(struct net_device *net_dev) EFX_LOG(efx, "opening device %s on CPU %d\n", net_dev->name, raw_smp_processor_id()); + if (efx->state == STATE_DISABLED) + return -EIO; if (efx->phy_mode & PHY_MODE_SPECIAL) return -EBUSY; @@ -1300,10 +1351,12 @@ static int efx_net_stop(struct net_device *net_dev) EFX_LOG(efx, "closing %s on CPU %d\n", net_dev->name, raw_smp_processor_id()); - /* Stop the device and flush all the channels */ - efx_stop_all(efx); - efx_fini_channels(efx); - efx_init_channels(efx); + if (efx->state != STATE_DISABLED) { + /* Stop the device and flush all the channels */ + efx_stop_all(efx); + efx_fini_channels(efx); + efx_init_channels(efx); + } return 0; } @@ -1322,7 +1375,7 @@ static struct net_device_stats *efx_net_stats(struct net_device *net_dev) if (!spin_trylock(&efx->stats_lock)) return stats; if (efx->stats_enabled) { - falcon_update_stats_xmac(efx); + efx->mac_op->update_stats(efx); falcon_update_nic_stats(efx); } spin_unlock(&efx->stats_lock); @@ -1360,12 +1413,11 @@ static void efx_watchdog(struct net_device *net_dev) { struct efx_nic *efx = netdev_priv(net_dev); - EFX_ERR(efx, "TX stuck with stop_count=%d port_enabled=%d: %s\n", - atomic_read(&efx->netif_stop_count), efx->port_enabled, - monitor_reset ? "resetting channels" : "skipping reset"); + EFX_ERR(efx, "TX stuck with stop_count=%d port_enabled=%d:" + " resetting channels\n", + atomic_read(&efx->netif_stop_count), efx->port_enabled); - if (monitor_reset) - efx_schedule_reset(efx, RESET_TYPE_MONITOR); + efx_schedule_reset(efx, RESET_TYPE_TX_WATCHDOG); } @@ -1401,9 +1453,8 @@ static int efx_set_mac_address(struct net_device *net_dev, void *data) EFX_ASSERT_RESET_SERIALISED(efx); if (!is_valid_ether_addr(new_addr)) { - DECLARE_MAC_BUF(mac); - EFX_ERR(efx, "invalid ethernet MAC address requested: %s\n", - print_mac(mac, new_addr)); + EFX_ERR(efx, "invalid ethernet MAC address requested: %pM\n", + new_addr); return -EINVAL; } @@ -1447,22 +1498,43 @@ static void efx_set_multicast_list(struct net_device *net_dev) return; if (changed) - queue_work(efx->workqueue, &efx->reconfigure_work); + queue_work(efx->workqueue, &efx->phy_work); /* Create and activate new global multicast hash table */ falcon_set_multicast_hash(efx); } +static const struct net_device_ops efx_netdev_ops = { + .ndo_open = efx_net_open, + .ndo_stop = efx_net_stop, + .ndo_get_stats = efx_net_stats, + .ndo_tx_timeout = efx_watchdog, + .ndo_start_xmit = efx_hard_start_xmit, + .ndo_validate_addr = eth_validate_addr, + .ndo_do_ioctl = efx_ioctl, + .ndo_change_mtu = efx_change_mtu, + .ndo_set_mac_address = efx_set_mac_address, + .ndo_set_multicast_list = efx_set_multicast_list, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = efx_netpoll, +#endif +}; + +static void efx_update_name(struct efx_nic *efx) +{ + strcpy(efx->name, efx->net_dev->name); + efx_mtd_rename(efx); + efx_set_channel_names(efx); +} + static int efx_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) { struct net_device *net_dev = ptr; - if (net_dev->open == efx_net_open && event == NETDEV_CHANGENAME) { - struct efx_nic *efx = netdev_priv(net_dev); - - strcpy(efx->name, net_dev->name); - } + if (net_dev->netdev_ops == &efx_netdev_ops && + event == NETDEV_CHANGENAME) + efx_update_name(netdev_priv(net_dev)); return NOTIFY_DONE; } @@ -1471,6 +1543,14 @@ static struct notifier_block efx_netdev_notifier = { .notifier_call = efx_netdev_event, }; +static ssize_t +show_phy_type(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); + return sprintf(buf, "%d\n", efx->phy_type); +} +static DEVICE_ATTR(phy_type, 0644, show_phy_type, NULL); + static int efx_register_netdev(struct efx_nic *efx) { struct net_device *net_dev = efx->net_dev; @@ -1478,18 +1558,7 @@ static int efx_register_netdev(struct efx_nic *efx) net_dev->watchdog_timeo = 5 * HZ; net_dev->irq = efx->pci_dev->irq; - net_dev->open = efx_net_open; - net_dev->stop = efx_net_stop; - net_dev->get_stats = efx_net_stats; - net_dev->tx_timeout = &efx_watchdog; - net_dev->hard_start_xmit = efx_hard_start_xmit; - net_dev->do_ioctl = efx_ioctl; - net_dev->change_mtu = efx_change_mtu; - net_dev->set_mac_address = efx_set_mac_address; - net_dev->set_multicast_list = efx_set_multicast_list; -#ifdef CONFIG_NET_POLL_CONTROLLER - net_dev->poll_controller = efx_netpoll; -#endif + net_dev->netdev_ops = &efx_netdev_ops; SET_NETDEV_DEV(net_dev, &efx->pci_dev->dev); SET_ETHTOOL_OPS(net_dev, &efx_ethtool_ops); @@ -1497,7 +1566,7 @@ static int efx_register_netdev(struct efx_nic *efx) netif_carrier_off(efx->net_dev); /* Clear MAC statistics */ - falcon_update_stats_xmac(efx); + efx->mac_op->update_stats(efx); memset(&efx->mac_stats, 0, sizeof(efx->mac_stats)); rc = register_netdev(net_dev); @@ -1505,9 +1574,22 @@ static int efx_register_netdev(struct efx_nic *efx) EFX_ERR(efx, "could not register net dev\n"); return rc; } - strcpy(efx->name, net_dev->name); + + rtnl_lock(); + efx_update_name(efx); + rtnl_unlock(); + + rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_type); + if (rc) { + EFX_ERR(efx, "failed to init net dev attributes\n"); + goto fail_registered; + } return 0; + +fail_registered: + unregister_netdev(net_dev); + return rc; } static void efx_unregister_netdev(struct efx_nic *efx) @@ -1527,6 +1609,7 @@ static void efx_unregister_netdev(struct efx_nic *efx) if (efx_dev_registered(efx)) { strlcpy(efx->name, pci_name(efx->pci_dev), sizeof(efx->name)); + device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_type); unregister_netdev(efx->net_dev); } } @@ -1541,8 +1624,6 @@ static void efx_unregister_netdev(struct efx_nic *efx) * before reset. */ void efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd) { - int rc; - EFX_ASSERT_RESET_SERIALISED(efx); /* The net_dev->get_stats handler is quite slow, and will fail @@ -1553,10 +1634,9 @@ void efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd) efx_stop_all(efx); mutex_lock(&efx->mac_lock); + mutex_lock(&efx->spi_lock); - rc = falcon_xmac_get_settings(efx, ecmd); - if (rc) - EFX_ERR(efx, "could not back up PHY settings\n"); + efx->phy_op->get_settings(efx, ecmd); efx_fini_channels(efx); } @@ -1581,10 +1661,11 @@ int efx_reset_up(struct efx_nic *efx, struct ethtool_cmd *ecmd, bool ok) if (ok) { efx_init_channels(efx); - if (falcon_xmac_set_settings(efx, ecmd)) + if (efx->phy_op->set_settings(efx, ecmd)) EFX_ERR(efx, "could not restore PHY settings\n"); } + mutex_unlock(&efx->spi_lock); mutex_unlock(&efx->mac_lock); if (ok) { @@ -1607,7 +1688,7 @@ static int efx_reset(struct efx_nic *efx) { struct ethtool_cmd ecmd; enum reset_type method = efx->reset_pending; - int rc; + int rc = 0; /* Serialise with kernel interfaces */ rtnl_lock(); @@ -1616,7 +1697,7 @@ static int efx_reset(struct efx_nic *efx) * flag set so that efx_pci_probe_main will be retried */ if (efx->state != STATE_RUNNING) { EFX_INFO(efx, "scheduled reset quenched. NIC not RUNNING\n"); - goto unlock_rtnl; + goto out_unlock; } EFX_INFO(efx, "resetting (%d)\n", method); @@ -1626,7 +1707,7 @@ static int efx_reset(struct efx_nic *efx) rc = falcon_reset_hw(efx, method); if (rc) { EFX_ERR(efx, "failed to reset hardware\n"); - goto fail; + goto out_disable; } /* Allow resets to be rescheduled. */ @@ -1640,28 +1721,23 @@ static int efx_reset(struct efx_nic *efx) /* Leave device stopped if necessary */ if (method == RESET_TYPE_DISABLE) { + efx_reset_up(efx, &ecmd, false); rc = -EIO; - goto fail; + } else { + rc = efx_reset_up(efx, &ecmd, true); } - rc = efx_reset_up(efx, &ecmd, true); - if (rc) - goto disable; - - EFX_LOG(efx, "reset complete\n"); - unlock_rtnl: - rtnl_unlock(); - return 0; - - fail: - efx_reset_up(efx, &ecmd, false); - disable: - EFX_ERR(efx, "has been disabled\n"); - efx->state = STATE_DISABLED; +out_disable: + if (rc) { + EFX_ERR(efx, "has been disabled\n"); + efx->state = STATE_DISABLED; + dev_close(efx->net_dev); + } else { + EFX_LOG(efx, "reset complete\n"); + } +out_unlock: rtnl_unlock(); - efx_unregister_netdev(efx); - efx_fini_port(efx); return rc; } @@ -1709,7 +1785,7 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type) efx->reset_pending = method; - queue_work(efx->reset_workqueue, &efx->reset_work); + queue_work(reset_workqueue, &efx->reset_work); } /************************************************************************** @@ -1743,10 +1819,16 @@ int efx_port_dummy_op_int(struct efx_nic *efx) void efx_port_dummy_op_void(struct efx_nic *efx) {} void efx_port_dummy_op_blink(struct efx_nic *efx, bool blink) {} +static struct efx_mac_operations efx_dummy_mac_operations = { + .reconfigure = efx_port_dummy_op_void, + .poll = efx_port_dummy_op_void, + .irq = efx_port_dummy_op_void, +}; + static struct efx_phy_operations efx_dummy_phy_operations = { .init = efx_port_dummy_op_int, .reconfigure = efx_port_dummy_op_void, - .check_hw = efx_port_dummy_op_int, + .poll = efx_port_dummy_op_void, .fini = efx_port_dummy_op_void, .clear_interrupt = efx_port_dummy_op_void, }; @@ -1755,6 +1837,7 @@ static struct efx_board efx_dummy_board_info = { .init = efx_port_dummy_op_int, .init_leds = efx_port_dummy_op_int, .set_fault_led = efx_port_dummy_op_blink, + .monitor = efx_port_dummy_op_int, .blink = efx_port_dummy_op_blink, .fini = efx_port_dummy_op_void, }; @@ -1774,12 +1857,13 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, struct efx_channel *channel; struct efx_tx_queue *tx_queue; struct efx_rx_queue *rx_queue; - int i, rc; + int i; /* Initialise common structures */ memset(efx, 0, sizeof(*efx)); spin_lock_init(&efx->biu_lock); spin_lock_init(&efx->phy_lock); + mutex_init(&efx->spi_lock); INIT_WORK(&efx->reset_work, efx_reset_work); INIT_DELAYED_WORK(&efx->monitor_work, efx_monitor); efx->pci_dev = pci_dev; @@ -1793,9 +1877,11 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, spin_lock_init(&efx->netif_stop_lock); spin_lock_init(&efx->stats_lock); mutex_init(&efx->mac_lock); + efx->mac_op = &efx_dummy_mac_operations; efx->phy_op = &efx_dummy_phy_operations; efx->mii.dev = net_dev; - INIT_WORK(&efx->reconfigure_work, efx_reconfigure_work); + INIT_WORK(&efx->phy_work, efx_phy_work); + INIT_WORK(&efx->mac_work, efx_mac_work); atomic_set(&efx->netif_stop_count, 1); for (i = 0; i < EFX_MAX_CHANNELS; i++) { @@ -1841,34 +1927,18 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, efx->interrupt_mode = max(efx->type->max_interrupt_mode, interrupt_mode); - efx->workqueue = create_singlethread_workqueue("sfc_work"); - if (!efx->workqueue) { - rc = -ENOMEM; - goto fail1; - } - - efx->reset_workqueue = create_singlethread_workqueue("sfc_reset"); - if (!efx->reset_workqueue) { - rc = -ENOMEM; - goto fail2; - } + /* Would be good to use the net_dev name, but we're too early */ + snprintf(efx->workqueue_name, sizeof(efx->workqueue_name), "sfc%s", + pci_name(pci_dev)); + efx->workqueue = create_singlethread_workqueue(efx->workqueue_name); + if (!efx->workqueue) + return -ENOMEM; return 0; - - fail2: - destroy_workqueue(efx->workqueue); - efx->workqueue = NULL; - - fail1: - return rc; } static void efx_fini_struct(struct efx_nic *efx) { - if (efx->reset_workqueue) { - destroy_workqueue(efx->reset_workqueue); - efx->reset_workqueue = NULL; - } if (efx->workqueue) { destroy_workqueue(efx->workqueue); efx->workqueue = NULL; @@ -1927,11 +1997,13 @@ static void efx_pci_remove(struct pci_dev *pci_dev) efx_unregister_netdev(efx); + efx_mtd_remove(efx); + /* Wait for any scheduled resets to complete. No more will be * scheduled from this point because efx_stop_all() has been * called, we are no longer registered with driverlink, and * the net_device's have been removed. */ - flush_workqueue(efx->reset_workqueue); + cancel_work_sync(&efx->reset_work); efx_pci_remove_main(efx); @@ -1992,6 +2064,7 @@ static int efx_pci_probe_main(struct efx_nic *efx) efx_fini_port(efx); fail5: fail4: + efx->board_info.fini(efx); fail3: efx_fini_napi(efx); fail2: @@ -2045,14 +2118,23 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev, * we're in STATE_INIT. */ for (i = 0; i < 5; i++) { rc = efx_pci_probe_main(efx); - if (rc == 0) - break; /* Serialise against efx_reset(). No more resets will be * scheduled since efx_stop_all() has been called, and we * have not and never have been registered with either * the rtnetlink or driverlink layers. */ - flush_workqueue(efx->reset_workqueue); + cancel_work_sync(&efx->reset_work); + + if (rc == 0) { + if (efx->reset_pending != RESET_TYPE_NONE) { + /* If there was a scheduled reset during + * probe, the NIC is probably hosed anyway */ + efx_pci_remove_main(efx); + rc = -EIO; + } else { + break; + } + } /* Retry if a recoverably reset event has been scheduled */ if ((efx->reset_pending != RESET_TYPE_INVISIBLE) && @@ -2070,16 +2152,15 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev, /* Switch to the running state before we expose the device to * the OS. This is to ensure that the initial gathering of * MAC stats succeeds. */ - rtnl_lock(); efx->state = STATE_RUNNING; - rtnl_unlock(); + + efx_mtd_probe(efx); /* allowed to fail */ rc = efx_register_netdev(efx); if (rc) goto fail5; EFX_LOG(efx, "initialisation successful\n"); - return 0; fail5: @@ -2127,6 +2208,11 @@ static int __init efx_init_module(void) rc = -ENOMEM; goto err_refill; } + reset_workqueue = create_singlethread_workqueue("sfc_reset"); + if (!reset_workqueue) { + rc = -ENOMEM; + goto err_reset; + } rc = pci_register_driver(&efx_pci_driver); if (rc < 0) @@ -2135,6 +2221,8 @@ static int __init efx_init_module(void) return 0; err_pci: + destroy_workqueue(reset_workqueue); + err_reset: destroy_workqueue(refill_workqueue); err_refill: unregister_netdevice_notifier(&efx_netdev_notifier); @@ -2147,6 +2235,7 @@ static void __exit efx_exit_module(void) printk(KERN_INFO "Solarflare NET driver unloading\n"); pci_unregister_driver(&efx_pci_driver); + destroy_workqueue(reset_workqueue); destroy_workqueue(refill_workqueue); unregister_netdevice_notifier(&efx_netdev_notifier); diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h index d02937b70eeefc504e49e2cdff620c3fa656df58..0dd7a532c78a4b06a5c92209d763313570983556 100644 --- a/drivers/net/sfc/efx.h +++ b/drivers/net/sfc/efx.h @@ -58,6 +58,16 @@ extern int efx_port_dummy_op_int(struct efx_nic *efx); extern void efx_port_dummy_op_void(struct efx_nic *efx); extern void efx_port_dummy_op_blink(struct efx_nic *efx, bool blink); +/* MTD */ +#ifdef CONFIG_SFC_MTD +extern int efx_mtd_probe(struct efx_nic *efx); +extern void efx_mtd_rename(struct efx_nic *efx); +extern void efx_mtd_remove(struct efx_nic *efx); +#else +static inline int efx_mtd_probe(struct efx_nic *efx) { return 0; } +static inline void efx_mtd_rename(struct efx_nic *efx) {} +static inline void efx_mtd_remove(struct efx_nic *efx) {} +#endif extern unsigned int efx_monitor_interval; @@ -67,7 +77,7 @@ static inline void efx_schedule_channel(struct efx_channel *channel) channel->channel, raw_smp_processor_id()); channel->work_pending = true; - netif_rx_schedule(channel->napi_dev, &channel->napi_str); + netif_rx_schedule(&channel->napi_str); } #endif /* EFX_EFX_H */ diff --git a/drivers/net/sfc/enum.h b/drivers/net/sfc/enum.h index cec15dbb88e474b4705d0141e6b264d2c79ec606..60cbc6e1e66b1e001b30bab735644794f3d8dce8 100644 --- a/drivers/net/sfc/enum.h +++ b/drivers/net/sfc/enum.h @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2007 Solarflare Communications Inc. + * Copyright 2007-2008 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published @@ -13,22 +13,24 @@ /** * enum efx_loopback_mode - loopback modes * @LOOPBACK_NONE: no loopback - * @LOOPBACK_XGMII: loopback within MAC at XGMII level - * @LOOPBACK_XGXS: loopback within MAC at XGXS level - * @LOOPBACK_XAUI: loopback within MAC at XAUI level - * @LOOPBACK_PHYXS: loopback within PHY at PHYXS level - * @LOOPBACK_PCS: loopback within PHY at PCS level - * @LOOPBACK_PMAPMD: loopback within PHY at PMAPMD level + * @LOOPBACK_GMAC: loopback within GMAC at unspecified level + * @LOOPBACK_XGMII: loopback within XMAC at XGMII level + * @LOOPBACK_XGXS: loopback within XMAC at XGXS level + * @LOOPBACK_XAUI: loopback within XMAC at XAUI level + * @LOOPBACK_GPHY: loopback within 1G PHY at unspecified level + * @LOOPBACK_PHYXS: loopback within 10G PHY at PHYXS level + * @LOOPBACK_PCS: loopback within 10G PHY at PCS level + * @LOOPBACK_PMAPMD: loopback within 10G PHY at PMAPMD level * @LOOPBACK_NETWORK: reflecting loopback (even further than furthest!) */ /* Please keep in order and up-to-date w.r.t the following two #defines */ enum efx_loopback_mode { LOOPBACK_NONE = 0, - LOOPBACK_MAC = 1, + LOOPBACK_GMAC = 1, LOOPBACK_XGMII = 2, LOOPBACK_XGXS = 3, LOOPBACK_XAUI = 4, - LOOPBACK_PHY = 5, + LOOPBACK_GPHY = 5, LOOPBACK_PHYXS = 6, LOOPBACK_PCS = 7, LOOPBACK_PMAPMD = 8, @@ -45,15 +47,19 @@ extern const char *efx_loopback_mode_names[]; LOOPBACK_MODE_NAME(efx->loopback_mode) /* These loopbacks occur within the controller */ -#define LOOPBACKS_10G_INTERNAL ((1 << LOOPBACK_XGMII)| \ - (1 << LOOPBACK_XGXS) | \ - (1 << LOOPBACK_XAUI)) +#define LOOPBACKS_INTERNAL ((1 << LOOPBACK_GMAC) | \ + (1 << LOOPBACK_XGMII)| \ + (1 << LOOPBACK_XGXS) | \ + (1 << LOOPBACK_XAUI)) #define LOOPBACK_MASK(_efx) \ (1 << (_efx)->loopback_mode) #define LOOPBACK_INTERNAL(_efx) \ - (!!(LOOPBACKS_10G_INTERNAL & LOOPBACK_MASK(_efx))) + (!!(LOOPBACKS_INTERNAL & LOOPBACK_MASK(_efx))) + +#define LOOPBACK_CHANGED(_from, _to, _mask) \ + (!!((LOOPBACK_MASK(_from) ^ LOOPBACK_MASK(_to)) & (_mask))) #define LOOPBACK_OUT_OF(_from, _to, _mask) \ ((LOOPBACK_MASK(_from) & (_mask)) && !(LOOPBACK_MASK(_to) & (_mask))) @@ -72,7 +78,7 @@ extern const char *efx_loopback_mode_names[]; * @RESET_TYPE_ALL: reset everything but PCI core blocks * @RESET_TYPE_WORLD: reset everything, save & restore PCI config * @RESET_TYPE_DISABLE: disable NIC - * @RESET_TYPE_MONITOR: reset due to hardware monitor + * @RESET_TYPE_TX_WATCHDOG: reset due to TX watchdog * @RESET_TYPE_INT_ERROR: reset due to internal error * @RESET_TYPE_RX_RECOVERY: reset to recover from RX datapath errors * @RESET_TYPE_RX_DESC_FETCH: pcie error during rx descriptor fetch @@ -86,7 +92,7 @@ enum reset_type { RESET_TYPE_WORLD = 2, RESET_TYPE_DISABLE = 3, RESET_TYPE_MAX_METHOD, - RESET_TYPE_MONITOR, + RESET_TYPE_TX_WATCHDOG, RESET_TYPE_INT_ERROR, RESET_TYPE_RX_RECOVERY, RESET_TYPE_RX_DESC_FETCH, diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index cd0d0873d9782a358e1c835c6a51967071a780d5..53d259e90187ae8017c664ef55579329a745608b 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -12,24 +12,24 @@ #include #include #include "net_driver.h" +#include "workarounds.h" #include "selftest.h" #include "efx.h" #include "ethtool.h" #include "falcon.h" -#include "gmii.h" #include "spi.h" -#include "mac.h" +#include "mdio_10g.h" const char *efx_loopback_mode_names[] = { [LOOPBACK_NONE] = "NONE", - [LOOPBACK_MAC] = "MAC", + [LOOPBACK_GMAC] = "GMAC", [LOOPBACK_XGMII] = "XGMII", [LOOPBACK_XGXS] = "XGXS", [LOOPBACK_XAUI] = "XAUI", - [LOOPBACK_PHY] = "PHY", - [LOOPBACK_PHYXS] = "PHY(XS)", - [LOOPBACK_PCS] = "PHY(PCS)", - [LOOPBACK_PMAPMD] = "PHY(PMAPMD)", + [LOOPBACK_GPHY] = "GPHY", + [LOOPBACK_PHYXS] = "PHYXS", + [LOOPBACK_PCS] = "PCS", + [LOOPBACK_PMAPMD] = "PMA/PMD", [LOOPBACK_NETWORK] = "NETWORK", }; @@ -172,10 +172,7 @@ static struct efx_ethtool_stat efx_ethtool_stats[] = { /* Number of ethtool statistics */ #define EFX_ETHTOOL_NUM_STATS ARRAY_SIZE(efx_ethtool_stats) -/* EEPROM range with gPXE configuration */ #define EFX_ETHTOOL_EEPROM_MAGIC 0xEFAB -#define EFX_ETHTOOL_EEPROM_MIN 0x800U -#define EFX_ETHTOOL_EEPROM_MAX 0x1800U /************************************************************************** * @@ -185,12 +182,16 @@ static struct efx_ethtool_stat efx_ethtool_stats[] = { */ /* Identify device by flashing LEDs */ -static int efx_ethtool_phys_id(struct net_device *net_dev, u32 seconds) +static int efx_ethtool_phys_id(struct net_device *net_dev, u32 count) { struct efx_nic *efx = netdev_priv(net_dev); efx->board_info.blink(efx, 1); - schedule_timeout_interruptible(seconds * HZ); + set_current_state(TASK_INTERRUPTIBLE); + if (count) + schedule_timeout(count * HZ); + else + schedule(); efx->board_info.blink(efx, 0); return 0; } @@ -200,13 +201,15 @@ int efx_ethtool_get_settings(struct net_device *net_dev, struct ethtool_cmd *ecmd) { struct efx_nic *efx = netdev_priv(net_dev); - int rc; mutex_lock(&efx->mac_lock); - rc = falcon_xmac_get_settings(efx, ecmd); + efx->phy_op->get_settings(efx, ecmd); mutex_unlock(&efx->mac_lock); - return rc; + /* Falcon GMAC does not support 1000Mbps HD */ + ecmd->supported &= ~SUPPORTED_1000baseT_Half; + + return 0; } /* This must be called with rtnl_lock held. */ @@ -216,8 +219,18 @@ int efx_ethtool_set_settings(struct net_device *net_dev, struct efx_nic *efx = netdev_priv(net_dev); int rc; + if (EFX_WORKAROUND_13963(efx) && !ecmd->autoneg) + return -EINVAL; + + /* Falcon GMAC does not support 1000Mbps HD */ + if (ecmd->speed == SPEED_1000 && ecmd->duplex != DUPLEX_FULL) { + EFX_LOG(efx, "rejecting unsupported 1000Mbps HD" + " setting\n"); + return -EINVAL; + } + mutex_lock(&efx->mac_lock); - rc = falcon_xmac_set_settings(efx, ecmd); + rc = efx->phy_op->set_settings(efx, ecmd); mutex_unlock(&efx->mac_lock); if (!rc) efx_reconfigure_port(efx); @@ -241,10 +254,10 @@ static void efx_ethtool_get_drvinfo(struct net_device *net_dev, * @strings: Ethtool strings, or %NULL * @data: Ethtool test results, or %NULL * @test: Pointer to test result (used only if data != %NULL) - * @unit_format: Unit name format (e.g. "channel\%d") - * @unit_id: Unit id (e.g. 0 for "channel0") + * @unit_format: Unit name format (e.g. "chan\%d") + * @unit_id: Unit id (e.g. 0 for "chan0") * @test_format: Test name format (e.g. "loopback.\%s.tx.sent") - * @test_id: Test id (e.g. "PHY" for "loopback.PHY.tx_sent") + * @test_id: Test id (e.g. "PHYXS" for "loopback.PHYXS.tx_sent") * * Fill in an individual self-test entry. */ @@ -261,18 +274,20 @@ static void efx_fill_test(unsigned int test_index, /* Fill string, if applicable */ if (strings) { - snprintf(unit_str.name, sizeof(unit_str.name), - unit_format, unit_id); + if (strchr(unit_format, '%')) + snprintf(unit_str.name, sizeof(unit_str.name), + unit_format, unit_id); + else + strcpy(unit_str.name, unit_format); snprintf(test_str.name, sizeof(test_str.name), test_format, test_id); snprintf(strings[test_index].name, sizeof(strings[test_index].name), - "%-9s%-17s", unit_str.name, test_str.name); + "%-6s %-24s", unit_str.name, test_str.name); } } -#define EFX_PORT_NAME "port%d", 0 -#define EFX_CHANNEL_NAME(_channel) "channel%d", _channel->channel +#define EFX_CHANNEL_NAME(_channel) "chan%d", _channel->channel #define EFX_TX_QUEUE_NAME(_tx_queue) "txq%d", _tx_queue->queue #define EFX_RX_QUEUE_NAME(_rx_queue) "rxq%d", _rx_queue->queue #define EFX_LOOPBACK_NAME(_mode, _counter) \ @@ -307,11 +322,11 @@ static int efx_fill_loopback_test(struct efx_nic *efx, } efx_fill_test(test_index++, strings, data, &lb_tests->rx_good, - EFX_PORT_NAME, + "rx", 0, EFX_LOOPBACK_NAME(mode, "rx_good")); efx_fill_test(test_index++, strings, data, &lb_tests->rx_bad, - EFX_PORT_NAME, + "rx", 0, EFX_LOOPBACK_NAME(mode, "rx_bad")); return test_index; @@ -330,7 +345,7 @@ static int efx_ethtool_fill_self_tests(struct efx_nic *efx, u64 *data) { struct efx_channel *channel; - unsigned int n = 0; + unsigned int n = 0, i; enum efx_loopback_mode mode; efx_fill_test(n++, strings, data, &tests->mii, @@ -358,14 +373,12 @@ static int efx_ethtool_fill_self_tests(struct efx_nic *efx, efx_fill_test(n++, strings, data, &tests->registers, "core", 0, "registers", NULL); - efx_fill_test(n++, strings, data, &tests->phy, - EFX_PORT_NAME, "phy", NULL); + + for (i = 0; i < efx->phy_op->num_tests; i++) + efx_fill_test(n++, strings, data, &tests->phy[i], + "phy", 0, efx->phy_op->test_names[i], NULL); /* Loopback tests */ - efx_fill_test(n++, strings, data, &tests->loopback_speed, - EFX_PORT_NAME, "loopback.speed", NULL); - efx_fill_test(n++, strings, data, &tests->loopback_full_duplex, - EFX_PORT_NAME, "loopback.full_duplex", NULL); for (mode = LOOPBACK_NONE; mode <= LOOPBACK_TEST_MAX; mode++) { if (!(efx->loopback_modes & (1 << mode))) continue; @@ -429,7 +442,7 @@ static void efx_ethtool_get_stats(struct net_device *net_dev, EFX_BUG_ON_PARANOID(stats->n_stats != EFX_ETHTOOL_NUM_STATS); /* Update MAC and NIC statistics */ - net_dev->get_stats(net_dev); + dev_get_stats(net_dev); /* Fill detailed statistics buffer */ for (i = 0; i < EFX_ETHTOOL_NUM_STATS; i++) { @@ -476,7 +489,7 @@ static void efx_ethtool_self_test(struct net_device *net_dev, { struct efx_nic *efx = netdev_priv(net_dev); struct efx_self_tests efx_tests; - int offline, already_up; + int already_up; int rc; ASSERT_RTNL(); @@ -496,24 +509,15 @@ static void efx_ethtool_self_test(struct net_device *net_dev, } memset(&efx_tests, 0, sizeof(efx_tests)); - offline = (test->flags & ETH_TEST_FL_OFFLINE); - - /* Perform online self tests first */ - rc = efx_online_test(efx, &efx_tests); - if (rc) - goto out; - /* Perform offline tests only if online tests passed */ - if (offline) - rc = efx_offline_test(efx, &efx_tests, - efx->loopback_modes); + rc = efx_selftest(efx, &efx_tests, test->flags); - out: if (!already_up) dev_close(efx->net_dev); - EFX_LOG(efx, "%s all %sline self-tests\n", - rc == 0 ? "passed" : "failed", offline ? "off" : "on"); + EFX_LOG(efx, "%s %sline self-tests\n", + rc == 0 ? "passed" : "failed", + (test->flags & ETH_TEST_FL_OFFLINE) ? "off" : "on"); fail2: fail1: @@ -545,8 +549,8 @@ static int efx_ethtool_get_eeprom_len(struct net_device *net_dev) if (!spi) return 0; - return min(spi->size, EFX_ETHTOOL_EEPROM_MAX) - - min(spi->size, EFX_ETHTOOL_EEPROM_MIN); + return min(spi->size, EFX_EEPROM_BOOTCONFIG_END) - + min(spi->size, EFX_EEPROM_BOOTCONFIG_START); } static int efx_ethtool_get_eeprom(struct net_device *net_dev, @@ -557,8 +561,13 @@ static int efx_ethtool_get_eeprom(struct net_device *net_dev, size_t len; int rc; - rc = falcon_spi_read(spi, eeprom->offset + EFX_ETHTOOL_EEPROM_MIN, + rc = mutex_lock_interruptible(&efx->spi_lock); + if (rc) + return rc; + rc = falcon_spi_read(spi, eeprom->offset + EFX_EEPROM_BOOTCONFIG_START, eeprom->len, &len, buf); + mutex_unlock(&efx->spi_lock); + eeprom->magic = EFX_ETHTOOL_EEPROM_MAGIC; eeprom->len = len; return rc; @@ -575,8 +584,13 @@ static int efx_ethtool_set_eeprom(struct net_device *net_dev, if (eeprom->magic != EFX_ETHTOOL_EEPROM_MAGIC) return -EINVAL; - rc = falcon_spi_write(spi, eeprom->offset + EFX_ETHTOOL_EEPROM_MIN, + rc = mutex_lock_interruptible(&efx->spi_lock); + if (rc) + return rc; + rc = falcon_spi_write(spi, eeprom->offset + EFX_EEPROM_BOOTCONFIG_START, eeprom->len, &len, buf); + mutex_unlock(&efx->spi_lock); + eeprom->len = len; return rc; } @@ -666,23 +680,52 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev, struct ethtool_pauseparam *pause) { struct efx_nic *efx = netdev_priv(net_dev); - enum efx_fc_type flow_control = efx->flow_control; - int rc; + enum efx_fc_type wanted_fc; + bool reset; - flow_control &= ~(EFX_FC_RX | EFX_FC_TX | EFX_FC_AUTO); - flow_control |= pause->rx_pause ? EFX_FC_RX : 0; - flow_control |= pause->tx_pause ? EFX_FC_TX : 0; - flow_control |= pause->autoneg ? EFX_FC_AUTO : 0; + wanted_fc = ((pause->rx_pause ? EFX_FC_RX : 0) | + (pause->tx_pause ? EFX_FC_TX : 0) | + (pause->autoneg ? EFX_FC_AUTO : 0)); + + if ((wanted_fc & EFX_FC_TX) && !(wanted_fc & EFX_FC_RX)) { + EFX_LOG(efx, "Flow control unsupported: tx ON rx OFF\n"); + return -EINVAL; + } + + if (!(efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN)) && + (wanted_fc & EFX_FC_AUTO)) { + EFX_LOG(efx, "PHY does not support flow control " + "autonegotiation\n"); + return -EINVAL; + } + + /* TX flow control may automatically turn itself off if the + * link partner (intermittently) stops responding to pause + * frames. There isn't any indication that this has happened, + * so the best we do is leave it up to the user to spot this + * and fix it be cycling transmit flow control on this end. */ + reset = (wanted_fc & EFX_FC_TX) && !(efx->wanted_fc & EFX_FC_TX); + if (EFX_WORKAROUND_11482(efx) && reset) { + if (falcon_rev(efx) >= FALCON_REV_B0) { + /* Recover by resetting the EM block */ + if (efx->link_up) + falcon_drain_tx_fifo(efx); + } else { + /* Schedule a reset to recover */ + efx_schedule_reset(efx, RESET_TYPE_INVISIBLE); + } + } /* Try to push the pause parameters */ mutex_lock(&efx->mac_lock); - rc = falcon_xmac_set_pause(efx, flow_control); - mutex_unlock(&efx->mac_lock); - if (!rc) - efx_reconfigure_port(efx); + efx->wanted_fc = wanted_fc; + mdio_clause45_set_pause(efx); + __efx_reconfigure_port(efx); - return rc; + mutex_unlock(&efx->mac_lock); + + return 0; } static void efx_ethtool_get_pauseparam(struct net_device *net_dev, @@ -690,9 +733,9 @@ static void efx_ethtool_get_pauseparam(struct net_device *net_dev, { struct efx_nic *efx = netdev_priv(net_dev); - pause->rx_pause = !!(efx->flow_control & EFX_FC_RX); - pause->tx_pause = !!(efx->flow_control & EFX_FC_TX); - pause->autoneg = !!(efx->flow_control & EFX_FC_AUTO); + pause->rx_pause = !!(efx->wanted_fc & EFX_FC_RX); + pause->tx_pause = !!(efx->wanted_fc & EFX_FC_TX); + pause->autoneg = !!(efx->wanted_fc & EFX_FC_AUTO); } diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index 31ed1f49de008a547e61828174a39331d00c2512..6884dc8c1f8259a69421a65b7a1f81df8ff57a97 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -15,11 +15,11 @@ #include #include #include +#include #include "net_driver.h" #include "bitfield.h" #include "efx.h" #include "mac.h" -#include "gmii.h" #include "spi.h" #include "falcon.h" #include "falcon_hwdefs.h" @@ -70,6 +70,20 @@ static int disable_dma_stats; #define RX_DC_ENTRIES_ORDER 2 #define RX_DC_BASE 0x100000 +static const unsigned int +/* "Large" EEPROM device: Atmel AT25640 or similar + * 8 KB, 16-bit address, 32 B write block */ +large_eeprom_type = ((13 << SPI_DEV_TYPE_SIZE_LBN) + | (2 << SPI_DEV_TYPE_ADDR_LEN_LBN) + | (5 << SPI_DEV_TYPE_BLOCK_SIZE_LBN)), +/* Default flash device: Atmel AT25F1024 + * 128 KB, 24-bit address, 32 KB erase block, 256 B write block */ +default_flash_type = ((17 << SPI_DEV_TYPE_SIZE_LBN) + | (3 << SPI_DEV_TYPE_ADDR_LEN_LBN) + | (0x52 << SPI_DEV_TYPE_ERASE_CMD_LBN) + | (15 << SPI_DEV_TYPE_ERASE_SIZE_LBN) + | (8 << SPI_DEV_TYPE_BLOCK_SIZE_LBN)); + /* RX FIFO XOFF watermark * * When the amount of the RX FIFO increases used increases past this @@ -770,15 +784,18 @@ static void falcon_handle_rx_not_ok(struct efx_rx_queue *rx_queue, rx_ev_buf_owner_id_err | rx_ev_eth_crc_err | rx_ev_frm_trunc | rx_ev_ip_hdr_chksum_err); - /* Count errors that are not in MAC stats. */ + /* Count errors that are not in MAC stats. Ignore expected + * checksum errors during self-test. */ if (rx_ev_frm_trunc) ++rx_queue->channel->n_rx_frm_trunc; else if (rx_ev_tobe_disc) ++rx_queue->channel->n_rx_tobe_disc; - else if (rx_ev_ip_hdr_chksum_err) - ++rx_queue->channel->n_rx_ip_hdr_chksum_err; - else if (rx_ev_tcp_udp_chksum_err) - ++rx_queue->channel->n_rx_tcp_udp_chksum_err; + else if (!efx->loopback_selftest) { + if (rx_ev_ip_hdr_chksum_err) + ++rx_queue->channel->n_rx_ip_hdr_chksum_err; + else if (rx_ev_tcp_udp_chksum_err) + ++rx_queue->channel->n_rx_tcp_udp_chksum_err; + } if (rx_ev_ip_frag_err) ++rx_queue->channel->n_rx_ip_frag_err; @@ -809,7 +826,7 @@ static void falcon_handle_rx_not_ok(struct efx_rx_queue *rx_queue, #endif if (unlikely(rx_ev_eth_crc_err && EFX_WORKAROUND_10750(efx) && - efx->phy_type == PHY_TYPE_10XPRESS)) + efx->phy_type == PHY_TYPE_SFX7101)) tenxpress_crc_err(efx); } @@ -893,22 +910,20 @@ static void falcon_handle_global_event(struct efx_channel *channel, efx_qword_t *event) { struct efx_nic *efx = channel->efx; - bool is_phy_event = false, handled = false; + bool handled = false; - /* Check for interrupt on either port. Some boards have a - * single PHY wired to the interrupt line for port 1. */ if (EFX_QWORD_FIELD(*event, G_PHY0_INTR) || EFX_QWORD_FIELD(*event, G_PHY1_INTR) || - EFX_QWORD_FIELD(*event, XG_PHY_INTR)) - is_phy_event = true; + EFX_QWORD_FIELD(*event, XG_PHY_INTR) || + EFX_QWORD_FIELD(*event, XFP_PHY_INTR)) { + efx->phy_op->clear_interrupt(efx); + queue_work(efx->workqueue, &efx->phy_work); + handled = true; + } if ((falcon_rev(efx) >= FALCON_REV_B0) && - EFX_QWORD_FIELD(*event, XG_MNT_INTR_B0)) - is_phy_event = true; - - if (is_phy_event) { - efx->phy_op->clear_interrupt(efx); - queue_work(efx->workqueue, &efx->reconfigure_work); + EFX_QWORD_FIELD(*event, XG_MNT_INTR_B0)) { + queue_work(efx->workqueue, &efx->mac_work); handled = true; } @@ -1151,6 +1166,19 @@ void falcon_generate_test_event(struct efx_channel *channel, unsigned int magic) falcon_generate_event(channel, &test_event); } +void falcon_sim_phy_event(struct efx_nic *efx) +{ + efx_qword_t phy_event; + + EFX_POPULATE_QWORD_1(phy_event, EV_CODE, GLOBAL_EV_DECODE); + if (EFX_IS10G(efx)) + EFX_SET_OWORD_FIELD(phy_event, XG_PHY_INTR, 1); + else + EFX_SET_OWORD_FIELD(phy_event, G_PHY0_INTR, 1); + + falcon_generate_event(&efx->channel[0], &phy_event); +} + /************************************************************************** * * Flush handling @@ -1560,7 +1588,7 @@ int falcon_init_interrupt(struct efx_nic *efx) efx_for_each_channel(channel, efx) { rc = request_irq(channel->irq, falcon_msi_interrupt, IRQF_PROBE_SHARED, /* Not shared */ - efx->name, channel); + channel->name, channel); if (rc) { EFX_ERR(efx, "failed to hook IRQ %d\n", channel->irq); goto fail2; @@ -1605,32 +1633,45 @@ void falcon_fini_interrupt(struct efx_nic *efx) ************************************************************************** */ -#define FALCON_SPI_MAX_LEN ((unsigned) sizeof(efx_oword_t)) +#define FALCON_SPI_MAX_LEN sizeof(efx_oword_t) + +static int falcon_spi_poll(struct efx_nic *efx) +{ + efx_oword_t reg; + falcon_read(efx, ®, EE_SPI_HCMD_REG_KER); + return EFX_OWORD_FIELD(reg, EE_SPI_HCMD_CMD_EN) ? -EBUSY : 0; +} /* Wait for SPI command completion */ static int falcon_spi_wait(struct efx_nic *efx) { - unsigned long timeout = jiffies + DIV_ROUND_UP(HZ, 10); - efx_oword_t reg; - bool cmd_en, timer_active; + /* Most commands will finish quickly, so we start polling at + * very short intervals. Sometimes the command may have to + * wait for VPD or expansion ROM access outside of our + * control, so we allow up to 100 ms. */ + unsigned long timeout = jiffies + 1 + DIV_ROUND_UP(HZ, 10); + int i; + + for (i = 0; i < 10; i++) { + if (!falcon_spi_poll(efx)) + return 0; + udelay(10); + } for (;;) { - falcon_read(efx, ®, EE_SPI_HCMD_REG_KER); - cmd_en = EFX_OWORD_FIELD(reg, EE_SPI_HCMD_CMD_EN); - timer_active = EFX_OWORD_FIELD(reg, EE_WR_TIMER_ACTIVE); - if (!cmd_en && !timer_active) + if (!falcon_spi_poll(efx)) return 0; if (time_after_eq(jiffies, timeout)) { EFX_ERR(efx, "timed out waiting for SPI\n"); return -ETIMEDOUT; } - cpu_relax(); + schedule_timeout_uninterruptible(1); } } -static int falcon_spi_cmd(const struct efx_spi_device *spi, - unsigned int command, int address, - const void *in, void *out, unsigned int len) +int falcon_spi_cmd(const struct efx_spi_device *spi, + unsigned int command, int address, + const void *in, void *out, size_t len) { struct efx_nic *efx = spi->efx; bool addressed = (address >= 0); @@ -1641,9 +1682,10 @@ static int falcon_spi_cmd(const struct efx_spi_device *spi, /* Input validation */ if (len > FALCON_SPI_MAX_LEN) return -EINVAL; + BUG_ON(!mutex_is_locked(&efx->spi_lock)); - /* Check SPI not currently being accessed */ - rc = falcon_spi_wait(efx); + /* Check that previous command is not still running */ + rc = falcon_spi_poll(efx); if (rc) return rc; @@ -1685,8 +1727,8 @@ static int falcon_spi_cmd(const struct efx_spi_device *spi, return 0; } -static unsigned int -falcon_spi_write_limit(const struct efx_spi_device *spi, unsigned int start) +static size_t +falcon_spi_write_limit(const struct efx_spi_device *spi, size_t start) { return min(FALCON_SPI_MAX_LEN, (spi->block_size - (start & (spi->block_size - 1)))); @@ -1699,38 +1741,40 @@ efx_spi_munge_command(const struct efx_spi_device *spi, return command | (((address >> 8) & spi->munge_address) << 3); } - -static int falcon_spi_fast_wait(const struct efx_spi_device *spi) +/* Wait up to 10 ms for buffered write completion */ +int falcon_spi_wait_write(const struct efx_spi_device *spi) { + struct efx_nic *efx = spi->efx; + unsigned long timeout = jiffies + 1 + DIV_ROUND_UP(HZ, 100); u8 status; - int i, rc; - - /* Wait up to 1000us for flash/EEPROM to finish a fast operation. */ - for (i = 0; i < 50; i++) { - udelay(20); + int rc; + for (;;) { rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL, &status, sizeof(status)); if (rc) return rc; if (!(status & SPI_STATUS_NRDY)) return 0; + if (time_after_eq(jiffies, timeout)) { + EFX_ERR(efx, "SPI write timeout on device %d" + " last status=0x%02x\n", + spi->device_id, status); + return -ETIMEDOUT; + } + schedule_timeout_uninterruptible(1); } - EFX_ERR(spi->efx, - "timed out waiting for device %d last status=0x%02x\n", - spi->device_id, status); - return -ETIMEDOUT; } int falcon_spi_read(const struct efx_spi_device *spi, loff_t start, size_t len, size_t *retlen, u8 *buffer) { - unsigned int command, block_len, pos = 0; + size_t block_len, pos = 0; + unsigned int command; int rc = 0; while (pos < len) { - block_len = min((unsigned int)len - pos, - FALCON_SPI_MAX_LEN); + block_len = min(len - pos, FALCON_SPI_MAX_LEN); command = efx_spi_munge_command(spi, SPI_READ, start + pos); rc = falcon_spi_cmd(spi, command, start + pos, NULL, @@ -1756,7 +1800,8 @@ int falcon_spi_write(const struct efx_spi_device *spi, loff_t start, size_t len, size_t *retlen, const u8 *buffer) { u8 verify_buffer[FALCON_SPI_MAX_LEN]; - unsigned int command, block_len, pos = 0; + size_t block_len, pos = 0; + unsigned int command; int rc = 0; while (pos < len) { @@ -1764,7 +1809,7 @@ int falcon_spi_write(const struct efx_spi_device *spi, loff_t start, if (rc) break; - block_len = min((unsigned int)len - pos, + block_len = min(len - pos, falcon_spi_write_limit(spi, start + pos)); command = efx_spi_munge_command(spi, SPI_WRITE, start + pos); rc = falcon_spi_cmd(spi, command, start + pos, @@ -1772,7 +1817,7 @@ int falcon_spi_write(const struct efx_spi_device *spi, loff_t start, if (rc) break; - rc = falcon_spi_fast_wait(spi); + rc = falcon_spi_wait_write(spi); if (rc) break; @@ -1805,40 +1850,61 @@ int falcon_spi_write(const struct efx_spi_device *spi, loff_t start, * ************************************************************************** */ -void falcon_drain_tx_fifo(struct efx_nic *efx) + +static int falcon_reset_macs(struct efx_nic *efx) { - efx_oword_t temp; + efx_oword_t reg; int count; - if ((falcon_rev(efx) < FALCON_REV_B0) || - (efx->loopback_mode != LOOPBACK_NONE)) - return; + if (falcon_rev(efx) < FALCON_REV_B0) { + /* It's not safe to use GLB_CTL_REG to reset the + * macs, so instead use the internal MAC resets + */ + if (!EFX_IS10G(efx)) { + EFX_POPULATE_OWORD_1(reg, GM_SW_RST, 1); + falcon_write(efx, ®, GM_CFG1_REG); + udelay(1000); + + EFX_POPULATE_OWORD_1(reg, GM_SW_RST, 0); + falcon_write(efx, ®, GM_CFG1_REG); + udelay(1000); + return 0; + } else { + EFX_POPULATE_OWORD_1(reg, XM_CORE_RST, 1); + falcon_write(efx, ®, XM_GLB_CFG_REG); + + for (count = 0; count < 10000; count++) { + falcon_read(efx, ®, XM_GLB_CFG_REG); + if (EFX_OWORD_FIELD(reg, XM_CORE_RST) == 0) + return 0; + udelay(10); + } - falcon_read(efx, &temp, MAC0_CTRL_REG_KER); - /* There is no point in draining more than once */ - if (EFX_OWORD_FIELD(temp, TXFIFO_DRAIN_EN_B0)) - return; + EFX_ERR(efx, "timed out waiting for XMAC core reset\n"); + return -ETIMEDOUT; + } + } /* MAC stats will fail whilst the TX fifo is draining. Serialise * the drain sequence with the statistics fetch */ spin_lock(&efx->stats_lock); - EFX_SET_OWORD_FIELD(temp, TXFIFO_DRAIN_EN_B0, 1); - falcon_write(efx, &temp, MAC0_CTRL_REG_KER); + falcon_read(efx, ®, MAC0_CTRL_REG_KER); + EFX_SET_OWORD_FIELD(reg, TXFIFO_DRAIN_EN_B0, 1); + falcon_write(efx, ®, MAC0_CTRL_REG_KER); - /* Reset the MAC and EM block. */ - falcon_read(efx, &temp, GLB_CTL_REG_KER); - EFX_SET_OWORD_FIELD(temp, RST_XGTX, 1); - EFX_SET_OWORD_FIELD(temp, RST_XGRX, 1); - EFX_SET_OWORD_FIELD(temp, RST_EM, 1); - falcon_write(efx, &temp, GLB_CTL_REG_KER); + falcon_read(efx, ®, GLB_CTL_REG_KER); + EFX_SET_OWORD_FIELD(reg, RST_XGTX, 1); + EFX_SET_OWORD_FIELD(reg, RST_XGRX, 1); + EFX_SET_OWORD_FIELD(reg, RST_EM, 1); + falcon_write(efx, ®, GLB_CTL_REG_KER); count = 0; while (1) { - falcon_read(efx, &temp, GLB_CTL_REG_KER); - if (!EFX_OWORD_FIELD(temp, RST_XGTX) && - !EFX_OWORD_FIELD(temp, RST_XGRX) && - !EFX_OWORD_FIELD(temp, RST_EM)) { + falcon_read(efx, ®, GLB_CTL_REG_KER); + if (!EFX_OWORD_FIELD(reg, RST_XGTX) && + !EFX_OWORD_FIELD(reg, RST_XGRX) && + !EFX_OWORD_FIELD(reg, RST_EM)) { EFX_LOG(efx, "Completed MAC reset after %d loops\n", count); break; @@ -1855,21 +1921,39 @@ void falcon_drain_tx_fifo(struct efx_nic *efx) /* If we've reset the EM block and the link is up, then * we'll have to kick the XAUI link so the PHY can recover */ - if (efx->link_up && EFX_WORKAROUND_5147(efx)) + if (efx->link_up && EFX_IS10G(efx) && EFX_WORKAROUND_5147(efx)) falcon_reset_xaui(efx); + + return 0; +} + +void falcon_drain_tx_fifo(struct efx_nic *efx) +{ + efx_oword_t reg; + + if ((falcon_rev(efx) < FALCON_REV_B0) || + (efx->loopback_mode != LOOPBACK_NONE)) + return; + + falcon_read(efx, ®, MAC0_CTRL_REG_KER); + /* There is no point in draining more than once */ + if (EFX_OWORD_FIELD(reg, TXFIFO_DRAIN_EN_B0)) + return; + + falcon_reset_macs(efx); } void falcon_deconfigure_mac_wrapper(struct efx_nic *efx) { - efx_oword_t temp; + efx_oword_t reg; if (falcon_rev(efx) < FALCON_REV_B0) return; /* Isolate the MAC -> RX */ - falcon_read(efx, &temp, RX_CFG_REG_KER); - EFX_SET_OWORD_FIELD(temp, RX_INGR_EN_B0, 0); - falcon_write(efx, &temp, RX_CFG_REG_KER); + falcon_read(efx, ®, RX_CFG_REG_KER); + EFX_SET_OWORD_FIELD(reg, RX_INGR_EN_B0, 0); + falcon_write(efx, ®, RX_CFG_REG_KER); if (!efx->link_up) falcon_drain_tx_fifo(efx); @@ -1881,14 +1965,12 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx) int link_speed; bool tx_fc; - if (efx->link_options & GM_LPA_10000) - link_speed = 0x3; - else if (efx->link_options & GM_LPA_1000) - link_speed = 0x2; - else if (efx->link_options & GM_LPA_100) - link_speed = 0x1; - else - link_speed = 0x0; + switch (efx->link_speed) { + case 10000: link_speed = 3; break; + case 1000: link_speed = 2; break; + case 100: link_speed = 1; break; + default: link_speed = 0; break; + } /* MAC_LINK_STATUS controls MAC backpressure but doesn't work * as advertised. Disable to ensure packets are not * indefinitely held and TX queue can be flushed at any point @@ -1914,7 +1996,7 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx) /* Transmission of pause frames when RX crosses the threshold is * covered by RX_XOFF_MAC_EN and XM_TX_CFG_REG:XM_FCNTL. * Action on receipt of pause frames is controller by XM_DIS_FCNTL */ - tx_fc = !!(efx->flow_control & EFX_FC_TX); + tx_fc = !!(efx->link_fc & EFX_FC_TX); falcon_read(efx, ®, RX_CFG_REG_KER); EFX_SET_OWORD_FIELD_VER(efx, reg, RX_XOFF_MAC_EN, tx_fc); @@ -1998,7 +2080,8 @@ static int falcon_gmii_wait(struct efx_nic *efx) efx_dword_t md_stat; int count; - for (count = 0; count < 1000; count++) { /* wait upto 10ms */ + /* wait upto 50ms - taken max from datasheet */ + for (count = 0; count < 5000; count++) { falcon_readl(efx, &md_stat, MD_STAT_REG_KER); if (EFX_DWORD_FIELD(md_stat, MD_BSY) == 0) { if (EFX_DWORD_FIELD(md_stat, MD_LNFL) != 0 || @@ -2162,10 +2245,14 @@ static void falcon_init_mdio(struct mii_if_info *gmii) static int falcon_probe_phy(struct efx_nic *efx) { switch (efx->phy_type) { - case PHY_TYPE_10XPRESS: - efx->phy_op = &falcon_tenxpress_phy_ops; + case PHY_TYPE_SFX7101: + efx->phy_op = &falcon_sfx7101_phy_ops; + break; + case PHY_TYPE_SFT9001A: + case PHY_TYPE_SFT9001B: + efx->phy_op = &falcon_sft9001_phy_ops; break; - case PHY_TYPE_XFP: + case PHY_TYPE_QT2022C2: efx->phy_op = &falcon_xfp_phy_ops; break; default: @@ -2174,10 +2261,59 @@ static int falcon_probe_phy(struct efx_nic *efx) return -1; } - efx->loopback_modes = LOOPBACKS_10G_INTERNAL | efx->phy_op->loopbacks; + if (efx->phy_op->macs & EFX_XMAC) + efx->loopback_modes |= ((1 << LOOPBACK_XGMII) | + (1 << LOOPBACK_XGXS) | + (1 << LOOPBACK_XAUI)); + if (efx->phy_op->macs & EFX_GMAC) + efx->loopback_modes |= (1 << LOOPBACK_GMAC); + efx->loopback_modes |= efx->phy_op->loopbacks; + return 0; } +int falcon_switch_mac(struct efx_nic *efx) +{ + struct efx_mac_operations *old_mac_op = efx->mac_op; + efx_oword_t nic_stat; + unsigned strap_val; + + /* Internal loopbacks override the phy speed setting */ + if (efx->loopback_mode == LOOPBACK_GMAC) { + efx->link_speed = 1000; + efx->link_fd = true; + } else if (LOOPBACK_INTERNAL(efx)) { + efx->link_speed = 10000; + efx->link_fd = true; + } + + efx->mac_op = (EFX_IS10G(efx) ? + &falcon_xmac_operations : &falcon_gmac_operations); + if (old_mac_op == efx->mac_op) + return 0; + + WARN_ON(!mutex_is_locked(&efx->mac_lock)); + + /* Not all macs support a mac-level link state */ + efx->mac_up = true; + + falcon_read(efx, &nic_stat, NIC_STAT_REG); + strap_val = EFX_IS10G(efx) ? 5 : 3; + if (falcon_rev(efx) >= FALCON_REV_B0) { + EFX_SET_OWORD_FIELD(nic_stat, EE_STRAP_EN, 1); + EFX_SET_OWORD_FIELD(nic_stat, EE_STRAP_OVR, strap_val); + falcon_write(efx, &nic_stat, NIC_STAT_REG); + } else { + /* Falcon A1 does not support 1G/10G speed switching + * and must not be used with a PHY that does. */ + BUG_ON(EFX_OWORD_FIELD(nic_stat, STRAP_PINS) != strap_val); + } + + + EFX_LOG(efx, "selected %cMAC\n", EFX_IS10G(efx) ? 'X' : 'G'); + return falcon_reset_macs(efx); +} + /* This call is responsible for hooking in the MAC and PHY operations */ int falcon_probe_port(struct efx_nic *efx) { @@ -2194,9 +2330,9 @@ int falcon_probe_port(struct efx_nic *efx) /* Hardware flow ctrl. FalconA RX FIFO too small for pause generation */ if (falcon_rev(efx) >= FALCON_REV_B0) - efx->flow_control = EFX_FC_RX | EFX_FC_TX; + efx->wanted_fc = EFX_FC_RX | EFX_FC_TX; else - efx->flow_control = EFX_FC_RX; + efx->wanted_fc = EFX_FC_RX; /* Allocate buffer for stats */ rc = falcon_alloc_buffer(efx, &efx->stats_buffer, @@ -2253,13 +2389,18 @@ int falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out) __le16 *word, *limit; u32 csum; - region = kmalloc(NVCONFIG_END, GFP_KERNEL); + spi = efx->spi_flash ? efx->spi_flash : efx->spi_eeprom; + if (!spi) + return -EINVAL; + + region = kmalloc(FALCON_NVCONFIG_END, GFP_KERNEL); if (!region) return -ENOMEM; nvconfig = region + NVCONFIG_OFFSET; - spi = efx->spi_flash ? efx->spi_flash : efx->spi_eeprom; - rc = falcon_spi_read(spi, 0, NVCONFIG_END, NULL, region); + mutex_lock(&efx->spi_lock); + rc = falcon_spi_read(spi, 0, FALCON_NVCONFIG_END, NULL, region); + mutex_unlock(&efx->spi_lock); if (rc) { EFX_ERR(efx, "Failed to read %s\n", efx->spi_flash ? "flash" : "EEPROM"); @@ -2283,7 +2424,7 @@ int falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out) limit = (__le16 *) (nvconfig + 1); } else { word = region; - limit = region + NVCONFIG_END; + limit = region + FALCON_NVCONFIG_END; } for (csum = 0; word < limit; ++word) csum += le16_to_cpu(*word); @@ -2325,6 +2466,10 @@ static struct { EFX_OWORD32(0x000003FF, 0x00000000, 0x00000000, 0x00000000) }, { DP_CTRL_REG, EFX_OWORD32(0x00000FFF, 0x00000000, 0x00000000, 0x00000000) }, + { GM_CFG2_REG, + EFX_OWORD32(0x00007337, 0x00000000, 0x00000000, 0x00000000) }, + { GMF_CFG0_REG, + EFX_OWORD32(0x00001F1F, 0x00000000, 0x00000000, 0x00000000) }, { XM_GLB_CFG_REG, EFX_OWORD32(0x00000C68, 0x00000000, 0x00000000, 0x00000000) }, { XM_TX_CFG_REG, @@ -2545,7 +2690,7 @@ static int falcon_spi_device_init(struct efx_nic *efx, struct efx_spi_device *spi_device; if (device_type != 0) { - spi_device = kmalloc(sizeof(*spi_device), GFP_KERNEL); + spi_device = kzalloc(sizeof(*spi_device), GFP_KERNEL); if (!spi_device) return -ENOMEM; spi_device->device_id = device_id; @@ -2555,6 +2700,11 @@ static int falcon_spi_device_init(struct efx_nic *efx, SPI_DEV_TYPE_FIELD(device_type, SPI_DEV_TYPE_ADDR_LEN); spi_device->munge_address = (spi_device->size == 1 << 9 && spi_device->addr_len == 1); + spi_device->erase_command = + SPI_DEV_TYPE_FIELD(device_type, SPI_DEV_TYPE_ERASE_CMD); + spi_device->erase_size = + 1 << SPI_DEV_TYPE_FIELD(device_type, + SPI_DEV_TYPE_ERASE_SIZE); spi_device->block_size = 1 << SPI_DEV_TYPE_FIELD(device_type, SPI_DEV_TYPE_BLOCK_SIZE); @@ -2645,6 +2795,7 @@ static int falcon_probe_nvconfig(struct efx_nic *efx) static int falcon_probe_nic_variant(struct efx_nic *efx) { efx_oword_t altera_build; + efx_oword_t nic_stat; falcon_read(efx, &altera_build, ALTERA_BUILD_REG_KER); if (EFX_OWORD_FIELD(altera_build, VER_ALL)) { @@ -2652,27 +2803,20 @@ static int falcon_probe_nic_variant(struct efx_nic *efx) return -ENODEV; } + falcon_read(efx, &nic_stat, NIC_STAT_REG); + switch (falcon_rev(efx)) { case FALCON_REV_A0: case 0xff: EFX_ERR(efx, "Falcon rev A0 not supported\n"); return -ENODEV; - case FALCON_REV_A1:{ - efx_oword_t nic_stat; - - falcon_read(efx, &nic_stat, NIC_STAT_REG); - + case FALCON_REV_A1: if (EFX_OWORD_FIELD(nic_stat, STRAP_PCIE) == 0) { EFX_ERR(efx, "Falcon rev A1 PCI-X not supported\n"); return -ENODEV; } - if (!EFX_OWORD_FIELD(nic_stat, STRAP_10G)) { - EFX_ERR(efx, "1G mode not supported\n"); - return -ENODEV; - } break; - } case FALCON_REV_B0: break; @@ -2682,6 +2826,9 @@ static int falcon_probe_nic_variant(struct efx_nic *efx) return -ENODEV; } + /* Initial assumed speed */ + efx->link_speed = EFX_OWORD_FIELD(nic_stat, STRAP_10G) ? 10000 : 1000; + return 0; } @@ -2689,80 +2836,37 @@ static int falcon_probe_nic_variant(struct efx_nic *efx) static void falcon_probe_spi_devices(struct efx_nic *efx) { efx_oword_t nic_stat, gpio_ctl, ee_vpd_cfg; - bool has_flash, has_eeprom, boot_is_external; + int boot_dev; falcon_read(efx, &gpio_ctl, GPIO_CTL_REG_KER); falcon_read(efx, &nic_stat, NIC_STAT_REG); falcon_read(efx, &ee_vpd_cfg, EE_VPD_CFG_REG_KER); - has_flash = EFX_OWORD_FIELD(nic_stat, SF_PRST); - has_eeprom = EFX_OWORD_FIELD(nic_stat, EE_PRST); - boot_is_external = EFX_OWORD_FIELD(gpio_ctl, BOOTED_USING_NVDEVICE); - - if (has_flash) { - /* Default flash SPI device: Atmel AT25F1024 - * 128 KB, 24-bit address, 32 KB erase block, - * 256 B write block - */ - u32 flash_device_type = - (17 << SPI_DEV_TYPE_SIZE_LBN) - | (3 << SPI_DEV_TYPE_ADDR_LEN_LBN) - | (0x52 << SPI_DEV_TYPE_ERASE_CMD_LBN) - | (15 << SPI_DEV_TYPE_ERASE_SIZE_LBN) - | (8 << SPI_DEV_TYPE_BLOCK_SIZE_LBN); - - falcon_spi_device_init(efx, &efx->spi_flash, - EE_SPI_FLASH, flash_device_type); - - if (!boot_is_external) { - /* Disable VPD and set clock dividers to safe - * values for initial programming. - */ - EFX_LOG(efx, "Booted from internal ASIC settings;" - " setting SPI config\n"); - EFX_POPULATE_OWORD_3(ee_vpd_cfg, EE_VPD_EN, 0, - /* 125 MHz / 7 ~= 20 MHz */ - EE_SF_CLOCK_DIV, 7, - /* 125 MHz / 63 ~= 2 MHz */ - EE_EE_CLOCK_DIV, 63); - falcon_write(efx, &ee_vpd_cfg, EE_VPD_CFG_REG_KER); - } - } - - if (has_eeprom) { - u32 eeprom_device_type; - - /* If it has no flash, it must have a large EEPROM - * for chip config; otherwise check whether 9-bit - * addressing is used for VPD configuration - */ - if (has_flash && - (!boot_is_external || - EFX_OWORD_FIELD(ee_vpd_cfg, EE_VPD_EN_AD9_MODE))) { - /* Default SPI device: Atmel AT25040 or similar - * 512 B, 9-bit address, 8 B write block - */ - eeprom_device_type = - (9 << SPI_DEV_TYPE_SIZE_LBN) - | (1 << SPI_DEV_TYPE_ADDR_LEN_LBN) - | (3 << SPI_DEV_TYPE_BLOCK_SIZE_LBN); - } else { - /* "Large" SPI device: Atmel AT25640 or similar - * 8 KB, 16-bit address, 32 B write block - */ - eeprom_device_type = - (13 << SPI_DEV_TYPE_SIZE_LBN) - | (2 << SPI_DEV_TYPE_ADDR_LEN_LBN) - | (5 << SPI_DEV_TYPE_BLOCK_SIZE_LBN); - } - - falcon_spi_device_init(efx, &efx->spi_eeprom, - EE_SPI_EEPROM, eeprom_device_type); - } - - EFX_LOG(efx, "flash is %s, EEPROM is %s\n", - (has_flash ? "present" : "absent"), - (has_eeprom ? "present" : "absent")); + if (EFX_OWORD_FIELD(gpio_ctl, BOOTED_USING_NVDEVICE)) { + boot_dev = (EFX_OWORD_FIELD(nic_stat, SF_PRST) ? + EE_SPI_FLASH : EE_SPI_EEPROM); + EFX_LOG(efx, "Booted from %s\n", + boot_dev == EE_SPI_FLASH ? "flash" : "EEPROM"); + } else { + /* Disable VPD and set clock dividers to safe + * values for initial programming. */ + boot_dev = -1; + EFX_LOG(efx, "Booted from internal ASIC settings;" + " setting SPI config\n"); + EFX_POPULATE_OWORD_3(ee_vpd_cfg, EE_VPD_EN, 0, + /* 125 MHz / 7 ~= 20 MHz */ + EE_SF_CLOCK_DIV, 7, + /* 125 MHz / 63 ~= 2 MHz */ + EE_EE_CLOCK_DIV, 63); + falcon_write(efx, &ee_vpd_cfg, EE_VPD_CFG_REG_KER); + } + + if (boot_dev == EE_SPI_FLASH) + falcon_spi_device_init(efx, &efx->spi_flash, EE_SPI_FLASH, + default_flash_type); + if (boot_dev == EE_SPI_EEPROM) + falcon_spi_device_init(efx, &efx->spi_eeprom, EE_SPI_EEPROM, + large_eeprom_type); } int falcon_probe_nic(struct efx_nic *efx) @@ -2825,10 +2929,10 @@ int falcon_probe_nic(struct efx_nic *efx) goto fail5; /* Initialise I2C adapter */ - efx->i2c_adap.owner = THIS_MODULE; + efx->i2c_adap.owner = THIS_MODULE; nic_data->i2c_data = falcon_i2c_bit_operations; nic_data->i2c_data.data = efx; - efx->i2c_adap.algo_data = &nic_data->i2c_data; + efx->i2c_adap.algo_data = &nic_data->i2c_data; efx->i2c_adap.dev.parent = &efx->pci_dev->dev; strlcpy(efx->i2c_adap.name, "SFC4000 GPIO", sizeof(efx->i2c_adap.name)); rc = i2c_bit_add_bus(&efx->i2c_adap); @@ -2862,20 +2966,18 @@ int falcon_init_nic(struct efx_nic *efx) unsigned thresh; int rc; - /* Set up the address region register. This is only needed - * for the B0 FPGA, but since we are just pushing in the - * reset defaults this may as well be unconditional. */ - EFX_POPULATE_OWORD_4(temp, ADR_REGION0, 0, - ADR_REGION1, (1 << 16), - ADR_REGION2, (2 << 16), - ADR_REGION3, (3 << 16)); - falcon_write(efx, &temp, ADR_REGION_REG_KER); - /* Use on-chip SRAM */ falcon_read(efx, &temp, NIC_STAT_REG); EFX_SET_OWORD_FIELD(temp, ONCHIP_SRAM, 1); falcon_write(efx, &temp, NIC_STAT_REG); + /* Set the source of the GMAC clock */ + if (falcon_rev(efx) == FALCON_REV_B0) { + falcon_read(efx, &temp, GPIO_CTL_REG_KER); + EFX_SET_OWORD_FIELD(temp, GPIO_USE_NIC_CLK, true); + falcon_write(efx, &temp, GPIO_CTL_REG_KER); + } + /* Set buffer table mode */ EFX_POPULATE_OWORD_1(temp, BUF_TBL_MODE, BUF_TBL_MODE_FULL); falcon_write(efx, &temp, BUF_TBL_CFG_REG_KER); diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h index be025ba7a6c6215c0ae2a2e8a3d166cc8f73063c..7869c3d74383cc971e818bda22ec5fc78cbf2395 100644 --- a/drivers/net/sfc/falcon.h +++ b/drivers/net/sfc/falcon.h @@ -12,6 +12,7 @@ #define EFX_FALCON_H #include "net_driver.h" +#include "efx.h" /* * Falcon hardware control @@ -65,6 +66,7 @@ extern int falcon_probe_port(struct efx_nic *efx); extern void falcon_remove_port(struct efx_nic *efx); /* MAC/PHY */ +extern int falcon_switch_mac(struct efx_nic *efx); extern bool falcon_xaui_link_ok(struct efx_nic *efx); extern int falcon_dma_stats(struct efx_nic *efx, unsigned int done_offset); @@ -77,6 +79,7 @@ extern int falcon_init_interrupt(struct efx_nic *efx); extern void falcon_enable_interrupts(struct efx_nic *efx); extern void falcon_generate_test_event(struct efx_channel *channel, unsigned int magic); +extern void falcon_sim_phy_event(struct efx_nic *efx); extern void falcon_generate_interrupt(struct efx_nic *efx); extern void falcon_set_int_moderation(struct efx_channel *channel); extern void falcon_disable_interrupts(struct efx_nic *efx); diff --git a/drivers/net/sfc/falcon_gmac.c b/drivers/net/sfc/falcon_gmac.c new file mode 100644 index 0000000000000000000000000000000000000000..8865eae20ac51ef0c40b6032ff38906e3f46b16d --- /dev/null +++ b/drivers/net/sfc/falcon_gmac.c @@ -0,0 +1,229 @@ +/**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards + * Copyright 2005-2006 Fen Systems Ltd. + * Copyright 2006-2008 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + */ + +#include +#include "net_driver.h" +#include "efx.h" +#include "falcon.h" +#include "mac.h" +#include "falcon_hwdefs.h" +#include "falcon_io.h" +#include "gmii.h" + +/************************************************************************** + * + * MAC operations + * + *************************************************************************/ + +static void falcon_reconfigure_gmac(struct efx_nic *efx) +{ + bool loopback, tx_fc, rx_fc, bytemode; + int if_mode; + unsigned int max_frame_len; + efx_oword_t reg; + + /* Configuration register 1 */ + tx_fc = (efx->link_fc & EFX_FC_TX) || !efx->link_fd; + rx_fc = !!(efx->link_fc & EFX_FC_RX); + loopback = (efx->loopback_mode == LOOPBACK_GMAC); + bytemode = (efx->link_speed == 1000); + + EFX_POPULATE_OWORD_5(reg, + GM_LOOP, loopback, + GM_TX_EN, 1, + GM_TX_FC_EN, tx_fc, + GM_RX_EN, 1, + GM_RX_FC_EN, rx_fc); + falcon_write(efx, ®, GM_CFG1_REG); + udelay(10); + + /* Configuration register 2 */ + if_mode = (bytemode) ? 2 : 1; + EFX_POPULATE_OWORD_5(reg, + GM_IF_MODE, if_mode, + GM_PAD_CRC_EN, 1, + GM_LEN_CHK, 1, + GM_FD, efx->link_fd, + GM_PAMBL_LEN, 0x7/*datasheet recommended */); + + falcon_write(efx, ®, GM_CFG2_REG); + udelay(10); + + /* Max frame len register */ + max_frame_len = EFX_MAX_FRAME_LEN(efx->net_dev->mtu); + EFX_POPULATE_OWORD_1(reg, GM_MAX_FLEN, max_frame_len); + falcon_write(efx, ®, GM_MAX_FLEN_REG); + udelay(10); + + /* FIFO configuration register 0 */ + EFX_POPULATE_OWORD_5(reg, + GMF_FTFENREQ, 1, + GMF_STFENREQ, 1, + GMF_FRFENREQ, 1, + GMF_SRFENREQ, 1, + GMF_WTMENREQ, 1); + falcon_write(efx, ®, GMF_CFG0_REG); + udelay(10); + + /* FIFO configuration register 1 */ + EFX_POPULATE_OWORD_2(reg, + GMF_CFGFRTH, 0x12, + GMF_CFGXOFFRTX, 0xffff); + falcon_write(efx, ®, GMF_CFG1_REG); + udelay(10); + + /* FIFO configuration register 2 */ + EFX_POPULATE_OWORD_2(reg, + GMF_CFGHWM, 0x3f, + GMF_CFGLWM, 0xa); + falcon_write(efx, ®, GMF_CFG2_REG); + udelay(10); + + /* FIFO configuration register 3 */ + EFX_POPULATE_OWORD_2(reg, + GMF_CFGHWMFT, 0x1c, + GMF_CFGFTTH, 0x08); + falcon_write(efx, ®, GMF_CFG3_REG); + udelay(10); + + /* FIFO configuration register 4 */ + EFX_POPULATE_OWORD_1(reg, GMF_HSTFLTRFRM_PAUSE, 1); + falcon_write(efx, ®, GMF_CFG4_REG); + udelay(10); + + /* FIFO configuration register 5 */ + falcon_read(efx, ®, GMF_CFG5_REG); + EFX_SET_OWORD_FIELD(reg, GMF_CFGBYTMODE, bytemode); + EFX_SET_OWORD_FIELD(reg, GMF_CFGHDPLX, !efx->link_fd); + EFX_SET_OWORD_FIELD(reg, GMF_HSTDRPLT64, !efx->link_fd); + EFX_SET_OWORD_FIELD(reg, GMF_HSTFLTRFRMDC_PAUSE, 0); + falcon_write(efx, ®, GMF_CFG5_REG); + udelay(10); + + /* MAC address */ + EFX_POPULATE_OWORD_4(reg, + GM_HWADDR_5, efx->net_dev->dev_addr[5], + GM_HWADDR_4, efx->net_dev->dev_addr[4], + GM_HWADDR_3, efx->net_dev->dev_addr[3], + GM_HWADDR_2, efx->net_dev->dev_addr[2]); + falcon_write(efx, ®, GM_ADR1_REG); + udelay(10); + EFX_POPULATE_OWORD_2(reg, + GM_HWADDR_1, efx->net_dev->dev_addr[1], + GM_HWADDR_0, efx->net_dev->dev_addr[0]); + falcon_write(efx, ®, GM_ADR2_REG); + udelay(10); + + falcon_reconfigure_mac_wrapper(efx); +} + +static void falcon_update_stats_gmac(struct efx_nic *efx) +{ + struct efx_mac_stats *mac_stats = &efx->mac_stats; + unsigned long old_rx_pause, old_tx_pause; + unsigned long new_rx_pause, new_tx_pause; + int rc; + + rc = falcon_dma_stats(efx, GDmaDone_offset); + if (rc) + return; + + /* Pause frames are erroneously counted as errors (SFC bug 3269) */ + old_rx_pause = mac_stats->rx_pause; + old_tx_pause = mac_stats->tx_pause; + + /* Update MAC stats from DMAed values */ + FALCON_STAT(efx, GRxGoodOct, rx_good_bytes); + FALCON_STAT(efx, GRxBadOct, rx_bad_bytes); + FALCON_STAT(efx, GRxMissPkt, rx_missed); + FALCON_STAT(efx, GRxFalseCRS, rx_false_carrier); + FALCON_STAT(efx, GRxPausePkt, rx_pause); + FALCON_STAT(efx, GRxBadPkt, rx_bad); + FALCON_STAT(efx, GRxUcastPkt, rx_unicast); + FALCON_STAT(efx, GRxMcastPkt, rx_multicast); + FALCON_STAT(efx, GRxBcastPkt, rx_broadcast); + FALCON_STAT(efx, GRxGoodLt64Pkt, rx_good_lt64); + FALCON_STAT(efx, GRxBadLt64Pkt, rx_bad_lt64); + FALCON_STAT(efx, GRx64Pkt, rx_64); + FALCON_STAT(efx, GRx65to127Pkt, rx_65_to_127); + FALCON_STAT(efx, GRx128to255Pkt, rx_128_to_255); + FALCON_STAT(efx, GRx256to511Pkt, rx_256_to_511); + FALCON_STAT(efx, GRx512to1023Pkt, rx_512_to_1023); + FALCON_STAT(efx, GRx1024to15xxPkt, rx_1024_to_15xx); + FALCON_STAT(efx, GRx15xxtoJumboPkt, rx_15xx_to_jumbo); + FALCON_STAT(efx, GRxGtJumboPkt, rx_gtjumbo); + FALCON_STAT(efx, GRxFcsErr64to15xxPkt, rx_bad_64_to_15xx); + FALCON_STAT(efx, GRxFcsErr15xxtoJumboPkt, rx_bad_15xx_to_jumbo); + FALCON_STAT(efx, GRxFcsErrGtJumboPkt, rx_bad_gtjumbo); + FALCON_STAT(efx, GTxGoodBadOct, tx_bytes); + FALCON_STAT(efx, GTxGoodOct, tx_good_bytes); + FALCON_STAT(efx, GTxSglColPkt, tx_single_collision); + FALCON_STAT(efx, GTxMultColPkt, tx_multiple_collision); + FALCON_STAT(efx, GTxExColPkt, tx_excessive_collision); + FALCON_STAT(efx, GTxDefPkt, tx_deferred); + FALCON_STAT(efx, GTxLateCol, tx_late_collision); + FALCON_STAT(efx, GTxExDefPkt, tx_excessive_deferred); + FALCON_STAT(efx, GTxPausePkt, tx_pause); + FALCON_STAT(efx, GTxBadPkt, tx_bad); + FALCON_STAT(efx, GTxUcastPkt, tx_unicast); + FALCON_STAT(efx, GTxMcastPkt, tx_multicast); + FALCON_STAT(efx, GTxBcastPkt, tx_broadcast); + FALCON_STAT(efx, GTxLt64Pkt, tx_lt64); + FALCON_STAT(efx, GTx64Pkt, tx_64); + FALCON_STAT(efx, GTx65to127Pkt, tx_65_to_127); + FALCON_STAT(efx, GTx128to255Pkt, tx_128_to_255); + FALCON_STAT(efx, GTx256to511Pkt, tx_256_to_511); + FALCON_STAT(efx, GTx512to1023Pkt, tx_512_to_1023); + FALCON_STAT(efx, GTx1024to15xxPkt, tx_1024_to_15xx); + FALCON_STAT(efx, GTx15xxtoJumboPkt, tx_15xx_to_jumbo); + FALCON_STAT(efx, GTxGtJumboPkt, tx_gtjumbo); + FALCON_STAT(efx, GTxNonTcpUdpPkt, tx_non_tcpudp); + FALCON_STAT(efx, GTxMacSrcErrPkt, tx_mac_src_error); + FALCON_STAT(efx, GTxIpSrcErrPkt, tx_ip_src_error); + + /* Pause frames are erroneously counted as errors (SFC bug 3269) */ + new_rx_pause = mac_stats->rx_pause; + new_tx_pause = mac_stats->tx_pause; + mac_stats->rx_bad -= (new_rx_pause - old_rx_pause); + mac_stats->tx_bad -= (new_tx_pause - old_tx_pause); + + /* Derive stats that the MAC doesn't provide directly */ + mac_stats->tx_bad_bytes = + mac_stats->tx_bytes - mac_stats->tx_good_bytes; + mac_stats->tx_packets = + mac_stats->tx_lt64 + mac_stats->tx_64 + + mac_stats->tx_65_to_127 + mac_stats->tx_128_to_255 + + mac_stats->tx_256_to_511 + mac_stats->tx_512_to_1023 + + mac_stats->tx_1024_to_15xx + mac_stats->tx_15xx_to_jumbo + + mac_stats->tx_gtjumbo; + mac_stats->tx_collision = + mac_stats->tx_single_collision + + mac_stats->tx_multiple_collision + + mac_stats->tx_excessive_collision + + mac_stats->tx_late_collision; + mac_stats->rx_bytes = + mac_stats->rx_good_bytes + mac_stats->rx_bad_bytes; + mac_stats->rx_packets = + mac_stats->rx_good_lt64 + mac_stats->rx_bad_lt64 + + mac_stats->rx_64 + mac_stats->rx_65_to_127 + + mac_stats->rx_128_to_255 + mac_stats->rx_256_to_511 + + mac_stats->rx_512_to_1023 + mac_stats->rx_1024_to_15xx + + mac_stats->rx_15xx_to_jumbo + mac_stats->rx_gtjumbo; + mac_stats->rx_good = mac_stats->rx_packets - mac_stats->rx_bad; + mac_stats->rx_lt64 = mac_stats->rx_good_lt64 + mac_stats->rx_bad_lt64; +} + +struct efx_mac_operations falcon_gmac_operations = { + .reconfigure = falcon_reconfigure_gmac, + .update_stats = falcon_update_stats_gmac, + .irq = efx_port_dummy_op_void, + .poll = efx_port_dummy_op_void, +}; diff --git a/drivers/net/sfc/falcon_hwdefs.h b/drivers/net/sfc/falcon_hwdefs.h index 5d584b0dbb517043c05ce3d7050ffd999932ce2f..bda8d5bb72e49476a26d92cb8a7692ef519814b7 100644 --- a/drivers/net/sfc/falcon_hwdefs.h +++ b/drivers/net/sfc/falcon_hwdefs.h @@ -111,12 +111,18 @@ /* NIC status register */ #define NIC_STAT_REG 0x0200 +#define EE_STRAP_EN_LBN 31 +#define EE_STRAP_EN_WIDTH 1 +#define EE_STRAP_OVR_LBN 24 +#define EE_STRAP_OVR_WIDTH 4 #define ONCHIP_SRAM_LBN 16 #define ONCHIP_SRAM_WIDTH 1 #define SF_PRST_LBN 9 #define SF_PRST_WIDTH 1 #define EE_PRST_LBN 8 #define EE_PRST_WIDTH 1 +#define STRAP_PINS_LBN 0 +#define STRAP_PINS_WIDTH 3 /* These bit definitions are extrapolated from the list of numerical * values for STRAP_PINS. */ @@ -130,6 +136,8 @@ /* GPIO control register */ #define GPIO_CTL_REG_KER 0x0210 +#define GPIO_USE_NIC_CLK_LBN (30) +#define GPIO_USE_NIC_CLK_WIDTH (1) #define GPIO_OUTPUTS_LBN (16) #define GPIO_OUTPUTS_WIDTH (4) #define GPIO_INPUTS_LBN (8) @@ -492,6 +500,107 @@ #define MAC_MCAST_HASH_REG0_KER 0xca0 #define MAC_MCAST_HASH_REG1_KER 0xcb0 +/* GMAC configuration register 1 */ +#define GM_CFG1_REG 0xe00 +#define GM_SW_RST_LBN 31 +#define GM_SW_RST_WIDTH 1 +#define GM_LOOP_LBN 8 +#define GM_LOOP_WIDTH 1 +#define GM_RX_FC_EN_LBN 5 +#define GM_RX_FC_EN_WIDTH 1 +#define GM_TX_FC_EN_LBN 4 +#define GM_TX_FC_EN_WIDTH 1 +#define GM_RX_EN_LBN 2 +#define GM_RX_EN_WIDTH 1 +#define GM_TX_EN_LBN 0 +#define GM_TX_EN_WIDTH 1 + +/* GMAC configuration register 2 */ +#define GM_CFG2_REG 0xe10 +#define GM_PAMBL_LEN_LBN 12 +#define GM_PAMBL_LEN_WIDTH 4 +#define GM_IF_MODE_LBN 8 +#define GM_IF_MODE_WIDTH 2 +#define GM_LEN_CHK_LBN 4 +#define GM_LEN_CHK_WIDTH 1 +#define GM_PAD_CRC_EN_LBN 2 +#define GM_PAD_CRC_EN_WIDTH 1 +#define GM_FD_LBN 0 +#define GM_FD_WIDTH 1 + +/* GMAC maximum frame length register */ +#define GM_MAX_FLEN_REG 0xe40 +#define GM_MAX_FLEN_LBN 0 +#define GM_MAX_FLEN_WIDTH 16 + +/* GMAC station address register 1 */ +#define GM_ADR1_REG 0xf00 +#define GM_HWADDR_5_LBN 24 +#define GM_HWADDR_5_WIDTH 8 +#define GM_HWADDR_4_LBN 16 +#define GM_HWADDR_4_WIDTH 8 +#define GM_HWADDR_3_LBN 8 +#define GM_HWADDR_3_WIDTH 8 +#define GM_HWADDR_2_LBN 0 +#define GM_HWADDR_2_WIDTH 8 + +/* GMAC station address register 2 */ +#define GM_ADR2_REG 0xf10 +#define GM_HWADDR_1_LBN 24 +#define GM_HWADDR_1_WIDTH 8 +#define GM_HWADDR_0_LBN 16 +#define GM_HWADDR_0_WIDTH 8 + +/* GMAC FIFO configuration register 0 */ +#define GMF_CFG0_REG 0xf20 +#define GMF_FTFENREQ_LBN 12 +#define GMF_FTFENREQ_WIDTH 1 +#define GMF_STFENREQ_LBN 11 +#define GMF_STFENREQ_WIDTH 1 +#define GMF_FRFENREQ_LBN 10 +#define GMF_FRFENREQ_WIDTH 1 +#define GMF_SRFENREQ_LBN 9 +#define GMF_SRFENREQ_WIDTH 1 +#define GMF_WTMENREQ_LBN 8 +#define GMF_WTMENREQ_WIDTH 1 + +/* GMAC FIFO configuration register 1 */ +#define GMF_CFG1_REG 0xf30 +#define GMF_CFGFRTH_LBN 16 +#define GMF_CFGFRTH_WIDTH 5 +#define GMF_CFGXOFFRTX_LBN 0 +#define GMF_CFGXOFFRTX_WIDTH 16 + +/* GMAC FIFO configuration register 2 */ +#define GMF_CFG2_REG 0xf40 +#define GMF_CFGHWM_LBN 16 +#define GMF_CFGHWM_WIDTH 6 +#define GMF_CFGLWM_LBN 0 +#define GMF_CFGLWM_WIDTH 6 + +/* GMAC FIFO configuration register 3 */ +#define GMF_CFG3_REG 0xf50 +#define GMF_CFGHWMFT_LBN 16 +#define GMF_CFGHWMFT_WIDTH 6 +#define GMF_CFGFTTH_LBN 0 +#define GMF_CFGFTTH_WIDTH 6 + +/* GMAC FIFO configuration register 4 */ +#define GMF_CFG4_REG 0xf60 +#define GMF_HSTFLTRFRM_PAUSE_LBN 12 +#define GMF_HSTFLTRFRM_PAUSE_WIDTH 12 + +/* GMAC FIFO configuration register 5 */ +#define GMF_CFG5_REG 0xf70 +#define GMF_CFGHDPLX_LBN 22 +#define GMF_CFGHDPLX_WIDTH 1 +#define GMF_CFGBYTMODE_LBN 19 +#define GMF_CFGBYTMODE_WIDTH 1 +#define GMF_HSTDRPLT64_LBN 18 +#define GMF_HSTDRPLT64_WIDTH 1 +#define GMF_HSTFLTRFRMDC_PAUSE_LBN 12 +#define GMF_HSTFLTRFRMDC_PAUSE_WIDTH 1 + /* XGMAC address register low */ #define XM_ADR_LO_REG 0x1200 #define XM_ADR_3_LBN 24 @@ -944,6 +1053,8 @@ #define XG_MNT_INTR_B0_WIDTH 1 #define RX_RECOVERY_A1_LBN 11 #define RX_RECOVERY_A1_WIDTH 1 +#define XFP_PHY_INTR_LBN 10 +#define XFP_PHY_INTR_WIDTH 1 #define XG_PHY_INTR_LBN 9 #define XG_PHY_INTR_WIDTH 1 #define G_PHY1_INTR_LBN 8 @@ -962,54 +1073,103 @@ ************************************************************************** * */ + #define GRxGoodOct_offset 0x0 +#define GRxGoodOct_WIDTH 48 #define GRxBadOct_offset 0x8 +#define GRxBadOct_WIDTH 48 #define GRxMissPkt_offset 0x10 +#define GRxMissPkt_WIDTH 32 #define GRxFalseCRS_offset 0x14 +#define GRxFalseCRS_WIDTH 32 #define GRxPausePkt_offset 0x18 +#define GRxPausePkt_WIDTH 32 #define GRxBadPkt_offset 0x1C +#define GRxBadPkt_WIDTH 32 #define GRxUcastPkt_offset 0x20 +#define GRxUcastPkt_WIDTH 32 #define GRxMcastPkt_offset 0x24 +#define GRxMcastPkt_WIDTH 32 #define GRxBcastPkt_offset 0x28 +#define GRxBcastPkt_WIDTH 32 #define GRxGoodLt64Pkt_offset 0x2C +#define GRxGoodLt64Pkt_WIDTH 32 #define GRxBadLt64Pkt_offset 0x30 +#define GRxBadLt64Pkt_WIDTH 32 #define GRx64Pkt_offset 0x34 +#define GRx64Pkt_WIDTH 32 #define GRx65to127Pkt_offset 0x38 +#define GRx65to127Pkt_WIDTH 32 #define GRx128to255Pkt_offset 0x3C +#define GRx128to255Pkt_WIDTH 32 #define GRx256to511Pkt_offset 0x40 +#define GRx256to511Pkt_WIDTH 32 #define GRx512to1023Pkt_offset 0x44 +#define GRx512to1023Pkt_WIDTH 32 #define GRx1024to15xxPkt_offset 0x48 +#define GRx1024to15xxPkt_WIDTH 32 #define GRx15xxtoJumboPkt_offset 0x4C +#define GRx15xxtoJumboPkt_WIDTH 32 #define GRxGtJumboPkt_offset 0x50 +#define GRxGtJumboPkt_WIDTH 32 #define GRxFcsErr64to15xxPkt_offset 0x54 +#define GRxFcsErr64to15xxPkt_WIDTH 32 #define GRxFcsErr15xxtoJumboPkt_offset 0x58 +#define GRxFcsErr15xxtoJumboPkt_WIDTH 32 #define GRxFcsErrGtJumboPkt_offset 0x5C +#define GRxFcsErrGtJumboPkt_WIDTH 32 #define GTxGoodBadOct_offset 0x80 +#define GTxGoodBadOct_WIDTH 48 #define GTxGoodOct_offset 0x88 +#define GTxGoodOct_WIDTH 48 #define GTxSglColPkt_offset 0x90 +#define GTxSglColPkt_WIDTH 32 #define GTxMultColPkt_offset 0x94 +#define GTxMultColPkt_WIDTH 32 #define GTxExColPkt_offset 0x98 +#define GTxExColPkt_WIDTH 32 #define GTxDefPkt_offset 0x9C +#define GTxDefPkt_WIDTH 32 #define GTxLateCol_offset 0xA0 +#define GTxLateCol_WIDTH 32 #define GTxExDefPkt_offset 0xA4 +#define GTxExDefPkt_WIDTH 32 #define GTxPausePkt_offset 0xA8 +#define GTxPausePkt_WIDTH 32 #define GTxBadPkt_offset 0xAC +#define GTxBadPkt_WIDTH 32 #define GTxUcastPkt_offset 0xB0 +#define GTxUcastPkt_WIDTH 32 #define GTxMcastPkt_offset 0xB4 +#define GTxMcastPkt_WIDTH 32 #define GTxBcastPkt_offset 0xB8 +#define GTxBcastPkt_WIDTH 32 #define GTxLt64Pkt_offset 0xBC +#define GTxLt64Pkt_WIDTH 32 #define GTx64Pkt_offset 0xC0 +#define GTx64Pkt_WIDTH 32 #define GTx65to127Pkt_offset 0xC4 +#define GTx65to127Pkt_WIDTH 32 #define GTx128to255Pkt_offset 0xC8 +#define GTx128to255Pkt_WIDTH 32 #define GTx256to511Pkt_offset 0xCC +#define GTx256to511Pkt_WIDTH 32 #define GTx512to1023Pkt_offset 0xD0 +#define GTx512to1023Pkt_WIDTH 32 #define GTx1024to15xxPkt_offset 0xD4 +#define GTx1024to15xxPkt_WIDTH 32 #define GTx15xxtoJumboPkt_offset 0xD8 +#define GTx15xxtoJumboPkt_WIDTH 32 #define GTxGtJumboPkt_offset 0xDC +#define GTxGtJumboPkt_WIDTH 32 #define GTxNonTcpUdpPkt_offset 0xE0 +#define GTxNonTcpUdpPkt_WIDTH 16 #define GTxMacSrcErrPkt_offset 0xE4 +#define GTxMacSrcErrPkt_WIDTH 16 #define GTxIpSrcErrPkt_offset 0xE8 +#define GTxIpSrcErrPkt_WIDTH 16 #define GDmaDone_offset 0xEC +#define GDmaDone_WIDTH 32 #define XgRxOctets_offset 0x0 #define XgRxOctets_WIDTH 48 @@ -1150,7 +1310,6 @@ struct falcon_nvconfig_board_v3 { (((type) >> EFX_LOW_BIT(field)) & EFX_MASK32(EFX_WIDTH(field))) #define NVCONFIG_OFFSET 0x300 -#define NVCONFIG_END 0x400 #define NVCONFIG_BOARD_MAGIC_NUM 0xFA1C struct falcon_nvconfig { diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c index d4012314dd01f1af81c0ca7be57da7d4dc67a639..5a03713685acda98fe958ad5c1f50e7d93a8d3dc 100644 --- a/drivers/net/sfc/falcon_xmac.c +++ b/drivers/net/sfc/falcon_xmac.c @@ -15,7 +15,6 @@ #include "falcon_hwdefs.h" #include "falcon_io.h" #include "mac.h" -#include "gmii.h" #include "mdio_10g.h" #include "phy.h" #include "boards.h" @@ -26,24 +25,6 @@ * MAC operations * *************************************************************************/ -static int falcon_reset_xmac(struct efx_nic *efx) -{ - efx_oword_t reg; - int count; - - EFX_POPULATE_OWORD_1(reg, XM_CORE_RST, 1); - falcon_write(efx, ®, XM_GLB_CFG_REG); - - for (count = 0; count < 10000; count++) { /* wait upto 100ms */ - falcon_read(efx, ®, XM_GLB_CFG_REG); - if (EFX_OWORD_FIELD(reg, XM_CORE_RST) == 0) - return 0; - udelay(10); - } - - EFX_ERR(efx, "timed out waiting for XMAC core reset\n"); - return -ETIMEDOUT; -} /* Configure the XAUI driver that is an output from Falcon */ static void falcon_setup_xaui(struct efx_nic *efx) @@ -99,31 +80,20 @@ int falcon_reset_xaui(struct efx_nic *efx) return -ETIMEDOUT; } -static bool falcon_xgmii_status(struct efx_nic *efx) +static void falcon_mask_status_intr(struct efx_nic *efx, bool enable) { efx_oword_t reg; - if (falcon_rev(efx) < FALCON_REV_B0) - return true; - - /* The ISR latches, so clear it and re-read */ - falcon_read(efx, ®, XM_MGT_INT_REG_B0); - falcon_read(efx, ®, XM_MGT_INT_REG_B0); - - if (EFX_OWORD_FIELD(reg, XM_LCLFLT) || - EFX_OWORD_FIELD(reg, XM_RMTFLT)) { - EFX_INFO(efx, "MGT_INT: "EFX_DWORD_FMT"\n", EFX_DWORD_VAL(reg)); - return false; - } - - return true; -} + if ((falcon_rev(efx) != FALCON_REV_B0) || LOOPBACK_INTERNAL(efx)) + return; -static void falcon_mask_status_intr(struct efx_nic *efx, bool enable) -{ - efx_oword_t reg; + /* We expect xgmii faults if the wireside link is up */ + if (!EFX_WORKAROUND_5147(efx) || !efx->link_up) + return; - if ((falcon_rev(efx) < FALCON_REV_B0) || LOOPBACK_INTERNAL(efx)) + /* We can only use this interrupt to signal the negative edge of + * xaui_align [we have to poll the positive edge]. */ + if (!efx->mac_up) return; /* Flush the ISR */ @@ -136,35 +106,7 @@ static void falcon_mask_status_intr(struct efx_nic *efx, bool enable) falcon_write(efx, ®, XM_MGT_INT_MSK_REG_B0); } -int falcon_init_xmac(struct efx_nic *efx) -{ - int rc; - - /* Initialize the PHY first so the clock is around */ - rc = efx->phy_op->init(efx); - if (rc) - goto fail1; - - rc = falcon_reset_xaui(efx); - if (rc) - goto fail2; - - /* Wait again. Give the PHY and MAC time to come back */ - schedule_timeout_uninterruptible(HZ / 10); - - rc = falcon_reset_xmac(efx); - if (rc) - goto fail2; - - falcon_mask_status_intr(efx, true); - return 0; - - fail2: - efx->phy_op->fini(efx); - fail1: - return rc; -} - +/* Get status of XAUI link */ bool falcon_xaui_link_ok(struct efx_nic *efx) { efx_oword_t reg; @@ -188,18 +130,10 @@ bool falcon_xaui_link_ok(struct efx_nic *efx) EFX_SET_OWORD_FIELD(reg, XX_DISPERR, XX_DISPERR_RESET); falcon_write(efx, ®, XX_CORE_STAT_REG); - /* If the link is up, then check the phy side of the xaui link - * (error conditions from the wire side propoagate back through - * the phy to the xaui side). */ - if (efx->link_up && link_ok) { + /* If the link is up, then check the phy side of the xaui link */ + if (efx->link_up && link_ok) if (efx->phy_op->mmds & (1 << MDIO_MMD_PHYXS)) link_ok = mdio_clause45_phyxgxs_lane_sync(efx); - } - - /* If the PHY and XAUI links are up, then check the mac's xgmii - * fault state */ - if (efx->link_up && link_ok) - link_ok = falcon_xgmii_status(efx); return link_ok; } @@ -208,7 +142,7 @@ static void falcon_reconfigure_xmac_core(struct efx_nic *efx) { unsigned int max_frame_len; efx_oword_t reg; - bool rx_fc = !!(efx->flow_control & EFX_FC_RX); + bool rx_fc = !!(efx->link_fc & EFX_FC_RX); /* Configure MAC - cut-thru mode is hard wired on */ EFX_POPULATE_DWORD_3(reg, @@ -311,70 +245,39 @@ static void falcon_reconfigure_xgxs_core(struct efx_nic *efx) /* Try and bring the Falcon side of the Falcon-Phy XAUI link fails * to come back up. Bash it until it comes back up */ -static bool falcon_check_xaui_link_up(struct efx_nic *efx) +static void falcon_check_xaui_link_up(struct efx_nic *efx, int tries) { - int max_tries, tries; - tries = EFX_WORKAROUND_5147(efx) ? 5 : 1; - max_tries = tries; + efx->mac_up = falcon_xaui_link_ok(efx); if ((efx->loopback_mode == LOOPBACK_NETWORK) || - (efx->phy_type == PHY_TYPE_NONE) || efx_phy_mode_disabled(efx->phy_mode)) - return false; - - while (tries) { - if (falcon_xaui_link_ok(efx)) - return true; + /* XAUI link is expected to be down */ + return; - EFX_LOG(efx, "%s Clobbering XAUI (%d tries left).\n", - __func__, tries); + while (!efx->mac_up && tries) { + EFX_LOG(efx, "bashing xaui\n"); falcon_reset_xaui(efx); udelay(200); - tries--; - } - EFX_LOG(efx, "Failed to bring XAUI link back up in %d tries!\n", - max_tries); - return false; + efx->mac_up = falcon_xaui_link_ok(efx); + --tries; + } } -void falcon_reconfigure_xmac(struct efx_nic *efx) +static void falcon_reconfigure_xmac(struct efx_nic *efx) { - bool xaui_link_ok; - falcon_mask_status_intr(efx, false); - falcon_deconfigure_mac_wrapper(efx); - - /* Reconfigure the PHY, disabling transmit in mac level loopback. */ - if (LOOPBACK_INTERNAL(efx)) - efx->phy_mode |= PHY_MODE_TX_DISABLED; - else - efx->phy_mode &= ~PHY_MODE_TX_DISABLED; - efx->phy_op->reconfigure(efx); - falcon_reconfigure_xgxs_core(efx); falcon_reconfigure_xmac_core(efx); falcon_reconfigure_mac_wrapper(efx); - /* Ensure XAUI link is up */ - xaui_link_ok = falcon_check_xaui_link_up(efx); - - if (xaui_link_ok && efx->link_up) - falcon_mask_status_intr(efx, true); -} - -void falcon_fini_xmac(struct efx_nic *efx) -{ - /* Isolate the MAC - PHY */ - falcon_deconfigure_mac_wrapper(efx); - - /* Potentially power down the PHY */ - efx->phy_op->fini(efx); + falcon_check_xaui_link_up(efx, 5); + falcon_mask_status_intr(efx, true); } -void falcon_update_stats_xmac(struct efx_nic *efx) +static void falcon_update_stats_xmac(struct efx_nic *efx) { struct efx_mac_stats *mac_stats = &efx->mac_stats; int rc; @@ -439,97 +342,35 @@ void falcon_update_stats_xmac(struct efx_nic *efx) mac_stats->rx_control * 64); } -int falcon_check_xmac(struct efx_nic *efx) +static void falcon_xmac_irq(struct efx_nic *efx) { - bool xaui_link_ok; - int rc; - - if ((efx->loopback_mode == LOOPBACK_NETWORK) || - efx_phy_mode_disabled(efx->phy_mode)) - return 0; - - falcon_mask_status_intr(efx, false); - xaui_link_ok = falcon_xaui_link_ok(efx); - - if (EFX_WORKAROUND_5147(efx) && !xaui_link_ok) - falcon_reset_xaui(efx); - - /* Call the PHY check_hw routine */ - rc = efx->phy_op->check_hw(efx); - - /* Unmask interrupt if everything was (and still is) ok */ - if (xaui_link_ok && efx->link_up) - falcon_mask_status_intr(efx, true); - - return rc; -} - -/* Simulate a PHY event */ -void falcon_xmac_sim_phy_event(struct efx_nic *efx) -{ - efx_qword_t phy_event; - - EFX_POPULATE_QWORD_2(phy_event, - EV_CODE, GLOBAL_EV_DECODE, - XG_PHY_INTR, 1); - falcon_generate_event(&efx->channel[0], &phy_event); + /* The XGMII link has a transient fault, which indicates either: + * - there's a transient xgmii fault + * - falcon's end of the xaui link may need a kick + * - the wire-side link may have gone down, but the lasi/poll() + * hasn't noticed yet. + * + * We only want to even bother polling XAUI if we're confident it's + * not (1) or (3). In both cases, the only reliable way to spot this + * is to wait a bit. We do this here by forcing the mac link state + * to down, and waiting for the mac poll to come round and check + */ + efx->mac_up = false; } -int falcon_xmac_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) +static void falcon_poll_xmac(struct efx_nic *efx) { - mdio_clause45_get_settings(efx, ecmd); - ecmd->transceiver = XCVR_INTERNAL; - ecmd->phy_address = efx->mii.phy_id; - ecmd->autoneg = AUTONEG_DISABLE; - ecmd->duplex = DUPLEX_FULL; - return 0; -} + if (!EFX_WORKAROUND_5147(efx) || !efx->link_up || efx->mac_up) + return; -int falcon_xmac_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) -{ - if (ecmd->transceiver != XCVR_INTERNAL) - return -EINVAL; - if (ecmd->autoneg != AUTONEG_DISABLE) - return -EINVAL; - if (ecmd->duplex != DUPLEX_FULL) - return -EINVAL; - - return mdio_clause45_set_settings(efx, ecmd); + falcon_mask_status_intr(efx, false); + falcon_check_xaui_link_up(efx, 1); + falcon_mask_status_intr(efx, true); } - -int falcon_xmac_set_pause(struct efx_nic *efx, enum efx_fc_type flow_control) -{ - bool reset; - - if (flow_control & EFX_FC_AUTO) { - EFX_LOG(efx, "10G does not support flow control " - "autonegotiation\n"); - return -EINVAL; - } - - if ((flow_control & EFX_FC_TX) && !(flow_control & EFX_FC_RX)) - return -EINVAL; - - /* TX flow control may automatically turn itself off if the - * link partner (intermittently) stops responding to pause - * frames. There isn't any indication that this has happened, - * so the best we do is leave it up to the user to spot this - * and fix it be cycling transmit flow control on this end. */ - reset = ((flow_control & EFX_FC_TX) && - !(efx->flow_control & EFX_FC_TX)); - if (EFX_WORKAROUND_11482(efx) && reset) { - if (falcon_rev(efx) >= FALCON_REV_B0) { - /* Recover by resetting the EM block */ - if (efx->link_up) - falcon_drain_tx_fifo(efx); - } else { - /* Schedule a reset to recover */ - efx_schedule_reset(efx, RESET_TYPE_INVISIBLE); - } - } - - efx->flow_control = flow_control; - - return 0; -} +struct efx_mac_operations falcon_xmac_operations = { + .reconfigure = falcon_reconfigure_xmac, + .update_stats = falcon_update_stats_xmac, + .irq = falcon_xmac_irq, + .poll = falcon_poll_xmac, +}; diff --git a/drivers/net/sfc/gmii.h b/drivers/net/sfc/gmii.h index d25bbd1297f40a240025d812fa8de8af8fa8ca1f..dfccaa7b573ef414bec46f36f068cd69326b1117 100644 --- a/drivers/net/sfc/gmii.h +++ b/drivers/net/sfc/gmii.h @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006 Solarflare Communications Inc. + * Copyright 2006-2008 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published @@ -57,139 +57,4 @@ #define ISR_POLARITY_CHG 0x0002 /* Bit 1 - polarity changed */ #define ISR_JABBER 0x0001 /* Bit 0 - jabber */ -/* Logically extended advertisement register */ -#define GM_ADVERTISE_SLCT ADVERTISE_SLCT -#define GM_ADVERTISE_CSMA ADVERTISE_CSMA -#define GM_ADVERTISE_10HALF ADVERTISE_10HALF -#define GM_ADVERTISE_1000XFULL ADVERTISE_1000XFULL -#define GM_ADVERTISE_10FULL ADVERTISE_10FULL -#define GM_ADVERTISE_1000XHALF ADVERTISE_1000XHALF -#define GM_ADVERTISE_100HALF ADVERTISE_100HALF -#define GM_ADVERTISE_1000XPAUSE ADVERTISE_1000XPAUSE -#define GM_ADVERTISE_100FULL ADVERTISE_100FULL -#define GM_ADVERTISE_1000XPSE_ASYM ADVERTISE_1000XPSE_ASYM -#define GM_ADVERTISE_100BASE4 ADVERTISE_100BASE4 -#define GM_ADVERTISE_PAUSE_CAP ADVERTISE_PAUSE_CAP -#define GM_ADVERTISE_PAUSE_ASYM ADVERTISE_PAUSE_ASYM -#define GM_ADVERTISE_RESV ADVERTISE_RESV -#define GM_ADVERTISE_RFAULT ADVERTISE_RFAULT -#define GM_ADVERTISE_LPACK ADVERTISE_LPACK -#define GM_ADVERTISE_NPAGE ADVERTISE_NPAGE -#define GM_ADVERTISE_1000FULL (ADVERTISE_1000FULL << 8) -#define GM_ADVERTISE_1000HALF (ADVERTISE_1000HALF << 8) -#define GM_ADVERTISE_1000 (GM_ADVERTISE_1000FULL | \ - GM_ADVERTISE_1000HALF) -#define GM_ADVERTISE_FULL (GM_ADVERTISE_1000FULL | \ - ADVERTISE_FULL) -#define GM_ADVERTISE_ALL (GM_ADVERTISE_1000FULL | \ - GM_ADVERTISE_1000HALF | \ - ADVERTISE_ALL) - -/* Logically extended link partner ability register */ -#define GM_LPA_SLCT LPA_SLCT -#define GM_LPA_10HALF LPA_10HALF -#define GM_LPA_1000XFULL LPA_1000XFULL -#define GM_LPA_10FULL LPA_10FULL -#define GM_LPA_1000XHALF LPA_1000XHALF -#define GM_LPA_100HALF LPA_100HALF -#define GM_LPA_1000XPAUSE LPA_1000XPAUSE -#define GM_LPA_100FULL LPA_100FULL -#define GM_LPA_1000XPAUSE_ASYM LPA_1000XPAUSE_ASYM -#define GM_LPA_100BASE4 LPA_100BASE4 -#define GM_LPA_PAUSE_CAP LPA_PAUSE_CAP -#define GM_LPA_PAUSE_ASYM LPA_PAUSE_ASYM -#define GM_LPA_RESV LPA_RESV -#define GM_LPA_RFAULT LPA_RFAULT -#define GM_LPA_LPACK LPA_LPACK -#define GM_LPA_NPAGE LPA_NPAGE -#define GM_LPA_1000FULL (LPA_1000FULL << 6) -#define GM_LPA_1000HALF (LPA_1000HALF << 6) -#define GM_LPA_10000FULL 0x00040000 -#define GM_LPA_10000HALF 0x00080000 -#define GM_LPA_DUPLEX (GM_LPA_1000FULL | GM_LPA_10000FULL \ - | LPA_DUPLEX) -#define GM_LPA_10 (LPA_10FULL | LPA_10HALF) -#define GM_LPA_100 LPA_100 -#define GM_LPA_1000 (GM_LPA_1000FULL | GM_LPA_1000HALF) -#define GM_LPA_10000 (GM_LPA_10000FULL | GM_LPA_10000HALF) - -/* Retrieve GMII autonegotiation advertised abilities - * - * The MII advertisment register (MII_ADVERTISE) is logically extended - * to include advertisement bits ADVERTISE_1000FULL and - * ADVERTISE_1000HALF from MII_CTRL1000. The result can be tested - * against the GM_ADVERTISE_xxx constants. - */ -static inline unsigned int gmii_advertised(struct mii_if_info *gmii) -{ - unsigned int advertise; - unsigned int ctrl1000; - - advertise = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_ADVERTISE); - ctrl1000 = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_CTRL1000); - return (((ctrl1000 << 8) & GM_ADVERTISE_1000) | advertise); -} - -/* Retrieve GMII autonegotiation link partner abilities - * - * The MII link partner ability register (MII_LPA) is logically - * extended by adding bits LPA_1000HALF and LPA_1000FULL from - * MII_STAT1000. The result can be tested against the GM_LPA_xxx - * constants. - */ -static inline unsigned int gmii_lpa(struct mii_if_info *gmii) -{ - unsigned int lpa; - unsigned int stat1000; - - lpa = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_LPA); - stat1000 = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_STAT1000); - return (((stat1000 << 6) & GM_LPA_1000) | lpa); -} - -/* Calculate GMII autonegotiated link technology - * - * "negotiated" should be the result of gmii_advertised() logically - * ANDed with the result of gmii_lpa(). - * - * "tech" will be negotiated with the unused bits masked out. For - * example, if both ends of the link are capable of both - * GM_LPA_1000FULL and GM_LPA_100FULL, GM_LPA_100FULL will be masked - * out. - */ -static inline unsigned int gmii_nway_result(unsigned int negotiated) -{ - unsigned int other_bits; - - /* Mask out the speed and duplexity bits */ - other_bits = negotiated & ~(GM_LPA_10 | GM_LPA_100 | GM_LPA_1000); - - if (negotiated & GM_LPA_1000FULL) - return (other_bits | GM_LPA_1000FULL); - else if (negotiated & GM_LPA_1000HALF) - return (other_bits | GM_LPA_1000HALF); - else - return (other_bits | mii_nway_result(negotiated)); -} - -/* Calculate GMII non-autonegotiated link technology - * - * This provides an equivalent to gmii_nway_result for the case when - * autonegotiation is disabled. - */ -static inline unsigned int gmii_forced_result(unsigned int bmcr) -{ - unsigned int result; - int full_duplex; - - full_duplex = bmcr & BMCR_FULLDPLX; - if (bmcr & BMCR_SPEED1000) - result = full_duplex ? GM_LPA_1000FULL : GM_LPA_1000HALF; - else if (bmcr & BMCR_SPEED100) - result = full_duplex ? GM_LPA_100FULL : GM_LPA_100HALF; - else - result = full_duplex ? GM_LPA_10FULL : GM_LPA_10HALF; - return result; -} - #endif /* EFX_GMII_H */ diff --git a/drivers/net/sfc/mac.h b/drivers/net/sfc/mac.h index a31571c6913780095181070d3b6675ac0674973e..4e7074278fe1f7b4fde0c619d6b1160502139efd 100644 --- a/drivers/net/sfc/mac.h +++ b/drivers/net/sfc/mac.h @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2007 Solarflare Communications Inc. + * Copyright 2006-2008 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published @@ -13,17 +13,7 @@ #include "net_driver.h" -extern int falcon_init_xmac(struct efx_nic *efx); -extern void falcon_reconfigure_xmac(struct efx_nic *efx); -extern void falcon_update_stats_xmac(struct efx_nic *efx); -extern void falcon_fini_xmac(struct efx_nic *efx); -extern int falcon_check_xmac(struct efx_nic *efx); -extern void falcon_xmac_sim_phy_event(struct efx_nic *efx); -extern int falcon_xmac_get_settings(struct efx_nic *efx, - struct ethtool_cmd *ecmd); -extern int falcon_xmac_set_settings(struct efx_nic *efx, - struct ethtool_cmd *ecmd); -extern int falcon_xmac_set_pause(struct efx_nic *efx, - enum efx_fc_type pause_params); +extern struct efx_mac_operations falcon_gmac_operations; +extern struct efx_mac_operations falcon_xmac_operations; #endif diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c index 003e48dcb2f3f67ea28f94d3731f3a7cbd9f7e88..f6a16428113dd3d61b0376a9ccd84df84c0262e4 100644 --- a/drivers/net/sfc/mdio_10g.c +++ b/drivers/net/sfc/mdio_10g.c @@ -47,13 +47,16 @@ static int mdio_clause45_check_mmd(struct efx_nic *efx, int mmd, if (LOOPBACK_INTERNAL(efx)) return 0; - /* Read MMD STATUS2 to check it is responding. */ - status = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_STAT2); - if (((status >> MDIO_MMDREG_STAT2_PRESENT_LBN) & - ((1 << MDIO_MMDREG_STAT2_PRESENT_WIDTH) - 1)) != - MDIO_MMDREG_STAT2_PRESENT_VAL) { - EFX_ERR(efx, "PHY MMD %d not responding.\n", mmd); - return -EIO; + if (mmd != MDIO_MMD_AN) { + /* Read MMD STATUS2 to check it is responding. */ + status = mdio_clause45_read(efx, phy_id, mmd, + MDIO_MMDREG_STAT2); + if (((status >> MDIO_MMDREG_STAT2_PRESENT_LBN) & + ((1 << MDIO_MMDREG_STAT2_PRESENT_WIDTH) - 1)) != + MDIO_MMDREG_STAT2_PRESENT_VAL) { + EFX_ERR(efx, "PHY MMD %d not responding.\n", mmd); + return -EIO; + } } /* Read MMD STATUS 1 to check for fault. */ @@ -121,16 +124,18 @@ int mdio_clause45_wait_reset_mmds(struct efx_nic *efx, int mdio_clause45_check_mmds(struct efx_nic *efx, unsigned int mmd_mask, unsigned int fatal_mask) { - int devices, mmd = 0; - int probe_mmd; + u32 devices; + int mmd = 0, probe_mmd; /* Historically we have probed the PHYXS to find out what devices are * present,but that doesn't work so well if the PHYXS isn't expected * to exist, if so just find the first item in the list supplied. */ - probe_mmd = (mmd_mask & MDIO_MMDREG_DEVS0_PHYXS) ? MDIO_MMD_PHYXS : + probe_mmd = (mmd_mask & MDIO_MMDREG_DEVS_PHYXS) ? MDIO_MMD_PHYXS : __ffs(mmd_mask); - devices = mdio_clause45_read(efx, efx->mii.phy_id, - probe_mmd, MDIO_MMDREG_DEVS0); + devices = (mdio_clause45_read(efx, efx->mii.phy_id, + probe_mmd, MDIO_MMDREG_DEVS0) | + mdio_clause45_read(efx, efx->mii.phy_id, + probe_mmd, MDIO_MMDREG_DEVS1) << 16); /* Check all the expected MMDs are present */ if (devices < 0) { @@ -162,7 +167,7 @@ int mdio_clause45_check_mmds(struct efx_nic *efx, bool mdio_clause45_links_ok(struct efx_nic *efx, unsigned int mmd_mask) { int phy_id = efx->mii.phy_id; - int status; + u32 reg; bool ok = true; int mmd = 0; @@ -174,26 +179,33 @@ bool mdio_clause45_links_ok(struct efx_nic *efx, unsigned int mmd_mask) return false; else if (efx_phy_mode_disabled(efx->phy_mode)) return false; - else if (efx->loopback_mode == LOOPBACK_PHYXS) - mmd_mask &= ~(MDIO_MMDREG_DEVS0_PHYXS | - MDIO_MMDREG_DEVS0_PCS | - MDIO_MMDREG_DEVS0_PMAPMD); - else if (efx->loopback_mode == LOOPBACK_PCS) - mmd_mask &= ~(MDIO_MMDREG_DEVS0_PCS | - MDIO_MMDREG_DEVS0_PMAPMD); + else if (efx->loopback_mode == LOOPBACK_PHYXS) { + mmd_mask &= ~(MDIO_MMDREG_DEVS_PHYXS | + MDIO_MMDREG_DEVS_PCS | + MDIO_MMDREG_DEVS_PMAPMD | + MDIO_MMDREG_DEVS_AN); + if (!mmd_mask) { + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PHYXS, + MDIO_PHYXS_STATUS2); + return !(reg & (1 << MDIO_PHYXS_STATUS2_RX_FAULT_LBN)); + } + } else if (efx->loopback_mode == LOOPBACK_PCS) + mmd_mask &= ~(MDIO_MMDREG_DEVS_PCS | + MDIO_MMDREG_DEVS_PMAPMD | + MDIO_MMDREG_DEVS_AN); else if (efx->loopback_mode == LOOPBACK_PMAPMD) - mmd_mask &= ~MDIO_MMDREG_DEVS0_PMAPMD; + mmd_mask &= ~(MDIO_MMDREG_DEVS_PMAPMD | + MDIO_MMDREG_DEVS_AN); while (mmd_mask) { if (mmd_mask & 1) { /* Double reads because link state is latched, and a * read moves the current state into the register */ - status = mdio_clause45_read(efx, phy_id, - mmd, MDIO_MMDREG_STAT1); - status = mdio_clause45_read(efx, phy_id, - mmd, MDIO_MMDREG_STAT1); - - ok = ok && (status & (1 << MDIO_MMDREG_STAT1_LINK_LBN)); + reg = mdio_clause45_read(efx, phy_id, + mmd, MDIO_MMDREG_STAT1); + reg = mdio_clause45_read(efx, phy_id, + mmd, MDIO_MMDREG_STAT1); + ok = ok && (reg & (1 << MDIO_MMDREG_STAT1_LINK_LBN)); } mmd_mask = (mmd_mask >> 1); mmd++; @@ -203,61 +215,73 @@ bool mdio_clause45_links_ok(struct efx_nic *efx, unsigned int mmd_mask) void mdio_clause45_transmit_disable(struct efx_nic *efx) { - int phy_id = efx->mii.phy_id; - int ctrl1, ctrl2; - - ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, - MDIO_MMDREG_TXDIS); - if (efx->phy_mode & PHY_MODE_TX_DISABLED) - ctrl2 |= (1 << MDIO_MMDREG_TXDIS_GLOBAL_LBN); - else - ctrl1 &= ~(1 << MDIO_MMDREG_TXDIS_GLOBAL_LBN); - if (ctrl1 != ctrl2) - mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, - MDIO_MMDREG_TXDIS, ctrl2); + mdio_clause45_set_flag(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, + MDIO_MMDREG_TXDIS, MDIO_MMDREG_TXDIS_GLOBAL_LBN, + efx->phy_mode & PHY_MODE_TX_DISABLED); } void mdio_clause45_phy_reconfigure(struct efx_nic *efx) { int phy_id = efx->mii.phy_id; - int ctrl1, ctrl2; - /* Handle (with debouncing) PMA/PMD loopback */ - ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, - MDIO_MMDREG_CTRL1); - - if (efx->loopback_mode == LOOPBACK_PMAPMD) - ctrl2 |= (1 << MDIO_PMAPMD_CTRL1_LBACK_LBN); - else - ctrl2 &= ~(1 << MDIO_PMAPMD_CTRL1_LBACK_LBN); + mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PMAPMD, + MDIO_MMDREG_CTRL1, MDIO_PMAPMD_CTRL1_LBACK_LBN, + efx->loopback_mode == LOOPBACK_PMAPMD); + mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PCS, + MDIO_MMDREG_CTRL1, MDIO_MMDREG_CTRL1_LBACK_LBN, + efx->loopback_mode == LOOPBACK_PCS); + mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PHYXS, + MDIO_MMDREG_CTRL1, MDIO_MMDREG_CTRL1_LBACK_LBN, + efx->loopback_mode == LOOPBACK_NETWORK); +} - if (ctrl1 != ctrl2) - mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, - MDIO_MMDREG_CTRL1, ctrl2); +static void mdio_clause45_set_mmd_lpower(struct efx_nic *efx, + int lpower, int mmd) +{ + int phy = efx->mii.phy_id; + int stat = mdio_clause45_read(efx, phy, mmd, MDIO_MMDREG_STAT1); - /* Handle (with debouncing) PCS loopback */ - ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PCS, - MDIO_MMDREG_CTRL1); - if (efx->loopback_mode == LOOPBACK_PCS) - ctrl2 |= (1 << MDIO_MMDREG_CTRL1_LBACK_LBN); - else - ctrl2 &= ~(1 << MDIO_MMDREG_CTRL1_LBACK_LBN); + EFX_TRACE(efx, "Setting low power mode for MMD %d to %d\n", + mmd, lpower); - if (ctrl1 != ctrl2) - mdio_clause45_write(efx, phy_id, MDIO_MMD_PCS, - MDIO_MMDREG_CTRL1, ctrl2); + if (stat & (1 << MDIO_MMDREG_STAT1_LPABLE_LBN)) { + mdio_clause45_set_flag(efx, phy, mmd, MDIO_MMDREG_CTRL1, + MDIO_MMDREG_CTRL1_LPOWER_LBN, lpower); + } +} - /* Handle (with debouncing) PHYXS network loopback */ - ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PHYXS, - MDIO_MMDREG_CTRL1); - if (efx->loopback_mode == LOOPBACK_NETWORK) - ctrl2 |= (1 << MDIO_MMDREG_CTRL1_LBACK_LBN); - else - ctrl2 &= ~(1 << MDIO_MMDREG_CTRL1_LBACK_LBN); +void mdio_clause45_set_mmds_lpower(struct efx_nic *efx, + int low_power, unsigned int mmd_mask) +{ + int mmd = 0; + mmd_mask &= ~MDIO_MMDREG_DEVS_AN; + while (mmd_mask) { + if (mmd_mask & 1) + mdio_clause45_set_mmd_lpower(efx, low_power, mmd); + mmd_mask = (mmd_mask >> 1); + mmd++; + } +} - if (ctrl1 != ctrl2) - mdio_clause45_write(efx, phy_id, MDIO_MMD_PHYXS, - MDIO_MMDREG_CTRL1, ctrl2); +static u32 mdio_clause45_get_an(struct efx_nic *efx, u16 addr, u32 xnp) +{ + int phy_id = efx->mii.phy_id; + u32 result = 0; + int reg; + + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, addr); + if (reg & ADVERTISE_10HALF) + result |= ADVERTISED_10baseT_Half; + if (reg & ADVERTISE_10FULL) + result |= ADVERTISED_10baseT_Full; + if (reg & ADVERTISE_100HALF) + result |= ADVERTISED_100baseT_Half; + if (reg & ADVERTISE_100FULL) + result |= ADVERTISED_100baseT_Full; + if (reg & LPA_RESV) + result |= xnp; + + return result; } /** @@ -266,95 +290,290 @@ void mdio_clause45_phy_reconfigure(struct efx_nic *efx) * @ecmd: Buffer for settings * * On return the 'port', 'speed', 'supported' and 'advertising' fields of - * ecmd have been filled out based on the PMA type. + * ecmd have been filled out. */ void mdio_clause45_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) { - int pma_type; + mdio_clause45_get_settings_ext(efx, ecmd, 0, 0); +} - /* If no PMA is present we are presumably talking something XAUI-ish - * like CX4. Which we report as FIBRE (see below) */ - if ((efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_PMAPMD)) == 0) { - ecmd->speed = SPEED_10000; - ecmd->port = PORT_FIBRE; - ecmd->supported = SUPPORTED_FIBRE; - ecmd->advertising = ADVERTISED_FIBRE; - return; - } +/** + * mdio_clause45_get_settings_ext - Read (some of) the PHY settings over MDIO. + * @efx: Efx NIC + * @ecmd: Buffer for settings + * @xnp: Advertised Extended Next Page state + * @xnp_lpa: Link Partner's advertised XNP state + * + * On return the 'port', 'speed', 'supported' and 'advertising' fields of + * ecmd have been filled out. + */ +void mdio_clause45_get_settings_ext(struct efx_nic *efx, + struct ethtool_cmd *ecmd, + u32 xnp, u32 xnp_lpa) +{ + int phy_id = efx->mii.phy_id; + int reg; - pma_type = mdio_clause45_read(efx, efx->mii.phy_id, - MDIO_MMD_PMAPMD, MDIO_MMDREG_CTRL2); - pma_type &= MDIO_PMAPMD_CTRL2_TYPE_MASK; + ecmd->transceiver = XCVR_INTERNAL; + ecmd->phy_address = phy_id; - switch (pma_type) { - /* We represent CX4 as fibre in the absence of anything - better. */ - case MDIO_PMAPMD_CTRL2_10G_CX4: - ecmd->speed = SPEED_10000; - ecmd->port = PORT_FIBRE; - ecmd->supported = SUPPORTED_FIBRE; - ecmd->advertising = ADVERTISED_FIBRE; - break; - /* 10G Base-T */ + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, + MDIO_MMDREG_CTRL2); + switch (reg & MDIO_PMAPMD_CTRL2_TYPE_MASK) { case MDIO_PMAPMD_CTRL2_10G_BT: - ecmd->speed = SPEED_10000; - ecmd->port = PORT_TP; - ecmd->supported = SUPPORTED_TP | SUPPORTED_10000baseT_Full; - ecmd->advertising = (ADVERTISED_FIBRE - | ADVERTISED_10000baseT_Full); - break; case MDIO_PMAPMD_CTRL2_1G_BT: - ecmd->speed = SPEED_1000; - ecmd->port = PORT_TP; - ecmd->supported = SUPPORTED_TP | SUPPORTED_1000baseT_Full; - ecmd->advertising = (ADVERTISED_FIBRE - | ADVERTISED_1000baseT_Full); - break; case MDIO_PMAPMD_CTRL2_100_BT: - ecmd->speed = SPEED_100; - ecmd->port = PORT_TP; - ecmd->supported = SUPPORTED_TP | SUPPORTED_100baseT_Full; - ecmd->advertising = (ADVERTISED_FIBRE - | ADVERTISED_100baseT_Full); - break; case MDIO_PMAPMD_CTRL2_10_BT: - ecmd->speed = SPEED_10; ecmd->port = PORT_TP; - ecmd->supported = SUPPORTED_TP | SUPPORTED_10baseT_Full; - ecmd->advertising = ADVERTISED_FIBRE | ADVERTISED_10baseT_Full; + ecmd->supported = SUPPORTED_TP; + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, + MDIO_MMDREG_SPEED); + if (reg & (1 << MDIO_MMDREG_SPEED_10G_LBN)) + ecmd->supported |= SUPPORTED_10000baseT_Full; + if (reg & (1 << MDIO_MMDREG_SPEED_1000M_LBN)) + ecmd->supported |= (SUPPORTED_1000baseT_Full | + SUPPORTED_1000baseT_Half); + if (reg & (1 << MDIO_MMDREG_SPEED_100M_LBN)) + ecmd->supported |= (SUPPORTED_100baseT_Full | + SUPPORTED_100baseT_Half); + if (reg & (1 << MDIO_MMDREG_SPEED_10M_LBN)) + ecmd->supported |= (SUPPORTED_10baseT_Full | + SUPPORTED_10baseT_Half); + ecmd->advertising = ADVERTISED_TP; break; - /* All the other defined modes are flavours of - * 10G optical */ + + /* We represent CX4 as fibre in the absence of anything better */ + case MDIO_PMAPMD_CTRL2_10G_CX4: + /* All the other defined modes are flavours of optical */ default: - ecmd->speed = SPEED_10000; ecmd->port = PORT_FIBRE; ecmd->supported = SUPPORTED_FIBRE; ecmd->advertising = ADVERTISED_FIBRE; break; } + + if (efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN)) { + ecmd->supported |= SUPPORTED_Autoneg; + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, + MDIO_MMDREG_CTRL1); + if (reg & BMCR_ANENABLE) { + ecmd->autoneg = AUTONEG_ENABLE; + ecmd->advertising |= + ADVERTISED_Autoneg | + mdio_clause45_get_an(efx, + MDIO_AN_ADVERTISE, xnp); + } else + ecmd->autoneg = AUTONEG_DISABLE; + } else + ecmd->autoneg = AUTONEG_DISABLE; + + if (ecmd->autoneg) { + /* If AN is complete, report best common mode, + * otherwise report best advertised mode. */ + u32 common = ecmd->advertising; + if (mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, + MDIO_MMDREG_STAT1) & + (1 << MDIO_AN_STATUS_AN_DONE_LBN)) { + common &= mdio_clause45_get_an(efx, MDIO_AN_LPA, + xnp_lpa); + } + if (common & ADVERTISED_10000baseT_Full) { + ecmd->speed = SPEED_10000; + ecmd->duplex = DUPLEX_FULL; + } else if (common & (ADVERTISED_1000baseT_Full | + ADVERTISED_1000baseT_Half)) { + ecmd->speed = SPEED_1000; + ecmd->duplex = !!(common & ADVERTISED_1000baseT_Full); + } else if (common & (ADVERTISED_100baseT_Full | + ADVERTISED_100baseT_Half)) { + ecmd->speed = SPEED_100; + ecmd->duplex = !!(common & ADVERTISED_100baseT_Full); + } else { + ecmd->speed = SPEED_10; + ecmd->duplex = !!(common & ADVERTISED_10baseT_Full); + } + } else { + /* Report forced settings */ + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, + MDIO_MMDREG_CTRL1); + ecmd->speed = (((reg & BMCR_SPEED1000) ? 100 : 1) * + ((reg & BMCR_SPEED100) ? 100 : 10)); + ecmd->duplex = (reg & BMCR_FULLDPLX || + ecmd->speed == SPEED_10000); + } } /** * mdio_clause45_set_settings - Set (some of) the PHY settings over MDIO. * @efx: Efx NIC * @ecmd: New settings - * - * Currently this just enforces that we are _not_ changing the - * 'port', 'speed', 'supported' or 'advertising' settings as these - * cannot be changed on any currently supported PHY. */ int mdio_clause45_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) { - struct ethtool_cmd tmpcmd; - mdio_clause45_get_settings(efx, &tmpcmd); - /* None of the current PHYs support more than one mode - * of operation (and only 10GBT ever will), so keep things - * simple for now */ - if ((ecmd->speed == tmpcmd.speed) && (ecmd->port == tmpcmd.port) && - (ecmd->supported == tmpcmd.supported) && - (ecmd->advertising == tmpcmd.advertising)) + int phy_id = efx->mii.phy_id; + struct ethtool_cmd prev; + u32 required; + int ctrl1_bits, reg; + + efx->phy_op->get_settings(efx, &prev); + + if (ecmd->advertising == prev.advertising && + ecmd->speed == prev.speed && + ecmd->duplex == prev.duplex && + ecmd->port == prev.port && + ecmd->autoneg == prev.autoneg) return 0; - return -EOPNOTSUPP; + + /* We can only change these settings for -T PHYs */ + if (prev.port != PORT_TP || ecmd->port != PORT_TP) + return -EINVAL; + + /* Check that PHY supports these settings and work out the + * basic control bits */ + if (ecmd->duplex) { + switch (ecmd->speed) { + case SPEED_10: + ctrl1_bits = BMCR_FULLDPLX; + required = SUPPORTED_10baseT_Full; + break; + case SPEED_100: + ctrl1_bits = BMCR_SPEED100 | BMCR_FULLDPLX; + required = SUPPORTED_100baseT_Full; + break; + case SPEED_1000: + ctrl1_bits = BMCR_SPEED1000 | BMCR_FULLDPLX; + required = SUPPORTED_1000baseT_Full; + break; + case SPEED_10000: + ctrl1_bits = (BMCR_SPEED1000 | BMCR_SPEED100 | + BMCR_FULLDPLX); + required = SUPPORTED_10000baseT_Full; + break; + default: + return -EINVAL; + } + } else { + switch (ecmd->speed) { + case SPEED_10: + ctrl1_bits = 0; + required = SUPPORTED_10baseT_Half; + break; + case SPEED_100: + ctrl1_bits = BMCR_SPEED100; + required = SUPPORTED_100baseT_Half; + break; + case SPEED_1000: + ctrl1_bits = BMCR_SPEED1000; + required = SUPPORTED_1000baseT_Half; + break; + default: + return -EINVAL; + } + } + if (ecmd->autoneg) + required |= SUPPORTED_Autoneg; + required |= ecmd->advertising; + if (required & ~prev.supported) + return -EINVAL; + + /* Set the basic control bits */ + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, + MDIO_MMDREG_CTRL1); + reg &= ~(BMCR_SPEED1000 | BMCR_SPEED100 | BMCR_FULLDPLX | 0x003c); + reg |= ctrl1_bits; + mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, MDIO_MMDREG_CTRL1, + reg); + + /* Set the AN registers */ + if (ecmd->autoneg != prev.autoneg || + ecmd->advertising != prev.advertising) { + bool xnp = false; + + if (efx->phy_op->set_xnp_advertise) + xnp = efx->phy_op->set_xnp_advertise(efx, + ecmd->advertising); + + if (ecmd->autoneg) { + reg = 0; + if (ecmd->advertising & ADVERTISED_10baseT_Half) + reg |= ADVERTISE_10HALF; + if (ecmd->advertising & ADVERTISED_10baseT_Full) + reg |= ADVERTISE_10FULL; + if (ecmd->advertising & ADVERTISED_100baseT_Half) + reg |= ADVERTISE_100HALF; + if (ecmd->advertising & ADVERTISED_100baseT_Full) + reg |= ADVERTISE_100FULL; + if (xnp) + reg |= ADVERTISE_RESV; + mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, + MDIO_AN_ADVERTISE, reg); + } + + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, + MDIO_MMDREG_CTRL1); + if (ecmd->autoneg) + reg |= BMCR_ANENABLE | BMCR_ANRESTART; + else + reg &= ~BMCR_ANENABLE; + if (xnp) + reg |= 1 << MDIO_AN_CTRL_XNP_LBN; + else + reg &= ~(1 << MDIO_AN_CTRL_XNP_LBN); + mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, + MDIO_MMDREG_CTRL1, reg); + } + + return 0; +} + +void mdio_clause45_set_pause(struct efx_nic *efx) +{ + int phy_id = efx->mii.phy_id; + int reg; + + if (efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN)) { + /* Set pause capability advertising */ + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, + MDIO_AN_ADVERTISE); + reg &= ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); + reg |= efx_fc_advertise(efx->wanted_fc); + mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, + MDIO_AN_ADVERTISE, reg); + + /* Restart auto-negotiation */ + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, + MDIO_MMDREG_CTRL1); + if (reg & BMCR_ANENABLE) { + reg |= BMCR_ANRESTART; + mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, + MDIO_MMDREG_CTRL1, reg); + } + } +} + +enum efx_fc_type mdio_clause45_get_pause(struct efx_nic *efx) +{ + int phy_id = efx->mii.phy_id; + int lpa; + + if (!(efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN))) + return efx->wanted_fc; + lpa = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, MDIO_AN_LPA); + return efx_fc_resolve(efx->wanted_fc, lpa); +} + +void mdio_clause45_set_flag(struct efx_nic *efx, u8 prt, u8 dev, + u16 addr, int bit, bool sense) +{ + int old_val = mdio_clause45_read(efx, prt, dev, addr); + int new_val; + + if (sense) + new_val = old_val | (1 << bit); + else + new_val = old_val & ~(1 << bit); + if (old_val != new_val) + mdio_clause45_write(efx, prt, dev, addr, new_val); } diff --git a/drivers/net/sfc/mdio_10g.h b/drivers/net/sfc/mdio_10g.h index 19c42eaf7fb47d714087c62efed01f3242b802c3..09bf801d0569a2199c79d89007bc7518e0163cdc 100644 --- a/drivers/net/sfc/mdio_10g.h +++ b/drivers/net/sfc/mdio_10g.h @@ -33,6 +33,8 @@ #define MDIO_MMD_TC (6) /* Auto negotiation */ #define MDIO_MMD_AN (7) +/* Clause 22 extension */ +#define MDIO_MMD_C22EXT 29 /* Generic register locations */ #define MDIO_MMDREG_CTRL1 (0) @@ -54,6 +56,9 @@ /* Loopback bit for WIS, PCS, PHYSX and DTEXS */ #define MDIO_MMDREG_CTRL1_LBACK_LBN (14) #define MDIO_MMDREG_CTRL1_LBACK_WIDTH (1) +/* Low power */ +#define MDIO_MMDREG_CTRL1_LPOWER_LBN (11) +#define MDIO_MMDREG_CTRL1_LPOWER_WIDTH (1) /* Bits in MMDREG_STAT1 */ #define MDIO_MMDREG_STAT1_FAULT_LBN (7) @@ -70,14 +75,26 @@ #define MDIO_ID_MODEL(_id32) ((_id32 >> 4) & 0x3f) #define MDIO_ID_OUI(_id32) (_id32 >> 10) -/* Bits in MMDREG_DEVS0. Someone thoughtfully layed things out +/* Bits in MMDREG_DEVS0/1. Someone thoughtfully layed things out * so the 'bit present' bit number of an MMD is the number of * that MMD */ #define DEV_PRESENT_BIT(_b) (1 << _b) -#define MDIO_MMDREG_DEVS0_PHYXS DEV_PRESENT_BIT(MDIO_MMD_PHYXS) -#define MDIO_MMDREG_DEVS0_PCS DEV_PRESENT_BIT(MDIO_MMD_PCS) -#define MDIO_MMDREG_DEVS0_PMAPMD DEV_PRESENT_BIT(MDIO_MMD_PMAPMD) +#define MDIO_MMDREG_DEVS_PHYXS DEV_PRESENT_BIT(MDIO_MMD_PHYXS) +#define MDIO_MMDREG_DEVS_PCS DEV_PRESENT_BIT(MDIO_MMD_PCS) +#define MDIO_MMDREG_DEVS_PMAPMD DEV_PRESENT_BIT(MDIO_MMD_PMAPMD) +#define MDIO_MMDREG_DEVS_AN DEV_PRESENT_BIT(MDIO_MMD_AN) +#define MDIO_MMDREG_DEVS_C22EXT DEV_PRESENT_BIT(MDIO_MMD_C22EXT) + +/* Bits in MMDREG_SPEED */ +#define MDIO_MMDREG_SPEED_10G_LBN 0 +#define MDIO_MMDREG_SPEED_10G_WIDTH 1 +#define MDIO_MMDREG_SPEED_1000M_LBN 4 +#define MDIO_MMDREG_SPEED_1000M_WIDTH 1 +#define MDIO_MMDREG_SPEED_100M_LBN 5 +#define MDIO_MMDREG_SPEED_100M_WIDTH 1 +#define MDIO_MMDREG_SPEED_10M_LBN 6 +#define MDIO_MMDREG_SPEED_10M_WIDTH 1 /* Bits in MMDREG_STAT2 */ #define MDIO_MMDREG_STAT2_PRESENT_VAL (2) @@ -111,17 +128,34 @@ #define MDIO_PMAPMD_CTRL2_10_BT (0xf) #define MDIO_PMAPMD_CTRL2_TYPE_MASK (0xf) +/* PMA 10GBT registers */ +#define MDIO_PMAPMD_10GBT_TXPWR (131) +#define MDIO_PMAPMD_10GBT_TXPWR_SHORT_LBN (0) +#define MDIO_PMAPMD_10GBT_TXPWR_SHORT_WIDTH (1) + +/* PHY XGXS Status 2 */ +#define MDIO_PHYXS_STATUS2 (8) +#define MDIO_PHYXS_STATUS2_RX_FAULT_LBN 10 + /* PHY XGXS lane state */ #define MDIO_PHYXS_LANE_STATE (0x18) #define MDIO_PHYXS_LANE_ALIGNED_LBN (12) /* AN registers */ +#define MDIO_AN_CTRL_XNP_LBN 13 #define MDIO_AN_STATUS (1) #define MDIO_AN_STATUS_XNP_LBN (7) #define MDIO_AN_STATUS_PAGE_LBN (6) #define MDIO_AN_STATUS_AN_DONE_LBN (5) #define MDIO_AN_STATUS_LP_AN_CAP_LBN (0) +#define MDIO_AN_ADVERTISE 16 +#define MDIO_AN_ADVERTISE_XNP_LBN 12 +#define MDIO_AN_LPA 19 +#define MDIO_AN_XNP 22 +#define MDIO_AN_LPA_XNP 25 + +#define MDIO_AN_10GBT_ADVERTISE 32 #define MDIO_AN_10GBT_STATUS (33) #define MDIO_AN_10GBT_STATUS_MS_FLT_LBN (15) /* MASTER/SLAVE config fault */ #define MDIO_AN_10GBT_STATUS_MS_LBN (14) /* MASTER/SLAVE config */ @@ -240,16 +274,37 @@ extern void mdio_clause45_transmit_disable(struct efx_nic *efx); /* Generic part of reconfigure: set/clear loopback bits */ extern void mdio_clause45_phy_reconfigure(struct efx_nic *efx); +/* Set the power state of the specified MMDs */ +extern void mdio_clause45_set_mmds_lpower(struct efx_nic *efx, + int low_power, unsigned int mmd_mask); + /* Read (some of) the PHY settings over MDIO */ extern void mdio_clause45_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd); +/* Read (some of) the PHY settings over MDIO */ +extern void +mdio_clause45_get_settings_ext(struct efx_nic *efx, struct ethtool_cmd *ecmd, + u32 xnp, u32 xnp_lpa); + /* Set (some of) the PHY settings over MDIO */ extern int mdio_clause45_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd); +/* Set pause parameters to be advertised through AN (if available) */ +extern void mdio_clause45_set_pause(struct efx_nic *efx); + +/* Get pause parameters from AN if available (otherwise return + * requested pause parameters) + */ +enum efx_fc_type mdio_clause45_get_pause(struct efx_nic *efx); + /* Wait for specified MMDs to exit reset within a timeout */ extern int mdio_clause45_wait_reset_mmds(struct efx_nic *efx, unsigned int mmd_mask); +/* Set or clear flag, debouncing */ +extern void mdio_clause45_set_flag(struct efx_nic *efx, u8 prt, u8 dev, + u16 addr, int bit, bool sense); + #endif /* EFX_MDIO_10G_H */ diff --git a/drivers/net/sfc/mtd.c b/drivers/net/sfc/mtd.c new file mode 100644 index 0000000000000000000000000000000000000000..665cafb88d6a087a190b0391497a681442109018 --- /dev/null +++ b/drivers/net/sfc/mtd.c @@ -0,0 +1,268 @@ +/**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards + * Copyright 2005-2006 Fen Systems Ltd. + * Copyright 2006-2008 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + */ + +#include +#include +#include + +#define EFX_DRIVER_NAME "sfc_mtd" +#include "net_driver.h" +#include "spi.h" + +#define EFX_SPI_VERIFY_BUF_LEN 16 + +struct efx_mtd { + const struct efx_spi_device *spi; + struct mtd_info mtd; + char name[IFNAMSIZ + 20]; +}; + +/* SPI utilities */ + +static int efx_spi_slow_wait(struct efx_mtd *efx_mtd, bool uninterruptible) +{ + const struct efx_spi_device *spi = efx_mtd->spi; + struct efx_nic *efx = spi->efx; + u8 status; + int rc, i; + + /* Wait up to 4s for flash/EEPROM to finish a slow operation. */ + for (i = 0; i < 40; i++) { + __set_current_state(uninterruptible ? + TASK_UNINTERRUPTIBLE : TASK_INTERRUPTIBLE); + schedule_timeout(HZ / 10); + rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL, + &status, sizeof(status)); + if (rc) + return rc; + if (!(status & SPI_STATUS_NRDY)) + return 0; + if (signal_pending(current)) + return -EINTR; + } + EFX_ERR(efx, "timed out waiting for %s\n", efx_mtd->name); + return -ETIMEDOUT; +} + +static int efx_spi_unlock(const struct efx_spi_device *spi) +{ + const u8 unlock_mask = (SPI_STATUS_BP2 | SPI_STATUS_BP1 | + SPI_STATUS_BP0); + u8 status; + int rc; + + rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL, &status, sizeof(status)); + if (rc) + return rc; + + if (!(status & unlock_mask)) + return 0; /* already unlocked */ + + rc = falcon_spi_cmd(spi, SPI_WREN, -1, NULL, NULL, 0); + if (rc) + return rc; + rc = falcon_spi_cmd(spi, SPI_SST_EWSR, -1, NULL, NULL, 0); + if (rc) + return rc; + + status &= ~unlock_mask; + rc = falcon_spi_cmd(spi, SPI_WRSR, -1, &status, NULL, sizeof(status)); + if (rc) + return rc; + rc = falcon_spi_wait_write(spi); + if (rc) + return rc; + + return 0; +} + +static int efx_spi_erase(struct efx_mtd *efx_mtd, loff_t start, size_t len) +{ + const struct efx_spi_device *spi = efx_mtd->spi; + unsigned pos, block_len; + u8 empty[EFX_SPI_VERIFY_BUF_LEN]; + u8 buffer[EFX_SPI_VERIFY_BUF_LEN]; + int rc; + + if (len != spi->erase_size) + return -EINVAL; + + if (spi->erase_command == 0) + return -EOPNOTSUPP; + + rc = efx_spi_unlock(spi); + if (rc) + return rc; + rc = falcon_spi_cmd(spi, SPI_WREN, -1, NULL, NULL, 0); + if (rc) + return rc; + rc = falcon_spi_cmd(spi, spi->erase_command, start, NULL, NULL, 0); + if (rc) + return rc; + rc = efx_spi_slow_wait(efx_mtd, false); + + /* Verify the entire region has been wiped */ + memset(empty, 0xff, sizeof(empty)); + for (pos = 0; pos < len; pos += block_len) { + block_len = min(len - pos, sizeof(buffer)); + rc = falcon_spi_read(spi, start + pos, block_len, NULL, buffer); + if (rc) + return rc; + if (memcmp(empty, buffer, block_len)) + return -EIO; + + /* Avoid locking up the system */ + cond_resched(); + if (signal_pending(current)) + return -EINTR; + } + + return rc; +} + +/* MTD interface */ + +static int efx_mtd_read(struct mtd_info *mtd, loff_t start, size_t len, + size_t *retlen, u8 *buffer) +{ + struct efx_mtd *efx_mtd = mtd->priv; + const struct efx_spi_device *spi = efx_mtd->spi; + struct efx_nic *efx = spi->efx; + int rc; + + rc = mutex_lock_interruptible(&efx->spi_lock); + if (rc) + return rc; + rc = falcon_spi_read(spi, FALCON_FLASH_BOOTCODE_START + start, + len, retlen, buffer); + mutex_unlock(&efx->spi_lock); + return rc; +} + +static int efx_mtd_erase(struct mtd_info *mtd, struct erase_info *erase) +{ + struct efx_mtd *efx_mtd = mtd->priv; + struct efx_nic *efx = efx_mtd->spi->efx; + int rc; + + rc = mutex_lock_interruptible(&efx->spi_lock); + if (rc) + return rc; + rc = efx_spi_erase(efx_mtd, FALCON_FLASH_BOOTCODE_START + erase->addr, + erase->len); + mutex_unlock(&efx->spi_lock); + + if (rc == 0) { + erase->state = MTD_ERASE_DONE; + } else { + erase->state = MTD_ERASE_FAILED; + erase->fail_addr = 0xffffffff; + } + mtd_erase_callback(erase); + return rc; +} + +static int efx_mtd_write(struct mtd_info *mtd, loff_t start, + size_t len, size_t *retlen, const u8 *buffer) +{ + struct efx_mtd *efx_mtd = mtd->priv; + const struct efx_spi_device *spi = efx_mtd->spi; + struct efx_nic *efx = spi->efx; + int rc; + + rc = mutex_lock_interruptible(&efx->spi_lock); + if (rc) + return rc; + rc = falcon_spi_write(spi, FALCON_FLASH_BOOTCODE_START + start, + len, retlen, buffer); + mutex_unlock(&efx->spi_lock); + return rc; +} + +static void efx_mtd_sync(struct mtd_info *mtd) +{ + struct efx_mtd *efx_mtd = mtd->priv; + struct efx_nic *efx = efx_mtd->spi->efx; + int rc; + + mutex_lock(&efx->spi_lock); + rc = efx_spi_slow_wait(efx_mtd, true); + mutex_unlock(&efx->spi_lock); + + if (rc) + EFX_ERR(efx, "%s sync failed (%d)\n", efx_mtd->name, rc); + return; +} + +void efx_mtd_remove(struct efx_nic *efx) +{ + if (efx->spi_flash && efx->spi_flash->mtd) { + struct efx_mtd *efx_mtd = efx->spi_flash->mtd; + int rc; + + for (;;) { + rc = del_mtd_device(&efx_mtd->mtd); + if (rc != -EBUSY) + break; + ssleep(1); + } + WARN_ON(rc); + kfree(efx_mtd); + } +} + +void efx_mtd_rename(struct efx_nic *efx) +{ + if (efx->spi_flash && efx->spi_flash->mtd) { + struct efx_mtd *efx_mtd = efx->spi_flash->mtd; + snprintf(efx_mtd->name, sizeof(efx_mtd->name), + "%s sfc_flash_bootrom", efx->name); + } +} + +int efx_mtd_probe(struct efx_nic *efx) +{ + struct efx_spi_device *spi = efx->spi_flash; + struct efx_mtd *efx_mtd; + + if (!spi || spi->size <= FALCON_FLASH_BOOTCODE_START) + return -ENODEV; + + efx_mtd = kzalloc(sizeof(*efx_mtd), GFP_KERNEL); + if (!efx_mtd) + return -ENOMEM; + + efx_mtd->spi = spi; + spi->mtd = efx_mtd; + + efx_mtd->mtd.type = MTD_NORFLASH; + efx_mtd->mtd.flags = MTD_CAP_NORFLASH; + efx_mtd->mtd.size = spi->size - FALCON_FLASH_BOOTCODE_START; + efx_mtd->mtd.erasesize = spi->erase_size; + efx_mtd->mtd.writesize = 1; + efx_mtd_rename(efx); + + efx_mtd->mtd.owner = THIS_MODULE; + efx_mtd->mtd.priv = efx_mtd; + efx_mtd->mtd.name = efx_mtd->name; + efx_mtd->mtd.erase = efx_mtd_erase; + efx_mtd->mtd.read = efx_mtd_read; + efx_mtd->mtd.write = efx_mtd_write; + efx_mtd->mtd.sync = efx_mtd_sync; + + if (add_mtd_device(&efx_mtd->mtd)) { + kfree(efx_mtd); + spi->mtd = NULL; + /* add_mtd_device() returns 1 if the MTD table is full */ + return -ENOMEM; + } + + return 0; +} diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index cdb11fad6050b0b7700ff8ca64ac8f4afcd68579..5f255f75754e526f6df041d8665908c59fba6e53 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -42,7 +42,7 @@ #ifndef EFX_DRIVER_NAME #define EFX_DRIVER_NAME "sfc" #endif -#define EFX_DRIVER_VERSION "2.2" +#define EFX_DRIVER_VERSION "2.3" #ifdef EFX_ENABLE_DEBUG #define EFX_BUG_ON_PARANOID(x) BUG_ON(x) @@ -327,6 +327,7 @@ enum efx_rx_alloc_method { * * @efx: Associated Efx NIC * @channel: Channel instance number + * @name: Name for channel and IRQ * @used_flags: Channel is used by net driver * @enabled: Channel enabled indicator * @irq: IRQ number (MSI and MSI-X only) @@ -357,6 +358,7 @@ enum efx_rx_alloc_method { struct efx_channel { struct efx_nic *efx; int channel; + char name[IFNAMSIZ + 6]; int used_flags; bool enabled; int irq; @@ -414,6 +416,7 @@ struct efx_blinker { * @init_leds: Sets up board LEDs * @set_fault_led: Turns the fault LED on or off * @blink: Starts/stops blinking + * @monitor: Board-specific health check function * @fini: Cleanup function * @blinker: used to blink LEDs in software * @hwmon_client: I2C client for hardware monitor @@ -428,6 +431,7 @@ struct efx_board { * have a separate init callback that happens later than * board init. */ int (*init_leds)(struct efx_nic *efx); + int (*monitor) (struct efx_nic *nic); void (*set_fault_led) (struct efx_nic *efx, bool state); void (*blink) (struct efx_nic *efx, bool start); void (*fini) (struct efx_nic *nic); @@ -449,16 +453,20 @@ enum efx_int_mode { enum phy_type { PHY_TYPE_NONE = 0, - PHY_TYPE_CX4_RTMR = 1, - PHY_TYPE_1G_ALASKA = 2, - PHY_TYPE_10XPRESS = 3, - PHY_TYPE_XFP = 4, + PHY_TYPE_TXC43128 = 1, + PHY_TYPE_88E1111 = 2, + PHY_TYPE_SFX7101 = 3, + PHY_TYPE_QT2022C2 = 4, PHY_TYPE_PM8358 = 6, + PHY_TYPE_SFT9001A = 8, + PHY_TYPE_SFT9001B = 10, PHY_TYPE_MAX /* Insert any new items before this */ }; #define PHY_ADDR_INVALID 0xff +#define EFX_IS10G(efx) ((efx)->link_speed == 10000) + enum nic_state { STATE_INIT = 0, STATE_RUNNING = 1, @@ -499,6 +507,55 @@ enum efx_fc_type { EFX_FC_AUTO = 4, }; +/* Supported MAC bit-mask */ +enum efx_mac_type { + EFX_GMAC = 1, + EFX_XMAC = 2, +}; + +static inline unsigned int efx_fc_advertise(enum efx_fc_type wanted_fc) +{ + unsigned int adv = 0; + if (wanted_fc & EFX_FC_RX) + adv = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; + if (wanted_fc & EFX_FC_TX) + adv ^= ADVERTISE_PAUSE_ASYM; + return adv; +} + +static inline enum efx_fc_type efx_fc_resolve(enum efx_fc_type wanted_fc, + unsigned int lpa) +{ + unsigned int adv = efx_fc_advertise(wanted_fc); + + if (!(wanted_fc & EFX_FC_AUTO)) + return wanted_fc; + + if (adv & lpa & ADVERTISE_PAUSE_CAP) + return EFX_FC_RX | EFX_FC_TX; + if (adv & lpa & ADVERTISE_PAUSE_ASYM) { + if (adv & ADVERTISE_PAUSE_CAP) + return EFX_FC_RX; + if (lpa & ADVERTISE_PAUSE_CAP) + return EFX_FC_TX; + } + return 0; +} + +/** + * struct efx_mac_operations - Efx MAC operations table + * @reconfigure: Reconfigure MAC. Serialised by the mac_lock + * @update_stats: Update statistics + * @irq: Hardware MAC event callback. Serialised by the mac_lock + * @poll: Poll for hardware state. Serialised by the mac_lock + */ +struct efx_mac_operations { + void (*reconfigure) (struct efx_nic *efx); + void (*update_stats) (struct efx_nic *efx); + void (*irq) (struct efx_nic *efx); + void (*poll) (struct efx_nic *efx); +}; + /** * struct efx_phy_operations - Efx PHY operations table * @init: Initialise PHY @@ -506,17 +563,33 @@ enum efx_fc_type { * @reconfigure: Reconfigure PHY (e.g. for new link parameters) * @clear_interrupt: Clear down interrupt * @blink: Blink LEDs - * @check_hw: Check hardware + * @poll: Poll for hardware state. Serialised by the mac_lock. + * @get_settings: Get ethtool settings. Serialised by the mac_lock. + * @set_settings: Set ethtool settings. Serialised by the mac_lock. + * @set_xnp_advertise: Set abilities advertised in Extended Next Page + * (only needed where AN bit is set in mmds) + * @num_tests: Number of PHY-specific tests/results + * @test_names: Names of the tests/results + * @run_tests: Run tests and record results as appropriate. + * Flags are the ethtool tests flags. * @mmds: MMD presence mask * @loopbacks: Supported loopback modes mask */ struct efx_phy_operations { + enum efx_mac_type macs; int (*init) (struct efx_nic *efx); void (*fini) (struct efx_nic *efx); void (*reconfigure) (struct efx_nic *efx); void (*clear_interrupt) (struct efx_nic *efx); - int (*check_hw) (struct efx_nic *efx); - int (*test) (struct efx_nic *efx); + void (*poll) (struct efx_nic *efx); + void (*get_settings) (struct efx_nic *efx, + struct ethtool_cmd *ecmd); + int (*set_settings) (struct efx_nic *efx, + struct ethtool_cmd *ecmd); + bool (*set_xnp_advertise) (struct efx_nic *efx, u32); + u32 num_tests; + const char *const *test_names; + int (*run_tests) (struct efx_nic *efx, int *results, unsigned flags); int mmds; unsigned loopbacks; }; @@ -525,11 +598,15 @@ struct efx_phy_operations { * @enum efx_phy_mode - PHY operating mode flags * @PHY_MODE_NORMAL: on and should pass traffic * @PHY_MODE_TX_DISABLED: on with TX disabled + * @PHY_MODE_LOW_POWER: set to low power through MDIO + * @PHY_MODE_OFF: switched off through external control * @PHY_MODE_SPECIAL: on but will not pass traffic */ enum efx_phy_mode { PHY_MODE_NORMAL = 0, PHY_MODE_TX_DISABLED = 1, + PHY_MODE_LOW_POWER = 2, + PHY_MODE_OFF = 4, PHY_MODE_SPECIAL = 8, }; @@ -629,7 +706,7 @@ union efx_multicast_hash { * @legacy_irq: IRQ number * @workqueue: Workqueue for port reconfigures and the HW monitor. * Work items do not hold and must not acquire RTNL. - * @reset_workqueue: Workqueue for resets. Work item will acquire RTNL. + * @workqueue_name: Name of workqueue * @reset_work: Scheduled reset workitem * @monitor_work: Hardware monitor workitem * @membase_phys: Memory BAR value as physical address @@ -644,6 +721,7 @@ union efx_multicast_hash { * @rx_queue: RX DMA queues * @channel: Channels * @n_rx_queues: Number of RX queues + * @n_channels: Number of channels in use * @rx_buffer_len: RX buffer length * @rx_buffer_order: Order (log2) of number of pages for each RX buffer * @irq_status: Interrupt status buffer @@ -655,15 +733,16 @@ union efx_multicast_hash { * This field will be %NULL if no flash device is present. * @spi_eeprom: SPI EEPROM device * This field will be %NULL if no EEPROM device is present. + * @spi_lock: SPI bus lock * @n_rx_nodesc_drop_cnt: RX no descriptor drop count * @nic_data: Hardware dependant state * @mac_lock: MAC access lock. Protects @port_enabled, @phy_mode, * @port_inhibited, efx_monitor() and efx_reconfigure_port() * @port_enabled: Port enabled indicator. - * Serialises efx_stop_all(), efx_start_all() and efx_monitor() and - * efx_reconfigure_work with kernel interfaces. Safe to read under any - * one of the rtnl_lock, mac_lock, or netif_tx_lock, but all three must - * be held to modify it. + * Serialises efx_stop_all(), efx_start_all(), efx_monitor(), + * efx_phy_work(), and efx_mac_work() with kernel interfaces. Safe to read + * under any one of the rtnl_lock, mac_lock, or netif_tx_lock, but all + * three must be held to modify it. * @port_inhibited: If set, the netif_carrier is always off. Hold the mac_lock * @port_initialized: Port initialized? * @net_dev: Operating system network device. Consider holding the rtnl lock @@ -677,6 +756,7 @@ union efx_multicast_hash { * @stats_lock: Statistics update lock. Serialises statistics fetches * @stats_enabled: Temporarily disable statistics fetches. * Serialised by @stats_lock + * @mac_op: MAC interface * @mac_address: Permanent MAC address * @phy_type: PHY type * @phy_lock: PHY access lock @@ -684,13 +764,17 @@ union efx_multicast_hash { * @phy_data: PHY private data (including PHY-specific stats) * @mii: PHY interface * @phy_mode: PHY operating mode. Serialised by @mac_lock. + * @mac_up: MAC link state * @link_up: Link status - * @link_options: Link options (MII/GMII format) + * @link_fd: Link is full duplex + * @link_fc: Actualy flow control flags + * @link_speed: Link speed (Mbps) * @n_link_state_changes: Number of times the link has changed state * @promiscuous: Promiscuous flag. Protected by netif_tx_lock. * @multicast_hash: Multicast hash table - * @flow_control: Flow control flags - separate RX/TX so can't use link_options - * @reconfigure_work: work item for dealing with PHY events + * @wanted_fc: Wanted flow control flags + * @phy_work: work item for dealing with PHY events + * @mac_work: work item for dealing with MAC events * @loopback_mode: Loopback status * @loopback_modes: Supported loopback mode bitmask * @loopback_selftest: Offline self-test private state @@ -704,7 +788,7 @@ struct efx_nic { const struct efx_nic_type *type; int legacy_irq; struct workqueue_struct *workqueue; - struct workqueue_struct *reset_workqueue; + char workqueue_name[16]; struct work_struct reset_work; struct delayed_work monitor_work; resource_size_t membase_phys; @@ -723,6 +807,7 @@ struct efx_nic { struct efx_channel channel[EFX_MAX_CHANNELS]; int n_rx_queues; + int n_channels; unsigned int rx_buffer_len; unsigned int rx_buffer_order; @@ -731,12 +816,14 @@ struct efx_nic { struct efx_spi_device *spi_flash; struct efx_spi_device *spi_eeprom; + struct mutex spi_lock; unsigned n_rx_nodesc_drop_cnt; struct falcon_nic_data *nic_data; struct mutex mac_lock; + struct work_struct mac_work; bool port_enabled; bool port_inhibited; @@ -752,23 +839,27 @@ struct efx_nic { spinlock_t stats_lock; bool stats_enabled; + struct efx_mac_operations *mac_op; unsigned char mac_address[ETH_ALEN]; enum phy_type phy_type; spinlock_t phy_lock; + struct work_struct phy_work; struct efx_phy_operations *phy_op; void *phy_data; struct mii_if_info mii; enum efx_phy_mode phy_mode; + bool mac_up; bool link_up; - unsigned int link_options; + bool link_fd; + enum efx_fc_type link_fc; + unsigned int link_speed; unsigned int n_link_state_changes; bool promiscuous; union efx_multicast_hash multicast_hash; - enum efx_fc_type flow_control; - struct work_struct reconfigure_work; + enum efx_fc_type wanted_fc; atomic_t rx_reset; enum efx_loopback_mode loopback_mode; diff --git a/drivers/net/sfc/phy.h b/drivers/net/sfc/phy.h index f746536f4ffaebab288537973eb85cb33294be71..58c493ef81bb09f5aa5d5120c4bf417a28ab8246 100644 --- a/drivers/net/sfc/phy.h +++ b/drivers/net/sfc/phy.h @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2007 Solarflare Communications Inc. + * Copyright 2007-2008 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published @@ -11,9 +11,10 @@ #define EFX_PHY_H /**************************************************************************** - * 10Xpress (SFX7101) PHY + * 10Xpress (SFX7101 and SFT9001) PHYs */ -extern struct efx_phy_operations falcon_tenxpress_phy_ops; +extern struct efx_phy_operations falcon_sfx7101_phy_ops; +extern struct efx_phy_operations falcon_sft9001_phy_ops; extern void tenxpress_phy_blink(struct efx_nic *efx, bool blink); extern void tenxpress_crc_err(struct efx_nic *efx); diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c index 0f805da4ce55e9c09abd9f6102eb741dbe7f71be..b8ba4bbad8897f384f6eb6f6168cce13df95132a 100644 --- a/drivers/net/sfc/rx.c +++ b/drivers/net/sfc/rx.c @@ -752,7 +752,7 @@ void __efx_rx_packet(struct efx_channel *channel, channel->rx_alloc_level += RX_ALLOC_FACTOR_SKB; done: - efx->net_dev->last_rx = jiffies; + ; } void efx_rx_strategy(struct efx_channel *channel) diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index 362956e3fe172ef1b0daaa2c5e10ac276b42f4b9..dba0d64d50cd07aeffe70c7b6af614d755d43989 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -26,7 +26,6 @@ #include "selftest.h" #include "boards.h" #include "workarounds.h" -#include "mac.h" #include "spi.h" #include "falcon_io.h" #include "mdio_10g.h" @@ -105,9 +104,11 @@ static int efx_test_mii(struct efx_nic *efx, struct efx_self_tests *tests) goto out; } - rc = mdio_clause45_check_mmds(efx, efx->phy_op->mmds, 0); - if (rc) - goto out; + if (EFX_IS10G(efx)) { + rc = mdio_clause45_check_mmds(efx, efx->phy_op->mmds, 0); + if (rc) + goto out; + } out: mutex_unlock(&efx->mac_lock); @@ -246,17 +247,20 @@ static int efx_test_eventq_irq(struct efx_channel *channel, return 0; } -static int efx_test_phy(struct efx_nic *efx, struct efx_self_tests *tests) +static int efx_test_phy(struct efx_nic *efx, struct efx_self_tests *tests, + unsigned flags) { int rc; - if (!efx->phy_op->test) + if (!efx->phy_op->run_tests) return 0; + EFX_BUG_ON_PARANOID(efx->phy_op->num_tests == 0 || + efx->phy_op->num_tests > EFX_MAX_PHY_TESTS); + mutex_lock(&efx->mac_lock); - rc = efx->phy_op->test(efx); + rc = efx->phy_op->run_tests(efx, tests->phy, flags); mutex_unlock(&efx->mac_lock); - tests->phy = rc ? -1 : 1; return rc; } @@ -563,8 +567,7 @@ efx_test_loopback(struct efx_tx_queue *tx_queue, return 0; } -static int efx_test_loopbacks(struct efx_nic *efx, struct ethtool_cmd ecmd, - struct efx_self_tests *tests, +static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests, unsigned int loopback_modes) { enum efx_loopback_mode mode; @@ -593,12 +596,14 @@ static int efx_test_loopbacks(struct efx_nic *efx, struct ethtool_cmd ecmd, efx->loopback_mode = mode; efx_reconfigure_port(efx); - /* Wait for the PHY to signal the link is up */ + /* Wait for the PHY to signal the link is up. Interrupts + * are enabled for PHY's using LASI, otherwise we poll() + * quickly */ count = 0; do { struct efx_channel *channel = &efx->channel[0]; - falcon_check_xmac(efx); + efx->phy_op->poll(efx); schedule_timeout_uninterruptible(HZ / 10); if (channel->work_pending) efx_process_channel_now(channel); @@ -606,13 +611,12 @@ static int efx_test_loopbacks(struct efx_nic *efx, struct ethtool_cmd ecmd, flush_workqueue(efx->workqueue); rmb(); - /* efx->link_up can be 1 even if the XAUI link is down, - * (bug5762). Usually, it's not worth bothering with the - * difference, but for selftests, we need that extra - * guarantee that the link is really, really, up. - */ + /* We need both the phy and xaui links to be ok. + * rather than relying on the falcon_xmac irq/poll + * regime, just poll xaui directly */ link_up = efx->link_up; - if (!falcon_xaui_link_ok(efx)) + if (link_up && EFX_IS10G(efx) && + !falcon_xaui_link_ok(efx)) link_up = false; } while ((++count < 20) && !link_up); @@ -652,47 +656,48 @@ static int efx_test_loopbacks(struct efx_nic *efx, struct ethtool_cmd ecmd, /************************************************************************** * - * Entry points + * Entry point * *************************************************************************/ -/* Online (i.e. non-disruptive) testing - * This checks interrupt generation, event delivery and PHY presence. */ -int efx_online_test(struct efx_nic *efx, struct efx_self_tests *tests) +int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, + unsigned flags) { + enum efx_loopback_mode loopback_mode = efx->loopback_mode; + int phy_mode = efx->phy_mode; + struct ethtool_cmd ecmd; struct efx_channel *channel; - int rc, rc2 = 0; + int rc_test = 0, rc_reset = 0, rc; + + /* Online (i.e. non-disruptive) testing + * This checks interrupt generation, event delivery and PHY presence. */ rc = efx_test_mii(efx, tests); - if (rc && !rc2) - rc2 = rc; + if (rc && !rc_test) + rc_test = rc; rc = efx_test_nvram(efx, tests); - if (rc && !rc2) - rc2 = rc; + if (rc && !rc_test) + rc_test = rc; rc = efx_test_interrupts(efx, tests); - if (rc && !rc2) - rc2 = rc; + if (rc && !rc_test) + rc_test = rc; efx_for_each_channel(channel, efx) { rc = efx_test_eventq_irq(channel, tests); - if (rc && !rc2) - rc2 = rc; + if (rc && !rc_test) + rc_test = rc; } - return rc2; -} + if (rc_test) + return rc_test; -/* Offline (i.e. disruptive) testing - * This checks MAC and PHY loopback on the specified port. */ -int efx_offline_test(struct efx_nic *efx, - struct efx_self_tests *tests, unsigned int loopback_modes) -{ - enum efx_loopback_mode loopback_mode = efx->loopback_mode; - int phy_mode = efx->phy_mode; - struct ethtool_cmd ecmd, ecmd_test; - int rc, rc2 = 0; + if (!(flags & ETH_TEST_FL_OFFLINE)) + return efx_test_phy(efx, tests, flags); + + /* Offline (i.e. disruptive) testing + * This checks MAC and PHY loopback on the specified port. */ /* force the carrier state off so the kernel doesn't transmit during * the loopback test, and the watchdog timeout doesn't fire. Also put @@ -700,8 +705,15 @@ int efx_offline_test(struct efx_nic *efx, */ mutex_lock(&efx->mac_lock); efx->port_inhibited = true; - if (efx->loopback_modes) - efx->loopback_mode = __ffs(efx->loopback_modes); + if (efx->loopback_modes) { + /* We need the 312 clock from the PHY to test the XMAC + * registers, so move into XGMII loopback if available */ + if (efx->loopback_modes & (1 << LOOPBACK_XGMII)) + efx->loopback_mode = LOOPBACK_XGMII; + else + efx->loopback_mode = __ffs(efx->loopback_modes); + } + __efx_reconfigure_port(efx); mutex_unlock(&efx->mac_lock); @@ -709,39 +721,34 @@ int efx_offline_test(struct efx_nic *efx, efx_reset_down(efx, &ecmd); rc = efx_test_chip(efx, tests); - if (rc && !rc2) - rc2 = rc; + if (rc && !rc_test) + rc_test = rc; /* reset the chip to recover from the register test */ - rc = falcon_reset_hw(efx, RESET_TYPE_ALL); - - /* Modify the saved ecmd so that when efx_reset_up() restores the phy - * state, AN is disabled, and the phy is powered, and out of loopback */ - memcpy(&ecmd_test, &ecmd, sizeof(ecmd_test)); - if (ecmd_test.autoneg == AUTONEG_ENABLE) { - ecmd_test.autoneg = AUTONEG_DISABLE; - ecmd_test.duplex = DUPLEX_FULL; - ecmd_test.speed = SPEED_10000; - } + rc_reset = falcon_reset_hw(efx, RESET_TYPE_ALL); + + /* Ensure that the phy is powered and out of loopback + * for the bist and loopback tests */ + efx->phy_mode &= ~PHY_MODE_LOW_POWER; efx->loopback_mode = LOOPBACK_NONE; - rc = efx_reset_up(efx, &ecmd_test, rc == 0); - if (rc) { + rc = efx_reset_up(efx, &ecmd, rc_reset == 0); + if (rc && !rc_reset) + rc_reset = rc; + + if (rc_reset) { EFX_ERR(efx, "Unable to recover from chip test\n"); efx_schedule_reset(efx, RESET_TYPE_DISABLE); - return rc; + return rc_reset; } - tests->loopback_speed = ecmd_test.speed; - tests->loopback_full_duplex = ecmd_test.duplex; - - rc = efx_test_phy(efx, tests); - if (rc && !rc2) - rc2 = rc; + rc = efx_test_phy(efx, tests, flags); + if (rc && !rc_test) + rc_test = rc; - rc = efx_test_loopbacks(efx, ecmd_test, tests, loopback_modes); - if (rc && !rc2) - rc2 = rc; + rc = efx_test_loopbacks(efx, tests, efx->loopback_modes); + if (rc && !rc_test) + rc_test = rc; /* restore the PHY to the previous state */ efx->loopback_mode = loopback_mode; @@ -749,6 +756,6 @@ int efx_offline_test(struct efx_nic *efx, efx->port_inhibited = false; efx_ethtool_set_settings(efx->net_dev, &ecmd); - return rc2; + return rc_test; } diff --git a/drivers/net/sfc/selftest.h b/drivers/net/sfc/selftest.h index fc15df15d76645c08b318988eadced248c5483cf..39451cf938cfe7bd1448553fa9b0fb13e8b33f89 100644 --- a/drivers/net/sfc/selftest.h +++ b/drivers/net/sfc/selftest.h @@ -24,6 +24,8 @@ struct efx_loopback_self_tests { int rx_bad; }; +#define EFX_MAX_PHY_TESTS 20 + /* Efx self test results * For fields which are not counters, 1 indicates success and -1 * indicates failure. @@ -38,18 +40,14 @@ struct efx_self_tests { int eventq_poll[EFX_MAX_CHANNELS]; /* offline tests */ int registers; - int phy; - int loopback_speed; - int loopback_full_duplex; + int phy[EFX_MAX_PHY_TESTS]; struct efx_loopback_self_tests loopback[LOOPBACK_TEST_MAX + 1]; }; extern void efx_loopback_rx_packet(struct efx_nic *efx, const char *buf_ptr, int pkt_len); -extern int efx_online_test(struct efx_nic *efx, - struct efx_self_tests *tests); -extern int efx_offline_test(struct efx_nic *efx, - struct efx_self_tests *tests, - unsigned int loopback_modes); +extern int efx_selftest(struct efx_nic *efx, + struct efx_self_tests *tests, + unsigned flags); #endif /* EFX_SELFTEST_H */ diff --git a/drivers/net/sfc/sfe4001.c b/drivers/net/sfc/sfe4001.c index fe4e3fd223307877ce616020f5a7dd672f734b32..16b80acb999204f9ce81f110e3fac11e39b2e4c6 100644 --- a/drivers/net/sfc/sfe4001.c +++ b/drivers/net/sfc/sfe4001.c @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2007 Solarflare Communications Inc. + * Copyright 2007-2008 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published @@ -8,10 +8,21 @@ */ /***************************************************************************** - * Support for the SFE4001 NIC: driver code for the PCA9539 I/O expander that - * controls the PHY power rails, and for the MAX6647 temp. sensor used to check - * the PHY + * Support for the SFE4001 and SFN4111T NICs. + * + * The SFE4001 does not power-up fully at reset due to its high power + * consumption. We control its power via a PCA9539 I/O expander. + * Both boards have a MAX6647 temperature monitor which we expose to + * the lm90 driver. + * + * This also provides minimal support for reflashing the PHY, which is + * initiated by resetting it with the FLASH_CFG_1 pin pulled down. + * On SFE4001 rev A2 and later this is connected to the 3V3X output of + * the IO-expander; on the SFN4111T it is connected to Falcon's GPIO3. + * We represent reflash mode as PHY_MODE_SPECIAL and make it mutually + * exclusive with the network device being open. */ + #include #include "net_driver.h" #include "efx.h" @@ -21,6 +32,7 @@ #include "falcon_hwdefs.h" #include "falcon_io.h" #include "mac.h" +#include "workarounds.h" /************************************************************************** * @@ -65,48 +77,9 @@ #define P1_SPARE_LBN 4 #define P1_SPARE_WIDTH 4 - -/************************************************************************** - * - * Temperature Sensor - * - **************************************************************************/ -#define MAX6647 0x4e - -#define RLTS 0x00 -#define RLTE 0x01 -#define RSL 0x02 -#define RCL 0x03 -#define RCRA 0x04 -#define RLHN 0x05 -#define RLLI 0x06 -#define RRHI 0x07 -#define RRLS 0x08 -#define WCRW 0x0a -#define WLHO 0x0b -#define WRHA 0x0c -#define WRLN 0x0e -#define OSHT 0x0f -#define REET 0x10 -#define RIET 0x11 -#define RWOE 0x19 -#define RWOI 0x20 -#define HYS 0x21 -#define QUEUE 0x22 -#define MFID 0xfe -#define REVID 0xff - -/* Status bits */ -#define MAX6647_BUSY (1 << 7) /* ADC is converting */ -#define MAX6647_LHIGH (1 << 6) /* Local high temp. alarm */ -#define MAX6647_LLOW (1 << 5) /* Local low temp. alarm */ -#define MAX6647_RHIGH (1 << 4) /* Remote high temp. alarm */ -#define MAX6647_RLOW (1 << 3) /* Remote low temp. alarm */ -#define MAX6647_FAULT (1 << 2) /* DXN/DXP short/open circuit */ -#define MAX6647_EOT (1 << 1) /* Remote junction overtemp. */ -#define MAX6647_IOT (1 << 0) /* Local junction overtemp. */ - -static const u8 xgphy_max_temperature = 90; +/* Temperature Sensor */ +#define MAX664X_REG_RSL 0x02 +#define MAX664X_REG_WLHO 0x0B static void sfe4001_poweroff(struct efx_nic *efx) { @@ -119,7 +92,7 @@ static void sfe4001_poweroff(struct efx_nic *efx) i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0xff); /* Clear any over-temperature alert */ - i2c_smbus_read_byte_data(hwmon_client, RSL); + i2c_smbus_read_byte_data(hwmon_client, MAX664X_REG_RSL); } static int sfe4001_poweron(struct efx_nic *efx) @@ -131,7 +104,7 @@ static int sfe4001_poweron(struct efx_nic *efx) u8 out; /* Clear any previous over-temperature alert */ - rc = i2c_smbus_read_byte_data(hwmon_client, RSL); + rc = i2c_smbus_read_byte_data(hwmon_client, MAX664X_REG_RSL); if (rc < 0) return rc; @@ -209,10 +182,29 @@ static int sfe4001_poweron(struct efx_nic *efx) return rc; } -/* On SFE4001 rev A2 and later, we can control the FLASH_CFG_1 pin - * using the 3V3X output of the IO-expander. Allow the user to set - * this when the device is stopped, and keep it stopped then. - */ +static int sfn4111t_reset(struct efx_nic *efx) +{ + efx_oword_t reg; + + /* GPIO pins are also used for I2C, so block that temporarily */ + mutex_lock(&efx->i2c_adap.bus_lock); + + falcon_read(efx, ®, GPIO_CTL_REG_KER); + EFX_SET_OWORD_FIELD(reg, GPIO2_OEN, true); + EFX_SET_OWORD_FIELD(reg, GPIO2_OUT, false); + falcon_write(efx, ®, GPIO_CTL_REG_KER); + msleep(1000); + EFX_SET_OWORD_FIELD(reg, GPIO2_OUT, true); + EFX_SET_OWORD_FIELD(reg, GPIO3_OEN, true); + EFX_SET_OWORD_FIELD(reg, GPIO3_OUT, + !(efx->phy_mode & PHY_MODE_SPECIAL)); + falcon_write(efx, ®, GPIO_CTL_REG_KER); + + mutex_unlock(&efx->i2c_adap.bus_lock); + + ssleep(1); + return 0; +} static ssize_t show_phy_flash_cfg(struct device *dev, struct device_attribute *attr, char *buf) @@ -241,7 +233,10 @@ static ssize_t set_phy_flash_cfg(struct device *dev, err = -EBUSY; } else { efx->phy_mode = new_mode; - err = sfe4001_poweron(efx); + if (efx->board_info.type == EFX_BOARD_SFE4001) + err = sfe4001_poweron(efx); + else + err = sfn4111t_reset(efx); efx_reconfigure_port(efx); } rtnl_unlock(); @@ -261,35 +256,62 @@ static void sfe4001_fini(struct efx_nic *efx) i2c_unregister_device(efx->board_info.hwmon_client); } +static int sfe4001_check_hw(struct efx_nic *efx) +{ + s32 status; + + /* If XAUI link is up then do not monitor */ + if (EFX_WORKAROUND_7884(efx) && efx->mac_up) + return 0; + + /* Check the powered status of the PHY. Lack of power implies that + * the MAX6647 has shut down power to it, probably due to a temp. + * alarm. Reading the power status rather than the MAX6647 status + * directly because the later is read-to-clear and would thus + * start to power up the PHY again when polled, causing us to blip + * the power undesirably. + * We know we can read from the IO expander because we did + * it during power-on. Assume failure now is bad news. */ + status = i2c_smbus_read_byte_data(efx->board_info.ioexp_client, P1_IN); + if (status >= 0 && + (status & ((1 << P1_AFE_PWD_LBN) | (1 << P1_DSP_PWD25_LBN))) != 0) + return 0; + + /* Use board power control, not PHY power control */ + sfe4001_poweroff(efx); + efx->phy_mode = PHY_MODE_OFF; + + return (status < 0) ? -EIO : -ERANGE; +} + +static struct i2c_board_info sfe4001_hwmon_info = { + I2C_BOARD_INFO("max6647", 0x4e), + .irq = -1, +}; + /* This board uses an I2C expander to provider power to the PHY, which needs to * be turned on before the PHY can be used. * Context: Process context, rtnl lock held */ int sfe4001_init(struct efx_nic *efx) { - struct i2c_client *hwmon_client; int rc; - hwmon_client = i2c_new_dummy(&efx->i2c_adap, MAX6647); - if (!hwmon_client) +#if defined(CONFIG_SENSORS_LM90) || defined(CONFIG_SENSORS_LM90_MODULE) + efx->board_info.hwmon_client = + i2c_new_device(&efx->i2c_adap, &sfe4001_hwmon_info); +#else + efx->board_info.hwmon_client = + i2c_new_dummy(&efx->i2c_adap, sfe4001_hwmon_info.addr); +#endif + if (!efx->board_info.hwmon_client) return -EIO; - efx->board_info.hwmon_client = hwmon_client; - /* Set DSP over-temperature alert threshold */ - EFX_INFO(efx, "DSP cut-out at %dC\n", xgphy_max_temperature); - rc = i2c_smbus_write_byte_data(hwmon_client, WLHO, - xgphy_max_temperature); + /* Raise board/PHY high limit from 85 to 90 degrees Celsius */ + rc = i2c_smbus_write_byte_data(efx->board_info.hwmon_client, + MAX664X_REG_WLHO, 90); if (rc) - goto fail_ioexp; - - /* Read it back and verify */ - rc = i2c_smbus_read_byte_data(hwmon_client, RLHN); - if (rc < 0) - goto fail_ioexp; - if (rc != xgphy_max_temperature) { - rc = -EFAULT; - goto fail_ioexp; - } + goto fail_hwmon; efx->board_info.ioexp_client = i2c_new_dummy(&efx->i2c_adap, PCA9539); if (!efx->board_info.ioexp_client) { @@ -301,6 +323,7 @@ int sfe4001_init(struct efx_nic *efx) * blink code. */ efx->board_info.blink = tenxpress_phy_blink; + efx->board_info.monitor = sfe4001_check_hw; efx->board_info.fini = sfe4001_fini; rc = sfe4001_poweron(efx); @@ -319,6 +342,64 @@ int sfe4001_init(struct efx_nic *efx) fail_ioexp: i2c_unregister_device(efx->board_info.ioexp_client); fail_hwmon: - i2c_unregister_device(hwmon_client); + i2c_unregister_device(efx->board_info.hwmon_client); + return rc; +} + +static int sfn4111t_check_hw(struct efx_nic *efx) +{ + s32 status; + + /* If XAUI link is up then do not monitor */ + if (EFX_WORKAROUND_7884(efx) && efx->mac_up) + return 0; + + /* Test LHIGH, RHIGH, FAULT, EOT and IOT alarms */ + status = i2c_smbus_read_byte_data(efx->board_info.hwmon_client, + MAX664X_REG_RSL); + if (status < 0) + return -EIO; + if (status & 0x57) + return -ERANGE; + return 0; +} + +static void sfn4111t_fini(struct efx_nic *efx) +{ + EFX_INFO(efx, "%s\n", __func__); + + device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); + i2c_unregister_device(efx->board_info.hwmon_client); +} + +static struct i2c_board_info sfn4111t_hwmon_info = { + I2C_BOARD_INFO("max6647", 0x4e), + .irq = -1, +}; + +int sfn4111t_init(struct efx_nic *efx) +{ + int rc; + + efx->board_info.hwmon_client = + i2c_new_device(&efx->i2c_adap, &sfn4111t_hwmon_info); + if (!efx->board_info.hwmon_client) + return -EIO; + + efx->board_info.blink = tenxpress_phy_blink; + efx->board_info.monitor = sfn4111t_check_hw; + efx->board_info.fini = sfn4111t_fini; + + rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); + if (rc) + goto fail_hwmon; + + if (efx->phy_mode & PHY_MODE_SPECIAL) + sfn4111t_reset(efx); + + return 0; + +fail_hwmon: + i2c_unregister_device(efx->board_info.hwmon_client); return rc; } diff --git a/drivers/net/sfc/spi.h b/drivers/net/sfc/spi.h index feef619423776889a0d275c81ad407c0a1b65465..1b1ceb41167193f13279a1d29aa17446c4886364 100644 --- a/drivers/net/sfc/spi.h +++ b/drivers/net/sfc/spi.h @@ -25,6 +25,7 @@ #define SPI_WRDI 0x04 /* Reset write enable latch */ #define SPI_RDSR 0x05 /* Read status register */ #define SPI_WREN 0x06 /* Set write enable latch */ +#define SPI_SST_EWSR 0x50 /* SST: Enable write to status register */ #define SPI_STATUS_WPEN 0x80 /* Write-protect pin enabled */ #define SPI_STATUS_BP2 0x10 /* Block protection bit 2 */ @@ -36,6 +37,7 @@ /** * struct efx_spi_device - an Efx SPI (Serial Peripheral Interface) device * @efx: The Efx controller that owns this device + * @mtd: MTD state * @device_id: Controller's id for the device * @size: Size (in bytes) * @addr_len: Number of address bytes in read/write commands @@ -44,23 +46,51 @@ * use bit 3 of the command byte as address bit A8, rather * than having a two-byte address. If this flag is set, then * commands should be munged in this way. + * @erase_command: Erase command (or 0 if sector erase not needed). + * @erase_size: Erase sector size (in bytes) + * Erase commands affect sectors with this size and alignment. + * This must be a power of two. * @block_size: Write block size (in bytes). * Write commands are limited to blocks with this size and alignment. - * @read: Read function for the device - * @write: Write function for the device */ struct efx_spi_device { struct efx_nic *efx; +#ifdef CONFIG_SFC_MTD + void *mtd; +#endif int device_id; unsigned int size; unsigned int addr_len; unsigned int munge_address:1; + u8 erase_command; + unsigned int erase_size; unsigned int block_size; }; +int falcon_spi_cmd(const struct efx_spi_device *spi, unsigned int command, + int address, const void* in, void *out, size_t len); +int falcon_spi_wait_write(const struct efx_spi_device *spi); int falcon_spi_read(const struct efx_spi_device *spi, loff_t start, size_t len, size_t *retlen, u8 *buffer); int falcon_spi_write(const struct efx_spi_device *spi, loff_t start, size_t len, size_t *retlen, const u8 *buffer); +/* + * SFC4000 flash is partitioned into: + * 0-0x400 chip and board config (see falcon_hwdefs.h) + * 0x400-0x8000 unused (or may contain VPD if EEPROM not present) + * 0x8000-end boot code (mapped to PCI expansion ROM) + * SFC4000 small EEPROM (size < 0x400) is used for VPD only. + * SFC4000 large EEPROM (size >= 0x400) is partitioned into: + * 0-0x400 chip and board config + * configurable VPD + * 0x800-0x1800 boot config + * Aside from the chip and board config, all of these are optional and may + * be absent or truncated depending on the devices used. + */ +#define FALCON_NVCONFIG_END 0x400U +#define FALCON_FLASH_BOOTCODE_START 0x8000U +#define EFX_EEPROM_BOOTCONFIG_START 0x800U +#define EFX_EEPROM_BOOTCONFIG_END 0x1800U + #endif /* EFX_SPI_H */ diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index d507c93d666e1130dc2cd27768f38f2c4b710221..b9768760fae7f8de80fa4109a4514d16e3c14ff7 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -1,6 +1,6 @@ /**************************************************************************** - * Driver for Solarflare 802.3an compliant PHY - * Copyright 2007 Solarflare Communications Inc. + * Driver for Solarflare Solarstorm network controllers and boards + * Copyright 2007-2008 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published @@ -10,45 +10,76 @@ #include #include #include "efx.h" -#include "gmii.h" #include "mdio_10g.h" #include "falcon.h" #include "phy.h" #include "falcon_hwdefs.h" #include "boards.h" -#include "mac.h" +#include "workarounds.h" +#include "selftest.h" -/* We expect these MMDs to be in the package */ -/* AN not here as mdio_check_mmds() requires STAT2 support */ -#define TENXPRESS_REQUIRED_DEVS (MDIO_MMDREG_DEVS0_PMAPMD | \ - MDIO_MMDREG_DEVS0_PCS | \ - MDIO_MMDREG_DEVS0_PHYXS) - -#define TENXPRESS_LOOPBACKS ((1 << LOOPBACK_PHYXS) | \ - (1 << LOOPBACK_PCS) | \ - (1 << LOOPBACK_PMAPMD) | \ - (1 << LOOPBACK_NETWORK)) +/* We expect these MMDs to be in the package. SFT9001 also has a + * clause 22 extension MMD, but since it doesn't have all the generic + * MMD registers it is pointless to include it here. + */ +#define TENXPRESS_REQUIRED_DEVS (MDIO_MMDREG_DEVS_PMAPMD | \ + MDIO_MMDREG_DEVS_PCS | \ + MDIO_MMDREG_DEVS_PHYXS | \ + MDIO_MMDREG_DEVS_AN) + +#define SFX7101_LOOPBACKS ((1 << LOOPBACK_PHYXS) | \ + (1 << LOOPBACK_PCS) | \ + (1 << LOOPBACK_PMAPMD) | \ + (1 << LOOPBACK_NETWORK)) + +#define SFT9001_LOOPBACKS ((1 << LOOPBACK_GPHY) | \ + (1 << LOOPBACK_PHYXS) | \ + (1 << LOOPBACK_PCS) | \ + (1 << LOOPBACK_PMAPMD) | \ + (1 << LOOPBACK_NETWORK)) /* We complain if we fail to see the link partner as 10G capable this many * times in a row (must be > 1 as sampling the autoneg. registers is racy) */ #define MAX_BAD_LP_TRIES (5) +/* LASI Control */ +#define PMA_PMD_LASI_CTRL 36866 +#define PMA_PMD_LASI_STATUS 36869 +#define PMA_PMD_LS_ALARM_LBN 0 +#define PMA_PMD_LS_ALARM_WIDTH 1 +#define PMA_PMD_TX_ALARM_LBN 1 +#define PMA_PMD_TX_ALARM_WIDTH 1 +#define PMA_PMD_RX_ALARM_LBN 2 +#define PMA_PMD_RX_ALARM_WIDTH 1 +#define PMA_PMD_AN_ALARM_LBN 3 +#define PMA_PMD_AN_ALARM_WIDTH 1 + /* Extended control register */ -#define PMA_PMD_XCONTROL_REG 0xc000 -#define PMA_PMD_LNPGA_POWERDOWN_LBN 8 -#define PMA_PMD_LNPGA_POWERDOWN_WIDTH 1 +#define PMA_PMD_XCONTROL_REG 49152 +#define PMA_PMD_EXT_GMII_EN_LBN 1 +#define PMA_PMD_EXT_GMII_EN_WIDTH 1 +#define PMA_PMD_EXT_CLK_OUT_LBN 2 +#define PMA_PMD_EXT_CLK_OUT_WIDTH 1 +#define PMA_PMD_LNPGA_POWERDOWN_LBN 8 /* SFX7101 only */ +#define PMA_PMD_LNPGA_POWERDOWN_WIDTH 1 +#define PMA_PMD_EXT_CLK312_LBN 8 /* SFT9001 only */ +#define PMA_PMD_EXT_CLK312_WIDTH 1 +#define PMA_PMD_EXT_LPOWER_LBN 12 +#define PMA_PMD_EXT_LPOWER_WIDTH 1 +#define PMA_PMD_EXT_SSR_LBN 15 +#define PMA_PMD_EXT_SSR_WIDTH 1 /* extended status register */ -#define PMA_PMD_XSTATUS_REG 0xc001 +#define PMA_PMD_XSTATUS_REG 49153 #define PMA_PMD_XSTAT_FLP_LBN (12) /* LED control register */ -#define PMA_PMD_LED_CTRL_REG (0xc007) +#define PMA_PMD_LED_CTRL_REG 49159 #define PMA_PMA_LED_ACTIVITY_LBN (3) /* LED function override register */ -#define PMA_PMD_LED_OVERR_REG (0xc009) +#define PMA_PMD_LED_OVERR_REG 49161 /* Bit positions for different LEDs (there are more but not wired on SFE4001)*/ #define PMA_PMD_LED_LINK_LBN (0) #define PMA_PMD_LED_SPEED_LBN (2) @@ -59,41 +90,99 @@ #define PMA_PMD_LED_ON (1) #define PMA_PMD_LED_OFF (2) #define PMA_PMD_LED_FLASH (3) +#define PMA_PMD_LED_MASK 3 /* All LEDs under hardware control */ #define PMA_PMD_LED_FULL_AUTO (0) /* Green and Amber under hardware control, Red off */ #define PMA_PMD_LED_DEFAULT (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN) - -/* Special Software reset register */ -#define PMA_PMD_EXT_CTRL_REG 49152 -#define PMA_PMD_EXT_SSR_LBN 15 - -/* Misc register defines */ -#define PCS_CLOCK_CTRL_REG 0xd801 +#define PMA_PMD_SPEED_ENABLE_REG 49192 +#define PMA_PMD_100TX_ADV_LBN 1 +#define PMA_PMD_100TX_ADV_WIDTH 1 +#define PMA_PMD_1000T_ADV_LBN 2 +#define PMA_PMD_1000T_ADV_WIDTH 1 +#define PMA_PMD_10000T_ADV_LBN 3 +#define PMA_PMD_10000T_ADV_WIDTH 1 +#define PMA_PMD_SPEED_LBN 4 +#define PMA_PMD_SPEED_WIDTH 4 + +/* Cable diagnostics - SFT9001 only */ +#define PMA_PMD_CDIAG_CTRL_REG 49213 +#define CDIAG_CTRL_IMMED_LBN 15 +#define CDIAG_CTRL_BRK_LINK_LBN 12 +#define CDIAG_CTRL_IN_PROG_LBN 11 +#define CDIAG_CTRL_LEN_UNIT_LBN 10 +#define CDIAG_CTRL_LEN_METRES 1 +#define PMA_PMD_CDIAG_RES_REG 49174 +#define CDIAG_RES_A_LBN 12 +#define CDIAG_RES_B_LBN 8 +#define CDIAG_RES_C_LBN 4 +#define CDIAG_RES_D_LBN 0 +#define CDIAG_RES_WIDTH 4 +#define CDIAG_RES_OPEN 2 +#define CDIAG_RES_OK 1 +#define CDIAG_RES_INVALID 0 +/* Set of 4 registers for pairs A-D */ +#define PMA_PMD_CDIAG_LEN_REG 49175 + +/* Serdes control registers - SFT9001 only */ +#define PMA_PMD_CSERDES_CTRL_REG 64258 +/* Set the 156.25 MHz output to 312.5 MHz to drive Falcon's XMAC */ +#define PMA_PMD_CSERDES_DEFAULT 0x000f + +/* Misc register defines - SFX7101 only */ +#define PCS_CLOCK_CTRL_REG 55297 #define PLL312_RST_N_LBN 2 -#define PCS_SOFT_RST2_REG 0xd806 +#define PCS_SOFT_RST2_REG 55302 #define SERDES_RST_N_LBN 13 #define XGXS_RST_N_LBN 12 -#define PCS_TEST_SELECT_REG 0xd807 /* PRM 10.5.8 */ +#define PCS_TEST_SELECT_REG 55303 /* PRM 10.5.8 */ #define CLK312_EN_LBN 3 /* PHYXS registers */ +#define PHYXS_XCONTROL_REG 49152 +#define PHYXS_RESET_LBN 15 +#define PHYXS_RESET_WIDTH 1 + #define PHYXS_TEST1 (49162) #define LOOPBACK_NEAR_LBN (8) #define LOOPBACK_NEAR_WIDTH (1) +#define PCS_10GBASET_STAT1 32 +#define PCS_10GBASET_BLKLK_LBN 0 +#define PCS_10GBASET_BLKLK_WIDTH 1 + /* Boot status register */ -#define PCS_BOOT_STATUS_REG (0xd000) +#define PCS_BOOT_STATUS_REG 53248 #define PCS_BOOT_FATAL_ERR_LBN (0) #define PCS_BOOT_PROGRESS_LBN (1) #define PCS_BOOT_PROGRESS_WIDTH (2) #define PCS_BOOT_COMPLETE_LBN (3) + #define PCS_BOOT_MAX_DELAY (100) #define PCS_BOOT_POLL_DELAY (10) +/* 100M/1G PHY registers */ +#define GPHY_XCONTROL_REG 49152 +#define GPHY_ISOLATE_LBN 10 +#define GPHY_ISOLATE_WIDTH 1 +#define GPHY_DUPLEX_LBN 8 +#define GPHY_DUPLEX_WIDTH 1 +#define GPHY_LOOPBACK_NEAR_LBN 14 +#define GPHY_LOOPBACK_NEAR_WIDTH 1 + +#define C22EXT_STATUS_REG 49153 +#define C22EXT_STATUS_LINK_LBN 2 +#define C22EXT_STATUS_LINK_WIDTH 1 + +#define C22EXT_MSTSLV_REG 49162 +#define C22EXT_MSTSLV_1000_HD_LBN 10 +#define C22EXT_MSTSLV_1000_HD_WIDTH 1 +#define C22EXT_MSTSLV_1000_FD_LBN 11 +#define C22EXT_MSTSLV_1000_FD_WIDTH 1 + /* Time to wait between powering down the LNPGA and turning off the power * rails */ #define LNPGA_PDOWN_WAIT (HZ / 5) @@ -117,6 +206,38 @@ void tenxpress_crc_err(struct efx_nic *efx) atomic_inc(&phy_data->bad_crc_count); } +static ssize_t show_phy_short_reach(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); + int reg; + + reg = mdio_clause45_read(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, + MDIO_PMAPMD_10GBT_TXPWR); + return sprintf(buf, "%d\n", + !!(reg & (1 << MDIO_PMAPMD_10GBT_TXPWR_SHORT_LBN))); +} + +static ssize_t set_phy_short_reach(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); + + rtnl_lock(); + mdio_clause45_set_flag(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, + MDIO_PMAPMD_10GBT_TXPWR, + MDIO_PMAPMD_10GBT_TXPWR_SHORT_LBN, + count != 0 && *buf != '0'); + efx_reconfigure_port(efx); + rtnl_unlock(); + + return count; +} + +static DEVICE_ATTR(phy_short_reach, 0644, show_phy_short_reach, + set_phy_short_reach); + /* Check that the C166 has booted successfully */ static int tenxpress_phy_check(struct efx_nic *efx) { @@ -148,27 +269,42 @@ static int tenxpress_phy_check(struct efx_nic *efx) static int tenxpress_init(struct efx_nic *efx) { - int rc, reg; + int phy_id = efx->mii.phy_id; + int reg; + int rc; - /* Turn on the clock */ - reg = (1 << CLK312_EN_LBN); - mdio_clause45_write(efx, efx->mii.phy_id, - MDIO_MMD_PCS, PCS_TEST_SELECT_REG, reg); + if (efx->phy_type == PHY_TYPE_SFX7101) { + /* Enable 312.5 MHz clock */ + mdio_clause45_write(efx, phy_id, + MDIO_MMD_PCS, PCS_TEST_SELECT_REG, + 1 << CLK312_EN_LBN); + } else { + /* Enable 312.5 MHz clock and GMII */ + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, + PMA_PMD_XCONTROL_REG); + reg |= ((1 << PMA_PMD_EXT_GMII_EN_LBN) | + (1 << PMA_PMD_EXT_CLK_OUT_LBN) | + (1 << PMA_PMD_EXT_CLK312_LBN)); + mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, + PMA_PMD_XCONTROL_REG, reg); + mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_C22EXT, + GPHY_XCONTROL_REG, GPHY_ISOLATE_LBN, + false); + } rc = tenxpress_phy_check(efx); if (rc < 0) return rc; /* Set the LEDs up as: Green = Link, Amber = Link/Act, Red = Off */ - reg = mdio_clause45_read(efx, efx->mii.phy_id, - MDIO_MMD_PMAPMD, PMA_PMD_LED_CTRL_REG); - reg |= (1 << PMA_PMA_LED_ACTIVITY_LBN); - mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_LED_CTRL_REG, reg); - - reg = PMA_PMD_LED_DEFAULT; - mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_LED_OVERR_REG, reg); + if (efx->phy_type == PHY_TYPE_SFX7101) { + mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PMAPMD, + PMA_PMD_LED_CTRL_REG, + PMA_PMA_LED_ACTIVITY_LBN, + true); + mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, + PMA_PMD_LED_OVERR_REG, PMA_PMD_LED_DEFAULT); + } return rc; } @@ -184,22 +320,43 @@ static int tenxpress_phy_init(struct efx_nic *efx) efx->phy_data = phy_data; phy_data->phy_mode = efx->phy_mode; - rc = mdio_clause45_wait_reset_mmds(efx, - TENXPRESS_REQUIRED_DEVS); - if (rc < 0) - goto fail; + if (!(efx->phy_mode & PHY_MODE_SPECIAL)) { + if (efx->phy_type == PHY_TYPE_SFT9001A) { + int reg; + reg = mdio_clause45_read(efx, efx->mii.phy_id, + MDIO_MMD_PMAPMD, + PMA_PMD_XCONTROL_REG); + reg |= (1 << PMA_PMD_EXT_SSR_LBN); + mdio_clause45_write(efx, efx->mii.phy_id, + MDIO_MMD_PMAPMD, + PMA_PMD_XCONTROL_REG, reg); + mdelay(200); + } - rc = mdio_clause45_check_mmds(efx, TENXPRESS_REQUIRED_DEVS, 0); - if (rc < 0) - goto fail; + rc = mdio_clause45_wait_reset_mmds(efx, + TENXPRESS_REQUIRED_DEVS); + if (rc < 0) + goto fail; + + rc = mdio_clause45_check_mmds(efx, TENXPRESS_REQUIRED_DEVS, 0); + if (rc < 0) + goto fail; + } rc = tenxpress_init(efx); if (rc < 0) goto fail; + if (efx->phy_type == PHY_TYPE_SFT9001B) { + rc = device_create_file(&efx->pci_dev->dev, + &dev_attr_phy_short_reach); + if (rc) + goto fail; + } + schedule_timeout_uninterruptible(HZ / 5); /* 200ms */ - /* Let XGXS and SerDes out of reset and resets 10XPress */ + /* Let XGXS and SerDes out of reset */ falcon_reset_xaui(efx); return 0; @@ -210,21 +367,24 @@ static int tenxpress_phy_init(struct efx_nic *efx) return rc; } +/* Perform a "special software reset" on the PHY. The caller is + * responsible for saving and restoring the PHY hardware registers + * properly, and masking/unmasking LASI */ static int tenxpress_special_reset(struct efx_nic *efx) { int rc, reg; /* The XGMAC clock is driven from the SFC7101/SFT9001 312MHz clock, so * a special software reset can glitch the XGMAC sufficiently for stats - * requests to fail. Since we don't ofen special_reset, just lock. */ + * requests to fail. Since we don't often special_reset, just lock. */ spin_lock(&efx->stats_lock); /* Initiate reset */ reg = mdio_clause45_read(efx, efx->mii.phy_id, - MDIO_MMD_PMAPMD, PMA_PMD_EXT_CTRL_REG); + MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG); reg |= (1 << PMA_PMD_EXT_SSR_LBN); mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_EXT_CTRL_REG, reg); + PMA_PMD_XCONTROL_REG, reg); mdelay(200); @@ -239,174 +399,257 @@ static int tenxpress_special_reset(struct efx_nic *efx) if (rc < 0) goto unlock; + /* Wait for the XGXS state machine to churn */ + mdelay(10); unlock: spin_unlock(&efx->stats_lock); return rc; } -static void tenxpress_set_bad_lp(struct efx_nic *efx, bool bad_lp) +static void sfx7101_check_bad_lp(struct efx_nic *efx, bool link_ok) { struct tenxpress_phy_data *pd = efx->phy_data; + int phy_id = efx->mii.phy_id; + bool bad_lp; int reg; + if (link_ok) { + bad_lp = false; + } else { + /* Check that AN has started but not completed. */ + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, + MDIO_AN_STATUS); + if (!(reg & (1 << MDIO_AN_STATUS_LP_AN_CAP_LBN))) + return; /* LP status is unknown */ + bad_lp = !(reg & (1 << MDIO_AN_STATUS_AN_DONE_LBN)); + if (bad_lp) + pd->bad_lp_tries++; + } + /* Nothing to do if all is well and was previously so. */ - if (!(bad_lp || pd->bad_lp_tries)) + if (!pd->bad_lp_tries) return; - reg = mdio_clause45_read(efx, efx->mii.phy_id, - MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG); + /* Use the RX (red) LED as an error indicator once we've seen AN + * failure several times in a row, and also log a message. */ + if (!bad_lp || pd->bad_lp_tries == MAX_BAD_LP_TRIES) { + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, + PMA_PMD_LED_OVERR_REG); + reg &= ~(PMA_PMD_LED_MASK << PMA_PMD_LED_RX_LBN); + if (!bad_lp) { + reg |= PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN; + } else { + reg |= PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN; + EFX_ERR(efx, "appears to be plugged into a port" + " that is not 10GBASE-T capable. The PHY" + " supports 10GBASE-T ONLY, so no link can" + " be established\n"); + } + mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, + PMA_PMD_LED_OVERR_REG, reg); + pd->bad_lp_tries = bad_lp; + } +} - if (bad_lp) - pd->bad_lp_tries++; - else - pd->bad_lp_tries = 0; - - if (pd->bad_lp_tries == MAX_BAD_LP_TRIES) { - pd->bad_lp_tries = 0; /* Restart count */ - reg &= ~(PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN); - reg |= (PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN); - EFX_ERR(efx, "This NIC appears to be plugged into" - " a port that is not 10GBASE-T capable.\n" - " This PHY is 10GBASE-T ONLY, so no link can" - " be established.\n"); +static bool sfx7101_link_ok(struct efx_nic *efx) +{ + return mdio_clause45_links_ok(efx, + MDIO_MMDREG_DEVS_PMAPMD | + MDIO_MMDREG_DEVS_PCS | + MDIO_MMDREG_DEVS_PHYXS); +} + +static bool sft9001_link_ok(struct efx_nic *efx, struct ethtool_cmd *ecmd) +{ + int phy_id = efx->mii.phy_id; + u32 reg; + + if (efx_phy_mode_disabled(efx->phy_mode)) + return false; + else if (efx->loopback_mode == LOOPBACK_GPHY) + return true; + else if (efx->loopback_mode) + return mdio_clause45_links_ok(efx, + MDIO_MMDREG_DEVS_PMAPMD | + MDIO_MMDREG_DEVS_PHYXS); + + /* We must use the same definition of link state as LASI, + * otherwise we can miss a link state transition + */ + if (ecmd->speed == 10000) { + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PCS, + PCS_10GBASET_STAT1); + return reg & (1 << PCS_10GBASET_BLKLK_LBN); } else { - reg |= (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN); + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_C22EXT, + C22EXT_STATUS_REG); + return reg & (1 << C22EXT_STATUS_LINK_LBN); } - mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_LED_OVERR_REG, reg); } -/* Check link status and return a boolean OK value. If the link is NOT - * OK we have a quick rummage round to see if we appear to be plugged - * into a non-10GBT port and if so warn the user that they won't get - * link any time soon as we are 10GBT only, unless caller specified - * not to do this check (it isn't useful in loopback) */ -static bool tenxpress_link_ok(struct efx_nic *efx, bool check_lp) +static void tenxpress_ext_loopback(struct efx_nic *efx) { - bool ok = mdio_clause45_links_ok(efx, TENXPRESS_REQUIRED_DEVS); - - if (ok) { - tenxpress_set_bad_lp(efx, false); - } else if (check_lp) { - /* Are we plugged into the wrong sort of link? */ - bool bad_lp = false; - int phy_id = efx->mii.phy_id; - int an_stat = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, - MDIO_AN_STATUS); - int xphy_stat = mdio_clause45_read(efx, phy_id, - MDIO_MMD_PMAPMD, - PMA_PMD_XSTATUS_REG); - /* Are we plugged into anything that sends FLPs? If - * not we can't distinguish between not being plugged - * in and being plugged into a non-AN antique. The FLP - * bit has the advantage of not clearing when autoneg - * restarts. */ - if (!(xphy_stat & (1 << PMA_PMD_XSTAT_FLP_LBN))) { - tenxpress_set_bad_lp(efx, false); - return ok; - } + int phy_id = efx->mii.phy_id; - /* If it can do 10GBT it must be XNP capable */ - bad_lp = !(an_stat & (1 << MDIO_AN_STATUS_XNP_LBN)); - if (!bad_lp && (an_stat & (1 << MDIO_AN_STATUS_PAGE_LBN))) { - bad_lp = !(mdio_clause45_read(efx, phy_id, - MDIO_MMD_AN, MDIO_AN_10GBT_STATUS) & - (1 << MDIO_AN_10GBT_STATUS_LP_10G_LBN)); - } - tenxpress_set_bad_lp(efx, bad_lp); - } - return ok; + mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PHYXS, + PHYXS_TEST1, LOOPBACK_NEAR_LBN, + efx->loopback_mode == LOOPBACK_PHYXS); + if (efx->phy_type != PHY_TYPE_SFX7101) + mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_C22EXT, + GPHY_XCONTROL_REG, + GPHY_LOOPBACK_NEAR_LBN, + efx->loopback_mode == LOOPBACK_GPHY); } -static void tenxpress_phyxs_loopback(struct efx_nic *efx) +static void tenxpress_low_power(struct efx_nic *efx) { int phy_id = efx->mii.phy_id; - int ctrl1, ctrl2; - ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PHYXS, - PHYXS_TEST1); - if (efx->loopback_mode == LOOPBACK_PHYXS) - ctrl2 |= (1 << LOOPBACK_NEAR_LBN); + if (efx->phy_type == PHY_TYPE_SFX7101) + mdio_clause45_set_mmds_lpower( + efx, !!(efx->phy_mode & PHY_MODE_LOW_POWER), + TENXPRESS_REQUIRED_DEVS); else - ctrl2 &= ~(1 << LOOPBACK_NEAR_LBN); - if (ctrl1 != ctrl2) - mdio_clause45_write(efx, phy_id, MDIO_MMD_PHYXS, - PHYXS_TEST1, ctrl2); + mdio_clause45_set_flag( + efx, phy_id, MDIO_MMD_PMAPMD, + PMA_PMD_XCONTROL_REG, PMA_PMD_EXT_LPOWER_LBN, + !!(efx->phy_mode & PHY_MODE_LOW_POWER)); } static void tenxpress_phy_reconfigure(struct efx_nic *efx) { struct tenxpress_phy_data *phy_data = efx->phy_data; - bool loop_change = LOOPBACK_OUT_OF(phy_data, efx, - TENXPRESS_LOOPBACKS); + struct ethtool_cmd ecmd; + bool phy_mode_change, loop_reset, loop_toggle, loopback; - if (efx->phy_mode & PHY_MODE_SPECIAL) { + if (efx->phy_mode & (PHY_MODE_OFF | PHY_MODE_SPECIAL)) { phy_data->phy_mode = efx->phy_mode; return; } - /* When coming out of transmit disable, coming out of low power - * mode, or moving out of any PHY internal loopback mode, - * perform a special software reset */ - if ((efx->phy_mode == PHY_MODE_NORMAL && - phy_data->phy_mode != PHY_MODE_NORMAL) || - loop_change) { - tenxpress_special_reset(efx); - falcon_reset_xaui(efx); + tenxpress_low_power(efx); + + phy_mode_change = (efx->phy_mode == PHY_MODE_NORMAL && + phy_data->phy_mode != PHY_MODE_NORMAL); + loopback = LOOPBACK_MASK(efx) & efx->phy_op->loopbacks; + loop_toggle = LOOPBACK_CHANGED(phy_data, efx, efx->phy_op->loopbacks); + loop_reset = (LOOPBACK_OUT_OF(phy_data, efx, efx->phy_op->loopbacks) || + LOOPBACK_CHANGED(phy_data, efx, 1 << LOOPBACK_GPHY)); + + if (loop_reset || loop_toggle || loopback || phy_mode_change) { + int rc; + + efx->phy_op->get_settings(efx, &ecmd); + + if (loop_reset || phy_mode_change) { + tenxpress_special_reset(efx); + + /* Reset XAUI if we were in 10G, and are staying + * in 10G. If we're moving into and out of 10G + * then xaui will be reset anyway */ + if (EFX_IS10G(efx)) + falcon_reset_xaui(efx); + } + + if (efx->phy_type != PHY_TYPE_SFX7101) { + /* Only change autoneg once, on coming out or + * going into loopback */ + if (loop_toggle) + ecmd.autoneg = !loopback; + if (loopback) { + ecmd.duplex = DUPLEX_FULL; + if (efx->loopback_mode == LOOPBACK_GPHY) + ecmd.speed = SPEED_1000; + else + ecmd.speed = SPEED_10000; + } + } + + rc = efx->phy_op->set_settings(efx, &ecmd); + WARN_ON(rc); } mdio_clause45_transmit_disable(efx); mdio_clause45_phy_reconfigure(efx); - tenxpress_phyxs_loopback(efx); + tenxpress_ext_loopback(efx); phy_data->loopback_mode = efx->loopback_mode; phy_data->phy_mode = efx->phy_mode; - efx->link_up = tenxpress_link_ok(efx, false); - efx->link_options = GM_LPA_10000FULL; -} -static void tenxpress_phy_clear_interrupt(struct efx_nic *efx) -{ - /* Nothing done here - LASI interrupts aren't reliable so poll */ + if (efx->phy_type == PHY_TYPE_SFX7101) { + efx->link_speed = 10000; + efx->link_fd = true; + efx->link_up = sfx7101_link_ok(efx); + } else { + efx->phy_op->get_settings(efx, &ecmd); + efx->link_speed = ecmd.speed; + efx->link_fd = ecmd.duplex == DUPLEX_FULL; + efx->link_up = sft9001_link_ok(efx, &ecmd); + } + efx->link_fc = mdio_clause45_get_pause(efx); } - /* Poll PHY for interrupt */ -static int tenxpress_phy_check_hw(struct efx_nic *efx) +static void tenxpress_phy_poll(struct efx_nic *efx) { struct tenxpress_phy_data *phy_data = efx->phy_data; - bool link_ok; - - link_ok = tenxpress_link_ok(efx, true); + bool change = false, link_ok; + unsigned link_fc; + + if (efx->phy_type == PHY_TYPE_SFX7101) { + link_ok = sfx7101_link_ok(efx); + if (link_ok != efx->link_up) { + change = true; + } else { + link_fc = mdio_clause45_get_pause(efx); + if (link_fc != efx->link_fc) + change = true; + } + sfx7101_check_bad_lp(efx, link_ok); + } else if (efx->loopback_mode) { + bool link_ok = sft9001_link_ok(efx, NULL); + if (link_ok != efx->link_up) + change = true; + } else { + u32 status = mdio_clause45_read(efx, efx->mii.phy_id, + MDIO_MMD_PMAPMD, + PMA_PMD_LASI_STATUS); + if (status & (1 << PMA_PMD_LS_ALARM_LBN)) + change = true; + } - if (link_ok != efx->link_up) - falcon_xmac_sim_phy_event(efx); + if (change) + falcon_sim_phy_event(efx); if (phy_data->phy_mode != PHY_MODE_NORMAL) - return 0; + return; - if (atomic_read(&phy_data->bad_crc_count) > crc_error_reset_threshold) { + if (EFX_WORKAROUND_10750(efx) && + atomic_read(&phy_data->bad_crc_count) > crc_error_reset_threshold) { EFX_ERR(efx, "Resetting XAUI due to too many CRC errors\n"); falcon_reset_xaui(efx); atomic_set(&phy_data->bad_crc_count, 0); } - - return 0; } static void tenxpress_phy_fini(struct efx_nic *efx) { int reg; - /* Power down the LNPGA */ - reg = (1 << PMA_PMD_LNPGA_POWERDOWN_LBN); - mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_XCONTROL_REG, reg); - - /* Waiting here ensures that the board fini, which can turn off the - * power to the PHY, won't get run until the LNPGA powerdown has been - * given long enough to complete. */ - schedule_timeout_uninterruptible(LNPGA_PDOWN_WAIT); /* 200 ms */ + if (efx->phy_type == PHY_TYPE_SFT9001B) { + device_remove_file(&efx->pci_dev->dev, + &dev_attr_phy_short_reach); + } else { + /* Power down the LNPGA */ + reg = (1 << PMA_PMD_LNPGA_POWERDOWN_LBN); + mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, + PMA_PMD_XCONTROL_REG, reg); + + /* Waiting here ensures that the board fini, which can turn + * off the power to the PHY, won't get run until the LNPGA + * powerdown has been given long enough to complete. */ + schedule_timeout_uninterruptible(LNPGA_PDOWN_WAIT); /* 200 ms */ + } kfree(efx->phy_data); efx->phy_data = NULL; @@ -430,19 +673,236 @@ void tenxpress_phy_blink(struct efx_nic *efx, bool blink) PMA_PMD_LED_OVERR_REG, reg); } -static int tenxpress_phy_test(struct efx_nic *efx) +static const char *const sfx7101_test_names[] = { + "bist" +}; + +static int +sfx7101_run_tests(struct efx_nic *efx, int *results, unsigned flags) { + int rc; + + if (!(flags & ETH_TEST_FL_OFFLINE)) + return 0; + /* BIST is automatically run after a special software reset */ - return tenxpress_special_reset(efx); + rc = tenxpress_special_reset(efx); + results[0] = rc ? -1 : 1; + return rc; } -struct efx_phy_operations falcon_tenxpress_phy_ops = { +static const char *const sft9001_test_names[] = { + "bist", + "cable.pairA.status", + "cable.pairB.status", + "cable.pairC.status", + "cable.pairD.status", + "cable.pairA.length", + "cable.pairB.length", + "cable.pairC.length", + "cable.pairD.length", +}; + +static int sft9001_run_tests(struct efx_nic *efx, int *results, unsigned flags) +{ + struct ethtool_cmd ecmd; + int phy_id = efx->mii.phy_id; + int rc = 0, rc2, i, res_reg; + + if (!(flags & ETH_TEST_FL_OFFLINE)) + return 0; + + efx->phy_op->get_settings(efx, &ecmd); + + /* Initialise cable diagnostic results to unknown failure */ + for (i = 1; i < 9; ++i) + results[i] = -1; + + /* Run cable diagnostics; wait up to 5 seconds for them to complete. + * A cable fault is not a self-test failure, but a timeout is. */ + mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, + PMA_PMD_CDIAG_CTRL_REG, + (1 << CDIAG_CTRL_IMMED_LBN) | + (1 << CDIAG_CTRL_BRK_LINK_LBN) | + (CDIAG_CTRL_LEN_METRES << CDIAG_CTRL_LEN_UNIT_LBN)); + i = 0; + while (mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, + PMA_PMD_CDIAG_CTRL_REG) & + (1 << CDIAG_CTRL_IN_PROG_LBN)) { + if (++i == 50) { + rc = -ETIMEDOUT; + goto reset; + } + msleep(100); + } + res_reg = mdio_clause45_read(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, + PMA_PMD_CDIAG_RES_REG); + for (i = 0; i < 4; i++) { + int pair_res = + (res_reg >> (CDIAG_RES_A_LBN - i * CDIAG_RES_WIDTH)) + & ((1 << CDIAG_RES_WIDTH) - 1); + int len_reg = mdio_clause45_read(efx, efx->mii.phy_id, + MDIO_MMD_PMAPMD, + PMA_PMD_CDIAG_LEN_REG + i); + if (pair_res == CDIAG_RES_OK) + results[1 + i] = 1; + else if (pair_res == CDIAG_RES_INVALID) + results[1 + i] = -1; + else + results[1 + i] = -pair_res; + if (pair_res != CDIAG_RES_INVALID && + pair_res != CDIAG_RES_OPEN && + len_reg != 0xffff) + results[5 + i] = len_reg; + } + + /* We must reset to exit cable diagnostic mode. The BIST will + * also run when we do this. */ +reset: + rc2 = tenxpress_special_reset(efx); + results[0] = rc2 ? -1 : 1; + if (!rc) + rc = rc2; + + rc2 = efx->phy_op->set_settings(efx, &ecmd); + if (!rc) + rc = rc2; + + return rc; +} + +static u32 tenxpress_get_xnp_lpa(struct efx_nic *efx) +{ + int phy = efx->mii.phy_id; + u32 lpa = 0; + int reg; + + if (efx->phy_type != PHY_TYPE_SFX7101) { + reg = mdio_clause45_read(efx, phy, MDIO_MMD_C22EXT, + C22EXT_MSTSLV_REG); + if (reg & (1 << C22EXT_MSTSLV_1000_HD_LBN)) + lpa |= ADVERTISED_1000baseT_Half; + if (reg & (1 << C22EXT_MSTSLV_1000_FD_LBN)) + lpa |= ADVERTISED_1000baseT_Full; + } + reg = mdio_clause45_read(efx, phy, MDIO_MMD_AN, MDIO_AN_10GBT_STATUS); + if (reg & (1 << MDIO_AN_10GBT_STATUS_LP_10G_LBN)) + lpa |= ADVERTISED_10000baseT_Full; + return lpa; +} + +static void sfx7101_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) +{ + mdio_clause45_get_settings_ext(efx, ecmd, ADVERTISED_10000baseT_Full, + tenxpress_get_xnp_lpa(efx)); + ecmd->supported |= SUPPORTED_10000baseT_Full; + ecmd->advertising |= ADVERTISED_10000baseT_Full; +} + +static void sft9001_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) +{ + int phy_id = efx->mii.phy_id; + u32 xnp_adv = 0; + int reg; + + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, + PMA_PMD_SPEED_ENABLE_REG); + if (EFX_WORKAROUND_13204(efx) && (reg & (1 << PMA_PMD_100TX_ADV_LBN))) + xnp_adv |= ADVERTISED_100baseT_Full; + if (reg & (1 << PMA_PMD_1000T_ADV_LBN)) + xnp_adv |= ADVERTISED_1000baseT_Full; + if (reg & (1 << PMA_PMD_10000T_ADV_LBN)) + xnp_adv |= ADVERTISED_10000baseT_Full; + + mdio_clause45_get_settings_ext(efx, ecmd, xnp_adv, + tenxpress_get_xnp_lpa(efx)); + + ecmd->supported |= (SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full); + + /* Use the vendor defined C22ext register for duplex settings */ + if (ecmd->speed != SPEED_10000 && !ecmd->autoneg) { + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_C22EXT, + GPHY_XCONTROL_REG); + ecmd->duplex = (reg & (1 << GPHY_DUPLEX_LBN) ? + DUPLEX_FULL : DUPLEX_HALF); + } +} + +static int sft9001_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) +{ + int phy_id = efx->mii.phy_id; + int rc; + + rc = mdio_clause45_set_settings(efx, ecmd); + if (rc) + return rc; + + if (ecmd->speed != SPEED_10000 && !ecmd->autoneg) + mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_C22EXT, + GPHY_XCONTROL_REG, GPHY_DUPLEX_LBN, + ecmd->duplex == DUPLEX_FULL); + + return rc; +} + +static bool sft9001_set_xnp_advertise(struct efx_nic *efx, u32 advertising) +{ + int phy = efx->mii.phy_id; + int reg = mdio_clause45_read(efx, phy, MDIO_MMD_PMAPMD, + PMA_PMD_SPEED_ENABLE_REG); + bool enabled; + + reg &= ~((1 << 2) | (1 << 3)); + if (EFX_WORKAROUND_13204(efx) && + (advertising & ADVERTISED_100baseT_Full)) + reg |= 1 << PMA_PMD_100TX_ADV_LBN; + if (advertising & ADVERTISED_1000baseT_Full) + reg |= 1 << PMA_PMD_1000T_ADV_LBN; + if (advertising & ADVERTISED_10000baseT_Full) + reg |= 1 << PMA_PMD_10000T_ADV_LBN; + mdio_clause45_write(efx, phy, MDIO_MMD_PMAPMD, + PMA_PMD_SPEED_ENABLE_REG, reg); + + enabled = (advertising & + (ADVERTISED_1000baseT_Half | + ADVERTISED_1000baseT_Full | + ADVERTISED_10000baseT_Full)); + if (EFX_WORKAROUND_13204(efx)) + enabled |= (advertising & ADVERTISED_100baseT_Full); + return enabled; +} + +struct efx_phy_operations falcon_sfx7101_phy_ops = { + .macs = EFX_XMAC, + .init = tenxpress_phy_init, + .reconfigure = tenxpress_phy_reconfigure, + .poll = tenxpress_phy_poll, + .fini = tenxpress_phy_fini, + .clear_interrupt = efx_port_dummy_op_void, + .get_settings = sfx7101_get_settings, + .set_settings = mdio_clause45_set_settings, + .num_tests = ARRAY_SIZE(sfx7101_test_names), + .test_names = sfx7101_test_names, + .run_tests = sfx7101_run_tests, + .mmds = TENXPRESS_REQUIRED_DEVS, + .loopbacks = SFX7101_LOOPBACKS, +}; + +struct efx_phy_operations falcon_sft9001_phy_ops = { + .macs = EFX_GMAC | EFX_XMAC, .init = tenxpress_phy_init, .reconfigure = tenxpress_phy_reconfigure, - .check_hw = tenxpress_phy_check_hw, + .poll = tenxpress_phy_poll, .fini = tenxpress_phy_fini, - .clear_interrupt = tenxpress_phy_clear_interrupt, - .test = tenxpress_phy_test, + .clear_interrupt = efx_port_dummy_op_void, + .get_settings = sft9001_get_settings, + .set_settings = sft9001_set_settings, + .set_xnp_advertise = sft9001_set_xnp_advertise, + .num_tests = ARRAY_SIZE(sft9001_test_names), + .test_names = sft9001_test_names, + .run_tests = sft9001_run_tests, .mmds = TENXPRESS_REQUIRED_DEVS, - .loopbacks = TENXPRESS_LOOPBACKS, + .loopbacks = SFT9001_LOOPBACKS, }; diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h index fa7b49d69288d3d3fe201f6cbd1aa788cf1e8e4f..82e03e1d73713ad2cc5c7dbbc110627fb21abe15 100644 --- a/drivers/net/sfc/workarounds.h +++ b/drivers/net/sfc/workarounds.h @@ -17,15 +17,20 @@ #define EFX_WORKAROUND_ALWAYS(efx) 1 #define EFX_WORKAROUND_FALCON_A(efx) (falcon_rev(efx) <= FALCON_REV_A1) +#define EFX_WORKAROUND_10G(efx) EFX_IS10G(efx) +#define EFX_WORKAROUND_SFX7101(efx) ((efx)->phy_type == PHY_TYPE_SFX7101) +#define EFX_WORKAROUND_SFT9001A(efx) ((efx)->phy_type == PHY_TYPE_SFT9001A) /* XAUI resets if link not detected */ #define EFX_WORKAROUND_5147 EFX_WORKAROUND_ALWAYS /* RX PCIe double split performance issue */ #define EFX_WORKAROUND_7575 EFX_WORKAROUND_ALWAYS +/* Bit-bashed I2C reads cause performance drop */ +#define EFX_WORKAROUND_7884 EFX_WORKAROUND_10G /* TX pkt parser problem with <= 16 byte TXes */ #define EFX_WORKAROUND_9141 EFX_WORKAROUND_ALWAYS /* Low rate CRC errors require XAUI reset */ -#define EFX_WORKAROUND_10750 EFX_WORKAROUND_ALWAYS +#define EFX_WORKAROUND_10750 EFX_WORKAROUND_SFX7101 /* TX_EV_PKT_ERR can be caused by a dangling TX descriptor * or a PCIe error (bug 11028) */ #define EFX_WORKAROUND_10727 EFX_WORKAROUND_ALWAYS @@ -49,4 +54,9 @@ /* Leak overlength packets rather than free */ #define EFX_WORKAROUND_8071 EFX_WORKAROUND_FALCON_A +/* Need to send XNP pages for 100BaseT */ +#define EFX_WORKAROUND_13204 EFX_WORKAROUND_SFT9001A +/* Need to keep AN enabled */ +#define EFX_WORKAROUND_13963 EFX_WORKAROUND_SFT9001A + #endif /* EFX_WORKAROUNDS_H */ diff --git a/drivers/net/sfc/xfp_phy.c b/drivers/net/sfc/xfp_phy.c index 276151df3a703537ba01a315c90e7842d82ce4a8..2d50b6ecf5f9e92b87330dc574f12dbf3741b560 100644 --- a/drivers/net/sfc/xfp_phy.c +++ b/drivers/net/sfc/xfp_phy.c @@ -7,22 +7,21 @@ * by the Free Software Foundation, incorporated herein by reference. */ /* - * Driver for XFP optical PHYs (plus some support specific to the Quake 2032) + * Driver for XFP optical PHYs (plus some support specific to the Quake 2022/32) * See www.amcc.com for details (search for qt2032) */ #include #include #include "efx.h" -#include "gmii.h" #include "mdio_10g.h" #include "xenpack.h" #include "phy.h" -#include "mac.h" +#include "falcon.h" -#define XFP_REQUIRED_DEVS (MDIO_MMDREG_DEVS0_PCS | \ - MDIO_MMDREG_DEVS0_PMAPMD | \ - MDIO_MMDREG_DEVS0_PHYXS) +#define XFP_REQUIRED_DEVS (MDIO_MMDREG_DEVS_PCS | \ + MDIO_MMDREG_DEVS_PMAPMD | \ + MDIO_MMDREG_DEVS_PHYXS) #define XFP_LOOPBACKS ((1 << LOOPBACK_PCS) | \ (1 << LOOPBACK_PMAPMD) | \ @@ -65,7 +64,7 @@ static int xfp_reset_phy(struct efx_nic *efx) /* Check that all the MMDs we expect are present and responding. We * expect faults on some if the link is down, but not on the PHY XS */ rc = mdio_clause45_check_mmds(efx, XFP_REQUIRED_DEVS, - MDIO_MMDREG_DEVS0_PHYXS); + MDIO_MMDREG_DEVS_PHYXS); if (rc < 0) goto fail; @@ -120,15 +119,12 @@ static int xfp_link_ok(struct efx_nic *efx) return mdio_clause45_links_ok(efx, XFP_REQUIRED_DEVS); } -static int xfp_phy_check_hw(struct efx_nic *efx) +static void xfp_phy_poll(struct efx_nic *efx) { - int rc = 0; int link_up = xfp_link_ok(efx); /* Simulate a PHY event if link state has changed */ if (link_up != efx->link_up) - falcon_xmac_sim_phy_event(efx); - - return rc; + falcon_sim_phy_event(efx); } static void xfp_phy_reconfigure(struct efx_nic *efx) @@ -145,7 +141,9 @@ static void xfp_phy_reconfigure(struct efx_nic *efx) phy_data->phy_mode = efx->phy_mode; efx->link_up = xfp_link_ok(efx); - efx->link_options = GM_LPA_10000FULL; + efx->link_speed = 10000; + efx->link_fd = true; + efx->link_fc = efx->wanted_fc; } @@ -160,11 +158,14 @@ static void xfp_phy_fini(struct efx_nic *efx) } struct efx_phy_operations falcon_xfp_phy_ops = { + .macs = EFX_XMAC, .init = xfp_phy_init, .reconfigure = xfp_phy_reconfigure, - .check_hw = xfp_phy_check_hw, + .poll = xfp_phy_poll, .fini = xfp_phy_fini, .clear_interrupt = xfp_phy_clear_interrupt, + .get_settings = mdio_clause45_get_settings, + .set_settings = mdio_clause45_set_settings, .mmds = XFP_REQUIRED_DEVS, .loopbacks = XFP_LOOPBACKS, }; diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c index 6261201403cdd143ca592a880ca5052c167522d9..97d68560067dd6e6a3da4be85c48b0e7fd5eacfe 100644 --- a/drivers/net/sgiseeq.c +++ b/drivers/net/sgiseeq.c @@ -377,7 +377,6 @@ static inline void sgiseeq_rx(struct net_device *dev, struct sgiseeq_private *sp skb_put(skb, len); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += len; } else { @@ -657,7 +656,7 @@ static void timeout(struct net_device *dev) static void sgiseeq_set_multicast(struct net_device *dev) { - struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv; + struct sgiseeq_private *sp = netdev_priv(dev); unsigned char oldmode = sp->mode; if(dev->flags & IFF_PROMISC) @@ -719,7 +718,6 @@ static int __init sgiseeq_probe(struct platform_device *pdev) struct sgiseeq_private *sp; struct net_device *dev; int err; - DECLARE_MAC_BUF(mac); dev = alloc_etherdev(sizeof (struct sgiseeq_private)); if (!dev) { @@ -793,8 +791,7 @@ static int __init sgiseeq_probe(struct platform_device *pdev) goto err_out_free_page; } - printk(KERN_INFO "%s: %s %s\n", - dev->name, sgiseeqstr, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: %s %pM\n", dev->name, sgiseeqstr, dev->dev_addr); return 0; diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index 59f242a6771497619e36f51cc424ef9a61e2036d..7f8e514eb5e9653613383bfe515afea8240e37f0 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -540,7 +540,6 @@ static int sh_eth_rx(struct net_device *ndev) skb_put(skb, pkt_len); skb->protocol = eth_type_trans(skb, ndev); netif_rx(skb); - ndev->last_rx = jiffies; mdp->stats.rx_packets++; mdp->stats.rx_bytes += pkt_len; } @@ -800,7 +799,7 @@ static int sh_eth_phy_init(struct net_device *ndev) char phy_id[BUS_ID_SIZE]; struct phy_device *phydev = NULL; - snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, + snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, mdp->mii_bus->id , mdp->phy_id); mdp->link = PHY_DOWN; diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index e6e3bf58a56939be71258819256e8386eb47bd11..83cc3c5f79464b1ff2643e565aaaadce3aab71b2 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -627,7 +627,6 @@ static int sis190_rx_interrupt(struct net_device *dev, sis190_rx_skb(skb); - dev->last_rx = jiffies; stats->rx_packets++; stats->rx_bytes += pkt_size; if ((status & BCAST) == MCAST) @@ -1791,7 +1790,6 @@ static int __devinit sis190_init_one(struct pci_dev *pdev, struct net_device *dev; void __iomem *ioaddr; int rc; - DECLARE_MAC_BUF(mac); if (!printed_version) { net_drv(&debug, KERN_INFO SIS190_DRIVER_NAME " loaded.\n"); @@ -1841,10 +1839,9 @@ static int __devinit sis190_init_one(struct pci_dev *pdev, if (rc < 0) goto err_remove_mii; - net_probe(tp, KERN_INFO "%s: %s at %p (IRQ: %d), " - "%s\n", + net_probe(tp, KERN_INFO "%s: %s at %p (IRQ: %d), %pM\n", pci_name(pdev), sis_chip_info[ent->driver_data].name, - ioaddr, dev->irq, print_mac(mac, dev->dev_addr)); + ioaddr, dev->irq, dev->dev_addr); net_probe(tp, KERN_INFO "%s: %s mode.\n", dev->name, (tp->features & F_HAS_RGMII) ? "RGMII" : "GMII"); diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index 8e8337e8b072252d416a497f233c8aa9a6f04ae4..4acd41a093ad8a19c1259eef5650af802b942782 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -381,6 +381,21 @@ static int __devinit sis96x_get_mac_addr(struct pci_dev * pci_dev, return 0; } +static const struct net_device_ops sis900_netdev_ops = { + .ndo_open = sis900_open, + .ndo_stop = sis900_close, + .ndo_start_xmit = sis900_start_xmit, + .ndo_set_config = sis900_set_config, + .ndo_set_multicast_list = set_rx_mode, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_do_ioctl = mii_ioctl, + .ndo_tx_timeout = sis900_tx_timeout, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = sis900_poll, +#endif +}; + /** * sis900_probe - Probe for sis900 device * @pci_dev: the sis900 pci device @@ -404,7 +419,6 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev, int i, ret; const char *card_name = card_names[pci_id->driver_data]; const char *dev_name = pci_name(pci_dev); - DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -437,7 +451,7 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev, if (ret) goto err_out; - sis_priv = net_dev->priv; + sis_priv = netdev_priv(net_dev); net_dev->base_addr = ioaddr; net_dev->irq = pci_dev->irq; sis_priv->pci_dev = pci_dev; @@ -462,20 +476,10 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev, sis_priv->rx_ring_dma = ring_dma; /* The SiS900-specific entries in the device structure. */ - net_dev->open = &sis900_open; - net_dev->hard_start_xmit = &sis900_start_xmit; - net_dev->stop = &sis900_close; - net_dev->set_config = &sis900_set_config; - net_dev->set_multicast_list = &set_rx_mode; - net_dev->do_ioctl = &mii_ioctl; - net_dev->tx_timeout = sis900_tx_timeout; + net_dev->netdev_ops = &sis900_netdev_ops; net_dev->watchdog_timeo = TX_TIMEOUT; net_dev->ethtool_ops = &sis900_ethtool_ops; -#ifdef CONFIG_NET_POLL_CONTROLLER - net_dev->poll_controller = &sis900_poll; -#endif - if (sis900_debug > 0) sis_priv->msg_enable = sis900_debug; else @@ -534,9 +538,9 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev, goto err_unmap_rx; /* print some information about our NIC */ - printk(KERN_INFO "%s: %s at %#lx, IRQ %d, %s\n", + printk(KERN_INFO "%s: %s at %#lx, IRQ %d, %pM\n", net_dev->name, card_name, ioaddr, net_dev->irq, - print_mac(mac, net_dev->dev_addr)); + net_dev->dev_addr); /* Detect Wake on Lan support */ ret = (inl(net_dev->base_addr + CFGPMC) & PMESP) >> 27; @@ -570,7 +574,7 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev, static int __devinit sis900_mii_probe(struct net_device * net_dev) { - struct sis900_private * sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); const char *dev_name = pci_name(sis_priv->pci_dev); u16 poll_bit = MII_STAT_LINK, status = 0; unsigned long timeout = jiffies + 5 * HZ; @@ -698,7 +702,7 @@ static int __devinit sis900_mii_probe(struct net_device * net_dev) static u16 sis900_default_phy(struct net_device * net_dev) { - struct sis900_private * sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); struct mii_phy *phy = NULL, *phy_home = NULL, *default_phy = NULL, *phy_lan = NULL; u16 status; @@ -999,7 +1003,7 @@ static void sis900_poll(struct net_device *dev) static int sis900_open(struct net_device *net_dev) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); long ioaddr = net_dev->base_addr; int ret; @@ -1055,7 +1059,7 @@ sis900_open(struct net_device *net_dev) static void sis900_init_rxfilter (struct net_device * net_dev) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); long ioaddr = net_dev->base_addr; u32 rfcrSave; u32 i; @@ -1093,7 +1097,7 @@ sis900_init_rxfilter (struct net_device * net_dev) static void sis900_init_tx_ring(struct net_device *net_dev) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); long ioaddr = net_dev->base_addr; int i; @@ -1127,7 +1131,7 @@ sis900_init_tx_ring(struct net_device *net_dev) static void sis900_init_rx_ring(struct net_device *net_dev) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); long ioaddr = net_dev->base_addr; int i; @@ -1198,7 +1202,7 @@ sis900_init_rx_ring(struct net_device *net_dev) static void sis630_set_eq(struct net_device *net_dev, u8 revision) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); u16 reg14h, eq_value=0, max_value=0, min_value=0; int i, maxcount=10; @@ -1271,13 +1275,13 @@ static void sis630_set_eq(struct net_device *net_dev, u8 revision) static void sis900_timer(unsigned long data) { struct net_device *net_dev = (struct net_device *)data; - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); struct mii_phy *mii_phy = sis_priv->mii; static const int next_tick = 5*HZ; u16 status; if (!sis_priv->autong_complete){ - int speed, duplex = 0; + int uninitialized_var(speed), duplex = 0; sis900_read_mode(net_dev, &speed, &duplex); if (duplex){ @@ -1341,7 +1345,7 @@ static void sis900_timer(unsigned long data) static void sis900_check_mode(struct net_device *net_dev, struct mii_phy *mii_phy) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); long ioaddr = net_dev->base_addr; int speed, duplex; @@ -1420,7 +1424,7 @@ static void sis900_set_mode (long ioaddr, int speed, int duplex) static void sis900_auto_negotiate(struct net_device *net_dev, int phy_addr) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); int i = 0; u32 status; @@ -1455,7 +1459,7 @@ static void sis900_auto_negotiate(struct net_device *net_dev, int phy_addr) static void sis900_read_mode(struct net_device *net_dev, int *speed, int *duplex) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); struct mii_phy *phy = sis_priv->mii; int phy_addr = sis_priv->cur_phy; u32 status; @@ -1510,7 +1514,7 @@ static void sis900_read_mode(struct net_device *net_dev, int *speed, int *duplex static void sis900_tx_timeout(struct net_device *net_dev) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); long ioaddr = net_dev->base_addr; unsigned long flags; int i; @@ -1569,7 +1573,7 @@ static void sis900_tx_timeout(struct net_device *net_dev) static int sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); long ioaddr = net_dev->base_addr; unsigned int entry; unsigned long flags; @@ -1638,7 +1642,7 @@ sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev) static irqreturn_t sis900_interrupt(int irq, void *dev_instance) { struct net_device *net_dev = dev_instance; - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); int boguscnt = max_interrupt_work; long ioaddr = net_dev->base_addr; u32 status; @@ -1700,7 +1704,7 @@ static irqreturn_t sis900_interrupt(int irq, void *dev_instance) static int sis900_rx(struct net_device *net_dev) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); long ioaddr = net_dev->base_addr; unsigned int entry = sis_priv->cur_rx % NUM_RX_DESC; u32 rx_status = sis_priv->rx_ring[entry].cmdsts; @@ -1789,7 +1793,6 @@ static int sis900_rx(struct net_device *net_dev) /* some network statistics */ if ((rx_status & BCAST) == MCAST) net_dev->stats.multicast++; - net_dev->last_rx = jiffies; net_dev->stats.rx_bytes += rx_size; net_dev->stats.rx_packets++; sis_priv->dirty_rx++; @@ -1850,7 +1853,7 @@ static int sis900_rx(struct net_device *net_dev) static void sis900_finish_xmit (struct net_device *net_dev) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); for (; sis_priv->dirty_tx != sis_priv->cur_tx; sis_priv->dirty_tx++) { struct sk_buff *skb; @@ -1919,7 +1922,7 @@ static void sis900_finish_xmit (struct net_device *net_dev) static int sis900_close(struct net_device *net_dev) { long ioaddr = net_dev->base_addr; - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); struct sk_buff *skb; int i; @@ -1974,7 +1977,7 @@ static int sis900_close(struct net_device *net_dev) static void sis900_get_drvinfo(struct net_device *net_dev, struct ethtool_drvinfo *info) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); strcpy (info->driver, SIS900_MODULE_NAME); strcpy (info->version, SIS900_DRV_VERSION); @@ -1983,26 +1986,26 @@ static void sis900_get_drvinfo(struct net_device *net_dev, static u32 sis900_get_msglevel(struct net_device *net_dev) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); return sis_priv->msg_enable; } static void sis900_set_msglevel(struct net_device *net_dev, u32 value) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); sis_priv->msg_enable = value; } static u32 sis900_get_link(struct net_device *net_dev) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); return mii_link_ok(&sis_priv->mii_info); } static int sis900_get_settings(struct net_device *net_dev, struct ethtool_cmd *cmd) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); spin_lock_irq(&sis_priv->lock); mii_ethtool_gset(&sis_priv->mii_info, cmd); spin_unlock_irq(&sis_priv->lock); @@ -2012,7 +2015,7 @@ static int sis900_get_settings(struct net_device *net_dev, static int sis900_set_settings(struct net_device *net_dev, struct ethtool_cmd *cmd) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); int rt; spin_lock_irq(&sis_priv->lock); rt = mii_ethtool_sset(&sis_priv->mii_info, cmd); @@ -2022,7 +2025,7 @@ static int sis900_set_settings(struct net_device *net_dev, static int sis900_nway_reset(struct net_device *net_dev) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); return mii_nway_restart(&sis_priv->mii_info); } @@ -2039,7 +2042,7 @@ static int sis900_nway_reset(struct net_device *net_dev) static int sis900_set_wol(struct net_device *net_dev, struct ethtool_wolinfo *wol) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); long pmctrl_addr = net_dev->base_addr + pmctrl; u32 cfgpmcsr = 0, pmctrl_bits = 0; @@ -2110,7 +2113,7 @@ static const struct ethtool_ops sis900_ethtool_ops = { static int mii_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); struct mii_ioctl_data *data = if_mii(rq); switch(cmd) { @@ -2144,7 +2147,7 @@ static int mii_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd) static int sis900_set_config(struct net_device *dev, struct ifmap *map) { - struct sis900_private *sis_priv = dev->priv; + struct sis900_private *sis_priv = netdev_priv(dev); struct mii_phy *mii_phy = sis_priv->mii; u16 status; @@ -2267,7 +2270,7 @@ static inline u16 sis900_mcast_bitnr(u8 *addr, u8 revision) static void set_rx_mode(struct net_device *net_dev) { long ioaddr = net_dev->base_addr; - struct sis900_private * sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); u16 mc_filter[16] = {0}; /* 256/128 bits multicast hash table */ int i, table_entries; u32 rx_mode; @@ -2342,7 +2345,7 @@ static void set_rx_mode(struct net_device *net_dev) static void sis900_reset(struct net_device *net_dev) { - struct sis900_private * sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); long ioaddr = net_dev->base_addr; int i = 0; u32 status = TxRCMP | RxRCMP; @@ -2375,7 +2378,7 @@ static void sis900_reset(struct net_device *net_dev) static void __devexit sis900_remove(struct pci_dev *pci_dev) { struct net_device *net_dev = pci_get_drvdata(pci_dev); - struct sis900_private * sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); struct mii_phy *phy = NULL; while (sis_priv->first_mii) { @@ -2419,7 +2422,7 @@ static int sis900_suspend(struct pci_dev *pci_dev, pm_message_t state) static int sis900_resume(struct pci_dev *pci_dev) { struct net_device *net_dev = pci_get_drvdata(pci_dev); - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); long ioaddr = net_dev->base_addr; if(!netif_running(net_dev)) diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c index a2b092bb3626b63a35ac44bec9ab6b2049242b19..607efeaf0bc5cd00949fcdb3feaf7ec7f2b03305 100644 --- a/drivers/net/skfp/skfddi.c +++ b/drivers/net/skfp/skfddi.c @@ -168,6 +168,17 @@ static int num_boards; /* total number of adapters configured */ #define PRINTK(s, args...) #endif // DRIVERDEBUG +static const struct net_device_ops skfp_netdev_ops = { + .ndo_open = skfp_open, + .ndo_stop = skfp_close, + .ndo_start_xmit = skfp_send_pkt, + .ndo_get_stats = skfp_ctl_get_stats, + .ndo_change_mtu = fddi_change_mtu, + .ndo_set_multicast_list = skfp_ctl_set_multicast_list, + .ndo_set_mac_address = skfp_ctl_set_mac_address, + .ndo_do_ioctl = skfp_ioctl, +}; + /* * ================= * = skfp_init_one = @@ -253,13 +264,7 @@ static int skfp_init_one(struct pci_dev *pdev, } dev->irq = pdev->irq; - dev->get_stats = &skfp_ctl_get_stats; - dev->open = &skfp_open; - dev->stop = &skfp_close; - dev->hard_start_xmit = &skfp_send_pkt; - dev->set_multicast_list = &skfp_ctl_set_multicast_list; - dev->set_mac_address = &skfp_ctl_set_mac_address; - dev->do_ioctl = &skfp_ioctl; + dev->netdev_ops = &skfp_netdev_ops; SET_NETDEV_DEV(dev, &pdev->dev); @@ -612,7 +617,7 @@ static int skfp_close(struct net_device *dev) * Interrupts are disabled, then reenabled at the adapter. */ -irqreturn_t skfp_interrupt(int irq, void *dev_id) +static irqreturn_t skfp_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct s_smc *smc; /* private board structure pointer */ @@ -679,7 +684,7 @@ irqreturn_t skfp_interrupt(int irq, void *dev_id) * independent. * */ -struct net_device_stats *skfp_ctl_get_stats(struct net_device *dev) +static struct net_device_stats *skfp_ctl_get_stats(struct net_device *dev) { struct s_smc *bp = netdev_priv(dev); @@ -1224,7 +1229,7 @@ static void send_queued_packets(struct s_smc *smc) * Verify if the source address is set. Insert it if necessary. * ************************/ -void CheckSourceAddress(unsigned char *frame, unsigned char *hw_addr) +static void CheckSourceAddress(unsigned char *frame, unsigned char *hw_addr) { unsigned char SRBit; @@ -1680,7 +1685,6 @@ void mac_drv_rx_complete(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, skb->protocol = fddi_type_trans(skb, bp->dev); netif_rx(skb); - bp->dev->last_rx = jiffies; HWM_RX_CHECK(smc, RX_LOW_WATERMARK); return; @@ -1939,7 +1943,6 @@ int mac_drv_rx_init(struct s_smc *smc, int len, int fc, // deliver frame to system skb->protocol = fddi_type_trans(skb, smc->os.dev); - skb->dev->last_rx = jiffies; netif_rx(skb); return (0); diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 43f4c730be42546b8be59f1f97127f2d0ef06a3a..c9dbb06f8c9430cfb06779a8486544792972996a 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -104,6 +104,7 @@ static void yukon_get_stats(struct skge_port *skge, u64 *data); static void yukon_init(struct skge_hw *hw, int port); static void genesis_mac_init(struct skge_hw *hw, int port); static void genesis_link_up(struct skge_port *skge); +static void skge_set_multicast(struct net_device *dev); /* Avoid conditionals by using array */ static const int txqaddr[] = { Q_XA1, Q_XA2 }; @@ -149,24 +150,6 @@ static u32 wol_supported(const struct skge_hw *hw) return WAKE_MAGIC | WAKE_PHY; } -static u32 pci_wake_enabled(struct pci_dev *dev) -{ - int pm = pci_find_capability(dev, PCI_CAP_ID_PM); - u16 value; - - /* If device doesn't support PM Capabilities, but request is to disable - * wake events, it's a nop; otherwise fail */ - if (!pm) - return 0; - - pci_read_config_word(dev, pm + PCI_PM_PMC, &value); - - value &= PCI_PM_CAP_PME_MASK; - value >>= ffs(PCI_PM_CAP_PME_MASK) - 1; /* First bit of mask */ - - return value != 0; -} - static void skge_wol_init(struct skge_port *skge) { struct skge_hw *hw = skge->hw; @@ -254,10 +237,14 @@ static int skge_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) struct skge_port *skge = netdev_priv(dev); struct skge_hw *hw = skge->hw; - if (wol->wolopts & ~wol_supported(hw)) + if ((wol->wolopts & ~wol_supported(hw)) + || !device_can_wakeup(&hw->pdev->dev)) return -EOPNOTSUPP; skge->wol = wol->wolopts; + + device_set_wakeup_enable(&hw->pdev->dev, skge->wol); + return 0; } @@ -2477,7 +2464,7 @@ static void skge_phy_reset(struct skge_port *skge) } spin_unlock_bh(&hw->phy_lock); - dev->set_multicast_list(dev); + skge_set_multicast(dev); } /* Basic MII support */ @@ -3045,6 +3032,18 @@ static inline int bad_phy_status(const struct skge_hw *hw, u32 status) (status & GMR_FS_RX_OK) == 0; } +static void skge_set_multicast(struct net_device *dev) +{ + struct skge_port *skge = netdev_priv(dev); + struct skge_hw *hw = skge->hw; + + if (hw->chip_id == CHIP_ID_GENESIS) + genesis_set_multicast(dev); + else + yukon_set_multicast(dev); + +} + /* Get receive buffer from descriptor. * Handles copy of small buffers and reallocation failures @@ -3200,7 +3199,6 @@ static int skge_poll(struct napi_struct *napi, int to_do) skb = skge_rx_get(dev, e, control, rd->status, rd->csum2); if (likely(skb)) { - dev->last_rx = jiffies; netif_receive_skb(skb); ++work_done; @@ -3216,7 +3214,7 @@ static int skge_poll(struct napi_struct *napi, int to_do) unsigned long flags; spin_lock_irqsave(&hw->hw_lock, flags); - __netif_rx_complete(dev, napi); + __netif_rx_complete(napi); hw->intr_mask |= napimask[skge->port]; skge_write32(hw, B0_IMSK, hw->intr_mask); skge_read32(hw, B0_IMSK); @@ -3379,7 +3377,7 @@ static irqreturn_t skge_intr(int irq, void *dev_id) if (status & (IS_XA1_F|IS_R1_F)) { struct skge_port *skge = netdev_priv(hw->dev[0]); hw->intr_mask &= ~(IS_XA1_F|IS_R1_F); - netif_rx_schedule(hw->dev[0], &skge->napi); + netif_rx_schedule(&skge->napi); } if (status & IS_PA_TO_TX1) @@ -3399,7 +3397,7 @@ static irqreturn_t skge_intr(int irq, void *dev_id) if (status & (IS_XA2_F|IS_R2_F)) { hw->intr_mask &= ~(IS_XA2_F|IS_R2_F); - netif_rx_schedule(hw->dev[1], &skge->napi); + netif_rx_schedule(&skge->napi); } if (status & IS_PA_TO_RX2) { @@ -3730,7 +3728,7 @@ static int skge_device_event(struct notifier_block *unused, struct skge_port *skge; struct dentry *d; - if (dev->open != &skge_up || !skge_debug) + if (dev->netdev_ops->ndo_open != &skge_up || !skge_debug) goto done; skge = netdev_priv(dev); @@ -3804,6 +3802,23 @@ static __exit void skge_debug_cleanup(void) #define skge_debug_cleanup() #endif +static const struct net_device_ops skge_netdev_ops = { + .ndo_open = skge_up, + .ndo_stop = skge_down, + .ndo_start_xmit = skge_xmit_frame, + .ndo_do_ioctl = skge_ioctl, + .ndo_get_stats = skge_get_stats, + .ndo_tx_timeout = skge_tx_timeout, + .ndo_change_mtu = skge_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = skge_set_multicast, + .ndo_set_mac_address = skge_set_mac_address, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = skge_netpoll, +#endif +}; + + /* Initialize network device */ static struct net_device *skge_devinit(struct skge_hw *hw, int port, int highmem) @@ -3817,24 +3832,9 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, } SET_NETDEV_DEV(dev, &hw->pdev->dev); - dev->open = skge_up; - dev->stop = skge_down; - dev->do_ioctl = skge_ioctl; - dev->hard_start_xmit = skge_xmit_frame; - dev->get_stats = skge_get_stats; - if (hw->chip_id == CHIP_ID_GENESIS) - dev->set_multicast_list = genesis_set_multicast; - else - dev->set_multicast_list = yukon_set_multicast; - - dev->set_mac_address = skge_set_mac_address; - dev->change_mtu = skge_change_mtu; - SET_ETHTOOL_OPS(dev, &skge_ethtool_ops); - dev->tx_timeout = skge_tx_timeout; + dev->netdev_ops = &skge_netdev_ops; + dev->ethtool_ops = &skge_ethtool_ops; dev->watchdog_timeo = TX_WATCHDOG; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = skge_netpoll; -#endif dev->irq = hw->pdev->irq; if (highmem) @@ -3856,7 +3856,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, skge->speed = -1; skge->advertising = skge_supported_modes(hw); - if (pci_wake_enabled(hw->pdev)) + if (device_may_wakeup(&hw->pdev->dev)) skge->wol = wol_supported(hw) & WAKE_MAGIC; hw->dev[port] = dev; @@ -3885,11 +3885,10 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, static void __devinit skge_show_addr(struct net_device *dev) { const struct skge_port *skge = netdev_priv(dev); - DECLARE_MAC_BUF(mac); if (netif_msg_probe(skge)) - printk(KERN_INFO PFX "%s: addr %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO PFX "%s: addr %pM\n", + dev->name, dev->dev_addr); } static int __devinit skge_probe(struct pci_dev *pdev, @@ -4082,8 +4081,8 @@ static int skge_suspend(struct pci_dev *pdev, pm_message_t state) } skge_write32(hw, B0_IMSK, 0); - pci_enable_wake(pdev, pci_choose_state(pdev, state), wol); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + pci_prepare_to_sleep(pdev); return 0; } @@ -4096,7 +4095,7 @@ static int skge_resume(struct pci_dev *pdev) if (!hw) return 0; - err = pci_set_power_state(pdev, PCI_D0); + err = pci_back_from_sleep(pdev); if (err) goto out; @@ -4104,8 +4103,6 @@ static int skge_resume(struct pci_dev *pdev) if (err) goto out; - pci_enable_wake(pdev, PCI_D0, 0); - err = skge_reset(hw); if (err) goto out; @@ -4146,8 +4143,8 @@ static void skge_shutdown(struct pci_dev *pdev) wol |= skge->wol; } - pci_enable_wake(pdev, PCI_D3hot, wol); - pci_enable_wake(pdev, PCI_D3cold, wol); + if (pci_enable_wake(pdev, PCI_D3cold, wol)) + pci_enable_wake(pdev, PCI_D3hot, wol); pci_disable_device(pdev); pci_set_power_state(pdev, PCI_D3hot); diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 3813d15e2df75d613392bf20f5e134f358cd26ed..3668e81e474ddbe3f83438378527e5af12cdb2d5 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -3979,7 +3979,7 @@ static int sky2_device_event(struct notifier_block *unused, struct net_device *dev = ptr; struct sky2_port *sky2 = netdev_priv(dev); - if (dev->open != sky2_up || !sky2_debug) + if (dev->netdev_ops->ndo_open != sky2_up || !sky2_debug) return NOTIFY_DONE; switch(event) { @@ -4041,6 +4041,41 @@ static __exit void sky2_debug_cleanup(void) #define sky2_debug_cleanup() #endif +/* Two copies of network device operations to handle special case of + not allowing netpoll on second port */ +static const struct net_device_ops sky2_netdev_ops[2] = { + { + .ndo_open = sky2_up, + .ndo_stop = sky2_down, + .ndo_start_xmit = sky2_xmit_frame, + .ndo_do_ioctl = sky2_ioctl, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = sky2_set_mac_address, + .ndo_set_multicast_list = sky2_set_multicast, + .ndo_change_mtu = sky2_change_mtu, + .ndo_tx_timeout = sky2_tx_timeout, +#ifdef SKY2_VLAN_TAG_USED + .ndo_vlan_rx_register = sky2_vlan_rx_register, +#endif +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = sky2_netpoll, +#endif + }, + { + .ndo_open = sky2_up, + .ndo_stop = sky2_down, + .ndo_start_xmit = sky2_xmit_frame, + .ndo_do_ioctl = sky2_ioctl, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = sky2_set_mac_address, + .ndo_set_multicast_list = sky2_set_multicast, + .ndo_change_mtu = sky2_change_mtu, + .ndo_tx_timeout = sky2_tx_timeout, +#ifdef SKY2_VLAN_TAG_USED + .ndo_vlan_rx_register = sky2_vlan_rx_register, +#endif + }, +}; /* Initialize network device */ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, @@ -4057,20 +4092,9 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, SET_NETDEV_DEV(dev, &hw->pdev->dev); dev->irq = hw->pdev->irq; - dev->open = sky2_up; - dev->stop = sky2_down; - dev->do_ioctl = sky2_ioctl; - dev->hard_start_xmit = sky2_xmit_frame; - dev->set_multicast_list = sky2_set_multicast; - dev->set_mac_address = sky2_set_mac_address; - dev->change_mtu = sky2_change_mtu; SET_ETHTOOL_OPS(dev, &sky2_ethtool_ops); - dev->tx_timeout = sky2_tx_timeout; dev->watchdog_timeo = TX_WATCHDOG; -#ifdef CONFIG_NET_POLL_CONTROLLER - if (port == 0) - dev->poll_controller = sky2_netpoll; -#endif + dev->netdev_ops = &sky2_netdev_ops[port]; sky2 = netdev_priv(dev); sky2->netdev = dev; @@ -4104,7 +4128,6 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, if (!(sky2->hw->chip_id == CHIP_ID_YUKON_FE_P && sky2->hw->chip_rev == CHIP_REV_YU_FE2_A0)) { dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - dev->vlan_rx_register = sky2_vlan_rx_register; } #endif @@ -4118,11 +4141,10 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, static void __devinit sky2_show_addr(struct net_device *dev) { const struct sky2_port *sky2 = netdev_priv(dev); - DECLARE_MAC_BUF(mac); if (netif_msg_probe(sky2)) - printk(KERN_INFO PFX "%s: addr %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO PFX "%s: addr %pM\n", + dev->name, dev->dev_addr); } /* Handle software interrupt used during MSI test */ diff --git a/drivers/net/slip.c b/drivers/net/slip.c index 1d58991d395b6ef32120e1e265c8245ab61219e3..8e1c0baf6958287365d5b2f1e634cedc33e46bb3 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -365,7 +365,6 @@ static void sl_bump(struct slip *sl) skb_reset_mac_header(skb); skb->protocol = htons(ETH_P_IP); netif_rx(skb); - sl->dev->last_rx = jiffies; sl->rx_packets++; } @@ -402,7 +401,7 @@ static void sl_encaps(struct slip *sl, unsigned char *icp, int len) * if we did not request it before write operation. * 14 Oct 1994 Dmitry Gorodchanin. */ - sl->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); + set_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags); actual = sl->tty->ops->write(sl->tty, sl->xbuff, count); #ifdef SL_CHECK_TRANSMIT sl->dev->trans_start = jiffies; @@ -432,7 +431,7 @@ static void slip_write_wakeup(struct tty_struct *tty) /* Now serial buffer is almost free & we can start * transmission of another packet */ sl->tx_packets++; - tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); sl_unlock(sl); return; } @@ -465,7 +464,7 @@ static void sl_tx_timeout(struct net_device *dev) (tty_chars_in_buffer(sl->tty) || sl->xleft) ? "bad line quality" : "driver error"); sl->xleft = 0; - sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + clear_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags); sl_unlock(sl); #endif } @@ -515,10 +514,9 @@ sl_close(struct net_device *dev) struct slip *sl = netdev_priv(dev); spin_lock_bh(&sl->lock); - if (sl->tty) { + if (sl->tty) /* TTY discipline is running. */ - sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); - } + clear_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags); netif_stop_queue(dev); sl->rcount = 0; sl->xleft = 0; diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c index d6abb68e6e2f20eb8b238c85f710ccd7a75f913d..404b80e5ba11b7cea9f2c3f7ad987704b6b8c280 100644 --- a/drivers/net/smc-mca.c +++ b/drivers/net/smc-mca.c @@ -182,6 +182,22 @@ static char *smc_mca_adapter_names[] __initdata = { static int ultra_found = 0; + +static const struct net_device_ops ultramca_netdev_ops = { + .ndo_open = ultramca_open, + .ndo_stop = ultramca_close_card, + + .ndo_start_xmit = ei_start_xmit, + .ndo_tx_timeout = ei_tx_timeout, + .ndo_get_stats = ei_get_stats, + .ndo_set_multicast_list = ei_set_multicast_list, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = ei_poll, +#endif +}; + static int __init ultramca_probe(struct device *gen_dev) { unsigned short ioaddr; @@ -196,7 +212,6 @@ static int __init ultramca_probe(struct device *gen_dev) int tirq = 0; int base_addr = ultra_io[ultra_found]; int irq = ultra_irq[ultra_found]; - DECLARE_MAC_BUF(mac); if (base_addr || irq) { printk(KERN_INFO "Probing for SMC MCA adapter"); @@ -334,8 +349,8 @@ static int __init ultramca_probe(struct device *gen_dev) for (i = 0; i < 6; i++) dev->dev_addr[i] = inb(ioaddr + 8 + i); - printk(KERN_INFO "smc_mca[%d]: Parameters: %#3x, %s", - slot + 1, ioaddr, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "smc_mca[%d]: Parameters: %#3x, %pM", + slot + 1, ioaddr, dev->dev_addr); /* Switch from the station address to the alternate register set * and read the useful registers there. @@ -385,11 +400,7 @@ static int __init ultramca_probe(struct device *gen_dev) ei_status.priv = slot; - dev->open = &ultramca_open; - dev->stop = &ultramca_close_card; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = ei_poll; -#endif + dev->netdev_ops = &ultramca_netdev_ops; NS8390_init(dev, 0); diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c index 00d6cf1af4843a929f5856a40c8bf3af9b0b0c9b..b3866089a206a48d4ad2900de16f80b754e07be0 100644 --- a/drivers/net/smc-ultra.c +++ b/drivers/net/smc-ultra.c @@ -187,6 +187,21 @@ struct net_device * __init ultra_probe(int unit) } #endif +static const struct net_device_ops ultra_netdev_ops = { + .ndo_open = ultra_open, + .ndo_stop = ultra_close_card, + + .ndo_start_xmit = ei_start_xmit, + .ndo_tx_timeout = ei_tx_timeout, + .ndo_get_stats = ei_get_stats, + .ndo_set_multicast_list = ei_set_multicast_list, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = ei_poll, +#endif +}; + static int __init ultra_probe1(struct net_device *dev, int ioaddr) { int i, retval; @@ -198,7 +213,6 @@ static int __init ultra_probe1(struct net_device *dev, int ioaddr) unsigned char num_pages, irqreg, addr, piomode; unsigned char idreg = inb(ioaddr + 7); unsigned char reg4 = inb(ioaddr + 4) & 0x7f; - DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, ULTRA_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -228,8 +242,8 @@ static int __init ultra_probe1(struct net_device *dev, int ioaddr) for (i = 0; i < 6; i++) dev->dev_addr[i] = inb(ioaddr + 8 + i); - printk("%s: %s at %#3x, %s", dev->name, model_name, - ioaddr, print_mac(mac, dev->dev_addr)); + printk("%s: %s at %#3x, %pM", dev->name, model_name, + ioaddr, dev->dev_addr); /* Switch from the station address to the alternate register set and read the useful registers there. */ @@ -301,11 +315,8 @@ static int __init ultra_probe1(struct net_device *dev, int ioaddr) ei_status.get_8390_hdr = &ultra_get_8390_hdr; } ei_status.reset_8390 = &ultra_reset_8390; - dev->open = &ultra_open; - dev->stop = &ultra_close_card; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = ei_poll; -#endif + + dev->netdev_ops = &ultra_netdev_ops; NS8390_init(dev, 0); retval = register_netdev(dev); diff --git a/drivers/net/smc-ultra32.c b/drivers/net/smc-ultra32.c index a5a91ace28ccec743507e38210164a67d5dc58c4..cb6c097a2e0ad78e7b31d01ac18750540cc9fb7b 100644 --- a/drivers/net/smc-ultra32.c +++ b/drivers/net/smc-ultra32.c @@ -163,7 +163,6 @@ static int __init ultra32_probe1(struct net_device *dev, int ioaddr) unsigned char idreg; unsigned char reg4; const char *ifmap[] = {"UTP No Link", "", "UTP/AUI", "UTP/BNC"}; - DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, ULTRA32_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -207,8 +206,8 @@ static int __init ultra32_probe1(struct net_device *dev, int ioaddr) for (i = 0; i < 6; i++) dev->dev_addr[i] = inb(ioaddr + 8 + i); - printk("%s: %s at 0x%X, %s", - dev->name, model_name, ioaddr, print_mac(mac, dev->dev_addr)); + printk("%s: %s at 0x%X, %pM", + dev->name, model_name, ioaddr, dev->dev_addr); /* Switch from the station address to the alternate register set and read the useful registers there. */ diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 9a16a79b67d0d432f1bcf629dfba358e2a7cf918..bf3aa2a1effed6fa6301fc675d01bbf33e9d72fd 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -439,7 +439,6 @@ static inline void smc911x_rcv(struct net_device *dev) DBG(SMC_DEBUG_PKTS, "%s: Received packet\n", dev->name); PRINT_PKT(data, ((pkt_len - 4) <= 64) ? pkt_len - 4 : 64); - dev->last_rx = jiffies; skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->stats.rx_packets++; @@ -1231,7 +1230,6 @@ smc911x_rx_dma_irq(int dma, void *data) BUG_ON(skb == NULL); lp->current_rx_skb = NULL; PRINT_PKT(skb->data, skb->len); - dev->last_rx = jiffies; skb->protocol = eth_type_trans(skb, dev); dev->stats.rx_packets++; dev->stats.rx_bytes += skb->len; @@ -2050,9 +2048,6 @@ static int __devinit smc911x_probe(struct net_device *dev) */ static int __devinit smc911x_drv_probe(struct platform_device *pdev) { -#ifdef SMC_DYNAMIC_BUS_CONFIG - struct smc911x_platdata *pd = pdev->dev.platform_data; -#endif struct net_device *ndev; struct resource *res; struct smc911x_local *lp; @@ -2087,11 +2082,14 @@ static int __devinit smc911x_drv_probe(struct platform_device *pdev) lp = netdev_priv(ndev); lp->netdev = ndev; #ifdef SMC_DYNAMIC_BUS_CONFIG - if (!pd) { - ret = -EINVAL; - goto release_both; + { + struct smc911x_platdata *pd = pdev->dev.platform_data; + if (!pd) { + ret = -EINVAL; + goto release_both; + } + memcpy(&lp->cfg, pd, sizeof(lp->cfg)); } - memcpy(&lp->cfg, pd, sizeof(lp->cfg)); #endif addr = ioremap(res->start, SMC911X_IO_EXTENT); diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c index de67744c4a2a1f1cf960e80a8cd0ec309db36e58..18d653bbd4e0556dfac549ff02510fa805f41fa0 100644 --- a/drivers/net/smc9194.c +++ b/drivers/net/smc9194.c @@ -764,7 +764,7 @@ struct net_device * __init smc_init(int unit) . interrupt, so an auto-detect routine can detect it, and find the IRQ, ------------------------------------------------------------------------ */ -int __init smc_findirq( int ioaddr ) +static int __init smc_findirq(int ioaddr) { #ifndef NO_AUTOPROBE int timeout = 20; @@ -876,8 +876,6 @@ static int __init smc_probe(struct net_device *dev, int ioaddr) word memory_info_register; word memory_cfg_register; - DECLARE_MAC_BUF(mac); - /* Grab the region so that no one else tries to probe our ioports. */ if (!request_region(ioaddr, SMC_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -1033,10 +1031,10 @@ static int __init smc_probe(struct net_device *dev, int ioaddr) /* . Print the Ethernet address */ - printk("ADDR: %s\n", print_mac(mac, dev->dev_addr)); + printk("ADDR: %pM\n", dev->dev_addr); /* set the private data to zero by default */ - memset(dev->priv, 0, sizeof(struct smc_local)); + memset(netdev_priv(dev), 0, sizeof(struct smc_local)); /* Grab the IRQ */ retval = request_irq(dev->irq, &smc_interrupt, 0, DRV_NAME, dev); @@ -1110,7 +1108,7 @@ static int smc_open(struct net_device *dev) int i; /* used to set hw ethernet address */ /* clear out all the junk that was put here before... */ - memset(dev->priv, 0, sizeof(struct smc_local)); + memset(netdev_priv(dev), 0, sizeof(struct smc_local)); /* reset the hardware */ @@ -1166,7 +1164,7 @@ static void smc_timeout(struct net_device *dev) smc_enable( dev->base_addr ); dev->trans_start = jiffies; /* clear anything saved */ - ((struct smc_local *)dev->priv)->saved_skb = NULL; + ((struct smc_local *)netdev_priv(dev))->saved_skb = NULL; netif_wake_queue(dev); } @@ -1272,7 +1270,6 @@ static void smc_rcv(struct net_device *dev) skb->protocol = eth_type_trans(skb, dev ); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += packet_length; } else { diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index 35c56abf4113193490c3ca4a91f1f12077e9eb13..b215a8d85e62d5e2fc3eb54064918ae8dd90fd97 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -90,33 +90,6 @@ static const char version[] = #include "smc91x.h" -#ifdef CONFIG_ISA -/* - * the LAN91C111 can be at any of the following port addresses. To change, - * for a slightly different card, you can add it to the array. Keep in - * mind that the array must end in zero. - */ -static unsigned int smc_portlist[] __initdata = { - 0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0, - 0x300, 0x320, 0x340, 0x360, 0x380, 0x3A0, 0x3C0, 0x3E0, 0 -}; - -#ifndef SMC_IOADDR -# define SMC_IOADDR -1 -#endif -static unsigned long io = SMC_IOADDR; -module_param(io, ulong, 0400); -MODULE_PARM_DESC(io, "I/O base address"); - -#ifndef SMC_IRQ -# define SMC_IRQ -1 -#endif -static int irq = SMC_IRQ; -module_param(irq, int, 0400); -MODULE_PARM_DESC(irq, "IRQ number"); - -#endif /* CONFIG_ISA */ - #ifndef SMC_NOWAIT # define SMC_NOWAIT 0 #endif @@ -518,7 +491,6 @@ static inline void smc_rcv(struct net_device *dev) PRINT_PKT(data, packet_len - 4); - dev->last_rx = jiffies; skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->stats.rx_packets++; @@ -1778,7 +1750,6 @@ static int __devinit smc_probe(struct net_device *dev, void __iomem *ioaddr, int retval; unsigned int val, revision_register; const char *version_string; - DECLARE_MAC_BUF(mac); DBG(2, "%s: %s\n", CARDNAME, __func__); @@ -1972,8 +1943,8 @@ static int __devinit smc_probe(struct net_device *dev, void __iomem *ioaddr, "set using ifconfig\n", dev->name); } else { /* Print the Ethernet address */ - printk("%s: Ethernet addr: %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk("%s: Ethernet addr: %pM\n", + dev->name, dev->dev_addr); } if (lp->phy_type == 0) { @@ -2316,15 +2287,6 @@ static struct platform_driver smc_driver = { static int __init smc_init(void) { -#ifdef MODULE -#ifdef CONFIG_ISA - if (io == -1) - printk(KERN_WARNING - "%s: You shouldn't use auto-probing with insmod!\n", - CARDNAME); -#endif -#endif - return platform_driver_register(&smc_driver); } diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h index a07cc9351c6bfd7568fe3502f5242cb3034e9b19..3e7c6a3cbc650c8f0a39afa4bc49eb48f7aac191 100644 --- a/drivers/net/smc91x.h +++ b/drivers/net/smc91x.h @@ -87,49 +87,28 @@ static inline void SMC_outw(u16 val, void __iomem *ioaddr, int reg) #define RPC_LSA_DEFAULT RPC_LED_100_10 #define RPC_LSB_DEFAULT RPC_LED_TX_RX -# if defined (CONFIG_BFIN561_EZKIT) #define SMC_CAN_USE_8BIT 0 #define SMC_CAN_USE_16BIT 1 +# if defined(CONFIG_BF561) #define SMC_CAN_USE_32BIT 1 -#define SMC_IO_SHIFT 0 -#define SMC_NOWAIT 1 -#define SMC_USE_BFIN_DMA 0 - - -#define SMC_inw(a, r) readw((a) + (r)) -#define SMC_outw(v, a, r) writew(v, (a) + (r)) -#define SMC_inl(a, r) readl((a) + (r)) -#define SMC_outl(v, a, r) writel(v, (a) + (r)) -#define SMC_outsl(a, r, p, l) outsl((unsigned long *)((a) + (r)), p, l) -#define SMC_insl(a, r, p, l) insl ((unsigned long *)((a) + (r)), p, l) # else -#define SMC_CAN_USE_8BIT 0 -#define SMC_CAN_USE_16BIT 1 #define SMC_CAN_USE_32BIT 0 +# endif #define SMC_IO_SHIFT 0 #define SMC_NOWAIT 1 #define SMC_USE_BFIN_DMA 0 - -#define SMC_inw(a, r) readw((a) + (r)) -#define SMC_outw(v, a, r) writew(v, (a) + (r)) -#define SMC_outsw(a, r, p, l) outsw((unsigned long *)((a) + (r)), p, l) -#define SMC_insw(a, r, p, l) insw ((unsigned long *)((a) + (r)), p, l) +#define SMC_inw(a, r) readw((a) + (r)) +#define SMC_outw(v, a, r) writew(v, (a) + (r)) +#define SMC_insw(a, r, p, l) readsw((a) + (r), p, l) +#define SMC_outsw(a, r, p, l) writesw((a) + (r), p, l) +# if SMC_CAN_USE_32BIT +#define SMC_inl(a, r) readl((a) + (r)) +#define SMC_outl(v, a, r) writel(v, (a) + (r)) +#define SMC_insl(a, r, p, l) readsl((a) + (r), p, l) +#define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l) # endif -/* check if the mac in reg is valid */ -#define SMC_GET_MAC_ADDR(lp, addr) \ - do { \ - unsigned int __v; \ - __v = SMC_inw(ioaddr, ADDR0_REG(lp)); \ - addr[0] = __v; addr[1] = __v >> 8; \ - __v = SMC_inw(ioaddr, ADDR1_REG(lp)); \ - addr[2] = __v; addr[3] = __v >> 8; \ - __v = SMC_inw(ioaddr, ADDR2_REG(lp)); \ - addr[4] = __v; addr[5] = __v >> 8; \ - if (*(u32 *)(&addr[0]) == 0xFFFFFFFF) { \ - random_ether_addr(addr); \ - } \ - } while (0) + #elif defined(CONFIG_REDWOOD_5) || defined(CONFIG_REDWOOD_6) /* We can only do 16-bit reads and writes in the static memory space. */ @@ -286,19 +265,6 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg) #define SMC_IRQ_FLAGS (0) -#elif defined(CONFIG_ISA) - -#define SMC_CAN_USE_8BIT 1 -#define SMC_CAN_USE_16BIT 1 -#define SMC_CAN_USE_32BIT 0 - -#define SMC_inb(a, r) inb((a) + (r)) -#define SMC_inw(a, r) inw((a) + (r)) -#define SMC_outb(v, a, r) outb(v, (a) + (r)) -#define SMC_outw(v, a, r) outw(v, (a) + (r)) -#define SMC_insw(a, r, p, l) insw((a) + (r), p, l) -#define SMC_outsw(a, r, p, l) outsw((a) + (r), p, l) - #elif defined(CONFIG_M32R) #define SMC_CAN_USE_8BIT 0 diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c new file mode 100644 index 0000000000000000000000000000000000000000..5e989d884dddc9bc13e3f14ca7bde9749332b0cf --- /dev/null +++ b/drivers/net/smsc911x.c @@ -0,0 +1,2071 @@ +/*************************************************************************** + * + * Copyright (C) 2004-2008 SMSC + * Copyright (C) 2005-2008 ARM + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + *************************************************************************** + * Rewritten, heavily based on smsc911x simple driver by SMSC. + * Partly uses io macros from smc91x.c by Nicolas Pitre + * + * Supported devices: + * LAN9115, LAN9116, LAN9117, LAN9118 + * LAN9215, LAN9216, LAN9217, LAN9218 + * LAN9210, LAN9211 + * LAN9220, LAN9221 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "smsc911x.h" + +#define SMSC_CHIPNAME "smsc911x" +#define SMSC_MDIONAME "smsc911x-mdio" +#define SMSC_DRV_VERSION "2008-10-21" + +MODULE_LICENSE("GPL"); +MODULE_VERSION(SMSC_DRV_VERSION); + +#if USE_DEBUG > 0 +static int debug = 16; +#else +static int debug = 3; +#endif + +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); + +struct smsc911x_data { + void __iomem *ioaddr; + + unsigned int idrev; + + /* used to decide which workarounds apply */ + unsigned int generation; + + /* device configuration (copied from platform_data during probe) */ + struct smsc911x_platform_config config; + + /* This needs to be acquired before calling any of below: + * smsc911x_mac_read(), smsc911x_mac_write() + */ + spinlock_t mac_lock; + + /* spinlock to ensure 16-bit accesses are serialised. + * unused with a 32-bit bus */ + spinlock_t dev_lock; + + struct phy_device *phy_dev; + struct mii_bus *mii_bus; + int phy_irq[PHY_MAX_ADDR]; + unsigned int using_extphy; + int last_duplex; + int last_carrier; + + u32 msg_enable; + unsigned int gpio_setting; + unsigned int gpio_orig_setting; + struct net_device *dev; + struct napi_struct napi; + + unsigned int software_irq_signal; + +#ifdef USE_PHY_WORK_AROUND +#define MIN_PACKET_SIZE (64) + char loopback_tx_pkt[MIN_PACKET_SIZE]; + char loopback_rx_pkt[MIN_PACKET_SIZE]; + unsigned int resetcount; +#endif + + /* Members for Multicast filter workaround */ + unsigned int multicast_update_pending; + unsigned int set_bits_mask; + unsigned int clear_bits_mask; + unsigned int hashhi; + unsigned int hashlo; +}; + +/* The 16-bit access functions are significantly slower, due to the locking + * necessary. If your bus hardware can be configured to do this for you + * (in response to a single 32-bit operation from software), you should use + * the 32-bit access functions instead. */ + +static inline u32 smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg) +{ + if (pdata->config.flags & SMSC911X_USE_32BIT) + return readl(pdata->ioaddr + reg); + + if (pdata->config.flags & SMSC911X_USE_16BIT) { + u32 data; + unsigned long flags; + + /* these two 16-bit reads must be performed consecutively, so + * must not be interrupted by our own ISR (which would start + * another read operation) */ + spin_lock_irqsave(&pdata->dev_lock, flags); + data = ((readw(pdata->ioaddr + reg) & 0xFFFF) | + ((readw(pdata->ioaddr + reg + 2) & 0xFFFF) << 16)); + spin_unlock_irqrestore(&pdata->dev_lock, flags); + + return data; + } + + BUG(); +} + +static inline void smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg, + u32 val) +{ + if (pdata->config.flags & SMSC911X_USE_32BIT) { + writel(val, pdata->ioaddr + reg); + return; + } + + if (pdata->config.flags & SMSC911X_USE_16BIT) { + unsigned long flags; + + /* these two 16-bit writes must be performed consecutively, so + * must not be interrupted by our own ISR (which would start + * another read operation) */ + spin_lock_irqsave(&pdata->dev_lock, flags); + writew(val & 0xFFFF, pdata->ioaddr + reg); + writew((val >> 16) & 0xFFFF, pdata->ioaddr + reg + 2); + spin_unlock_irqrestore(&pdata->dev_lock, flags); + return; + } + + BUG(); +} + +/* Writes a packet to the TX_DATA_FIFO */ +static inline void +smsc911x_tx_writefifo(struct smsc911x_data *pdata, unsigned int *buf, + unsigned int wordcount) +{ + if (pdata->config.flags & SMSC911X_USE_32BIT) { + writesl(pdata->ioaddr + TX_DATA_FIFO, buf, wordcount); + return; + } + + if (pdata->config.flags & SMSC911X_USE_16BIT) { + while (wordcount--) + smsc911x_reg_write(pdata, TX_DATA_FIFO, *buf++); + return; + } + + BUG(); +} + +/* Reads a packet out of the RX_DATA_FIFO */ +static inline void +smsc911x_rx_readfifo(struct smsc911x_data *pdata, unsigned int *buf, + unsigned int wordcount) +{ + if (pdata->config.flags & SMSC911X_USE_32BIT) { + readsl(pdata->ioaddr + RX_DATA_FIFO, buf, wordcount); + return; + } + + if (pdata->config.flags & SMSC911X_USE_16BIT) { + while (wordcount--) + *buf++ = smsc911x_reg_read(pdata, RX_DATA_FIFO); + return; + } + + BUG(); +} + +/* waits for MAC not busy, with timeout. Only called by smsc911x_mac_read + * and smsc911x_mac_write, so assumes mac_lock is held */ +static int smsc911x_mac_complete(struct smsc911x_data *pdata) +{ + int i; + u32 val; + + SMSC_ASSERT_MAC_LOCK(pdata); + + for (i = 0; i < 40; i++) { + val = smsc911x_reg_read(pdata, MAC_CSR_CMD); + if (!(val & MAC_CSR_CMD_CSR_BUSY_)) + return 0; + } + SMSC_WARNING(HW, "Timed out waiting for MAC not BUSY. " + "MAC_CSR_CMD: 0x%08X", val); + return -EIO; +} + +/* Fetches a MAC register value. Assumes mac_lock is acquired */ +static u32 smsc911x_mac_read(struct smsc911x_data *pdata, unsigned int offset) +{ + unsigned int temp; + + SMSC_ASSERT_MAC_LOCK(pdata); + + temp = smsc911x_reg_read(pdata, MAC_CSR_CMD); + if (unlikely(temp & MAC_CSR_CMD_CSR_BUSY_)) { + SMSC_WARNING(HW, "MAC busy at entry"); + return 0xFFFFFFFF; + } + + /* Send the MAC cmd */ + smsc911x_reg_write(pdata, MAC_CSR_CMD, ((offset & 0xFF) | + MAC_CSR_CMD_CSR_BUSY_ | MAC_CSR_CMD_R_NOT_W_)); + + /* Workaround for hardware read-after-write restriction */ + temp = smsc911x_reg_read(pdata, BYTE_TEST); + + /* Wait for the read to complete */ + if (likely(smsc911x_mac_complete(pdata) == 0)) + return smsc911x_reg_read(pdata, MAC_CSR_DATA); + + SMSC_WARNING(HW, "MAC busy after read"); + return 0xFFFFFFFF; +} + +/* Set a mac register, mac_lock must be acquired before calling */ +static void smsc911x_mac_write(struct smsc911x_data *pdata, + unsigned int offset, u32 val) +{ + unsigned int temp; + + SMSC_ASSERT_MAC_LOCK(pdata); + + temp = smsc911x_reg_read(pdata, MAC_CSR_CMD); + if (unlikely(temp & MAC_CSR_CMD_CSR_BUSY_)) { + SMSC_WARNING(HW, + "smsc911x_mac_write failed, MAC busy at entry"); + return; + } + + /* Send data to write */ + smsc911x_reg_write(pdata, MAC_CSR_DATA, val); + + /* Write the actual data */ + smsc911x_reg_write(pdata, MAC_CSR_CMD, ((offset & 0xFF) | + MAC_CSR_CMD_CSR_BUSY_)); + + /* Workaround for hardware read-after-write restriction */ + temp = smsc911x_reg_read(pdata, BYTE_TEST); + + /* Wait for the write to complete */ + if (likely(smsc911x_mac_complete(pdata) == 0)) + return; + + SMSC_WARNING(HW, + "smsc911x_mac_write failed, MAC busy after write"); +} + +/* Get a phy register */ +static int smsc911x_mii_read(struct mii_bus *bus, int phyaddr, int regidx) +{ + struct smsc911x_data *pdata = (struct smsc911x_data *)bus->priv; + unsigned long flags; + unsigned int addr; + int i, reg; + + spin_lock_irqsave(&pdata->mac_lock, flags); + + /* Confirm MII not busy */ + if (unlikely(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) { + SMSC_WARNING(HW, + "MII is busy in smsc911x_mii_read???"); + reg = -EIO; + goto out; + } + + /* Set the address, index & direction (read from PHY) */ + addr = ((phyaddr & 0x1F) << 11) | ((regidx & 0x1F) << 6); + smsc911x_mac_write(pdata, MII_ACC, addr); + + /* Wait for read to complete w/ timeout */ + for (i = 0; i < 100; i++) + if (!(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) { + reg = smsc911x_mac_read(pdata, MII_DATA); + goto out; + } + + SMSC_WARNING(HW, "Timed out waiting for MII write to finish"); + reg = -EIO; + +out: + spin_unlock_irqrestore(&pdata->mac_lock, flags); + return reg; +} + +/* Set a phy register */ +static int smsc911x_mii_write(struct mii_bus *bus, int phyaddr, int regidx, + u16 val) +{ + struct smsc911x_data *pdata = (struct smsc911x_data *)bus->priv; + unsigned long flags; + unsigned int addr; + int i, reg; + + spin_lock_irqsave(&pdata->mac_lock, flags); + + /* Confirm MII not busy */ + if (unlikely(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) { + SMSC_WARNING(HW, + "MII is busy in smsc911x_mii_write???"); + reg = -EIO; + goto out; + } + + /* Put the data to write in the MAC */ + smsc911x_mac_write(pdata, MII_DATA, val); + + /* Set the address, index & direction (write to PHY) */ + addr = ((phyaddr & 0x1F) << 11) | ((regidx & 0x1F) << 6) | + MII_ACC_MII_WRITE_; + smsc911x_mac_write(pdata, MII_ACC, addr); + + /* Wait for write to complete w/ timeout */ + for (i = 0; i < 100; i++) + if (!(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) { + reg = 0; + goto out; + } + + SMSC_WARNING(HW, "Timed out waiting for MII write to finish"); + reg = -EIO; + +out: + spin_unlock_irqrestore(&pdata->mac_lock, flags); + return reg; +} + +/* Autodetects and initialises external phy for SMSC9115 and SMSC9117 flavors. + * If something goes wrong, returns -ENODEV to revert back to internal phy. + * Performed at initialisation only, so interrupts are enabled */ +static int smsc911x_phy_initialise_external(struct smsc911x_data *pdata) +{ + unsigned int hwcfg = smsc911x_reg_read(pdata, HW_CFG); + + /* External phy is requested, supported, and detected */ + if (hwcfg & HW_CFG_EXT_PHY_DET_) { + + /* Switch to external phy. Assuming tx and rx are stopped + * because smsc911x_phy_initialise is called before + * smsc911x_rx_initialise and tx_initialise. */ + + /* Disable phy clocks to the MAC */ + hwcfg &= (~HW_CFG_PHY_CLK_SEL_); + hwcfg |= HW_CFG_PHY_CLK_SEL_CLK_DIS_; + smsc911x_reg_write(pdata, HW_CFG, hwcfg); + udelay(10); /* Enough time for clocks to stop */ + + /* Switch to external phy */ + hwcfg |= HW_CFG_EXT_PHY_EN_; + smsc911x_reg_write(pdata, HW_CFG, hwcfg); + + /* Enable phy clocks to the MAC */ + hwcfg &= (~HW_CFG_PHY_CLK_SEL_); + hwcfg |= HW_CFG_PHY_CLK_SEL_EXT_PHY_; + smsc911x_reg_write(pdata, HW_CFG, hwcfg); + udelay(10); /* Enough time for clocks to restart */ + + hwcfg |= HW_CFG_SMI_SEL_; + smsc911x_reg_write(pdata, HW_CFG, hwcfg); + + SMSC_TRACE(HW, "Successfully switched to external PHY"); + pdata->using_extphy = 1; + } else { + SMSC_WARNING(HW, "No external PHY detected, " + "Using internal PHY instead."); + /* Use internal phy */ + return -ENODEV; + } + return 0; +} + +/* Fetches a tx status out of the status fifo */ +static unsigned int smsc911x_tx_get_txstatus(struct smsc911x_data *pdata) +{ + unsigned int result = + smsc911x_reg_read(pdata, TX_FIFO_INF) & TX_FIFO_INF_TSUSED_; + + if (result != 0) + result = smsc911x_reg_read(pdata, TX_STATUS_FIFO); + + return result; +} + +/* Fetches the next rx status */ +static unsigned int smsc911x_rx_get_rxstatus(struct smsc911x_data *pdata) +{ + unsigned int result = + smsc911x_reg_read(pdata, RX_FIFO_INF) & RX_FIFO_INF_RXSUSED_; + + if (result != 0) + result = smsc911x_reg_read(pdata, RX_STATUS_FIFO); + + return result; +} + +#ifdef USE_PHY_WORK_AROUND +static int smsc911x_phy_check_loopbackpkt(struct smsc911x_data *pdata) +{ + unsigned int tries; + u32 wrsz; + u32 rdsz; + ulong bufp; + + for (tries = 0; tries < 10; tries++) { + unsigned int txcmd_a; + unsigned int txcmd_b; + unsigned int status; + unsigned int pktlength; + unsigned int i; + + /* Zero-out rx packet memory */ + memset(pdata->loopback_rx_pkt, 0, MIN_PACKET_SIZE); + + /* Write tx packet to 118 */ + txcmd_a = (u32)((ulong)pdata->loopback_tx_pkt & 0x03) << 16; + txcmd_a |= TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_; + txcmd_a |= MIN_PACKET_SIZE; + + txcmd_b = MIN_PACKET_SIZE << 16 | MIN_PACKET_SIZE; + + smsc911x_reg_write(pdata, TX_DATA_FIFO, txcmd_a); + smsc911x_reg_write(pdata, TX_DATA_FIFO, txcmd_b); + + bufp = (ulong)pdata->loopback_tx_pkt & (~0x3); + wrsz = MIN_PACKET_SIZE + 3; + wrsz += (u32)((ulong)pdata->loopback_tx_pkt & 0x3); + wrsz >>= 2; + + smsc911x_tx_writefifo(pdata, (unsigned int *)bufp, wrsz); + + /* Wait till transmit is done */ + i = 60; + do { + udelay(5); + status = smsc911x_tx_get_txstatus(pdata); + } while ((i--) && (!status)); + + if (!status) { + SMSC_WARNING(HW, "Failed to transmit " + "during loopback test"); + continue; + } + if (status & TX_STS_ES_) { + SMSC_WARNING(HW, "Transmit encountered " + "errors during loopback test"); + continue; + } + + /* Wait till receive is done */ + i = 60; + do { + udelay(5); + status = smsc911x_rx_get_rxstatus(pdata); + } while ((i--) && (!status)); + + if (!status) { + SMSC_WARNING(HW, + "Failed to receive during loopback test"); + continue; + } + if (status & RX_STS_ES_) { + SMSC_WARNING(HW, "Receive encountered " + "errors during loopback test"); + continue; + } + + pktlength = ((status & 0x3FFF0000UL) >> 16); + bufp = (ulong)pdata->loopback_rx_pkt; + rdsz = pktlength + 3; + rdsz += (u32)((ulong)pdata->loopback_rx_pkt & 0x3); + rdsz >>= 2; + + smsc911x_rx_readfifo(pdata, (unsigned int *)bufp, rdsz); + + if (pktlength != (MIN_PACKET_SIZE + 4)) { + SMSC_WARNING(HW, "Unexpected packet size " + "during loop back test, size=%d, will retry", + pktlength); + } else { + unsigned int j; + int mismatch = 0; + for (j = 0; j < MIN_PACKET_SIZE; j++) { + if (pdata->loopback_tx_pkt[j] + != pdata->loopback_rx_pkt[j]) { + mismatch = 1; + break; + } + } + if (!mismatch) { + SMSC_TRACE(HW, "Successfully verified " + "loopback packet"); + return 0; + } else { + SMSC_WARNING(HW, "Data mismatch " + "during loop back test, will retry"); + } + } + } + + return -EIO; +} + +static int smsc911x_phy_reset(struct smsc911x_data *pdata) +{ + struct phy_device *phy_dev = pdata->phy_dev; + unsigned int temp; + unsigned int i = 100000; + + BUG_ON(!phy_dev); + BUG_ON(!phy_dev->bus); + + SMSC_TRACE(HW, "Performing PHY BCR Reset"); + smsc911x_mii_write(phy_dev->bus, phy_dev->addr, MII_BMCR, BMCR_RESET); + do { + msleep(1); + temp = smsc911x_mii_read(phy_dev->bus, phy_dev->addr, + MII_BMCR); + } while ((i--) && (temp & BMCR_RESET)); + + if (temp & BMCR_RESET) { + SMSC_WARNING(HW, "PHY reset failed to complete."); + return -EIO; + } + /* Extra delay required because the phy may not be completed with + * its reset when BMCR_RESET is cleared. Specs say 256 uS is + * enough delay but using 1ms here to be safe */ + msleep(1); + + return 0; +} + +static int smsc911x_phy_loopbacktest(struct net_device *dev) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + struct phy_device *phy_dev = pdata->phy_dev; + int result = -EIO; + unsigned int i, val; + unsigned long flags; + + /* Initialise tx packet using broadcast destination address */ + memset(pdata->loopback_tx_pkt, 0xff, ETH_ALEN); + + /* Use incrementing source address */ + for (i = 6; i < 12; i++) + pdata->loopback_tx_pkt[i] = (char)i; + + /* Set length type field */ + pdata->loopback_tx_pkt[12] = 0x00; + pdata->loopback_tx_pkt[13] = 0x00; + + for (i = 14; i < MIN_PACKET_SIZE; i++) + pdata->loopback_tx_pkt[i] = (char)i; + + val = smsc911x_reg_read(pdata, HW_CFG); + val &= HW_CFG_TX_FIF_SZ_; + val |= HW_CFG_SF_; + smsc911x_reg_write(pdata, HW_CFG, val); + + smsc911x_reg_write(pdata, TX_CFG, TX_CFG_TX_ON_); + smsc911x_reg_write(pdata, RX_CFG, + (u32)((ulong)pdata->loopback_rx_pkt & 0x03) << 8); + + for (i = 0; i < 10; i++) { + /* Set PHY to 10/FD, no ANEG, and loopback mode */ + smsc911x_mii_write(phy_dev->bus, phy_dev->addr, MII_BMCR, + BMCR_LOOPBACK | BMCR_FULLDPLX); + + /* Enable MAC tx/rx, FD */ + spin_lock_irqsave(&pdata->mac_lock, flags); + smsc911x_mac_write(pdata, MAC_CR, MAC_CR_FDPX_ + | MAC_CR_TXEN_ | MAC_CR_RXEN_); + spin_unlock_irqrestore(&pdata->mac_lock, flags); + + if (smsc911x_phy_check_loopbackpkt(pdata) == 0) { + result = 0; + break; + } + pdata->resetcount++; + + /* Disable MAC rx */ + spin_lock_irqsave(&pdata->mac_lock, flags); + smsc911x_mac_write(pdata, MAC_CR, 0); + spin_unlock_irqrestore(&pdata->mac_lock, flags); + + smsc911x_phy_reset(pdata); + } + + /* Disable MAC */ + spin_lock_irqsave(&pdata->mac_lock, flags); + smsc911x_mac_write(pdata, MAC_CR, 0); + spin_unlock_irqrestore(&pdata->mac_lock, flags); + + /* Cancel PHY loopback mode */ + smsc911x_mii_write(phy_dev->bus, phy_dev->addr, MII_BMCR, 0); + + smsc911x_reg_write(pdata, TX_CFG, 0); + smsc911x_reg_write(pdata, RX_CFG, 0); + + return result; +} +#endif /* USE_PHY_WORK_AROUND */ + +static void smsc911x_phy_update_flowcontrol(struct smsc911x_data *pdata) +{ + struct phy_device *phy_dev = pdata->phy_dev; + u32 afc = smsc911x_reg_read(pdata, AFC_CFG); + u32 flow; + unsigned long flags; + + if (phy_dev->duplex == DUPLEX_FULL) { + u16 lcladv = phy_read(phy_dev, MII_ADVERTISE); + u16 rmtadv = phy_read(phy_dev, MII_LPA); + u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv); + + if (cap & FLOW_CTRL_RX) + flow = 0xFFFF0002; + else + flow = 0; + + if (cap & FLOW_CTRL_TX) + afc |= 0xF; + else + afc &= ~0xF; + + SMSC_TRACE(HW, "rx pause %s, tx pause %s", + (cap & FLOW_CTRL_RX ? "enabled" : "disabled"), + (cap & FLOW_CTRL_TX ? "enabled" : "disabled")); + } else { + SMSC_TRACE(HW, "half duplex"); + flow = 0; + afc |= 0xF; + } + + spin_lock_irqsave(&pdata->mac_lock, flags); + smsc911x_mac_write(pdata, FLOW, flow); + spin_unlock_irqrestore(&pdata->mac_lock, flags); + + smsc911x_reg_write(pdata, AFC_CFG, afc); +} + +/* Update link mode if anything has changed. Called periodically when the + * PHY is in polling mode, even if nothing has changed. */ +static void smsc911x_phy_adjust_link(struct net_device *dev) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + struct phy_device *phy_dev = pdata->phy_dev; + unsigned long flags; + int carrier; + + if (phy_dev->duplex != pdata->last_duplex) { + unsigned int mac_cr; + SMSC_TRACE(HW, "duplex state has changed"); + + spin_lock_irqsave(&pdata->mac_lock, flags); + mac_cr = smsc911x_mac_read(pdata, MAC_CR); + if (phy_dev->duplex) { + SMSC_TRACE(HW, + "configuring for full duplex mode"); + mac_cr |= MAC_CR_FDPX_; + } else { + SMSC_TRACE(HW, + "configuring for half duplex mode"); + mac_cr &= ~MAC_CR_FDPX_; + } + smsc911x_mac_write(pdata, MAC_CR, mac_cr); + spin_unlock_irqrestore(&pdata->mac_lock, flags); + + smsc911x_phy_update_flowcontrol(pdata); + pdata->last_duplex = phy_dev->duplex; + } + + carrier = netif_carrier_ok(dev); + if (carrier != pdata->last_carrier) { + SMSC_TRACE(HW, "carrier state has changed"); + if (carrier) { + SMSC_TRACE(HW, "configuring for carrier OK"); + if ((pdata->gpio_orig_setting & GPIO_CFG_LED1_EN_) && + (!pdata->using_extphy)) { + /* Restore orginal GPIO configuration */ + pdata->gpio_setting = pdata->gpio_orig_setting; + smsc911x_reg_write(pdata, GPIO_CFG, + pdata->gpio_setting); + } + } else { + SMSC_TRACE(HW, "configuring for no carrier"); + /* Check global setting that LED1 + * usage is 10/100 indicator */ + pdata->gpio_setting = smsc911x_reg_read(pdata, + GPIO_CFG); + if ((pdata->gpio_setting & GPIO_CFG_LED1_EN_) + && (!pdata->using_extphy)) { + /* Force 10/100 LED off, after saving + * orginal GPIO configuration */ + pdata->gpio_orig_setting = pdata->gpio_setting; + + pdata->gpio_setting &= ~GPIO_CFG_LED1_EN_; + pdata->gpio_setting |= (GPIO_CFG_GPIOBUF0_ + | GPIO_CFG_GPIODIR0_ + | GPIO_CFG_GPIOD0_); + smsc911x_reg_write(pdata, GPIO_CFG, + pdata->gpio_setting); + } + } + pdata->last_carrier = carrier; + } +} + +static int smsc911x_mii_probe(struct net_device *dev) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + struct phy_device *phydev = NULL; + int phy_addr; + + /* find the first phy */ + for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { + if (pdata->mii_bus->phy_map[phy_addr]) { + phydev = pdata->mii_bus->phy_map[phy_addr]; + SMSC_TRACE(PROBE, "PHY %d: addr %d, phy_id 0x%08X", + phy_addr, phydev->addr, phydev->phy_id); + break; + } + } + + if (!phydev) { + pr_err("%s: no PHY found\n", dev->name); + return -ENODEV; + } + + phydev = phy_connect(dev, phydev->dev.bus_id, + &smsc911x_phy_adjust_link, 0, pdata->config.phy_interface); + + if (IS_ERR(phydev)) { + pr_err("%s: Could not attach to PHY\n", dev->name); + return PTR_ERR(phydev); + } + + pr_info("%s: attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n", + dev->name, phydev->drv->name, phydev->dev.bus_id, phydev->irq); + + /* mask with MAC supported features */ + phydev->supported &= (PHY_BASIC_FEATURES | SUPPORTED_Pause | + SUPPORTED_Asym_Pause); + phydev->advertising = phydev->supported; + + pdata->phy_dev = phydev; + pdata->last_duplex = -1; + pdata->last_carrier = -1; + +#ifdef USE_PHY_WORK_AROUND + if (smsc911x_phy_loopbacktest(dev) < 0) { + SMSC_WARNING(HW, "Failed Loop Back Test"); + return -ENODEV; + } + SMSC_TRACE(HW, "Passed Loop Back Test"); +#endif /* USE_PHY_WORK_AROUND */ + + SMSC_TRACE(HW, "phy initialised succesfully"); + return 0; +} + +static int __devinit smsc911x_mii_init(struct platform_device *pdev, + struct net_device *dev) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + int err = -ENXIO, i; + + pdata->mii_bus = mdiobus_alloc(); + if (!pdata->mii_bus) { + err = -ENOMEM; + goto err_out_1; + } + + pdata->mii_bus->name = SMSC_MDIONAME; + snprintf(pdata->mii_bus->id, MII_BUS_ID_SIZE, "%x", pdev->id); + pdata->mii_bus->priv = pdata; + pdata->mii_bus->read = smsc911x_mii_read; + pdata->mii_bus->write = smsc911x_mii_write; + pdata->mii_bus->irq = pdata->phy_irq; + for (i = 0; i < PHY_MAX_ADDR; ++i) + pdata->mii_bus->irq[i] = PHY_POLL; + + pdata->mii_bus->parent = &pdev->dev; + + pdata->using_extphy = 0; + + switch (pdata->idrev & 0xFFFF0000) { + case 0x01170000: + case 0x01150000: + case 0x117A0000: + case 0x115A0000: + /* External PHY supported, try to autodetect */ + if (smsc911x_phy_initialise_external(pdata) < 0) { + SMSC_TRACE(HW, "No external PHY detected, " + "using internal PHY"); + } + break; + default: + SMSC_TRACE(HW, "External PHY is not supported, " + "using internal PHY"); + break; + } + + if (!pdata->using_extphy) { + /* Mask all PHYs except ID 1 (internal) */ + pdata->mii_bus->phy_mask = ~(1 << 1); + } + + if (mdiobus_register(pdata->mii_bus)) { + SMSC_WARNING(PROBE, "Error registering mii bus"); + goto err_out_free_bus_2; + } + + if (smsc911x_mii_probe(dev) < 0) { + SMSC_WARNING(PROBE, "Error registering mii bus"); + goto err_out_unregister_bus_3; + } + + return 0; + +err_out_unregister_bus_3: + mdiobus_unregister(pdata->mii_bus); +err_out_free_bus_2: + mdiobus_free(pdata->mii_bus); +err_out_1: + return err; +} + +/* Gets the number of tx statuses in the fifo */ +static unsigned int smsc911x_tx_get_txstatcount(struct smsc911x_data *pdata) +{ + return (smsc911x_reg_read(pdata, TX_FIFO_INF) + & TX_FIFO_INF_TSUSED_) >> 16; +} + +/* Reads tx statuses and increments counters where necessary */ +static void smsc911x_tx_update_txcounters(struct net_device *dev) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + unsigned int tx_stat; + + while ((tx_stat = smsc911x_tx_get_txstatus(pdata)) != 0) { + if (unlikely(tx_stat & 0x80000000)) { + /* In this driver the packet tag is used as the packet + * length. Since a packet length can never reach the + * size of 0x8000, this bit is reserved. It is worth + * noting that the "reserved bit" in the warning above + * does not reference a hardware defined reserved bit + * but rather a driver defined one. + */ + SMSC_WARNING(HW, + "Packet tag reserved bit is high"); + } else { + if (unlikely(tx_stat & 0x00008000)) { + dev->stats.tx_errors++; + } else { + dev->stats.tx_packets++; + dev->stats.tx_bytes += (tx_stat >> 16); + } + if (unlikely(tx_stat & 0x00000100)) { + dev->stats.collisions += 16; + dev->stats.tx_aborted_errors += 1; + } else { + dev->stats.collisions += + ((tx_stat >> 3) & 0xF); + } + if (unlikely(tx_stat & 0x00000800)) + dev->stats.tx_carrier_errors += 1; + if (unlikely(tx_stat & 0x00000200)) { + dev->stats.collisions++; + dev->stats.tx_aborted_errors++; + } + } + } +} + +/* Increments the Rx error counters */ +static void +smsc911x_rx_counterrors(struct net_device *dev, unsigned int rxstat) +{ + int crc_err = 0; + + if (unlikely(rxstat & 0x00008000)) { + dev->stats.rx_errors++; + if (unlikely(rxstat & 0x00000002)) { + dev->stats.rx_crc_errors++; + crc_err = 1; + } + } + if (likely(!crc_err)) { + if (unlikely((rxstat & 0x00001020) == 0x00001020)) { + /* Frame type indicates length, + * and length error is set */ + dev->stats.rx_length_errors++; + } + if (rxstat & RX_STS_MCAST_) + dev->stats.multicast++; + } +} + +/* Quickly dumps bad packets */ +static void +smsc911x_rx_fastforward(struct smsc911x_data *pdata, unsigned int pktbytes) +{ + unsigned int pktwords = (pktbytes + NET_IP_ALIGN + 3) >> 2; + + if (likely(pktwords >= 4)) { + unsigned int timeout = 500; + unsigned int val; + smsc911x_reg_write(pdata, RX_DP_CTRL, RX_DP_CTRL_RX_FFWD_); + do { + udelay(1); + val = smsc911x_reg_read(pdata, RX_DP_CTRL); + } while (timeout-- && (val & RX_DP_CTRL_RX_FFWD_)); + + if (unlikely(timeout == 0)) + SMSC_WARNING(HW, "Timed out waiting for " + "RX FFWD to finish, RX_DP_CTRL: 0x%08X", val); + } else { + unsigned int temp; + while (pktwords--) + temp = smsc911x_reg_read(pdata, RX_DATA_FIFO); + } +} + +/* NAPI poll function */ +static int smsc911x_poll(struct napi_struct *napi, int budget) +{ + struct smsc911x_data *pdata = + container_of(napi, struct smsc911x_data, napi); + struct net_device *dev = pdata->dev; + int npackets = 0; + + while (likely(netif_running(dev)) && (npackets < budget)) { + unsigned int pktlength; + unsigned int pktwords; + struct sk_buff *skb; + unsigned int rxstat = smsc911x_rx_get_rxstatus(pdata); + + if (!rxstat) { + unsigned int temp; + /* We processed all packets available. Tell NAPI it can + * stop polling then re-enable rx interrupts */ + smsc911x_reg_write(pdata, INT_STS, INT_STS_RSFL_); + netif_rx_complete(napi); + temp = smsc911x_reg_read(pdata, INT_EN); + temp |= INT_EN_RSFL_EN_; + smsc911x_reg_write(pdata, INT_EN, temp); + break; + } + + /* Count packet for NAPI scheduling, even if it has an error. + * Error packets still require cycles to discard */ + npackets++; + + pktlength = ((rxstat & 0x3FFF0000) >> 16); + pktwords = (pktlength + NET_IP_ALIGN + 3) >> 2; + smsc911x_rx_counterrors(dev, rxstat); + + if (unlikely(rxstat & RX_STS_ES_)) { + SMSC_WARNING(RX_ERR, + "Discarding packet with error bit set"); + /* Packet has an error, discard it and continue with + * the next */ + smsc911x_rx_fastforward(pdata, pktwords); + dev->stats.rx_dropped++; + continue; + } + + skb = netdev_alloc_skb(dev, pktlength + NET_IP_ALIGN); + if (unlikely(!skb)) { + SMSC_WARNING(RX_ERR, + "Unable to allocate skb for rx packet"); + /* Drop the packet and stop this polling iteration */ + smsc911x_rx_fastforward(pdata, pktwords); + dev->stats.rx_dropped++; + break; + } + + skb->data = skb->head; + skb_reset_tail_pointer(skb); + + /* Align IP on 16B boundary */ + skb_reserve(skb, NET_IP_ALIGN); + skb_put(skb, pktlength - 4); + smsc911x_rx_readfifo(pdata, (unsigned int *)skb->head, + pktwords); + skb->protocol = eth_type_trans(skb, dev); + skb->ip_summed = CHECKSUM_NONE; + netif_receive_skb(skb); + + /* Update counters */ + dev->stats.rx_packets++; + dev->stats.rx_bytes += (pktlength - 4); + dev->last_rx = jiffies; + } + + /* Return total received packets */ + return npackets; +} + +/* Returns hash bit number for given MAC address + * Example: + * 01 00 5E 00 00 01 -> returns bit number 31 */ +static unsigned int smsc911x_hash(char addr[ETH_ALEN]) +{ + return (ether_crc(ETH_ALEN, addr) >> 26) & 0x3f; +} + +static void smsc911x_rx_multicast_update(struct smsc911x_data *pdata) +{ + /* Performs the multicast & mac_cr update. This is called when + * safe on the current hardware, and with the mac_lock held */ + unsigned int mac_cr; + + SMSC_ASSERT_MAC_LOCK(pdata); + + mac_cr = smsc911x_mac_read(pdata, MAC_CR); + mac_cr |= pdata->set_bits_mask; + mac_cr &= ~(pdata->clear_bits_mask); + smsc911x_mac_write(pdata, MAC_CR, mac_cr); + smsc911x_mac_write(pdata, HASHH, pdata->hashhi); + smsc911x_mac_write(pdata, HASHL, pdata->hashlo); + SMSC_TRACE(HW, "maccr 0x%08X, HASHH 0x%08X, HASHL 0x%08X", + mac_cr, pdata->hashhi, pdata->hashlo); +} + +static void smsc911x_rx_multicast_update_workaround(struct smsc911x_data *pdata) +{ + unsigned int mac_cr; + + /* This function is only called for older LAN911x devices + * (revA or revB), where MAC_CR, HASHH and HASHL should not + * be modified during Rx - newer devices immediately update the + * registers. + * + * This is called from interrupt context */ + + spin_lock(&pdata->mac_lock); + + /* Check Rx has stopped */ + if (smsc911x_mac_read(pdata, MAC_CR) & MAC_CR_RXEN_) + SMSC_WARNING(DRV, "Rx not stopped"); + + /* Perform the update - safe to do now Rx has stopped */ + smsc911x_rx_multicast_update(pdata); + + /* Re-enable Rx */ + mac_cr = smsc911x_mac_read(pdata, MAC_CR); + mac_cr |= MAC_CR_RXEN_; + smsc911x_mac_write(pdata, MAC_CR, mac_cr); + + pdata->multicast_update_pending = 0; + + spin_unlock(&pdata->mac_lock); +} + +static int smsc911x_soft_reset(struct smsc911x_data *pdata) +{ + unsigned int timeout; + unsigned int temp; + + /* Reset the LAN911x */ + smsc911x_reg_write(pdata, HW_CFG, HW_CFG_SRST_); + timeout = 10; + do { + udelay(10); + temp = smsc911x_reg_read(pdata, HW_CFG); + } while ((--timeout) && (temp & HW_CFG_SRST_)); + + if (unlikely(temp & HW_CFG_SRST_)) { + SMSC_WARNING(DRV, "Failed to complete reset"); + return -EIO; + } + return 0; +} + +/* Sets the device MAC address to dev_addr, called with mac_lock held */ +static void +smsc911x_set_mac_address(struct smsc911x_data *pdata, u8 dev_addr[6]) +{ + u32 mac_high16 = (dev_addr[5] << 8) | dev_addr[4]; + u32 mac_low32 = (dev_addr[3] << 24) | (dev_addr[2] << 16) | + (dev_addr[1] << 8) | dev_addr[0]; + + SMSC_ASSERT_MAC_LOCK(pdata); + + smsc911x_mac_write(pdata, ADDRH, mac_high16); + smsc911x_mac_write(pdata, ADDRL, mac_low32); +} + +static int smsc911x_open(struct net_device *dev) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + unsigned int timeout; + unsigned int temp; + unsigned int intcfg; + + /* if the phy is not yet registered, retry later*/ + if (!pdata->phy_dev) { + SMSC_WARNING(HW, "phy_dev is NULL"); + return -EAGAIN; + } + + if (!is_valid_ether_addr(dev->dev_addr)) { + SMSC_WARNING(HW, "dev_addr is not a valid MAC address"); + return -EADDRNOTAVAIL; + } + + /* Reset the LAN911x */ + if (smsc911x_soft_reset(pdata)) { + SMSC_WARNING(HW, "soft reset failed"); + return -EIO; + } + + smsc911x_reg_write(pdata, HW_CFG, 0x00050000); + smsc911x_reg_write(pdata, AFC_CFG, 0x006E3740); + + /* Make sure EEPROM has finished loading before setting GPIO_CFG */ + timeout = 50; + while ((timeout--) && + (smsc911x_reg_read(pdata, E2P_CMD) & E2P_CMD_EPC_BUSY_)) { + udelay(10); + } + + if (unlikely(timeout == 0)) + SMSC_WARNING(IFUP, + "Timed out waiting for EEPROM busy bit to clear"); + + smsc911x_reg_write(pdata, GPIO_CFG, 0x70070000); + + /* The soft reset above cleared the device's MAC address, + * restore it from local copy (set in probe) */ + spin_lock_irq(&pdata->mac_lock); + smsc911x_set_mac_address(pdata, dev->dev_addr); + spin_unlock_irq(&pdata->mac_lock); + + /* Initialise irqs, but leave all sources disabled */ + smsc911x_reg_write(pdata, INT_EN, 0); + smsc911x_reg_write(pdata, INT_STS, 0xFFFFFFFF); + + /* Set interrupt deassertion to 100uS */ + intcfg = ((10 << 24) | INT_CFG_IRQ_EN_); + + if (pdata->config.irq_polarity) { + SMSC_TRACE(IFUP, "irq polarity: active high"); + intcfg |= INT_CFG_IRQ_POL_; + } else { + SMSC_TRACE(IFUP, "irq polarity: active low"); + } + + if (pdata->config.irq_type) { + SMSC_TRACE(IFUP, "irq type: push-pull"); + intcfg |= INT_CFG_IRQ_TYPE_; + } else { + SMSC_TRACE(IFUP, "irq type: open drain"); + } + + smsc911x_reg_write(pdata, INT_CFG, intcfg); + + SMSC_TRACE(IFUP, "Testing irq handler using IRQ %d", dev->irq); + pdata->software_irq_signal = 0; + smp_wmb(); + + temp = smsc911x_reg_read(pdata, INT_EN); + temp |= INT_EN_SW_INT_EN_; + smsc911x_reg_write(pdata, INT_EN, temp); + + timeout = 1000; + while (timeout--) { + if (pdata->software_irq_signal) + break; + msleep(1); + } + + if (!pdata->software_irq_signal) { + dev_warn(&dev->dev, "ISR failed signaling test (IRQ %d)\n", + dev->irq); + return -ENODEV; + } + SMSC_TRACE(IFUP, "IRQ handler passed test using IRQ %d", dev->irq); + + dev_info(&dev->dev, "SMSC911x/921x identified at %#08lx, IRQ: %d\n", + (unsigned long)pdata->ioaddr, dev->irq); + + /* Bring the PHY up */ + phy_start(pdata->phy_dev); + + temp = smsc911x_reg_read(pdata, HW_CFG); + /* Preserve TX FIFO size and external PHY configuration */ + temp &= (HW_CFG_TX_FIF_SZ_|0x00000FFF); + temp |= HW_CFG_SF_; + smsc911x_reg_write(pdata, HW_CFG, temp); + + temp = smsc911x_reg_read(pdata, FIFO_INT); + temp |= FIFO_INT_TX_AVAIL_LEVEL_; + temp &= ~(FIFO_INT_RX_STS_LEVEL_); + smsc911x_reg_write(pdata, FIFO_INT, temp); + + /* set RX Data offset to 2 bytes for alignment */ + smsc911x_reg_write(pdata, RX_CFG, (2 << 8)); + + /* enable NAPI polling before enabling RX interrupts */ + napi_enable(&pdata->napi); + + temp = smsc911x_reg_read(pdata, INT_EN); + temp |= (INT_EN_TDFA_EN_ | INT_EN_RSFL_EN_); + smsc911x_reg_write(pdata, INT_EN, temp); + + spin_lock_irq(&pdata->mac_lock); + temp = smsc911x_mac_read(pdata, MAC_CR); + temp |= (MAC_CR_TXEN_ | MAC_CR_RXEN_ | MAC_CR_HBDIS_); + smsc911x_mac_write(pdata, MAC_CR, temp); + spin_unlock_irq(&pdata->mac_lock); + + smsc911x_reg_write(pdata, TX_CFG, TX_CFG_TX_ON_); + + netif_start_queue(dev); + return 0; +} + +/* Entry point for stopping the interface */ +static int smsc911x_stop(struct net_device *dev) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + unsigned int temp; + + /* Disable all device interrupts */ + temp = smsc911x_reg_read(pdata, INT_CFG); + temp &= ~INT_CFG_IRQ_EN_; + smsc911x_reg_write(pdata, INT_CFG, temp); + + /* Stop Tx and Rx polling */ + netif_stop_queue(dev); + napi_disable(&pdata->napi); + + /* At this point all Rx and Tx activity is stopped */ + dev->stats.rx_dropped += smsc911x_reg_read(pdata, RX_DROP); + smsc911x_tx_update_txcounters(dev); + + /* Bring the PHY down */ + if (pdata->phy_dev) + phy_stop(pdata->phy_dev); + + SMSC_TRACE(IFDOWN, "Interface stopped"); + return 0; +} + +/* Entry point for transmitting a packet */ +static int smsc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + unsigned int freespace; + unsigned int tx_cmd_a; + unsigned int tx_cmd_b; + unsigned int temp; + u32 wrsz; + ulong bufp; + + freespace = smsc911x_reg_read(pdata, TX_FIFO_INF) & TX_FIFO_INF_TDFREE_; + + if (unlikely(freespace < TX_FIFO_LOW_THRESHOLD)) + SMSC_WARNING(TX_ERR, + "Tx data fifo low, space available: %d", freespace); + + /* Word alignment adjustment */ + tx_cmd_a = (u32)((ulong)skb->data & 0x03) << 16; + tx_cmd_a |= TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_; + tx_cmd_a |= (unsigned int)skb->len; + + tx_cmd_b = ((unsigned int)skb->len) << 16; + tx_cmd_b |= (unsigned int)skb->len; + + smsc911x_reg_write(pdata, TX_DATA_FIFO, tx_cmd_a); + smsc911x_reg_write(pdata, TX_DATA_FIFO, tx_cmd_b); + + bufp = (ulong)skb->data & (~0x3); + wrsz = (u32)skb->len + 3; + wrsz += (u32)((ulong)skb->data & 0x3); + wrsz >>= 2; + + smsc911x_tx_writefifo(pdata, (unsigned int *)bufp, wrsz); + freespace -= (skb->len + 32); + dev_kfree_skb(skb); + dev->trans_start = jiffies; + + if (unlikely(smsc911x_tx_get_txstatcount(pdata) >= 30)) + smsc911x_tx_update_txcounters(dev); + + if (freespace < TX_FIFO_LOW_THRESHOLD) { + netif_stop_queue(dev); + temp = smsc911x_reg_read(pdata, FIFO_INT); + temp &= 0x00FFFFFF; + temp |= 0x32000000; + smsc911x_reg_write(pdata, FIFO_INT, temp); + } + + return NETDEV_TX_OK; +} + +/* Entry point for getting status counters */ +static struct net_device_stats *smsc911x_get_stats(struct net_device *dev) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + smsc911x_tx_update_txcounters(dev); + dev->stats.rx_dropped += smsc911x_reg_read(pdata, RX_DROP); + return &dev->stats; +} + +/* Entry point for setting addressing modes */ +static void smsc911x_set_multicast_list(struct net_device *dev) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + unsigned long flags; + + if (dev->flags & IFF_PROMISC) { + /* Enabling promiscuous mode */ + pdata->set_bits_mask = MAC_CR_PRMS_; + pdata->clear_bits_mask = (MAC_CR_MCPAS_ | MAC_CR_HPFILT_); + pdata->hashhi = 0; + pdata->hashlo = 0; + } else if (dev->flags & IFF_ALLMULTI) { + /* Enabling all multicast mode */ + pdata->set_bits_mask = MAC_CR_MCPAS_; + pdata->clear_bits_mask = (MAC_CR_PRMS_ | MAC_CR_HPFILT_); + pdata->hashhi = 0; + pdata->hashlo = 0; + } else if (dev->mc_count > 0) { + /* Enabling specific multicast addresses */ + unsigned int hash_high = 0; + unsigned int hash_low = 0; + unsigned int count = 0; + struct dev_mc_list *mc_list = dev->mc_list; + + pdata->set_bits_mask = MAC_CR_HPFILT_; + pdata->clear_bits_mask = (MAC_CR_PRMS_ | MAC_CR_MCPAS_); + + while (mc_list) { + count++; + if ((mc_list->dmi_addrlen) == ETH_ALEN) { + unsigned int bitnum = + smsc911x_hash(mc_list->dmi_addr); + unsigned int mask = 0x01 << (bitnum & 0x1F); + if (bitnum & 0x20) + hash_high |= mask; + else + hash_low |= mask; + } else { + SMSC_WARNING(DRV, "dmi_addrlen != 6"); + } + mc_list = mc_list->next; + } + if (count != (unsigned int)dev->mc_count) + SMSC_WARNING(DRV, "mc_count != dev->mc_count"); + + pdata->hashhi = hash_high; + pdata->hashlo = hash_low; + } else { + /* Enabling local MAC address only */ + pdata->set_bits_mask = 0; + pdata->clear_bits_mask = + (MAC_CR_PRMS_ | MAC_CR_MCPAS_ | MAC_CR_HPFILT_); + pdata->hashhi = 0; + pdata->hashlo = 0; + } + + spin_lock_irqsave(&pdata->mac_lock, flags); + + if (pdata->generation <= 1) { + /* Older hardware revision - cannot change these flags while + * receiving data */ + if (!pdata->multicast_update_pending) { + unsigned int temp; + SMSC_TRACE(HW, "scheduling mcast update"); + pdata->multicast_update_pending = 1; + + /* Request the hardware to stop, then perform the + * update when we get an RX_STOP interrupt */ + smsc911x_reg_write(pdata, INT_STS, INT_STS_RXSTOP_INT_); + temp = smsc911x_reg_read(pdata, INT_EN); + temp |= INT_EN_RXSTOP_INT_EN_; + smsc911x_reg_write(pdata, INT_EN, temp); + + temp = smsc911x_mac_read(pdata, MAC_CR); + temp &= ~(MAC_CR_RXEN_); + smsc911x_mac_write(pdata, MAC_CR, temp); + } else { + /* There is another update pending, this should now + * use the newer values */ + } + } else { + /* Newer hardware revision - can write immediately */ + smsc911x_rx_multicast_update(pdata); + } + + spin_unlock_irqrestore(&pdata->mac_lock, flags); +} + +static irqreturn_t smsc911x_irqhandler(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct smsc911x_data *pdata = netdev_priv(dev); + u32 intsts = smsc911x_reg_read(pdata, INT_STS); + u32 inten = smsc911x_reg_read(pdata, INT_EN); + int serviced = IRQ_NONE; + u32 temp; + + if (unlikely(intsts & inten & INT_STS_SW_INT_)) { + temp = smsc911x_reg_read(pdata, INT_EN); + temp &= (~INT_EN_SW_INT_EN_); + smsc911x_reg_write(pdata, INT_EN, temp); + smsc911x_reg_write(pdata, INT_STS, INT_STS_SW_INT_); + pdata->software_irq_signal = 1; + smp_wmb(); + serviced = IRQ_HANDLED; + } + + if (unlikely(intsts & inten & INT_STS_RXSTOP_INT_)) { + /* Called when there is a multicast update scheduled and + * it is now safe to complete the update */ + SMSC_TRACE(INTR, "RX Stop interrupt"); + temp = smsc911x_reg_read(pdata, INT_EN); + temp &= (~INT_EN_RXSTOP_INT_EN_); + smsc911x_reg_write(pdata, INT_EN, temp); + smsc911x_reg_write(pdata, INT_STS, INT_STS_RXSTOP_INT_); + smsc911x_rx_multicast_update_workaround(pdata); + serviced = IRQ_HANDLED; + } + + if (intsts & inten & INT_STS_TDFA_) { + temp = smsc911x_reg_read(pdata, FIFO_INT); + temp |= FIFO_INT_TX_AVAIL_LEVEL_; + smsc911x_reg_write(pdata, FIFO_INT, temp); + smsc911x_reg_write(pdata, INT_STS, INT_STS_TDFA_); + netif_wake_queue(dev); + serviced = IRQ_HANDLED; + } + + if (unlikely(intsts & inten & INT_STS_RXE_)) { + SMSC_TRACE(INTR, "RX Error interrupt"); + smsc911x_reg_write(pdata, INT_STS, INT_STS_RXE_); + serviced = IRQ_HANDLED; + } + + if (likely(intsts & inten & INT_STS_RSFL_)) { + if (likely(netif_rx_schedule_prep(dev, &pdata->napi))) { + /* Disable Rx interrupts */ + temp = smsc911x_reg_read(pdata, INT_EN); + temp &= (~INT_EN_RSFL_EN_); + smsc911x_reg_write(pdata, INT_EN, temp); + /* Schedule a NAPI poll */ + __netif_rx_schedule(dev, &pdata->napi); + } else { + SMSC_WARNING(RX_ERR, + "netif_rx_schedule_prep failed"); + } + serviced = IRQ_HANDLED; + } + + return serviced; +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void smsc911x_poll_controller(struct net_device *dev) +{ + disable_irq(dev->irq); + smsc911x_irqhandler(0, dev); + enable_irq(dev->irq); +} +#endif /* CONFIG_NET_POLL_CONTROLLER */ + +/* Standard ioctls for mii-tool */ +static int smsc911x_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + + if (!netif_running(dev) || !pdata->phy_dev) + return -EINVAL; + + return phy_mii_ioctl(pdata->phy_dev, if_mii(ifr), cmd); +} + +static int +smsc911x_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + + cmd->maxtxpkt = 1; + cmd->maxrxpkt = 1; + return phy_ethtool_gset(pdata->phy_dev, cmd); +} + +static int +smsc911x_ethtool_setsettings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + + return phy_ethtool_sset(pdata->phy_dev, cmd); +} + +static void smsc911x_ethtool_getdrvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + strlcpy(info->driver, SMSC_CHIPNAME, sizeof(info->driver)); + strlcpy(info->version, SMSC_DRV_VERSION, sizeof(info->version)); + strlcpy(info->bus_info, dev->dev.parent->bus_id, + sizeof(info->bus_info)); +} + +static int smsc911x_ethtool_nwayreset(struct net_device *dev) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + + return phy_start_aneg(pdata->phy_dev); +} + +static u32 smsc911x_ethtool_getmsglevel(struct net_device *dev) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + return pdata->msg_enable; +} + +static void smsc911x_ethtool_setmsglevel(struct net_device *dev, u32 level) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + pdata->msg_enable = level; +} + +static int smsc911x_ethtool_getregslen(struct net_device *dev) +{ + return (((E2P_DATA - ID_REV) / 4 + 1) + (WUCSR - MAC_CR) + 1 + 32) * + sizeof(u32); +} + +static void +smsc911x_ethtool_getregs(struct net_device *dev, struct ethtool_regs *regs, + void *buf) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + struct phy_device *phy_dev = pdata->phy_dev; + unsigned long flags; + unsigned int i; + unsigned int j = 0; + u32 *data = buf; + + regs->version = pdata->idrev; + for (i = ID_REV; i <= E2P_DATA; i += (sizeof(u32))) + data[j++] = smsc911x_reg_read(pdata, i); + + for (i = MAC_CR; i <= WUCSR; i++) { + spin_lock_irqsave(&pdata->mac_lock, flags); + data[j++] = smsc911x_mac_read(pdata, i); + spin_unlock_irqrestore(&pdata->mac_lock, flags); + } + + for (i = 0; i <= 31; i++) + data[j++] = smsc911x_mii_read(phy_dev->bus, phy_dev->addr, i); +} + +static void smsc911x_eeprom_enable_access(struct smsc911x_data *pdata) +{ + unsigned int temp = smsc911x_reg_read(pdata, GPIO_CFG); + temp &= ~GPIO_CFG_EEPR_EN_; + smsc911x_reg_write(pdata, GPIO_CFG, temp); + msleep(1); +} + +static int smsc911x_eeprom_send_cmd(struct smsc911x_data *pdata, u32 op) +{ + int timeout = 100; + u32 e2cmd; + + SMSC_TRACE(DRV, "op 0x%08x", op); + if (smsc911x_reg_read(pdata, E2P_CMD) & E2P_CMD_EPC_BUSY_) { + SMSC_WARNING(DRV, "Busy at start"); + return -EBUSY; + } + + e2cmd = op | E2P_CMD_EPC_BUSY_; + smsc911x_reg_write(pdata, E2P_CMD, e2cmd); + + do { + msleep(1); + e2cmd = smsc911x_reg_read(pdata, E2P_CMD); + } while ((e2cmd & E2P_CMD_EPC_BUSY_) && (timeout--)); + + if (!timeout) { + SMSC_TRACE(DRV, "TIMED OUT"); + return -EAGAIN; + } + + if (e2cmd & E2P_CMD_EPC_TIMEOUT_) { + SMSC_TRACE(DRV, "Error occured during eeprom operation"); + return -EINVAL; + } + + return 0; +} + +static int smsc911x_eeprom_read_location(struct smsc911x_data *pdata, + u8 address, u8 *data) +{ + u32 op = E2P_CMD_EPC_CMD_READ_ | address; + int ret; + + SMSC_TRACE(DRV, "address 0x%x", address); + ret = smsc911x_eeprom_send_cmd(pdata, op); + + if (!ret) + data[address] = smsc911x_reg_read(pdata, E2P_DATA); + + return ret; +} + +static int smsc911x_eeprom_write_location(struct smsc911x_data *pdata, + u8 address, u8 data) +{ + u32 op = E2P_CMD_EPC_CMD_ERASE_ | address; + int ret; + + SMSC_TRACE(DRV, "address 0x%x, data 0x%x", address, data); + ret = smsc911x_eeprom_send_cmd(pdata, op); + + if (!ret) { + op = E2P_CMD_EPC_CMD_WRITE_ | address; + smsc911x_reg_write(pdata, E2P_DATA, (u32)data); + ret = smsc911x_eeprom_send_cmd(pdata, op); + } + + return ret; +} + +static int smsc911x_ethtool_get_eeprom_len(struct net_device *dev) +{ + return SMSC911X_EEPROM_SIZE; +} + +static int smsc911x_ethtool_get_eeprom(struct net_device *dev, + struct ethtool_eeprom *eeprom, u8 *data) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + u8 eeprom_data[SMSC911X_EEPROM_SIZE]; + int len; + int i; + + smsc911x_eeprom_enable_access(pdata); + + len = min(eeprom->len, SMSC911X_EEPROM_SIZE); + for (i = 0; i < len; i++) { + int ret = smsc911x_eeprom_read_location(pdata, i, eeprom_data); + if (ret < 0) { + eeprom->len = 0; + return ret; + } + } + + memcpy(data, &eeprom_data[eeprom->offset], len); + eeprom->len = len; + return 0; +} + +static int smsc911x_ethtool_set_eeprom(struct net_device *dev, + struct ethtool_eeprom *eeprom, u8 *data) +{ + int ret; + struct smsc911x_data *pdata = netdev_priv(dev); + + smsc911x_eeprom_enable_access(pdata); + smsc911x_eeprom_send_cmd(pdata, E2P_CMD_EPC_CMD_EWEN_); + ret = smsc911x_eeprom_write_location(pdata, eeprom->offset, *data); + smsc911x_eeprom_send_cmd(pdata, E2P_CMD_EPC_CMD_EWDS_); + + /* Single byte write, according to man page */ + eeprom->len = 1; + + return ret; +} + +static const struct ethtool_ops smsc911x_ethtool_ops = { + .get_settings = smsc911x_ethtool_getsettings, + .set_settings = smsc911x_ethtool_setsettings, + .get_link = ethtool_op_get_link, + .get_drvinfo = smsc911x_ethtool_getdrvinfo, + .nway_reset = smsc911x_ethtool_nwayreset, + .get_msglevel = smsc911x_ethtool_getmsglevel, + .set_msglevel = smsc911x_ethtool_setmsglevel, + .get_regs_len = smsc911x_ethtool_getregslen, + .get_regs = smsc911x_ethtool_getregs, + .get_eeprom_len = smsc911x_ethtool_get_eeprom_len, + .get_eeprom = smsc911x_ethtool_get_eeprom, + .set_eeprom = smsc911x_ethtool_set_eeprom, +}; + +static const struct net_device_ops smsc911x_netdev_ops = { + .ndo_open = smsc911x_open, + .ndo_stop = smsc911x_stop, + .ndo_start_xmit = smsc911x_hard_start_xmit, + .ndo_get_stats = smsc911x_get_stats, + .ndo_set_multicast_list = smsc911x_set_multicast_list, + .ndo_do_ioctl = smsc911x_do_ioctl, + .ndo_validate_addr = eth_validate_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = smsc911x_poll_controller, +#endif +}; + +/* Initializing private device structures, only called from probe */ +static int __devinit smsc911x_init(struct net_device *dev) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + unsigned int byte_test; + + SMSC_TRACE(PROBE, "Driver Parameters:"); + SMSC_TRACE(PROBE, "LAN base: 0x%08lX", + (unsigned long)pdata->ioaddr); + SMSC_TRACE(PROBE, "IRQ: %d", dev->irq); + SMSC_TRACE(PROBE, "PHY will be autodetected."); + + spin_lock_init(&pdata->dev_lock); + + if (pdata->ioaddr == 0) { + SMSC_WARNING(PROBE, "pdata->ioaddr: 0x00000000"); + return -ENODEV; + } + + /* Check byte ordering */ + byte_test = smsc911x_reg_read(pdata, BYTE_TEST); + SMSC_TRACE(PROBE, "BYTE_TEST: 0x%08X", byte_test); + if (byte_test == 0x43218765) { + SMSC_TRACE(PROBE, "BYTE_TEST looks swapped, " + "applying WORD_SWAP"); + smsc911x_reg_write(pdata, WORD_SWAP, 0xffffffff); + + /* 1 dummy read of BYTE_TEST is needed after a write to + * WORD_SWAP before its contents are valid */ + byte_test = smsc911x_reg_read(pdata, BYTE_TEST); + + byte_test = smsc911x_reg_read(pdata, BYTE_TEST); + } + + if (byte_test != 0x87654321) { + SMSC_WARNING(DRV, "BYTE_TEST: 0x%08X", byte_test); + if (((byte_test >> 16) & 0xFFFF) == (byte_test & 0xFFFF)) { + SMSC_WARNING(PROBE, + "top 16 bits equal to bottom 16 bits"); + SMSC_TRACE(PROBE, "This may mean the chip is set " + "for 32 bit while the bus is reading 16 bit"); + } + return -ENODEV; + } + + /* Default generation to zero (all workarounds apply) */ + pdata->generation = 0; + + pdata->idrev = smsc911x_reg_read(pdata, ID_REV); + switch (pdata->idrev & 0xFFFF0000) { + case 0x01180000: + case 0x01170000: + case 0x01160000: + case 0x01150000: + /* LAN911[5678] family */ + pdata->generation = pdata->idrev & 0x0000FFFF; + break; + + case 0x118A0000: + case 0x117A0000: + case 0x116A0000: + case 0x115A0000: + /* LAN921[5678] family */ + pdata->generation = 3; + break; + + case 0x92100000: + case 0x92110000: + case 0x92200000: + case 0x92210000: + /* LAN9210/LAN9211/LAN9220/LAN9221 */ + pdata->generation = 4; + break; + + default: + SMSC_WARNING(PROBE, "LAN911x not identified, idrev: 0x%08X", + pdata->idrev); + return -ENODEV; + } + + SMSC_TRACE(PROBE, "LAN911x identified, idrev: 0x%08X, generation: %d", + pdata->idrev, pdata->generation); + + if (pdata->generation == 0) + SMSC_WARNING(PROBE, + "This driver is not intended for this chip revision"); + + /* Reset the LAN911x */ + if (smsc911x_soft_reset(pdata)) + return -ENODEV; + + /* Disable all interrupt sources until we bring the device up */ + smsc911x_reg_write(pdata, INT_EN, 0); + + ether_setup(dev); + dev->flags |= IFF_MULTICAST; + netif_napi_add(dev, &pdata->napi, smsc911x_poll, SMSC_NAPI_WEIGHT); + dev->netdev_ops = &smsc911x_netdev_ops; + dev->ethtool_ops = &smsc911x_ethtool_ops; + + return 0; +} + +static int __devexit smsc911x_drv_remove(struct platform_device *pdev) +{ + struct net_device *dev; + struct smsc911x_data *pdata; + struct resource *res; + + dev = platform_get_drvdata(pdev); + BUG_ON(!dev); + pdata = netdev_priv(dev); + BUG_ON(!pdata); + BUG_ON(!pdata->ioaddr); + BUG_ON(!pdata->phy_dev); + + SMSC_TRACE(IFDOWN, "Stopping driver."); + + phy_disconnect(pdata->phy_dev); + pdata->phy_dev = NULL; + mdiobus_unregister(pdata->mii_bus); + mdiobus_free(pdata->mii_bus); + + platform_set_drvdata(pdev, NULL); + unregister_netdev(dev); + free_irq(dev->irq, dev); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "smsc911x-memory"); + if (!res) + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + release_mem_region(res->start, res->end - res->start); + + iounmap(pdata->ioaddr); + + free_netdev(dev); + + return 0; +} + +static int __devinit smsc911x_drv_probe(struct platform_device *pdev) +{ + struct net_device *dev; + struct smsc911x_data *pdata; + struct smsc911x_platform_config *config = pdev->dev.platform_data; + struct resource *res; + unsigned int intcfg = 0; + int res_size; + int retval; + DECLARE_MAC_BUF(mac); + + pr_info("%s: Driver version %s.\n", SMSC_CHIPNAME, SMSC_DRV_VERSION); + + /* platform data specifies irq & dynamic bus configuration */ + if (!pdev->dev.platform_data) { + pr_warning("%s: platform_data not provided\n", SMSC_CHIPNAME); + retval = -ENODEV; + goto out_0; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "smsc911x-memory"); + if (!res) + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + pr_warning("%s: Could not allocate resource.\n", + SMSC_CHIPNAME); + retval = -ENODEV; + goto out_0; + } + res_size = res->end - res->start; + + if (!request_mem_region(res->start, res_size, SMSC_CHIPNAME)) { + retval = -EBUSY; + goto out_0; + } + + dev = alloc_etherdev(sizeof(struct smsc911x_data)); + if (!dev) { + pr_warning("%s: Could not allocate device.\n", SMSC_CHIPNAME); + retval = -ENOMEM; + goto out_release_io_1; + } + + SET_NETDEV_DEV(dev, &pdev->dev); + + pdata = netdev_priv(dev); + + dev->irq = platform_get_irq(pdev, 0); + pdata->ioaddr = ioremap_nocache(res->start, res_size); + + /* copy config parameters across to pdata */ + memcpy(&pdata->config, config, sizeof(pdata->config)); + + pdata->dev = dev; + pdata->msg_enable = ((1 << debug) - 1); + + if (pdata->ioaddr == NULL) { + SMSC_WARNING(PROBE, + "Error smsc911x base address invalid"); + retval = -ENOMEM; + goto out_free_netdev_2; + } + + retval = smsc911x_init(dev); + if (retval < 0) + goto out_unmap_io_3; + + /* configure irq polarity and type before connecting isr */ + if (pdata->config.irq_polarity == SMSC911X_IRQ_POLARITY_ACTIVE_HIGH) + intcfg |= INT_CFG_IRQ_POL_; + + if (pdata->config.irq_type == SMSC911X_IRQ_TYPE_PUSH_PULL) + intcfg |= INT_CFG_IRQ_TYPE_; + + smsc911x_reg_write(pdata, INT_CFG, intcfg); + + /* Ensure interrupts are globally disabled before connecting ISR */ + smsc911x_reg_write(pdata, INT_EN, 0); + smsc911x_reg_write(pdata, INT_STS, 0xFFFFFFFF); + + retval = request_irq(dev->irq, smsc911x_irqhandler, IRQF_DISABLED, + SMSC_CHIPNAME, dev); + if (retval) { + SMSC_WARNING(PROBE, + "Unable to claim requested irq: %d", dev->irq); + goto out_unmap_io_3; + } + + platform_set_drvdata(pdev, dev); + + retval = register_netdev(dev); + if (retval) { + SMSC_WARNING(PROBE, + "Error %i registering device", retval); + goto out_unset_drvdata_4; + } else { + SMSC_TRACE(PROBE, "Network interface: \"%s\"", dev->name); + } + + spin_lock_init(&pdata->mac_lock); + + retval = smsc911x_mii_init(pdev, dev); + if (retval) { + SMSC_WARNING(PROBE, + "Error %i initialising mii", retval); + goto out_unregister_netdev_5; + } + + spin_lock_irq(&pdata->mac_lock); + + /* Check if mac address has been specified when bringing interface up */ + if (is_valid_ether_addr(dev->dev_addr)) { + smsc911x_set_mac_address(pdata, dev->dev_addr); + SMSC_TRACE(PROBE, "MAC Address is specified by configuration"); + } else { + /* Try reading mac address from device. if EEPROM is present + * it will already have been set */ + u32 mac_high16 = smsc911x_mac_read(pdata, ADDRH); + u32 mac_low32 = smsc911x_mac_read(pdata, ADDRL); + dev->dev_addr[0] = (u8)(mac_low32); + dev->dev_addr[1] = (u8)(mac_low32 >> 8); + dev->dev_addr[2] = (u8)(mac_low32 >> 16); + dev->dev_addr[3] = (u8)(mac_low32 >> 24); + dev->dev_addr[4] = (u8)(mac_high16); + dev->dev_addr[5] = (u8)(mac_high16 >> 8); + + if (is_valid_ether_addr(dev->dev_addr)) { + /* eeprom values are valid so use them */ + SMSC_TRACE(PROBE, + "Mac Address is read from LAN911x EEPROM"); + } else { + /* eeprom values are invalid, generate random MAC */ + random_ether_addr(dev->dev_addr); + smsc911x_set_mac_address(pdata, dev->dev_addr); + SMSC_TRACE(PROBE, + "MAC Address is set to random_ether_addr"); + } + } + + spin_unlock_irq(&pdata->mac_lock); + + dev_info(&dev->dev, "MAC Address: %s\n", + print_mac(mac, dev->dev_addr)); + + return 0; + +out_unregister_netdev_5: + unregister_netdev(dev); +out_unset_drvdata_4: + platform_set_drvdata(pdev, NULL); + free_irq(dev->irq, dev); +out_unmap_io_3: + iounmap(pdata->ioaddr); +out_free_netdev_2: + free_netdev(dev); +out_release_io_1: + release_mem_region(res->start, res->end - res->start); +out_0: + return retval; +} + +static struct platform_driver smsc911x_driver = { + .probe = smsc911x_drv_probe, + .remove = smsc911x_drv_remove, + .driver = { + .name = SMSC_CHIPNAME, + }, +}; + +/* Entry point for loading the module */ +static int __init smsc911x_init_module(void) +{ + return platform_driver_register(&smsc911x_driver); +} + +/* entry point for unloading the module */ +static void __exit smsc911x_cleanup_module(void) +{ + platform_driver_unregister(&smsc911x_driver); +} + +module_init(smsc911x_init_module); +module_exit(smsc911x_cleanup_module); diff --git a/drivers/net/smsc911x.h b/drivers/net/smsc911x.h new file mode 100644 index 0000000000000000000000000000000000000000..2b76654bb958c665fb39fbe7a2b5bae225e61320 --- /dev/null +++ b/drivers/net/smsc911x.h @@ -0,0 +1,390 @@ +/*************************************************************************** + * + * Copyright (C) 2004-2008 SMSC + * Copyright (C) 2005-2008 ARM + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + ***************************************************************************/ +#ifndef __SMSC911X_H__ +#define __SMSC911X_H__ + +#define TX_FIFO_LOW_THRESHOLD ((u32)1600) +#define SMSC911X_EEPROM_SIZE ((u32)7) +#define USE_DEBUG 0 + +/* This is the maximum number of packets to be received every + * NAPI poll */ +#define SMSC_NAPI_WEIGHT 16 + +/* implements a PHY loopback test at initialisation time, to ensure a packet + * can be succesfully looped back */ +#define USE_PHY_WORK_AROUND + +#define DPRINTK(nlevel, klevel, fmt, args...) \ + ((void)((NETIF_MSG_##nlevel & pdata->msg_enable) && \ + printk(KERN_##klevel "%s: %s: " fmt "\n", \ + pdata->dev->name, __func__, ## args))) + +#if USE_DEBUG >= 1 +#define SMSC_WARNING(nlevel, fmt, args...) \ + DPRINTK(nlevel, WARNING, fmt, ## args) +#else +#define SMSC_WARNING(nlevel, fmt, args...) \ + ({ do {} while (0); 0; }) +#endif + +#if USE_DEBUG >= 2 +#define SMSC_TRACE(nlevel, fmt, args...) \ + DPRINTK(nlevel, INFO, fmt, ## args) +#else +#define SMSC_TRACE(nlevel, fmt, args...) \ + ({ do {} while (0); 0; }) +#endif + +#ifdef CONFIG_DEBUG_SPINLOCK +#define SMSC_ASSERT_MAC_LOCK(pdata) \ + WARN_ON(!spin_is_locked(&pdata->mac_lock)) +#else +#define SMSC_ASSERT_MAC_LOCK(pdata) do {} while (0) +#endif /* CONFIG_DEBUG_SPINLOCK */ + +/* SMSC911x registers and bitfields */ +#define RX_DATA_FIFO 0x00 + +#define TX_DATA_FIFO 0x20 +#define TX_CMD_A_ON_COMP_ 0x80000000 +#define TX_CMD_A_BUF_END_ALGN_ 0x03000000 +#define TX_CMD_A_4_BYTE_ALGN_ 0x00000000 +#define TX_CMD_A_16_BYTE_ALGN_ 0x01000000 +#define TX_CMD_A_32_BYTE_ALGN_ 0x02000000 +#define TX_CMD_A_DATA_OFFSET_ 0x001F0000 +#define TX_CMD_A_FIRST_SEG_ 0x00002000 +#define TX_CMD_A_LAST_SEG_ 0x00001000 +#define TX_CMD_A_BUF_SIZE_ 0x000007FF +#define TX_CMD_B_PKT_TAG_ 0xFFFF0000 +#define TX_CMD_B_ADD_CRC_DISABLE_ 0x00002000 +#define TX_CMD_B_DISABLE_PADDING_ 0x00001000 +#define TX_CMD_B_PKT_BYTE_LENGTH_ 0x000007FF + +#define RX_STATUS_FIFO 0x40 +#define RX_STS_ES_ 0x00008000 +#define RX_STS_MCAST_ 0x00000400 + +#define RX_STATUS_FIFO_PEEK 0x44 + +#define TX_STATUS_FIFO 0x48 +#define TX_STS_ES_ 0x00008000 + +#define TX_STATUS_FIFO_PEEK 0x4C + +#define ID_REV 0x50 +#define ID_REV_CHIP_ID_ 0xFFFF0000 +#define ID_REV_REV_ID_ 0x0000FFFF + +#define INT_CFG 0x54 +#define INT_CFG_INT_DEAS_ 0xFF000000 +#define INT_CFG_INT_DEAS_CLR_ 0x00004000 +#define INT_CFG_INT_DEAS_STS_ 0x00002000 +#define INT_CFG_IRQ_INT_ 0x00001000 +#define INT_CFG_IRQ_EN_ 0x00000100 +#define INT_CFG_IRQ_POL_ 0x00000010 +#define INT_CFG_IRQ_TYPE_ 0x00000001 + +#define INT_STS 0x58 +#define INT_STS_SW_INT_ 0x80000000 +#define INT_STS_TXSTOP_INT_ 0x02000000 +#define INT_STS_RXSTOP_INT_ 0x01000000 +#define INT_STS_RXDFH_INT_ 0x00800000 +#define INT_STS_RXDF_INT_ 0x00400000 +#define INT_STS_TX_IOC_ 0x00200000 +#define INT_STS_RXD_INT_ 0x00100000 +#define INT_STS_GPT_INT_ 0x00080000 +#define INT_STS_PHY_INT_ 0x00040000 +#define INT_STS_PME_INT_ 0x00020000 +#define INT_STS_TXSO_ 0x00010000 +#define INT_STS_RWT_ 0x00008000 +#define INT_STS_RXE_ 0x00004000 +#define INT_STS_TXE_ 0x00002000 +#define INT_STS_TDFU_ 0x00000800 +#define INT_STS_TDFO_ 0x00000400 +#define INT_STS_TDFA_ 0x00000200 +#define INT_STS_TSFF_ 0x00000100 +#define INT_STS_TSFL_ 0x00000080 +#define INT_STS_RXDF_ 0x00000040 +#define INT_STS_RDFL_ 0x00000020 +#define INT_STS_RSFF_ 0x00000010 +#define INT_STS_RSFL_ 0x00000008 +#define INT_STS_GPIO2_INT_ 0x00000004 +#define INT_STS_GPIO1_INT_ 0x00000002 +#define INT_STS_GPIO0_INT_ 0x00000001 + +#define INT_EN 0x5C +#define INT_EN_SW_INT_EN_ 0x80000000 +#define INT_EN_TXSTOP_INT_EN_ 0x02000000 +#define INT_EN_RXSTOP_INT_EN_ 0x01000000 +#define INT_EN_RXDFH_INT_EN_ 0x00800000 +#define INT_EN_TIOC_INT_EN_ 0x00200000 +#define INT_EN_RXD_INT_EN_ 0x00100000 +#define INT_EN_GPT_INT_EN_ 0x00080000 +#define INT_EN_PHY_INT_EN_ 0x00040000 +#define INT_EN_PME_INT_EN_ 0x00020000 +#define INT_EN_TXSO_EN_ 0x00010000 +#define INT_EN_RWT_EN_ 0x00008000 +#define INT_EN_RXE_EN_ 0x00004000 +#define INT_EN_TXE_EN_ 0x00002000 +#define INT_EN_TDFU_EN_ 0x00000800 +#define INT_EN_TDFO_EN_ 0x00000400 +#define INT_EN_TDFA_EN_ 0x00000200 +#define INT_EN_TSFF_EN_ 0x00000100 +#define INT_EN_TSFL_EN_ 0x00000080 +#define INT_EN_RXDF_EN_ 0x00000040 +#define INT_EN_RDFL_EN_ 0x00000020 +#define INT_EN_RSFF_EN_ 0x00000010 +#define INT_EN_RSFL_EN_ 0x00000008 +#define INT_EN_GPIO2_INT_ 0x00000004 +#define INT_EN_GPIO1_INT_ 0x00000002 +#define INT_EN_GPIO0_INT_ 0x00000001 + +#define BYTE_TEST 0x64 + +#define FIFO_INT 0x68 +#define FIFO_INT_TX_AVAIL_LEVEL_ 0xFF000000 +#define FIFO_INT_TX_STS_LEVEL_ 0x00FF0000 +#define FIFO_INT_RX_AVAIL_LEVEL_ 0x0000FF00 +#define FIFO_INT_RX_STS_LEVEL_ 0x000000FF + +#define RX_CFG 0x6C +#define RX_CFG_RX_END_ALGN_ 0xC0000000 +#define RX_CFG_RX_END_ALGN4_ 0x00000000 +#define RX_CFG_RX_END_ALGN16_ 0x40000000 +#define RX_CFG_RX_END_ALGN32_ 0x80000000 +#define RX_CFG_RX_DMA_CNT_ 0x0FFF0000 +#define RX_CFG_RX_DUMP_ 0x00008000 +#define RX_CFG_RXDOFF_ 0x00001F00 + +#define TX_CFG 0x70 +#define TX_CFG_TXS_DUMP_ 0x00008000 +#define TX_CFG_TXD_DUMP_ 0x00004000 +#define TX_CFG_TXSAO_ 0x00000004 +#define TX_CFG_TX_ON_ 0x00000002 +#define TX_CFG_STOP_TX_ 0x00000001 + +#define HW_CFG 0x74 +#define HW_CFG_TTM_ 0x00200000 +#define HW_CFG_SF_ 0x00100000 +#define HW_CFG_TX_FIF_SZ_ 0x000F0000 +#define HW_CFG_TR_ 0x00003000 +#define HW_CFG_SRST_ 0x00000001 + +/* only available on 115/117 */ +#define HW_CFG_PHY_CLK_SEL_ 0x00000060 +#define HW_CFG_PHY_CLK_SEL_INT_PHY_ 0x00000000 +#define HW_CFG_PHY_CLK_SEL_EXT_PHY_ 0x00000020 +#define HW_CFG_PHY_CLK_SEL_CLK_DIS_ 0x00000040 +#define HW_CFG_SMI_SEL_ 0x00000010 +#define HW_CFG_EXT_PHY_DET_ 0x00000008 +#define HW_CFG_EXT_PHY_EN_ 0x00000004 +#define HW_CFG_SRST_TO_ 0x00000002 + +/* only available on 116/118 */ +#define HW_CFG_32_16_BIT_MODE_ 0x00000004 + +#define RX_DP_CTRL 0x78 +#define RX_DP_CTRL_RX_FFWD_ 0x80000000 + +#define RX_FIFO_INF 0x7C +#define RX_FIFO_INF_RXSUSED_ 0x00FF0000 +#define RX_FIFO_INF_RXDUSED_ 0x0000FFFF + +#define TX_FIFO_INF 0x80 +#define TX_FIFO_INF_TSUSED_ 0x00FF0000 +#define TX_FIFO_INF_TDFREE_ 0x0000FFFF + +#define PMT_CTRL 0x84 +#define PMT_CTRL_PM_MODE_ 0x00003000 +#define PMT_CTRL_PM_MODE_D0_ 0x00000000 +#define PMT_CTRL_PM_MODE_D1_ 0x00001000 +#define PMT_CTRL_PM_MODE_D2_ 0x00002000 +#define PMT_CTRL_PM_MODE_D3_ 0x00003000 +#define PMT_CTRL_PHY_RST_ 0x00000400 +#define PMT_CTRL_WOL_EN_ 0x00000200 +#define PMT_CTRL_ED_EN_ 0x00000100 +#define PMT_CTRL_PME_TYPE_ 0x00000040 +#define PMT_CTRL_WUPS_ 0x00000030 +#define PMT_CTRL_WUPS_NOWAKE_ 0x00000000 +#define PMT_CTRL_WUPS_ED_ 0x00000010 +#define PMT_CTRL_WUPS_WOL_ 0x00000020 +#define PMT_CTRL_WUPS_MULTI_ 0x00000030 +#define PMT_CTRL_PME_IND_ 0x00000008 +#define PMT_CTRL_PME_POL_ 0x00000004 +#define PMT_CTRL_PME_EN_ 0x00000002 +#define PMT_CTRL_READY_ 0x00000001 + +#define GPIO_CFG 0x88 +#define GPIO_CFG_LED3_EN_ 0x40000000 +#define GPIO_CFG_LED2_EN_ 0x20000000 +#define GPIO_CFG_LED1_EN_ 0x10000000 +#define GPIO_CFG_GPIO2_INT_POL_ 0x04000000 +#define GPIO_CFG_GPIO1_INT_POL_ 0x02000000 +#define GPIO_CFG_GPIO0_INT_POL_ 0x01000000 +#define GPIO_CFG_EEPR_EN_ 0x00700000 +#define GPIO_CFG_GPIOBUF2_ 0x00040000 +#define GPIO_CFG_GPIOBUF1_ 0x00020000 +#define GPIO_CFG_GPIOBUF0_ 0x00010000 +#define GPIO_CFG_GPIODIR2_ 0x00000400 +#define GPIO_CFG_GPIODIR1_ 0x00000200 +#define GPIO_CFG_GPIODIR0_ 0x00000100 +#define GPIO_CFG_GPIOD4_ 0x00000020 +#define GPIO_CFG_GPIOD3_ 0x00000010 +#define GPIO_CFG_GPIOD2_ 0x00000004 +#define GPIO_CFG_GPIOD1_ 0x00000002 +#define GPIO_CFG_GPIOD0_ 0x00000001 + +#define GPT_CFG 0x8C +#define GPT_CFG_TIMER_EN_ 0x20000000 +#define GPT_CFG_GPT_LOAD_ 0x0000FFFF + +#define GPT_CNT 0x90 +#define GPT_CNT_GPT_CNT_ 0x0000FFFF + +#define WORD_SWAP 0x98 + +#define FREE_RUN 0x9C + +#define RX_DROP 0xA0 + +#define MAC_CSR_CMD 0xA4 +#define MAC_CSR_CMD_CSR_BUSY_ 0x80000000 +#define MAC_CSR_CMD_R_NOT_W_ 0x40000000 +#define MAC_CSR_CMD_CSR_ADDR_ 0x000000FF + +#define MAC_CSR_DATA 0xA8 + +#define AFC_CFG 0xAC +#define AFC_CFG_AFC_HI_ 0x00FF0000 +#define AFC_CFG_AFC_LO_ 0x0000FF00 +#define AFC_CFG_BACK_DUR_ 0x000000F0 +#define AFC_CFG_FCMULT_ 0x00000008 +#define AFC_CFG_FCBRD_ 0x00000004 +#define AFC_CFG_FCADD_ 0x00000002 +#define AFC_CFG_FCANY_ 0x00000001 + +#define E2P_CMD 0xB0 +#define E2P_CMD_EPC_BUSY_ 0x80000000 +#define E2P_CMD_EPC_CMD_ 0x70000000 +#define E2P_CMD_EPC_CMD_READ_ 0x00000000 +#define E2P_CMD_EPC_CMD_EWDS_ 0x10000000 +#define E2P_CMD_EPC_CMD_EWEN_ 0x20000000 +#define E2P_CMD_EPC_CMD_WRITE_ 0x30000000 +#define E2P_CMD_EPC_CMD_WRAL_ 0x40000000 +#define E2P_CMD_EPC_CMD_ERASE_ 0x50000000 +#define E2P_CMD_EPC_CMD_ERAL_ 0x60000000 +#define E2P_CMD_EPC_CMD_RELOAD_ 0x70000000 +#define E2P_CMD_EPC_TIMEOUT_ 0x00000200 +#define E2P_CMD_MAC_ADDR_LOADED_ 0x00000100 +#define E2P_CMD_EPC_ADDR_ 0x000000FF + +#define E2P_DATA 0xB4 +#define E2P_DATA_EEPROM_DATA_ 0x000000FF +#define LAN_REGISTER_EXTENT 0x00000100 + +/* + * MAC Control and Status Register (Indirect Address) + * Offset (through the MAC_CSR CMD and DATA port) + */ +#define MAC_CR 0x01 +#define MAC_CR_RXALL_ 0x80000000 +#define MAC_CR_HBDIS_ 0x10000000 +#define MAC_CR_RCVOWN_ 0x00800000 +#define MAC_CR_LOOPBK_ 0x00200000 +#define MAC_CR_FDPX_ 0x00100000 +#define MAC_CR_MCPAS_ 0x00080000 +#define MAC_CR_PRMS_ 0x00040000 +#define MAC_CR_INVFILT_ 0x00020000 +#define MAC_CR_PASSBAD_ 0x00010000 +#define MAC_CR_HFILT_ 0x00008000 +#define MAC_CR_HPFILT_ 0x00002000 +#define MAC_CR_LCOLL_ 0x00001000 +#define MAC_CR_BCAST_ 0x00000800 +#define MAC_CR_DISRTY_ 0x00000400 +#define MAC_CR_PADSTR_ 0x00000100 +#define MAC_CR_BOLMT_MASK_ 0x000000C0 +#define MAC_CR_DFCHK_ 0x00000020 +#define MAC_CR_TXEN_ 0x00000008 +#define MAC_CR_RXEN_ 0x00000004 + +#define ADDRH 0x02 + +#define ADDRL 0x03 + +#define HASHH 0x04 + +#define HASHL 0x05 + +#define MII_ACC 0x06 +#define MII_ACC_PHY_ADDR_ 0x0000F800 +#define MII_ACC_MIIRINDA_ 0x000007C0 +#define MII_ACC_MII_WRITE_ 0x00000002 +#define MII_ACC_MII_BUSY_ 0x00000001 + +#define MII_DATA 0x07 + +#define FLOW 0x08 +#define FLOW_FCPT_ 0xFFFF0000 +#define FLOW_FCPASS_ 0x00000004 +#define FLOW_FCEN_ 0x00000002 +#define FLOW_FCBSY_ 0x00000001 + +#define VLAN1 0x09 + +#define VLAN2 0x0A + +#define WUFF 0x0B + +#define WUCSR 0x0C +#define WUCSR_GUE_ 0x00000200 +#define WUCSR_WUFR_ 0x00000040 +#define WUCSR_MPR_ 0x00000020 +#define WUCSR_WAKE_EN_ 0x00000004 +#define WUCSR_MPEN_ 0x00000002 + +/* + * Phy definitions (vendor-specific) + */ +#define LAN9118_PHY_ID 0x00C0001C + +#define MII_INTSTS 0x1D + +#define MII_INTMSK 0x1E +#define PHY_INTMSK_AN_RCV_ (1 << 1) +#define PHY_INTMSK_PDFAULT_ (1 << 2) +#define PHY_INTMSK_AN_ACK_ (1 << 3) +#define PHY_INTMSK_LNKDOWN_ (1 << 4) +#define PHY_INTMSK_RFAULT_ (1 << 5) +#define PHY_INTMSK_AN_COMP_ (1 << 6) +#define PHY_INTMSK_ENERGYON_ (1 << 7) +#define PHY_INTMSK_DEFAULT_ (PHY_INTMSK_ENERGYON_ | \ + PHY_INTMSK_AN_COMP_ | \ + PHY_INTMSK_RFAULT_ | \ + PHY_INTMSK_LNKDOWN_) + +#define ADVERTISE_PAUSE_ALL (ADVERTISE_PAUSE_CAP | \ + ADVERTISE_PAUSE_ASYM) + +#define LPA_PAUSE_ALL (LPA_PAUSE_CAP | \ + LPA_PAUSE_ASYM) + +#endif /* __SMSC911X_H__ */ diff --git a/drivers/net/smsc9420.c b/drivers/net/smsc9420.c new file mode 100644 index 0000000000000000000000000000000000000000..27e017d969667f474b4c647c23c1fffe42a19bbf --- /dev/null +++ b/drivers/net/smsc9420.c @@ -0,0 +1,1744 @@ + /*************************************************************************** + * + * Copyright (C) 2007,2008 SMSC + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + *************************************************************************** + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "smsc9420.h" + +#define DRV_NAME "smsc9420" +#define PFX DRV_NAME ": " +#define DRV_MDIONAME "smsc9420-mdio" +#define DRV_DESCRIPTION "SMSC LAN9420 driver" +#define DRV_VERSION "1.01" + +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); + +struct smsc9420_dma_desc { + u32 status; + u32 length; + u32 buffer1; + u32 buffer2; +}; + +struct smsc9420_ring_info { + struct sk_buff *skb; + dma_addr_t mapping; +}; + +struct smsc9420_pdata { + void __iomem *base_addr; + struct pci_dev *pdev; + struct net_device *dev; + + struct smsc9420_dma_desc *rx_ring; + struct smsc9420_dma_desc *tx_ring; + struct smsc9420_ring_info *tx_buffers; + struct smsc9420_ring_info *rx_buffers; + dma_addr_t rx_dma_addr; + dma_addr_t tx_dma_addr; + int tx_ring_head, tx_ring_tail; + int rx_ring_head, rx_ring_tail; + + spinlock_t int_lock; + spinlock_t phy_lock; + + struct napi_struct napi; + + bool software_irq_signal; + bool rx_csum; + u32 msg_enable; + + struct phy_device *phy_dev; + struct mii_bus *mii_bus; + int phy_irq[PHY_MAX_ADDR]; + int last_duplex; + int last_carrier; +}; + +static const struct pci_device_id smsc9420_id_table[] = { + { PCI_VENDOR_ID_9420, PCI_DEVICE_ID_9420, PCI_ANY_ID, PCI_ANY_ID, }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, smsc9420_id_table); + +#define SMSC_MSG_DEFAULT (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK) + +static uint smsc_debug; +static uint debug = -1; +module_param(debug, uint, 0); +MODULE_PARM_DESC(debug, "debug level"); + +#define smsc_dbg(TYPE, f, a...) \ +do { if ((pd)->msg_enable & NETIF_MSG_##TYPE) \ + printk(KERN_DEBUG PFX f "\n", ## a); \ +} while (0) + +#define smsc_info(TYPE, f, a...) \ +do { if ((pd)->msg_enable & NETIF_MSG_##TYPE) \ + printk(KERN_INFO PFX f "\n", ## a); \ +} while (0) + +#define smsc_warn(TYPE, f, a...) \ +do { if ((pd)->msg_enable & NETIF_MSG_##TYPE) \ + printk(KERN_WARNING PFX f "\n", ## a); \ +} while (0) + +static inline u32 smsc9420_reg_read(struct smsc9420_pdata *pd, u32 offset) +{ + return ioread32(pd->base_addr + offset); +} + +static inline void +smsc9420_reg_write(struct smsc9420_pdata *pd, u32 offset, u32 value) +{ + iowrite32(value, pd->base_addr + offset); +} + +static inline void smsc9420_pci_flush_write(struct smsc9420_pdata *pd) +{ + /* to ensure PCI write completion, we must perform a PCI read */ + smsc9420_reg_read(pd, ID_REV); +} + +static int smsc9420_mii_read(struct mii_bus *bus, int phyaddr, int regidx) +{ + struct smsc9420_pdata *pd = (struct smsc9420_pdata *)bus->priv; + unsigned long flags; + u32 addr; + int i, reg = -EIO; + + spin_lock_irqsave(&pd->phy_lock, flags); + + /* confirm MII not busy */ + if ((smsc9420_reg_read(pd, MII_ACCESS) & MII_ACCESS_MII_BUSY_)) { + smsc_warn(DRV, "MII is busy???"); + goto out; + } + + /* set the address, index & direction (read from PHY) */ + addr = ((phyaddr & 0x1F) << 11) | ((regidx & 0x1F) << 6) | + MII_ACCESS_MII_READ_; + smsc9420_reg_write(pd, MII_ACCESS, addr); + + /* wait for read to complete with 50us timeout */ + for (i = 0; i < 5; i++) { + if (!(smsc9420_reg_read(pd, MII_ACCESS) & + MII_ACCESS_MII_BUSY_)) { + reg = (u16)smsc9420_reg_read(pd, MII_DATA); + goto out; + } + udelay(10); + } + + smsc_warn(DRV, "MII busy timeout!"); + +out: + spin_unlock_irqrestore(&pd->phy_lock, flags); + return reg; +} + +static int smsc9420_mii_write(struct mii_bus *bus, int phyaddr, int regidx, + u16 val) +{ + struct smsc9420_pdata *pd = (struct smsc9420_pdata *)bus->priv; + unsigned long flags; + u32 addr; + int i, reg = -EIO; + + spin_lock_irqsave(&pd->phy_lock, flags); + + /* confirm MII not busy */ + if ((smsc9420_reg_read(pd, MII_ACCESS) & MII_ACCESS_MII_BUSY_)) { + smsc_warn(DRV, "MII is busy???"); + goto out; + } + + /* put the data to write in the MAC */ + smsc9420_reg_write(pd, MII_DATA, (u32)val); + + /* set the address, index & direction (write to PHY) */ + addr = ((phyaddr & 0x1F) << 11) | ((regidx & 0x1F) << 6) | + MII_ACCESS_MII_WRITE_; + smsc9420_reg_write(pd, MII_ACCESS, addr); + + /* wait for write to complete with 50us timeout */ + for (i = 0; i < 5; i++) { + if (!(smsc9420_reg_read(pd, MII_ACCESS) & + MII_ACCESS_MII_BUSY_)) { + reg = 0; + goto out; + } + udelay(10); + } + + smsc_warn(DRV, "MII busy timeout!"); + +out: + spin_unlock_irqrestore(&pd->phy_lock, flags); + return reg; +} + +/* Returns hash bit number for given MAC address + * Example: + * 01 00 5E 00 00 01 -> returns bit number 31 */ +static u32 smsc9420_hash(u8 addr[ETH_ALEN]) +{ + return (ether_crc(ETH_ALEN, addr) >> 26) & 0x3f; +} + +static int smsc9420_eeprom_reload(struct smsc9420_pdata *pd) +{ + int timeout = 100000; + + BUG_ON(!pd); + + if (smsc9420_reg_read(pd, E2P_CMD) & E2P_CMD_EPC_BUSY_) { + smsc_dbg(DRV, "smsc9420_eeprom_reload: Eeprom busy"); + return -EIO; + } + + smsc9420_reg_write(pd, E2P_CMD, + (E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_RELOAD_)); + + do { + udelay(10); + if (!(smsc9420_reg_read(pd, E2P_CMD) & E2P_CMD_EPC_BUSY_)) + return 0; + } while (timeout--); + + smsc_warn(DRV, "smsc9420_eeprom_reload: Eeprom timed out"); + return -EIO; +} + +/* Standard ioctls for mii-tool */ +static int smsc9420_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct smsc9420_pdata *pd = netdev_priv(dev); + + if (!netif_running(dev) || !pd->phy_dev) + return -EINVAL; + + return phy_mii_ioctl(pd->phy_dev, if_mii(ifr), cmd); +} + +static int smsc9420_ethtool_get_settings(struct net_device *dev, + struct ethtool_cmd *cmd) +{ + struct smsc9420_pdata *pd = netdev_priv(dev); + + cmd->maxtxpkt = 1; + cmd->maxrxpkt = 1; + return phy_ethtool_gset(pd->phy_dev, cmd); +} + +static int smsc9420_ethtool_set_settings(struct net_device *dev, + struct ethtool_cmd *cmd) +{ + struct smsc9420_pdata *pd = netdev_priv(dev); + + return phy_ethtool_sset(pd->phy_dev, cmd); +} + +static void smsc9420_ethtool_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *drvinfo) +{ + struct smsc9420_pdata *pd = netdev_priv(netdev); + + strcpy(drvinfo->driver, DRV_NAME); + strcpy(drvinfo->bus_info, pci_name(pd->pdev)); + strcpy(drvinfo->version, DRV_VERSION); +} + +static u32 smsc9420_ethtool_get_msglevel(struct net_device *netdev) +{ + struct smsc9420_pdata *pd = netdev_priv(netdev); + return pd->msg_enable; +} + +static void smsc9420_ethtool_set_msglevel(struct net_device *netdev, u32 data) +{ + struct smsc9420_pdata *pd = netdev_priv(netdev); + pd->msg_enable = data; +} + +static int smsc9420_ethtool_nway_reset(struct net_device *netdev) +{ + struct smsc9420_pdata *pd = netdev_priv(netdev); + return phy_start_aneg(pd->phy_dev); +} + +static int smsc9420_ethtool_getregslen(struct net_device *dev) +{ + /* all smsc9420 registers plus all phy registers */ + return 0x100 + (32 * sizeof(u32)); +} + +static void +smsc9420_ethtool_getregs(struct net_device *dev, struct ethtool_regs *regs, + void *buf) +{ + struct smsc9420_pdata *pd = netdev_priv(dev); + struct phy_device *phy_dev = pd->phy_dev; + unsigned int i, j = 0; + u32 *data = buf; + + regs->version = smsc9420_reg_read(pd, ID_REV); + for (i = 0; i < 0x100; i += (sizeof(u32))) + data[j++] = smsc9420_reg_read(pd, i); + + for (i = 0; i <= 31; i++) + data[j++] = smsc9420_mii_read(phy_dev->bus, phy_dev->addr, i); +} + +static void smsc9420_eeprom_enable_access(struct smsc9420_pdata *pd) +{ + unsigned int temp = smsc9420_reg_read(pd, GPIO_CFG); + temp &= ~GPIO_CFG_EEPR_EN_; + smsc9420_reg_write(pd, GPIO_CFG, temp); + msleep(1); +} + +static int smsc9420_eeprom_send_cmd(struct smsc9420_pdata *pd, u32 op) +{ + int timeout = 100; + u32 e2cmd; + + smsc_dbg(HW, "op 0x%08x", op); + if (smsc9420_reg_read(pd, E2P_CMD) & E2P_CMD_EPC_BUSY_) { + smsc_warn(HW, "Busy at start"); + return -EBUSY; + } + + e2cmd = op | E2P_CMD_EPC_BUSY_; + smsc9420_reg_write(pd, E2P_CMD, e2cmd); + + do { + msleep(1); + e2cmd = smsc9420_reg_read(pd, E2P_CMD); + } while ((e2cmd & E2P_CMD_EPC_BUSY_) && (timeout--)); + + if (!timeout) { + smsc_info(HW, "TIMED OUT"); + return -EAGAIN; + } + + if (e2cmd & E2P_CMD_EPC_TIMEOUT_) { + smsc_info(HW, "Error occured during eeprom operation"); + return -EINVAL; + } + + return 0; +} + +static int smsc9420_eeprom_read_location(struct smsc9420_pdata *pd, + u8 address, u8 *data) +{ + u32 op = E2P_CMD_EPC_CMD_READ_ | address; + int ret; + + smsc_dbg(HW, "address 0x%x", address); + ret = smsc9420_eeprom_send_cmd(pd, op); + + if (!ret) + data[address] = smsc9420_reg_read(pd, E2P_DATA); + + return ret; +} + +static int smsc9420_eeprom_write_location(struct smsc9420_pdata *pd, + u8 address, u8 data) +{ + u32 op = E2P_CMD_EPC_CMD_ERASE_ | address; + int ret; + + smsc_dbg(HW, "address 0x%x, data 0x%x", address, data); + ret = smsc9420_eeprom_send_cmd(pd, op); + + if (!ret) { + op = E2P_CMD_EPC_CMD_WRITE_ | address; + smsc9420_reg_write(pd, E2P_DATA, (u32)data); + ret = smsc9420_eeprom_send_cmd(pd, op); + } + + return ret; +} + +static int smsc9420_ethtool_get_eeprom_len(struct net_device *dev) +{ + return SMSC9420_EEPROM_SIZE; +} + +static int smsc9420_ethtool_get_eeprom(struct net_device *dev, + struct ethtool_eeprom *eeprom, u8 *data) +{ + struct smsc9420_pdata *pd = netdev_priv(dev); + u8 eeprom_data[SMSC9420_EEPROM_SIZE]; + int len, i; + + smsc9420_eeprom_enable_access(pd); + + len = min(eeprom->len, SMSC9420_EEPROM_SIZE); + for (i = 0; i < len; i++) { + int ret = smsc9420_eeprom_read_location(pd, i, eeprom_data); + if (ret < 0) { + eeprom->len = 0; + return ret; + } + } + + memcpy(data, &eeprom_data[eeprom->offset], len); + eeprom->len = len; + return 0; +} + +static int smsc9420_ethtool_set_eeprom(struct net_device *dev, + struct ethtool_eeprom *eeprom, u8 *data) +{ + struct smsc9420_pdata *pd = netdev_priv(dev); + int ret; + + smsc9420_eeprom_enable_access(pd); + smsc9420_eeprom_send_cmd(pd, E2P_CMD_EPC_CMD_EWEN_); + ret = smsc9420_eeprom_write_location(pd, eeprom->offset, *data); + smsc9420_eeprom_send_cmd(pd, E2P_CMD_EPC_CMD_EWDS_); + + /* Single byte write, according to man page */ + eeprom->len = 1; + + return ret; +} + +static const struct ethtool_ops smsc9420_ethtool_ops = { + .get_settings = smsc9420_ethtool_get_settings, + .set_settings = smsc9420_ethtool_set_settings, + .get_drvinfo = smsc9420_ethtool_get_drvinfo, + .get_msglevel = smsc9420_ethtool_get_msglevel, + .set_msglevel = smsc9420_ethtool_set_msglevel, + .nway_reset = smsc9420_ethtool_nway_reset, + .get_link = ethtool_op_get_link, + .get_eeprom_len = smsc9420_ethtool_get_eeprom_len, + .get_eeprom = smsc9420_ethtool_get_eeprom, + .set_eeprom = smsc9420_ethtool_set_eeprom, + .get_regs_len = smsc9420_ethtool_getregslen, + .get_regs = smsc9420_ethtool_getregs, +}; + +/* Sets the device MAC address to dev_addr */ +static void smsc9420_set_mac_address(struct net_device *dev) +{ + struct smsc9420_pdata *pd = netdev_priv(dev); + u8 *dev_addr = dev->dev_addr; + u32 mac_high16 = (dev_addr[5] << 8) | dev_addr[4]; + u32 mac_low32 = (dev_addr[3] << 24) | (dev_addr[2] << 16) | + (dev_addr[1] << 8) | dev_addr[0]; + + smsc9420_reg_write(pd, ADDRH, mac_high16); + smsc9420_reg_write(pd, ADDRL, mac_low32); +} + +static void smsc9420_check_mac_address(struct net_device *dev) +{ + struct smsc9420_pdata *pd = netdev_priv(dev); + + /* Check if mac address has been specified when bringing interface up */ + if (is_valid_ether_addr(dev->dev_addr)) { + smsc9420_set_mac_address(dev); + smsc_dbg(PROBE, "MAC Address is specified by configuration"); + } else { + /* Try reading mac address from device. if EEPROM is present + * it will already have been set */ + u32 mac_high16 = smsc9420_reg_read(pd, ADDRH); + u32 mac_low32 = smsc9420_reg_read(pd, ADDRL); + dev->dev_addr[0] = (u8)(mac_low32); + dev->dev_addr[1] = (u8)(mac_low32 >> 8); + dev->dev_addr[2] = (u8)(mac_low32 >> 16); + dev->dev_addr[3] = (u8)(mac_low32 >> 24); + dev->dev_addr[4] = (u8)(mac_high16); + dev->dev_addr[5] = (u8)(mac_high16 >> 8); + + if (is_valid_ether_addr(dev->dev_addr)) { + /* eeprom values are valid so use them */ + smsc_dbg(PROBE, "Mac Address is read from EEPROM"); + } else { + /* eeprom values are invalid, generate random MAC */ + random_ether_addr(dev->dev_addr); + smsc9420_set_mac_address(dev); + smsc_dbg(PROBE, + "MAC Address is set to random_ether_addr"); + } + } +} + +static void smsc9420_stop_tx(struct smsc9420_pdata *pd) +{ + u32 dmac_control, mac_cr, dma_intr_ena; + int timeOut = 1000; + + /* disable TX DMAC */ + dmac_control = smsc9420_reg_read(pd, DMAC_CONTROL); + dmac_control &= (~DMAC_CONTROL_ST_); + smsc9420_reg_write(pd, DMAC_CONTROL, dmac_control); + + /* Wait max 10ms for transmit process to stop */ + while (timeOut--) { + if (smsc9420_reg_read(pd, DMAC_STATUS) & DMAC_STS_TS_) + break; + udelay(10); + } + + if (!timeOut) + smsc_warn(IFDOWN, "TX DMAC failed to stop"); + + /* ACK Tx DMAC stop bit */ + smsc9420_reg_write(pd, DMAC_STATUS, DMAC_STS_TXPS_); + + /* mask TX DMAC interrupts */ + dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA); + dma_intr_ena &= ~(DMAC_INTR_ENA_TX_); + smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena); + smsc9420_pci_flush_write(pd); + + /* stop MAC TX */ + mac_cr = smsc9420_reg_read(pd, MAC_CR) & (~MAC_CR_TXEN_); + smsc9420_reg_write(pd, MAC_CR, mac_cr); + smsc9420_pci_flush_write(pd); +} + +static void smsc9420_free_tx_ring(struct smsc9420_pdata *pd) +{ + int i; + + BUG_ON(!pd->tx_ring); + + if (!pd->tx_buffers) + return; + + for (i = 0; i < TX_RING_SIZE; i++) { + struct sk_buff *skb = pd->tx_buffers[i].skb; + + if (skb) { + BUG_ON(!pd->tx_buffers[i].mapping); + pci_unmap_single(pd->pdev, pd->tx_buffers[i].mapping, + skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb_any(skb); + } + + pd->tx_ring[i].status = 0; + pd->tx_ring[i].length = 0; + pd->tx_ring[i].buffer1 = 0; + pd->tx_ring[i].buffer2 = 0; + } + wmb(); + + kfree(pd->tx_buffers); + pd->tx_buffers = NULL; + + pd->tx_ring_head = 0; + pd->tx_ring_tail = 0; +} + +static void smsc9420_free_rx_ring(struct smsc9420_pdata *pd) +{ + int i; + + BUG_ON(!pd->rx_ring); + + if (!pd->rx_buffers) + return; + + for (i = 0; i < RX_RING_SIZE; i++) { + if (pd->rx_buffers[i].skb) + dev_kfree_skb_any(pd->rx_buffers[i].skb); + + if (pd->rx_buffers[i].mapping) + pci_unmap_single(pd->pdev, pd->rx_buffers[i].mapping, + PKT_BUF_SZ, PCI_DMA_FROMDEVICE); + + pd->rx_ring[i].status = 0; + pd->rx_ring[i].length = 0; + pd->rx_ring[i].buffer1 = 0; + pd->rx_ring[i].buffer2 = 0; + } + wmb(); + + kfree(pd->rx_buffers); + pd->rx_buffers = NULL; + + pd->rx_ring_head = 0; + pd->rx_ring_tail = 0; +} + +static void smsc9420_stop_rx(struct smsc9420_pdata *pd) +{ + int timeOut = 1000; + u32 mac_cr, dmac_control, dma_intr_ena; + + /* mask RX DMAC interrupts */ + dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA); + dma_intr_ena &= (~DMAC_INTR_ENA_RX_); + smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena); + smsc9420_pci_flush_write(pd); + + /* stop RX MAC prior to stoping DMA */ + mac_cr = smsc9420_reg_read(pd, MAC_CR) & (~MAC_CR_RXEN_); + smsc9420_reg_write(pd, MAC_CR, mac_cr); + smsc9420_pci_flush_write(pd); + + /* stop RX DMAC */ + dmac_control = smsc9420_reg_read(pd, DMAC_CONTROL); + dmac_control &= (~DMAC_CONTROL_SR_); + smsc9420_reg_write(pd, DMAC_CONTROL, dmac_control); + smsc9420_pci_flush_write(pd); + + /* wait up to 10ms for receive to stop */ + while (timeOut--) { + if (smsc9420_reg_read(pd, DMAC_STATUS) & DMAC_STS_RS_) + break; + udelay(10); + } + + if (!timeOut) + smsc_warn(IFDOWN, "RX DMAC did not stop! timeout."); + + /* ACK the Rx DMAC stop bit */ + smsc9420_reg_write(pd, DMAC_STATUS, DMAC_STS_RXPS_); +} + +static irqreturn_t smsc9420_isr(int irq, void *dev_id) +{ + struct smsc9420_pdata *pd = dev_id; + u32 int_cfg, int_sts, int_ctl; + irqreturn_t ret = IRQ_NONE; + ulong flags; + + BUG_ON(!pd); + BUG_ON(!pd->base_addr); + + int_cfg = smsc9420_reg_read(pd, INT_CFG); + + /* check if it's our interrupt */ + if ((int_cfg & (INT_CFG_IRQ_EN_ | INT_CFG_IRQ_INT_)) != + (INT_CFG_IRQ_EN_ | INT_CFG_IRQ_INT_)) + return IRQ_NONE; + + int_sts = smsc9420_reg_read(pd, INT_STAT); + + if (likely(INT_STAT_DMAC_INT_ & int_sts)) { + u32 status = smsc9420_reg_read(pd, DMAC_STATUS); + u32 ints_to_clear = 0; + + if (status & DMAC_STS_TX_) { + ints_to_clear |= (DMAC_STS_TX_ | DMAC_STS_NIS_); + netif_wake_queue(pd->dev); + } + + if (status & DMAC_STS_RX_) { + /* mask RX DMAC interrupts */ + u32 dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA); + dma_intr_ena &= (~DMAC_INTR_ENA_RX_); + smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena); + smsc9420_pci_flush_write(pd); + + ints_to_clear |= (DMAC_STS_RX_ | DMAC_STS_NIS_); + netif_rx_schedule(&pd->napi); + } + + if (ints_to_clear) + smsc9420_reg_write(pd, DMAC_STATUS, ints_to_clear); + + ret = IRQ_HANDLED; + } + + if (unlikely(INT_STAT_SW_INT_ & int_sts)) { + /* mask software interrupt */ + spin_lock_irqsave(&pd->int_lock, flags); + int_ctl = smsc9420_reg_read(pd, INT_CTL); + int_ctl &= (~INT_CTL_SW_INT_EN_); + smsc9420_reg_write(pd, INT_CTL, int_ctl); + spin_unlock_irqrestore(&pd->int_lock, flags); + + smsc9420_reg_write(pd, INT_STAT, INT_STAT_SW_INT_); + pd->software_irq_signal = true; + smp_wmb(); + + ret = IRQ_HANDLED; + } + + /* to ensure PCI write completion, we must perform a PCI read */ + smsc9420_pci_flush_write(pd); + + return ret; +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void smsc9420_poll_controller(struct net_device *dev) +{ + disable_irq(dev->irq); + smsc9420_isr(0, dev); + enable_irq(dev->irq); +} +#endif /* CONFIG_NET_POLL_CONTROLLER */ + +static void smsc9420_dmac_soft_reset(struct smsc9420_pdata *pd) +{ + smsc9420_reg_write(pd, BUS_MODE, BUS_MODE_SWR_); + smsc9420_reg_read(pd, BUS_MODE); + udelay(2); + if (smsc9420_reg_read(pd, BUS_MODE) & BUS_MODE_SWR_) + smsc_warn(DRV, "Software reset not cleared"); +} + +static int smsc9420_stop(struct net_device *dev) +{ + struct smsc9420_pdata *pd = netdev_priv(dev); + u32 int_cfg; + ulong flags; + + BUG_ON(!pd); + BUG_ON(!pd->phy_dev); + + /* disable master interrupt */ + spin_lock_irqsave(&pd->int_lock, flags); + int_cfg = smsc9420_reg_read(pd, INT_CFG) & (~INT_CFG_IRQ_EN_); + smsc9420_reg_write(pd, INT_CFG, int_cfg); + spin_unlock_irqrestore(&pd->int_lock, flags); + + netif_tx_disable(dev); + napi_disable(&pd->napi); + + smsc9420_stop_tx(pd); + smsc9420_free_tx_ring(pd); + + smsc9420_stop_rx(pd); + smsc9420_free_rx_ring(pd); + + free_irq(dev->irq, pd); + + smsc9420_dmac_soft_reset(pd); + + phy_stop(pd->phy_dev); + + phy_disconnect(pd->phy_dev); + pd->phy_dev = NULL; + mdiobus_unregister(pd->mii_bus); + mdiobus_free(pd->mii_bus); + + return 0; +} + +static void smsc9420_rx_count_stats(struct net_device *dev, u32 desc_status) +{ + if (unlikely(desc_status & RDES0_ERROR_SUMMARY_)) { + dev->stats.rx_errors++; + if (desc_status & RDES0_DESCRIPTOR_ERROR_) + dev->stats.rx_over_errors++; + else if (desc_status & (RDES0_FRAME_TOO_LONG_ | + RDES0_RUNT_FRAME_ | RDES0_COLLISION_SEEN_)) + dev->stats.rx_frame_errors++; + else if (desc_status & RDES0_CRC_ERROR_) + dev->stats.rx_crc_errors++; + } + + if (unlikely(desc_status & RDES0_LENGTH_ERROR_)) + dev->stats.rx_length_errors++; + + if (unlikely(!((desc_status & RDES0_LAST_DESCRIPTOR_) && + (desc_status & RDES0_FIRST_DESCRIPTOR_)))) + dev->stats.rx_length_errors++; + + if (desc_status & RDES0_MULTICAST_FRAME_) + dev->stats.multicast++; +} + +static void smsc9420_rx_handoff(struct smsc9420_pdata *pd, const int index, + const u32 status) +{ + struct net_device *dev = pd->dev; + struct sk_buff *skb; + u16 packet_length = (status & RDES0_FRAME_LENGTH_MASK_) + >> RDES0_FRAME_LENGTH_SHFT_; + + /* remove crc from packet lendth */ + packet_length -= 4; + + if (pd->rx_csum) + packet_length -= 2; + + dev->stats.rx_packets++; + dev->stats.rx_bytes += packet_length; + + pci_unmap_single(pd->pdev, pd->rx_buffers[index].mapping, + PKT_BUF_SZ, PCI_DMA_FROMDEVICE); + pd->rx_buffers[index].mapping = 0; + + skb = pd->rx_buffers[index].skb; + pd->rx_buffers[index].skb = NULL; + + if (pd->rx_csum) { + u16 hw_csum = get_unaligned_le16(skb_tail_pointer(skb) + + NET_IP_ALIGN + packet_length + 4); + put_unaligned_le16(cpu_to_le16(hw_csum), &skb->csum); + skb->ip_summed = CHECKSUM_COMPLETE; + } + + skb_reserve(skb, NET_IP_ALIGN); + skb_put(skb, packet_length); + + skb->protocol = eth_type_trans(skb, dev); + + netif_receive_skb(skb); + dev->last_rx = jiffies; +} + +static int smsc9420_alloc_rx_buffer(struct smsc9420_pdata *pd, int index) +{ + struct sk_buff *skb = netdev_alloc_skb(pd->dev, PKT_BUF_SZ); + dma_addr_t mapping; + + BUG_ON(pd->rx_buffers[index].skb); + BUG_ON(pd->rx_buffers[index].mapping); + + if (unlikely(!skb)) { + smsc_warn(RX_ERR, "Failed to allocate new skb!"); + return -ENOMEM; + } + + skb->dev = pd->dev; + + mapping = pci_map_single(pd->pdev, skb_tail_pointer(skb), + PKT_BUF_SZ, PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(pd->pdev, mapping)) { + dev_kfree_skb_any(skb); + smsc_warn(RX_ERR, "pci_map_single failed!"); + return -ENOMEM; + } + + pd->rx_buffers[index].skb = skb; + pd->rx_buffers[index].mapping = mapping; + pd->rx_ring[index].buffer1 = mapping + NET_IP_ALIGN; + pd->rx_ring[index].status = RDES0_OWN_; + wmb(); + + return 0; +} + +static void smsc9420_alloc_new_rx_buffers(struct smsc9420_pdata *pd) +{ + while (pd->rx_ring_tail != pd->rx_ring_head) { + if (smsc9420_alloc_rx_buffer(pd, pd->rx_ring_tail)) + break; + + pd->rx_ring_tail = (pd->rx_ring_tail + 1) % RX_RING_SIZE; + } +} + +static int smsc9420_rx_poll(struct napi_struct *napi, int budget) +{ + struct smsc9420_pdata *pd = + container_of(napi, struct smsc9420_pdata, napi); + struct net_device *dev = pd->dev; + u32 drop_frame_cnt, dma_intr_ena, status; + int work_done; + + for (work_done = 0; work_done < budget; work_done++) { + rmb(); + status = pd->rx_ring[pd->rx_ring_head].status; + + /* stop if DMAC owns this dma descriptor */ + if (status & RDES0_OWN_) + break; + + smsc9420_rx_count_stats(dev, status); + smsc9420_rx_handoff(pd, pd->rx_ring_head, status); + pd->rx_ring_head = (pd->rx_ring_head + 1) % RX_RING_SIZE; + smsc9420_alloc_new_rx_buffers(pd); + } + + drop_frame_cnt = smsc9420_reg_read(pd, MISS_FRAME_CNTR); + dev->stats.rx_dropped += + (drop_frame_cnt & 0xFFFF) + ((drop_frame_cnt >> 17) & 0x3FF); + + /* Kick RXDMA */ + smsc9420_reg_write(pd, RX_POLL_DEMAND, 1); + smsc9420_pci_flush_write(pd); + + if (work_done < budget) { + netif_rx_complete(&pd->napi); + + /* re-enable RX DMA interrupts */ + dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA); + dma_intr_ena |= (DMAC_INTR_ENA_RX_ | DMAC_INTR_ENA_NIS_); + smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena); + smsc9420_pci_flush_write(pd); + } + return work_done; +} + +static void +smsc9420_tx_update_stats(struct net_device *dev, u32 status, u32 length) +{ + if (unlikely(status & TDES0_ERROR_SUMMARY_)) { + dev->stats.tx_errors++; + if (status & (TDES0_EXCESSIVE_DEFERRAL_ | + TDES0_EXCESSIVE_COLLISIONS_)) + dev->stats.tx_aborted_errors++; + + if (status & (TDES0_LOSS_OF_CARRIER_ | TDES0_NO_CARRIER_)) + dev->stats.tx_carrier_errors++; + } else { + dev->stats.tx_packets++; + dev->stats.tx_bytes += (length & 0x7FF); + } + + if (unlikely(status & TDES0_EXCESSIVE_COLLISIONS_)) { + dev->stats.collisions += 16; + } else { + dev->stats.collisions += + (status & TDES0_COLLISION_COUNT_MASK_) >> + TDES0_COLLISION_COUNT_SHFT_; + } + + if (unlikely(status & TDES0_HEARTBEAT_FAIL_)) + dev->stats.tx_heartbeat_errors++; +} + +/* Check for completed dma transfers, update stats and free skbs */ +static void smsc9420_complete_tx(struct net_device *dev) +{ + struct smsc9420_pdata *pd = netdev_priv(dev); + + while (pd->tx_ring_tail != pd->tx_ring_head) { + int index = pd->tx_ring_tail; + u32 status, length; + + rmb(); + status = pd->tx_ring[index].status; + length = pd->tx_ring[index].length; + + /* Check if DMA still owns this descriptor */ + if (unlikely(TDES0_OWN_ & status)) + break; + + smsc9420_tx_update_stats(dev, status, length); + + BUG_ON(!pd->tx_buffers[index].skb); + BUG_ON(!pd->tx_buffers[index].mapping); + + pci_unmap_single(pd->pdev, pd->tx_buffers[index].mapping, + pd->tx_buffers[index].skb->len, PCI_DMA_TODEVICE); + pd->tx_buffers[index].mapping = 0; + + dev_kfree_skb_any(pd->tx_buffers[index].skb); + pd->tx_buffers[index].skb = NULL; + + pd->tx_ring[index].buffer1 = 0; + wmb(); + + pd->tx_ring_tail = (pd->tx_ring_tail + 1) % TX_RING_SIZE; + } +} + +static int smsc9420_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct smsc9420_pdata *pd = netdev_priv(dev); + dma_addr_t mapping; + int index = pd->tx_ring_head; + u32 tmp_desc1; + bool about_to_take_last_desc = + (((pd->tx_ring_head + 2) % TX_RING_SIZE) == pd->tx_ring_tail); + + smsc9420_complete_tx(dev); + + rmb(); + BUG_ON(pd->tx_ring[index].status & TDES0_OWN_); + BUG_ON(pd->tx_buffers[index].skb); + BUG_ON(pd->tx_buffers[index].mapping); + + mapping = pci_map_single(pd->pdev, skb->data, + skb->len, PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(pd->pdev, mapping)) { + smsc_warn(TX_ERR, "pci_map_single failed, dropping packet"); + return NETDEV_TX_BUSY; + } + + pd->tx_buffers[index].skb = skb; + pd->tx_buffers[index].mapping = mapping; + + tmp_desc1 = (TDES1_LS_ | ((u32)skb->len & 0x7FF)); + if (unlikely(about_to_take_last_desc)) { + tmp_desc1 |= TDES1_IC_; + netif_stop_queue(pd->dev); + } + + /* check if we are at the last descriptor and need to set EOR */ + if (unlikely(index == (TX_RING_SIZE - 1))) + tmp_desc1 |= TDES1_TER_; + + pd->tx_ring[index].buffer1 = mapping; + pd->tx_ring[index].length = tmp_desc1; + wmb(); + + /* increment head */ + pd->tx_ring_head = (pd->tx_ring_head + 1) % TX_RING_SIZE; + + /* assign ownership to DMAC */ + pd->tx_ring[index].status = TDES0_OWN_; + wmb(); + + /* kick the DMA */ + smsc9420_reg_write(pd, TX_POLL_DEMAND, 1); + smsc9420_pci_flush_write(pd); + + dev->trans_start = jiffies; + + return NETDEV_TX_OK; +} + +static struct net_device_stats *smsc9420_get_stats(struct net_device *dev) +{ + struct smsc9420_pdata *pd = netdev_priv(dev); + u32 counter = smsc9420_reg_read(pd, MISS_FRAME_CNTR); + dev->stats.rx_dropped += + (counter & 0x0000FFFF) + ((counter >> 17) & 0x000003FF); + return &dev->stats; +} + +static void smsc9420_set_multicast_list(struct net_device *dev) +{ + struct smsc9420_pdata *pd = netdev_priv(dev); + u32 mac_cr = smsc9420_reg_read(pd, MAC_CR); + + if (dev->flags & IFF_PROMISC) { + smsc_dbg(HW, "Promiscuous Mode Enabled"); + mac_cr |= MAC_CR_PRMS_; + mac_cr &= (~MAC_CR_MCPAS_); + mac_cr &= (~MAC_CR_HPFILT_); + } else if (dev->flags & IFF_ALLMULTI) { + smsc_dbg(HW, "Receive all Multicast Enabled"); + mac_cr &= (~MAC_CR_PRMS_); + mac_cr |= MAC_CR_MCPAS_; + mac_cr &= (~MAC_CR_HPFILT_); + } else if (dev->mc_count > 0) { + struct dev_mc_list *mc_list = dev->mc_list; + u32 hash_lo = 0, hash_hi = 0; + + smsc_dbg(HW, "Multicast filter enabled"); + while (mc_list) { + u32 bit_num = smsc9420_hash(mc_list->dmi_addr); + u32 mask = 1 << (bit_num & 0x1F); + + if (bit_num & 0x20) + hash_hi |= mask; + else + hash_lo |= mask; + + mc_list = mc_list->next; + } + smsc9420_reg_write(pd, HASHH, hash_hi); + smsc9420_reg_write(pd, HASHL, hash_lo); + + mac_cr &= (~MAC_CR_PRMS_); + mac_cr &= (~MAC_CR_MCPAS_); + mac_cr |= MAC_CR_HPFILT_; + } else { + smsc_dbg(HW, "Receive own packets only."); + smsc9420_reg_write(pd, HASHH, 0); + smsc9420_reg_write(pd, HASHL, 0); + + mac_cr &= (~MAC_CR_PRMS_); + mac_cr &= (~MAC_CR_MCPAS_); + mac_cr &= (~MAC_CR_HPFILT_); + } + + smsc9420_reg_write(pd, MAC_CR, mac_cr); + smsc9420_pci_flush_write(pd); +} + +static void smsc9420_phy_update_flowcontrol(struct smsc9420_pdata *pd) +{ + struct phy_device *phy_dev = pd->phy_dev; + u32 flow; + + if (phy_dev->duplex == DUPLEX_FULL) { + u16 lcladv = phy_read(phy_dev, MII_ADVERTISE); + u16 rmtadv = phy_read(phy_dev, MII_LPA); + u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv); + + if (cap & FLOW_CTRL_RX) + flow = 0xFFFF0002; + else + flow = 0; + + smsc_info(LINK, "rx pause %s, tx pause %s", + (cap & FLOW_CTRL_RX ? "enabled" : "disabled"), + (cap & FLOW_CTRL_TX ? "enabled" : "disabled")); + } else { + smsc_info(LINK, "half duplex"); + flow = 0; + } + + smsc9420_reg_write(pd, FLOW, flow); +} + +/* Update link mode if anything has changed. Called periodically when the + * PHY is in polling mode, even if nothing has changed. */ +static void smsc9420_phy_adjust_link(struct net_device *dev) +{ + struct smsc9420_pdata *pd = netdev_priv(dev); + struct phy_device *phy_dev = pd->phy_dev; + int carrier; + + if (phy_dev->duplex != pd->last_duplex) { + u32 mac_cr = smsc9420_reg_read(pd, MAC_CR); + if (phy_dev->duplex) { + smsc_dbg(LINK, "full duplex mode"); + mac_cr |= MAC_CR_FDPX_; + } else { + smsc_dbg(LINK, "half duplex mode"); + mac_cr &= ~MAC_CR_FDPX_; + } + smsc9420_reg_write(pd, MAC_CR, mac_cr); + + smsc9420_phy_update_flowcontrol(pd); + pd->last_duplex = phy_dev->duplex; + } + + carrier = netif_carrier_ok(dev); + if (carrier != pd->last_carrier) { + if (carrier) + smsc_dbg(LINK, "carrier OK"); + else + smsc_dbg(LINK, "no carrier"); + pd->last_carrier = carrier; + } +} + +static int smsc9420_mii_probe(struct net_device *dev) +{ + struct smsc9420_pdata *pd = netdev_priv(dev); + struct phy_device *phydev = NULL; + + BUG_ON(pd->phy_dev); + + /* Device only supports internal PHY at address 1 */ + if (!pd->mii_bus->phy_map[1]) { + pr_err("%s: no PHY found at address 1\n", dev->name); + return -ENODEV; + } + + phydev = pd->mii_bus->phy_map[1]; + smsc_info(PROBE, "PHY addr %d, phy_id 0x%08X", phydev->addr, + phydev->phy_id); + + phydev = phy_connect(dev, phydev->dev.bus_id, + &smsc9420_phy_adjust_link, 0, PHY_INTERFACE_MODE_MII); + + if (IS_ERR(phydev)) { + pr_err("%s: Could not attach to PHY\n", dev->name); + return PTR_ERR(phydev); + } + + pr_info("%s: attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n", + dev->name, phydev->drv->name, phydev->dev.bus_id, phydev->irq); + + /* mask with MAC supported features */ + phydev->supported &= (PHY_BASIC_FEATURES | SUPPORTED_Pause | + SUPPORTED_Asym_Pause); + phydev->advertising = phydev->supported; + + pd->phy_dev = phydev; + pd->last_duplex = -1; + pd->last_carrier = -1; + + return 0; +} + +static int smsc9420_mii_init(struct net_device *dev) +{ + struct smsc9420_pdata *pd = netdev_priv(dev); + int err = -ENXIO, i; + + pd->mii_bus = mdiobus_alloc(); + if (!pd->mii_bus) { + err = -ENOMEM; + goto err_out_1; + } + pd->mii_bus->name = DRV_MDIONAME; + snprintf(pd->mii_bus->id, MII_BUS_ID_SIZE, "%x", + (pd->pdev->bus->number << 8) | pd->pdev->devfn); + pd->mii_bus->priv = pd; + pd->mii_bus->read = smsc9420_mii_read; + pd->mii_bus->write = smsc9420_mii_write; + pd->mii_bus->irq = pd->phy_irq; + for (i = 0; i < PHY_MAX_ADDR; ++i) + pd->mii_bus->irq[i] = PHY_POLL; + + /* Mask all PHYs except ID 1 (internal) */ + pd->mii_bus->phy_mask = ~(1 << 1); + + if (mdiobus_register(pd->mii_bus)) { + smsc_warn(PROBE, "Error registering mii bus"); + goto err_out_free_bus_2; + } + + if (smsc9420_mii_probe(dev) < 0) { + smsc_warn(PROBE, "Error probing mii bus"); + goto err_out_unregister_bus_3; + } + + return 0; + +err_out_unregister_bus_3: + mdiobus_unregister(pd->mii_bus); +err_out_free_bus_2: + mdiobus_free(pd->mii_bus); +err_out_1: + return err; +} + +static int smsc9420_alloc_tx_ring(struct smsc9420_pdata *pd) +{ + int i; + + BUG_ON(!pd->tx_ring); + + pd->tx_buffers = kmalloc((sizeof(struct smsc9420_ring_info) * + TX_RING_SIZE), GFP_KERNEL); + if (!pd->tx_buffers) { + smsc_warn(IFUP, "Failed to allocated tx_buffers"); + return -ENOMEM; + } + + /* Initialize the TX Ring */ + for (i = 0; i < TX_RING_SIZE; i++) { + pd->tx_buffers[i].skb = NULL; + pd->tx_buffers[i].mapping = 0; + pd->tx_ring[i].status = 0; + pd->tx_ring[i].length = 0; + pd->tx_ring[i].buffer1 = 0; + pd->tx_ring[i].buffer2 = 0; + } + pd->tx_ring[TX_RING_SIZE - 1].length = TDES1_TER_; + wmb(); + + pd->tx_ring_head = 0; + pd->tx_ring_tail = 0; + + smsc9420_reg_write(pd, TX_BASE_ADDR, pd->tx_dma_addr); + smsc9420_pci_flush_write(pd); + + return 0; +} + +static int smsc9420_alloc_rx_ring(struct smsc9420_pdata *pd) +{ + int i; + + BUG_ON(!pd->rx_ring); + + pd->rx_buffers = kmalloc((sizeof(struct smsc9420_ring_info) * + RX_RING_SIZE), GFP_KERNEL); + if (pd->rx_buffers == NULL) { + smsc_warn(IFUP, "Failed to allocated rx_buffers"); + goto out; + } + + /* initialize the rx ring */ + for (i = 0; i < RX_RING_SIZE; i++) { + pd->rx_ring[i].status = 0; + pd->rx_ring[i].length = PKT_BUF_SZ; + pd->rx_ring[i].buffer2 = 0; + pd->rx_buffers[i].skb = NULL; + pd->rx_buffers[i].mapping = 0; + } + pd->rx_ring[RX_RING_SIZE - 1].length = (PKT_BUF_SZ | RDES1_RER_); + + /* now allocate the entire ring of skbs */ + for (i = 0; i < RX_RING_SIZE; i++) { + if (smsc9420_alloc_rx_buffer(pd, i)) { + smsc_warn(IFUP, "failed to allocate rx skb %d", i); + goto out_free_rx_skbs; + } + } + + pd->rx_ring_head = 0; + pd->rx_ring_tail = 0; + + smsc9420_reg_write(pd, VLAN1, ETH_P_8021Q); + smsc_dbg(IFUP, "VLAN1 = 0x%08x", smsc9420_reg_read(pd, VLAN1)); + + if (pd->rx_csum) { + /* Enable RX COE */ + u32 coe = smsc9420_reg_read(pd, COE_CR) | RX_COE_EN; + smsc9420_reg_write(pd, COE_CR, coe); + smsc_dbg(IFUP, "COE_CR = 0x%08x", coe); + } + + smsc9420_reg_write(pd, RX_BASE_ADDR, pd->rx_dma_addr); + smsc9420_pci_flush_write(pd); + + return 0; + +out_free_rx_skbs: + smsc9420_free_rx_ring(pd); +out: + return -ENOMEM; +} + +static int smsc9420_open(struct net_device *dev) +{ + struct smsc9420_pdata *pd; + u32 bus_mode, mac_cr, dmac_control, int_cfg, dma_intr_ena, int_ctl; + unsigned long flags; + int result = 0, timeout; + + BUG_ON(!dev); + pd = netdev_priv(dev); + BUG_ON(!pd); + + if (!is_valid_ether_addr(dev->dev_addr)) { + smsc_warn(IFUP, "dev_addr is not a valid MAC address"); + result = -EADDRNOTAVAIL; + goto out_0; + } + + netif_carrier_off(dev); + + /* disable, mask and acknowlege all interrupts */ + spin_lock_irqsave(&pd->int_lock, flags); + int_cfg = smsc9420_reg_read(pd, INT_CFG) & (~INT_CFG_IRQ_EN_); + smsc9420_reg_write(pd, INT_CFG, int_cfg); + smsc9420_reg_write(pd, INT_CTL, 0); + spin_unlock_irqrestore(&pd->int_lock, flags); + smsc9420_reg_write(pd, DMAC_INTR_ENA, 0); + smsc9420_reg_write(pd, INT_STAT, 0xFFFFFFFF); + smsc9420_pci_flush_write(pd); + + if (request_irq(dev->irq, smsc9420_isr, IRQF_SHARED | IRQF_DISABLED, + DRV_NAME, pd)) { + smsc_warn(IFUP, "Unable to use IRQ = %d", dev->irq); + result = -ENODEV; + goto out_0; + } + + smsc9420_dmac_soft_reset(pd); + + /* make sure MAC_CR is sane */ + smsc9420_reg_write(pd, MAC_CR, 0); + + smsc9420_set_mac_address(dev); + + /* Configure GPIO pins to drive LEDs */ + smsc9420_reg_write(pd, GPIO_CFG, + (GPIO_CFG_LED_3_ | GPIO_CFG_LED_2_ | GPIO_CFG_LED_1_)); + + bus_mode = BUS_MODE_DMA_BURST_LENGTH_16; + +#ifdef __BIG_ENDIAN + bus_mode |= BUS_MODE_DBO_; +#endif + + smsc9420_reg_write(pd, BUS_MODE, bus_mode); + + smsc9420_pci_flush_write(pd); + + /* set bus master bridge arbitration priority for Rx and TX DMA */ + smsc9420_reg_write(pd, BUS_CFG, BUS_CFG_RXTXWEIGHT_4_1); + + smsc9420_reg_write(pd, DMAC_CONTROL, + (DMAC_CONTROL_SF_ | DMAC_CONTROL_OSF_)); + + smsc9420_pci_flush_write(pd); + + /* test the IRQ connection to the ISR */ + smsc_dbg(IFUP, "Testing ISR using IRQ %d", dev->irq); + + spin_lock_irqsave(&pd->int_lock, flags); + /* configure interrupt deassertion timer and enable interrupts */ + int_cfg = smsc9420_reg_read(pd, INT_CFG) | INT_CFG_IRQ_EN_; + int_cfg &= ~(INT_CFG_INT_DEAS_MASK); + int_cfg |= (INT_DEAS_TIME & INT_CFG_INT_DEAS_MASK); + smsc9420_reg_write(pd, INT_CFG, int_cfg); + + /* unmask software interrupt */ + int_ctl = smsc9420_reg_read(pd, INT_CTL) | INT_CTL_SW_INT_EN_; + smsc9420_reg_write(pd, INT_CTL, int_ctl); + spin_unlock_irqrestore(&pd->int_lock, flags); + smsc9420_pci_flush_write(pd); + + timeout = 1000; + pd->software_irq_signal = false; + smp_wmb(); + while (timeout--) { + if (pd->software_irq_signal) + break; + msleep(1); + } + + /* disable interrupts */ + spin_lock_irqsave(&pd->int_lock, flags); + int_cfg = smsc9420_reg_read(pd, INT_CFG) & (~INT_CFG_IRQ_EN_); + smsc9420_reg_write(pd, INT_CFG, int_cfg); + spin_unlock_irqrestore(&pd->int_lock, flags); + + if (!pd->software_irq_signal) { + smsc_warn(IFUP, "ISR failed signaling test"); + result = -ENODEV; + goto out_free_irq_1; + } + + smsc_dbg(IFUP, "ISR passed test using IRQ %d", dev->irq); + + result = smsc9420_alloc_tx_ring(pd); + if (result) { + smsc_warn(IFUP, "Failed to Initialize tx dma ring"); + result = -ENOMEM; + goto out_free_irq_1; + } + + result = smsc9420_alloc_rx_ring(pd); + if (result) { + smsc_warn(IFUP, "Failed to Initialize rx dma ring"); + result = -ENOMEM; + goto out_free_tx_ring_2; + } + + result = smsc9420_mii_init(dev); + if (result) { + smsc_warn(IFUP, "Failed to initialize Phy"); + result = -ENODEV; + goto out_free_rx_ring_3; + } + + /* Bring the PHY up */ + phy_start(pd->phy_dev); + + napi_enable(&pd->napi); + + /* start tx and rx */ + mac_cr = smsc9420_reg_read(pd, MAC_CR) | MAC_CR_TXEN_ | MAC_CR_RXEN_; + smsc9420_reg_write(pd, MAC_CR, mac_cr); + + dmac_control = smsc9420_reg_read(pd, DMAC_CONTROL); + dmac_control |= DMAC_CONTROL_ST_ | DMAC_CONTROL_SR_; + smsc9420_reg_write(pd, DMAC_CONTROL, dmac_control); + smsc9420_pci_flush_write(pd); + + dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA); + dma_intr_ena |= + (DMAC_INTR_ENA_TX_ | DMAC_INTR_ENA_RX_ | DMAC_INTR_ENA_NIS_); + smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena); + smsc9420_pci_flush_write(pd); + + netif_wake_queue(dev); + + smsc9420_reg_write(pd, RX_POLL_DEMAND, 1); + + /* enable interrupts */ + spin_lock_irqsave(&pd->int_lock, flags); + int_cfg = smsc9420_reg_read(pd, INT_CFG) | INT_CFG_IRQ_EN_; + smsc9420_reg_write(pd, INT_CFG, int_cfg); + spin_unlock_irqrestore(&pd->int_lock, flags); + + return 0; + +out_free_rx_ring_3: + smsc9420_free_rx_ring(pd); +out_free_tx_ring_2: + smsc9420_free_tx_ring(pd); +out_free_irq_1: + free_irq(dev->irq, pd); +out_0: + return result; +} + +#ifdef CONFIG_PM + +static int smsc9420_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct smsc9420_pdata *pd = netdev_priv(dev); + u32 int_cfg; + ulong flags; + + /* disable interrupts */ + spin_lock_irqsave(&pd->int_lock, flags); + int_cfg = smsc9420_reg_read(pd, INT_CFG) & (~INT_CFG_IRQ_EN_); + smsc9420_reg_write(pd, INT_CFG, int_cfg); + spin_unlock_irqrestore(&pd->int_lock, flags); + + if (netif_running(dev)) { + netif_tx_disable(dev); + smsc9420_stop_tx(pd); + smsc9420_free_tx_ring(pd); + + napi_disable(&pd->napi); + smsc9420_stop_rx(pd); + smsc9420_free_rx_ring(pd); + + free_irq(dev->irq, pd); + + netif_device_detach(dev); + } + + pci_save_state(pdev); + pci_enable_wake(pdev, pci_choose_state(pdev, state), 0); + pci_disable_device(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + return 0; +} + +static int smsc9420_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct smsc9420_pdata *pd = netdev_priv(dev); + int err; + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + + err = pci_enable_device(pdev); + if (err) + return err; + + pci_set_master(pdev); + + err = pci_enable_wake(pdev, 0, 0); + if (err) + smsc_warn(IFUP, "pci_enable_wake failed: %d", err); + + if (netif_running(dev)) { + err = smsc9420_open(dev); + netif_device_attach(dev); + } + return err; +} + +#endif /* CONFIG_PM */ + +static const struct net_device_ops smsc9420_netdev_ops = { + .ndo_open = smsc9420_open, + .ndo_stop = smsc9420_stop, + .ndo_start_xmit = smsc9420_hard_start_xmit, + .ndo_get_stats = smsc9420_get_stats, + .ndo_set_multicast_list = smsc9420_set_multicast_list, + .ndo_do_ioctl = smsc9420_do_ioctl, + .ndo_validate_addr = eth_validate_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = smsc9420_poll_controller, +#endif /* CONFIG_NET_POLL_CONTROLLER */ +}; + +static int __devinit +smsc9420_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct net_device *dev; + struct smsc9420_pdata *pd; + void __iomem *virt_addr; + int result = 0; + u32 id_rev; + + printk(KERN_INFO DRV_DESCRIPTION " version " DRV_VERSION "\n"); + + /* First do the PCI initialisation */ + result = pci_enable_device(pdev); + if (unlikely(result)) { + printk(KERN_ERR "Cannot enable smsc9420\n"); + goto out_0; + } + + pci_set_master(pdev); + + dev = alloc_etherdev(sizeof(*pd)); + if (!dev) { + printk(KERN_ERR "ether device alloc failed\n"); + goto out_disable_pci_device_1; + } + + SET_NETDEV_DEV(dev, &pdev->dev); + + if (!(pci_resource_flags(pdev, SMSC_BAR) & IORESOURCE_MEM)) { + printk(KERN_ERR "Cannot find PCI device base address\n"); + goto out_free_netdev_2; + } + + if ((pci_request_regions(pdev, DRV_NAME))) { + printk(KERN_ERR "Cannot obtain PCI resources, aborting.\n"); + goto out_free_netdev_2; + } + + if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { + printk(KERN_ERR "No usable DMA configuration, aborting.\n"); + goto out_free_regions_3; + } + + virt_addr = ioremap(pci_resource_start(pdev, SMSC_BAR), + pci_resource_len(pdev, SMSC_BAR)); + if (!virt_addr) { + printk(KERN_ERR "Cannot map device registers, aborting.\n"); + goto out_free_regions_3; + } + + /* registers are double mapped with 0 offset for LE and 0x200 for BE */ + virt_addr += LAN9420_CPSR_ENDIAN_OFFSET; + + dev->base_addr = (ulong)virt_addr; + + pd = netdev_priv(dev); + + /* pci descriptors are created in the PCI consistent area */ + pd->rx_ring = pci_alloc_consistent(pdev, + sizeof(struct smsc9420_dma_desc) * RX_RING_SIZE + + sizeof(struct smsc9420_dma_desc) * TX_RING_SIZE, + &pd->rx_dma_addr); + + if (!pd->rx_ring) + goto out_free_io_4; + + /* descriptors are aligned due to the nature of pci_alloc_consistent */ + pd->tx_ring = (struct smsc9420_dma_desc *) + (pd->rx_ring + RX_RING_SIZE); + pd->tx_dma_addr = pd->rx_dma_addr + + sizeof(struct smsc9420_dma_desc) * RX_RING_SIZE; + + pd->pdev = pdev; + pd->dev = dev; + pd->base_addr = virt_addr; + pd->msg_enable = smsc_debug; + pd->rx_csum = true; + + smsc_dbg(PROBE, "lan_base=0x%08lx", (ulong)virt_addr); + + id_rev = smsc9420_reg_read(pd, ID_REV); + switch (id_rev & 0xFFFF0000) { + case 0x94200000: + smsc_info(PROBE, "LAN9420 identified, ID_REV=0x%08X", id_rev); + break; + default: + smsc_warn(PROBE, "LAN9420 NOT identified"); + smsc_warn(PROBE, "ID_REV=0x%08X", id_rev); + goto out_free_dmadesc_5; + } + + smsc9420_dmac_soft_reset(pd); + smsc9420_eeprom_reload(pd); + smsc9420_check_mac_address(dev); + + dev->netdev_ops = &smsc9420_netdev_ops; + dev->ethtool_ops = &smsc9420_ethtool_ops; + dev->irq = pdev->irq; + + netif_napi_add(dev, &pd->napi, smsc9420_rx_poll, NAPI_WEIGHT); + + result = register_netdev(dev); + if (result) { + smsc_warn(PROBE, "error %i registering device", result); + goto out_free_dmadesc_5; + } + + pci_set_drvdata(pdev, dev); + + spin_lock_init(&pd->int_lock); + spin_lock_init(&pd->phy_lock); + + dev_info(&dev->dev, "MAC Address: %pM\n", dev->dev_addr); + + return 0; + +out_free_dmadesc_5: + pci_free_consistent(pdev, sizeof(struct smsc9420_dma_desc) * + (RX_RING_SIZE + TX_RING_SIZE), pd->rx_ring, pd->rx_dma_addr); +out_free_io_4: + iounmap(virt_addr - LAN9420_CPSR_ENDIAN_OFFSET); +out_free_regions_3: + pci_release_regions(pdev); +out_free_netdev_2: + free_netdev(dev); +out_disable_pci_device_1: + pci_disable_device(pdev); +out_0: + return -ENODEV; +} + +static void __devexit smsc9420_remove(struct pci_dev *pdev) +{ + struct net_device *dev; + struct smsc9420_pdata *pd; + + dev = pci_get_drvdata(pdev); + if (!dev) + return; + + pci_set_drvdata(pdev, NULL); + + pd = netdev_priv(dev); + unregister_netdev(dev); + + /* tx_buffers and rx_buffers are freed in stop */ + BUG_ON(pd->tx_buffers); + BUG_ON(pd->rx_buffers); + + BUG_ON(!pd->tx_ring); + BUG_ON(!pd->rx_ring); + + pci_free_consistent(pdev, sizeof(struct smsc9420_dma_desc) * + (RX_RING_SIZE + TX_RING_SIZE), pd->rx_ring, pd->rx_dma_addr); + + iounmap(pd->base_addr - LAN9420_CPSR_ENDIAN_OFFSET); + pci_release_regions(pdev); + free_netdev(dev); + pci_disable_device(pdev); +} + +static struct pci_driver smsc9420_driver = { + .name = DRV_NAME, + .id_table = smsc9420_id_table, + .probe = smsc9420_probe, + .remove = __devexit_p(smsc9420_remove), +#ifdef CONFIG_PM + .suspend = smsc9420_suspend, + .resume = smsc9420_resume, +#endif /* CONFIG_PM */ +}; + +static int __init smsc9420_init_module(void) +{ + smsc_debug = netif_msg_init(debug, SMSC_MSG_DEFAULT); + + return pci_register_driver(&smsc9420_driver); +} + +static void __exit smsc9420_exit_module(void) +{ + pci_unregister_driver(&smsc9420_driver); +} + +module_init(smsc9420_init_module); +module_exit(smsc9420_exit_module); diff --git a/drivers/net/smsc9420.h b/drivers/net/smsc9420.h new file mode 100644 index 0000000000000000000000000000000000000000..69c351f93f86cd3c531121411215ca692061c8b2 --- /dev/null +++ b/drivers/net/smsc9420.h @@ -0,0 +1,275 @@ + /*************************************************************************** + * + * Copyright (C) 2007,2008 SMSC + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + *************************************************************************** + */ + +#ifndef _SMSC9420_H +#define _SMSC9420_H + +#define TX_RING_SIZE (32) +#define RX_RING_SIZE (128) + +/* interrupt deassertion in multiples of 10us */ +#define INT_DEAS_TIME (50) + +#define NAPI_WEIGHT (64) +#define SMSC_BAR (3) + +#ifdef __BIG_ENDIAN +/* Register set is duplicated for BE at an offset of 0x200 */ +#define LAN9420_CPSR_ENDIAN_OFFSET (0x200) +#else +#define LAN9420_CPSR_ENDIAN_OFFSET (0) +#endif + +#define PCI_VENDOR_ID_9420 (0x1055) +#define PCI_DEVICE_ID_9420 (0xE420) + +#define LAN_REGISTER_EXTENT (0x400) + +#define SMSC9420_EEPROM_SIZE ((u32)11) + +#define PKT_BUF_SZ (VLAN_ETH_FRAME_LEN + NET_IP_ALIGN + 4) + +/***********************************************/ +/* DMA Controller Control and Status Registers */ +/***********************************************/ +#define BUS_MODE (0x00) +#define BUS_MODE_SWR_ (BIT(0)) +#define BUS_MODE_DMA_BURST_LENGTH_1 (BIT(8)) +#define BUS_MODE_DMA_BURST_LENGTH_2 (BIT(9)) +#define BUS_MODE_DMA_BURST_LENGTH_4 (BIT(10)) +#define BUS_MODE_DMA_BURST_LENGTH_8 (BIT(11)) +#define BUS_MODE_DMA_BURST_LENGTH_16 (BIT(12)) +#define BUS_MODE_DMA_BURST_LENGTH_32 (BIT(13)) +#define BUS_MODE_DBO_ (BIT(20)) + +#define TX_POLL_DEMAND (0x04) + +#define RX_POLL_DEMAND (0x08) + +#define RX_BASE_ADDR (0x0C) + +#define TX_BASE_ADDR (0x10) + +#define DMAC_STATUS (0x14) +#define DMAC_STS_TS_ (7 << 20) +#define DMAC_STS_RS_ (7 << 17) +#define DMAC_STS_NIS_ (BIT(16)) +#define DMAC_STS_AIS_ (BIT(15)) +#define DMAC_STS_RWT_ (BIT(9)) +#define DMAC_STS_RXPS_ (BIT(8)) +#define DMAC_STS_RXBU_ (BIT(7)) +#define DMAC_STS_RX_ (BIT(6)) +#define DMAC_STS_TXUNF_ (BIT(5)) +#define DMAC_STS_TXBU_ (BIT(2)) +#define DMAC_STS_TXPS_ (BIT(1)) +#define DMAC_STS_TX_ (BIT(0)) + +#define DMAC_CONTROL (0x18) +#define DMAC_CONTROL_TTM_ (BIT(22)) +#define DMAC_CONTROL_SF_ (BIT(21)) +#define DMAC_CONTROL_ST_ (BIT(13)) +#define DMAC_CONTROL_OSF_ (BIT(2)) +#define DMAC_CONTROL_SR_ (BIT(1)) + +#define DMAC_INTR_ENA (0x1C) +#define DMAC_INTR_ENA_NIS_ (BIT(16)) +#define DMAC_INTR_ENA_AIS_ (BIT(15)) +#define DMAC_INTR_ENA_RWT_ (BIT(9)) +#define DMAC_INTR_ENA_RXPS_ (BIT(8)) +#define DMAC_INTR_ENA_RXBU_ (BIT(7)) +#define DMAC_INTR_ENA_RX_ (BIT(6)) +#define DMAC_INTR_ENA_TXBU_ (BIT(2)) +#define DMAC_INTR_ENA_TXPS_ (BIT(1)) +#define DMAC_INTR_ENA_TX_ (BIT(0)) + +#define MISS_FRAME_CNTR (0x20) + +#define TX_BUFF_ADDR (0x50) + +#define RX_BUFF_ADDR (0x54) + +/* Transmit Descriptor Bit Defs */ +#define TDES0_OWN_ (0x80000000) +#define TDES0_ERROR_SUMMARY_ (0x00008000) +#define TDES0_LOSS_OF_CARRIER_ (0x00000800) +#define TDES0_NO_CARRIER_ (0x00000400) +#define TDES0_LATE_COLLISION_ (0x00000200) +#define TDES0_EXCESSIVE_COLLISIONS_ (0x00000100) +#define TDES0_HEARTBEAT_FAIL_ (0x00000080) +#define TDES0_COLLISION_COUNT_MASK_ (0x00000078) +#define TDES0_COLLISION_COUNT_SHFT_ (3) +#define TDES0_EXCESSIVE_DEFERRAL_ (0x00000004) +#define TDES0_DEFERRED_ (0x00000001) + +#define TDES1_IC_ 0x80000000 +#define TDES1_LS_ 0x40000000 +#define TDES1_FS_ 0x20000000 +#define TDES1_TXCSEN_ 0x08000000 +#define TDES1_TER_ (BIT(25)) +#define TDES1_TCH_ 0x01000000 + +/* Receive Descriptor 0 Bit Defs */ +#define RDES0_OWN_ (0x80000000) +#define RDES0_FRAME_LENGTH_MASK_ (0x07FF0000) +#define RDES0_FRAME_LENGTH_SHFT_ (16) +#define RDES0_ERROR_SUMMARY_ (0x00008000) +#define RDES0_DESCRIPTOR_ERROR_ (0x00004000) +#define RDES0_LENGTH_ERROR_ (0x00001000) +#define RDES0_RUNT_FRAME_ (0x00000800) +#define RDES0_MULTICAST_FRAME_ (0x00000400) +#define RDES0_FIRST_DESCRIPTOR_ (0x00000200) +#define RDES0_LAST_DESCRIPTOR_ (0x00000100) +#define RDES0_FRAME_TOO_LONG_ (0x00000080) +#define RDES0_COLLISION_SEEN_ (0x00000040) +#define RDES0_FRAME_TYPE_ (0x00000020) +#define RDES0_WATCHDOG_TIMEOUT_ (0x00000010) +#define RDES0_MII_ERROR_ (0x00000008) +#define RDES0_DRIBBLING_BIT_ (0x00000004) +#define RDES0_CRC_ERROR_ (0x00000002) + +/* Receive Descriptor 1 Bit Defs */ +#define RDES1_RER_ (0x02000000) + +/***********************************************/ +/* MAC Control and Status Registers */ +/***********************************************/ +#define MAC_CR (0x80) +#define MAC_CR_RXALL_ (0x80000000) +#define MAC_CR_DIS_RXOWN_ (0x00800000) +#define MAC_CR_LOOPBK_ (0x00200000) +#define MAC_CR_FDPX_ (0x00100000) +#define MAC_CR_MCPAS_ (0x00080000) +#define MAC_CR_PRMS_ (0x00040000) +#define MAC_CR_INVFILT_ (0x00020000) +#define MAC_CR_PASSBAD_ (0x00010000) +#define MAC_CR_HFILT_ (0x00008000) +#define MAC_CR_HPFILT_ (0x00002000) +#define MAC_CR_LCOLL_ (0x00001000) +#define MAC_CR_DIS_BCAST_ (0x00000800) +#define MAC_CR_DIS_RTRY_ (0x00000400) +#define MAC_CR_PADSTR_ (0x00000100) +#define MAC_CR_BOLMT_MSK (0x000000C0) +#define MAC_CR_MFCHK_ (0x00000020) +#define MAC_CR_TXEN_ (0x00000008) +#define MAC_CR_RXEN_ (0x00000004) + +#define ADDRH (0x84) + +#define ADDRL (0x88) + +#define HASHH (0x8C) + +#define HASHL (0x90) + +#define MII_ACCESS (0x94) +#define MII_ACCESS_MII_BUSY_ (0x00000001) +#define MII_ACCESS_MII_WRITE_ (0x00000002) +#define MII_ACCESS_MII_READ_ (0x00000000) +#define MII_ACCESS_INDX_MSK_ (0x000007C0) +#define MII_ACCESS_PHYADDR_MSK_ (0x0000F8C0) +#define MII_ACCESS_INDX_SHFT_CNT (6) +#define MII_ACCESS_PHYADDR_SHFT_CNT (11) + +#define MII_DATA (0x98) + +#define FLOW (0x9C) + +#define VLAN1 (0xA0) + +#define VLAN2 (0xA4) + +#define WUFF (0xA8) + +#define WUCSR (0xAC) + +#define COE_CR (0xB0) +#define TX_COE_EN (0x00010000) +#define RX_COE_MODE (0x00000002) +#define RX_COE_EN (0x00000001) + +/***********************************************/ +/* System Control and Status Registers */ +/***********************************************/ +#define ID_REV (0xC0) + +#define INT_CTL (0xC4) +#define INT_CTL_SW_INT_EN_ (0x00008000) +#define INT_CTL_SBERR_INT_EN_ (1 << 12) +#define INT_CTL_MBERR_INT_EN_ (1 << 13) +#define INT_CTL_GPT_INT_EN_ (0x00000008) +#define INT_CTL_PHY_INT_EN_ (0x00000004) +#define INT_CTL_WAKE_INT_EN_ (0x00000002) + +#define INT_STAT (0xC8) +#define INT_STAT_SW_INT_ (1 << 15) +#define INT_STAT_MBERR_INT_ (1 << 13) +#define INT_STAT_SBERR_INT_ (1 << 12) +#define INT_STAT_GPT_INT_ (1 << 3) +#define INT_STAT_PHY_INT_ (0x00000004) +#define INT_STAT_WAKE_INT_ (0x00000002) +#define INT_STAT_DMAC_INT_ (0x00000001) + +#define INT_CFG (0xCC) +#define INT_CFG_IRQ_INT_ (0x00080000) +#define INT_CFG_IRQ_EN_ (0x00040000) +#define INT_CFG_INT_DEAS_CLR_ (0x00000200) +#define INT_CFG_INT_DEAS_MASK (0x000000FF) + +#define GPIO_CFG (0xD0) +#define GPIO_CFG_LED_3_ (0x40000000) +#define GPIO_CFG_LED_2_ (0x20000000) +#define GPIO_CFG_LED_1_ (0x10000000) +#define GPIO_CFG_EEPR_EN_ (0x00700000) + +#define GPT_CFG (0xD4) +#define GPT_CFG_TIMER_EN_ (0x20000000) + +#define GPT_CNT (0xD8) + +#define BUS_CFG (0xDC) +#define BUS_CFG_RXTXWEIGHT_1_1 (0 << 25) +#define BUS_CFG_RXTXWEIGHT_2_1 (1 << 25) +#define BUS_CFG_RXTXWEIGHT_3_1 (2 << 25) +#define BUS_CFG_RXTXWEIGHT_4_1 (3 << 25) + +#define PMT_CTRL (0xE0) + +#define FREE_RUN (0xF4) + +#define E2P_CMD (0xF8) +#define E2P_CMD_EPC_BUSY_ (0x80000000) +#define E2P_CMD_EPC_CMD_ (0x70000000) +#define E2P_CMD_EPC_CMD_READ_ (0x00000000) +#define E2P_CMD_EPC_CMD_EWDS_ (0x10000000) +#define E2P_CMD_EPC_CMD_EWEN_ (0x20000000) +#define E2P_CMD_EPC_CMD_WRITE_ (0x30000000) +#define E2P_CMD_EPC_CMD_WRAL_ (0x40000000) +#define E2P_CMD_EPC_CMD_ERASE_ (0x50000000) +#define E2P_CMD_EPC_CMD_ERAL_ (0x60000000) +#define E2P_CMD_EPC_CMD_RELOAD_ (0x70000000) +#define E2P_CMD_EPC_TIMEOUT_ (0x00000200) +#define E2P_CMD_MAC_ADDR_LOADED_ (0x00000100) +#define E2P_CMD_EPC_ADDR_ (0x000000FF) + +#define E2P_DATA (0xFC) +#define E2P_DATA_EEPROM_DATA_ (0x000000FF) + +#endif /* _SMSC9420_H */ diff --git a/drivers/net/sonic.c b/drivers/net/sonic.c index 8069f3e32d83db988a33277073c1cd5d706b601a..211e805c122350a2707e90858321d8a8fd4a5a60 100644 --- a/drivers/net/sonic.c +++ b/drivers/net/sonic.c @@ -450,7 +450,6 @@ static void sonic_rx(struct net_device *dev) skb_trim(used_skb, pkt_len); used_skb->protocol = eth_type_trans(used_skb, dev); netif_rx(used_skb); - dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes += pkt_len; diff --git a/drivers/net/sonic.h b/drivers/net/sonic.h index 7db13e4a7ea55c70c8b31c9cd0c93dbbb6012d1f..07091dd27e5df2969592a3faa54f30fdad4a4844 100644 --- a/drivers/net/sonic.h +++ b/drivers/net/sonic.h @@ -371,7 +371,7 @@ static inline __u16 sonic_buf_get(void* base, int bitmode, static inline void sonic_cda_put(struct net_device* dev, int entry, int offset, __u16 val) { - struct sonic_local* lp = (struct sonic_local *) dev->priv; + struct sonic_local *lp = netdev_priv(dev); sonic_buf_put(lp->cda, lp->dma_bitmode, (entry * SIZEOF_SONIC_CD) + offset, val); } @@ -379,27 +379,27 @@ static inline void sonic_cda_put(struct net_device* dev, int entry, static inline __u16 sonic_cda_get(struct net_device* dev, int entry, int offset) { - struct sonic_local* lp = (struct sonic_local *) dev->priv; + struct sonic_local *lp = netdev_priv(dev); return sonic_buf_get(lp->cda, lp->dma_bitmode, (entry * SIZEOF_SONIC_CD) + offset); } static inline void sonic_set_cam_enable(struct net_device* dev, __u16 val) { - struct sonic_local* lp = (struct sonic_local *) dev->priv; + struct sonic_local *lp = netdev_priv(dev); sonic_buf_put(lp->cda, lp->dma_bitmode, SONIC_CDA_CAM_ENABLE, val); } static inline __u16 sonic_get_cam_enable(struct net_device* dev) { - struct sonic_local* lp = (struct sonic_local *) dev->priv; + struct sonic_local *lp = netdev_priv(dev); return sonic_buf_get(lp->cda, lp->dma_bitmode, SONIC_CDA_CAM_ENABLE); } static inline void sonic_tda_put(struct net_device* dev, int entry, int offset, __u16 val) { - struct sonic_local* lp = (struct sonic_local *) dev->priv; + struct sonic_local *lp = netdev_priv(dev); sonic_buf_put(lp->tda, lp->dma_bitmode, (entry * SIZEOF_SONIC_TD) + offset, val); } @@ -407,7 +407,7 @@ static inline void sonic_tda_put(struct net_device* dev, int entry, static inline __u16 sonic_tda_get(struct net_device* dev, int entry, int offset) { - struct sonic_local* lp = (struct sonic_local *) dev->priv; + struct sonic_local *lp = netdev_priv(dev); return sonic_buf_get(lp->tda, lp->dma_bitmode, (entry * SIZEOF_SONIC_TD) + offset); } @@ -415,7 +415,7 @@ static inline __u16 sonic_tda_get(struct net_device* dev, int entry, static inline void sonic_rda_put(struct net_device* dev, int entry, int offset, __u16 val) { - struct sonic_local* lp = (struct sonic_local *) dev->priv; + struct sonic_local *lp = netdev_priv(dev); sonic_buf_put(lp->rda, lp->dma_bitmode, (entry * SIZEOF_SONIC_RD) + offset, val); } @@ -423,7 +423,7 @@ static inline void sonic_rda_put(struct net_device* dev, int entry, static inline __u16 sonic_rda_get(struct net_device* dev, int entry, int offset) { - struct sonic_local* lp = (struct sonic_local *) dev->priv; + struct sonic_local *lp = netdev_priv(dev); return sonic_buf_get(lp->rda, lp->dma_bitmode, (entry * SIZEOF_SONIC_RD) + offset); } @@ -431,7 +431,7 @@ static inline __u16 sonic_rda_get(struct net_device* dev, int entry, static inline void sonic_rra_put(struct net_device* dev, int entry, int offset, __u16 val) { - struct sonic_local* lp = (struct sonic_local *) dev->priv; + struct sonic_local *lp = netdev_priv(dev); sonic_buf_put(lp->rra, lp->dma_bitmode, (entry * SIZEOF_SONIC_RR) + offset, val); } @@ -439,7 +439,7 @@ static inline void sonic_rra_put(struct net_device* dev, int entry, static inline __u16 sonic_rra_get(struct net_device* dev, int entry, int offset) { - struct sonic_local* lp = (struct sonic_local *) dev->priv; + struct sonic_local *lp = netdev_priv(dev); return sonic_buf_get(lp->rra, lp->dma_bitmode, (entry * SIZEOF_SONIC_RR) + offset); } diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 07599b492359f16bc348f4271eb32793a3a362e0..c5c123d3af57f00b5930d7cf318f1a3444f5dcd5 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -789,7 +789,7 @@ spider_net_set_low_watermark(struct spider_net_card *card) * spider_net_release_tx_chain releases the tx descriptors that spider has * finished with (if non-brutal) or simply release tx descriptors (if brutal). * If some other context is calling this function, we return 1 so that we're - * scheduled again (if we were scheduled) and will not loose initiative. + * scheduled again (if we were scheduled) and will not lose initiative. */ static int spider_net_release_tx_chain(struct spider_net_card *card, int brutal) @@ -1302,7 +1302,7 @@ static int spider_net_poll(struct napi_struct *napi, int budget) /* if all packets are in the stack, enable interrupts and return 0 */ /* if not, return 1 */ if (packets_done < budget) { - netif_rx_complete(netdev, napi); + netif_rx_complete(napi); spider_net_rx_irq_on(card); card->ignore_rx_ramfull = 0; } @@ -1529,8 +1529,7 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg, spider_net_refill_rx_chain(card); spider_net_enable_rxdmac(card); card->num_rx_ints ++; - netif_rx_schedule(card->netdev, - &card->napi); + netif_rx_schedule(&card->napi); } show_error = 0; break; @@ -1550,8 +1549,7 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg, spider_net_refill_rx_chain(card); spider_net_enable_rxdmac(card); card->num_rx_ints ++; - netif_rx_schedule(card->netdev, - &card->napi); + netif_rx_schedule(&card->napi); show_error = 0; break; @@ -1565,8 +1563,7 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg, spider_net_refill_rx_chain(card); spider_net_enable_rxdmac(card); card->num_rx_ints ++; - netif_rx_schedule(card->netdev, - &card->napi); + netif_rx_schedule(&card->napi); show_error = 0; break; @@ -1660,11 +1657,11 @@ spider_net_interrupt(int irq, void *ptr) if (status_reg & SPIDER_NET_RXINT ) { spider_net_rx_irq_off(card); - netif_rx_schedule(netdev, &card->napi); + netif_rx_schedule(&card->napi); card->num_rx_ints ++; } if (status_reg & SPIDER_NET_TXINT) - netif_rx_schedule(netdev, &card->napi); + netif_rx_schedule(&card->napi); if (status_reg & SPIDER_NET_LINKINT) spider_net_link_reset(netdev); diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c index 85691d2a0be26a454e65550d867d4e59a0713119..5bae728c3820a01b00ace7672d1422fecc9d8aee 100644 --- a/drivers/net/spider_net_ethtool.c +++ b/drivers/net/spider_net_ethtool.c @@ -118,7 +118,7 @@ spider_net_ethtool_nway_reset(struct net_device *netdev) static u32 spider_net_ethtool_get_rx_csum(struct net_device *netdev) { - struct spider_net_card *card = netdev->priv; + struct spider_net_card *card = netdev_priv(netdev); return card->options.rx_csum; } @@ -126,7 +126,7 @@ spider_net_ethtool_get_rx_csum(struct net_device *netdev) static int spider_net_ethtool_set_rx_csum(struct net_device *netdev, u32 n) { - struct spider_net_card *card = netdev->priv; + struct spider_net_card *card = netdev_priv(netdev); card->options.rx_csum = n; return 0; @@ -137,7 +137,7 @@ static void spider_net_ethtool_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ering) { - struct spider_net_card *card = netdev->priv; + struct spider_net_card *card = netdev_priv(netdev); ering->tx_max_pending = SPIDER_NET_TX_DESCRIPTORS_MAX; ering->tx_pending = card->tx_chain.num_desc; @@ -158,7 +158,7 @@ static int spider_net_get_sset_count(struct net_device *netdev, int sset) static void spider_net_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, u64 *data) { - struct spider_net_card *card = netdev->priv; + struct spider_net_card *card = netdev_priv(netdev); data[0] = netdev->stats.tx_packets; data[1] = netdev->stats.tx_bytes; diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index 5a40f2d78beb1a9114478ac9e0385556c29d30bf..f54ac2389da29dd444395853582c5153a55309e9 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -653,7 +653,6 @@ static int __devinit starfire_init_one(struct pci_dev *pdev, void __iomem *base; int drv_flags, io_size; int boguscnt; - DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -823,9 +822,9 @@ static int __devinit starfire_init_one(struct pci_dev *pdev, if (register_netdev(dev)) goto err_out_cleardev; - printk(KERN_INFO "%s: %s at %p, %s, IRQ %d.\n", + printk(KERN_INFO "%s: %s at %p, %pM, IRQ %d.\n", dev->name, netdrv_tbl[chip_idx].name, base, - print_mac(mac, dev->dev_addr), irq); + dev->dev_addr, irq); if (drv_flags & CanHaveMII) { int phy, phy_idx = 0; @@ -881,9 +880,9 @@ static int mdio_read(struct net_device *dev, int phy_id, int location) void __iomem *mdio_addr = np->base + MIICtrl + (phy_id<<7) + (location<<2); int result, boguscnt=1000; /* ??? Should we add a busy-wait here? */ - do + do { result = readl(mdio_addr); - while ((result & 0xC0000000) != 0x80000000 && --boguscnt > 0); + } while ((result & 0xC0000000) != 0x80000000 && --boguscnt > 0); if (boguscnt == 0) return 0; if ((result & 0xffff) == 0xffff) @@ -1291,8 +1290,8 @@ static irqreturn_t intr_handler(int irq, void *dev_instance) if (intr_status & (IntrRxDone | IntrRxEmpty)) { u32 enable; - if (likely(netif_rx_schedule_prep(dev, &np->napi))) { - __netif_rx_schedule(dev, &np->napi); + if (likely(netif_rx_schedule_prep(&np->napi))) { + __netif_rx_schedule(&np->napi); enable = readl(ioaddr + IntrEnable); enable &= ~(IntrRxDone | IntrRxEmpty); writel(enable, ioaddr + IntrEnable); @@ -1452,12 +1451,8 @@ static int __netdev_rx(struct net_device *dev, int *quota) #ifndef final_version /* Remove after testing. */ /* You will want this info for the initial debug. */ if (debug > 5) { - printk(KERN_DEBUG " Rx data " MAC_FMT " " MAC_FMT - " %2.2x%2.2x.\n", - skb->data[0], skb->data[1], skb->data[2], - skb->data[3], skb->data[4], skb->data[5], - skb->data[6], skb->data[7], skb->data[8], - skb->data[9], skb->data[10], skb->data[11], + printk(KERN_DEBUG " Rx data %pM %pM %2.2x%2.2x.\n", + skb->data, skb->data + 6, skb->data[12], skb->data[13]); } #endif @@ -1501,7 +1496,6 @@ static int __netdev_rx(struct net_device *dev, int *quota) } else #endif /* VLAN_SUPPORT */ netif_receive_skb(skb); - dev->last_rx = jiffies; np->stats.rx_packets++; next_rx: @@ -1541,7 +1535,7 @@ static int netdev_poll(struct napi_struct *napi, int budget) intr_status = readl(ioaddr + IntrStatus); } while (intr_status & (IntrRxDone | IntrRxEmpty)); - netif_rx_complete(dev, napi); + netif_rx_complete(napi); intr_status = readl(ioaddr + IntrEnable); intr_status |= IntrRxDone | IntrRxEmpty; writel(intr_status, ioaddr + IntrEnable); diff --git a/drivers/net/stnic.c b/drivers/net/stnic.c index 2ed0bd5968157620a2179757875fe25cafaa3d6a..87a6b8eabc672355fd9ee12ae6aa738c8e8d3c0c 100644 --- a/drivers/net/stnic.c +++ b/drivers/net/stnic.c @@ -60,8 +60,6 @@ static byte stnic_eadr[6] = static struct net_device *stnic_dev; -static int stnic_open (struct net_device *dev); -static int stnic_close (struct net_device *dev); static void stnic_reset (struct net_device *dev); static void stnic_get_hdr (struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page); @@ -122,11 +120,7 @@ static int __init stnic_probe(void) /* Set the base address to point to the NIC, not the "real" base! */ dev->base_addr = 0x1000; dev->irq = IRQ_STNIC; - dev->open = &stnic_open; - dev->stop = &stnic_close; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = ei_poll; -#endif + dev->netdev_ops = &ei_netdev_ops; /* Snarf the interrupt now. There's no point in waiting since we cannot share and the board will usually be enabled. */ @@ -168,23 +162,6 @@ static int __init stnic_probe(void) return 0; } -static int -stnic_open (struct net_device *dev) -{ -#if 0 - printk (KERN_DEBUG "stnic open\n"); -#endif - ei_open (dev); - return 0; -} - -static int -stnic_close (struct net_device *dev) -{ - ei_close (dev); - return 0; -} - static void stnic_reset (struct net_device *dev) { diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c index e531302d95f5078680e1065bda74550346574055..e0d84772771ca6bf61a32f9019104b500680114b 100644 --- a/drivers/net/sun3_82586.c +++ b/drivers/net/sun3_82586.c @@ -209,7 +209,7 @@ static int sun3_82586_open(struct net_device *dev) static int check586(struct net_device *dev,char *where,unsigned size) { struct priv pb; - struct priv *p = /* (struct priv *) dev->priv*/ &pb; + struct priv *p = &pb; char *iscp_addr; int i; @@ -247,7 +247,7 @@ static int check586(struct net_device *dev,char *where,unsigned size) */ static void alloc586(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); sun3_reset586(); DELAY(1); @@ -363,17 +363,21 @@ static int __init sun3_82586_probe1(struct net_device *dev,int ioaddr) goto out; } - ((struct priv *) (dev->priv))->memtop = (char *)dvma_btov(dev->mem_start); - ((struct priv *) (dev->priv))->base = (unsigned long) dvma_btov(0); + ((struct priv *)netdev_priv(dev))->memtop = + (char *)dvma_btov(dev->mem_start); + ((struct priv *)netdev_priv(dev))->base = (unsigned long) dvma_btov(0); alloc586(dev); /* set number of receive-buffs according to memsize */ if(size == 0x2000) - ((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_8; + ((struct priv *)netdev_priv(dev))->num_recv_buffs = + NUM_RECV_BUFFS_8; else if(size == 0x4000) - ((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_16; + ((struct priv *)netdev_priv(dev))->num_recv_buffs = + NUM_RECV_BUFFS_16; else - ((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_32; + ((struct priv *)netdev_priv(dev))->num_recv_buffs = + NUM_RECV_BUFFS_32; printk("Memaddr: 0x%lx, Memsize: %d, IRQ %d\n",dev->mem_start,size, dev->irq); @@ -397,7 +401,7 @@ static int init586(struct net_device *dev) { void *ptr; int i,result=0; - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); volatile struct configure_cmd_struct *cfg_cmd; volatile struct iasetup_cmd_struct *ias_cmd; volatile struct tdr_cmd_struct *tdr_cmd; @@ -631,7 +635,7 @@ static void *alloc_rfa(struct net_device *dev,void *ptr) volatile struct rfd_struct *rfd = (struct rfd_struct *)ptr; volatile struct rbd_struct *rbd; int i; - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); memset((char *) rfd,0,sizeof(struct rfd_struct)*(p->num_recv_buffs+rfdadd)); p->rfd_first = rfd; @@ -683,7 +687,7 @@ static irqreturn_t sun3_82586_interrupt(int irq,void *dev_id) printk ("sun3_82586-interrupt: irq %d for unknown device.\n",irq); return IRQ_NONE; } - p = (struct priv *) dev->priv; + p = netdev_priv(dev); if(debuglevel > 1) printk("I"); @@ -753,7 +757,7 @@ static void sun3_82586_rcv_int(struct net_device *dev) unsigned short totlen; struct sk_buff *skb; struct rbd_struct *rbd; - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); if(debuglevel > 0) printk("R"); @@ -871,7 +875,7 @@ static void sun3_82586_rcv_int(struct net_device *dev) static void sun3_82586_rnr_int(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); p->stats.rx_errors++; @@ -895,7 +899,7 @@ static void sun3_82586_rnr_int(struct net_device *dev) static void sun3_82586_xmt_int(struct net_device *dev) { int status; - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); if(debuglevel > 0) printk("X"); @@ -945,7 +949,7 @@ static void sun3_82586_xmt_int(struct net_device *dev) static void startrecv586(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); WAIT_4_SCB_CMD(); WAIT_4_SCB_CMD_RUC(); @@ -957,7 +961,7 @@ static void startrecv586(struct net_device *dev) static void sun3_82586_timeout(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); #ifndef NO_NOPCOMMANDS if(p->scb->cus & CU_ACTIVE) /* COMMAND-UNIT active? */ { @@ -999,7 +1003,7 @@ static int sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev) #ifndef NO_NOPCOMMANDS int next_nop; #endif - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); if(skb->len > XMIT_BUFF_SIZE) { @@ -1108,7 +1112,7 @@ static int sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev) static struct net_device_stats *sun3_82586_get_stats(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); unsigned short crc,aln,rsc,ovrn; crc = swab16(p->scb->crc_errs); /* get error-statistic from the ni82586 */ @@ -1171,7 +1175,7 @@ void cleanup_module(void) */ void sun3_82586_dump(struct net_device *dev,void *ptr) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); struct dump_cmd_struct *dump_cmd = (struct dump_cmd_struct *) ptr; int i; diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c index 359452a06c67d7160e444ee3ab893afec2747f6d..4bb8f72c65cceb3f4e20d20229c299ebca33abf0 100644 --- a/drivers/net/sun3lance.c +++ b/drivers/net/sun3lance.c @@ -303,7 +303,6 @@ static int __init lance_probe( struct net_device *dev) static int did_version; volatile unsigned short *ioaddr_probe; unsigned short tmp1, tmp2; - DECLARE_MAC_BUF(mac); #ifdef CONFIG_SUN3 ioaddr = (unsigned long)ioremap(LANCE_OBIO, PAGE_SIZE); @@ -379,7 +378,7 @@ static int __init lance_probe( struct net_device *dev) MEM->init.hwaddr[4] = dev->dev_addr[5]; MEM->init.hwaddr[5] = dev->dev_addr[4]; - printk("%s\n", print_mac(mac, dev->dev_addr)); + printk("%pM\n", dev->dev_addr); MEM->init.mode = 0x0000; MEM->init.filter[0] = 0x00000000; @@ -824,12 +823,10 @@ static int lance_rx( struct net_device *dev ) #if 0 if (lance_debug >= 3) { u_char *data = PKTBUF_ADDR(head); - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2) printk("%s: RX pkt %d type 0x%04x" - " from %s to %s", + " from %pM to %pM", dev->name, lp->new_tx, ((u_short *)data)[6], - print_mac(mac, &data[6]), print_mac(mac2, data)); + &data[6], data); printk(" data %02x %02x %02x %02x %02x %02x %02x %02x " "len %d at %08x\n", @@ -852,7 +849,6 @@ static int lance_rx( struct net_device *dev ) skb->protocol = eth_type_trans( skb, dev ); netif_rx( skb ); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c index 018d0fca9422bc2760c835b6f9a9de46670da7e1..7f69c7f176c457f7d6d46f58fda37ab7363c4b3a 100644 --- a/drivers/net/sunbmac.c +++ b/drivers/net/sunbmac.c @@ -878,7 +878,6 @@ static void bigmac_rx(struct bigmac *bp) /* No checksums done by the BigMAC ;-( */ skb->protocol = eth_type_trans(skb, bp->dev); netif_rx(skb); - bp->dev->last_rx = jiffies; bp->enet_stats.rx_packets++; bp->enet_stats.rx_bytes += len; next: @@ -917,7 +916,7 @@ static irqreturn_t bigmac_interrupt(int irq, void *dev_id) static int bigmac_open(struct net_device *dev) { - struct bigmac *bp = (struct bigmac *) dev->priv; + struct bigmac *bp = netdev_priv(dev); int ret; ret = request_irq(dev->irq, &bigmac_interrupt, IRQF_SHARED, dev->name, bp); @@ -934,7 +933,7 @@ static int bigmac_open(struct net_device *dev) static int bigmac_close(struct net_device *dev) { - struct bigmac *bp = (struct bigmac *) dev->priv; + struct bigmac *bp = netdev_priv(dev); del_timer(&bp->bigmac_timer); bp->timer_state = asleep; @@ -948,7 +947,7 @@ static int bigmac_close(struct net_device *dev) static void bigmac_tx_timeout(struct net_device *dev) { - struct bigmac *bp = (struct bigmac *) dev->priv; + struct bigmac *bp = netdev_priv(dev); bigmac_init_hw(bp, 0); netif_wake_queue(dev); @@ -957,7 +956,7 @@ static void bigmac_tx_timeout(struct net_device *dev) /* Put a packet on the wire. */ static int bigmac_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct bigmac *bp = (struct bigmac *) dev->priv; + struct bigmac *bp = netdev_priv(dev); int len, entry; u32 mapping; @@ -990,7 +989,7 @@ static int bigmac_start_xmit(struct sk_buff *skb, struct net_device *dev) static struct net_device_stats *bigmac_get_stats(struct net_device *dev) { - struct bigmac *bp = (struct bigmac *) dev->priv; + struct bigmac *bp = netdev_priv(dev); bigmac_get_counters(bp, bp->bregs); return &bp->enet_stats; @@ -998,7 +997,7 @@ static struct net_device_stats *bigmac_get_stats(struct net_device *dev) static void bigmac_set_multicast(struct net_device *dev) { - struct bigmac *bp = (struct bigmac *) dev->priv; + struct bigmac *bp = netdev_priv(dev); void __iomem *bregs = bp->bregs; struct dev_mc_list *dmi = dev->mc_list; char *addrs; @@ -1061,7 +1060,7 @@ static void bigmac_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *i static u32 bigmac_get_link(struct net_device *dev) { - struct bigmac *bp = dev->priv; + struct bigmac *bp = netdev_priv(dev); spin_lock_irq(&bp->lock); bp->sw_bmsr = bigmac_tcvr_read(bp, bp->tregs, BIGMAC_BMSR); @@ -1081,7 +1080,6 @@ static int __devinit bigmac_ether_init(struct of_device *op, static int version_printed; struct net_device *dev; u8 bsizes, bsizes_more; - DECLARE_MAC_BUF(mac); struct bigmac *bp; int i; @@ -1212,8 +1210,8 @@ static int __devinit bigmac_ether_init(struct of_device *op, dev_set_drvdata(&bp->bigmac_op->dev, bp); - printk(KERN_INFO "%s: BigMAC 100baseT Ethernet %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: BigMAC 100baseT Ethernet %pM\n", + dev->name, dev->dev_addr); return 0; @@ -1235,7 +1233,7 @@ static int __devinit bigmac_ether_init(struct of_device *op, bp->bmac_block, bp->bblock_dvma); - /* This also frees the co-located 'dev->priv' */ + /* This also frees the co-located private data */ free_netdev(dev); return -ENODEV; } diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index f860ea150395871357639e4f457834fbf67408c1..698893b92003d0f5022a86ba43f12f3a0fa064ce 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -468,7 +468,6 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, int bar = 1; #endif int phy, phy_end, phy_idx = 0; - DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -547,9 +546,9 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, if (i) goto err_out_unmap_rx; - printk(KERN_INFO "%s: %s at %p, %s, IRQ %d.\n", + printk(KERN_INFO "%s: %s at %p, %pM, IRQ %d.\n", dev->name, pci_id_tbl[chip_idx].name, ioaddr, - print_mac(mac, dev->dev_addr), irq); + dev->dev_addr, irq); np->phys[0] = 1; /* Default setting */ np->mii_preamble_required++; @@ -1351,7 +1350,6 @@ static void rx_poll(unsigned long data) skb->protocol = eth_type_trans(skb, dev); /* Note: checksum -> skb->ip_summed = CHECKSUM_UNNECESSARY; */ netif_rx(skb); - dev->last_rx = jiffies; } entry = (entry + 1) % RX_RING_SIZE; received++; diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index fed7eba65ead6268e292eddc66c73905d8e263c7..8a7460412482d5165f24f74c3a13a1c7d4df333a 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -164,7 +164,7 @@ static u16 __phy_read(struct gem *gp, int phy_addr, int reg) static inline int _phy_read(struct net_device *dev, int mii_id, int reg) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); return __phy_read(gp, mii_id, reg); } @@ -197,7 +197,7 @@ static void __phy_write(struct gem *gp, int phy_addr, int reg, u16 val) static inline void _phy_write(struct net_device *dev, int mii_id, int reg, int val) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); __phy_write(gp, mii_id, reg, val & 0xffff); } @@ -863,7 +863,6 @@ static int gem_rx(struct gem *gp, int work_to_do) gp->net_stats.rx_packets++; gp->net_stats.rx_bytes += len; - gp->dev->last_rx = jiffies; next: entry = NEXT_RX(entry); @@ -922,7 +921,7 @@ static int gem_poll(struct napi_struct *napi, int budget) gp->status = readl(gp->regs + GREG_STAT); } while (gp->status & GREG_STAT_NAPI); - __netif_rx_complete(dev, napi); + __netif_rx_complete(napi); gem_enable_ints(gp); spin_unlock_irqrestore(&gp->lock, flags); @@ -933,7 +932,7 @@ static int gem_poll(struct napi_struct *napi, int budget) static irqreturn_t gem_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); unsigned long flags; /* Swallow interrupts when shutting the chip down, though @@ -945,7 +944,7 @@ static irqreturn_t gem_interrupt(int irq, void *dev_id) spin_lock_irqsave(&gp->lock, flags); - if (netif_rx_schedule_prep(dev, &gp->napi)) { + if (netif_rx_schedule_prep(&gp->napi)) { u32 gem_status = readl(gp->regs + GREG_STAT); if (gem_status == 0) { @@ -955,7 +954,7 @@ static irqreturn_t gem_interrupt(int irq, void *dev_id) } gp->status = gem_status; gem_disable_ints(gp); - __netif_rx_schedule(dev, &gp->napi); + __netif_rx_schedule(&gp->napi); } spin_unlock_irqrestore(&gp->lock, flags); @@ -979,7 +978,7 @@ static void gem_poll_controller(struct net_device *dev) static void gem_tx_timeout(struct net_device *dev) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name); if (!gp->running) { @@ -1018,7 +1017,7 @@ static __inline__ int gem_intme(int entry) static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); int entry; u64 ctrl; unsigned long flags; @@ -2208,7 +2207,7 @@ static void gem_stop_phy(struct gem *gp, int wol) static int gem_do_start(struct net_device *dev) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); unsigned long flags; spin_lock_irqsave(&gp->lock, flags); @@ -2255,7 +2254,7 @@ static int gem_do_start(struct net_device *dev) static void gem_do_stop(struct net_device *dev, int wol) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); unsigned long flags; spin_lock_irqsave(&gp->lock, flags); @@ -2330,7 +2329,7 @@ static void gem_reset_task(struct work_struct *work) static int gem_open(struct net_device *dev) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); int rc = 0; mutex_lock(&gp->pm_mutex); @@ -2349,7 +2348,7 @@ static int gem_open(struct net_device *dev) static int gem_close(struct net_device *dev) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); mutex_lock(&gp->pm_mutex); @@ -2368,7 +2367,7 @@ static int gem_close(struct net_device *dev) static int gem_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *dev = pci_get_drvdata(pdev); - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); unsigned long flags; mutex_lock(&gp->pm_mutex); @@ -2432,7 +2431,7 @@ static int gem_suspend(struct pci_dev *pdev, pm_message_t state) static int gem_resume(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); unsigned long flags; printk(KERN_INFO "%s: resuming\n", dev->name); @@ -2506,7 +2505,7 @@ static int gem_resume(struct pci_dev *pdev) static struct net_device_stats *gem_get_stats(struct net_device *dev) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); struct net_device_stats *stats = &gp->net_stats; spin_lock_irq(&gp->lock); @@ -2542,7 +2541,7 @@ static struct net_device_stats *gem_get_stats(struct net_device *dev) static int gem_set_mac_address(struct net_device *dev, void *addr) { struct sockaddr *macaddr = (struct sockaddr *) addr; - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); unsigned char *e = &dev->dev_addr[0]; if (!is_valid_ether_addr(macaddr->sa_data)) @@ -2570,7 +2569,7 @@ static int gem_set_mac_address(struct net_device *dev, void *addr) static void gem_set_multicast(struct net_device *dev) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); u32 rxcfg, rxcfg_new; int limit = 10000; @@ -2619,7 +2618,7 @@ static void gem_set_multicast(struct net_device *dev) static int gem_change_mtu(struct net_device *dev, int new_mtu) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); if (new_mtu < GEM_MIN_MTU || new_mtu > GEM_MAX_MTU) return -EINVAL; @@ -2650,7 +2649,7 @@ static int gem_change_mtu(struct net_device *dev, int new_mtu) static void gem_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); strcpy(info->driver, DRV_NAME); strcpy(info->version, DRV_VERSION); @@ -2659,7 +2658,7 @@ static void gem_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info static int gem_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); if (gp->phy_type == phy_mii_mdio0 || gp->phy_type == phy_mii_mdio1) { @@ -2720,7 +2719,7 @@ static int gem_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) static int gem_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); /* Verify the settings we care about. */ if (cmd->autoneg != AUTONEG_ENABLE && @@ -2751,7 +2750,7 @@ static int gem_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) static int gem_nway_reset(struct net_device *dev) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); if (!gp->want_autoneg) return -EINVAL; @@ -2768,13 +2767,13 @@ static int gem_nway_reset(struct net_device *dev) static u32 gem_get_msglevel(struct net_device *dev) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); return gp->msg_enable; } static void gem_set_msglevel(struct net_device *dev, u32 value) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); gp->msg_enable = value; } @@ -2786,7 +2785,7 @@ static void gem_set_msglevel(struct net_device *dev, u32 value) static void gem_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); /* Add more when I understand how to program the chip */ if (gp->has_wol) { @@ -2800,7 +2799,7 @@ static void gem_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) static int gem_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); if (!gp->has_wol) return -EOPNOTSUPP; @@ -2822,7 +2821,7 @@ static const struct ethtool_ops gem_ethtool_ops = { static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); struct mii_ioctl_data *data = if_mii(ifr); int rc = -EOPNOTSUPP; unsigned long flags; @@ -2954,7 +2953,7 @@ static void gem_remove_one(struct pci_dev *pdev) struct net_device *dev = pci_get_drvdata(pdev); if (dev) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); unregister_netdev(dev); @@ -2998,7 +2997,6 @@ static int __devinit gem_init_one(struct pci_dev *pdev, struct net_device *dev; struct gem *gp; int err, pci_using_dac; - DECLARE_MAC_BUF(mac); if (gem_version_printed++ == 0) printk(KERN_INFO "%s", version); @@ -3058,7 +3056,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev, } SET_NETDEV_DEV(dev, &pdev->dev); - gp = dev->priv; + gp = netdev_priv(dev); err = pci_request_regions(pdev, DRV_NAME); if (err) { @@ -3182,9 +3180,8 @@ static int __devinit gem_init_one(struct pci_dev *pdev, goto err_out_free_consistent; } - printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet " - "%s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet %pM\n", + dev->name, dev->dev_addr); if (gp->phy_type == phy_mii_mdio0 || gp->phy_type == phy_mii_mdio1) diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index f1ebeb5f65b2f56d6ba3a6ee9da9eb579cfb16d1..b22d3355fb45f7157328824390315fcf9013d372 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -2072,7 +2072,6 @@ static void happy_meal_rx(struct happy_meal *hp, struct net_device *dev) skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; hp->net_stats.rx_packets++; hp->net_stats.rx_bytes += len; next: @@ -2131,7 +2130,7 @@ static irqreturn_t quattro_sbus_interrupt(int irq, void *cookie) for (i = 0; i < 4; i++) { struct net_device *dev = qp->happy_meals[i]; - struct happy_meal *hp = dev->priv; + struct happy_meal *hp = netdev_priv(dev); u32 happy_status = hme_read32(hp, hp->gregs + GREG_STAT); HMD(("quattro_interrupt: status=%08x ", happy_status)); @@ -2176,7 +2175,7 @@ static irqreturn_t quattro_sbus_interrupt(int irq, void *cookie) static int happy_meal_open(struct net_device *dev) { - struct happy_meal *hp = dev->priv; + struct happy_meal *hp = netdev_priv(dev); int res; HMD(("happy_meal_open: ")); @@ -2208,7 +2207,7 @@ static int happy_meal_open(struct net_device *dev) static int happy_meal_close(struct net_device *dev) { - struct happy_meal *hp = dev->priv; + struct happy_meal *hp = netdev_priv(dev); spin_lock_irq(&hp->happy_lock); happy_meal_stop(hp, hp->gregs); @@ -2237,7 +2236,7 @@ static int happy_meal_close(struct net_device *dev) static void happy_meal_tx_timeout(struct net_device *dev) { - struct happy_meal *hp = dev->priv; + struct happy_meal *hp = netdev_priv(dev); printk (KERN_ERR "%s: transmit timed out, resetting\n", dev->name); tx_dump_log(); @@ -2255,7 +2254,7 @@ static void happy_meal_tx_timeout(struct net_device *dev) static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct happy_meal *hp = dev->priv; + struct happy_meal *hp = netdev_priv(dev); int entry; u32 tx_flags; @@ -2344,7 +2343,7 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev) static struct net_device_stats *happy_meal_get_stats(struct net_device *dev) { - struct happy_meal *hp = dev->priv; + struct happy_meal *hp = netdev_priv(dev); spin_lock_irq(&hp->happy_lock); happy_meal_get_counters(hp, hp->bigmacregs); @@ -2355,7 +2354,7 @@ static struct net_device_stats *happy_meal_get_stats(struct net_device *dev) static void happy_meal_set_multicast(struct net_device *dev) { - struct happy_meal *hp = dev->priv; + struct happy_meal *hp = netdev_priv(dev); void __iomem *bregs = hp->bigmacregs; struct dev_mc_list *dmi = dev->mc_list; char *addrs; @@ -2401,7 +2400,7 @@ static void happy_meal_set_multicast(struct net_device *dev) /* Ethtool support... */ static int hme_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct happy_meal *hp = dev->priv; + struct happy_meal *hp = netdev_priv(dev); cmd->supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | @@ -2446,7 +2445,7 @@ static int hme_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) static int hme_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct happy_meal *hp = dev->priv; + struct happy_meal *hp = netdev_priv(dev); /* Verify the settings we care about. */ if (cmd->autoneg != AUTONEG_ENABLE && @@ -2470,7 +2469,7 @@ static int hme_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) static void hme_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct happy_meal *hp = dev->priv; + struct happy_meal *hp = netdev_priv(dev); strcpy(info->driver, "sunhme"); strcpy(info->version, "2.02"); @@ -2492,7 +2491,7 @@ static void hme_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info static u32 hme_get_link(struct net_device *dev) { - struct happy_meal *hp = dev->priv; + struct happy_meal *hp = netdev_priv(dev); spin_lock_irq(&hp->happy_lock); hp->sw_bmcr = happy_meal_tcvr_read(hp, hp->tcvregs, MII_BMCR); @@ -2617,7 +2616,6 @@ static int __devinit happy_meal_sbus_probe_one(struct of_device *op, int is_qfe) struct net_device *dev; int i, qfe_slot = -1; int err = -ENODEV; - DECLARE_MAC_BUF(mac); if (is_qfe) { qp = quattro_sbus_find(op); @@ -2797,7 +2795,7 @@ static int __devinit happy_meal_sbus_probe_one(struct of_device *op, int is_qfe) printk(KERN_INFO "%s: HAPPY MEAL (SBUS) 10/100baseT Ethernet ", dev->name); - printk("%s\n", print_mac(mac, dev->dev_addr)); + printk("%pM\n", dev->dev_addr); return 0; @@ -2932,7 +2930,6 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, int i, qfe_slot = -1; char prom_name[64]; int err; - DECLARE_MAC_BUF(mac); /* Now make sure pci_dev cookie is there. */ #ifdef CONFIG_SPARC @@ -2973,7 +2970,7 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, dev->base_addr = (long) pdev; - hp = (struct happy_meal *)dev->priv; + hp = netdev_priv(dev); memset(hp, 0, sizeof(*hp)); hp->happy_dev = pdev; @@ -3141,7 +3138,7 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, printk(KERN_INFO "%s: HAPPY MEAL (PCI/CheerIO) 10/100BaseT Ethernet ", dev->name); - printk("%s\n", print_mac(mac, dev->dev_addr)); + printk("%pM\n", dev->dev_addr); return 0; diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index 704301a5a7ffed417655912cbc0a61552d55bf71..281373281756e381d24125eb841f903eda0a8286 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -555,7 +555,6 @@ static void lance_rx_dvma(struct net_device *dev) len); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; } @@ -726,7 +725,6 @@ static void lance_rx_pio(struct net_device *dev) lance_piocopy_to_skb(skb, &(ib->rx_buf[entry][0]), len); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; } @@ -1321,7 +1319,6 @@ static int __devinit sparc_lance_probe_one(struct of_device *op, static unsigned version_printed; struct lance_private *lp; struct net_device *dev; - DECLARE_MAC_BUF(mac); int i; dev = alloc_etherdev(sizeof(struct lance_private) + 8); @@ -1491,8 +1488,8 @@ static int __devinit sparc_lance_probe_one(struct of_device *op, dev_set_drvdata(&op->dev, lp); - printk(KERN_INFO "%s: LANCE %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: LANCE %pM\n", + dev->name, dev->dev_addr); return 0; diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c index f63644744ff9dafafb56eb746d3acf5018b3733f..6e8f377355fe8a6e98ab28676c0fa09671bc501a 100644 --- a/drivers/net/sunqe.c +++ b/drivers/net/sunqe.c @@ -446,7 +446,6 @@ static void qe_rx(struct sunqe *qep) len); skb->protocol = eth_type_trans(skb, qep->dev); netif_rx(skb); - qep->dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += len; } @@ -513,7 +512,7 @@ static irqreturn_t qec_interrupt(int irq, void *dev_id) static int qe_open(struct net_device *dev) { - struct sunqe *qep = (struct sunqe *) dev->priv; + struct sunqe *qep = netdev_priv(dev); qep->mconfig = (MREGS_MCONFIG_TXENAB | MREGS_MCONFIG_RXENAB | @@ -523,7 +522,7 @@ static int qe_open(struct net_device *dev) static int qe_close(struct net_device *dev) { - struct sunqe *qep = (struct sunqe *) dev->priv; + struct sunqe *qep = netdev_priv(dev); qe_stop(qep); return 0; @@ -549,7 +548,7 @@ static void qe_tx_reclaim(struct sunqe *qep) static void qe_tx_timeout(struct net_device *dev) { - struct sunqe *qep = (struct sunqe *) dev->priv; + struct sunqe *qep = netdev_priv(dev); int tx_full; spin_lock_irq(&qep->lock); @@ -575,7 +574,7 @@ static void qe_tx_timeout(struct net_device *dev) /* Get a packet queued to go onto the wire. */ static int qe_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct sunqe *qep = (struct sunqe *) dev->priv; + struct sunqe *qep = netdev_priv(dev); struct sunqe_buffers *qbufs = qep->buffers; __u32 txbuf_dvma, qbufs_dvma = qep->buffers_dvma; unsigned char *txbuf; @@ -627,7 +626,7 @@ static int qe_start_xmit(struct sk_buff *skb, struct net_device *dev) static void qe_set_multicast(struct net_device *dev) { - struct sunqe *qep = (struct sunqe *) dev->priv; + struct sunqe *qep = netdev_priv(dev); struct dev_mc_list *dmi = dev->mc_list; u8 new_mconfig = qep->mconfig; char *addrs; @@ -693,7 +692,7 @@ static void qe_set_multicast(struct net_device *dev) static void qe_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { const struct linux_prom_registers *regs; - struct sunqe *qep = dev->priv; + struct sunqe *qep = netdev_priv(dev); struct of_device *op; strcpy(info->driver, "sunqe"); @@ -708,7 +707,7 @@ static void qe_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) static u32 qe_get_link(struct net_device *dev) { - struct sunqe *qep = dev->priv; + struct sunqe *qep = netdev_priv(dev); void __iomem *mregs = qep->mregs; u8 phyconfig; diff --git a/drivers/net/sunvnet.c b/drivers/net/sunvnet.c index a720065553df48645f121c86b11bcf8bf5c61e52..233f1cda36e52b425e952ba823a02bfe11c1ab81 100644 --- a/drivers/net/sunvnet.c +++ b/drivers/net/sunvnet.c @@ -1149,7 +1149,6 @@ static int __devinit vnet_port_probe(struct vio_dev *vdev, struct vnet *vp; const u64 *rmac; int len, i, err, switch_port; - DECLARE_MAC_BUF(mac); print_version(); @@ -1214,8 +1213,8 @@ static int __devinit vnet_port_probe(struct vio_dev *vdev, dev_set_drvdata(&vdev->dev, port); - printk(KERN_INFO "%s: PORT ( remote-mac %s%s )\n", - vp->dev->name, print_mac(mac, port->raddr), + printk(KERN_INFO "%s: PORT ( remote-mac %pM%s )\n", + vp->dev->name, port->raddr, switch_port ? " switch-port" : ""); vio_port_up(&port->vio); diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index df20cafff7dd3a5da1926740e5cb14193f5b81f9..bcd0e60cbda98984c9383f55cc4df671510d33a1 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -37,6 +37,7 @@ static const char *version = "tc35815.c:v" DRV_VERSION "\n"; #include #include #include +#include #include #include #include @@ -236,7 +237,7 @@ struct tc35815_regs { #define Rx_Halted 0x00008000 /* Rx Halted */ #define Rx_Good 0x00004000 /* Rx Good */ #define Rx_RxPar 0x00002000 /* Rx Parity Error */ - /* 0x00001000 not use */ +#define Rx_TypePkt 0x00001000 /* Rx Type Packet */ #define Rx_LongErr 0x00000800 /* Rx Long Error */ #define Rx_Over 0x00000400 /* Rx Overflow */ #define Rx_CRCErr 0x00000200 /* Rx CRC Error */ @@ -244,8 +245,9 @@ struct tc35815_regs { #define Rx_10Stat 0x00000080 /* Rx 10Mbps Status */ #define Rx_IntRx 0x00000040 /* Rx Interrupt */ #define Rx_CtlRecd 0x00000020 /* Rx Control Receive */ +#define Rx_InLenErr 0x00000010 /* Rx In Range Frame Length Error */ -#define Rx_Stat_Mask 0x0000EFC0 /* Rx All Status Mask */ +#define Rx_Stat_Mask 0x0000FFF0 /* Rx All Status Mask */ /* Int_En bit asign -------------------------------------------------------- */ #define Int_NRAbtEn 0x00000800 /* 1:Non-recoverable Abort Enable */ @@ -340,7 +342,7 @@ struct BDesc { Tx_En) /* maybe 0x7b01 */ #endif #define RX_CTL_CMD (Rx_EnGood | Rx_EnRxPar | Rx_EnLongErr | Rx_EnOver \ - | Rx_EnCRCErr | Rx_EnAlign | Rx_RxEn) /* maybe 0x6f01 */ + | Rx_EnCRCErr | Rx_EnAlign | Rx_StripCRC | Rx_RxEn) /* maybe 0x6f11 */ #define INT_EN_CMD (Int_NRAbtEn | \ Int_DmParErrEn | Int_DParDEn | Int_DParErrEn | \ Int_SSysErrEn | Int_RMasAbtEn | Int_RTargAbtEn | \ @@ -372,9 +374,11 @@ struct BDesc { #if RX_CTL_CMD & Rx_LongEn #define RX_BUF_SIZE PAGE_SIZE #elif RX_CTL_CMD & Rx_StripCRC -#define RX_BUF_SIZE ALIGN(ETH_FRAME_LEN + 4 + 2, 32) /* +2: reserve */ +#define RX_BUF_SIZE \ + L1_CACHE_ALIGN(ETH_FRAME_LEN + VLAN_HLEN + NET_IP_ALIGN) #else -#define RX_BUF_SIZE ALIGN(ETH_FRAME_LEN + 2, 32) /* +2: reserve */ +#define RX_BUF_SIZE \ + L1_CACHE_ALIGN(ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN + NET_IP_ALIGN) #endif #endif /* TC35815_USE_PACKEDBUFFER */ #define RX_FD_RESERVE (2 / 2) /* max 2 BD per RxFD */ @@ -865,7 +869,6 @@ static int __devinit tc35815_init_one(struct pci_dev *pdev, struct net_device *dev; struct tc35815_local *lp; int rc; - DECLARE_MAC_BUF(mac); static int printed_version; if (!printed_version++) { @@ -942,11 +945,11 @@ static int __devinit tc35815_init_one(struct pci_dev *pdev, goto err_out; memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); - printk(KERN_INFO "%s: %s at 0x%lx, %s, IRQ %d\n", + printk(KERN_INFO "%s: %s at 0x%lx, %pM, IRQ %d\n", dev->name, chip_info[ent->driver_data].name, dev->base_addr, - print_mac(mac, dev->dev_addr), + dev->dev_addr, dev->irq); rc = tc_mii_init(dev); @@ -1288,12 +1291,9 @@ panic_queues(struct net_device *dev) static void print_eth(const u8 *add) { - DECLARE_MAC_BUF(mac); - printk(KERN_DEBUG "print_eth(%p)\n", add); - printk(KERN_DEBUG " %s =>", print_mac(mac, add + 6)); - printk(KERN_CONT " %s : %02x%02x\n", - print_mac(mac, add), add[12], add[13]); + printk(KERN_DEBUG " %pM => %pM : %02x%02x\n", + add + 6, add, add[12], add[13]); } static int tc35815_tx_full(struct net_device *dev) @@ -1609,8 +1609,8 @@ static irqreturn_t tc35815_interrupt(int irq, void *dev_id) if (!(dmactl & DMA_IntMask)) { /* disable interrupts */ tc_writel(dmactl | DMA_IntMask, &tr->DMA_Ctl); - if (netif_rx_schedule_prep(dev, &lp->napi)) - __netif_rx_schedule(dev, &lp->napi); + if (netif_rx_schedule_prep(&lp->napi)) + __netif_rx_schedule(&lp->napi); else { printk(KERN_ERR "%s: interrupt taken in poll\n", dev->name); @@ -1669,7 +1669,7 @@ tc35815_rx(struct net_device *dev) struct RxFD *next_rfd; #endif #if (RX_CTL_CMD & Rx_StripCRC) == 0 - pkt_len -= 4; + pkt_len -= ETH_FCS_LEN; #endif if (netif_msg_rx_status(lp)) @@ -1688,14 +1688,14 @@ tc35815_rx(struct net_device *dev) #endif #ifdef TC35815_USE_PACKEDBUFFER BUG_ON(bd_count > 2); - skb = dev_alloc_skb(pkt_len + 2); /* +2: for reserve */ + skb = dev_alloc_skb(pkt_len + NET_IP_ALIGN); if (skb == NULL) { printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); dev->stats.rx_dropped++; break; } - skb_reserve(skb, 2); /* 16 bit alignment */ + skb_reserve(skb, NET_IP_ALIGN); data = skb_put(skb, pkt_len); @@ -1747,8 +1747,9 @@ tc35815_rx(struct net_device *dev) pci_unmap_single(lp->pci_dev, lp->rx_skbs[cur_bd].skb_dma, RX_BUF_SIZE, PCI_DMA_FROMDEVICE); - if (!HAVE_DMA_RXALIGN(lp)) - memmove(skb->data, skb->data - 2, pkt_len); + if (!HAVE_DMA_RXALIGN(lp) && NET_IP_ALIGN) + memmove(skb->data, skb->data - NET_IP_ALIGN, + pkt_len); data = skb_put(skb, pkt_len); #endif /* TC35815_USE_PACKEDBUFFER */ if (netif_msg_pktdata(lp)) @@ -1760,7 +1761,6 @@ tc35815_rx(struct net_device *dev) #else netif_rx(skb); #endif - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } else { @@ -1919,7 +1919,7 @@ static int tc35815_poll(struct napi_struct *napi, int budget) spin_unlock(&lp->lock); if (received < budget) { - netif_rx_complete(dev, napi); + netif_rx_complete(napi); /* enable interrupts */ tc_writel(tc_readl(&tr->DMA_Ctl) & ~DMA_IntMask, &tr->DMA_Ctl); } @@ -2153,13 +2153,12 @@ static void tc35815_set_cam_entry(struct net_device *dev, int index, unsigned ch int cam_index = index * 6; u32 cam_data; u32 saved_addr; - DECLARE_MAC_BUF(mac); saved_addr = tc_readl(&tr->CAM_Adr); if (netif_msg_hw(lp)) - printk(KERN_DEBUG "%s: CAM %d: %s\n", - dev->name, index, print_mac(mac, addr)); + printk(KERN_DEBUG "%s: CAM %d: %pM\n", + dev->name, index, addr); if (index & 1) { /* read modify write */ tc_writel(cam_index - 2, &tr->CAM_Adr); diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c index 91f9054a1d9522b5f60f0347d6264beeba8d4c60..a10a83a11d9fb07a02d10d2f8b1fad1f13c26a71 100644 --- a/drivers/net/tehuti.c +++ b/drivers/net/tehuti.c @@ -251,7 +251,7 @@ static void bdx_isr_extra(struct bdx_priv *priv, u32 isr) static irqreturn_t bdx_isr_napi(int irq, void *dev) { struct net_device *ndev = dev; - struct bdx_priv *priv = ndev->priv; + struct bdx_priv *priv = netdev_priv(ndev); u32 isr; ENTER; @@ -265,8 +265,8 @@ static irqreturn_t bdx_isr_napi(int irq, void *dev) bdx_isr_extra(priv, isr); if (isr & (IR_RX_DESC_0 | IR_TX_FREE_0)) { - if (likely(netif_rx_schedule_prep(ndev, &priv->napi))) { - __netif_rx_schedule(ndev, &priv->napi); + if (likely(netif_rx_schedule_prep(&priv->napi))) { + __netif_rx_schedule(&priv->napi); RET(IRQ_HANDLED); } else { /* NOTE: we get here if intr has slipped into window @@ -289,7 +289,6 @@ static irqreturn_t bdx_isr_napi(int irq, void *dev) static int bdx_poll(struct napi_struct *napi, int budget) { struct bdx_priv *priv = container_of(napi, struct bdx_priv, napi); - struct net_device *dev = priv->ndev; int work_done; ENTER; @@ -303,7 +302,7 @@ static int bdx_poll(struct napi_struct *napi, int budget) * device lock and allow waiting tasks (eg rmmod) to advance) */ priv->napi_stop = 0; - netif_rx_complete(dev, napi); + netif_rx_complete(napi); bdx_enable_interrupts(priv); } return work_done; @@ -559,7 +558,7 @@ static int bdx_close(struct net_device *ndev) struct bdx_priv *priv = NULL; ENTER; - priv = ndev->priv; + priv = netdev_priv(ndev); napi_disable(&priv->napi); @@ -588,7 +587,7 @@ static int bdx_open(struct net_device *ndev) int rc; ENTER; - priv = ndev->priv; + priv = netdev_priv(ndev); bdx_reset(priv); if (netif_running(ndev)) netif_stop_queue(priv->ndev); @@ -633,7 +632,7 @@ static int bdx_range_check(struct bdx_priv *priv, u32 offset) static int bdx_ioctl_priv(struct net_device *ndev, struct ifreq *ifr, int cmd) { - struct bdx_priv *priv = ndev->priv; + struct bdx_priv *priv = netdev_priv(ndev); u32 data[3]; int error; @@ -698,7 +697,7 @@ static int bdx_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd) */ static void __bdx_vlan_rx_vid(struct net_device *ndev, uint16_t vid, int enable) { - struct bdx_priv *priv = ndev->priv; + struct bdx_priv *priv = netdev_priv(ndev); u32 reg, bit, val; ENTER; @@ -748,7 +747,7 @@ static void bdx_vlan_rx_kill_vid(struct net_device *ndev, unsigned short vid) static void bdx_vlan_rx_register(struct net_device *ndev, struct vlan_group *grp) { - struct bdx_priv *priv = ndev->priv; + struct bdx_priv *priv = netdev_priv(ndev); ENTER; DBG("device='%s', group='%p'\n", ndev->name, grp); @@ -787,7 +786,7 @@ static int bdx_change_mtu(struct net_device *ndev, int new_mtu) static void bdx_setmulti(struct net_device *ndev) { - struct bdx_priv *priv = ndev->priv; + struct bdx_priv *priv = netdev_priv(ndev); u32 rxf_val = GMAC_RX_FILTER_AM | GMAC_RX_FILTER_AB | GMAC_RX_FILTER_OSEN; @@ -847,7 +846,7 @@ static void bdx_setmulti(struct net_device *ndev) static int bdx_set_mac(struct net_device *ndev, void *p) { - struct bdx_priv *priv = ndev->priv; + struct bdx_priv *priv = netdev_priv(ndev); struct sockaddr *addr = p; ENTER; @@ -929,7 +928,7 @@ static void bdx_update_stats(struct bdx_priv *priv) static struct net_device_stats *bdx_get_stats(struct net_device *ndev) { - struct bdx_priv *priv = ndev->priv; + struct bdx_priv *priv = netdev_priv(ndev); struct net_device_stats *net_stat = &priv->net_stats; return net_stat; } @@ -1237,7 +1236,6 @@ static int bdx_rx_receive(struct bdx_priv *priv, struct rxd_fifo *f, int budget) ENTER; max_done = budget; - priv->ndev->last_rx = jiffies; f->m.wptr = READ_REG(priv, f->m.reg_WPTR) & TXF_WPTR_WR_PTR; size = f->m.wptr - f->m.rptr; @@ -1624,7 +1622,7 @@ static inline int bdx_tx_space(struct bdx_priv *priv) */ static int bdx_tx_transmit(struct sk_buff *skb, struct net_device *ndev) { - struct bdx_priv *priv = ndev->priv; + struct bdx_priv *priv = netdev_priv(ndev); struct txd_fifo *f = &priv->txd_fifo0; int txd_checksum = 7; /* full checksum */ int txd_lgsnd = 0; @@ -1886,6 +1884,21 @@ static void bdx_tx_push_desc_safe(struct bdx_priv *priv, void *data, int size) RET(); } +static const struct net_device_ops bdx_netdev_ops = { + .ndo_open = bdx_open, + .ndo_stop = bdx_close, + .ndo_start_xmit = bdx_tx_transmit, + .ndo_validate_addr = eth_validate_addr, + .ndo_do_ioctl = bdx_ioctl, + .ndo_set_multicast_list = bdx_setmulti, + .ndo_get_stats = bdx_get_stats, + .ndo_change_mtu = bdx_change_mtu, + .ndo_set_mac_address = bdx_set_mac, + .ndo_vlan_rx_register = bdx_vlan_rx_register, + .ndo_vlan_rx_add_vid = bdx_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = bdx_vlan_rx_kill_vid, +}; + /** * bdx_probe - Device Initialization Routine * @pdev: PCI device information struct @@ -1995,18 +2008,8 @@ bdx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_iomap; } - ndev->open = bdx_open; - ndev->stop = bdx_close; - ndev->hard_start_xmit = bdx_tx_transmit; - ndev->do_ioctl = bdx_ioctl; - ndev->set_multicast_list = bdx_setmulti; - ndev->get_stats = bdx_get_stats; - ndev->change_mtu = bdx_change_mtu; - ndev->set_mac_address = bdx_set_mac; + ndev->netdev_ops = &bdx_netdev_ops; ndev->tx_queue_len = BDX_NDEV_TXQ_LEN; - ndev->vlan_rx_register = bdx_vlan_rx_register; - ndev->vlan_rx_add_vid = bdx_vlan_rx_add_vid; - ndev->vlan_rx_kill_vid = bdx_vlan_rx_kill_vid; bdx_ethtool_ops(ndev); /* ethtool interface */ @@ -2027,7 +2030,7 @@ bdx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ndev->features |= NETIF_F_HIGHDMA; /************** priv ****************/ - priv = nic->priv[port] = ndev->priv; + priv = nic->priv[port] = netdev_priv(ndev); memset(priv, 0, sizeof(struct bdx_priv)); priv->pBdxRegs = nic->regs + port * 0x8000; @@ -2150,7 +2153,7 @@ static int bdx_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) { u32 rdintcm; u32 tdintcm; - struct bdx_priv *priv = netdev->priv; + struct bdx_priv *priv = netdev_priv(netdev); rdintcm = priv->rdintcm; tdintcm = priv->tdintcm; @@ -2181,7 +2184,7 @@ static int bdx_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) static void bdx_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) { - struct bdx_priv *priv = netdev->priv; + struct bdx_priv *priv = netdev_priv(netdev); strlcat(drvinfo->driver, BDX_DRV_NAME, sizeof(drvinfo->driver)); strlcat(drvinfo->version, BDX_DRV_VERSION, sizeof(drvinfo->version)); @@ -2223,7 +2226,7 @@ bdx_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *ecoal) { u32 rdintcm; u32 tdintcm; - struct bdx_priv *priv = netdev->priv; + struct bdx_priv *priv = netdev_priv(netdev); rdintcm = priv->rdintcm; tdintcm = priv->tdintcm; @@ -2252,7 +2255,7 @@ bdx_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ecoal) { u32 rdintcm; u32 tdintcm; - struct bdx_priv *priv = netdev->priv; + struct bdx_priv *priv = netdev_priv(netdev); int rx_coal; int tx_coal; int rx_max_coal; @@ -2310,7 +2313,7 @@ static inline int bdx_tx_fifo_size_to_packets(int tx_size) static void bdx_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) { - struct bdx_priv *priv = netdev->priv; + struct bdx_priv *priv = netdev_priv(netdev); /*max_pending - the maximum-sized FIFO we allow */ ring->rx_max_pending = bdx_rx_fifo_size_to_packets(3); @@ -2327,7 +2330,7 @@ bdx_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) static int bdx_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) { - struct bdx_priv *priv = netdev->priv; + struct bdx_priv *priv = netdev_priv(netdev); int rx_size = 0; int tx_size = 0; @@ -2388,7 +2391,7 @@ static void bdx_get_strings(struct net_device *netdev, u32 stringset, u8 *data) */ static int bdx_get_stats_count(struct net_device *netdev) { - struct bdx_priv *priv = netdev->priv; + struct bdx_priv *priv = netdev_priv(netdev); BDX_ASSERT(ARRAY_SIZE(bdx_stat_names) != sizeof(struct bdx_stats) / sizeof(u64)); return ((priv->stats_flag) ? ARRAY_SIZE(bdx_stat_names) : 0); @@ -2403,7 +2406,7 @@ static int bdx_get_stats_count(struct net_device *netdev) static void bdx_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, u64 *data) { - struct bdx_priv *priv = netdev->priv; + struct bdx_priv *priv = netdev_priv(netdev); if (priv->stats_flag) { diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index eb9f8f3638e1923bf664f55bdbf4de9e32621a47..04ae1e86aeaa4c8b05ad6de192034f43e439420d 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -54,20 +54,21 @@ #include #endif +#define BAR_0 0 +#define BAR_2 2 + #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) #define TG3_VLAN_TAG_USED 1 #else #define TG3_VLAN_TAG_USED 0 #endif -#define TG3_TSO_SUPPORT 1 - #include "tg3.h" #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.94" -#define DRV_MODULE_RELDATE "August 14, 2008" +#define DRV_MODULE_VERSION "3.97" +#define DRV_MODULE_RELDATE "December 10, 2008" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -129,6 +130,8 @@ /* minimum number of free TX descriptors required to wake up TX process */ #define TG3_TX_WAKEUP_THRESH(tp) ((tp)->tx_pending / 4) +#define TG3_RAW_IP_ALIGN 2 + /* number of ETHTOOL_GSTATS u64's */ #define TG3_NUM_STATS (sizeof(struct tg3_ethtool_stats)/sizeof(u64)) @@ -205,7 +208,13 @@ static struct pci_device_id tg3_pci_tbl[] = { {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5723)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761E)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5761S)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5761SE)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5785)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57780)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57760)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57790)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57720)}, {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)}, {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX)}, {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000)}, @@ -872,13 +881,48 @@ static int tg3_mdio_reset(struct mii_bus *bp) return 0; } -static void tg3_mdio_config(struct tg3 *tp) +static void tg3_mdio_config_5785(struct tg3 *tp) { u32 val; + struct phy_device *phydev; - if (tp->mdio_bus->phy_map[PHY_ADDR]->interface != - PHY_INTERFACE_MODE_RGMII) + phydev = tp->mdio_bus->phy_map[PHY_ADDR]; + switch (phydev->drv->phy_id & phydev->drv->phy_id_mask) { + case TG3_PHY_ID_BCM50610: + val = MAC_PHYCFG2_50610_LED_MODES; + break; + case TG3_PHY_ID_BCMAC131: + val = MAC_PHYCFG2_AC131_LED_MODES; + break; + case TG3_PHY_ID_RTL8211C: + val = MAC_PHYCFG2_RTL8211C_LED_MODES; + break; + case TG3_PHY_ID_RTL8201E: + val = MAC_PHYCFG2_RTL8201E_LED_MODES; + break; + default: return; + } + + if (phydev->interface != PHY_INTERFACE_MODE_RGMII) { + tw32(MAC_PHYCFG2, val); + + val = tr32(MAC_PHYCFG1); + val &= ~MAC_PHYCFG1_RGMII_INT; + tw32(MAC_PHYCFG1, val); + + return; + } + + if (!(tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE)) + val |= MAC_PHYCFG2_EMODE_MASK_MASK | + MAC_PHYCFG2_FMODE_MASK_MASK | + MAC_PHYCFG2_GMODE_MASK_MASK | + MAC_PHYCFG2_ACT_MASK_MASK | + MAC_PHYCFG2_QUAL_MASK_MASK | + MAC_PHYCFG2_INBAND_ENABLE; + + tw32(MAC_PHYCFG2, val); val = tr32(MAC_PHYCFG1) & ~(MAC_PHYCFG1_RGMII_EXT_RX_DEC | MAC_PHYCFG1_RGMII_SND_STAT_EN); @@ -890,11 +934,6 @@ static void tg3_mdio_config(struct tg3 *tp) } tw32(MAC_PHYCFG1, val | MAC_PHYCFG1_RGMII_INT | MAC_PHYCFG1_TXC_DRV); - val = tr32(MAC_PHYCFG2) & ~(MAC_PHYCFG2_INBAND_ENABLE); - if (!(tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE)) - val |= MAC_PHYCFG2_INBAND_ENABLE; - tw32(MAC_PHYCFG2, val); - val = tr32(MAC_EXT_RGMII_MODE); val &= ~(MAC_RGMII_MODE_RX_INT_B | MAC_RGMII_MODE_RX_QUALITY | @@ -903,7 +942,7 @@ static void tg3_mdio_config(struct tg3 *tp) MAC_RGMII_MODE_TX_ENABLE | MAC_RGMII_MODE_TX_LOWPWR | MAC_RGMII_MODE_TX_RESET); - if (tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE) { + if (!(tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE)) { if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN) val |= MAC_RGMII_MODE_RX_INT_B | MAC_RGMII_MODE_RX_QUALITY | @@ -929,8 +968,9 @@ static void tg3_mdio_start(struct tg3 *tp) tw32_f(MAC_MI_MODE, tp->mi_mode); udelay(80); - if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) - tg3_mdio_config(tp); + if ((tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) && + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) + tg3_mdio_config_5785(tp); } static void tg3_mdio_stop(struct tg3 *tp) @@ -984,29 +1024,44 @@ static int tg3_mdio_init(struct tg3 *tp) if (i) { printk(KERN_WARNING "%s: mdiobus_reg failed (0x%x)\n", tp->dev->name, i); + mdiobus_free(tp->mdio_bus); return i; } - tp->tg3_flags3 |= TG3_FLG3_MDIOBUS_INITED; - phydev = tp->mdio_bus->phy_map[PHY_ADDR]; - switch (phydev->phy_id) { + if (!phydev || !phydev->drv) { + printk(KERN_WARNING "%s: No PHY devices\n", tp->dev->name); + mdiobus_unregister(tp->mdio_bus); + mdiobus_free(tp->mdio_bus); + return -ENODEV; + } + + switch (phydev->drv->phy_id & phydev->drv->phy_id_mask) { + case TG3_PHY_ID_BCM57780: + phydev->interface = PHY_INTERFACE_MODE_GMII; + break; case TG3_PHY_ID_BCM50610: - phydev->interface = PHY_INTERFACE_MODE_RGMII; if (tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE) phydev->dev_flags |= PHY_BRCM_STD_IBND_DISABLE; if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN) phydev->dev_flags |= PHY_BRCM_EXT_IBND_RX_ENABLE; if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_TX_EN) phydev->dev_flags |= PHY_BRCM_EXT_IBND_TX_ENABLE; + /* fallthru */ + case TG3_PHY_ID_RTL8211C: + phydev->interface = PHY_INTERFACE_MODE_RGMII; break; + case TG3_PHY_ID_RTL8201E: case TG3_PHY_ID_BCMAC131: phydev->interface = PHY_INTERFACE_MODE_MII; break; } - tg3_mdio_config(tp); + tp->tg3_flags3 |= TG3_FLG3_MDIOBUS_INITED; + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) + tg3_mdio_config_5785(tp); return 0; } @@ -1130,9 +1185,9 @@ static void tg3_link_report(struct tg3 *tp) printk(KERN_INFO PFX "%s: Flow control is %s for TX and %s for RX.\n", tp->dev->name, - (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_TX) ? + (tp->link_config.active_flowctrl & FLOW_CTRL_TX) ? "on" : "off", - (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_RX) ? + (tp->link_config.active_flowctrl & FLOW_CTRL_RX) ? "on" : "off"); tg3_ump_link_report(tp); } @@ -1142,11 +1197,11 @@ static u16 tg3_advert_flowctrl_1000T(u8 flow_ctrl) { u16 miireg; - if ((flow_ctrl & TG3_FLOW_CTRL_TX) && (flow_ctrl & TG3_FLOW_CTRL_RX)) + if ((flow_ctrl & FLOW_CTRL_TX) && (flow_ctrl & FLOW_CTRL_RX)) miireg = ADVERTISE_PAUSE_CAP; - else if (flow_ctrl & TG3_FLOW_CTRL_TX) + else if (flow_ctrl & FLOW_CTRL_TX) miireg = ADVERTISE_PAUSE_ASYM; - else if (flow_ctrl & TG3_FLOW_CTRL_RX) + else if (flow_ctrl & FLOW_CTRL_RX) miireg = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; else miireg = 0; @@ -1158,11 +1213,11 @@ static u16 tg3_advert_flowctrl_1000X(u8 flow_ctrl) { u16 miireg; - if ((flow_ctrl & TG3_FLOW_CTRL_TX) && (flow_ctrl & TG3_FLOW_CTRL_RX)) + if ((flow_ctrl & FLOW_CTRL_TX) && (flow_ctrl & FLOW_CTRL_RX)) miireg = ADVERTISE_1000XPAUSE; - else if (flow_ctrl & TG3_FLOW_CTRL_TX) + else if (flow_ctrl & FLOW_CTRL_TX) miireg = ADVERTISE_1000XPSE_ASYM; - else if (flow_ctrl & TG3_FLOW_CTRL_RX) + else if (flow_ctrl & FLOW_CTRL_RX) miireg = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM; else miireg = 0; @@ -1170,28 +1225,6 @@ static u16 tg3_advert_flowctrl_1000X(u8 flow_ctrl) return miireg; } -static u8 tg3_resolve_flowctrl_1000T(u16 lcladv, u16 rmtadv) -{ - u8 cap = 0; - - if (lcladv & ADVERTISE_PAUSE_CAP) { - if (lcladv & ADVERTISE_PAUSE_ASYM) { - if (rmtadv & LPA_PAUSE_CAP) - cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX; - else if (rmtadv & LPA_PAUSE_ASYM) - cap = TG3_FLOW_CTRL_RX; - } else { - if (rmtadv & LPA_PAUSE_CAP) - cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX; - } - } else if (lcladv & ADVERTISE_PAUSE_ASYM) { - if ((rmtadv & LPA_PAUSE_CAP) && (rmtadv & LPA_PAUSE_ASYM)) - cap = TG3_FLOW_CTRL_TX; - } - - return cap; -} - static u8 tg3_resolve_flowctrl_1000X(u16 lcladv, u16 rmtadv) { u8 cap = 0; @@ -1199,16 +1232,16 @@ static u8 tg3_resolve_flowctrl_1000X(u16 lcladv, u16 rmtadv) if (lcladv & ADVERTISE_1000XPAUSE) { if (lcladv & ADVERTISE_1000XPSE_ASYM) { if (rmtadv & LPA_1000XPAUSE) - cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX; + cap = FLOW_CTRL_TX | FLOW_CTRL_RX; else if (rmtadv & LPA_1000XPAUSE_ASYM) - cap = TG3_FLOW_CTRL_RX; + cap = FLOW_CTRL_RX; } else { if (rmtadv & LPA_1000XPAUSE) - cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX; + cap = FLOW_CTRL_TX | FLOW_CTRL_RX; } } else if (lcladv & ADVERTISE_1000XPSE_ASYM) { if ((rmtadv & LPA_1000XPAUSE) && (rmtadv & LPA_1000XPAUSE_ASYM)) - cap = TG3_FLOW_CTRL_TX; + cap = FLOW_CTRL_TX; } return cap; @@ -1231,13 +1264,13 @@ static void tg3_setup_flow_control(struct tg3 *tp, u32 lcladv, u32 rmtadv) if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) flowctrl = tg3_resolve_flowctrl_1000X(lcladv, rmtadv); else - flowctrl = tg3_resolve_flowctrl_1000T(lcladv, rmtadv); + flowctrl = mii_resolve_flowctrl_fdx(lcladv, rmtadv); } else flowctrl = tp->link_config.flowctrl; tp->link_config.active_flowctrl = flowctrl; - if (flowctrl & TG3_FLOW_CTRL_RX) + if (flowctrl & FLOW_CTRL_RX) tp->rx_mode |= RX_MODE_FLOW_CTRL_ENABLE; else tp->rx_mode &= ~RX_MODE_FLOW_CTRL_ENABLE; @@ -1245,7 +1278,7 @@ static void tg3_setup_flow_control(struct tg3 *tp, u32 lcladv, u32 rmtadv) if (old_rx_mode != tp->rx_mode) tw32_f(MAC_RX_MODE, tp->rx_mode); - if (flowctrl & TG3_FLOW_CTRL_TX) + if (flowctrl & FLOW_CTRL_TX) tp->tx_mode |= TX_MODE_FLOW_CTRL_ENABLE; else tp->tx_mode &= ~TX_MODE_FLOW_CTRL_ENABLE; @@ -1299,6 +1332,15 @@ static void tg3_adjust_link(struct net_device *dev) udelay(40); } + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) { + if (phydev->speed == SPEED_10) + tw32(MAC_MI_STAT, + MAC_MI_STAT_10MBPS_MODE | + MAC_MI_STAT_LNKSTAT_ATTN_ENAB); + else + tw32(MAC_MI_STAT, MAC_MI_STAT_LNKSTAT_ATTN_ENAB); + } + if (phydev->speed == SPEED_1000 && phydev->duplex == DUPLEX_HALF) tw32(MAC_TX_LENGTHS, ((2 << TX_LENGTHS_IPG_CRS_SHIFT) | @@ -1339,25 +1381,37 @@ static int tg3_phy_init(struct tg3 *tp) phydev = tp->mdio_bus->phy_map[PHY_ADDR]; /* Attach the MAC to the PHY. */ - phydev = phy_connect(tp->dev, phydev->dev.bus_id, tg3_adjust_link, + phydev = phy_connect(tp->dev, dev_name(&phydev->dev), tg3_adjust_link, phydev->dev_flags, phydev->interface); if (IS_ERR(phydev)) { printk(KERN_ERR "%s: Could not attach to PHY\n", tp->dev->name); return PTR_ERR(phydev); } - tp->tg3_flags3 |= TG3_FLG3_PHY_CONNECTED; - /* Mask with MAC supported features. */ - phydev->supported &= (PHY_GBIT_FEATURES | - SUPPORTED_Pause | - SUPPORTED_Asym_Pause); + switch (phydev->interface) { + case PHY_INTERFACE_MODE_GMII: + case PHY_INTERFACE_MODE_RGMII: + if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY)) { + phydev->supported &= (PHY_GBIT_FEATURES | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause); + break; + } + /* fallthru */ + case PHY_INTERFACE_MODE_MII: + phydev->supported &= (PHY_BASIC_FEATURES | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause); + break; + default: + phy_disconnect(tp->mdio_bus->phy_map[PHY_ADDR]); + return -EINVAL; + } - phydev->advertising = phydev->supported; + tp->tg3_flags3 |= TG3_FLG3_PHY_CONNECTED; - printk(KERN_INFO - "%s: attached PHY driver [%s] (mii_bus:phy_addr=%s)\n", - tp->dev->name, phydev->drv->name, phydev->dev.bus_id); + phydev->advertising = phydev->supported; return 0; } @@ -1406,6 +1460,34 @@ static void tg3_phydsp_write(struct tg3 *tp, u32 reg, u32 val) tg3_writephy(tp, MII_TG3_DSP_RW_PORT, val); } +static void tg3_phy_toggle_apd(struct tg3 *tp, bool enable) +{ + u32 reg; + + if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) + return; + + reg = MII_TG3_MISC_SHDW_WREN | + MII_TG3_MISC_SHDW_SCR5_SEL | + MII_TG3_MISC_SHDW_SCR5_LPED | + MII_TG3_MISC_SHDW_SCR5_DLPTLM | + MII_TG3_MISC_SHDW_SCR5_SDTL | + MII_TG3_MISC_SHDW_SCR5_C125OE; + if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 || !enable) + reg |= MII_TG3_MISC_SHDW_SCR5_DLLAPD; + + tg3_writephy(tp, MII_TG3_MISC_SHDW, reg); + + + reg = MII_TG3_MISC_SHDW_WREN | + MII_TG3_MISC_SHDW_APD_SEL | + MII_TG3_MISC_SHDW_APD_WKTM_84MS; + if (enable) + reg |= MII_TG3_MISC_SHDW_APD_ENABLE; + + tg3_writephy(tp, MII_TG3_MISC_SHDW, reg); +} + static void tg3_phy_toggle_automdix(struct tg3 *tp, int enable) { u32 phy; @@ -1737,7 +1819,8 @@ static int tg3_phy_reset(struct tg3 *tp) tw32(TG3_CPMU_CTRL, cpmuctrl); } - if (tp->tg3_flags3 & TG3_FLG3_5761_5784_AX_FIXES) { + if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX || + GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5761_AX) { u32 val; val = tr32(TG3_CPMU_LSPD_1000MB_CLK); @@ -1747,16 +1830,15 @@ static int tg3_phy_reset(struct tg3 *tp) udelay(40); tw32_f(TG3_CPMU_LSPD_1000MB_CLK, val); } - - /* Disable GPHY autopowerdown. */ - tg3_writephy(tp, MII_TG3_MISC_SHDW, - MII_TG3_MISC_SHDW_WREN | - MII_TG3_MISC_SHDW_APD_SEL | - MII_TG3_MISC_SHDW_APD_WKTM_84MS); } tg3_phy_apply_otp(tp); + if (tp->tg3_flags3 & TG3_FLG3_PHY_ENABLE_APD) + tg3_phy_toggle_apd(tp, true); + else + tg3_phy_toggle_apd(tp, false); + out: if (tp->tg3_flags2 & TG3_FLG2_PHY_ADC_BUG) { tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00); @@ -1961,7 +2043,7 @@ static int tg3_halt_cpu(struct tg3 *, u32); static int tg3_nvram_lock(struct tg3 *); static void tg3_nvram_unlock(struct tg3 *); -static void tg3_power_down_phy(struct tg3 *tp) +static void tg3_power_down_phy(struct tg3 *tp, bool do_low_power) { u32 val; @@ -1984,10 +2066,15 @@ static void tg3_power_down_phy(struct tg3 *tp) tw32_f(GRC_MISC_CFG, val | GRC_MISC_CFG_EPHY_IDDQ); udelay(40); return; - } else if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) { + } else if (do_low_power) { tg3_writephy(tp, MII_TG3_EXT_CTRL, MII_TG3_EXT_CTRL_FORCE_LED_OFF); - tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x01b2); + + tg3_writephy(tp, MII_TG3_AUX_CTRL, + MII_TG3_AUXCTL_SHDWSEL_PWRCTL | + MII_TG3_AUXCTL_PCTL_100TX_LPWR | + MII_TG3_AUXCTL_PCTL_SPR_ISOLATE | + MII_TG3_AUXCTL_PCTL_VREG_11V); } /* The PHY should not be powered down on some chips because @@ -1999,7 +2086,8 @@ static void tg3_power_down_phy(struct tg3 *tp) (tp->tg3_flags2 & TG3_FLG2_MII_SERDES))) return; - if (tp->tg3_flags3 & TG3_FLG3_5761_5784_AX_FIXES) { + if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX || + GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5761_AX) { val = tr32(TG3_CPMU_LSPD_1000MB_CLK); val &= ~CPMU_LSPD_1000MB_MACCLK_MASK; val |= CPMU_LSPD_1000MB_MACCLK_12_5; @@ -2009,9 +2097,47 @@ static void tg3_power_down_phy(struct tg3 *tp) tg3_writephy(tp, MII_BMCR, BMCR_PDOWN); } +/* tp->lock is held. */ +static void __tg3_set_mac_addr(struct tg3 *tp, int skip_mac_1) +{ + u32 addr_high, addr_low; + int i; + + addr_high = ((tp->dev->dev_addr[0] << 8) | + tp->dev->dev_addr[1]); + addr_low = ((tp->dev->dev_addr[2] << 24) | + (tp->dev->dev_addr[3] << 16) | + (tp->dev->dev_addr[4] << 8) | + (tp->dev->dev_addr[5] << 0)); + for (i = 0; i < 4; i++) { + if (i == 1 && skip_mac_1) + continue; + tw32(MAC_ADDR_0_HIGH + (i * 8), addr_high); + tw32(MAC_ADDR_0_LOW + (i * 8), addr_low); + } + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) { + for (i = 0; i < 12; i++) { + tw32(MAC_EXTADDR_0_HIGH + (i * 8), addr_high); + tw32(MAC_EXTADDR_0_LOW + (i * 8), addr_low); + } + } + + addr_high = (tp->dev->dev_addr[0] + + tp->dev->dev_addr[1] + + tp->dev->dev_addr[2] + + tp->dev->dev_addr[3] + + tp->dev->dev_addr[4] + + tp->dev->dev_addr[5]) & + TX_BACKOFF_SEED_MASK; + tw32(MAC_TX_BACKOFF_SEED, addr_high); +} + static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) { u32 misc_host_ctrl; + bool device_should_wake, do_low_power; /* Make sure register accesses (indirect or otherwise) * will function correctly. @@ -2041,15 +2167,34 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) tp->dev->name, state); return -EINVAL; } + + /* Restore the CLKREQ setting. */ + if (tp->tg3_flags3 & TG3_FLG3_CLKREQ_BUG) { + u16 lnkctl; + + pci_read_config_word(tp->pdev, + tp->pcie_cap + PCI_EXP_LNKCTL, + &lnkctl); + lnkctl |= PCI_EXP_LNKCTL_CLKREQ_EN; + pci_write_config_word(tp->pdev, + tp->pcie_cap + PCI_EXP_LNKCTL, + lnkctl); + } + misc_host_ctrl = tr32(TG3PCI_MISC_HOST_CTRL); tw32(TG3PCI_MISC_HOST_CTRL, misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT); + device_should_wake = pci_pme_capable(tp->pdev, state) && + device_may_wakeup(&tp->pdev->dev) && + (tp->tg3_flags & TG3_FLAG_WOL_ENABLE); + if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { + do_low_power = false; if ((tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) && !tp->link_config.phy_is_low_power) { struct phy_device *phydev; - u32 advertising; + u32 phyid, advertising; phydev = tp->mdio_bus->phy_map[PHY_ADDR]; @@ -2066,7 +2211,7 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) ADVERTISED_10baseT_Half; if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) || - (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)) { + device_should_wake) { if (tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB) advertising |= ADVERTISED_100baseT_Half | @@ -2079,8 +2224,19 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) phydev->advertising = advertising; phy_start_aneg(phydev); + + phyid = phydev->drv->phy_id & phydev->drv->phy_id_mask; + if (phyid != TG3_PHY_ID_BCMAC131) { + phyid &= TG3_PHY_OUI_MASK; + if (phyid == TG3_PHY_OUI_1 && + phyid == TG3_PHY_OUI_2 && + phyid == TG3_PHY_OUI_3) + do_low_power = true; + } } } else { + do_low_power = true; + if (tp->link_config.phy_is_low_power == 0) { tp->link_config.phy_is_low_power = 1; tp->link_config.orig_speed = tp->link_config.speed; @@ -2096,6 +2252,8 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) } } + __tg3_set_mac_addr(tp, 0); + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { u32 val; @@ -2118,11 +2276,11 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) WOL_DRV_WOL | WOL_SET_MAGIC_PKT); - if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE) { + if (device_should_wake) { u32 mac_mode; if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) { - if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) { + if (do_low_power) { tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x5a); udelay(40); } @@ -2150,9 +2308,12 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) if (!(tp->tg3_flags2 & TG3_FLG2_5750_PLUS)) tw32(MAC_LED_CTRL, tp->led_ctrl); - if (pci_pme_capable(tp->pdev, state) && - (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)) - mac_mode |= MAC_MODE_MAGIC_PKT_ENABLE; + mac_mode |= MAC_MODE_MAGIC_PKT_ENABLE; + if (((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) && + !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) && + ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) || + (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))) + mac_mode |= MAC_MODE_KEEP_FRAME_IN_WOL; if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) { mac_mode |= tp->mac_mode & @@ -2224,10 +2385,9 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) } } - if (!(tp->tg3_flags & TG3_FLAG_WOL_ENABLE) && - !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF) && - !(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) - tg3_power_down_phy(tp); + if (!(device_should_wake) && + !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) + tg3_power_down_phy(tp, do_low_power); tg3_frob_aux_power(tp); @@ -2250,7 +2410,7 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN); - if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE) + if (device_should_wake) pci_enable_wake(tp->pdev, state, true); /* Finally, set the new power state. */ @@ -2789,6 +2949,24 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset) NIC_SRAM_FIRMWARE_MBOX_MAGIC2); } + /* Prevent send BD corruption. */ + if (tp->tg3_flags3 & TG3_FLG3_CLKREQ_BUG) { + u16 oldlnkctl, newlnkctl; + + pci_read_config_word(tp->pdev, + tp->pcie_cap + PCI_EXP_LNKCTL, + &oldlnkctl); + if (tp->link_config.active_speed == SPEED_100 || + tp->link_config.active_speed == SPEED_10) + newlnkctl = oldlnkctl & ~PCI_EXP_LNKCTL_CLKREQ_EN; + else + newlnkctl = oldlnkctl | PCI_EXP_LNKCTL_CLKREQ_EN; + if (newlnkctl != oldlnkctl) + pci_write_config_word(tp->pdev, + tp->pcie_cap + PCI_EXP_LNKCTL, + newlnkctl); + } + if (current_link_up != netif_carrier_ok(tp->dev)) { if (current_link_up) netif_carrier_on(tp->dev); @@ -3765,8 +3943,7 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset) err = tg3_setup_copper_phy(tp, force_reset); } - if (tp->pci_chip_rev_id == CHIPREV_ID_5784_A0 || - tp->pci_chip_rev_id == CHIPREV_ID_5784_A1) { + if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX) { u32 val, scale; val = tr32(TG3_CPMU_CLCK_STAT) & CPMU_CLCK_STAT_MAC_CLCK_MASK; @@ -4100,12 +4277,15 @@ static int tg3_rx(struct tg3 *tp, int budget) goto next_pkt; } - len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) - 4; /* omit crc */ + len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) - + ETH_FCS_LEN; if (len > RX_COPY_THRESHOLD - && tp->rx_offset == 2 - /* rx_offset != 2 iff this is a 5701 card running - * in PCI-X mode [see tg3_get_invariants()] */ + && tp->rx_offset == NET_IP_ALIGN + /* rx_offset will likely not equal NET_IP_ALIGN + * if this is a 5701 card running in PCI-X mode + * [see tg3_get_invariants()] + */ ) { int skb_size; @@ -4125,11 +4305,12 @@ static int tg3_rx(struct tg3 *tp, int budget) tg3_recycle_rx(tp, opaque_key, desc_idx, *post_ptr); - copy_skb = netdev_alloc_skb(tp->dev, len + 2); + copy_skb = netdev_alloc_skb(tp->dev, + len + TG3_RAW_IP_ALIGN); if (copy_skb == NULL) goto drop_it_no_recycle; - skb_reserve(copy_skb, 2); + skb_reserve(copy_skb, TG3_RAW_IP_ALIGN); skb_put(copy_skb, len); pci_dma_sync_single_for_cpu(tp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE); skb_copy_from_linear_data(skb, copy_skb->data, len); @@ -4157,7 +4338,6 @@ static int tg3_rx(struct tg3 *tp, int budget) #endif netif_receive_skb(skb); - tp->dev->last_rx = jiffies; received++; budget--; @@ -4271,7 +4451,7 @@ static int tg3_poll(struct napi_struct *napi, int budget) sblk->status &= ~SD_STATUS_UPDATED; if (likely(!tg3_has_work(tp))) { - netif_rx_complete(tp->dev, napi); + netif_rx_complete(napi); tg3_restart_ints(tp); break; } @@ -4281,7 +4461,7 @@ static int tg3_poll(struct napi_struct *napi, int budget) tx_recovery: /* work_done is guaranteed to be less than budget. */ - netif_rx_complete(tp->dev, napi); + netif_rx_complete(napi); schedule_work(&tp->reset_task); return work_done; } @@ -4330,7 +4510,7 @@ static irqreturn_t tg3_msi_1shot(int irq, void *dev_id) prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); if (likely(!tg3_irq_sync(tp))) - netif_rx_schedule(dev, &tp->napi); + netif_rx_schedule(&tp->napi); return IRQ_HANDLED; } @@ -4355,7 +4535,7 @@ static irqreturn_t tg3_msi(int irq, void *dev_id) */ tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001); if (likely(!tg3_irq_sync(tp))) - netif_rx_schedule(dev, &tp->napi); + netif_rx_schedule(&tp->napi); return IRQ_RETVAL(1); } @@ -4397,7 +4577,7 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id) sblk->status &= ~SD_STATUS_UPDATED; if (likely(tg3_has_work(tp))) { prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); - netif_rx_schedule(dev, &tp->napi); + netif_rx_schedule(&tp->napi); } else { /* No work, shared interrupt perhaps? re-enable * interrupts, and flush that PCI write @@ -4443,7 +4623,7 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id) tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001); if (tg3_irq_sync(tp)) goto out; - if (netif_rx_schedule_prep(dev, &tp->napi)) { + if (netif_rx_schedule_prep(&tp->napi)) { prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); /* Update last_tag to mark that this status has been * seen. Because interrupt may be shared, we may be @@ -4451,7 +4631,7 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id) * if tg3_poll() is not scheduled. */ tp->last_tag = sblk->status_tag; - __netif_rx_schedule(dev, &tp->napi); + __netif_rx_schedule(&tp->napi); } out: return IRQ_RETVAL(handled); @@ -5557,6 +5737,13 @@ static void tg3_ape_driver_state_change(struct tg3 *tp, int kind) event = APE_EVENT_STATUS_STATE_START; break; case RESET_KIND_SHUTDOWN: + /* With the interface we are currently using, + * APE does not track driver state. Wiping + * out the HOST SEGMENT SIGNATURE forces + * the APE to assume OS absent status. + */ + tg3_ape_write32(tp, TG3_APE_HOST_SEG_SIG, 0x0); + event = APE_EVENT_STATUS_STATE_UNLOAD; break; case RESET_KIND_SUSPEND: @@ -5721,17 +5908,19 @@ static void tg3_restore_pci_state(struct tg3 *tp) pci_write_config_word(tp->pdev, PCI_COMMAND, tp->pci_cmd); - if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) - pcie_set_readrq(tp->pdev, 4096); - else { - pci_write_config_byte(tp->pdev, PCI_CACHE_LINE_SIZE, - tp->pci_cacheline_sz); - pci_write_config_byte(tp->pdev, PCI_LATENCY_TIMER, - tp->pci_lat_timer); + if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785) { + if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) + pcie_set_readrq(tp->pdev, 4096); + else { + pci_write_config_byte(tp->pdev, PCI_CACHE_LINE_SIZE, + tp->pci_cacheline_sz); + pci_write_config_byte(tp->pdev, PCI_LATENCY_TIMER, + tp->pci_lat_timer); + } } /* Make sure PCI-X relaxed ordering bit is clear. */ - if (tp->pcix_cap) { + if (tp->tg3_flags & TG3_FLAG_PCIX_MODE) { u16 pcix_cmd; pci_read_config_word(tp->pdev, tp->pcix_cap + PCI_X_CMD, @@ -5788,11 +5977,7 @@ static int tg3_chip_reset(struct tg3 *tp) tg3_save_pci_state(tp); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) + (tp->tg3_flags3 & TG3_FLG3_5755_PLUS)) tw32(GRC_FASTBOOT_PC, 0); /* @@ -5871,7 +6056,7 @@ static int tg3_chip_reset(struct tg3 *tp) udelay(120); - if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) { + if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) && tp->pcie_cap) { if (tp->pci_chip_rev_id == CHIPREV_ID_5750_A0) { int i; u32 cfg_val; @@ -5884,8 +6069,23 @@ static int tg3_chip_reset(struct tg3 *tp) pci_write_config_dword(tp->pdev, 0xc4, cfg_val | (1 << 15)); } - /* Set PCIE max payload size and clear error status. */ - pci_write_config_dword(tp->pdev, 0xd8, 0xf5000); + + /* Set PCIE max payload size to 128 bytes and + * clear the "no snoop" and "relaxed ordering" bits. + */ + pci_write_config_word(tp->pdev, + tp->pcie_cap + PCI_EXP_DEVCTL, + 0); + + pcie_set_readrq(tp->pdev, 4096); + + /* Clear error status */ + pci_write_config_word(tp->pdev, + tp->pcie_cap + PCI_EXP_DEVSTA, + PCI_EXP_DEVSTA_CED | + PCI_EXP_DEVSTA_NFED | + PCI_EXP_DEVSTA_FED | + PCI_EXP_DEVSTA_URD); } tg3_restore_pci_state(tp); @@ -6883,43 +7083,6 @@ static int tg3_load_tso_firmware(struct tg3 *tp) } -/* tp->lock is held. */ -static void __tg3_set_mac_addr(struct tg3 *tp, int skip_mac_1) -{ - u32 addr_high, addr_low; - int i; - - addr_high = ((tp->dev->dev_addr[0] << 8) | - tp->dev->dev_addr[1]); - addr_low = ((tp->dev->dev_addr[2] << 24) | - (tp->dev->dev_addr[3] << 16) | - (tp->dev->dev_addr[4] << 8) | - (tp->dev->dev_addr[5] << 0)); - for (i = 0; i < 4; i++) { - if (i == 1 && skip_mac_1) - continue; - tw32(MAC_ADDR_0_HIGH + (i * 8), addr_high); - tw32(MAC_ADDR_0_LOW + (i * 8), addr_low); - } - - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) { - for (i = 0; i < 12; i++) { - tw32(MAC_EXTADDR_0_HIGH + (i * 8), addr_high); - tw32(MAC_EXTADDR_0_LOW + (i * 8), addr_low); - } - } - - addr_high = (tp->dev->dev_addr[0] + - tp->dev->dev_addr[1] + - tp->dev->dev_addr[2] + - tp->dev->dev_addr[3] + - tp->dev->dev_addr[4] + - tp->dev->dev_addr[5]) & - TX_BACKOFF_SEED_MASK; - tw32(MAC_TX_BACKOFF_SEED, addr_high); -} - static int tg3_set_mac_addr(struct net_device *dev, void *p) { struct tg3 *tp = netdev_priv(dev); @@ -7024,8 +7187,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tg3_write_sig_legacy(tp, RESET_KIND_INIT); - if (tp->pci_chip_rev_id == CHIPREV_ID_5784_A0 || - tp->pci_chip_rev_id == CHIPREV_ID_5784_A1) { + if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX) { val = tr32(TG3_CPMU_CTRL); val &= ~(CPMU_CTRL_LINK_AWARE_MODE | CPMU_CTRL_LINK_IDLE_MODE); tw32(TG3_CPMU_CTRL, val); @@ -7091,8 +7253,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) return err; if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785) { + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761) { /* This value is determined during the probe time DMA * engine test, tg3_test_dma. */ @@ -7332,7 +7493,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) RDMAC_MODE_LNGREAD_ENAB); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) rdmac_mode |= RDMAC_MODE_BD_SBD_CRPT_ENAB | RDMAC_MODE_MBUF_RBD_CRPT_ENAB | RDMAC_MODE_MBUF_SBD_CRPT_ENAB; @@ -7354,7 +7516,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) rdmac_mode |= RDMAC_MODE_FIFO_LONG_BURST; if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) - rdmac_mode |= (1 << 27); + rdmac_mode |= RDMAC_MODE_IPV4_LSO_EN; + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) + rdmac_mode |= RDMAC_MODE_IPV6_LSO_EN; /* Receive/send statistics. */ if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) { @@ -7501,11 +7667,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) } /* Enable host coalescing bug fix */ - if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) || - (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) || - (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) || - (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) || - (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)) + if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS) val |= WDMAC_MODE_STATUS_TAG_FIX; tw32_f(WDMAC_MODE, val); @@ -7566,10 +7728,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) udelay(100); tp->rx_mode = RX_MODE_ENABLE; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) + if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS) tp->rx_mode |= RX_MODE_IPV6_CSUM_ENABLE; tw32_f(MAC_RX_MODE, tp->rx_mode); @@ -9066,7 +9225,8 @@ static void tg3_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) else wol->supported = 0; wol->wolopts = 0; - if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE) + if ((tp->tg3_flags & TG3_FLAG_WOL_ENABLE) && + device_can_wakeup(&tp->pdev->dev)) wol->wolopts = WAKE_MAGIC; memset(&wol->sopass, 0, sizeof(wol->sopass)); } @@ -9116,14 +9276,15 @@ static int tg3_set_tso(struct net_device *dev, u32 value) return -EINVAL; return 0; } - if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) && - (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)) { + if ((dev->features & NETIF_F_IPV6_CSUM) && + (tp->tg3_flags2 & TG3_FLG2_HW_TSO_2)) { if (value) { dev->features |= NETIF_F_TSO6; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 && GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) dev->features |= NETIF_F_TSO_ECN; } else dev->features &= ~(NETIF_F_TSO6 | NETIF_F_TSO_ECN); @@ -9238,12 +9399,12 @@ static void tg3_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam epause->autoneg = (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) != 0; - if (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_RX) + if (tp->link_config.active_flowctrl & FLOW_CTRL_RX) epause->rx_pause = 1; else epause->rx_pause = 0; - if (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_TX) + if (tp->link_config.active_flowctrl & FLOW_CTRL_TX) epause->tx_pause = 1; else epause->tx_pause = 0; @@ -9294,14 +9455,14 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam } } else { if (epause->rx_pause) - tp->link_config.flowctrl |= TG3_FLOW_CTRL_RX; + tp->link_config.flowctrl |= FLOW_CTRL_RX; else - tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_RX; + tp->link_config.flowctrl &= ~FLOW_CTRL_RX; if (epause->tx_pause) - tp->link_config.flowctrl |= TG3_FLOW_CTRL_TX; + tp->link_config.flowctrl |= FLOW_CTRL_TX; else - tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_TX; + tp->link_config.flowctrl &= ~FLOW_CTRL_TX; if (netif_running(dev)) tg3_setup_flow_control(tp, 0, 0); @@ -9321,13 +9482,13 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam else tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG; if (epause->rx_pause) - tp->link_config.flowctrl |= TG3_FLOW_CTRL_RX; + tp->link_config.flowctrl |= FLOW_CTRL_RX; else - tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_RX; + tp->link_config.flowctrl &= ~FLOW_CTRL_RX; if (epause->tx_pause) - tp->link_config.flowctrl |= TG3_FLOW_CTRL_TX; + tp->link_config.flowctrl |= FLOW_CTRL_TX; else - tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_TX; + tp->link_config.flowctrl &= ~FLOW_CTRL_TX; if (netif_running(dev)) { tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); @@ -9378,11 +9539,7 @@ static int tg3_set_tx_csum(struct net_device *dev, u32 data) return 0; } - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) + if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS) ethtool_op_set_tx_ipv6_csum(dev, data); else ethtool_op_set_tx_csum(dev, data); @@ -9899,18 +10056,13 @@ static int tg3_test_memory(struct tg3 *tp) int err = 0; int i; - if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) { - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) - mem_tbl = mem_tbl_5755; - else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) - mem_tbl = mem_tbl_5906; - else - mem_tbl = mem_tbl_5705; - } else + if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS) + mem_tbl = mem_tbl_5755; + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) + mem_tbl = mem_tbl_5906; + else if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) + mem_tbl = mem_tbl_5705; + else mem_tbl = mem_tbl_570x; for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) { @@ -10110,9 +10262,11 @@ static int tg3_test_loopback(struct tg3 *tp) if (err) return TG3_LOOPBACK_FAILED; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) { + /* Turn off gphy autopowerdown. */ + if (tp->tg3_flags3 & TG3_FLG3_PHY_ENABLE_APD) + tg3_phy_toggle_apd(tp, false); + + if (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) { int i; u32 status; @@ -10139,9 +10293,7 @@ static int tg3_test_loopback(struct tg3 *tp) if (tg3_run_loopback(tp, TG3_MAC_LOOPBACK)) err |= TG3_MAC_LOOPBACK_FAILED; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) { + if (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) { tw32(TG3_CPMU_CTRL, cpmuctrl); /* Release the mutex */ @@ -10154,6 +10306,10 @@ static int tg3_test_loopback(struct tg3 *tp) err |= TG3_PHY_LOOPBACK_FAILED; } + /* Re-enable gphy autopowerdown. */ + if (tp->tg3_flags3 & TG3_FLG3_PHY_ENABLE_APD) + tg3_phy_toggle_apd(tp, true); + return err; } @@ -10756,6 +10912,102 @@ static void __devinit tg3_get_5906_nvram_info(struct tg3 *tp) tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE; } +static void __devinit tg3_get_57780_nvram_info(struct tg3 *tp) +{ + u32 nvcfg1; + + nvcfg1 = tr32(NVRAM_CFG1); + + switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) { + case FLASH_5787VENDOR_ATMEL_EEPROM_376KHZ: + case FLASH_5787VENDOR_MICRO_EEPROM_376KHZ: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE; + + nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS; + tw32(NVRAM_CFG1, nvcfg1); + return; + case FLASH_5752VENDOR_ATMEL_FLASH_BUFFERED: + case FLASH_57780VENDOR_ATMEL_AT45DB011D: + case FLASH_57780VENDOR_ATMEL_AT45DB011B: + case FLASH_57780VENDOR_ATMEL_AT45DB021D: + case FLASH_57780VENDOR_ATMEL_AT45DB021B: + case FLASH_57780VENDOR_ATMEL_AT45DB041D: + case FLASH_57780VENDOR_ATMEL_AT45DB041B: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->tg3_flags2 |= TG3_FLG2_FLASH; + + switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) { + case FLASH_5752VENDOR_ATMEL_FLASH_BUFFERED: + case FLASH_57780VENDOR_ATMEL_AT45DB011D: + case FLASH_57780VENDOR_ATMEL_AT45DB011B: + tp->nvram_size = TG3_NVRAM_SIZE_128KB; + break; + case FLASH_57780VENDOR_ATMEL_AT45DB021D: + case FLASH_57780VENDOR_ATMEL_AT45DB021B: + tp->nvram_size = TG3_NVRAM_SIZE_256KB; + break; + case FLASH_57780VENDOR_ATMEL_AT45DB041D: + case FLASH_57780VENDOR_ATMEL_AT45DB041B: + tp->nvram_size = TG3_NVRAM_SIZE_512KB; + break; + } + break; + case FLASH_5752VENDOR_ST_M45PE10: + case FLASH_5752VENDOR_ST_M45PE20: + case FLASH_5752VENDOR_ST_M45PE40: + tp->nvram_jedecnum = JEDEC_ST; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->tg3_flags2 |= TG3_FLG2_FLASH; + + switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) { + case FLASH_5752VENDOR_ST_M45PE10: + tp->nvram_size = TG3_NVRAM_SIZE_128KB; + break; + case FLASH_5752VENDOR_ST_M45PE20: + tp->nvram_size = TG3_NVRAM_SIZE_256KB; + break; + case FLASH_5752VENDOR_ST_M45PE40: + tp->nvram_size = TG3_NVRAM_SIZE_512KB; + break; + } + break; + default: + return; + } + + switch (nvcfg1 & NVRAM_CFG1_5752PAGE_SIZE_MASK) { + case FLASH_5752PAGE_SIZE_256: + tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; + tp->nvram_pagesize = 256; + break; + case FLASH_5752PAGE_SIZE_512: + tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; + tp->nvram_pagesize = 512; + break; + case FLASH_5752PAGE_SIZE_1K: + tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; + tp->nvram_pagesize = 1024; + break; + case FLASH_5752PAGE_SIZE_2K: + tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; + tp->nvram_pagesize = 2048; + break; + case FLASH_5752PAGE_SIZE_4K: + tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; + tp->nvram_pagesize = 4096; + break; + case FLASH_5752PAGE_SIZE_264: + tp->nvram_pagesize = 264; + break; + case FLASH_5752PAGE_SIZE_528: + tp->nvram_pagesize = 528; + break; + } +} + /* Chips other than 5700/5701 use the NVRAM for fetching info. */ static void __devinit tg3_nvram_init(struct tg3 *tp) { @@ -10796,6 +11048,8 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) tg3_get_5761_nvram_info(tp); else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) tg3_get_5906_nvram_info(tp); + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) + tg3_get_57780_nvram_info(tp); else tg3_get_nvram_info(tp); @@ -11116,12 +11370,8 @@ static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len, if (i == (len - 4)) nvram_cmd |= NVRAM_CMD_LAST; - if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752) && - (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5755) && - (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787) && - (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784) && - (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761) && - (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785) && + if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752 && + !(tp->tg3_flags3 & TG3_FLG3_5755_PLUS) && (tp->nvram_jedecnum == JEDEC_ST) && (nvram_cmd & NVRAM_CMD_FIRST)) { @@ -11296,10 +11546,9 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) if (val & VCPU_CFGSHDW_ASPM_DBNC) tp->tg3_flags |= TG3_FLAG_ASPM_WORKAROUND; if ((val & VCPU_CFGSHDW_WOL_ENABLE) && - (val & VCPU_CFGSHDW_WOL_MAGPKT) && - device_may_wakeup(&tp->pdev->dev)) + (val & VCPU_CFGSHDW_WOL_MAGPKT)) tp->tg3_flags |= TG3_FLAG_WOL_ENABLE; - return; + goto done; } tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val); @@ -11421,15 +11670,17 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) tp->tg3_flags2 |= TG3_FLG2_ASF_NEW_HANDSHAKE; } - if (nic_cfg & NIC_SRAM_DATA_CFG_APE_ENABLE) + + if ((nic_cfg & NIC_SRAM_DATA_CFG_APE_ENABLE) && + (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)) tp->tg3_flags3 |= TG3_FLG3_ENABLE_APE; + if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES && !(nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL)) tp->tg3_flags &= ~TG3_FLAG_WOL_CAP; if ((tp->tg3_flags & TG3_FLAG_WOL_CAP) && - (nic_cfg & NIC_SRAM_DATA_CFG_WOL_ENABLE) && - device_may_wakeup(&tp->pdev->dev)) + (nic_cfg & NIC_SRAM_DATA_CFG_WOL_ENABLE)) tp->tg3_flags |= TG3_FLAG_WOL_ENABLE; if (cfg2 & (1 << 17)) @@ -11440,6 +11691,11 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) if (cfg2 & (1 << 18)) tp->tg3_flags2 |= TG3_FLG2_SERDES_PREEMPHASIS; + if (((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 && + GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX)) && + (cfg2 & NIC_SRAM_DATA_CFG_2_APD_EN)) + tp->tg3_flags3 |= TG3_FLG3_PHY_ENABLE_APD; + if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) { u32 cfg3; @@ -11455,6 +11711,10 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) if (cfg4 & NIC_SRAM_RGMII_EXT_IBND_TX_EN) tp->tg3_flags3 |= TG3_FLG3_RGMII_EXT_IBND_TX_EN; } +done: + device_init_wakeup(&tp->pdev->dev, tp->tg3_flags & TG3_FLAG_WOL_CAP); + device_set_wakeup_enable(&tp->pdev->dev, + tp->tg3_flags & TG3_FLAG_WOL_ENABLE); } static int __devinit tg3_issue_otp_command(struct tg3 *tp, u32 cmd) @@ -11751,6 +12011,51 @@ static int __devinit tg3_fw_img_is_valid(struct tg3 *tp, u32 offset) return 1; } +static void __devinit tg3_read_sb_ver(struct tg3 *tp, u32 val) +{ + u32 offset, major, minor, build; + + tp->fw_ver[0] = 's'; + tp->fw_ver[1] = 'b'; + tp->fw_ver[2] = '\0'; + + if ((val & TG3_EEPROM_SB_FORMAT_MASK) != TG3_EEPROM_SB_FORMAT_1) + return; + + switch (val & TG3_EEPROM_SB_REVISION_MASK) { + case TG3_EEPROM_SB_REVISION_0: + offset = TG3_EEPROM_SB_F1R0_EDH_OFF; + break; + case TG3_EEPROM_SB_REVISION_2: + offset = TG3_EEPROM_SB_F1R2_EDH_OFF; + break; + case TG3_EEPROM_SB_REVISION_3: + offset = TG3_EEPROM_SB_F1R3_EDH_OFF; + break; + default: + return; + } + + if (tg3_nvram_read_swab(tp, offset, &val)) + return; + + build = (val & TG3_EEPROM_SB_EDH_BLD_MASK) >> + TG3_EEPROM_SB_EDH_BLD_SHFT; + major = (val & TG3_EEPROM_SB_EDH_MAJ_MASK) >> + TG3_EEPROM_SB_EDH_MAJ_SHFT; + minor = val & TG3_EEPROM_SB_EDH_MIN_MASK; + + if (minor > 99 || build > 26) + return; + + snprintf(&tp->fw_ver[2], 30, " v%d.%02d", major, minor); + + if (build > 0) { + tp->fw_ver[8] = 'a' + build - 1; + tp->fw_ver[9] = '\0'; + } +} + static void __devinit tg3_read_fw_ver(struct tg3 *tp) { u32 val, offset, start; @@ -11760,8 +12065,12 @@ static void __devinit tg3_read_fw_ver(struct tg3 *tp) if (tg3_nvram_read_swab(tp, 0, &val)) return; - if (val != TG3_EEPROM_MAGIC) + if (val != TG3_EEPROM_MAGIC) { + if ((val & TG3_EEPROM_MAGIC_FW_MSK) == TG3_EEPROM_MAGIC_FW) + tg3_read_sb_ver(tp, val); + return; + } if (tg3_nvram_read_swab(tp, 0xc, &offset) || tg3_nvram_read_swab(tp, 0x4, &start)) @@ -11849,11 +12158,10 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) { }, }; u32 misc_ctrl_reg; - u32 cacheline_sz_reg; u32 pci_state_reg, grc_misc_cfg; u32 val; u16 pci_cmd; - int err, pcie_cap; + int err; /* Force memory write invalidate off. If we leave it on, * then on 5700_BX chips we have to enable a workaround. @@ -11882,7 +12190,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) pci_read_config_dword(tp->pdev, TG3PCI_PRODID_ASICREV, &prod_id_asic_rev); - tp->pci_chip_rev_id = prod_id_asic_rev & PROD_ID_ASIC_REV_MASK; + tp->pci_chip_rev_id = prod_id_asic_rev; } /* Wrong chip ID in 5752 A0. This code can be removed later @@ -12019,26 +12327,23 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL, tp->misc_host_ctrl); - pci_read_config_dword(tp->pdev, TG3PCI_CACHELINESZ, - &cacheline_sz_reg); - - tp->pci_cacheline_sz = (cacheline_sz_reg >> 0) & 0xff; - tp->pci_lat_timer = (cacheline_sz_reg >> 8) & 0xff; - tp->pci_hdr_type = (cacheline_sz_reg >> 16) & 0xff; - tp->pci_bist = (cacheline_sz_reg >> 24) & 0xff; - if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) || (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714)) tp->pdev_peer = tg3_find_peer(tp); - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || + /* Intentionally exclude ASIC_REV_5906 */ + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) + tp->tg3_flags3 |= TG3_FLG3_5755_PLUS; + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 || + (tp->tg3_flags3 & TG3_FLG3_5755_PLUS) || (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) tp->tg3_flags2 |= TG3_FLG2_5750_PLUS; @@ -12046,6 +12351,18 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)) tp->tg3_flags2 |= TG3_FLG2_5705_PLUS; + /* 5700 B0 chips do not support checksumming correctly due + * to hardware bugs. + */ + if (tp->pci_chip_rev_id == CHIPREV_ID_5700_B0) + tp->tg3_flags |= TG3_FLAG_BROKEN_CHECKSUMS; + else { + tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS; + tp->dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; + if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS) + tp->dev->features |= NETIF_F_IPV6_CSUM; + } + if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) { tp->tg3_flags |= TG3_FLAG_SUPPORT_MSI; if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_AX || @@ -12055,11 +12372,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->pdev_peer == tp->pdev)) tp->tg3_flags &= ~TG3_FLAG_SUPPORT_MSI; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || + if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { tp->tg3_flags2 |= TG3_FLG2_HW_TSO_2; tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI; @@ -12076,21 +12389,41 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) tp->tg3_flags2 |= TG3_FLG2_JUMBO_CAPABLE; - pcie_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_EXP); - if (pcie_cap != 0) { + pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE, + &pci_state_reg); + + tp->pcie_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_EXP); + if (tp->pcie_cap != 0) { + u16 lnkctl; + tp->tg3_flags2 |= TG3_FLG2_PCI_EXPRESS; pcie_set_readrq(tp->pdev, 4096); - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { - u16 lnkctl; - - pci_read_config_word(tp->pdev, - pcie_cap + PCI_EXP_LNKCTL, - &lnkctl); - if (lnkctl & PCI_EXP_LNKCTL_CLKREQ_EN) + pci_read_config_word(tp->pdev, + tp->pcie_cap + PCI_EXP_LNKCTL, + &lnkctl); + if (lnkctl & PCI_EXP_LNKCTL_CLKREQ_EN) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) tp->tg3_flags2 &= ~TG3_FLG2_HW_TSO_2; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) + tp->tg3_flags3 |= TG3_FLG3_CLKREQ_BUG; } + } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) { + tp->tg3_flags2 |= TG3_FLG2_PCI_EXPRESS; + } else if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) || + (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) { + tp->pcix_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_PCIX); + if (!tp->pcix_cap) { + printk(KERN_ERR PFX "Cannot find PCI-X " + "capability, aborting.\n"); + return -EIO; + } + + if (!(pci_state_reg & PCISTATE_CONV_PCI_MODE)) + tp->tg3_flags |= TG3_FLAG_PCIX_MODE; } /* If we have an AMD 762 or VIA K8T800 chipset, write @@ -12103,42 +12436,29 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) !(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)) tp->tg3_flags |= TG3_FLAG_MBOX_WRITE_REORDER; + pci_read_config_byte(tp->pdev, PCI_CACHE_LINE_SIZE, + &tp->pci_cacheline_sz); + pci_read_config_byte(tp->pdev, PCI_LATENCY_TIMER, + &tp->pci_lat_timer); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 && tp->pci_lat_timer < 64) { tp->pci_lat_timer = 64; - - cacheline_sz_reg = ((tp->pci_cacheline_sz & 0xff) << 0); - cacheline_sz_reg |= ((tp->pci_lat_timer & 0xff) << 8); - cacheline_sz_reg |= ((tp->pci_hdr_type & 0xff) << 16); - cacheline_sz_reg |= ((tp->pci_bist & 0xff) << 24); - - pci_write_config_dword(tp->pdev, TG3PCI_CACHELINESZ, - cacheline_sz_reg); - } - - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) || - (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) { - tp->pcix_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_PCIX); - if (!tp->pcix_cap) { - printk(KERN_ERR PFX "Cannot find PCI-X " - "capability, aborting.\n"); - return -EIO; - } + pci_write_config_byte(tp->pdev, PCI_LATENCY_TIMER, + tp->pci_lat_timer); } - pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE, - &pci_state_reg); - - if (tp->pcix_cap && (pci_state_reg & PCISTATE_CONV_PCI_MODE) == 0) { - tp->tg3_flags |= TG3_FLAG_PCIX_MODE; + if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5700_BX) { + /* 5700 BX chips need to have their TX producer index + * mailboxes written twice to workaround a bug. + */ + tp->tg3_flags |= TG3_FLAG_TXD_MBOX_HWBUG; - /* If this is a 5700 BX chipset, and we are in PCI-X - * mode, enable register write workaround. + /* If we are in PCI-X mode, enable register write workaround. * * The workaround is to use indirect register accesses * for all chip writes not to mailbox registers. */ - if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5700_BX) { + if (tp->tg3_flags & TG3_FLAG_PCIX_MODE) { u32 pm_reg; tp->tg3_flags |= TG3_FLAG_PCIX_TARGET_HWBUG; @@ -12163,12 +12483,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) } } - /* 5700 BX chips need to have their TX producer index mailboxes - * written twice to workaround a bug. - */ - if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5700_BX) - tp->tg3_flags |= TG3_FLAG_TXD_MBOX_HWBUG; - if ((pci_state_reg & PCISTATE_BUS_SPEED_HIGH) != 0) tp->tg3_flags |= TG3_FLAG_PCI_HIGH_SPEED; if ((pci_state_reg & PCISTATE_BUS_32BIT) != 0) @@ -12263,16 +12577,10 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) { + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) tp->tg3_flags |= TG3_FLAG_CPMU_PRESENT; - if (tp->pci_chip_rev_id == CHIPREV_ID_5784_A0 || - tp->pci_chip_rev_id == CHIPREV_ID_5784_A1 || - tp->pci_chip_rev_id == CHIPREV_ID_5761_A0 || - tp->pci_chip_rev_id == CHIPREV_ID_5761_A1) - tp->tg3_flags3 |= TG3_FLG3_5761_5784_AX_FIXES; - } - /* Set up tp->grc_local_ctrl before calling tg3_set_power_state(). * GPIO1 driven high will bring 5700's external PHY out of reset. * It is also used as eeprom write protect on LOMs. @@ -12288,7 +12596,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_OE3; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_UART_SEL; if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5761) { @@ -12308,12 +12617,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) return err; } - /* 5700 B0 chips do not support checksumming correctly due - * to hardware bugs. - */ - if (tp->pci_chip_rev_id == CHIPREV_ID_5700_B0) - tp->tg3_flags |= TG3_FLAG_BROKEN_CHECKSUMS; - /* Derive initial jumbo mode from MTU assigned in * ether_setup() via the alloc_etherdev() call */ @@ -12346,7 +12649,10 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0) tp->tg3_flags2 |= TG3_FLG2_PHY_5704_A0_BUG; - if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) { + if ((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57780) { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || @@ -12356,8 +12662,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->tg3_flags2 |= TG3_FLG2_PHY_JITTER_BUG; if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5755M) tp->tg3_flags2 |= TG3_FLG2_PHY_ADJUST_TRIM; - } else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785) + } else tp->tg3_flags2 |= TG3_FLG2_PHY_BER_BUG; } @@ -12378,7 +12683,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_BX) tp->coalesce_mode |= HOSTCC_MODE_32BYTE; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) tp->tg3_flags3 |= TG3_FLG3_USE_PHYLIB; err = tg3_mdio_init(tp); @@ -12463,6 +12769,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5751F || tp->pdev->device == PCI_DEVICE_ID_TIGON3_5753F || tp->pdev->device == PCI_DEVICE_ID_TIGON3_5787F)) || + tp->pdev->device == TG3PCI_DEVICE_TIGON3_57790 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) tp->tg3_flags |= TG3_FLAG_10_100_ONLY; @@ -12512,20 +12819,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) else tp->tg3_flags &= ~TG3_FLAG_POLL_SERDES; - /* All chips before 5787 can get confused if TX buffers - * straddle the 4GB address boundary in some cases. - */ - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) - tp->dev->hard_start_xmit = tg3_start_xmit; - else - tp->dev->hard_start_xmit = tg3_start_xmit_dma_bug; - - tp->rx_offset = 2; + tp->rx_offset = NET_IP_ALIGN; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 && (tp->tg3_flags & TG3_FLAG_PCIX_MODE) != 0) tp->rx_offset = 0; @@ -13241,18 +13535,53 @@ static void __devinit tg3_init_coal(struct tg3 *tp) } } +static const struct net_device_ops tg3_netdev_ops = { + .ndo_open = tg3_open, + .ndo_stop = tg3_close, + .ndo_start_xmit = tg3_start_xmit, + .ndo_get_stats = tg3_get_stats, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = tg3_set_rx_mode, + .ndo_set_mac_address = tg3_set_mac_addr, + .ndo_do_ioctl = tg3_ioctl, + .ndo_tx_timeout = tg3_tx_timeout, + .ndo_change_mtu = tg3_change_mtu, +#if TG3_VLAN_TAG_USED + .ndo_vlan_rx_register = tg3_vlan_rx_register, +#endif +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = tg3_poll_controller, +#endif +}; + +static const struct net_device_ops tg3_netdev_ops_dma_bug = { + .ndo_open = tg3_open, + .ndo_stop = tg3_close, + .ndo_start_xmit = tg3_start_xmit_dma_bug, + .ndo_get_stats = tg3_get_stats, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = tg3_set_rx_mode, + .ndo_set_mac_address = tg3_set_mac_addr, + .ndo_do_ioctl = tg3_ioctl, + .ndo_tx_timeout = tg3_tx_timeout, + .ndo_change_mtu = tg3_change_mtu, +#if TG3_VLAN_TAG_USED + .ndo_vlan_rx_register = tg3_vlan_rx_register, +#endif +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = tg3_poll_controller, +#endif +}; + static int __devinit tg3_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { static int tg3_version_printed = 0; - resource_size_t tg3reg_base; - unsigned long tg3reg_len; struct net_device *dev; struct tg3 *tp; int err, pm_cap; char str[40]; u64 dma_mask, persist_dma_mask; - DECLARE_MAC_BUF(mac); if (tg3_version_printed++ == 0) printk(KERN_INFO "%s", version); @@ -13264,13 +13593,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, return err; } - if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { - printk(KERN_ERR PFX "Cannot find proper PCI device " - "base address, aborting.\n"); - err = -ENODEV; - goto err_out_disable_pdev; - } - err = pci_request_regions(pdev, DRV_MODULE_NAME); if (err) { printk(KERN_ERR PFX "Cannot obtain PCI resources, " @@ -13289,9 +13611,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, goto err_out_free_res; } - tg3reg_base = pci_resource_start(pdev, 0); - tg3reg_len = pci_resource_len(pdev, 0); - dev = alloc_etherdev(sizeof(*tp)); if (!dev) { printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n"); @@ -13303,7 +13622,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, #if TG3_VLAN_TAG_USED dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - dev->vlan_rx_register = tg3_vlan_rx_register; #endif tp = netdev_priv(dev); @@ -13343,7 +13661,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, spin_lock_init(&tp->indirect_lock); INIT_WORK(&tp->reset_task, tg3_reset_task); - tp->regs = ioremap_nocache(tg3reg_base, tg3reg_len); + tp->regs = pci_ioremap_bar(pdev, BAR_0); if (!tp->regs) { printk(KERN_ERR PFX "Cannot map device registers, " "aborting.\n"); @@ -13357,21 +13675,10 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, tp->rx_jumbo_pending = TG3_DEF_RX_JUMBO_RING_PENDING; tp->tx_pending = TG3_DEF_TX_RING_PENDING; - dev->open = tg3_open; - dev->stop = tg3_close; - dev->get_stats = tg3_get_stats; - dev->set_multicast_list = tg3_set_rx_mode; - dev->set_mac_address = tg3_set_mac_addr; - dev->do_ioctl = tg3_ioctl; - dev->tx_timeout = tg3_tx_timeout; netif_napi_add(dev, &tp->napi, tg3_poll, 64); dev->ethtool_ops = &tg3_ethtool_ops; dev->watchdog_timeo = TG3_TX_TIMEOUT; - dev->change_mtu = tg3_change_mtu; dev->irq = pdev->irq; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = tg3_poll_controller; -#endif err = tg3_get_invariants(tp); if (err) { @@ -13380,6 +13687,13 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, goto err_out_iounmap; } + if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) + dev->netdev_ops = &tg3_netdev_ops; + else + dev->netdev_ops = &tg3_netdev_ops_dma_bug; + + /* The EPB bridge inside 5714, 5715, and 5780 and any * device behind the EPB cannot support DMA addresses > 40-bit. * On 64-bit systems with IOMMU, use 40-bit dma_mask. @@ -13439,14 +13753,16 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, * is off by default, but can be enabled using ethtool. */ if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) { - dev->features |= NETIF_F_TSO; - if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) && - (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)) + if (dev->features & NETIF_F_IP_CSUM) + dev->features |= NETIF_F_TSO; + if ((dev->features & NETIF_F_IPV6_CSUM) && + (tp->tg3_flags2 & TG3_FLG2_HW_TSO_2)) dev->features |= NETIF_F_TSO6; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 && GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) dev->features |= NETIF_F_TSO_ECN; } @@ -13466,17 +13782,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, } if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) { - if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) { - printk(KERN_ERR PFX "Cannot find proper PCI device " - "base address for APE, aborting.\n"); - err = -ENODEV; - goto err_out_iounmap; - } - - tg3reg_base = pci_resource_start(pdev, 2); - tg3reg_len = pci_resource_len(pdev, 2); - - tp->aperegs = ioremap_nocache(tg3reg_base, tg3reg_len); + tp->aperegs = pci_ioremap_bar(pdev, BAR_2); if (!tp->aperegs) { printk(KERN_ERR PFX "Cannot map APE registers, " "aborting.\n"); @@ -13504,25 +13810,9 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, goto err_out_apeunmap; } - /* Tigon3 can do ipv4 only... and some chips have buggy - * checksumming. - */ - if ((tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) == 0) { - dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) - dev->features |= NETIF_F_IPV6_CSUM; - - tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS; - } else - tp->tg3_flags &= ~TG3_FLAG_RX_CHECKSUMS; - /* flow control autonegotiation is default behavior */ tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG; - tp->link_config.flowctrl = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX; + tp->link_config.flowctrl = FLOW_CTRL_TX | FLOW_CTRL_RX; tg3_init_coal(tp); @@ -13535,26 +13825,34 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, goto err_out_apeunmap; } - printk(KERN_INFO "%s: Tigon3 [partno(%s) rev %04x PHY(%s)] " - "(%s) %s Ethernet %s\n", + printk(KERN_INFO "%s: Tigon3 [partno(%s) rev %04x] (%s) MAC address %pM\n", dev->name, tp->board_part_number, tp->pci_chip_rev_id, - tg3_phy_string(tp), tg3_bus_string(tp, str), - ((tp->tg3_flags & TG3_FLAG_10_100_ONLY) ? "10/100Base-TX" : - ((tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) ? "1000Base-SX" : - "10/100/1000Base-T")), - print_mac(mac, dev->dev_addr)); + dev->dev_addr); - printk(KERN_INFO "%s: RXcsums[%d] LinkChgREG[%d] " - "MIirq[%d] ASF[%d] WireSpeed[%d] TSOcap[%d]\n", + if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) + printk(KERN_INFO + "%s: attached PHY driver [%s] (mii_bus:phy_addr=%s)\n", + tp->dev->name, + tp->mdio_bus->phy_map[PHY_ADDR]->drv->name, + dev_name(&tp->mdio_bus->phy_map[PHY_ADDR]->dev)); + else + printk(KERN_INFO + "%s: attached PHY is %s (%s Ethernet) (WireSpeed[%d])\n", + tp->dev->name, tg3_phy_string(tp), + ((tp->tg3_flags & TG3_FLAG_10_100_ONLY) ? "10/100Base-TX" : + ((tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) ? "1000Base-SX" : + "10/100/1000Base-T")), + (tp->tg3_flags2 & TG3_FLG2_NO_ETH_WIRE_SPEED) == 0); + + printk(KERN_INFO "%s: RXcsums[%d] LinkChgREG[%d] MIirq[%d] ASF[%d] TSOcap[%d]\n", dev->name, (tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) != 0, (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) != 0, (tp->tg3_flags & TG3_FLAG_USE_MI_INTERRUPT) != 0, (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) != 0, - (tp->tg3_flags2 & TG3_FLG2_NO_ETH_WIRE_SPEED) == 0, (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) != 0); printk(KERN_INFO "%s: dma_rwctrl[%08x] dma_mask[%d-bit]\n", dev->name, tp->dma_rwctrl, diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index be252abe8985faf0fb2d7c75bec2d10095ef4f7c..8936edfb0438c992c6cf7ceeb8d6880aa0fa98fe 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -38,26 +38,13 @@ #define TG3PCI_DEVICE_TIGON3_2 0x1645 /* BCM5701 */ #define TG3PCI_DEVICE_TIGON3_3 0x1646 /* BCM5702 */ #define TG3PCI_DEVICE_TIGON3_4 0x1647 /* BCM5703 */ -#define TG3PCI_COMMAND 0x00000004 -#define TG3PCI_STATUS 0x00000006 -#define TG3PCI_CCREVID 0x00000008 -#define TG3PCI_CACHELINESZ 0x0000000c -#define TG3PCI_LATTIMER 0x0000000d -#define TG3PCI_HEADERTYPE 0x0000000e -#define TG3PCI_BIST 0x0000000f -#define TG3PCI_BASE0_LOW 0x00000010 -#define TG3PCI_BASE0_HIGH 0x00000014 -/* 0x18 --> 0x2c unused */ -#define TG3PCI_SUBSYSVENID 0x0000002c -#define TG3PCI_SUBSYSID 0x0000002e -#define TG3PCI_ROMADDR 0x00000030 -#define TG3PCI_CAPLIST 0x00000034 -/* 0x35 --> 0x3c unused */ -#define TG3PCI_IRQ_LINE 0x0000003c -#define TG3PCI_IRQ_PIN 0x0000003d -#define TG3PCI_MIN_GNT 0x0000003e -#define TG3PCI_MAX_LAT 0x0000003f -/* 0x40 --> 0x64 unused */ +#define TG3PCI_DEVICE_TIGON3_5761S 0x1688 +#define TG3PCI_DEVICE_TIGON3_5761SE 0x1689 +#define TG3PCI_DEVICE_TIGON3_57780 0x1692 +#define TG3PCI_DEVICE_TIGON3_57760 0x1690 +#define TG3PCI_DEVICE_TIGON3_57790 0x1694 +#define TG3PCI_DEVICE_TIGON3_57720 0x168c +/* 0x04 --> 0x64 unused */ #define TG3PCI_MSI_DATA 0x00000064 /* 0x66 --> 0x68 unused */ #define TG3PCI_MISC_HOST_CTRL 0x00000068 @@ -108,10 +95,6 @@ #define CHIPREV_ID_5752_A1 0x6001 #define CHIPREV_ID_5714_A2 0x9002 #define CHIPREV_ID_5906_A1 0xc001 -#define CHIPREV_ID_5784_A0 0x5784000 -#define CHIPREV_ID_5784_A1 0x5784001 -#define CHIPREV_ID_5761_A0 0x5761000 -#define CHIPREV_ID_5761_A1 0x5761001 #define GET_ASIC_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 12) #define ASIC_REV_5700 0x07 #define ASIC_REV_5701 0x00 @@ -129,6 +112,7 @@ #define ASIC_REV_5784 0x5784 #define ASIC_REV_5761 0x5761 #define ASIC_REV_5785 0x5785 +#define ASIC_REV_57780 0x57780 #define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8) #define CHIPREV_5700_AX 0x70 #define CHIPREV_5700_BX 0x71 @@ -325,6 +309,7 @@ #define MAC_MODE_TDE_ENABLE 0x00200000 #define MAC_MODE_RDE_ENABLE 0x00400000 #define MAC_MODE_FHDE_ENABLE 0x00800000 +#define MAC_MODE_KEEP_FRAME_IN_WOL 0x01000000 #define MAC_MODE_APE_RX_EN 0x08000000 #define MAC_MODE_APE_TX_EN 0x10000000 #define MAC_STATUS 0x00000404 @@ -414,6 +399,7 @@ #define MI_COM_DATA_MASK 0x0000ffff #define MAC_MI_STAT 0x00000450 #define MAC_MI_STAT_LNKSTAT_ATTN_ENAB 0x00000001 +#define MAC_MI_STAT_10MBPS_MODE 0x00000002 #define MAC_MI_MODE 0x00000454 #define MAC_MI_MODE_CLK_10MHZ 0x00000001 #define MAC_MI_MODE_SHORT_PREAMBLE 0x00000002 @@ -539,6 +525,100 @@ #define MAC_PHYCFG1_TXC_DRV 0x20000000 #define MAC_PHYCFG2 0x000005a4 #define MAC_PHYCFG2_INBAND_ENABLE 0x00000001 +#define MAC_PHYCFG2_EMODE_MASK_MASK 0x000001c0 +#define MAC_PHYCFG2_EMODE_MASK_AC131 0x000000c0 +#define MAC_PHYCFG2_EMODE_MASK_50610 0x00000100 +#define MAC_PHYCFG2_EMODE_MASK_RT8211 0x00000000 +#define MAC_PHYCFG2_EMODE_MASK_RT8201 0x000001c0 +#define MAC_PHYCFG2_EMODE_COMP_MASK 0x00000e00 +#define MAC_PHYCFG2_EMODE_COMP_AC131 0x00000600 +#define MAC_PHYCFG2_EMODE_COMP_50610 0x00000400 +#define MAC_PHYCFG2_EMODE_COMP_RT8211 0x00000800 +#define MAC_PHYCFG2_EMODE_COMP_RT8201 0x00000000 +#define MAC_PHYCFG2_FMODE_MASK_MASK 0x00007000 +#define MAC_PHYCFG2_FMODE_MASK_AC131 0x00006000 +#define MAC_PHYCFG2_FMODE_MASK_50610 0x00004000 +#define MAC_PHYCFG2_FMODE_MASK_RT8211 0x00000000 +#define MAC_PHYCFG2_FMODE_MASK_RT8201 0x00007000 +#define MAC_PHYCFG2_FMODE_COMP_MASK 0x00038000 +#define MAC_PHYCFG2_FMODE_COMP_AC131 0x00030000 +#define MAC_PHYCFG2_FMODE_COMP_50610 0x00008000 +#define MAC_PHYCFG2_FMODE_COMP_RT8211 0x00038000 +#define MAC_PHYCFG2_FMODE_COMP_RT8201 0x00000000 +#define MAC_PHYCFG2_GMODE_MASK_MASK 0x001c0000 +#define MAC_PHYCFG2_GMODE_MASK_AC131 0x001c0000 +#define MAC_PHYCFG2_GMODE_MASK_50610 0x00100000 +#define MAC_PHYCFG2_GMODE_MASK_RT8211 0x00000000 +#define MAC_PHYCFG2_GMODE_MASK_RT8201 0x001c0000 +#define MAC_PHYCFG2_GMODE_COMP_MASK 0x00e00000 +#define MAC_PHYCFG2_GMODE_COMP_AC131 0x00e00000 +#define MAC_PHYCFG2_GMODE_COMP_50610 0x00000000 +#define MAC_PHYCFG2_GMODE_COMP_RT8211 0x00200000 +#define MAC_PHYCFG2_GMODE_COMP_RT8201 0x00000000 +#define MAC_PHYCFG2_ACT_MASK_MASK 0x03000000 +#define MAC_PHYCFG2_ACT_MASK_AC131 0x03000000 +#define MAC_PHYCFG2_ACT_MASK_50610 0x01000000 +#define MAC_PHYCFG2_ACT_MASK_RT8211 0x03000000 +#define MAC_PHYCFG2_ACT_MASK_RT8201 0x01000000 +#define MAC_PHYCFG2_ACT_COMP_MASK 0x0c000000 +#define MAC_PHYCFG2_ACT_COMP_AC131 0x00000000 +#define MAC_PHYCFG2_ACT_COMP_50610 0x00000000 +#define MAC_PHYCFG2_ACT_COMP_RT8211 0x00000000 +#define MAC_PHYCFG2_ACT_COMP_RT8201 0x08000000 +#define MAC_PHYCFG2_QUAL_MASK_MASK 0x30000000 +#define MAC_PHYCFG2_QUAL_MASK_AC131 0x30000000 +#define MAC_PHYCFG2_QUAL_MASK_50610 0x30000000 +#define MAC_PHYCFG2_QUAL_MASK_RT8211 0x30000000 +#define MAC_PHYCFG2_QUAL_MASK_RT8201 0x30000000 +#define MAC_PHYCFG2_QUAL_COMP_MASK 0xc0000000 +#define MAC_PHYCFG2_QUAL_COMP_AC131 0x00000000 +#define MAC_PHYCFG2_QUAL_COMP_50610 0x00000000 +#define MAC_PHYCFG2_QUAL_COMP_RT8211 0x00000000 +#define MAC_PHYCFG2_QUAL_COMP_RT8201 0x00000000 +#define MAC_PHYCFG2_50610_LED_MODES \ + (MAC_PHYCFG2_EMODE_MASK_50610 | \ + MAC_PHYCFG2_EMODE_COMP_50610 | \ + MAC_PHYCFG2_FMODE_MASK_50610 | \ + MAC_PHYCFG2_FMODE_COMP_50610 | \ + MAC_PHYCFG2_GMODE_MASK_50610 | \ + MAC_PHYCFG2_GMODE_COMP_50610 | \ + MAC_PHYCFG2_ACT_MASK_50610 | \ + MAC_PHYCFG2_ACT_COMP_50610 | \ + MAC_PHYCFG2_QUAL_MASK_50610 | \ + MAC_PHYCFG2_QUAL_COMP_50610) +#define MAC_PHYCFG2_AC131_LED_MODES \ + (MAC_PHYCFG2_EMODE_MASK_AC131 | \ + MAC_PHYCFG2_EMODE_COMP_AC131 | \ + MAC_PHYCFG2_FMODE_MASK_AC131 | \ + MAC_PHYCFG2_FMODE_COMP_AC131 | \ + MAC_PHYCFG2_GMODE_MASK_AC131 | \ + MAC_PHYCFG2_GMODE_COMP_AC131 | \ + MAC_PHYCFG2_ACT_MASK_AC131 | \ + MAC_PHYCFG2_ACT_COMP_AC131 | \ + MAC_PHYCFG2_QUAL_MASK_AC131 | \ + MAC_PHYCFG2_QUAL_COMP_AC131) +#define MAC_PHYCFG2_RTL8211C_LED_MODES \ + (MAC_PHYCFG2_EMODE_MASK_RT8211 | \ + MAC_PHYCFG2_EMODE_COMP_RT8211 | \ + MAC_PHYCFG2_FMODE_MASK_RT8211 | \ + MAC_PHYCFG2_FMODE_COMP_RT8211 | \ + MAC_PHYCFG2_GMODE_MASK_RT8211 | \ + MAC_PHYCFG2_GMODE_COMP_RT8211 | \ + MAC_PHYCFG2_ACT_MASK_RT8211 | \ + MAC_PHYCFG2_ACT_COMP_RT8211 | \ + MAC_PHYCFG2_QUAL_MASK_RT8211 | \ + MAC_PHYCFG2_QUAL_COMP_RT8211) +#define MAC_PHYCFG2_RTL8201E_LED_MODES \ + (MAC_PHYCFG2_EMODE_MASK_RT8201 | \ + MAC_PHYCFG2_EMODE_COMP_RT8201 | \ + MAC_PHYCFG2_FMODE_MASK_RT8201 | \ + MAC_PHYCFG2_FMODE_COMP_RT8201 | \ + MAC_PHYCFG2_GMODE_MASK_RT8201 | \ + MAC_PHYCFG2_GMODE_COMP_RT8201 | \ + MAC_PHYCFG2_ACT_MASK_RT8201 | \ + MAC_PHYCFG2_ACT_COMP_RT8201 | \ + MAC_PHYCFG2_QUAL_MASK_RT8201 | \ + MAC_PHYCFG2_QUAL_COMP_RT8201) #define MAC_EXT_RGMII_MODE 0x000005a8 #define MAC_RGMII_MODE_TX_ENABLE 0x00000001 #define MAC_RGMII_MODE_TX_LOWPWR 0x00000002 @@ -1104,6 +1184,8 @@ #define RDMAC_MODE_MBUF_SBD_CRPT_ENAB 0x00002000 #define RDMAC_MODE_FIFO_SIZE_128 0x00020000 #define RDMAC_MODE_FIFO_LONG_BURST 0x00030000 +#define RDMAC_MODE_IPV4_LSO_EN 0x08000000 +#define RDMAC_MODE_IPV6_LSO_EN 0x10000000 #define RDMAC_STATUS 0x00004804 #define RDMAC_STATUS_TGTABORT 0x00000004 #define RDMAC_STATUS_MSTABORT 0x00000008 @@ -1550,6 +1632,12 @@ #define FLASH_5761VENDOR_ST_A_M45PE40 0x02000000 #define FLASH_5761VENDOR_ST_A_M45PE80 0x02000002 #define FLASH_5761VENDOR_ST_A_M45PE16 0x02000003 +#define FLASH_57780VENDOR_ATMEL_AT45DB011D 0x00400000 +#define FLASH_57780VENDOR_ATMEL_AT45DB011B 0x03400000 +#define FLASH_57780VENDOR_ATMEL_AT45DB021D 0x00400002 +#define FLASH_57780VENDOR_ATMEL_AT45DB021B 0x03400002 +#define FLASH_57780VENDOR_ATMEL_AT45DB041D 0x00400001 +#define FLASH_57780VENDOR_ATMEL_AT45DB041B 0x03400001 #define NVRAM_CFG1_5752PAGE_SIZE_MASK 0x70000000 #define FLASH_5752PAGE_SIZE_256 0x00000000 #define FLASH_5752PAGE_SIZE_512 0x10000000 @@ -1557,6 +1645,7 @@ #define FLASH_5752PAGE_SIZE_2K 0x30000000 #define FLASH_5752PAGE_SIZE_4K 0x40000000 #define FLASH_5752PAGE_SIZE_264 0x50000000 +#define FLASH_5752PAGE_SIZE_528 0x60000000 #define NVRAM_CFG2 0x00007018 #define NVRAM_CFG3 0x0000701c #define NVRAM_SWARB 0x00007020 @@ -1649,6 +1738,17 @@ #define TG3_NVM_DIRTYPE_SHIFT 24 #define TG3_NVM_DIRTYPE_ASFINI 1 +#define TG3_EEPROM_SB_F1R0_EDH_OFF 0x10 +#define TG3_EEPROM_SB_F1R2_EDH_OFF 0x14 +#define TG3_EEPROM_SB_F1R2_MBA_OFF 0x10 +#define TG3_EEPROM_SB_F1R3_EDH_OFF 0x18 +#define TG3_EEPROM_SB_EDH_MAJ_MASK 0x00000700 +#define TG3_EEPROM_SB_EDH_MAJ_SHFT 8 +#define TG3_EEPROM_SB_EDH_MIN_MASK 0x000000ff +#define TG3_EEPROM_SB_EDH_BLD_MASK 0x0000f800 +#define TG3_EEPROM_SB_EDH_BLD_SHFT 11 + + /* 32K Window into NIC internal memory */ #define NIC_SRAM_WIN_BASE 0x00008000 @@ -1724,6 +1824,7 @@ #define NIC_SRAM_DATA_CFG_2 0x00000d38 +#define NIC_SRAM_DATA_CFG_2_APD_EN 0x00000400 #define SHASTA_EXT_LED_MODE_MASK 0x00018000 #define SHASTA_EXT_LED_LEGACY 0x00000000 #define SHASTA_EXT_LED_SHARED 0x00008000 @@ -1792,6 +1893,11 @@ #define MII_TG3_AUX_CTRL 0x18 /* auxilliary control register */ +#define MII_TG3_AUXCTL_PCTL_100TX_LPWR 0x0010 +#define MII_TG3_AUXCTL_PCTL_SPR_ISOLATE 0x0020 +#define MII_TG3_AUXCTL_PCTL_VREG_11V 0x0180 +#define MII_TG3_AUXCTL_SHDWSEL_PWRCTL 0x0002 + #define MII_TG3_AUXCTL_MISC_WREN 0x8000 #define MII_TG3_AUXCTL_MISC_FORCE_AMDIX 0x0200 #define MII_TG3_AUXCTL_MISC_RDSEL_MISC 0x7000 @@ -1817,12 +1923,6 @@ #define MII_TG3_ISTAT 0x1a /* IRQ status register */ #define MII_TG3_IMASK 0x1b /* IRQ mask register */ -#define MII_TG3_MISC_SHDW 0x1c -#define MII_TG3_MISC_SHDW_WREN 0x8000 -#define MII_TG3_MISC_SHDW_APD_SEL 0x2800 - -#define MII_TG3_MISC_SHDW_APD_WKTM_84MS 0x0001 - /* ISTAT/IMASK event bits */ #define MII_TG3_INT_LINKCHG 0x0002 #define MII_TG3_INT_SPEEDCHG 0x0004 @@ -1831,7 +1931,9 @@ #define MII_TG3_MISC_SHDW 0x1c #define MII_TG3_MISC_SHDW_WREN 0x8000 -#define MII_TG3_MISC_SHDW_SCR5_SEL 0x1400 + +#define MII_TG3_MISC_SHDW_APD_WKTM_84MS 0x0001 +#define MII_TG3_MISC_SHDW_APD_ENABLE 0x0020 #define MII_TG3_MISC_SHDW_APD_SEL 0x2800 #define MII_TG3_MISC_SHDW_SCR5_C125OE 0x0001 @@ -1839,9 +1941,8 @@ #define MII_TG3_MISC_SHDW_SCR5_SDTL 0x0004 #define MII_TG3_MISC_SHDW_SCR5_DLPTLM 0x0008 #define MII_TG3_MISC_SHDW_SCR5_LPED 0x0010 +#define MII_TG3_MISC_SHDW_SCR5_SEL 0x1400 -#define MII_TG3_MISC_SHDW_APD_WKTM_84MS 0x0001 -#define MII_TG3_MISC_SHDW_APD_ENABLE 0x0020 #define MII_TG3_EPHY_TEST 0x1f /* 5906 PHY register */ #define MII_TG3_EPHY_SHADOW_EN 0x80 @@ -2211,8 +2312,6 @@ struct tg3_link_config { u8 duplex; u8 autoneg; u8 flowctrl; -#define TG3_FLOW_CTRL_TX 0x01 -#define TG3_FLOW_CTRL_RX 0x02 /* Describes what we actually have. */ u8 active_flowctrl; @@ -2507,7 +2606,6 @@ struct tg3 { u32 tg3_flags3; #define TG3_FLG3_NO_NVRAM_ADDR_TRANS 0x00000001 #define TG3_FLG3_ENABLE_APE 0x00000002 -#define TG3_FLG3_5761_5784_AX_FIXES 0x00000004 #define TG3_FLG3_5701_DMA_BUG 0x00000008 #define TG3_FLG3_USE_PHYLIB 0x00000010 #define TG3_FLG3_MDIOBUS_INITED 0x00000020 @@ -2516,6 +2614,9 @@ struct tg3 { #define TG3_FLG3_RGMII_STD_IBND_DISABLE 0x00000100 #define TG3_FLG3_RGMII_EXT_IBND_RX_EN 0x00000200 #define TG3_FLG3_RGMII_EXT_IBND_TX_EN 0x00000400 +#define TG3_FLG3_CLKREQ_BUG 0x00000800 +#define TG3_FLG3_PHY_ENABLE_APD 0x00001000 +#define TG3_FLG3_5755_PLUS 0x00002000 struct timer_list timer; u16 timer_counter; @@ -2547,14 +2648,16 @@ struct tg3 { /* PCI block */ u32 pci_chip_rev_id; + u16 pci_cmd; u8 pci_cacheline_sz; u8 pci_lat_timer; - u8 pci_hdr_type; - u8 pci_bist; int pm_cap; int msi_cap; + union { int pcix_cap; + int pcie_cap; + }; struct mii_bus *mdio_bus; int mdio_irq[PHY_MAX_ADDR]; @@ -2588,11 +2691,16 @@ struct tg3 { #define PHY_REV_BCM5411_X0 0x1 /* Found on Netgear GA302T */ #define TG3_PHY_ID_BCM50610 0x143bd60 #define TG3_PHY_ID_BCMAC131 0x143bc70 - +#define TG3_PHY_ID_RTL8211C 0x001cc910 +#define TG3_PHY_ID_RTL8201E 0x00008200 +#define TG3_PHY_ID_BCM57780 0x03625d90 +#define TG3_PHY_OUI_MASK 0xfffffc00 +#define TG3_PHY_OUI_1 0x00206000 +#define TG3_PHY_OUI_2 0x0143bc00 +#define TG3_PHY_OUI_3 0x03625c00 u32 led_ctrl; u32 phy_otp; - u16 pci_cmd; char board_part_number[24]; #define TG3_VER_SIZE 32 diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index e60498232b94f83dede6c6d4ae153d8d135d7b19..85ef8b744557621f335134b2be61a119be72d09c 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -163,6 +163,11 @@ * v1.15 Apr 4, 2002 - Correct operation when aui=1 to be * 10T half duplex no loopback * Thanks to Gunnar Eikman + * + * Sakari Ailus : + * + * v1.15a Dec 15 2008 - Remove bbuf support, it doesn't work anyway. + * *******************************************************************************/ #include @@ -213,12 +218,8 @@ static int debug; module_param(debug, int, 0); MODULE_PARM_DESC(debug, "ThunderLAN debug mask"); -static int bbuf; -module_param(bbuf, int, 0); -MODULE_PARM_DESC(bbuf, "ThunderLAN use big buffer (0-1)"); - static const char TLanSignature[] = "TLAN"; -static const char tlan_banner[] = "ThunderLAN driver v1.15\n"; +static const char tlan_banner[] = "ThunderLAN driver v1.15a\n"; static int tlan_have_pci; static int tlan_have_eisa; @@ -859,13 +860,8 @@ static int TLan_Init( struct net_device *dev ) priv = netdev_priv(dev); - if ( bbuf ) { - dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS ) - * ( sizeof(TLanList) + TLAN_MAX_FRAME_SIZE ); - } else { - dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS ) - * ( sizeof(TLanList) ); - } + dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS ) + * ( sizeof(TLanList) ); priv->dmaStorage = pci_alloc_consistent(priv->pciDev, dma_size, &priv->dmaStorageDMA); priv->dmaSize = dma_size; @@ -881,16 +877,6 @@ static int TLan_Init( struct net_device *dev ) priv->txList = priv->rxList + TLAN_NUM_RX_LISTS; priv->txListDMA = priv->rxListDMA + sizeof(TLanList) * TLAN_NUM_RX_LISTS; - if ( bbuf ) { - priv->rxBuffer = (u8 *) ( priv->txList + TLAN_NUM_TX_LISTS ); - priv->rxBufferDMA =priv->txListDMA - + sizeof(TLanList) * TLAN_NUM_TX_LISTS; - priv->txBuffer = priv->rxBuffer - + ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE ); - priv->txBufferDMA = priv->rxBufferDMA - + ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE ); - } - err = 0; for ( i = 0; i < 6 ; i++ ) err |= TLan_EeReadByte( dev, @@ -1094,9 +1080,8 @@ static void TLan_tx_timeout_work(struct work_struct *work) static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) { TLanPrivateInfo *priv = netdev_priv(dev); - TLanList *tail_list; dma_addr_t tail_list_phys; - u8 *tail_buffer; + TLanList *tail_list; unsigned long flags; unsigned int txlen; @@ -1125,15 +1110,10 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) tail_list->forward = 0; - if ( bbuf ) { - tail_buffer = priv->txBuffer + ( priv->txTail * TLAN_MAX_FRAME_SIZE ); - skb_copy_from_linear_data(skb, tail_buffer, txlen); - } else { - tail_list->buffer[0].address = pci_map_single(priv->pciDev, - skb->data, txlen, - PCI_DMA_TODEVICE); - TLan_StoreSKB(tail_list, skb); - } + tail_list->buffer[0].address = pci_map_single(priv->pciDev, + skb->data, txlen, + PCI_DMA_TODEVICE); + TLan_StoreSKB(tail_list, skb); tail_list->frameSize = (u16) txlen; tail_list->buffer[0].count = TLAN_LAST_BUFFER | (u32) txlen; @@ -1163,9 +1143,6 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) CIRC_INC( priv->txTail, TLAN_NUM_TX_LISTS ); - if ( bbuf ) - dev_kfree_skb_any(skb); - dev->trans_start = jiffies; return 0; @@ -1429,17 +1406,16 @@ static u32 TLan_HandleTxEOF( struct net_device *dev, u16 host_int ) head_list = priv->txList + priv->txHead; while (((tmpCStat = head_list->cStat ) & TLAN_CSTAT_FRM_CMP) && (ack < 255)) { + struct sk_buff *skb = TLan_GetSKB(head_list); + ack++; - if ( ! bbuf ) { - struct sk_buff *skb = TLan_GetSKB(head_list); - pci_unmap_single(priv->pciDev, head_list->buffer[0].address, - max(skb->len, - (unsigned int)TLAN_MIN_FRAME_SIZE), - PCI_DMA_TODEVICE); - dev_kfree_skb_any(skb); - head_list->buffer[8].address = 0; - head_list->buffer[9].address = 0; - } + pci_unmap_single(priv->pciDev, head_list->buffer[0].address, + max(skb->len, + (unsigned int)TLAN_MIN_FRAME_SIZE), + PCI_DMA_TODEVICE); + dev_kfree_skb_any(skb); + head_list->buffer[8].address = 0; + head_list->buffer[9].address = 0; if ( tmpCStat & TLAN_CSTAT_EOC ) eoc = 1; @@ -1549,7 +1525,6 @@ static u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int ) TLanPrivateInfo *priv = netdev_priv(dev); u32 ack = 0; int eoc = 0; - u8 *head_buffer; TLanList *head_list; struct sk_buff *skb; TLanList *tail_list; @@ -1564,53 +1539,33 @@ static u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int ) while (((tmpCStat = head_list->cStat) & TLAN_CSTAT_FRM_CMP) && (ack < 255)) { dma_addr_t frameDma = head_list->buffer[0].address; u32 frameSize = head_list->frameSize; + struct sk_buff *new_skb; + ack++; if (tmpCStat & TLAN_CSTAT_EOC) eoc = 1; - if (bbuf) { - skb = netdev_alloc_skb(dev, frameSize + 7); - if ( !skb ) - goto drop_and_reuse; - - head_buffer = priv->rxBuffer - + (priv->rxHead * TLAN_MAX_FRAME_SIZE); - skb_reserve(skb, 2); - pci_dma_sync_single_for_cpu(priv->pciDev, - frameDma, frameSize, - PCI_DMA_FROMDEVICE); - skb_copy_from_linear_data(skb, head_buffer, frameSize); - skb_put(skb, frameSize); - dev->stats.rx_bytes += frameSize; - - skb->protocol = eth_type_trans( skb, dev ); - netif_rx( skb ); - } else { - struct sk_buff *new_skb; - - new_skb = netdev_alloc_skb(dev, TLAN_MAX_FRAME_SIZE + 7 ); - if ( !new_skb ) - goto drop_and_reuse; - - skb = TLan_GetSKB(head_list); - pci_unmap_single(priv->pciDev, frameDma, - TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE); - skb_put( skb, frameSize ); + new_skb = netdev_alloc_skb(dev, TLAN_MAX_FRAME_SIZE + 7 ); + if ( !new_skb ) + goto drop_and_reuse; - dev->stats.rx_bytes += frameSize; + skb = TLan_GetSKB(head_list); + pci_unmap_single(priv->pciDev, frameDma, + TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE); + skb_put( skb, frameSize ); - skb->protocol = eth_type_trans( skb, dev ); - netif_rx( skb ); + dev->stats.rx_bytes += frameSize; - skb_reserve( new_skb, NET_IP_ALIGN ); - head_list->buffer[0].address = pci_map_single(priv->pciDev, - new_skb->data, - TLAN_MAX_FRAME_SIZE, - PCI_DMA_FROMDEVICE); + skb->protocol = eth_type_trans( skb, dev ); + netif_rx( skb ); - TLan_StoreSKB(head_list, new_skb); + skb_reserve( new_skb, NET_IP_ALIGN ); + head_list->buffer[0].address = pci_map_single(priv->pciDev, + new_skb->data, + TLAN_MAX_FRAME_SIZE, + PCI_DMA_FROMDEVICE); - } + TLan_StoreSKB(head_list, new_skb); drop_and_reuse: head_list->forward = 0; head_list->cStat = 0; @@ -1653,8 +1608,6 @@ static u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int ) } } - dev->last_rx = jiffies; - return ack; } /* TLan_HandleRxEOF */ @@ -1995,12 +1948,7 @@ static void TLan_ResetLists( struct net_device *dev ) for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ ) { list = priv->txList + i; list->cStat = TLAN_CSTAT_UNUSED; - if ( bbuf ) { - list->buffer[0].address = priv->txBufferDMA - + ( i * TLAN_MAX_FRAME_SIZE ); - } else { - list->buffer[0].address = 0; - } + list->buffer[0].address = 0; list->buffer[2].count = 0; list->buffer[2].address = 0; list->buffer[8].address = 0; @@ -2015,23 +1963,18 @@ static void TLan_ResetLists( struct net_device *dev ) list->cStat = TLAN_CSTAT_READY; list->frameSize = TLAN_MAX_FRAME_SIZE; list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER; - if ( bbuf ) { - list->buffer[0].address = priv->rxBufferDMA - + ( i * TLAN_MAX_FRAME_SIZE ); - } else { - skb = netdev_alloc_skb(dev, TLAN_MAX_FRAME_SIZE + 7 ); - if ( !skb ) { - pr_err("TLAN: out of memory for received data.\n" ); - break; - } - - skb_reserve( skb, NET_IP_ALIGN ); - list->buffer[0].address = pci_map_single(priv->pciDev, - skb->data, - TLAN_MAX_FRAME_SIZE, - PCI_DMA_FROMDEVICE); - TLan_StoreSKB(list, skb); + skb = netdev_alloc_skb(dev, TLAN_MAX_FRAME_SIZE + 7 ); + if ( !skb ) { + pr_err("TLAN: out of memory for received data.\n" ); + break; } + + skb_reserve( skb, NET_IP_ALIGN ); + list->buffer[0].address = pci_map_single(priv->pciDev, + skb->data, + TLAN_MAX_FRAME_SIZE, + PCI_DMA_FROMDEVICE); + TLan_StoreSKB(list, skb); list->buffer[1].count = 0; list->buffer[1].address = 0; list->forward = list_phys + sizeof(TLanList); @@ -2054,35 +1997,33 @@ static void TLan_FreeLists( struct net_device *dev ) TLanList *list; struct sk_buff *skb; - if ( ! bbuf ) { - for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ ) { - list = priv->txList + i; - skb = TLan_GetSKB(list); - if ( skb ) { - pci_unmap_single( - priv->pciDev, - list->buffer[0].address, - max(skb->len, - (unsigned int)TLAN_MIN_FRAME_SIZE), - PCI_DMA_TODEVICE); - dev_kfree_skb_any( skb ); - list->buffer[8].address = 0; - list->buffer[9].address = 0; - } + for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ ) { + list = priv->txList + i; + skb = TLan_GetSKB(list); + if ( skb ) { + pci_unmap_single( + priv->pciDev, + list->buffer[0].address, + max(skb->len, + (unsigned int)TLAN_MIN_FRAME_SIZE), + PCI_DMA_TODEVICE); + dev_kfree_skb_any( skb ); + list->buffer[8].address = 0; + list->buffer[9].address = 0; } + } - for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ ) { - list = priv->rxList + i; - skb = TLan_GetSKB(list); - if ( skb ) { - pci_unmap_single(priv->pciDev, - list->buffer[0].address, - TLAN_MAX_FRAME_SIZE, - PCI_DMA_FROMDEVICE); - dev_kfree_skb_any( skb ); - list->buffer[8].address = 0; - list->buffer[9].address = 0; - } + for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ ) { + list = priv->rxList + i; + skb = TLan_GetSKB(list); + if ( skb ) { + pci_unmap_single(priv->pciDev, + list->buffer[0].address, + TLAN_MAX_FRAME_SIZE, + PCI_DMA_FROMDEVICE); + dev_kfree_skb_any( skb ); + list->buffer[8].address = 0; + list->buffer[9].address = 0; } } } /* TLan_FreeLists */ diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c index bf621328b6019e3a89bc21406ecaf4f8370218d9..43853e3b210e42977100f1c1b3828a3dfa9fe623 100644 --- a/drivers/net/tokenring/3c359.c +++ b/drivers/net/tokenring/3c359.c @@ -296,8 +296,9 @@ static int __devinit xl_probe(struct pci_dev *pdev, } ; /* - * Allowing init_trdev to allocate the dev->priv structure will align xl_private - * on a 32 bytes boundary which we need for the rx/tx descriptors + * Allowing init_trdev to allocate the private data will align + * xl_private on a 32 bytes boundary which we need for the rx/tx + * descriptors */ dev = alloc_trdev(sizeof(struct xl_private)) ; @@ -638,13 +639,13 @@ static int xl_open(struct net_device *dev) /* These MUST be on 8 byte boundaries */ xl_priv->xl_tx_ring = kzalloc((sizeof(struct xl_tx_desc) * XL_TX_RING_SIZE) + 7, GFP_DMA | GFP_KERNEL); if (xl_priv->xl_tx_ring == NULL) { - printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers.\n", + printk(KERN_WARNING "%s: Not enough memory to allocate tx buffers.\n", dev->name); free_irq(dev->irq,dev); return -ENOMEM; } xl_priv->xl_rx_ring = kzalloc((sizeof(struct xl_rx_desc) * XL_RX_RING_SIZE) +7, GFP_DMA | GFP_KERNEL); - if (xl_priv->xl_tx_ring == NULL) { + if (xl_priv->xl_rx_ring == NULL) { printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers.\n", dev->name); free_irq(dev->irq,dev); @@ -669,6 +670,8 @@ static int xl_open(struct net_device *dev) if (i==0) { printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers. Adapter disabled \n",dev->name) ; free_irq(dev->irq,dev) ; + kfree(xl_priv->xl_tx_ring); + kfree(xl_priv->xl_rx_ring); return -EIO ; } @@ -974,7 +977,6 @@ static void xl_rx(struct net_device *dev) netif_rx(skb2) ; } /* if multiple buffers */ - dev->last_rx = jiffies ; } /* while packet to do */ /* Clear the updComplete interrupt */ @@ -1571,7 +1573,6 @@ static void xl_arb_cmd(struct net_device *dev) * anyway. */ - dev->last_rx = jiffies ; /* Acknowledge interrupt, this tells nic we are done with the arb */ writel(ACK_INTERRUPT | ARBCACK | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; diff --git a/drivers/net/tokenring/Kconfig b/drivers/net/tokenring/Kconfig index e6b2e06493e79b4c0fe05dbd5397bf48224b36d8..c4137b0f808e6bd443967f4f3f49c8d44d823daa 100644 --- a/drivers/net/tokenring/Kconfig +++ b/drivers/net/tokenring/Kconfig @@ -4,7 +4,7 @@ # So far, we only have PCI, ISA, and MCA token ring devices menuconfig TR - bool "Token Ring driver support" + tristate "Token Ring driver support" depends on NETDEVICES && !UML depends on (PCI || ISA || MCA || CCW) select LLC diff --git a/drivers/net/tokenring/abyss.c b/drivers/net/tokenring/abyss.c index 7a7de0469eae098412036df35e8b9b636e291622..b566d6d79ecdbe7ce0a5f58f7546f50e77600ec5 100644 --- a/drivers/net/tokenring/abyss.c +++ b/drivers/net/tokenring/abyss.c @@ -99,7 +99,6 @@ static int __devinit abyss_attach(struct pci_dev *pdev, const struct pci_device_ struct net_local *tp; int ret, pci_irq_line; unsigned long pci_ioaddr; - DECLARE_MAC_BUF(mac); if (versionprinted++ == 0) printk("%s", version); @@ -147,8 +146,7 @@ static int __devinit abyss_attach(struct pci_dev *pdev, const struct pci_device_ abyss_read_eeprom(dev); - printk("%s: Ring Station Address: %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk("%s: Ring Station Address: %pM\n", dev->name, dev->dev_addr); tp = netdev_priv(dev); tp->setnselout = abyss_setnselout_pins; diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c index e494c63bfbd9643088c0c30680fdc956becf8b60..fa7bce6e0c6dc56019d18197b2076ddfd3e6a3d8 100644 --- a/drivers/net/tokenring/ibmtr.c +++ b/drivers/net/tokenring/ibmtr.c @@ -389,7 +389,6 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr) unsigned long timeout; static int version_printed; #endif - DECLARE_MAC_BUF(mac); /* Query the adapter PIO base port which will return * indication of where MMIO was placed. We also have a @@ -703,8 +702,7 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr) channel_def[cardpresent - 1], adapter_def(ti->adapter_type)); DPRINTK("using irq %d, PIOaddr %hx, %dK shared RAM.\n", irq, PIOaddr, ti->mapped_ram_size / 2); - DPRINTK("Hardware address : %s\n", - print_mac(mac, dev->dev_addr)); + DPRINTK("Hardware address : %pM\n", dev->dev_addr); if (ti->page_mask) DPRINTK("Shared RAM paging enabled. " "Page size: %uK Shared Ram size %dK\n", @@ -1741,8 +1739,6 @@ static void tr_rx(struct net_device *dev) void __iomem *trhhdr = rbuf + offsetof(struct rec_buf, data); u8 saddr[6]; u8 daddr[6]; - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); int i; for (i = 0 ; i < 6 ; i++) saddr[i] = readb(trhhdr + SADDR_OFST + i); @@ -1750,9 +1746,9 @@ static void tr_rx(struct net_device *dev) daddr[i] = readb(trhhdr + DADDR_OFST + i); DPRINTK("Probably non-IP frame received.\n"); DPRINTK("ssap: %02X dsap: %02X " - "saddr: %s daddr: %$s\n", + "saddr: %pM daddr: %pM\n", readb(llc + SSAP_OFST), readb(llc + DSAP_OFST), - print_mac(mac, saddr), print_mac(mac2, daddr)); + saddr, daddr); } #endif @@ -1826,7 +1822,6 @@ static void tr_rx(struct net_device *dev) skb->ip_summed = CHECKSUM_COMPLETE; } netif_rx(skb); - dev->last_rx = jiffies; } /*tr_rx */ /*****************************************************************************/ @@ -1842,8 +1837,8 @@ static void ibmtr_reset_timer(struct timer_list *tmr, struct net_device *dev) /*****************************************************************************/ -void tok_rerun(unsigned long dev_addr){ - +static void tok_rerun(unsigned long dev_addr) +{ struct net_device *dev = (struct net_device *)dev_addr; struct tok_info *ti = netdev_priv(dev); diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c index 59d1673f9387febe69304c48e1c6a17a6e19e538..239c75217b120624d7ae500ce919552a869507b5 100644 --- a/drivers/net/tokenring/lanstreamer.c +++ b/drivers/net/tokenring/lanstreamer.c @@ -446,9 +446,6 @@ static int streamer_reset(struct net_device *dev) unsigned int uaa_addr; struct sk_buff *skb = NULL; __u16 misr; -#if STREAMER_DEBUG - DECLARE_MAC_BUF(mac); -#endif streamer_priv = netdev_priv(dev); streamer_mmio = streamer_priv->streamer_mmio; @@ -577,8 +574,7 @@ static int streamer_reset(struct net_device *dev) dev->dev_addr[i+1]= addr & 0xff; } #if STREAMER_DEBUG - printk("Adapter address: %s\n", - print_mac(mac, dev->dev_addr)); + printk("Adapter address: %pM\n", dev->dev_addr); #endif } return 0; @@ -1013,7 +1009,6 @@ static void streamer_rx(struct net_device *dev) /* send up to the protocol */ netif_rx(skb); } - dev->last_rx = jiffies; streamer_priv->streamer_stats.rx_packets++; streamer_priv->streamer_stats.rx_bytes += length; } /* if skb == null */ @@ -1538,7 +1533,6 @@ static void streamer_arb_cmd(struct net_device *dev) #if STREAMER_NETWORK_MONITOR struct trh_hdr *mac_hdr; - DECLARE_MAC_BUF(mac); #endif writew(streamer_priv->arb, streamer_mmio + LAPA); @@ -1611,11 +1605,11 @@ static void streamer_arb_cmd(struct net_device *dev) dev->name); mac_hdr = tr_hdr(mac_frame); printk(KERN_WARNING - "%s: MAC Frame Dest. Addr: %s\n", - dev->name, print_mac(mac, mac_hdr->daddr)); + "%s: MAC Frame Dest. Addr: %pM\n", + dev->name, mac_hdr->daddr); printk(KERN_WARNING - "%s: MAC Frame Srce. Addr: %s\n", - dev->name, DEV->ADDR6(mac_hdr->saddr)); + "%s: MAC Frame Srce. Addr: %pM\n", + dev->name, mac_hdr->saddr); #endif netif_rx(mac_frame); @@ -1850,8 +1844,6 @@ static int sprintf_info(char *buffer, struct net_device *dev) struct streamer_parameters_table spt; int size = 0; int i; - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); writew(streamer_priv->streamer_addr_table_addr, streamer_mmio + LAPA); for (i = 0; i < 14; i += 2) { @@ -1873,9 +1865,8 @@ static int sprintf_info(char *buffer, struct net_device *dev) size = sprintf(buffer, "\n%6s: Adapter Address : Node Address : Functional Addr\n", dev->name); size += sprintf(buffer + size, - "%6s: %s : %s : %02x:%02x:%02x:%02x\n", - dev->name, print_mac(mac, dev->dev_addr), - print_mac(mac2, sat.node_addr), + "%6s: %pM : %pM : %02x:%02x:%02x:%02x\n", + dev->name, dev->dev_addr, sat.node_addr, sat.func_addr[0], sat.func_addr[1], sat.func_addr[2], sat.func_addr[3]); @@ -1884,19 +1875,18 @@ static int sprintf_info(char *buffer, struct net_device *dev) size += sprintf(buffer + size, "%6s: Physical Addr : Up Node Address : Poll Address : AccPri : Auth Src : Att Code :\n", dev->name); size += sprintf(buffer + size, - "%6s: %02x:%02x:%02x:%02x : %s : %s : %04x : %04x : %04x :\n", + "%6s: %02x:%02x:%02x:%02x : %pM : %pM : %04x : %04x : %04x :\n", dev->name, spt.phys_addr[0], spt.phys_addr[1], spt.phys_addr[2], spt.phys_addr[3], - print_mac(mac, spt.up_node_addr), - print_mac(mac2, spt.poll_addr), + spt.up_node_addr, spt.poll_addr, ntohs(spt.acc_priority), ntohs(spt.auth_source_class), ntohs(spt.att_code)); size += sprintf(buffer + size, "%6s: Source Address : Bcn T : Maj. V : Lan St : Lcl Rg : Mon Err : Frame Correl : \n", dev->name); size += sprintf(buffer + size, - "%6s: %s : %04x : %04x : %04x : %04x : %04x : %04x : \n", - dev->name, print_mac(mac, spt.source_addr), + "%6s: %pM : %04x : %04x : %04x : %04x : %04x : %04x : \n", + dev->name, spt.source_addr, ntohs(spt.beacon_type), ntohs(spt.major_vector), ntohs(spt.lan_status), ntohs(spt.local_ring), ntohs(spt.mon_error), ntohs(spt.frame_correl)); @@ -1905,10 +1895,10 @@ static int sprintf_info(char *buffer, struct net_device *dev) dev->name); size += sprintf(buffer + size, - "%6s: : %02x : %02x : %s : %02x:%02x:%02x:%02x : \n", + "%6s: : %02x : %02x : %pM : %02x:%02x:%02x:%02x : \n", dev->name, ntohs(spt.beacon_transmit), ntohs(spt.beacon_receive), - print_mac(mac, spt.beacon_naun), + spt.beacon_naun, spt.beacon_phys[0], spt.beacon_phys[1], spt.beacon_phys[2], spt.beacon_phys[3]); return size; diff --git a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c index c9c5a2b1ed9e9ea6a49d8e5f2af22e9799adb403..917b4d201e099da1aa3ed3a7b64f78ea4a5aceed 100644 --- a/drivers/net/tokenring/madgemc.c +++ b/drivers/net/tokenring/madgemc.c @@ -152,7 +152,6 @@ static int __devinit madgemc_probe(struct device *device) struct card_info *card; struct mca_device *mdev = to_mca_device(device); int ret = 0; - DECLARE_MAC_BUF(mac); if (versionprinted++ == 0) printk("%s", version); @@ -323,8 +322,8 @@ static int __devinit madgemc_probe(struct device *device) mca_device_set_name(mdev, (card->cardtype == 0x08)?MADGEMC16_CARDNAME:MADGEMC32_CARDNAME); mca_set_adapter_procfn(mdev->slot, madgemc_mcaproc, dev); - printk("%s: Ring Station Address: %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk("%s: Ring Station Address: %pM\n", + dev->name, dev->dev_addr); if (tmsdev_init(dev, device)) { printk("%s: unable to get memory for dev->priv.\n", @@ -467,7 +466,7 @@ static irqreturn_t madgemc_interrupt(int irq, void *dev_id) * zero to leave the TMS NSELOUT bits unaffected. * */ -unsigned short madgemc_setnselout_pins(struct net_device *dev) +static unsigned short madgemc_setnselout_pins(struct net_device *dev) { unsigned char reg1; struct net_local *tp = netdev_priv(dev); @@ -690,7 +689,6 @@ static int madgemc_mcaproc(char *buf, int slot, void *d) struct net_local *tp = netdev_priv(dev); struct card_info *curcard = tp->tmspriv; int len = 0; - DECLARE_MAC_BUF(mac); len += sprintf(buf+len, "-------\n"); if (curcard) { @@ -714,8 +712,8 @@ static int madgemc_mcaproc(char *buf, int slot, void *d) } len += sprintf(buf+len, " (%s)\n", (curcard->fairness)?"Unfair":"Fair"); - len += sprintf(buf+len, "Ring Station Address: %s\n", - print_mac(mac, dev->dev_addr)); + len += sprintf(buf+len, "Ring Station Address: %pM\n", + dev->dev_addr); } else len += sprintf(buf+len, "Card not configured\n"); diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index 0ab51a0f35fc9cc5ae811610bc776759ff49c453..ecb5c7c969105ff6d79622f17f50a47c6ea3bd3e 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -421,10 +421,7 @@ static int olympic_init(struct net_device *dev) memcpy_fromio(&dev->dev_addr[0], adapter_addr,6); #if OLYMPIC_DEBUG - { - DECLARE_MAC_BUF(mac); - printk("adapter address: %s\n", print_mac(mac, dev->dev_addr)); - } + printk("adapter address: %pM\n", dev->dev_addr); #endif olympic_priv->olympic_addr_table_addr = swab16(readw(init_srb + 12)); @@ -441,7 +438,6 @@ static int olympic_open(struct net_device *dev) unsigned long flags, t; int i, open_finished = 1 ; u8 resp, err; - DECLARE_MAC_BUF(mac); DECLARE_WAITQUEUE(wait,current) ; @@ -569,8 +565,8 @@ static int olympic_open(struct net_device *dev) goto out; case 0x32: - printk(KERN_WARNING "%s: Invalid LAA: %s\n", - dev->name, print_mac(mac, olympic_priv->olympic_laa)); + printk(KERN_WARNING "%s: Invalid LAA: %pM\n", + dev->name, olympic_priv->olympic_laa); goto out; default: @@ -704,13 +700,12 @@ static int olympic_open(struct net_device *dev) u8 __iomem *opt; int i; u8 addr[6]; - DECLARE_MAC_BUF(mac); oat = (olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr); opt = (olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr); for (i = 0; i < 6; i++) addr[i] = readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+i); - printk("%s: Node Address: %s\n",dev->name, print_mac(mac, addr)); + printk("%s: Node Address: %pM\n", dev->name, addr); printk("%s: Functional Address: %02x:%02x:%02x:%02x\n",dev->name, readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)), readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+1), @@ -719,7 +714,7 @@ static int olympic_open(struct net_device *dev) for (i = 0; i < 6; i++) addr[i] = readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+i); - printk("%s: NAUN Address: %s\n",dev->name, print_mac(mac, addr)); + printk("%s: NAUN Address: %pM\n", dev->name, addr); } netif_start_queue(dev); @@ -867,7 +862,6 @@ static void olympic_rx(struct net_device *dev) skb->protocol = tr_type_trans(skb,dev); netif_rx(skb) ; } - dev->last_rx = jiffies ; olympic_priv->olympic_stats.rx_packets++ ; olympic_priv->olympic_stats.rx_bytes += length ; } /* if skb == null */ @@ -1440,19 +1434,12 @@ static void olympic_arb_cmd(struct net_device *dev) struct trh_hdr *mac_hdr; printk(KERN_WARNING "%s: Received MAC Frame, details: \n",dev->name); mac_hdr = tr_hdr(mac_frame); - printk(KERN_WARNING "%s: MAC Frame Dest. Addr: " - MAC_FMT " \n", dev->name, - mac_hdr->daddr[0], mac_hdr->daddr[1], - mac_hdr->daddr[2], mac_hdr->daddr[3], - mac_hdr->daddr[4], mac_hdr->daddr[5]); - printk(KERN_WARNING "%s: MAC Frame Srce. Addr: " - MAC_FMT " \n", dev->name, - mac_hdr->saddr[0], mac_hdr->saddr[1], - mac_hdr->saddr[2], mac_hdr->saddr[3], - mac_hdr->saddr[4], mac_hdr->saddr[5]); + printk(KERN_WARNING "%s: MAC Frame Dest. Addr: %pM\n", + dev->name, mac_hdr->daddr); + printk(KERN_WARNING "%s: MAC Frame Srce. Addr: %pM\n", + dev->name, mac_hdr->saddr); } netif_rx(mac_frame); - dev->last_rx = jiffies; drop_frame: /* Now tell the card we have dealt with the received frame */ @@ -1647,8 +1634,6 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt u8 addr[6]; u8 addr2[6]; int i; - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); size = sprintf(buffer, "IBM Pit/Pit-Phy/Olympic Chipset Token Ring Adapter %s\n",dev->name); @@ -1658,10 +1643,9 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt for (i = 0 ; i < 6 ; i++) addr[i] = readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr) + i); - size += sprintf(buffer+size, "%6s: %s : %s : %02x:%02x:%02x:%02x\n", + size += sprintf(buffer+size, "%6s: %pM : %pM : %02x:%02x:%02x:%02x\n", dev->name, - print_mac(mac, dev->dev_addr), - print_mac(mac2, addr), + dev->dev_addr, addr, readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)), readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+1), readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+2), @@ -1677,14 +1661,13 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt for (i = 0 ; i < 6 ; i++) addr2[i] = readb(opt+offsetof(struct olympic_parameters_table, poll_addr) + i); - size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x : %s : %s : %04x : %04x : %04x :\n", + size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x : %pM : %pM : %04x : %04x : %04x :\n", dev->name, readb(opt+offsetof(struct olympic_parameters_table, phys_addr)), readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+1), readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+2), readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+3), - print_mac(mac, addr), - print_mac(mac2, addr2), + addr, addr2, swab16(readw(opt+offsetof(struct olympic_parameters_table, acc_priority))), swab16(readw(opt+offsetof(struct olympic_parameters_table, auth_source_class))), swab16(readw(opt+offsetof(struct olympic_parameters_table, att_code)))); @@ -1694,9 +1677,8 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt for (i = 0 ; i < 6 ; i++) addr[i] = readb(opt+offsetof(struct olympic_parameters_table, source_addr) + i); - size += sprintf(buffer+size, "%6s: %s : %04x : %04x : %04x : %04x : %04x : %04x : \n", - dev->name, - print_mac(mac, addr), + size += sprintf(buffer+size, "%6s: %pM : %04x : %04x : %04x : %04x : %04x : %04x : \n", + dev->name, addr, swab16(readw(opt+offsetof(struct olympic_parameters_table, beacon_type))), swab16(readw(opt+offsetof(struct olympic_parameters_table, major_vector))), swab16(readw(opt+offsetof(struct olympic_parameters_table, lan_status))), @@ -1709,11 +1691,11 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt for (i = 0 ; i < 6 ; i++) addr[i] = readb(opt+offsetof(struct olympic_parameters_table, beacon_naun) + i); - size += sprintf(buffer+size, "%6s: : %02x : %02x : %s : %02x:%02x:%02x:%02x : \n", + size += sprintf(buffer+size, "%6s: : %02x : %02x : %pM : %02x:%02x:%02x:%02x : \n", dev->name, swab16(readw(opt+offsetof(struct olympic_parameters_table, beacon_transmit))), swab16(readw(opt+offsetof(struct olympic_parameters_table, beacon_receive))), - print_mac(mac, addr), + addr, readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)), readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+1), readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+2), diff --git a/drivers/net/tokenring/proteon.c b/drivers/net/tokenring/proteon.c index 00ea94513460d5e118b811a3496625b98ad4a9cb..b8c955f6d31ae8355307b872b9c55e6abb650937 100644 --- a/drivers/net/tokenring/proteon.c +++ b/drivers/net/tokenring/proteon.c @@ -122,7 +122,6 @@ static int __init setup_card(struct net_device *dev, struct device *pdev) static int versionprinted; const unsigned *port; int j,err = 0; - DECLARE_MAC_BUF(mac); if (!dev) return -ENOMEM; @@ -153,8 +152,8 @@ static int __init setup_card(struct net_device *dev, struct device *pdev) proteon_read_eeprom(dev); - printk(KERN_DEBUG "proteon.c: Ring Station Address: %s\n", - print_mac(mac, dev->dev_addr)); + printk(KERN_DEBUG "proteon.c: Ring Station Address: %pM\n", + dev->dev_addr); tp = netdev_priv(dev); tp->setnselout = proteon_setnselout_pins; @@ -284,7 +283,7 @@ static void proteon_read_eeprom(struct net_device *dev) dev->dev_addr[i] = proteon_sifreadw(dev, SIFINC) >> 8; } -unsigned short proteon_setnselout_pins(struct net_device *dev) +static unsigned short proteon_setnselout_pins(struct net_device *dev) { return 0; } diff --git a/drivers/net/tokenring/skisa.c b/drivers/net/tokenring/skisa.c index 41b6999a0f33487719f56898a489c9748b975f7f..c0f58f08782cd543d6df4bd3c4a883b4cc6aa269 100644 --- a/drivers/net/tokenring/skisa.c +++ b/drivers/net/tokenring/skisa.c @@ -139,7 +139,6 @@ static int __init setup_card(struct net_device *dev, struct device *pdev) static int versionprinted; const unsigned *port; int j, err = 0; - DECLARE_MAC_BUF(mac); if (!dev) return -ENOMEM; @@ -170,8 +169,8 @@ static int __init setup_card(struct net_device *dev, struct device *pdev) sk_isa_read_eeprom(dev); - printk(KERN_DEBUG "skisa.c: Ring Station Address: %s\n", - print_mac(mac, dev->dev_addr)); + printk(KERN_DEBUG "skisa.c: Ring Station Address: %pM\n", + dev->dev_addr); tp = netdev_priv(dev); tp->setnselout = sk_isa_setnselout_pins; @@ -301,7 +300,7 @@ static void sk_isa_read_eeprom(struct net_device *dev) dev->dev_addr[i] = sk_isa_sifreadw(dev, SIFINC) >> 8; } -unsigned short sk_isa_setnselout_pins(struct net_device *dev) +static unsigned short sk_isa_setnselout_pins(struct net_device *dev) { return 0; } diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c index ed50d288e4940a79bdefca127a6c92d5713ab45d..a011666342ffb62af52bdea2a8eba09980ee777f 100644 --- a/drivers/net/tokenring/smctr.c +++ b/drivers/net/tokenring/smctr.c @@ -3910,7 +3910,6 @@ static int smctr_process_rx_packet(MAC_HEADER *rmf, __u16 size, /* Kick the packet on up. */ skb->protocol = tr_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; err = 0; } @@ -4496,7 +4495,6 @@ static int smctr_rx_frame(struct net_device *dev) /* Kick the packet on up. */ skb->protocol = tr_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; } else { } } diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c index d07c4523c847a1ceb3c4e98876c1cce025459b2c..5be34c2fd48385751844d82dc0c12b1e6d5390d4 100644 --- a/drivers/net/tokenring/tms380tr.c +++ b/drivers/net/tokenring/tms380tr.c @@ -180,10 +180,14 @@ void tms380tr_wait(unsigned long time); static void tms380tr_write_rpl_status(RPL *rpl, unsigned int Status); static void tms380tr_write_tpl_status(TPL *tpl, unsigned int Status); -#define SIFREADB(reg) (((struct net_local *)dev->priv)->sifreadb(dev, reg)) -#define SIFWRITEB(val, reg) (((struct net_local *)dev->priv)->sifwriteb(dev, val, reg)) -#define SIFREADW(reg) (((struct net_local *)dev->priv)->sifreadw(dev, reg)) -#define SIFWRITEW(val, reg) (((struct net_local *)dev->priv)->sifwritew(dev, val, reg)) +#define SIFREADB(reg) \ + (((struct net_local *)netdev_priv(dev))->sifreadb(dev, reg)) +#define SIFWRITEB(val, reg) \ + (((struct net_local *)netdev_priv(dev))->sifwriteb(dev, val, reg)) +#define SIFREADW(reg) \ + (((struct net_local *)netdev_priv(dev))->sifreadw(dev, reg)) +#define SIFWRITEW(val, reg) \ + (((struct net_local *)netdev_priv(dev))->sifwritew(dev, val, reg)) @@ -2186,7 +2190,6 @@ static void tms380tr_rcv_status_irq(struct net_device *dev) skb_trim(skb,Length); skb->protocol = tr_type_trans(skb,dev); netif_rx(skb); - dev->last_rx = jiffies; } } else /* Invalid frame */ @@ -2331,7 +2334,7 @@ int tmsdev_init(struct net_device *dev, struct device *pdev) { struct net_local *tms_local; - memset(dev->priv, 0, sizeof(struct net_local)); + memset(netdev_priv(dev), 0, sizeof(struct net_local)); tms_local = netdev_priv(dev); init_waitqueue_head(&tms_local->wait_for_tok_int); if (pdev->dma_mask) diff --git a/drivers/net/tokenring/tmspci.c b/drivers/net/tokenring/tmspci.c index 5f0ee880cfff1f7fa4d7c5096265322f043bef39..5f601773c26064e7962e6bc5026018f5f1c666af 100644 --- a/drivers/net/tokenring/tmspci.c +++ b/drivers/net/tokenring/tmspci.c @@ -100,7 +100,6 @@ static int __devinit tms_pci_attach(struct pci_dev *pdev, const struct pci_devic unsigned int pci_irq_line; unsigned long pci_ioaddr; struct card_info *cardinfo = &card_info_table[ent->driver_data]; - DECLARE_MAC_BUF(mac); if (versionprinted++ == 0) printk("%s", version); @@ -137,8 +136,8 @@ static int __devinit tms_pci_attach(struct pci_dev *pdev, const struct pci_devic tms_pci_read_eeprom(dev); - printk("%s: Ring Station Address: %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk("%s: Ring Station Address: %pM\n", + dev->name, dev->dev_addr); ret = tmsdev_init(dev, &pdev->dev); if (ret) { diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c index eb1da6f0b0863cbd827224ddebbc3d5e19275e35..75461dbd487657bd8e6a8002499db7c54fe2d774 100644 --- a/drivers/net/tsi108_eth.c +++ b/drivers/net/tsi108_eth.c @@ -788,7 +788,6 @@ static int tsi108_complete_rx(struct net_device *dev, int budget) skb_put(skb, data->rxring[rx].len); skb->protocol = eth_type_trans(skb, dev); netif_receive_skb(skb); - dev->last_rx = jiffies; } return done; @@ -889,7 +888,7 @@ static int tsi108_poll(struct napi_struct *napi, int budget) if (num_received < budget) { data->rxpending = 0; - netif_rx_complete(dev, napi); + netif_rx_complete(napi); TSI_WRITE(TSI108_EC_INTMASK, TSI_READ(TSI108_EC_INTMASK) @@ -920,7 +919,7 @@ static void tsi108_rx_int(struct net_device *dev) * from tsi108_check_rxring(). */ - if (netif_rx_schedule_prep(dev, &data->napi)) { + if (netif_rx_schedule_prep(&data->napi)) { /* Mask, rather than ack, the receive interrupts. The ack * will happen in tsi108_poll(). */ @@ -931,7 +930,7 @@ static void tsi108_rx_int(struct net_device *dev) | TSI108_INT_RXTHRESH | TSI108_INT_RXOVERRUN | TSI108_INT_RXERROR | TSI108_INT_RXWAIT); - __netif_rx_schedule(dev, &data->napi); + __netif_rx_schedule(&data->napi); } else { if (!netif_running(dev)) { /* This can happen if an interrupt occurs while the @@ -1569,7 +1568,6 @@ tsi108_init_one(struct platform_device *pdev) struct tsi108_prv_data *data = NULL; hw_info *einfo; int err = 0; - DECLARE_MAC_BUF(mac); einfo = pdev->dev.platform_data; @@ -1659,8 +1657,8 @@ tsi108_init_one(struct platform_device *pdev) } platform_set_drvdata(pdev, dev); - printk(KERN_INFO "%s: Tsi108 Gigabit Ethernet, MAC: %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: Tsi108 Gigabit Ethernet, MAC: %pM\n", + dev->name, dev->dev_addr); #ifdef DEBUG data->msg_enable = DEBUG; dump_eth_one(dev); diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index 124d5d690dde2508a29b8d5ae7bd907bcd259c38..5166be930a52c204f38d99394d4cdbff1fa6be94 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -459,7 +459,6 @@ static void de_rx (struct de_private *de) de->net_stats.rx_packets++; de->net_stats.rx_bytes += skb->len; - de->dev->last_rx = jiffies; rc = netif_rx (skb); if (rc == NET_RX_DROP) drop = 1; @@ -484,7 +483,7 @@ static void de_rx (struct de_private *de) static irqreturn_t de_interrupt (int irq, void *dev_instance) { struct net_device *dev = dev_instance; - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); u32 status; status = dr32(MacStatus); @@ -590,7 +589,7 @@ static void de_tx (struct de_private *de) static int de_start_xmit (struct sk_buff *skb, struct net_device *dev) { - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); unsigned int entry, tx_free; u32 mapping, len, flags = FirstFrag | LastFrag; struct de_desc *txd; @@ -653,7 +652,7 @@ static int de_start_xmit (struct sk_buff *skb, struct net_device *dev) static void build_setup_frame_hash(u16 *setup_frm, struct net_device *dev) { - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); u16 hash_table[32]; struct dev_mc_list *mclist; int i; @@ -684,7 +683,7 @@ static void build_setup_frame_hash(u16 *setup_frm, struct net_device *dev) static void build_setup_frame_perfect(u16 *setup_frm, struct net_device *dev) { - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); struct dev_mc_list *mclist; int i; u16 *eaddrs; @@ -712,7 +711,7 @@ static void build_setup_frame_perfect(u16 *setup_frm, struct net_device *dev) static void __de_set_rx_mode (struct net_device *dev) { - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); u32 macmode; unsigned int entry; u32 mapping; @@ -797,7 +796,7 @@ static void __de_set_rx_mode (struct net_device *dev) static void de_set_rx_mode (struct net_device *dev) { unsigned long flags; - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); spin_lock_irqsave (&de->lock, flags); __de_set_rx_mode(dev); @@ -821,7 +820,7 @@ static void __de_get_stats(struct de_private *de) static struct net_device_stats *de_get_stats(struct net_device *dev) { - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); /* The chip only need report frame silently dropped. */ spin_lock_irq(&de->lock); @@ -1355,7 +1354,7 @@ static void de_free_rings (struct de_private *de) static int de_open (struct net_device *dev) { - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); int rc; if (netif_msg_ifup(de)) @@ -1400,7 +1399,7 @@ static int de_open (struct net_device *dev) static int de_close (struct net_device *dev) { - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); unsigned long flags; if (netif_msg_ifdown(de)) @@ -1423,7 +1422,7 @@ static int de_close (struct net_device *dev) static void de_tx_timeout (struct net_device *dev) { - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); printk(KERN_DEBUG "%s: NIC status %08x mode %08x sia %08x desc %u/%u/%u\n", dev->name, dr32(MacStatus), dr32(MacMode), dr32(SIAStatus), @@ -1574,7 +1573,7 @@ static int __de_set_settings(struct de_private *de, struct ethtool_cmd *ecmd) static void de_get_drvinfo (struct net_device *dev,struct ethtool_drvinfo *info) { - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); strcpy (info->driver, DRV_NAME); strcpy (info->version, DRV_VERSION); @@ -1589,7 +1588,7 @@ static int de_get_regs_len(struct net_device *dev) static int de_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) { - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); int rc; spin_lock_irq(&de->lock); @@ -1601,7 +1600,7 @@ static int de_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) static int de_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) { - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); int rc; spin_lock_irq(&de->lock); @@ -1613,14 +1612,14 @@ static int de_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) static u32 de_get_msglevel(struct net_device *dev) { - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); return de->msg_enable; } static void de_set_msglevel(struct net_device *dev, u32 msglvl) { - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); de->msg_enable = msglvl; } @@ -1628,7 +1627,7 @@ static void de_set_msglevel(struct net_device *dev, u32 msglvl) static int de_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data) { - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); if (!de->ee_data) return -EOPNOTSUPP; @@ -1642,7 +1641,7 @@ static int de_get_eeprom(struct net_device *dev, static int de_nway_reset(struct net_device *dev) { - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); u32 status; if (de->media_type != DE_MEDIA_TP_AUTO) @@ -1661,7 +1660,7 @@ static int de_nway_reset(struct net_device *dev) static void de_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *data) { - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); regs->version = (DE_REGS_VER << 2) | de->de21040; @@ -1692,9 +1691,9 @@ static void __devinit de21040_get_mac_address (struct de_private *de) for (i = 0; i < 6; i++) { int value, boguscnt = 100000; - do + do { value = dr32(ROMCmd); - while (value < 0 && --boguscnt > 0); + } while (value < 0 && --boguscnt > 0); de->dev->dev_addr[i] = value; udelay(1); if (boguscnt <= 0) @@ -1932,7 +1931,6 @@ static int __devinit de_init_one (struct pci_dev *pdev, void __iomem *regs; unsigned long pciaddr; static int board_idx = -1; - DECLARE_MAC_BUF(mac); board_idx++; @@ -1956,7 +1954,7 @@ static int __devinit de_init_one (struct pci_dev *pdev, dev->tx_timeout = de_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; - de = dev->priv; + de = netdev_priv(dev); de->de21040 = ent->driver_data == 0 ? 1 : 0; de->pdev = pdev; de->dev = dev; @@ -2046,11 +2044,11 @@ static int __devinit de_init_one (struct pci_dev *pdev, goto err_out_iomap; /* print info about board and interface just registered */ - printk (KERN_INFO "%s: %s at 0x%lx, %s, IRQ %d\n", + printk (KERN_INFO "%s: %s at 0x%lx, %pM, IRQ %d\n", dev->name, de->de21040 ? "21040" : "21041", dev->base_addr, - print_mac(mac, dev->dev_addr), + dev->dev_addr, dev->irq); pci_set_drvdata(pdev, dev); @@ -2078,7 +2076,7 @@ static int __devinit de_init_one (struct pci_dev *pdev, static void __devexit de_remove_one (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); BUG_ON(!dev); unregister_netdev(dev); @@ -2095,7 +2093,7 @@ static void __devexit de_remove_one (struct pci_dev *pdev) static int de_suspend (struct pci_dev *pdev, pm_message_t state) { struct net_device *dev = pci_get_drvdata (pdev); - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); rtnl_lock(); if (netif_running (dev)) { @@ -2130,7 +2128,7 @@ static int de_suspend (struct pci_dev *pdev, pm_message_t state) static int de_resume (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata (pdev); - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); int retval = 0; rtnl_lock(); diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index 6444cbec0bdc8dd02a0a9eca4c2066af15be2a96..67bfd6f4336617854f1c627544a4181b226ad585 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -1085,7 +1085,6 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev) struct de4x5_private *lp = netdev_priv(dev); struct pci_dev *pdev = NULL; int i, status=0; - DECLARE_MAC_BUF(mac); gendev->driver_data = dev; @@ -1119,10 +1118,10 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev) } dev->base_addr = iobase; - printk ("%s: %s at 0x%04lx", gendev->bus_id, name, iobase); + printk ("%s: %s at 0x%04lx", dev_name(gendev), name, iobase); status = get_hw_addr(dev); - printk(", h/w address %s\n", print_mac(mac, dev->dev_addr)); + printk(", h/w address %pM\n", dev->dev_addr); if (status != 0) { printk(" which has an Ethernet PROM CRC error.\n"); @@ -1154,7 +1153,7 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev) } } lp->fdx = lp->params.fdx; - sprintf(lp->adapter_name,"%s (%s)", name, gendev->bus_id); + sprintf(lp->adapter_name,"%s (%s)", name, dev_name(gendev)); lp->dma_size = (NUM_RX_DESC + NUM_TX_DESC) * sizeof(struct de4x5_desc); #if defined(__alpha__) || defined(__powerpc__) || defined(CONFIG_SPARC) || defined(DE4X5_DO_MEMCPY) @@ -1647,7 +1646,6 @@ de4x5_rx(struct net_device *dev) netif_rx(skb); /* Update stats */ - dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes += pkt_len; } @@ -5401,7 +5399,6 @@ static void de4x5_dbg_srom(struct de4x5_srom *p) { int i; - DECLARE_MAC_BUF(mac); if (de4x5_debug & DEBUG_SROM) { printk("Sub-system Vendor ID: %04x\n", *((u_short *)p->sub_vendor_id)); @@ -5410,7 +5407,7 @@ de4x5_dbg_srom(struct de4x5_srom *p) printk("SROM version: %02x\n", (u_char)(p->version)); printk("# controllers: %02x\n", (u_char)(p->num_controllers)); - printk("Hardware Address: %s\n", print_mac(mac, p->ieee_addr)); + printk("Hardware Address: %pM\n", p->ieee_addr); printk("CRC checksum: %04x\n", (u_short)(p->chksum)); for (i=0; i<64; i++) { printk("%3d %04x\n", i<<1, (u_short)*((u_short *)p+i)); @@ -5424,12 +5421,10 @@ static void de4x5_dbg_rx(struct sk_buff *skb, int len) { int i, j; - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); if (de4x5_debug & DEBUG_RX) { - printk("R: %s <- %s len/SAP:%02x%02x [%d]\n", - print_mac(mac, skb->data), print_mac(mac2, &skb->data[6]), + printk("R: %pM <- %pM len/SAP:%02x%02x [%d]\n", + skb->data, &skb->data[6], (u_char)skb->data[12], (u_char)skb->data[13], len); diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c index c91852f49a48e015cfc6056d337607087263f837..28a5c51b43a0654a846a2a4fa33f92f64d516602 100644 --- a/drivers/net/tulip/dmfe.c +++ b/drivers/net/tulip/dmfe.c @@ -362,7 +362,6 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev, struct net_device *dev; u32 pci_pmr; int i, err; - DECLARE_MAC_BUF(mac); DMFE_DBUG(0, "dmfe_init_one()", 0); @@ -475,12 +474,11 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev, if (err) goto err_out_free_buf; - printk(KERN_INFO "%s: Davicom DM%04lx at pci%s, " - "%s, irq %d.\n", + printk(KERN_INFO "%s: Davicom DM%04lx at pci%s, %pM, irq %d.\n", dev->name, ent->driver_data >> 16, pci_name(pdev), - print_mac(mac, dev->dev_addr), + dev->dev_addr, dev->irq); pci_set_master(pdev); @@ -1010,7 +1008,6 @@ static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db) skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; db->stats.rx_packets++; db->stats.rx_bytes += rxlen; } diff --git a/drivers/net/tulip/eeprom.c b/drivers/net/tulip/eeprom.c index 0dcced1263b9879fdf072b02d65f4d879da761d2..391acd32a6a5c04cc6234ddcb1b8833bff3f7a18 100644 --- a/drivers/net/tulip/eeprom.c +++ b/drivers/net/tulip/eeprom.c @@ -337,7 +337,7 @@ int __devinit tulip_read_eeprom(struct net_device *dev, int location, int addr_l { int i; unsigned retval = 0; - struct tulip_private *tp = dev->priv; + struct tulip_private *tp = netdev_priv(dev); void __iomem *ee_addr = tp->base_addr + CSR9; int read_cmd = location | (EE_READ_CMD << addr_len); diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c index c6bad987d63e744c452ed9d8b999aa0affe441d0..6c3428a37c0b9d5c672e777b052a199710d01c97 100644 --- a/drivers/net/tulip/interrupt.c +++ b/drivers/net/tulip/interrupt.c @@ -103,7 +103,7 @@ void oom_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; struct tulip_private *tp = netdev_priv(dev); - netif_rx_schedule(dev, &tp->napi); + netif_rx_schedule(&tp->napi); } int tulip_poll(struct napi_struct *napi, int budget) @@ -231,7 +231,6 @@ int tulip_poll(struct napi_struct *napi, int budget) netif_receive_skb(skb); - dev->last_rx = jiffies; tp->stats.rx_packets++; tp->stats.rx_bytes += pkt_len; } @@ -301,7 +300,7 @@ int tulip_poll(struct napi_struct *napi, int budget) /* Remove us from polling list and enable RX intr. */ - netif_rx_complete(dev, napi); + netif_rx_complete(napi); iowrite32(tulip_tbl[tp->chip_id].valid_intrs, tp->base_addr+CSR7); /* The last op happens after poll completion. Which means the following: @@ -337,7 +336,7 @@ int tulip_poll(struct napi_struct *napi, int budget) * before we did netif_rx_complete(). See? We would lose it. */ /* remove ourselves from the polling list */ - netif_rx_complete(dev, napi); + netif_rx_complete(napi); return work_done; } @@ -444,7 +443,6 @@ static int tulip_rx(struct net_device *dev) netif_rx(skb); - dev->last_rx = jiffies; tp->stats.rx_packets++; tp->stats.rx_bytes += pkt_len; } @@ -521,7 +519,7 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance) rxd++; /* Mask RX intrs and add the device to poll list. */ iowrite32(tulip_tbl[tp->chip_id].valid_intrs&~RxPollInt, ioaddr + CSR7); - netif_rx_schedule(dev, &tp->napi); + netif_rx_schedule(&tp->napi); if (!(csr5&~(AbnormalIntr|NormalIntr|RxPollInt|TPLnkPass))) break; diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index cafa89e6016772b0a5442df05dd348ae4984c857..ff84babb3ff38af2954b8e348b04e40512171014 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -1050,13 +1050,11 @@ static void set_rx_mode(struct net_device *dev) filterbit = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; filterbit &= 0x3f; mc_filter[filterbit >> 5] |= 1 << (filterbit & 31); - if (tulip_debug > 2) { - DECLARE_MAC_BUF(mac); - printk(KERN_INFO "%s: Added filter for %s" + if (tulip_debug > 2) + printk(KERN_INFO "%s: Added filter for %pM" " %8.8x bit %d.\n", - dev->name, print_mac(mac, mclist->dmi_addr), + dev->name, mclist->dmi_addr, ether_crc(ETH_ALEN, mclist->dmi_addr), filterbit); - } } if (mc_filter[0] == tp->mc_filter[0] && mc_filter[1] == tp->mc_filter[1]) @@ -1250,7 +1248,6 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, const char *chip_name = tulip_tbl[chip_idx].chip_name; unsigned int eeprom_missing = 0; unsigned int force_csr0 = 0; - DECLARE_MAC_BUF(mac); #ifndef MODULE static int did_version; /* Already printed version info. */ @@ -1432,9 +1429,9 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, for (i = 0; i < 3; i++) { int value, boguscnt = 100000; iowrite32(0x600 | i, ioaddr + 0x98); - do + do { value = ioread32(ioaddr + CSR9); - while (value < 0 && --boguscnt > 0); + } while (value < 0 && --boguscnt > 0); put_unaligned_le16(value, ((__le16 *)dev->dev_addr) + i); sum += value & 0xffff; } @@ -1635,7 +1632,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, if (eeprom_missing) printk(" EEPROM not present,"); - printk(" %s", print_mac(mac, dev->dev_addr)); + printk(" %pM", dev->dev_addr); printk(", IRQ %d.\n", irq); if (tp->chip_id == PNIC2) diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c index e9e628621639b6d5d8ceaf850086bf8da9587ab1..00cbc5251dccd16d083c69a93664fa5bb627e991 100644 --- a/drivers/net/tulip/uli526x.c +++ b/drivers/net/tulip/uli526x.c @@ -261,7 +261,6 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev, struct uli526x_board_info *db; /* board information structure */ struct net_device *dev; int i, err; - DECLARE_MAC_BUF(mac); ULI526X_DBUG(0, "uli526x_init_one()", 0); @@ -379,9 +378,9 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev, if (err) goto err_out_res; - printk(KERN_INFO "%s: ULi M%04lx at pci%s, %s, irq %d.\n", + printk(KERN_INFO "%s: ULi M%04lx at pci%s, %pM, irq %d.\n", dev->name,ent->driver_data >> 16,pci_name(pdev), - print_mac(mac, dev->dev_addr), dev->irq); + dev->dev_addr, dev->irq); pci_set_master(pdev); @@ -855,7 +854,6 @@ static void uli526x_rx_packet(struct net_device *dev, struct uli526x_board_info skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; db->stats.rx_packets++; db->stats.rx_bytes += rxlen; @@ -892,7 +890,7 @@ static struct net_device_stats * uli526x_get_stats(struct net_device *dev) static void uli526x_set_filter_mode(struct net_device * dev) { - struct uli526x_board_info *db = dev->priv; + struct uli526x_board_info *db = netdev_priv(dev); unsigned long flags; ULI526X_DBUG(0, "uli526x_set_filter_mode()", 0); diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index 50068194c163e55baec8c6e00bce96c970f56798..022d99af8646303bb25b1e0b7c7c4c6929fbee88 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -355,7 +355,6 @@ static int __devinit w840_probe1 (struct pci_dev *pdev, int irq; int i, option = find_cnt < MAX_UNITS ? options[find_cnt] : 0; void __iomem *ioaddr; - DECLARE_MAC_BUF(mac); i = pci_enable_device(pdev); if (i) return i; @@ -435,9 +434,9 @@ static int __devinit w840_probe1 (struct pci_dev *pdev, if (i) goto err_out_cleardev; - printk(KERN_INFO "%s: %s at %p, %s, IRQ %d.\n", + printk(KERN_INFO "%s: %s at %p, %pM, IRQ %d.\n", dev->name, pci_id_tbl[chip_idx].name, ioaddr, - print_mac(mac, dev->dev_addr), irq); + dev->dev_addr, irq); if (np->drv_flags & CanHaveMII) { int phy, phy_idx = 0; @@ -1245,20 +1244,15 @@ static int netdev_rx(struct net_device *dev) } #ifndef final_version /* Remove after testing. */ /* You will want this info for the initial debug. */ - if (debug > 5) { - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); - - printk(KERN_DEBUG " Rx data %s %s" + if (debug > 5) + printk(KERN_DEBUG " Rx data %pM %pM" " %2.2x%2.2x %d.%d.%d.%d.\n", - print_mac(mac, &skb->data[0]), print_mac(mac2, &skb->data[6]), + &skb->data[0], &skb->data[6], skb->data[12], skb->data[13], skb->data[14], skb->data[15], skb->data[16], skb->data[17]); - } #endif skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; np->stats.rx_packets++; np->stats.rx_bytes += pkt_len; } diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c index 6b93d016911650e0ef778ffeaf3dd9c06e370069..13c8703ecb9f0794e4ca718797a8ea0ea3ef8ed9 100644 --- a/drivers/net/tulip/xircom_cb.c +++ b/drivers/net/tulip/xircom_cb.c @@ -1072,7 +1072,6 @@ static void read_mac_address(struct xircom_private *card) unsigned char j, tuple, link, data_id, data_count; unsigned long flags; int i; - DECLARE_MAC_BUF(mac); enter("read_mac_address"); @@ -1102,7 +1101,7 @@ static void read_mac_address(struct xircom_private *card) } } spin_unlock_irqrestore(&card->lock, flags); - pr_debug(" %s\n", print_mac(mac, card->dev->dev_addr)); + pr_debug(" %pM\n", card->dev->dev_addr); leave("read_mac_address"); } @@ -1202,7 +1201,6 @@ static void investigate_read_descriptor(struct net_device *dev,struct xircom_pri skb_put(skb, pkt_len); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; card->stats.rx_packets++; card->stats.rx_bytes += pkt_len; diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 33b6d1b122fb59fdadfdd2f156a0596f37efcc25..666c1d98cdaf1d695aece39e195eac212d42e264 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -305,6 +305,23 @@ tun_net_change_mtu(struct net_device *dev, int new_mtu) return 0; } +static const struct net_device_ops tun_netdev_ops = { + .ndo_open = tun_net_open, + .ndo_stop = tun_net_close, + .ndo_start_xmit = tun_net_xmit, + .ndo_change_mtu = tun_net_change_mtu, +}; + +static const struct net_device_ops tap_netdev_ops = { + .ndo_open = tun_net_open, + .ndo_stop = tun_net_close, + .ndo_start_xmit = tun_net_xmit, + .ndo_change_mtu = tun_net_change_mtu, + .ndo_set_multicast_list = tun_net_mclist, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +}; + /* Initialize net device. */ static void tun_net_init(struct net_device *dev) { @@ -312,11 +329,12 @@ static void tun_net_init(struct net_device *dev) switch (tun->flags & TUN_TYPE_MASK) { case TUN_TUN_DEV: + dev->netdev_ops = &tun_netdev_ops; + /* Point-to-Point TUN Device */ dev->hard_header_len = 0; dev->addr_len = 0; dev->mtu = 1500; - dev->change_mtu = tun_net_change_mtu; /* Zero header length */ dev->type = ARPHRD_NONE; @@ -325,10 +343,9 @@ static void tun_net_init(struct net_device *dev) break; case TUN_TAP_DEV: + dev->netdev_ops = &tun_netdev_ops; /* Ethernet TAP Device */ ether_setup(dev); - dev->change_mtu = tun_net_change_mtu; - dev->set_multicast_list = tun_net_mclist; random_ether_addr(dev->dev_addr); @@ -529,7 +546,6 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv, } netif_rx_ni(skb); - tun->dev->last_rx = jiffies; tun->dev->stats.rx_packets++; tun->dev->stats.rx_bytes += len; @@ -676,9 +692,6 @@ static void tun_setup(struct net_device *dev) tun->owner = -1; tun->group = -1; - dev->open = tun_net_open; - dev->hard_start_xmit = tun_net_xmit; - dev->stop = tun_net_close; dev->ethtool_ops = &tun_ethtool_ops; dev->destructor = free_netdev; dev->features |= NETIF_F_NETNS_LOCAL; @@ -702,6 +715,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) struct tun_net *tn; struct tun_struct *tun; struct net_device *dev; + const struct cred *cred = current_cred(); int err; tn = net_generic(net, tun_net_id); @@ -712,11 +726,12 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) /* Check permissions */ if (((tun->owner != -1 && - current->euid != tun->owner) || + cred->euid != tun->owner) || (tun->group != -1 && - current->egid != tun->group)) && - !capable(CAP_NET_ADMIN)) + cred->egid != tun->group)) && + !capable(CAP_NET_ADMIN)) { return -EPERM; + } } else if (__dev_get_by_name(net, ifr->ifr_name)) return -EINVAL; @@ -750,6 +765,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) return -ENOMEM; dev_net_set(dev, net); + tun = netdev_priv(dev); tun->dev = dev; tun->flags = flags; @@ -883,7 +899,6 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, void __user* argp = (void __user*)arg; struct ifreq ifr; int ret; - DECLARE_MAC_BUF(mac); if (cmd == TUNSETIFF || _IOC_TYPE(cmd) == 0x89) if (copy_from_user(&ifr, argp, sizeof ifr)) @@ -1011,8 +1026,8 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, case SIOCSIFHWADDR: /* Set hw address */ - DBG(KERN_DEBUG "%s: set hw address: %s\n", - tun->dev->name, print_mac(mac, ifr.ifr_hwaddr.sa_data)); + DBG(KERN_DEBUG "%s: set hw address: %pM\n", + tun->dev->name, ifr.ifr_hwaddr.sa_data); rtnl_lock(); ret = dev_set_mac_address(tun->dev, &ifr.ifr_hwaddr); diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 734ce0977f02891e1c6d7a0ac0ba666e3f36ec49..0009f4e34433ee9f9130ca2c1a8122df612f07b7 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -1729,7 +1729,6 @@ typhoon_rx(struct typhoon *tp, struct basic_ring *rxRing, volatile __le32 * read netif_receive_skb(new_skb); spin_unlock(&tp->state_lock); - tp->dev->last_rx = jiffies; received++; budget--; } @@ -1756,7 +1755,6 @@ static int typhoon_poll(struct napi_struct *napi, int budget) { struct typhoon *tp = container_of(napi, struct typhoon, napi); - struct net_device *dev = tp->dev; struct typhoon_indexes *indexes = tp->indexes; int work_done; @@ -1785,7 +1783,7 @@ typhoon_poll(struct napi_struct *napi, int budget) } if (work_done < budget) { - netif_rx_complete(dev, napi); + netif_rx_complete(napi); iowrite32(TYPHOON_INTR_NONE, tp->ioaddr + TYPHOON_REG_INTR_MASK); typhoon_post_pci_writes(tp->ioaddr); @@ -1798,7 +1796,7 @@ static irqreturn_t typhoon_interrupt(int irq, void *dev_instance) { struct net_device *dev = dev_instance; - struct typhoon *tp = dev->priv; + struct typhoon *tp = netdev_priv(dev); void __iomem *ioaddr = tp->ioaddr; u32 intr_status; @@ -1808,10 +1806,10 @@ typhoon_interrupt(int irq, void *dev_instance) iowrite32(intr_status, ioaddr + TYPHOON_REG_INTR_STATUS); - if (netif_rx_schedule_prep(dev, &tp->napi)) { + if (netif_rx_schedule_prep(&tp->napi)) { iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK); typhoon_post_pci_writes(ioaddr); - __netif_rx_schedule(dev, &tp->napi); + __netif_rx_schedule(&tp->napi); } else { printk(KERN_ERR "%s: Error, poll already scheduled\n", dev->name); @@ -2311,7 +2309,6 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) struct cmd_desc xp_cmd; struct resp_desc xp_resp[3]; int err = 0; - DECLARE_MAC_BUF(mac); if(!did_version++) printk(KERN_INFO "%s", version); @@ -2526,11 +2523,11 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_drvdata(pdev, dev); - printk(KERN_INFO "%s: %s at %s 0x%llx, %s\n", + printk(KERN_INFO "%s: %s at %s 0x%llx, %pM\n", dev->name, typhoon_card_info[card_id].name, use_mmio ? "MMIO" : "IO", (unsigned long long)pci_resource_start(pdev, use_mmio), - print_mac(mac, dev->dev_addr)); + dev->dev_addr); /* xp_resp still contains the response to the READ_VERSIONS command. * For debugging, let the user know what version he has. diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index c87747bb24c55eb9ea2ac58992eabfdf348b664b..7d5a1303e30d2976aa518c161bcec2f281000339 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -188,17 +188,6 @@ static void mem_disp(u8 *addr, int size) } #endif /* DEBUG */ -#ifdef CONFIG_UGETH_FILTERING -static void enqueue(struct list_head *node, struct list_head *lh) -{ - unsigned long flags; - - spin_lock_irqsave(&ugeth_lock, flags); - list_add_tail(node, lh); - spin_unlock_irqrestore(&ugeth_lock, flags); -} -#endif /* CONFIG_UGETH_FILTERING */ - static struct list_head *dequeue(struct list_head *lh) { unsigned long flags; @@ -391,23 +380,6 @@ static int dump_init_enet_entries(struct ucc_geth_private *ugeth, } #endif -#ifdef CONFIG_UGETH_FILTERING -static struct enet_addr_container *get_enet_addr_container(void) -{ - struct enet_addr_container *enet_addr_cont; - - /* allocate memory */ - enet_addr_cont = kmalloc(sizeof(struct enet_addr_container), GFP_KERNEL); - if (!enet_addr_cont) { - ugeth_err("%s: No memory for enet_addr_container object.", - __func__); - return NULL; - } - - return enet_addr_cont; -} -#endif /* CONFIG_UGETH_FILTERING */ - static void put_enet_addr_container(struct enet_addr_container *enet_addr_cont) { kfree(enet_addr_cont); @@ -420,28 +392,6 @@ static void set_mac_addr(__be16 __iomem *reg, u8 *mac) out_be16(®[2], ((u16)mac[1] << 8) | mac[0]); } -#ifdef CONFIG_UGETH_FILTERING -static int hw_add_addr_in_paddr(struct ucc_geth_private *ugeth, - u8 *p_enet_addr, u8 paddr_num) -{ - struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt; - - if (!(paddr_num < NUM_OF_PADDRS)) { - ugeth_warn("%s: Illegal paddr_num.", __func__); - return -EINVAL; - } - - p_82xx_addr_filt = - (struct ucc_geth_82xx_address_filtering_pram *) ugeth->p_rx_glbl_pram-> - addressfiltering; - - /* Ethernet frames are defined in Little Endian mode, */ - /* therefore to insert the address we reverse the bytes. */ - set_mac_addr(&p_82xx_addr_filt->paddr[paddr_num].h, p_enet_addr); - return 0; -} -#endif /* CONFIG_UGETH_FILTERING */ - static int hw_clear_addr_in_paddr(struct ucc_geth_private *ugeth, u8 paddr_num) { struct ucc_geth_82xx_address_filtering_pram __iomem *p_82xx_addr_filt; @@ -1615,8 +1565,8 @@ static int init_phy(struct net_device *dev) priv->oldspeed = 0; priv->oldduplex = -1; - snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, priv->ug_info->mdio_bus, - priv->ug_info->phy_address); + snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, priv->ug_info->mdio_bus, + priv->ug_info->phy_address); phydev = phy_connect(dev, phy_id, &adjust_link, 0, priv->phy_interface); @@ -1647,6 +1597,7 @@ static int ugeth_graceful_stop_tx(struct ucc_geth_private *ugeth) struct ucc_fast_private *uccf; u32 cecr_subblock; u32 temp; + int i = 10; uccf = ugeth->uccf; @@ -1664,8 +1615,9 @@ static int ugeth_graceful_stop_tx(struct ucc_geth_private *ugeth) /* Wait for command to complete */ do { + msleep(10); temp = in_be32(uccf->p_ucce); - } while (!(temp & UCCE_GRA)); + } while (!(temp & UCCE_GRA) && --i); uccf->stopped_tx = 1; @@ -1677,6 +1629,7 @@ static int ugeth_graceful_stop_rx(struct ucc_geth_private * ugeth) struct ucc_fast_private *uccf; u32 cecr_subblock; u8 temp; + int i = 10; uccf = ugeth->uccf; @@ -1694,9 +1647,9 @@ static int ugeth_graceful_stop_rx(struct ucc_geth_private * ugeth) ucc_num); qe_issue_cmd(QE_GRACEFUL_STOP_RX, cecr_subblock, QE_CR_PROTOCOL_ETHERNET, 0); - + msleep(10); temp = in_8(&ugeth->p_rx_glbl_pram->rxgstpack); - } while (!(temp & GRACEFUL_STOP_ACKNOWLEDGE_RX)); + } while (!(temp & GRACEFUL_STOP_ACKNOWLEDGE_RX) && --i); uccf->stopped_rx = 1; @@ -1799,196 +1752,6 @@ static void ugeth_dump_regs(struct ucc_geth_private *ugeth) #endif } -#ifdef CONFIG_UGETH_FILTERING -static int ugeth_ext_filtering_serialize_tad(struct ucc_geth_tad_params * - p_UccGethTadParams, - struct qe_fltr_tad *qe_fltr_tad) -{ - u16 temp; - - /* Zero serialized TAD */ - memset(qe_fltr_tad, 0, QE_FLTR_TAD_SIZE); - - qe_fltr_tad->serialized[0] |= UCC_GETH_TAD_V; /* Must have this */ - if (p_UccGethTadParams->rx_non_dynamic_extended_features_mode || - (p_UccGethTadParams->vtag_op != UCC_GETH_VLAN_OPERATION_TAGGED_NOP) - || (p_UccGethTadParams->vnontag_op != - UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP) - ) - qe_fltr_tad->serialized[0] |= UCC_GETH_TAD_EF; - if (p_UccGethTadParams->reject_frame) - qe_fltr_tad->serialized[0] |= UCC_GETH_TAD_REJ; - temp = - (u16) (((u16) p_UccGethTadParams-> - vtag_op) << UCC_GETH_TAD_VTAG_OP_SHIFT); - qe_fltr_tad->serialized[0] |= (u8) (temp >> 8); /* upper bits */ - - qe_fltr_tad->serialized[1] |= (u8) (temp & 0x00ff); /* lower bits */ - if (p_UccGethTadParams->vnontag_op == - UCC_GETH_VLAN_OPERATION_NON_TAGGED_Q_TAG_INSERT) - qe_fltr_tad->serialized[1] |= UCC_GETH_TAD_V_NON_VTAG_OP; - qe_fltr_tad->serialized[1] |= - p_UccGethTadParams->rqos << UCC_GETH_TAD_RQOS_SHIFT; - - qe_fltr_tad->serialized[2] |= - p_UccGethTadParams->vpri << UCC_GETH_TAD_V_PRIORITY_SHIFT; - /* upper bits */ - qe_fltr_tad->serialized[2] |= (u8) (p_UccGethTadParams->vid >> 8); - /* lower bits */ - qe_fltr_tad->serialized[3] |= (u8) (p_UccGethTadParams->vid & 0x00ff); - - return 0; -} - -static struct enet_addr_container_t - *ugeth_82xx_filtering_get_match_addr_in_hash(struct ucc_geth_private *ugeth, - struct enet_addr *p_enet_addr) -{ - struct enet_addr_container *enet_addr_cont; - struct list_head *p_lh; - u16 i, num; - int32_t j; - u8 *p_counter; - - if ((*p_enet_addr)[0] & ENET_GROUP_ADDR) { - p_lh = &ugeth->group_hash_q; - p_counter = &(ugeth->numGroupAddrInHash); - } else { - p_lh = &ugeth->ind_hash_q; - p_counter = &(ugeth->numIndAddrInHash); - } - - if (!p_lh) - return NULL; - - num = *p_counter; - - for (i = 0; i < num; i++) { - enet_addr_cont = - (struct enet_addr_container *) - ENET_ADDR_CONT_ENTRY(dequeue(p_lh)); - for (j = ENET_NUM_OCTETS_PER_ADDRESS - 1; j >= 0; j--) { - if ((*p_enet_addr)[j] != (enet_addr_cont->address)[j]) - break; - if (j == 0) - return enet_addr_cont; /* Found */ - } - enqueue(p_lh, &enet_addr_cont->node); /* Put it back */ - } - return NULL; -} - -static int ugeth_82xx_filtering_add_addr_in_hash(struct ucc_geth_private *ugeth, - struct enet_addr *p_enet_addr) -{ - enum ucc_geth_enet_address_recognition_location location; - struct enet_addr_container *enet_addr_cont; - struct list_head *p_lh; - u8 i; - u32 limit; - u8 *p_counter; - - if ((*p_enet_addr)[0] & ENET_GROUP_ADDR) { - p_lh = &ugeth->group_hash_q; - limit = ugeth->ug_info->maxGroupAddrInHash; - location = - UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_GROUP_HASH; - p_counter = &(ugeth->numGroupAddrInHash); - } else { - p_lh = &ugeth->ind_hash_q; - limit = ugeth->ug_info->maxIndAddrInHash; - location = - UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_INDIVIDUAL_HASH; - p_counter = &(ugeth->numIndAddrInHash); - } - - if ((enet_addr_cont = - ugeth_82xx_filtering_get_match_addr_in_hash(ugeth, p_enet_addr))) { - list_add(p_lh, &enet_addr_cont->node); /* Put it back */ - return 0; - } - if ((!p_lh) || (!(*p_counter < limit))) - return -EBUSY; - if (!(enet_addr_cont = get_enet_addr_container())) - return -ENOMEM; - for (i = 0; i < ENET_NUM_OCTETS_PER_ADDRESS; i++) - (enet_addr_cont->address)[i] = (*p_enet_addr)[i]; - enet_addr_cont->location = location; - enqueue(p_lh, &enet_addr_cont->node); /* Put it back */ - ++(*p_counter); - - hw_add_addr_in_hash(ugeth, enet_addr_cont->address); - return 0; -} - -static int ugeth_82xx_filtering_clear_addr_in_hash(struct ucc_geth_private *ugeth, - struct enet_addr *p_enet_addr) -{ - struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt; - struct enet_addr_container *enet_addr_cont; - struct ucc_fast_private *uccf; - enum comm_dir comm_dir; - u16 i, num; - struct list_head *p_lh; - u32 *addr_h, *addr_l; - u8 *p_counter; - - uccf = ugeth->uccf; - - p_82xx_addr_filt = - (struct ucc_geth_82xx_address_filtering_pram *) ugeth->p_rx_glbl_pram-> - addressfiltering; - - if (! - (enet_addr_cont = - ugeth_82xx_filtering_get_match_addr_in_hash(ugeth, p_enet_addr))) - return -ENOENT; - - /* It's been found and removed from the CQ. */ - /* Now destroy its container */ - put_enet_addr_container(enet_addr_cont); - - if ((*p_enet_addr)[0] & ENET_GROUP_ADDR) { - addr_h = &(p_82xx_addr_filt->gaddr_h); - addr_l = &(p_82xx_addr_filt->gaddr_l); - p_lh = &ugeth->group_hash_q; - p_counter = &(ugeth->numGroupAddrInHash); - } else { - addr_h = &(p_82xx_addr_filt->iaddr_h); - addr_l = &(p_82xx_addr_filt->iaddr_l); - p_lh = &ugeth->ind_hash_q; - p_counter = &(ugeth->numIndAddrInHash); - } - - comm_dir = 0; - if (uccf->enabled_tx) - comm_dir |= COMM_DIR_TX; - if (uccf->enabled_rx) - comm_dir |= COMM_DIR_RX; - if (comm_dir) - ugeth_disable(ugeth, comm_dir); - - /* Clear the hash table. */ - out_be32(addr_h, 0x00000000); - out_be32(addr_l, 0x00000000); - - /* Add all remaining CQ elements back into hash */ - num = --(*p_counter); - for (i = 0; i < num; i++) { - enet_addr_cont = - (struct enet_addr_container *) - ENET_ADDR_CONT_ENTRY(dequeue(p_lh)); - hw_add_addr_in_hash(ugeth, enet_addr_cont->address); - enqueue(p_lh, &enet_addr_cont->node); /* Put it back */ - } - - if (comm_dir) - ugeth_enable(ugeth, comm_dir); - - return 0; -} -#endif /* CONFIG_UGETH_FILTERING */ - static int ugeth_82xx_filtering_clear_all_addr_in_hash(struct ucc_geth_private * ugeth, enum enet_addr_type @@ -2051,28 +1814,6 @@ static int ugeth_82xx_filtering_clear_all_addr_in_hash(struct ucc_geth_private * return 0; } -#ifdef CONFIG_UGETH_FILTERING -static int ugeth_82xx_filtering_add_addr_in_paddr(struct ucc_geth_private *ugeth, - struct enet_addr *p_enet_addr, - u8 paddr_num) -{ - int i; - - if ((*p_enet_addr)[0] & ENET_GROUP_ADDR) - ugeth_warn - ("%s: multicast address added to paddr will have no " - "effect - is this what you wanted?", - __func__); - - ugeth->indAddrRegUsed[paddr_num] = 1; /* mark this paddr as used */ - /* store address in our database */ - for (i = 0; i < ENET_NUM_OCTETS_PER_ADDRESS; i++) - ugeth->paddr[paddr_num][i] = (*p_enet_addr)[i]; - /* put in hardware */ - return hw_add_addr_in_paddr(ugeth, p_enet_addr, paddr_num); -} -#endif /* CONFIG_UGETH_FILTERING */ - static int ugeth_82xx_filtering_clear_addr_in_paddr(struct ucc_geth_private *ugeth, u8 paddr_num) { @@ -2215,7 +1956,10 @@ static void ucc_geth_memclean(struct ucc_geth_private *ugeth) while (!list_empty(&ugeth->ind_hash_q)) put_enet_addr_container(ENET_ADDR_CONT_ENTRY (dequeue(&ugeth->ind_hash_q))); - + if (ugeth->ug_regs) { + iounmap(ugeth->ug_regs); + ugeth->ug_regs = NULL; + } } static void ucc_geth_set_multi(struct net_device *dev) @@ -2297,8 +2041,6 @@ static void ucc_geth_stop(struct ucc_geth_private *ugeth) tempval &= ~(MACCFG1_ENABLE_RX | MACCFG1_ENABLE_TX); out_be32(&ug_regs->maccfg1, tempval); - free_irq(ugeth->ug_info->uf_info.irq, ugeth->dev); - ucc_geth_memclean(ugeth); } @@ -2419,11 +2161,15 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth) if (ucc_fast_init(uf_info, &ugeth->uccf)) { if (netif_msg_probe(ugeth)) ugeth_err("%s: Failed to init uccf.", __func__); - ucc_geth_memclean(ugeth); return -ENOMEM; } - ugeth->ug_regs = (struct ucc_geth __iomem *) ioremap(uf_info->regs, sizeof(struct ucc_geth)); + ugeth->ug_regs = ioremap(uf_info->regs, sizeof(*ugeth->ug_regs)); + if (!ugeth->ug_regs) { + if (netif_msg_probe(ugeth)) + ugeth_err("%s: Failed to ioremap regs.", __func__); + return -ENOMEM; + } return 0; } @@ -2475,7 +2221,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) ugeth_err("%s: Bad number of Rx threads value.", __func__); - ucc_geth_memclean(ugeth); return -EINVAL; break; } @@ -2500,7 +2245,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) ugeth_err("%s: Bad number of Tx threads value.", __func__); - ucc_geth_memclean(ugeth); return -EINVAL; break; } @@ -2554,7 +2298,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) ugeth_err("%s: IPGIFG initialization parameter too large.", __func__); - ucc_geth_memclean(ugeth); return ret_val; } @@ -2572,7 +2315,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) ugeth_err("%s: Half Duplex initialization parameter too large.", __func__); - ucc_geth_memclean(ugeth); return ret_val; } @@ -2627,7 +2369,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) ugeth_err ("%s: Can not allocate memory for Tx bd rings.", __func__); - ucc_geth_memclean(ugeth); return -ENOMEM; } /* Zero unused end of bd ring, according to spec */ @@ -2663,7 +2404,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) ugeth_err ("%s: Can not allocate memory for Rx bd rings.", __func__); - ucc_geth_memclean(ugeth); return -ENOMEM; } } @@ -2679,7 +2419,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) ugeth_err("%s: Could not allocate tx_skbuff", __func__); - ucc_geth_memclean(ugeth); return -ENOMEM; } @@ -2711,7 +2450,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) ugeth_err("%s: Could not allocate rx_skbuff", __func__); - ucc_geth_memclean(ugeth); return -ENOMEM; } @@ -2745,7 +2483,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) ugeth_err ("%s: Can not allocate DPRAM memory for p_tx_glbl_pram.", __func__); - ucc_geth_memclean(ugeth); return -ENOMEM; } ugeth->p_tx_glbl_pram = @@ -2768,7 +2505,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) ugeth_err ("%s: Can not allocate DPRAM memory for p_thread_data_tx.", __func__); - ucc_geth_memclean(ugeth); return -ENOMEM; } @@ -2798,7 +2534,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) ugeth_err ("%s: Can not allocate DPRAM memory for p_send_q_mem_reg.", __func__); - ucc_geth_memclean(ugeth); return -ENOMEM; } @@ -2842,7 +2577,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) ugeth_err ("%s: Can not allocate DPRAM memory for p_scheduler.", __func__); - ucc_geth_memclean(ugeth); return -ENOMEM; } @@ -2893,7 +2627,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) ("%s: Can not allocate DPRAM memory for" " p_tx_fw_statistics_pram.", __func__); - ucc_geth_memclean(ugeth); return -ENOMEM; } ugeth->p_tx_fw_statistics_pram = @@ -2933,7 +2666,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) ugeth_err ("%s: Can not allocate DPRAM memory for p_rx_glbl_pram.", __func__); - ucc_geth_memclean(ugeth); return -ENOMEM; } ugeth->p_rx_glbl_pram = @@ -2955,7 +2687,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) ugeth_err ("%s: Can not allocate DPRAM memory for p_thread_data_rx.", __func__); - ucc_geth_memclean(ugeth); return -ENOMEM; } @@ -2979,7 +2710,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) ugeth_err ("%s: Can not allocate DPRAM memory for" " p_rx_fw_statistics_pram.", __func__); - ucc_geth_memclean(ugeth); return -ENOMEM; } ugeth->p_rx_fw_statistics_pram = @@ -3002,7 +2732,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) ugeth_err ("%s: Can not allocate DPRAM memory for" " p_rx_irq_coalescing_tbl.", __func__); - ucc_geth_memclean(ugeth); return -ENOMEM; } @@ -3071,7 +2800,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) ugeth_err ("%s: Can not allocate DPRAM memory for p_rx_bd_qs_tbl.", __func__); - ucc_geth_memclean(ugeth); return -ENOMEM; } @@ -3148,7 +2876,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) ugeth_err("%s: Null Extended Filtering Chain Pointer.", __func__); - ucc_geth_memclean(ugeth); return -EINVAL; } @@ -3162,7 +2889,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) ugeth_err ("%s: Can not allocate DPRAM memory for" " p_exf_glbl_param.", __func__); - ucc_geth_memclean(ugeth); return -ENOMEM; } @@ -3210,7 +2936,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) ugeth_err ("%s: Can not allocate memory for" " p_UccInitEnetParamShadows.", __func__); - ucc_geth_memclean(ugeth); return -ENOMEM; } /* Zero out *p_init_enet_param_shadow */ @@ -3245,7 +2970,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) ugeth_err("%s: Invalid largest External Lookup Key Size.", __func__); - ucc_geth_memclean(ugeth); return -EINVAL; } ugeth->p_init_enet_param_shadow->largestexternallookupkeysize = @@ -3272,7 +2996,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) ugeth_err("%s: Can not fill p_init_enet_param_shadow.", __func__); - ucc_geth_memclean(ugeth); return ret_val; } @@ -3288,7 +3011,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) ugeth_err("%s: Can not fill p_init_enet_param_shadow.", __func__); - ucc_geth_memclean(ugeth); return ret_val; } @@ -3298,7 +3020,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) ugeth_err("%s: Can not fill Rx bds with buffers.", __func__); - ucc_geth_memclean(ugeth); return ret_val; } } @@ -3310,7 +3031,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) ugeth_err ("%s: Can not allocate DPRAM memory for p_init_enet_pram.", __func__); - ucc_geth_memclean(ugeth); return -ENOMEM; } p_init_enet_pram = @@ -3352,28 +3072,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) return 0; } -/* ucc_geth_timeout gets called when a packet has not been - * transmitted after a set amount of time. - * For now, assume that clearing out all the structures, and - * starting over will fix the problem. */ -static void ucc_geth_timeout(struct net_device *dev) -{ - struct ucc_geth_private *ugeth = netdev_priv(dev); - - ugeth_vdbg("%s: IN", __func__); - - dev->stats.tx_errors++; - - ugeth_dump_regs(ugeth); - - if (dev->flags & IFF_UP) { - ucc_geth_stop(ugeth); - ucc_geth_startup(ugeth); - } - - netif_tx_schedule_all(dev); -} - /* This is called by the kernel when a frame is ready for transmission. */ /* It is pointed to by the dev->hard_start_xmit function pointer */ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev) @@ -3502,8 +3200,6 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit netif_receive_skb(skb); } - ugeth->dev->last_rx = jiffies; - skb = get_new_skb(ugeth, bd); if (!skb) { if (netif_msg_rx_err(ugeth)) @@ -3592,7 +3288,7 @@ static int ucc_geth_poll(struct napi_struct *napi, int budget) struct ucc_fast_private *uccf; u32 uccm; - netif_rx_complete(dev, napi); + netif_rx_complete(napi); uccf = ugeth->uccf; uccm = in_be32(uccf->p_uccm); uccm |= UCCE_RX_EVENTS; @@ -3626,10 +3322,10 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info) /* check for receive events that require processing */ if (ucce & UCCE_RX_EVENTS) { - if (netif_rx_schedule_prep(dev, &ugeth->napi)) { + if (netif_rx_schedule_prep(&ugeth->napi)) { uccm &= ~UCCE_RX_EVENTS; out_be32(uccf->p_uccm, uccm); - __netif_rx_schedule(dev, &ugeth->napi); + __netif_rx_schedule(&ugeth->napi); } } @@ -3697,7 +3393,7 @@ static int ucc_geth_open(struct net_device *dev) if (err) { if (netif_msg_ifup(ugeth)) ugeth_err("%s: Cannot configure internal struct, aborting.", dev->name); - return err; + goto out_err_stop; } napi_enable(&ugeth->napi); @@ -3738,22 +3434,19 @@ static int ucc_geth_open(struct net_device *dev) phy_start(ugeth->phydev); - err = - request_irq(ugeth->ug_info->uf_info.irq, ucc_geth_irq_handler, 0, - "UCC Geth", dev); + err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX); if (err) { if (netif_msg_ifup(ugeth)) - ugeth_err("%s: Cannot get IRQ for net device, aborting.", - dev->name); - ucc_geth_stop(ugeth); + ugeth_err("%s: Cannot enable net device, aborting.", dev->name); goto out_err; } - err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX); + err = request_irq(ugeth->ug_info->uf_info.irq, ucc_geth_irq_handler, + 0, "UCC Geth", dev); if (err) { if (netif_msg_ifup(ugeth)) - ugeth_err("%s: Cannot enable net device, aborting.", dev->name); - ucc_geth_stop(ugeth); + ugeth_err("%s: Cannot get IRQ for net device, aborting.", + dev->name); goto out_err; } @@ -3763,7 +3456,8 @@ static int ucc_geth_open(struct net_device *dev) out_err: napi_disable(&ugeth->napi); - +out_err_stop: + ucc_geth_stop(ugeth); return err; } @@ -3778,6 +3472,8 @@ static int ucc_geth_close(struct net_device *dev) ucc_geth_stop(ugeth); + free_irq(ugeth->ug_info->uf_info.irq, ugeth->dev); + phy_disconnect(ugeth->phydev); ugeth->phydev = NULL; @@ -3786,6 +3482,45 @@ static int ucc_geth_close(struct net_device *dev) return 0; } +/* Reopen device. This will reset the MAC and PHY. */ +static void ucc_geth_timeout_work(struct work_struct *work) +{ + struct ucc_geth_private *ugeth; + struct net_device *dev; + + ugeth = container_of(work, struct ucc_geth_private, timeout_work); + dev = ugeth->dev; + + ugeth_vdbg("%s: IN", __func__); + + dev->stats.tx_errors++; + + ugeth_dump_regs(ugeth); + + if (dev->flags & IFF_UP) { + /* + * Must reset MAC *and* PHY. This is done by reopening + * the device. + */ + ucc_geth_close(dev); + ucc_geth_open(dev); + } + + netif_tx_schedule_all(dev); +} + +/* + * ucc_geth_timeout gets called when a packet has not been + * transmitted after a set amount of time. + */ +static void ucc_geth_timeout(struct net_device *dev) +{ + struct ucc_geth_private *ugeth = netdev_priv(dev); + + netif_carrier_off(dev); + schedule_work(&ugeth->timeout_work); +} + static phy_interface_t to_phy_interface(const char *phy_connection_type) { if (strcasecmp(phy_connection_type, "mii") == 0) @@ -4026,6 +3761,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma dev->hard_start_xmit = ucc_geth_start_xmit; dev->tx_timeout = ucc_geth_timeout; dev->watchdog_timeo = TX_TIMEOUT; + INIT_WORK(&ugeth->timeout_work, ucc_geth_timeout_work); netif_napi_add(dev, &ugeth->napi, ucc_geth_poll, UCC_GETH_DEV_WEIGHT); #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = ucc_netpoll; diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h index abc0e224263487efb7a28ab7a07f4d40bdce9d87..d74d2f7cb73968e8e98e3a7f1ef65f8ddb20c794 100644 --- a/drivers/net/ucc_geth.h +++ b/drivers/net/ucc_geth.h @@ -1186,6 +1186,7 @@ struct ucc_geth_private { struct ucc_fast_private *uccf; struct net_device *dev; struct napi_struct napi; + struct work_struct timeout_work; struct ucc_geth __iomem *ug_regs; struct ucc_geth_init_pram *p_init_enet_param_shadow; struct ucc_geth_exf_global_pram __iomem *p_exf_glbl_param; diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c index de57490103fcd05e58a8610d7fb77b3dbc0ffc20..e009481c606c740cea0b2a30fd7bad7f30f3fe8d 100644 --- a/drivers/net/usb/asix.c +++ b/drivers/net/usb/asix.c @@ -246,10 +246,11 @@ static int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, static void asix_async_cmd_callback(struct urb *urb) { struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; + int status = urb->status; - if (urb->status < 0) + if (status < 0) printk(KERN_DEBUG "asix_async_cmd_callback() failed with %d", - urb->status); + status); kfree(req); usb_free_urb(urb); diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c index 466a89e244445cb59bdd3a94c43c184be4fee185..cb7acbbb279875893a1fa3f398a8fe5eaa5fe22e 100644 --- a/drivers/net/usb/catc.c +++ b/drivers/net/usb/catc.c @@ -229,14 +229,15 @@ static void catc_rx_done(struct urb *urb) u8 *pkt_start = urb->transfer_buffer; struct sk_buff *skb; int pkt_len, pkt_offset = 0; + int status = urb->status; if (!catc->is_f5u011) { clear_bit(RX_RUNNING, &catc->flags); pkt_offset = 2; } - if (urb->status) { - dbg("rx_done, status %d, length %d", urb->status, urb->actual_length); + if (status) { + dbg("rx_done, status %d, length %d", status, urb->actual_length); return; } @@ -271,16 +272,14 @@ static void catc_rx_done(struct urb *urb) } while (pkt_start - (u8 *) urb->transfer_buffer < urb->actual_length); - catc->netdev->last_rx = jiffies; - if (catc->is_f5u011) { if (atomic_read(&catc->recq_sz)) { - int status; + int state; atomic_dec(&catc->recq_sz); dbg("getting extra packet"); urb->dev = catc->usbdev; - if ((status = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { - dbg("submit(rx_urb) status %d", status); + if ((state = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { + dbg("submit(rx_urb) status %d", state); } } else { clear_bit(RX_RUNNING, &catc->flags); @@ -292,8 +291,9 @@ static void catc_irq_done(struct urb *urb) { struct catc *catc = urb->context; u8 *data = urb->transfer_buffer; - int status; + int status = urb->status; unsigned int hasdata = 0, linksts = LinkNoChange; + int res; if (!catc->is_f5u011) { hasdata = data[1] & 0x80; @@ -309,7 +309,7 @@ static void catc_irq_done(struct urb *urb) linksts = LinkBad; } - switch (urb->status) { + switch (status) { case 0: /* success */ break; case -ECONNRESET: /* unlink */ @@ -318,7 +318,7 @@ static void catc_irq_done(struct urb *urb) return; /* -EPIPE: should clear the halt */ default: /* error */ - dbg("irq_done, status %d, data %02x %02x.", urb->status, data[0], data[1]); + dbg("irq_done, status %d, data %02x %02x.", status, data[0], data[1]); goto resubmit; } @@ -338,17 +338,17 @@ static void catc_irq_done(struct urb *urb) atomic_inc(&catc->recq_sz); } else { catc->rx_urb->dev = catc->usbdev; - if ((status = usb_submit_urb(catc->rx_urb, GFP_ATOMIC)) < 0) { - err("submit(rx_urb) status %d", status); + if ((res = usb_submit_urb(catc->rx_urb, GFP_ATOMIC)) < 0) { + err("submit(rx_urb) status %d", res); } } } resubmit: - status = usb_submit_urb (urb, GFP_ATOMIC); - if (status) + res = usb_submit_urb (urb, GFP_ATOMIC); + if (res) err ("can't resubmit intr, %s-%s, status %d", catc->usbdev->bus->bus_name, - catc->usbdev->devpath, status); + catc->usbdev->devpath, res); } /* @@ -380,9 +380,9 @@ static void catc_tx_done(struct urb *urb) { struct catc *catc = urb->context; unsigned long flags; - int r; + int r, status = urb->status; - if (urb->status == -ECONNRESET) { + if (status == -ECONNRESET) { dbg("Tx Reset."); urb->status = 0; catc->netdev->trans_start = jiffies; @@ -392,8 +392,8 @@ static void catc_tx_done(struct urb *urb) return; } - if (urb->status) { - dbg("tx_done, status %d, length %d", urb->status, urb->actual_length); + if (status) { + dbg("tx_done, status %d, length %d", status, urb->actual_length); return; } @@ -504,9 +504,10 @@ static void catc_ctrl_done(struct urb *urb) struct catc *catc = urb->context; struct ctrl_queue *q; unsigned long flags; + int status = urb->status; - if (urb->status) - dbg("ctrl_done, status %d, len %d.", urb->status, urb->actual_length); + if (status) + dbg("ctrl_done, status %d, len %d.", status, urb->actual_length); spin_lock_irqsave(&catc->ctrl_lock, flags); diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c index db3377dae9d5f99156cf569008ca8795dc598fed..edd244f3acb50488c031863997101ff41469c797 100644 --- a/drivers/net/usb/dm9601.c +++ b/drivers/net/usb/dm9601.c @@ -123,10 +123,11 @@ static int dm_write_reg(struct usbnet *dev, u8 reg, u8 value) static void dm_write_async_callback(struct urb *urb) { struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; + int status = urb->status; - if (urb->status < 0) + if (status < 0) printk(KERN_DEBUG "dm_write_async_callback() failed with %d\n", - urb->status); + status); kfree(req); usb_free_urb(urb); diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 8e90891f0e422b8cc0f645c9eab388ff39b22d45..198ce3cf378ae2b884ce16b21a5fa1ba7a028d5c 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -417,6 +417,11 @@ static const struct usb_device_id hso_ids[] = { {USB_DEVICE(0x0af0, 0x7401)}, /* GI 0401 */ {USB_DEVICE(0x0af0, 0x7501)}, /* GTM 382 */ {USB_DEVICE(0x0af0, 0x7601)}, /* GE40x */ + {USB_DEVICE(0x0af0, 0x7701)}, + {USB_DEVICE(0x0af0, 0x7801)}, + {USB_DEVICE(0x0af0, 0x7901)}, + {USB_DEVICE(0x0af0, 0x7361)}, + {icon321_port_device(0x0af0, 0xd051)}, {} }; MODULE_DEVICE_TABLE(usb, hso_ids); @@ -658,10 +663,9 @@ static int hso_net_open(struct net_device *net) odev->rx_buf_missing = sizeof(struct iphdr); spin_unlock_irqrestore(&odev->net_lock, flags); - hso_start_net_device(odev->parent); - /* We are up and running. */ set_bit(HSO_NET_RUNNING, &odev->flags); + hso_start_net_device(odev->parent); /* Tell the kernel we are ready to start receiving from it */ netif_start_queue(net); @@ -2750,18 +2754,21 @@ static int hso_resume(struct usb_interface *iface) if (network_table[i] && (network_table[i]->interface == iface)) { hso_net = dev2net(network_table[i]); - /* First transmit any lingering data, then restart the - * device. */ - if (hso_net->skb_tx_buf) { - dev_dbg(&iface->dev, - "Transmitting lingering data\n"); - hso_net_start_xmit(hso_net->skb_tx_buf, - hso_net->net); - hso_net->skb_tx_buf = NULL; + if (hso_net->flags & IFF_UP) { + /* First transmit any lingering data, + then restart the device. */ + if (hso_net->skb_tx_buf) { + dev_dbg(&iface->dev, + "Transmitting" + " lingering data\n"); + hso_net_start_xmit(hso_net->skb_tx_buf, + hso_net->net); + hso_net->skb_tx_buf = NULL; + } + result = hso_start_net_device(network_table[i]); + if (result) + goto out; } - result = hso_start_net_device(network_table[i]); - if (result) - goto out; } } @@ -2894,6 +2901,7 @@ static struct usb_driver hso_driver = { .id_table = hso_ids, .suspend = hso_suspend, .resume = hso_resume, + .reset_resume = hso_resume, .supports_autosuspend = 1, }; diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index fdbf3be24fda499e5065b7b3c691ade64f56397e..2ee034f70d1c61a1cfd0cbb799f02485ce654bdc 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c @@ -516,8 +516,9 @@ static void int_callback(struct urb *u) { struct kaweth_device *kaweth = u->context; int act_state; + int status = u->status; - switch (u->status) { + switch (status) { case 0: /* success */ break; case -ECONNRESET: /* unlink */ @@ -598,6 +599,7 @@ static void kaweth_usb_receive(struct urb *urb) { struct kaweth_device *kaweth = urb->context; struct net_device *net = kaweth->net; + int status = urb->status; int count = urb->actual_length; int count2 = urb->transfer_buffer_length; @@ -606,7 +608,7 @@ static void kaweth_usb_receive(struct urb *urb) struct sk_buff *skb; - if(unlikely(urb->status == -ECONNRESET || urb->status == -ESHUTDOWN)) + if(unlikely(status == -ECONNRESET || status == -ESHUTDOWN)) /* we are killed - set a flag and wake the disconnect handler */ { kaweth->end = 1; @@ -621,10 +623,10 @@ static void kaweth_usb_receive(struct urb *urb) } spin_unlock(&kaweth->device_lock); - if(urb->status && urb->status != -EREMOTEIO && count != 1) { + if(status && status != -EREMOTEIO && count != 1) { err("%s RX status: %d count: %d packet_len: %d", net->name, - urb->status, + status, count, (int)pkt_len); kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC); @@ -775,10 +777,11 @@ static void kaweth_usb_transmit_complete(struct urb *urb) { struct kaweth_device *kaweth = urb->context; struct sk_buff *skb = kaweth->tx_skb; + int status = urb->status; - if (unlikely(urb->status != 0)) - if (urb->status != -ENOENT) - dbg("%s: TX status %d.", kaweth->net->name, urb->status); + if (unlikely(status != 0)) + if (status != -ENOENT) + dbg("%s: TX status %d.", kaweth->net->name, status); netif_wake_queue(kaweth->net); dev_kfree_skb_irq(skb); diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c index b5143509e8be1f70e0433939d30ac44ef9a7e28f..5385d66b306ebd284ac973e87a9209b4b7aa89ff 100644 --- a/drivers/net/usb/mcs7830.c +++ b/drivers/net/usb/mcs7830.c @@ -115,10 +115,11 @@ static int mcs7830_set_reg(struct usbnet *dev, u16 index, u16 size, void *data) static void mcs7830_async_cmd_callback(struct urb *urb) { struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; + int status = urb->status; - if (urb->status < 0) + if (status < 0) printk(KERN_DEBUG "%s() failed with %d\n", - __func__, urb->status); + __func__, status); kfree(req); usb_free_urb(urb); @@ -344,14 +345,14 @@ static int mcs7830_init_dev(struct usbnet *dev) static int mcs7830_mdio_read(struct net_device *netdev, int phy_id, int location) { - struct usbnet *dev = netdev->priv; + struct usbnet *dev = netdev_priv(netdev); return mcs7830_read_phy(dev, location); } static void mcs7830_mdio_write(struct net_device *netdev, int phy_id, int location, int val) { - struct usbnet *dev = netdev->priv; + struct usbnet *dev = netdev_priv(netdev); mcs7830_write_phy(dev, location, val); } diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index 7914867110ed74ef3e0f17f4dcba685ea4450d73..166880c113d6718ad00b87f75f0b84caa93867b3 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -99,11 +99,12 @@ static int update_eth_regs_async(pegasus_t *); static void ctrl_callback(struct urb *urb) { pegasus_t *pegasus = urb->context; + int status = urb->status; if (!pegasus) return; - switch (urb->status) { + switch (status) { case 0: if (pegasus->flags & ETH_REGS_CHANGE) { pegasus->flags &= ~ETH_REGS_CHANGE; @@ -119,7 +120,7 @@ static void ctrl_callback(struct urb *urb) default: if (netif_msg_drv(pegasus) && printk_ratelimit()) dev_dbg(&pegasus->intf->dev, "%s, status %d\n", - __func__, urb->status); + __func__, status); } pegasus->flags &= ~ETH_REGS_CHANGED; wake_up(&pegasus->ctrl_wait); @@ -611,6 +612,7 @@ static void read_bulk_callback(struct urb *urb) pegasus_t *pegasus = urb->context; struct net_device *net; int rx_status, count = urb->actual_length; + int status = urb->status; u8 *buf = urb->transfer_buffer; __u16 pkt_len; @@ -621,7 +623,7 @@ static void read_bulk_callback(struct urb *urb) if (!netif_device_present(net) || !netif_running(net)) return; - switch (urb->status) { + switch (status) { case 0: break; case -ETIME: @@ -639,11 +641,11 @@ static void read_bulk_callback(struct urb *urb) case -ECONNRESET: case -ESHUTDOWN: if (netif_msg_ifdown(pegasus)) - pr_debug("%s: rx unlink, %d\n", net->name, urb->status); + pr_debug("%s: rx unlink, %d\n", net->name, status); return; default: if (netif_msg_rx_err(pegasus)) - pr_debug("%s: RX status %d\n", net->name, urb->status); + pr_debug("%s: RX status %d\n", net->name, status); goto goon; } @@ -769,6 +771,7 @@ static void write_bulk_callback(struct urb *urb) { pegasus_t *pegasus = urb->context; struct net_device *net; + int status = urb->status; if (!pegasus) return; @@ -778,7 +781,7 @@ static void write_bulk_callback(struct urb *urb) if (!netif_device_present(net) || !netif_running(net)) return; - switch (urb->status) { + switch (status) { case -EPIPE: /* FIXME schedule_work() to clear the tx halt */ netif_stop_queue(net); @@ -790,11 +793,11 @@ static void write_bulk_callback(struct urb *urb) case -ECONNRESET: case -ESHUTDOWN: if (netif_msg_ifdown(pegasus)) - pr_debug("%s: tx unlink, %d\n", net->name, urb->status); + pr_debug("%s: tx unlink, %d\n", net->name, status); return; default: if (netif_msg_tx_err(pegasus)) - pr_info("%s: TX status %d\n", net->name, urb->status); + pr_info("%s: TX status %d\n", net->name, status); /* FALL THROUGH */ case 0: break; @@ -808,13 +811,13 @@ static void intr_callback(struct urb *urb) { pegasus_t *pegasus = urb->context; struct net_device *net; - int status; + int res, status = urb->status; if (!pegasus) return; net = pegasus->net; - switch (urb->status) { + switch (status) { case 0: break; case -ECONNRESET: /* unlink */ @@ -827,7 +830,7 @@ static void intr_callback(struct urb *urb) */ if (netif_msg_timer(pegasus)) pr_debug("%s: intr status %d\n", net->name, - urb->status); + status); } if (urb->actual_length >= 6) { @@ -854,12 +857,12 @@ static void intr_callback(struct urb *urb) pegasus->stats.rx_missed_errors += ((d[3] & 0x7f) << 8) | d[4]; } - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status == -ENODEV) + res = usb_submit_urb(urb, GFP_ATOMIC); + if (res == -ENODEV) netif_device_detach(pegasus->net); - if (status && netif_msg_timer(pegasus)) + if (res && netif_msg_timer(pegasus)) printk(KERN_ERR "%s: can't resubmit interrupt urb, %d\n", - net->name, status); + net->name, res); } static void pegasus_tx_timeout(struct net_device *net) @@ -1213,7 +1216,7 @@ static void pegasus_set_multicast(struct net_device *net) pegasus->eth_regs[EthCtrl0] |= RX_MULTICAST; pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS; if (netif_msg_link(pegasus)) - pr_info("%s: set allmulti\n", net->name); + pr_debug("%s: set allmulti\n", net->name); } else { pegasus->eth_regs[EthCtrl0] &= ~RX_MULTICAST; pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS; @@ -1273,6 +1276,7 @@ static inline void setup_pegasus_II(pegasus_t * pegasus) } +static int pegasus_count; static struct workqueue_struct *pegasus_workqueue = NULL; #define CARRIER_CHECK_DELAY (2 * HZ) @@ -1301,6 +1305,18 @@ static int pegasus_blacklisted(struct usb_device *udev) return 0; } +/* we rely on probe() and remove() being serialized so we + * don't need extra locking on pegasus_count. + */ +static void pegasus_dec_workqueue(void) +{ + pegasus_count--; + if (pegasus_count == 0) { + destroy_workqueue(pegasus_workqueue); + pegasus_workqueue = NULL; + } +} + static int pegasus_probe(struct usb_interface *intf, const struct usb_device_id *id) { @@ -1309,14 +1325,18 @@ static int pegasus_probe(struct usb_interface *intf, pegasus_t *pegasus; int dev_index = id - pegasus_ids; int res = -ENOMEM; - DECLARE_MAC_BUF(mac); - usb_get_dev(dev); + if (pegasus_blacklisted(dev)) + return -ENODEV; - if (pegasus_blacklisted(dev)) { - res = -ENODEV; - goto out; + if (pegasus_count == 0) { + pegasus_workqueue = create_singlethread_workqueue("pegasus"); + if (!pegasus_workqueue) + return -ENOMEM; } + pegasus_count++; + + usb_get_dev(dev); net = alloc_etherdev(sizeof(struct pegasus)); if (!net) { @@ -1386,10 +1406,10 @@ static int pegasus_probe(struct usb_interface *intf, queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check, CARRIER_CHECK_DELAY); - dev_info(&intf->dev, "%s, %s, %s\n", + dev_info(&intf->dev, "%s, %s, %pM\n", net->name, usb_dev_id[dev_index].name, - print_mac(mac, net->dev_addr)); + net->dev_addr); return 0; out3: @@ -1401,6 +1421,7 @@ static int pegasus_probe(struct usb_interface *intf, free_netdev(net); out: usb_put_dev(dev); + pegasus_dec_workqueue(); return res; } @@ -1426,6 +1447,7 @@ static void pegasus_disconnect(struct usb_interface *intf) pegasus->rx_skb = NULL; } free_netdev(pegasus->net); + pegasus_dec_workqueue(); } static int pegasus_suspend (struct usb_interface *intf, pm_message_t message) @@ -1469,7 +1491,7 @@ static struct usb_driver pegasus_driver = { .resume = pegasus_resume, }; -static void parse_id(char *id) +static void __init parse_id(char *id) { unsigned int vendor_id=0, device_id=0, flags=0, i=0; char *token, *name=NULL; @@ -1505,15 +1527,11 @@ static int __init pegasus_init(void) pr_info("%s: %s, " DRIVER_DESC "\n", driver_name, DRIVER_VERSION); if (devid) parse_id(devid); - pegasus_workqueue = create_singlethread_workqueue("pegasus"); - if (!pegasus_workqueue) - return -ENOMEM; return usb_register(&pegasus_driver); } static void __exit pegasus_exit(void) { - destroy_workqueue(pegasus_workqueue); usb_deregister(&pegasus_driver); } diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index 6133401ebc67c258aff5ca98f51a40cf9219f488..d8664bf18c0000bd77a93426d39a10e0f48b6589 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -212,8 +212,9 @@ static int set_registers(rtl8150_t * dev, u16 indx, u16 size, void *data) static void ctrl_callback(struct urb *urb) { rtl8150_t *dev; + int status = urb->status; - switch (urb->status) { + switch (status) { case 0: break; case -EINPROGRESS: @@ -221,7 +222,7 @@ static void ctrl_callback(struct urb *urb) case -ENOENT: break; default: - dev_warn(&urb->dev->dev, "ctrl urb status %d\n", urb->status); + dev_warn(&urb->dev->dev, "ctrl urb status %d\n", status); } dev = urb->context; clear_bit(RX_REG_SET, &dev->flags); @@ -424,7 +425,8 @@ static void read_bulk_callback(struct urb *urb) struct sk_buff *skb; struct net_device *netdev; u16 rx_stat; - int status; + int status = urb->status; + int result; dev = urb->context; if (!dev) @@ -435,7 +437,7 @@ static void read_bulk_callback(struct urb *urb) if (!netif_device_present(netdev)) return; - switch (urb->status) { + switch (status) { case 0: break; case -ENOENT: @@ -444,7 +446,7 @@ static void read_bulk_callback(struct urb *urb) dev_warn(&urb->dev->dev, "may be reset is needed?..\n"); goto goon; default: - dev_warn(&urb->dev->dev, "Rx status %d\n", urb->status); + dev_warn(&urb->dev->dev, "Rx status %d\n", status); goto goon; } @@ -474,10 +476,10 @@ static void read_bulk_callback(struct urb *urb) goon: usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1), dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev); - status = usb_submit_urb(dev->rx_urb, GFP_ATOMIC); - if (status == -ENODEV) + result = usb_submit_urb(dev->rx_urb, GFP_ATOMIC); + if (result == -ENODEV) netif_device_detach(dev->netdev); - else if (status) { + else if (result) { set_bit(RX_URB_FAIL, &dev->flags); goto resched; } else { @@ -530,6 +532,7 @@ static void rx_fixup(unsigned long data) static void write_bulk_callback(struct urb *urb) { rtl8150_t *dev; + int status = urb->status; dev = urb->context; if (!dev) @@ -537,9 +540,9 @@ static void write_bulk_callback(struct urb *urb) dev_kfree_skb_irq(dev->tx_skb); if (!netif_device_present(dev->netdev)) return; - if (urb->status) + if (status) dev_info(&urb->dev->dev, "%s: Tx status %d\n", - dev->netdev->name, urb->status); + dev->netdev->name, status); dev->netdev->trans_start = jiffies; netif_wake_queue(dev->netdev); } @@ -548,12 +551,13 @@ static void intr_callback(struct urb *urb) { rtl8150_t *dev; __u8 *d; - int status; + int status = urb->status; + int res; dev = urb->context; if (!dev) return; - switch (urb->status) { + switch (status) { case 0: /* success */ break; case -ECONNRESET: /* unlink */ @@ -563,7 +567,7 @@ static void intr_callback(struct urb *urb) /* -EPIPE: should clear the halt */ default: dev_info(&urb->dev->dev, "%s: intr status %d\n", - dev->netdev->name, urb->status); + dev->netdev->name, status); goto resubmit; } @@ -591,13 +595,13 @@ static void intr_callback(struct urb *urb) } resubmit: - status = usb_submit_urb (urb, GFP_ATOMIC); - if (status == -ENODEV) + res = usb_submit_urb (urb, GFP_ATOMIC); + if (res == -ENODEV) netif_device_detach(dev->netdev); - else if (status) + else if (res) err ("can't resubmit intr, %s-%s/input0, status %d", dev->udev->bus->bus_name, - dev->udev->devpath, status); + dev->udev->devpath, res); } static int rtl8150_suspend(struct usb_interface *intf, pm_message_t message) diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index 51e2f5d7d14e5d5eaead2064c64d9cdef7df51ac..5574abe29c73b64c63d0e123e132f3afb762e7f3 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -31,7 +31,7 @@ #include "smsc95xx.h" #define SMSC_CHIPNAME "smsc95xx" -#define SMSC_DRIVER_VERSION "1.0.3" +#define SMSC_DRIVER_VERSION "1.0.4" #define HS_USB_PKT_SIZE (512) #define FS_USB_PKT_SIZE (64) #define DEFAULT_HS_BURST_CAP_SIZE (16 * 1024 + 5 * HS_USB_PKT_SIZE) @@ -40,15 +40,16 @@ #define MAX_SINGLE_PACKET_SIZE (2048) #define LAN95XX_EEPROM_MAGIC (0x9500) #define EEPROM_MAC_OFFSET (0x01) +#define DEFAULT_TX_CSUM_ENABLE (true) #define DEFAULT_RX_CSUM_ENABLE (true) #define SMSC95XX_INTERNAL_PHY_ID (1) #define SMSC95XX_TX_OVERHEAD (8) -#define FLOW_CTRL_TX (1) -#define FLOW_CTRL_RX (2) +#define SMSC95XX_TX_OVERHEAD_CSUM (12) struct smsc95xx_priv { u32 mac_cr; spinlock_t mac_cr_lock; + bool use_tx_csum; bool use_rx_csum; }; @@ -310,9 +311,10 @@ static void smsc95xx_async_cmd_callback(struct urb *urb, struct pt_regs *regs) { struct usb_context *usb_context = urb->context; struct usbnet *dev = usb_context->dev; + int status = urb->status; - if (urb->status < 0) - devwarn(dev, "async callback failed with %d", urb->status); + if (status < 0) + devwarn(dev, "async callback failed with %d", status); complete(&usb_context->notify); @@ -434,28 +436,6 @@ static void smsc95xx_set_multicast(struct net_device *netdev) smsc95xx_write_reg_async(dev, MAC_CR, &pdata->mac_cr); } -static u8 smsc95xx_resolve_flowctrl_fulldplx(u16 lcladv, u16 rmtadv) -{ - u8 cap = 0; - - if (lcladv & ADVERTISE_PAUSE_CAP) { - if (lcladv & ADVERTISE_PAUSE_ASYM) { - if (rmtadv & LPA_PAUSE_CAP) - cap = FLOW_CTRL_TX | FLOW_CTRL_RX; - else if (rmtadv & LPA_PAUSE_ASYM) - cap = FLOW_CTRL_RX; - } else { - if (rmtadv & LPA_PAUSE_CAP) - cap = FLOW_CTRL_TX | FLOW_CTRL_RX; - } - } else if (lcladv & ADVERTISE_PAUSE_ASYM) { - if ((rmtadv & LPA_PAUSE_CAP) && (rmtadv & LPA_PAUSE_ASYM)) - cap = FLOW_CTRL_TX; - } - - return cap; -} - static void smsc95xx_phy_update_flowcontrol(struct usbnet *dev, u8 duplex, u16 lcladv, u16 rmtadv) { @@ -468,7 +448,7 @@ static void smsc95xx_phy_update_flowcontrol(struct usbnet *dev, u8 duplex, } if (duplex == DUPLEX_FULL) { - u8 cap = smsc95xx_resolve_flowctrl_fulldplx(lcladv, rmtadv); + u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv); if (cap & FLOW_CTRL_RX) flow = 0xFFFF0002; @@ -556,9 +536,10 @@ static void smsc95xx_status(struct usbnet *dev, struct urb *urb) devwarn(dev, "unexpected interrupt, intdata=0x%08X", intdata); } -/* Enable or disable Rx checksum offload engine */ -static int smsc95xx_set_rx_csum(struct usbnet *dev, bool enable) +/* Enable or disable Tx & Rx checksum offload engines */ +static int smsc95xx_set_csums(struct usbnet *dev) { + struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); u32 read_buf; int ret = smsc95xx_read_reg(dev, COE_CR, &read_buf); if (ret < 0) { @@ -566,7 +547,12 @@ static int smsc95xx_set_rx_csum(struct usbnet *dev, bool enable) return ret; } - if (enable) + if (pdata->use_tx_csum) + read_buf |= Tx_COE_EN_; + else + read_buf &= ~Tx_COE_EN_; + + if (pdata->use_rx_csum) read_buf |= Rx_COE_EN_; else read_buf &= ~Rx_COE_EN_; @@ -626,7 +612,26 @@ static int smsc95xx_ethtool_set_rx_csum(struct net_device *netdev, u32 val) pdata->use_rx_csum = !!val; - return smsc95xx_set_rx_csum(dev, pdata->use_rx_csum); + return smsc95xx_set_csums(dev); +} + +static u32 smsc95xx_ethtool_get_tx_csum(struct net_device *netdev) +{ + struct usbnet *dev = netdev_priv(netdev); + struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); + + return pdata->use_tx_csum; +} + +static int smsc95xx_ethtool_set_tx_csum(struct net_device *netdev, u32 val) +{ + struct usbnet *dev = netdev_priv(netdev); + struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); + + pdata->use_tx_csum = !!val; + + ethtool_op_set_tx_hw_csum(netdev, pdata->use_tx_csum); + return smsc95xx_set_csums(dev); } static struct ethtool_ops smsc95xx_ethtool_ops = { @@ -640,6 +645,8 @@ static struct ethtool_ops smsc95xx_ethtool_ops = { .get_eeprom_len = smsc95xx_ethtool_get_eeprom_len, .get_eeprom = smsc95xx_ethtool_get_eeprom, .set_eeprom = smsc95xx_ethtool_set_eeprom, + .get_tx_csum = smsc95xx_ethtool_get_tx_csum, + .set_tx_csum = smsc95xx_ethtool_set_tx_csum, .get_rx_csum = smsc95xx_ethtool_get_rx_csum, .set_rx_csum = smsc95xx_ethtool_set_rx_csum, }; @@ -757,9 +764,9 @@ static int smsc95xx_phy_initialize(struct usbnet *dev) static int smsc95xx_reset(struct usbnet *dev) { struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); + struct net_device *netdev = dev->net; u32 read_buf, write_buf, burst_cap; int ret = 0, timeout; - DECLARE_MAC_BUF(mac); if (netif_msg_ifup(dev)) devdbg(dev, "entering smsc95xx_reset"); @@ -818,8 +825,7 @@ static int smsc95xx_reset(struct usbnet *dev) return ret; if (netif_msg_ifup(dev)) - devdbg(dev, "MAC Address: %s", - print_mac(mac, dev->net->dev_addr)); + devdbg(dev, "MAC Address: %pM", dev->net->dev_addr); ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf); if (ret < 0) { @@ -970,10 +976,11 @@ static int smsc95xx_reset(struct usbnet *dev) return ret; } - /* Enable or disable Rx checksum offload engine */ - ret = smsc95xx_set_rx_csum(dev, pdata->use_rx_csum); + /* Enable or disable checksum offload engines */ + ethtool_op_set_tx_hw_csum(netdev, pdata->use_tx_csum); + ret = smsc95xx_set_csums(dev); if (ret < 0) { - devwarn(dev, "Failed to set Rx csum offload: %d", ret); + devwarn(dev, "Failed to set csum offload: %d", ret); return ret; } @@ -1029,6 +1036,7 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf) spin_lock_init(&pdata->mac_cr_lock); + pdata->use_tx_csum = DEFAULT_TX_CSUM_ENABLE; pdata->use_rx_csum = DEFAULT_RX_CSUM_ENABLE; /* Init all registers */ @@ -1148,22 +1156,44 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) return 1; } +static u32 smsc95xx_calc_csum_preamble(struct sk_buff *skb) +{ + int len = skb->data - skb->head; + u16 high_16 = (u16)(skb->csum_offset + skb->csum_start - len); + u16 low_16 = (u16)(skb->csum_start - len); + return (high_16 << 16) | low_16; +} + static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) { + struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); + bool csum = pdata->use_tx_csum && (skb->ip_summed == CHECKSUM_PARTIAL); + int overhead = csum ? SMSC95XX_TX_OVERHEAD_CSUM : SMSC95XX_TX_OVERHEAD; u32 tx_cmd_a, tx_cmd_b; - if (skb_headroom(skb) < SMSC95XX_TX_OVERHEAD) { + /* We do not advertise SG, so skbs should be already linearized */ + BUG_ON(skb_shinfo(skb)->nr_frags); + + if (skb_headroom(skb) < overhead) { struct sk_buff *skb2 = skb_copy_expand(skb, - SMSC95XX_TX_OVERHEAD, 0, flags); + overhead, 0, flags); dev_kfree_skb_any(skb); skb = skb2; if (!skb) return NULL; } + if (csum) { + u32 csum_preamble = smsc95xx_calc_csum_preamble(skb); + skb_push(skb, 4); + memcpy(skb->data, &csum_preamble, 4); + } + skb_push(skb, 4); tx_cmd_b = (u32)(skb->len - 4); + if (csum) + tx_cmd_b |= TX_CMD_B_CSUM_ENABLE; cpu_to_le32s(&tx_cmd_b); memcpy(skb->data, &tx_cmd_b, 4); diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 02d25c743994e3f5539744587697ae1685187e16..aa31490788880bb3b609acae0a9ab7332cce28c7 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1125,7 +1125,6 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) struct usb_device *xdev; int status; const char *name; - DECLARE_MAC_BUF(mac); name = udev->dev.driver->name; info = (struct driver_info *) prod->driver_info; @@ -1236,11 +1235,11 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) if (status) goto out3; if (netif_msg_probe (dev)) - devinfo (dev, "register '%s' at usb-%s-%s, %s, %s", + devinfo (dev, "register '%s' at usb-%s-%s, %s, %pM", udev->dev.driver->name, xdev->bus->bus_name, xdev->devpath, dev->driver_info->description, - print_mac(mac, net->dev_addr)); + net->dev_addr); // ok, it's ready to go. usb_set_intfdata (udev, dev); diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 31cd817f33f97be658d31bed4ba93ec101312255..852d0e7c4e62abbfb13421664293dd70182c4126 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -8,7 +8,6 @@ * */ -#include #include #include #include @@ -30,14 +29,10 @@ struct veth_net_stats { struct veth_priv { struct net_device *peer; - struct net_device *dev; - struct list_head list; struct veth_net_stats *stats; unsigned ip_summed; }; -static LIST_HEAD(veth_list); - /* * ethtool interface */ @@ -267,16 +262,20 @@ static void veth_dev_free(struct net_device *dev) free_netdev(dev); } +static const struct net_device_ops veth_netdev_ops = { + .ndo_init = veth_dev_init, + .ndo_open = veth_open, + .ndo_start_xmit = veth_xmit, + .ndo_get_stats = veth_get_stats, +}; + static void veth_setup(struct net_device *dev) { ether_setup(dev); - dev->hard_start_xmit = veth_xmit; - dev->get_stats = veth_get_stats; - dev->open = veth_open; + dev->netdev_ops = &veth_netdev_ops; dev->ethtool_ops = &veth_ethtool_ops; dev->features |= NETIF_F_LLTX; - dev->init = veth_dev_init; dev->destructor = veth_dev_free; } @@ -302,7 +301,7 @@ static int veth_device_event(struct notifier_block *unused, { struct net_device *dev = ptr; - if (dev->open != veth_open) + if (dev->netdev_ops->ndo_open != veth_open) goto out; switch (event) { @@ -420,14 +419,10 @@ static int veth_newlink(struct net_device *dev, */ priv = netdev_priv(dev); - priv->dev = dev; priv->peer = peer; - list_add(&priv->list, &veth_list); priv = netdev_priv(peer); - priv->dev = peer; priv->peer = dev; - INIT_LIST_HEAD(&priv->list); return 0; err_register_dev: @@ -449,13 +444,6 @@ static void veth_dellink(struct net_device *dev) priv = netdev_priv(dev); peer = priv->peer; - if (!list_empty(&priv->list)) - list_del(&priv->list); - - priv = netdev_priv(peer); - if (!list_empty(&priv->list)) - list_del(&priv->list); - unregister_netdevice(dev); unregister_netdevice(peer); } diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 5b7870080c5661d36325c72c95ee9975d36fd4a3..ac07cc6e3cb214eb7a56336205836e0b50bdfb1c 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -191,12 +191,13 @@ IIId. Synchronization The driver runs as two independent, single-threaded flows of control. One is the send-packet routine, which enforces single-threaded use by the -dev->priv->lock spinlock. The other thread is the interrupt handler, which -is single threaded by the hardware and interrupt handling software. +netdev_priv(dev)->lock spinlock. The other thread is the interrupt handler, +which is single threaded by the hardware and interrupt handling software. The send packet thread has partial control over the Tx ring. It locks the -dev->priv->lock whenever it's queuing a Tx packet. If the next slot in the ring -is not available it stops the transmit queue by calling netif_stop_queue. +netdev_priv(dev)->lock whenever it's queuing a Tx packet. If the next slot in +the ring is not available it stops the transmit queue by +calling netif_stop_queue. The interrupt handler has exclusive control over the Rx ring and records stats from the Tx ring. After reaping the stats, it marks the Tx queue entry as @@ -588,7 +589,7 @@ static int rhine_napipoll(struct napi_struct *napi, int budget) work_done = rhine_rx(dev, budget); if (work_done < budget) { - netif_rx_complete(dev, napi); + netif_rx_complete(napi); iowrite16(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow | IntrRxDropped | IntrRxNoBuf | IntrTxAborted | @@ -614,6 +615,20 @@ static void __devinit rhine_hw_init(struct net_device *dev, long pioaddr) rhine_reload_eeprom(pioaddr, dev); } +static const struct net_device_ops rhine_netdev_ops = { + .ndo_open = rhine_open, + .ndo_stop = rhine_close, + .ndo_start_xmit = rhine_start_tx, + .ndo_get_stats = rhine_get_stats, + .ndo_set_multicast_list = rhine_set_rx_mode, + .ndo_validate_addr = eth_validate_addr, + .ndo_do_ioctl = netdev_ioctl, + .ndo_tx_timeout = rhine_tx_timeout, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = rhine_poll, +#endif +}; + static int __devinit rhine_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -631,7 +646,6 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, #else int bar = 0; #endif - DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -765,18 +779,10 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, rp->mii_if.reg_num_mask = 0x1f; /* The chip-specific entries in the device structure. */ - dev->open = rhine_open; - dev->hard_start_xmit = rhine_start_tx; - dev->stop = rhine_close; - dev->get_stats = rhine_get_stats; - dev->set_multicast_list = rhine_set_rx_mode; - dev->do_ioctl = netdev_ioctl; - dev->ethtool_ops = &netdev_ethtool_ops; - dev->tx_timeout = rhine_tx_timeout; + dev->netdev_ops = &rhine_netdev_ops; + dev->ethtool_ops = &netdev_ethtool_ops, dev->watchdog_timeo = TX_TIMEOUT; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = rhine_poll; -#endif + netif_napi_add(dev, &rp->napi, rhine_napipoll, 64); if (rp->quirks & rqRhineI) @@ -787,14 +793,14 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, if (rc) goto err_out_unmap; - printk(KERN_INFO "%s: VIA %s at 0x%lx, %s, IRQ %d.\n", + printk(KERN_INFO "%s: VIA %s at 0x%lx, %pM, IRQ %d.\n", dev->name, name, #ifdef USE_MMIO memaddr, #else (long)ioaddr, #endif - print_mac(mac, dev->dev_addr), pdev->irq); + dev->dev_addr, pdev->irq); pci_set_drvdata(pdev, dev); @@ -1312,7 +1318,7 @@ static irqreturn_t rhine_interrupt(int irq, void *dev_instance) IntrPCIErr | IntrStatsMax | IntrLinkChange, ioaddr + IntrEnable); - netif_rx_schedule(dev, &rp->napi); + netif_rx_schedule(&rp->napi); } if (intr_status & (IntrTxErrSummary | IntrTxDone)) { @@ -1505,7 +1511,6 @@ static int rhine_rx(struct net_device *dev, int limit) } skb->protocol = eth_type_trans(skb, dev); netif_receive_skb(skb); - dev->last_rx = jiffies; rp->stats.rx_bytes += pkt_len; rp->stats.rx_packets++; } diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 11cb3e504e1cb43e16c4eb5b81dda369ab4c75c1..58e25d090ae0687b7ca05a762447df7c6408f414 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -849,6 +849,20 @@ static int velocity_soft_reset(struct velocity_info *vptr) return 0; } +static const struct net_device_ops velocity_netdev_ops = { + .ndo_open = velocity_open, + .ndo_stop = velocity_close, + .ndo_start_xmit = velocity_xmit, + .ndo_get_stats = velocity_get_stats, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = velocity_set_multi, + .ndo_change_mtu = velocity_change_mtu, + .ndo_do_ioctl = velocity_ioctl, + .ndo_vlan_rx_add_vid = velocity_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = velocity_vlan_rx_kill_vid, + .ndo_vlan_rx_register = velocity_vlan_rx_register, +}; + /** * velocity_found1 - set up discovered velocity card * @pdev: PCI device @@ -958,18 +972,8 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi vptr->phy_id = MII_GET_PHY_ID(vptr->mac_regs); dev->irq = pdev->irq; - dev->open = velocity_open; - dev->hard_start_xmit = velocity_xmit; - dev->stop = velocity_close; - dev->get_stats = velocity_get_stats; - dev->set_multicast_list = velocity_set_multi; - dev->do_ioctl = velocity_ioctl; + dev->netdev_ops = &velocity_netdev_ops; dev->ethtool_ops = &velocity_ethtool_ops; - dev->change_mtu = velocity_change_mtu; - - dev->vlan_rx_add_vid = velocity_vlan_rx_add_vid; - dev->vlan_rx_kill_vid = velocity_vlan_rx_kill_vid; - dev->vlan_rx_register = velocity_vlan_rx_register; #ifdef VELOCITY_ZERO_COPY_SUPPORT dev->features |= NETIF_F_SG; @@ -1412,8 +1416,6 @@ static int velocity_rx_srv(struct velocity_info *vptr, int status) rd->size |= RX_INTEN; - vptr->dev->last_rx = jiffies; - rd_curr++; if (rd_curr >= vptr->options.numrx) rd_curr = 0; diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 0196a0df90210995ec6a5abe228eb23bb22d494c..b7004ff36451764278e47eac267ffb4cd6bcd4bf 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -34,6 +34,7 @@ module_param(gso, bool, 0444); /* FIXME: MTU in config. */ #define MAX_PACKET_LEN (ETH_HLEN+ETH_DATA_LEN) +#define GOOD_COPY_LEN 128 struct virtnet_info { @@ -58,6 +59,9 @@ struct virtnet_info /* I like... big packets and I cannot lie! */ bool big_packets; + /* Host will merge rx buffers for big packets (shake it! shake it!) */ + bool mergeable_rx_bufs; + /* Receive & send queues. */ struct sk_buff_head recv; struct sk_buff_head send; @@ -66,22 +70,27 @@ struct virtnet_info struct page *pages; }; -static inline struct virtio_net_hdr *skb_vnet_hdr(struct sk_buff *skb) +static inline void *skb_vnet_hdr(struct sk_buff *skb) { return (struct virtio_net_hdr *)skb->cb; } -static inline void vnet_hdr_to_sg(struct scatterlist *sg, struct sk_buff *skb) -{ - sg_init_one(sg, skb_vnet_hdr(skb), sizeof(struct virtio_net_hdr)); -} - static void give_a_page(struct virtnet_info *vi, struct page *page) { page->private = (unsigned long)vi->pages; vi->pages = page; } +static void trim_pages(struct virtnet_info *vi, struct sk_buff *skb) +{ + unsigned int i; + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) + give_a_page(vi, skb_shinfo(skb)->frags[i].page); + skb_shinfo(skb)->nr_frags = 0; + skb->data_len = 0; +} + static struct page *get_a_page(struct virtnet_info *vi, gfp_t gfp_mask) { struct page *p = vi->pages; @@ -111,31 +120,97 @@ static void skb_xmit_done(struct virtqueue *svq) static void receive_skb(struct net_device *dev, struct sk_buff *skb, unsigned len) { + struct virtnet_info *vi = netdev_priv(dev); struct virtio_net_hdr *hdr = skb_vnet_hdr(skb); int err; + int i; if (unlikely(len < sizeof(struct virtio_net_hdr) + ETH_HLEN)) { pr_debug("%s: short packet %i\n", dev->name, len); dev->stats.rx_length_errors++; goto drop; } - len -= sizeof(struct virtio_net_hdr); - if (len <= MAX_PACKET_LEN) { - unsigned int i; + if (vi->mergeable_rx_bufs) { + struct virtio_net_hdr_mrg_rxbuf *mhdr = skb_vnet_hdr(skb); + unsigned int copy; + char *p = page_address(skb_shinfo(skb)->frags[0].page); - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) - give_a_page(dev->priv, skb_shinfo(skb)->frags[i].page); - skb->data_len = 0; - skb_shinfo(skb)->nr_frags = 0; - } + if (len > PAGE_SIZE) + len = PAGE_SIZE; + len -= sizeof(struct virtio_net_hdr_mrg_rxbuf); - err = pskb_trim(skb, len); - if (err) { - pr_debug("%s: pskb_trim failed %i %d\n", dev->name, len, err); - dev->stats.rx_dropped++; - goto drop; + memcpy(hdr, p, sizeof(*mhdr)); + p += sizeof(*mhdr); + + copy = len; + if (copy > skb_tailroom(skb)) + copy = skb_tailroom(skb); + + memcpy(skb_put(skb, copy), p, copy); + + len -= copy; + + if (!len) { + give_a_page(vi, skb_shinfo(skb)->frags[0].page); + skb_shinfo(skb)->nr_frags--; + } else { + skb_shinfo(skb)->frags[0].page_offset += + sizeof(*mhdr) + copy; + skb_shinfo(skb)->frags[0].size = len; + skb->data_len += len; + skb->len += len; + } + + while (--mhdr->num_buffers) { + struct sk_buff *nskb; + + i = skb_shinfo(skb)->nr_frags; + if (i >= MAX_SKB_FRAGS) { + pr_debug("%s: packet too long %d\n", dev->name, + len); + dev->stats.rx_length_errors++; + goto drop; + } + + nskb = vi->rvq->vq_ops->get_buf(vi->rvq, &len); + if (!nskb) { + pr_debug("%s: rx error: %d buffers missing\n", + dev->name, mhdr->num_buffers); + dev->stats.rx_length_errors++; + goto drop; + } + + __skb_unlink(nskb, &vi->recv); + vi->num--; + + skb_shinfo(skb)->frags[i] = skb_shinfo(nskb)->frags[0]; + skb_shinfo(nskb)->nr_frags = 0; + kfree_skb(nskb); + + if (len > PAGE_SIZE) + len = PAGE_SIZE; + + skb_shinfo(skb)->frags[i].size = len; + skb_shinfo(skb)->nr_frags++; + skb->data_len += len; + skb->len += len; + } + } else { + len -= sizeof(struct virtio_net_hdr); + + if (len <= MAX_PACKET_LEN) + trim_pages(vi, skb); + + err = pskb_trim(skb, len); + if (err) { + pr_debug("%s: pskb_trim failed %i %d\n", dev->name, + len, err); + dev->stats.rx_dropped++; + goto drop; + } } + skb->truesize += skb->data_len; dev->stats.rx_bytes += skb->len; dev->stats.rx_packets++; @@ -194,7 +269,7 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb, dev_kfree_skb(skb); } -static void try_fill_recv(struct virtnet_info *vi) +static void try_fill_recv_maxbufs(struct virtnet_info *vi) { struct sk_buff *skb; struct scatterlist sg[2+MAX_SKB_FRAGS]; @@ -202,12 +277,16 @@ static void try_fill_recv(struct virtnet_info *vi) sg_init_table(sg, 2+MAX_SKB_FRAGS); for (;;) { + struct virtio_net_hdr *hdr; + skb = netdev_alloc_skb(vi->dev, MAX_PACKET_LEN); if (unlikely(!skb)) break; skb_put(skb, MAX_PACKET_LEN); - vnet_hdr_to_sg(sg, skb); + + hdr = skb_vnet_hdr(skb); + sg_init_one(sg, hdr, sizeof(*hdr)); if (vi->big_packets) { for (i = 0; i < MAX_SKB_FRAGS; i++) { @@ -230,6 +309,55 @@ static void try_fill_recv(struct virtnet_info *vi) skb_queue_head(&vi->recv, skb); err = vi->rvq->vq_ops->add_buf(vi->rvq, sg, 0, num, skb); + if (err) { + skb_unlink(skb, &vi->recv); + trim_pages(vi, skb); + kfree_skb(skb); + break; + } + vi->num++; + } + if (unlikely(vi->num > vi->max)) + vi->max = vi->num; + vi->rvq->vq_ops->kick(vi->rvq); +} + +static void try_fill_recv(struct virtnet_info *vi) +{ + struct sk_buff *skb; + struct scatterlist sg[1]; + int err; + + if (!vi->mergeable_rx_bufs) { + try_fill_recv_maxbufs(vi); + return; + } + + for (;;) { + skb_frag_t *f; + + skb = netdev_alloc_skb(vi->dev, GOOD_COPY_LEN + NET_IP_ALIGN); + if (unlikely(!skb)) + break; + + skb_reserve(skb, NET_IP_ALIGN); + + f = &skb_shinfo(skb)->frags[0]; + f->page = get_a_page(vi, GFP_ATOMIC); + if (!f->page) { + kfree_skb(skb); + break; + } + + f->page_offset = 0; + f->size = PAGE_SIZE; + + skb_shinfo(skb)->nr_frags++; + + sg_init_one(sg, page_address(f->page), PAGE_SIZE); + skb_queue_head(&vi->recv, skb); + + err = vi->rvq->vq_ops->add_buf(vi->rvq, sg, 0, 1, skb); if (err) { skb_unlink(skb, &vi->recv); kfree_skb(skb); @@ -246,9 +374,9 @@ static void skb_recv_done(struct virtqueue *rvq) { struct virtnet_info *vi = rvq->vdev->priv; /* Schedule NAPI, Suppress further interrupts if successful. */ - if (netif_rx_schedule_prep(vi->dev, &vi->napi)) { + if (netif_rx_schedule_prep(&vi->napi)) { rvq->vq_ops->disable_cb(rvq); - __netif_rx_schedule(vi->dev, &vi->napi); + __netif_rx_schedule(&vi->napi); } } @@ -274,11 +402,11 @@ static int virtnet_poll(struct napi_struct *napi, int budget) /* Out of packets? */ if (received < budget) { - netif_rx_complete(vi->dev, napi); + netif_rx_complete(napi); if (unlikely(!vi->rvq->vq_ops->enable_cb(vi->rvq)) && napi_schedule_prep(napi)) { vi->rvq->vq_ops->disable_cb(vi->rvq); - __netif_rx_schedule(vi->dev, napi); + __netif_rx_schedule(napi); goto again; } } @@ -320,17 +448,14 @@ static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb) { int num, err; struct scatterlist sg[2+MAX_SKB_FRAGS]; - struct virtio_net_hdr *hdr; + struct virtio_net_hdr_mrg_rxbuf *mhdr = skb_vnet_hdr(skb); + struct virtio_net_hdr *hdr = skb_vnet_hdr(skb); const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest; sg_init_table(sg, 2+MAX_SKB_FRAGS); - pr_debug("%s: xmit %p " MAC_FMT "\n", vi->dev->name, skb, - dest[0], dest[1], dest[2], - dest[3], dest[4], dest[5]); + pr_debug("%s: xmit %p %pM\n", vi->dev->name, skb, dest); - /* Encode metadata header at front. */ - hdr = skb_vnet_hdr(skb); if (skb->ip_summed == CHECKSUM_PARTIAL) { hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; hdr->csum_start = skb->csum_start - skb_headroom(skb); @@ -358,7 +483,14 @@ static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb) hdr->gso_size = hdr->hdr_len = 0; } - vnet_hdr_to_sg(sg, skb); + mhdr->num_buffers = 0; + + /* Encode metadata header at front. */ + if (vi->mergeable_rx_bufs) + sg_init_one(sg, mhdr, sizeof(*mhdr)); + else + sg_init_one(sg, hdr, sizeof(*hdr)); + num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1; err = vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb); @@ -448,9 +580,9 @@ static int virtnet_open(struct net_device *dev) * won't get another interrupt, so process any outstanding packets * now. virtnet_poll wants re-enable the queue, so we disable here. * We synchronize against interrupts via NAPI_STATE_SCHED */ - if (netif_rx_schedule_prep(dev, &vi->napi)) { + if (netif_rx_schedule_prep(&vi->napi)) { vi->rvq->vq_ops->disable_cb(vi->rvq); - __netif_rx_schedule(dev, &vi->napi); + __netif_rx_schedule(&vi->napi); } return 0; } @@ -478,8 +610,20 @@ static int virtnet_set_tx_csum(struct net_device *dev, u32 data) static struct ethtool_ops virtnet_ethtool_ops = { .set_tx_csum = virtnet_set_tx_csum, .set_sg = ethtool_op_set_sg, + .set_tso = ethtool_op_set_tso, }; +#define MIN_MTU 68 +#define MAX_MTU 65535 + +static int virtnet_change_mtu(struct net_device *dev, int new_mtu) +{ + if (new_mtu < MIN_MTU || new_mtu > MAX_MTU) + return -EINVAL; + dev->mtu = new_mtu; + return 0; +} + static int virtnet_probe(struct virtio_device *vdev) { int err; @@ -495,6 +639,7 @@ static int virtnet_probe(struct virtio_device *vdev) dev->open = virtnet_open; dev->stop = virtnet_close; dev->hard_start_xmit = start_xmit; + dev->change_mtu = virtnet_change_mtu; dev->features = NETIF_F_HIGHDMA; #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = virtnet_netpoll; @@ -547,6 +692,9 @@ static int virtnet_probe(struct virtio_device *vdev) || virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN)) vi->big_packets = true; + if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF)) + vi->mergeable_rx_bufs = true; + /* We expect two virtqueues, receive then send. */ vi->rvq = vdev->config->find_vq(vdev, 0, skb_recv_done); if (IS_ERR(vi->rvq)) { @@ -639,6 +787,7 @@ static unsigned int features[] = { VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6, VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6, VIRTIO_NET_F_GUEST_ECN, /* We don't yet handle UFO input. */ + VIRTIO_NET_F_MRG_RXBUF, VIRTIO_F_NOTIFY_ON_EMPTY, }; diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig index 21efd99b9294bac7a17ce21763f4074e65596ef1..d08ce6a264cb9cbe5cdfc0e5e79b4588f8ea775a 100644 --- a/drivers/net/wan/Kconfig +++ b/drivers/net/wan/Kconfig @@ -207,6 +207,8 @@ config PC300 tristate "Cyclades-PC300 support (RS-232/V.35, X.21, T1/E1 boards)" depends on HDLC && PCI && BROKEN ---help--- + This driver is broken because of struct tty_driver change. + Driver for the Cyclades-PC300 synchronous communication boards. These boards provide synchronous serial interfaces to your @@ -333,6 +335,13 @@ config DSCC4_PCI_RST Say Y if your card supports this feature. +config IXP4XX_HSS + tristate "Intel IXP4xx HSS (synchronous serial port) support" + depends on HDLC && ARM && ARCH_IXP4XX && IXP4XX_NPE && IXP4XX_QMGR + help + Say Y here if you want to use built-in HSS ports + on IXP4xx processor. + config DLCI tristate "Frame Relay DLCI support" ---help--- diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile index 102549605d098681a26db81af6a393ea5476fdc9..19d14bc28356f097ccf3a091fc6a42174597eba3 100644 --- a/drivers/net/wan/Makefile +++ b/drivers/net/wan/Makefile @@ -14,7 +14,7 @@ obj-$(CONFIG_HDLC_RAW) += hdlc_raw.o obj-$(CONFIG_HDLC_RAW_ETH) += hdlc_raw_eth.o obj-$(CONFIG_HDLC_CISCO) += hdlc_cisco.o obj-$(CONFIG_HDLC_FR) += hdlc_fr.o -obj-$(CONFIG_HDLC_PPP) += hdlc_ppp.o syncppp.o +obj-$(CONFIG_HDLC_PPP) += hdlc_ppp.o obj-$(CONFIG_HDLC_X25) += hdlc_x25.o pc300-y := pc300_drv.o @@ -41,6 +41,7 @@ obj-$(CONFIG_C101) += c101.o obj-$(CONFIG_WANXL) += wanxl.o obj-$(CONFIG_PCI200SYN) += pci200syn.o obj-$(CONFIG_PC300TOO) += pc300too.o +obj-$(CONFIG_IXP4XX_HSS) += ixp4xx_hss.o clean-files := wanxlfw.inc $(obj)/wanxl.o: $(obj)/wanxlfw.inc diff --git a/drivers/net/wan/c101.c b/drivers/net/wan/c101.c index c8e563106a4af357fad4513e393b480b2a2bfe4a..b46897996f7e3edf98645c3ec433f006d0f95059 100644 --- a/drivers/net/wan/c101.c +++ b/drivers/net/wan/c101.c @@ -88,7 +88,7 @@ static card_t **new_card = &first_card; /* EDA address register must be set in EDAL, EDAH order - 8 bit ISA bus */ #define sca_outw(value, reg, card) do { \ writeb(value & 0xFF, (card)->win0base + C101_SCA + (reg)); \ - writeb((value >> 8 ) & 0xFF, (card)->win0base + C101_SCA + (reg+1));\ + writeb((value >> 8 ) & 0xFF, (card)->win0base + C101_SCA + (reg + 1));\ } while(0) #define port_to_card(port) (port) @@ -113,7 +113,7 @@ static inline void openwin(card_t *card, u8 page) } -#include "hd6457x.c" +#include "hd64570.c" static inline void set_carrier(port_t *port) @@ -381,7 +381,7 @@ static int __init c101_run(unsigned long irq, unsigned long winbase) return result; } - sca_init_sync_port(card); /* Set up C101 memory */ + sca_init_port(card); /* Set up C101 memory */ set_carrier(card); printk(KERN_INFO "%s: Moxa C101 on IRQ%u," diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c index 7f97f8d08c39eeba79eaa4da5cdfc5368d59487d..d80b72e22dea6be26d69b4e2d0fd016541a546f8 100644 --- a/drivers/net/wan/cosa.c +++ b/drivers/net/wan/cosa.c @@ -754,7 +754,6 @@ static int cosa_net_rx_done(struct channel_data *chan) chan->netdev->stats.rx_bytes += chan->cosa->rxsize; netif_rx(chan->rx_skb); chan->rx_skb = NULL; - chan->netdev->last_rx = jiffies; return 0; } diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c index 5a7303dc0965e7b5db3f8af3aa35202755602a51..5fa52923efa80e7401852c11dfee6864874ded5b 100644 --- a/drivers/net/wan/cycx_x25.c +++ b/drivers/net/wan/cycx_x25.c @@ -199,6 +199,8 @@ static struct net_device *cycx_x25_get_dev_by_lcn(struct wan_device *wandev, static struct net_device * cycx_x25_get_dev_by_dte_addr(struct wan_device *wandev, char *dte); +static void cycx_x25_chan_setup(struct net_device *dev); + #ifdef CYCLOMX_X25_DEBUG static void hex_dump(char *msg, unsigned char *p, int len); static void cycx_x25_dump_config(struct cycx_x25_config *conf); @@ -353,6 +355,12 @@ static int cycx_wan_update(struct wan_device *wandev) return 0; } +/* callback to initialize device */ +static void cycx_x25_chan_setup(struct net_device *dev) +{ + dev->init = cycx_netdevice_init; +} + /* Create new logical channel. * This routine is called by the router when ROUTER_IFNEW IOCTL is being * handled. @@ -376,11 +384,12 @@ static int cycx_wan_new_if(struct wan_device *wandev, struct net_device *dev, return -EINVAL; } - /* allocate and initialize private data */ - chan = kzalloc(sizeof(struct cycx_x25_channel), GFP_KERNEL); - if (!chan) + dev = alloc_netdev(sizeof(struct cycx_x25_channel), conf->name, + cycx_x25_chan_setup); + if (!dev) return -ENOMEM; + chan = netdev_priv(dev); strcpy(chan->name, conf->name); chan->card = card; chan->link = conf->port; @@ -396,14 +405,14 @@ static int cycx_wan_new_if(struct wan_device *wandev, struct net_device *dev, if (len > WAN_ADDRESS_SZ) { printk(KERN_ERR "%s: %s local addr too long!\n", wandev->name, chan->name); - kfree(chan); - return -EINVAL; + err = -EINVAL; + goto error; } else { chan->local_addr = kmalloc(len + 1, GFP_KERNEL); if (!chan->local_addr) { - kfree(chan); - return -ENOMEM; + err = -ENOMEM; + goto error; } } @@ -429,41 +438,31 @@ static int cycx_wan_new_if(struct wan_device *wandev, struct net_device *dev, "%s: PVC %u is out of range on interface %s!\n", wandev->name, lcn, chan->name); err = -EINVAL; + goto error; } } else { printk(KERN_ERR "%s: invalid media address on interface %s!\n", wandev->name, chan->name); err = -EINVAL; + goto error; } - if (err) { - kfree(chan->local_addr); - kfree(chan); - return err; - } - - /* prepare network device data space for registration */ - strcpy(dev->name, chan->name); - dev->init = cycx_netdevice_init; - dev->priv = chan; - return 0; + +error: + free_netdev(dev); + return err; } /* Delete logical channel. */ static int cycx_wan_del_if(struct wan_device *wandev, struct net_device *dev) { - if (dev->priv) { - struct cycx_x25_channel *chan = dev->priv; + struct cycx_x25_channel *chan = netdev_priv(dev); - if (chan->svc) { - kfree(chan->local_addr); - if (chan->state == WAN_CONNECTED) - del_timer(&chan->timer); - } - - kfree(chan); - dev->priv = NULL; + if (chan->svc) { + kfree(chan->local_addr); + if (chan->state == WAN_CONNECTED) + del_timer(&chan->timer); } return 0; @@ -484,7 +483,7 @@ static const struct header_ops cycx_header_ops = { * registration. */ static int cycx_netdevice_init(struct net_device *dev) { - struct cycx_x25_channel *chan = dev->priv; + struct cycx_x25_channel *chan = netdev_priv(dev); struct cycx_device *card = chan->card; struct wan_device *wandev = &card->wandev; @@ -542,7 +541,7 @@ static int cycx_netdevice_open(struct net_device *dev) * o if there's no more open channels then disconnect physical link. */ static int cycx_netdevice_stop(struct net_device *dev) { - struct cycx_x25_channel *chan = dev->priv; + struct cycx_x25_channel *chan = netdev_priv(dev); netif_stop_queue(dev); @@ -596,7 +595,7 @@ static int cycx_netdevice_rebuild_header(struct sk_buff *skb) static int cycx_netdevice_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct cycx_x25_channel *chan = dev->priv; + struct cycx_x25_channel *chan = netdev_priv(dev); struct cycx_device *card = chan->card; if (!chan->svc) @@ -670,7 +669,7 @@ static int cycx_netdevice_hard_start_xmit(struct sk_buff *skb, * Return a pointer to struct net_device_stats */ static struct net_device_stats *cycx_netdevice_get_stats(struct net_device *dev) { - struct cycx_x25_channel *chan = dev->priv; + struct cycx_x25_channel *chan = netdev_priv(dev); return chan ? &chan->ifstats : NULL; } @@ -783,7 +782,7 @@ static void cycx_x25_irq_rx(struct cycx_device *card, struct cycx_x25_cmd *cmd) return; } - chan = dev->priv; + chan = netdev_priv(dev); reset_timer(dev); if (chan->drop_sequence) { @@ -843,7 +842,6 @@ static void cycx_x25_irq_rx(struct cycx_device *card, struct cycx_x25_cmd *cmd) skb_reset_mac_header(skb); netif_rx(skb); - dev->last_rx = jiffies; /* timestamp */ } /* Connect interrupt handler. */ @@ -884,7 +882,7 @@ static void cycx_x25_irq_connect(struct cycx_device *card, return; } - chan = dev->priv; + chan = netdev_priv(dev); chan->lcn = lcn; cycx_x25_connect_response(card, chan); cycx_x25_set_chan_state(dev, WAN_CONNECTED); @@ -914,7 +912,7 @@ static void cycx_x25_irq_connect_confirm(struct cycx_device *card, } clear_bit(--key, (void*)&card->u.x.connection_keys); - chan = dev->priv; + chan = netdev_priv(dev); chan->lcn = lcn; cycx_x25_set_chan_state(dev, WAN_CONNECTED); } @@ -954,7 +952,7 @@ static void cycx_x25_irq_disconnect(struct cycx_device *card, dev = cycx_x25_get_dev_by_lcn(wandev, lcn); if (dev) { - struct cycx_x25_channel *chan = dev->priv; + struct cycx_x25_channel *chan = netdev_priv(dev); cycx_x25_disconnect_response(card, chan->link, lcn); cycx_x25_set_chan_state(dev, WAN_DISCONNECTED); @@ -1302,7 +1300,7 @@ static struct net_device *cycx_x25_get_dev_by_lcn(struct wan_device *wandev, struct cycx_x25_channel *chan; while (dev) { - chan = (struct cycx_x25_channel*)dev->priv; + chan = netdev_priv(dev); if (chan->lcn == lcn) break; @@ -1319,7 +1317,7 @@ static struct net_device * struct cycx_x25_channel *chan; while (dev) { - chan = (struct cycx_x25_channel*)dev->priv; + chan = netdev_priv(dev); if (!strcmp(chan->addr, dte)) break; @@ -1337,7 +1335,7 @@ static struct net_device * * <0 failure */ static int cycx_x25_chan_connect(struct net_device *dev) { - struct cycx_x25_channel *chan = dev->priv; + struct cycx_x25_channel *chan = netdev_priv(dev); struct cycx_device *card = chan->card; if (chan->svc) { @@ -1362,7 +1360,7 @@ static int cycx_x25_chan_connect(struct net_device *dev) * o if SVC then clear X.25 call */ static void cycx_x25_chan_disconnect(struct net_device *dev) { - struct cycx_x25_channel *chan = dev->priv; + struct cycx_x25_channel *chan = netdev_priv(dev); if (chan->svc) { x25_clear_call(chan->card, chan->link, chan->lcn, 0, 0); @@ -1375,7 +1373,7 @@ static void cycx_x25_chan_disconnect(struct net_device *dev) static void cycx_x25_chan_timer(unsigned long d) { struct net_device *dev = (struct net_device *)d; - struct cycx_x25_channel *chan = dev->priv; + struct cycx_x25_channel *chan = netdev_priv(dev); if (chan->state == WAN_CONNECTED) cycx_x25_chan_disconnect(dev); @@ -1387,7 +1385,7 @@ static void cycx_x25_chan_timer(unsigned long d) /* Set logical channel state. */ static void cycx_x25_set_chan_state(struct net_device *dev, u8 state) { - struct cycx_x25_channel *chan = dev->priv; + struct cycx_x25_channel *chan = netdev_priv(dev); struct cycx_device *card = chan->card; unsigned long flags; char *string_state = NULL; @@ -1453,7 +1451,7 @@ static void cycx_x25_set_chan_state(struct net_device *dev, u8 state) * to the router. */ static int cycx_x25_chan_send(struct net_device *dev, struct sk_buff *skb) { - struct cycx_x25_channel *chan = dev->priv; + struct cycx_x25_channel *chan = netdev_priv(dev); struct cycx_device *card = chan->card; int bitm = 0; /* final packet */ unsigned len = skb->len; @@ -1494,7 +1492,6 @@ static void cycx_x25_chan_send_event(struct net_device *dev, u8 event) skb->protocol = x25_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; /* timestamp */ } /* Convert line speed in bps to a number used by cyclom 2x code. */ @@ -1547,7 +1544,7 @@ static unsigned dec_to_uint(u8 *str, int len) static void reset_timer(struct net_device *dev) { - struct cycx_x25_channel *chan = dev->priv; + struct cycx_x25_channel *chan = netdev_priv(dev); if (chan->svc) mod_timer(&chan->timer, jiffies+chan->idle_tmout*HZ); @@ -1600,7 +1597,7 @@ static void cycx_x25_dump_devs(struct wan_device *wandev) printk(KERN_INFO "---------------------------------------\n"); while(dev) { - struct cycx_x25_channel *chan = dev->priv; + struct cycx_x25_channel *chan = netdev_priv(dev); printk(KERN_INFO "%-5.5s %-15.15s %d ETH_P_%s\n", chan->name, chan->addr, netif_queue_stopped(dev), diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c index b14242768fad19c381cff1d3d232d4abcf5f7e24..a297e3efa05dd32369d0c1c23c14378675c51436 100644 --- a/drivers/net/wan/dlci.c +++ b/drivers/net/wan/dlci.c @@ -74,7 +74,7 @@ static int dlci_header(struct sk_buff *skb, struct net_device *dev, unsigned int hlen; char *dest; - dlp = dev->priv; + dlp = netdev_priv(dev); hdr.control = FRAD_I_UI; switch(type) @@ -110,7 +110,7 @@ static void dlci_receive(struct sk_buff *skb, struct net_device *dev) struct frhdr *hdr; int process, header; - dlp = dev->priv; + dlp = netdev_priv(dev); if (!pskb_may_pull(skb, sizeof(*hdr))) { printk(KERN_NOTICE "%s: invalid data no header\n", dev->name); @@ -181,7 +181,6 @@ static void dlci_receive(struct sk_buff *skb, struct net_device *dev) dlp->stats.rx_bytes += skb->len; netif_rx(skb); dlp->stats.rx_packets++; - dev->last_rx = jiffies; } else dev_kfree_skb(skb); @@ -197,7 +196,7 @@ static int dlci_transmit(struct sk_buff *skb, struct net_device *dev) if (!skb || !dev) return(0); - dlp = dev->priv; + dlp = netdev_priv(dev); netif_stop_queue(dev); @@ -235,9 +234,9 @@ static int dlci_config(struct net_device *dev, struct dlci_conf __user *conf, in struct frad_local *flp; int err; - dlp = dev->priv; + dlp = netdev_priv(dev); - flp = dlp->slave->priv; + flp = netdev_priv(dlp->slave); if (!get) { @@ -269,7 +268,7 @@ static int dlci_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) if (!capable(CAP_NET_ADMIN)) return(-EPERM); - dlp = dev->priv; + dlp = netdev_priv(dev); switch(cmd) { @@ -298,7 +297,7 @@ static int dlci_change_mtu(struct net_device *dev, int new_mtu) { struct dlci_local *dlp; - dlp = dev->priv; + dlp = netdev_priv(dev); return((*dlp->slave->change_mtu)(dlp->slave, new_mtu)); } @@ -309,7 +308,7 @@ static int dlci_open(struct net_device *dev) struct frad_local *flp; int err; - dlp = dev->priv; + dlp = netdev_priv(dev); if (!*(short *)(dev->dev_addr)) return(-EINVAL); @@ -317,7 +316,7 @@ static int dlci_open(struct net_device *dev) if (!netif_running(dlp->slave)) return(-ENOTCONN); - flp = dlp->slave->priv; + flp = netdev_priv(dlp->slave); err = (*flp->activate)(dlp->slave, dev); if (err) return(err); @@ -335,9 +334,9 @@ static int dlci_close(struct net_device *dev) netif_stop_queue(dev); - dlp = dev->priv; + dlp = netdev_priv(dev); - flp = dlp->slave->priv; + flp = netdev_priv(dlp->slave); err = (*flp->deactivate)(dlp->slave, dev); return 0; @@ -347,7 +346,7 @@ static struct net_device_stats *dlci_get_stats(struct net_device *dev) { struct dlci_local *dlp; - dlp = dev->priv; + dlp = netdev_priv(dev); return(&dlp->stats); } @@ -365,7 +364,7 @@ static int dlci_add(struct dlci_add *dlci) if (!slave) return -ENODEV; - if (slave->type != ARPHRD_FRAD || slave->priv == NULL) + if (slave->type != ARPHRD_FRAD || netdev_priv(slave) == NULL) goto err1; /* create device name */ @@ -391,11 +390,11 @@ static int dlci_add(struct dlci_add *dlci) *(short *)(master->dev_addr) = dlci->dlci; - dlp = (struct dlci_local *) master->priv; + dlp = netdev_priv(master); dlp->slave = slave; dlp->master = master; - flp = slave->priv; + flp = netdev_priv(slave); err = (*flp->assoc)(slave, master); if (err < 0) goto err2; @@ -435,9 +434,9 @@ static int dlci_del(struct dlci_add *dlci) return(-EBUSY); } - dlp = master->priv; + dlp = netdev_priv(master); slave = dlp->slave; - flp = slave->priv; + flp = netdev_priv(slave); rtnl_lock(); err = (*flp->deassoc)(slave, master); @@ -491,7 +490,7 @@ static const struct header_ops dlci_header_ops = { static void dlci_setup(struct net_device *dev) { - struct dlci_local *dlp = dev->priv; + struct dlci_local *dlp = netdev_priv(dev); dev->flags = 0; dev->open = dlci_open; diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index 5f1ccb2b08b11d1dbe0f4a7cab308b6ec92105ef..888025db2f022616d6c0bd4343835be5e5c6a989 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -659,7 +659,6 @@ static inline void dscc4_rx_skb(struct dscc4_dev_priv *dpriv, skb_put(skb, pkt_len); if (netif_running(dev)) skb->protocol = hdlc_type_trans(skb, dev); - skb->dev->last_rx = jiffies; netif_rx(skb); } else { if (skb->data[pkt_len] & FrameRdo) @@ -730,8 +729,7 @@ static int __devinit dscc4_init_one(struct pci_dev *pdev, goto err_free_mmio_region_1; } - ioaddr = ioremap(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); + ioaddr = pci_ioremap_bar(pdev, 0); if (!ioaddr) { printk(KERN_ERR "%s: cannot remap MMIO region %llx @ %llx\n", DRV_NAME, (unsigned long long)pci_resource_len(pdev, 0), diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c index 9557ad078ab802e711496516d950f2d04cff3727..48a2c9d28950fc875a72334623343300bda21181 100644 --- a/drivers/net/wan/farsync.c +++ b/drivers/net/wan/farsync.c @@ -896,7 +896,6 @@ fst_rx_dma_complete(struct fst_card_info *card, struct fst_port_info *port, fst_process_rx_status(rx_status, port_to_dev(port)->name); if (rx_status == NET_RX_DROP) dev->stats.rx_dropped++; - dev->last_rx = jiffies; } /* @@ -1322,7 +1321,6 @@ fst_intr_rx(struct fst_card_info *card, struct fst_port_info *port) fst_process_rx_status(rx_status, port_to_dev(port)->name); if (rx_status == NET_RX_DROP) dev->stats.rx_dropped++; - dev->last_rx = jiffies; } else { card->dma_skb_rx = skb; card->dma_port_rx = port; diff --git a/drivers/net/wan/hd6457x.c b/drivers/net/wan/hd64570.c similarity index 78% rename from drivers/net/wan/hd6457x.c rename to drivers/net/wan/hd64570.c index 591fb45a7c68d01748fa8a15c1581ae0debb5720..223238de475cdf2ed8802334dfa8addca693f90f 100644 --- a/drivers/net/wan/hd6457x.c +++ b/drivers/net/wan/hd64570.c @@ -1,5 +1,5 @@ /* - * Hitachi SCA HD64570 and HD64572 common driver for Linux + * Hitachi SCA HD64570 driver for Linux * * Copyright (C) 1998-2003 Krzysztof Halasa * @@ -7,9 +7,7 @@ * under the terms of version 2 of the GNU General Public License * as published by the Free Software Foundation. * - * Sources of information: - * Hitachi HD64570 SCA User's Manual - * Hitachi HD64572 SCA-II User's Manual + * Source of information: Hitachi HD64570 SCA User's Manual * * We use the following SCA memory map: * @@ -26,33 +24,26 @@ * tx_ring_buffers * HDLC_MAX_MRU = logical channel #0 TX buffers (if used) */ -#include -#include -#include -#include -#include +#include +#include #include -#include +#include #include -#include -#include #include +#include #include -#include - -#include -#include -#include - +#include +#include +#include #include #include - -#include - -#if (!defined (__HD64570_H) && !defined (__HD64572_H)) || \ - (defined (__HD64570_H) && defined (__HD64572_H)) -#error Either hd64570.h or hd64572.h must be included -#endif +#include +#include +#include +#include +#include +#include +#include "hd64570.h" #define get_msci(port) (phy_node(port) ? MSCI1_OFFSET : MSCI0_OFFSET) #define get_dmac_rx(port) (phy_node(port) ? DMAC1RX_OFFSET : DMAC0RX_OFFSET) @@ -62,16 +53,6 @@ #define SCA_INTR_DMAC_RX(node) (node ? 0x20 : 0x02) #define SCA_INTR_DMAC_TX(node) (node ? 0x40 : 0x04) -#ifdef __HD64570_H /* HD64570 */ -#define sca_outa(value, reg, card) sca_outw(value, reg, card) -#define sca_ina(reg, card) sca_inw(reg, card) -#define writea(value, ptr) writew(value, ptr) - -#else /* HD64572 */ -#define sca_outa(value, reg, card) sca_outl(value, reg, card) -#define sca_ina(reg, card) sca_inl(reg, card) -#define writea(value, ptr) writel(value, ptr) -#endif static inline struct net_device *port_to_dev(port_t *port) { @@ -81,8 +62,6 @@ static inline struct net_device *port_to_dev(port_t *port) static inline int sca_intr_status(card_t *card) { u8 result = 0; - -#ifdef __HD64570_H /* HD64570 */ u8 isr0 = sca_in(ISR0, card); u8 isr1 = sca_in(ISR1, card); @@ -93,18 +72,6 @@ static inline int sca_intr_status(card_t *card) if (isr0 & 0x0F) result |= SCA_INTR_MSCI(0); if (isr0 & 0xF0) result |= SCA_INTR_MSCI(1); -#else /* HD64572 */ - u32 isr0 = sca_inl(ISR0, card); - - if (isr0 & 0x0000000F) result |= SCA_INTR_DMAC_RX(0); - if (isr0 & 0x000000F0) result |= SCA_INTR_DMAC_TX(0); - if (isr0 & 0x00000F00) result |= SCA_INTR_DMAC_RX(1); - if (isr0 & 0x0000F000) result |= SCA_INTR_DMAC_TX(1); - if (isr0 & 0x003E0000) result |= SCA_INTR_MSCI(0); - if (isr0 & 0x3E000000) result |= SCA_INTR_MSCI(1); - -#endif /* HD64570 vs HD64572 */ - if (!(result & SCA_INTR_DMAC_TX(0))) if (sca_in(DSR_TX(0), card) & DSR_EOM) result |= SCA_INTR_DMAC_TX(0); @@ -127,7 +94,6 @@ static inline u16 next_desc(port_t *port, u16 desc, int transmit) } - static inline u16 desc_abs_number(port_t *port, u16 desc, int transmit) { u16 rx_buffs = port_to_card(port)->rx_ring_buffers; @@ -139,28 +105,26 @@ static inline u16 desc_abs_number(port_t *port, u16 desc, int transmit) } - static inline u16 desc_offset(port_t *port, u16 desc, int transmit) { - /* Descriptor offset always fits in 16 bytes */ + /* Descriptor offset always fits in 16 bits */ return desc_abs_number(port, desc, transmit) * sizeof(pkt_desc); } - -static inline pkt_desc __iomem *desc_address(port_t *port, u16 desc, int transmit) +static inline pkt_desc __iomem *desc_address(port_t *port, u16 desc, + int transmit) { #ifdef PAGE0_ALWAYS_MAPPED return (pkt_desc __iomem *)(win0base(port_to_card(port)) - + desc_offset(port, desc, transmit)); + + desc_offset(port, desc, transmit)); #else return (pkt_desc __iomem *)(winbase(port_to_card(port)) - + desc_offset(port, desc, transmit)); + + desc_offset(port, desc, transmit)); #endif } - static inline u32 buffer_offset(port_t *port, u16 desc, int transmit) { return port_to_card(port)->buff_offset + @@ -186,7 +150,7 @@ static inline void sca_set_carrier(port_t *port) } -static void sca_init_sync_port(port_t *port) +static void sca_init_port(port_t *port) { card_t *card = port_to_card(port); int transmit, i; @@ -195,7 +159,7 @@ static void sca_init_sync_port(port_t *port) port->txin = 0; port->txlast = 0; -#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED) +#ifndef PAGE0_ALWAYS_MAPPED openwin(card, 0); #endif @@ -209,7 +173,7 @@ static void sca_init_sync_port(port_t *port) u16 chain_off = desc_offset(port, i + 1, transmit); u32 buff_off = buffer_offset(port, i, transmit); - writea(chain_off, &desc->cp); + writew(chain_off, &desc->cp); writel(buff_off, &desc->bp); writew(0, &desc->len); writeb(0, &desc->stat); @@ -222,16 +186,14 @@ static void sca_init_sync_port(port_t *port) sca_out(DCR_ABORT, transmit ? DCR_TX(phy_node(port)) : DCR_RX(phy_node(port)), card); -#ifdef __HD64570_H - sca_out(0, dmac + CPB, card); /* pointer base */ -#endif /* current desc addr */ - sca_outa(desc_offset(port, 0, transmit), dmac + CDAL, card); + sca_out(0, dmac + CPB, card); /* pointer base */ + sca_outw(desc_offset(port, 0, transmit), dmac + CDAL, card); if (!transmit) - sca_outa(desc_offset(port, buffs - 1, transmit), + sca_outw(desc_offset(port, buffs - 1, transmit), dmac + EDAL, card); else - sca_outa(desc_offset(port, 0, transmit), dmac + EDAL, + sca_outw(desc_offset(port, 0, transmit), dmac + EDAL, card); /* clear frame end interrupt counter */ @@ -258,7 +220,6 @@ static void sca_init_sync_port(port_t *port) } - #ifdef NEED_SCA_MSCI_INTR /* MSCI interrupt service */ static inline void sca_msci_intr(port_t *port) @@ -282,17 +243,15 @@ static inline void sca_msci_intr(port_t *port) #endif - -static inline void sca_rx(card_t *card, port_t *port, pkt_desc __iomem *desc, u16 rxin) +static inline void sca_rx(card_t *card, port_t *port, pkt_desc __iomem *desc, + u16 rxin) { struct net_device *dev = port_to_dev(port); struct sk_buff *skb; u16 len; u32 buff; -#ifndef ALL_PAGES_ALWAYS_MAPPED u32 maxlen; u8 page; -#endif len = readw(&desc->len); skb = dev_alloc_skb(len); @@ -302,7 +261,6 @@ static inline void sca_rx(card_t *card, port_t *port, pkt_desc __iomem *desc, u1 } buff = buffer_offset(port, rxin, 0); -#ifndef ALL_PAGES_ALWAYS_MAPPED page = buff / winsize(card); buff = buff % winsize(card); maxlen = winsize(card) - buff; @@ -314,12 +272,10 @@ static inline void sca_rx(card_t *card, port_t *port, pkt_desc __iomem *desc, u1 openwin(card, page + 1); memcpy_fromio(skb->data + maxlen, winbase(card), len - maxlen); } else -#endif - memcpy_fromio(skb->data, winbase(card) + buff, len); + memcpy_fromio(skb->data, winbase(card) + buff, len); -#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED) - /* select pkt_desc table page back */ - openwin(card, 0); +#ifndef PAGE0_ALWAYS_MAPPED + openwin(card, 0); /* select pkt_desc table page back */ #endif skb_put(skb, len); #ifdef DEBUG_PKT @@ -328,13 +284,11 @@ static inline void sca_rx(card_t *card, port_t *port, pkt_desc __iomem *desc, u1 #endif dev->stats.rx_packets++; dev->stats.rx_bytes += skb->len; - dev->last_rx = jiffies; skb->protocol = hdlc_type_trans(skb, dev); netif_rx(skb); } - /* Receive DMA interrupt service */ static inline void sca_rx_intr(port_t *port) { @@ -354,7 +308,7 @@ static inline void sca_rx_intr(port_t *port) while (1) { u32 desc_off = desc_offset(port, port->rxin, 0); pkt_desc __iomem *desc; - u32 cda = sca_ina(dmac + CDAL, card); + u32 cda = sca_inw(dmac + CDAL, card); if ((cda >= desc_off) && (cda < desc_off + sizeof(pkt_desc))) break; /* No frame received */ @@ -378,7 +332,7 @@ static inline void sca_rx_intr(port_t *port) sca_rx(card, port, desc, port->rxin); /* Set new error descriptor address */ - sca_outa(desc_off, dmac + EDAL, card); + sca_outw(desc_off, dmac + EDAL, card); port->rxin = next_desc(port, port->rxin, 0); } @@ -387,7 +341,6 @@ static inline void sca_rx_intr(port_t *port) } - /* Transmit DMA interrupt service */ static inline void sca_tx_intr(port_t *port) { @@ -408,7 +361,7 @@ static inline void sca_tx_intr(port_t *port) pkt_desc __iomem *desc; u32 desc_off = desc_offset(port, port->txlast, 1); - u32 cda = sca_ina(dmac + CDAL, card); + u32 cda = sca_inw(dmac + CDAL, card); if ((cda >= desc_off) && (cda < desc_off + sizeof(pkt_desc))) break; /* Transmitter is/will_be sending this frame */ @@ -424,17 +377,13 @@ static inline void sca_tx_intr(port_t *port) } - static irqreturn_t sca_intr(int irq, void* dev_id) { card_t *card = dev_id; int i; u8 stat; int handled = 0; - -#ifndef ALL_PAGES_ALWAYS_MAPPED u8 page = sca_get_page(card); -#endif while((stat = sca_intr_status(card)) != 0) { handled = 1; @@ -453,14 +402,11 @@ static irqreturn_t sca_intr(int irq, void* dev_id) } } -#ifndef ALL_PAGES_ALWAYS_MAPPED openwin(card, page); /* Restore original page */ -#endif return IRQ_RETVAL(handled); } - static void sca_set_port(port_t *port) { card_t* card = port_to_card(port); @@ -498,12 +444,7 @@ static void sca_set_port(port_t *port) port->tmc = tmc; /* baud divisor - time constant*/ -#ifdef __HD64570_H sca_out(port->tmc, msci + TMC, card); -#else - sca_out(port->tmc, msci + TMCR, card); - sca_out(port->tmc, msci + TMCT, card); -#endif /* Set BRG bits */ sca_out(port->rxs, msci + RXS, card); @@ -519,7 +460,6 @@ static void sca_set_port(port_t *port) } - static void sca_open(struct net_device *dev) { port_t *port = dev_to_port(dev); @@ -541,11 +481,7 @@ static void sca_open(struct net_device *dev) switch(port->parity) { case PARITY_CRC16_PR0: md0 = MD0_HDLC | MD0_CRC_16_0; break; case PARITY_CRC16_PR1: md0 = MD0_HDLC | MD0_CRC_16; break; -#ifdef __HD64570_H case PARITY_CRC16_PR0_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU_0; break; -#else - case PARITY_CRC32_PR1_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU32; break; -#endif case PARITY_CRC16_PR1_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU; break; default: md0 = MD0_HDLC | MD0_CRC_NONE; } @@ -555,35 +491,20 @@ static void sca_open(struct net_device *dev) sca_out(0x00, msci + MD1, card); /* no address field check */ sca_out(md2, msci + MD2, card); sca_out(0x7E, msci + IDL, card); /* flag character 0x7E */ -#ifdef __HD64570_H sca_out(CTL_IDLE, msci + CTL, card); -#else - /* Skip the rest of underrun frame */ - sca_out(CTL_IDLE | CTL_URCT | CTL_URSKP, msci + CTL, card); -#endif -#ifdef __HD64570_H /* Allow at least 8 bytes before requesting RX DMA operation */ /* TX with higher priority and possibly with shorter transfers */ sca_out(0x07, msci + RRC, card); /* +1=RXRDY/DMA activation condition*/ sca_out(0x10, msci + TRC0, card); /* = TXRDY/DMA activation condition*/ sca_out(0x14, msci + TRC1, card); /* +1=TXRDY/DMA deactiv condition */ -#else - sca_out(0x0F, msci + RNR, card); /* +1=RX DMA activation condition */ - sca_out(0x3C, msci + TFS, card); /* +1 = TX start */ - sca_out(0x38, msci + TCR, card); /* =Critical TX DMA activ condition */ - sca_out(0x38, msci + TNR0, card); /* =TX DMA activation condition */ - sca_out(0x3F, msci + TNR1, card); /* +1=TX DMA deactivation condition*/ -#endif /* We're using the following interrupts: - TXINT (DMAC completed all transmisions, underrun or DCD change) - all DMA interrupts */ - sca_set_carrier(port); -#ifdef __HD64570_H /* MSCI TX INT and RX INT A IRQ enable */ sca_out(IE0_TXINT | IE0_RXINTA, msci + IE0, card); sca_out(IE1_UDRN | IE1_CDCD, msci + IE1, card); @@ -592,21 +513,8 @@ static void sca_open(struct net_device *dev) /* enable DMA IRQ */ sca_out(sca_in(IER1, card) | (phy_node(port) ? 0xF0 : 0x0F), IER1, card); -#else - /* MSCI TXINT and RXINTA interrupt enable */ - sca_outl(IE0_TXINT | IE0_RXINTA | IE0_UDRN | IE0_CDCD, msci + IE0, - card); - /* DMA & MSCI IRQ enable */ - sca_outl(sca_inl(IER0, card) | - (phy_node(port) ? 0x0A006600 : 0x000A0066), IER0, card); -#endif -#ifdef __HD64570_H sca_out(port->tmc, msci + TMC, card); /* Restore registers */ -#else - sca_out(port->tmc, msci + TMCR, card); - sca_out(port->tmc, msci + TMCT, card); -#endif sca_out(port->rxs, msci + RXS, card); sca_out(port->txs, msci + TXS, card); sca_out(CMD_TX_ENABLE, msci + CMD, card); @@ -616,7 +524,6 @@ static void sca_open(struct net_device *dev) } - static void sca_close(struct net_device *dev) { port_t *port = dev_to_port(dev); @@ -624,23 +531,17 @@ static void sca_close(struct net_device *dev) /* reset channel */ sca_out(CMD_RESET, get_msci(port) + CMD, port_to_card(port)); -#ifdef __HD64570_H /* disable MSCI interrupts */ sca_out(sca_in(IER0, card) & (phy_node(port) ? 0x0F : 0xF0), IER0, card); /* disable DMA interrupts */ sca_out(sca_in(IER1, card) & (phy_node(port) ? 0x0F : 0xF0), IER1, card); -#else - /* disable DMA & MSCI IRQ */ - sca_outl(sca_inl(IER0, card) & - (phy_node(port) ? 0x00FF00FF : 0xFF00FF00), IER0, card); -#endif + netif_stop_queue(dev); } - static int sca_attach(struct net_device *dev, unsigned short encoding, unsigned short parity) { @@ -654,11 +555,7 @@ static int sca_attach(struct net_device *dev, unsigned short encoding, if (parity != PARITY_NONE && parity != PARITY_CRC16_PR0 && parity != PARITY_CRC16_PR1 && -#ifdef __HD64570_H parity != PARITY_CRC16_PR0_CCITT && -#else - parity != PARITY_CRC32_PR1_CCITT && -#endif parity != PARITY_CRC16_PR1_CCITT) return -EINVAL; @@ -668,34 +565,30 @@ static int sca_attach(struct net_device *dev, unsigned short encoding, } - #ifdef DEBUG_RINGS static void sca_dump_rings(struct net_device *dev) { port_t *port = dev_to_port(dev); card_t *card = port_to_card(port); u16 cnt; -#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED) - u8 page; -#endif +#ifndef PAGE0_ALWAYS_MAPPED + u8 page = sca_get_page(card); -#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED) - page = sca_get_page(card); openwin(card, 0); #endif printk(KERN_DEBUG "RX ring: CDA=%u EDA=%u DSR=%02X in=%u %sactive", - sca_ina(get_dmac_rx(port) + CDAL, card), - sca_ina(get_dmac_rx(port) + EDAL, card), + sca_inw(get_dmac_rx(port) + CDAL, card), + sca_inw(get_dmac_rx(port) + EDAL, card), sca_in(DSR_RX(phy_node(port)), card), port->rxin, - sca_in(DSR_RX(phy_node(port)), card) & DSR_DE?"":"in"); + sca_in(DSR_RX(phy_node(port)), card) & DSR_DE ? "" : "in"); for (cnt = 0; cnt < port_to_card(port)->rx_ring_buffers; cnt++) printk(" %02X", readb(&(desc_address(port, cnt, 0)->stat))); printk("\n" KERN_DEBUG "TX ring: CDA=%u EDA=%u DSR=%02X in=%u " "last=%u %sactive", - sca_ina(get_dmac_tx(port) + CDAL, card), - sca_ina(get_dmac_tx(port) + EDAL, card), + sca_inw(get_dmac_tx(port) + CDAL, card), + sca_inw(get_dmac_tx(port) + EDAL, card), sca_in(DSR_TX(phy_node(port)), card), port->txin, port->txlast, sca_in(DSR_TX(phy_node(port)), card) & DSR_DE ? "" : "in"); @@ -703,12 +596,8 @@ static void sca_dump_rings(struct net_device *dev) printk(" %02X", readb(&(desc_address(port, cnt, 1)->stat))); printk("\n"); - printk(KERN_DEBUG "MSCI: MD: %02x %02x %02x, " - "ST: %02x %02x %02x %02x" -#ifdef __HD64572_H - " %02x" -#endif - ", FST: %02x CST: %02x %02x\n", + printk(KERN_DEBUG "MSCI: MD: %02x %02x %02x, ST: %02x %02x %02x %02x," + " FST: %02x CST: %02x %02x\n", sca_in(get_msci(port) + MD0, card), sca_in(get_msci(port) + MD1, card), sca_in(get_msci(port) + MD2, card), @@ -716,52 +605,33 @@ static void sca_dump_rings(struct net_device *dev) sca_in(get_msci(port) + ST1, card), sca_in(get_msci(port) + ST2, card), sca_in(get_msci(port) + ST3, card), -#ifdef __HD64572_H - sca_in(get_msci(port) + ST4, card), -#endif sca_in(get_msci(port) + FST, card), sca_in(get_msci(port) + CST0, card), sca_in(get_msci(port) + CST1, card)); -#ifdef __HD64572_H - printk(KERN_DEBUG "ILAR: %02x ISR: %08x %08x\n", sca_in(ILAR, card), - sca_inl(ISR0, card), sca_inl(ISR1, card)); -#else printk(KERN_DEBUG "ISR: %02x %02x %02x\n", sca_in(ISR0, card), sca_in(ISR1, card), sca_in(ISR2, card)); -#endif -#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED) +#ifndef PAGE0_ALWAYS_MAPPED openwin(card, page); /* Restore original page */ #endif } #endif /* DEBUG_RINGS */ - static int sca_xmit(struct sk_buff *skb, struct net_device *dev) { port_t *port = dev_to_port(dev); card_t *card = port_to_card(port); pkt_desc __iomem *desc; u32 buff, len; -#ifndef ALL_PAGES_ALWAYS_MAPPED u8 page; u32 maxlen; -#endif spin_lock_irq(&port->lock); desc = desc_address(port, port->txin + 1, 1); - if (readb(&desc->stat)) { /* allow 1 packet gap */ - /* should never happen - previous xmit should stop queue */ -#ifdef DEBUG_PKT - printk(KERN_DEBUG "%s: transmitter buffer full\n", dev->name); -#endif - netif_stop_queue(dev); - spin_unlock_irq(&port->lock); - return 1; /* request packet to be queued */ - } + BUG_ON(readb(&desc->stat)); /* previous xmit should stop queue */ #ifdef DEBUG_PKT printk(KERN_DEBUG "%s TX(%i):", dev->name, skb->len); @@ -771,7 +641,6 @@ static int sca_xmit(struct sk_buff *skb, struct net_device *dev) desc = desc_address(port, port->txin, 1); buff = buffer_offset(port, port->txin, 1); len = skb->len; -#ifndef ALL_PAGES_ALWAYS_MAPPED page = buff / winsize(card); buff = buff % winsize(card); maxlen = winsize(card) - buff; @@ -781,12 +650,10 @@ static int sca_xmit(struct sk_buff *skb, struct net_device *dev) memcpy_toio(winbase(card) + buff, skb->data, maxlen); openwin(card, page + 1); memcpy_toio(winbase(card), skb->data + maxlen, len - maxlen); - } - else -#endif + } else memcpy_toio(winbase(card) + buff, skb->data, len); -#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED) +#ifndef PAGE0_ALWAYS_MAPPED openwin(card, 0); /* select pkt_desc table page back */ #endif writew(len, &desc->len); @@ -794,7 +661,7 @@ static int sca_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; port->txin = next_desc(port, port->txin, 1); - sca_outa(desc_offset(port, port->txin, 1), + sca_outw(desc_offset(port, port->txin, 1), get_dmac_tx(port) + EDAL, card); sca_out(DSR_DE, DSR_TX(phy_node(port)), card); /* Enable TX DMA */ @@ -810,40 +677,29 @@ static int sca_xmit(struct sk_buff *skb, struct net_device *dev) } - #ifdef NEED_DETECT_RAM -static u32 __devinit sca_detect_ram(card_t *card, u8 __iomem *rambase, u32 ramsize) +static u32 __devinit sca_detect_ram(card_t *card, u8 __iomem *rambase, + u32 ramsize) { /* Round RAM size to 32 bits, fill from end to start */ u32 i = ramsize &= ~3; - -#ifndef ALL_PAGES_ALWAYS_MAPPED u32 size = winsize(card); openwin(card, (i - 4) / size); /* select last window */ -#endif + do { i -= 4; -#ifndef ALL_PAGES_ALWAYS_MAPPED if ((i + 4) % size == 0) openwin(card, i / size); writel(i ^ 0x12345678, rambase + i % size); -#else - writel(i ^ 0x12345678, rambase + i); -#endif - }while (i > 0); + } while (i > 0); for (i = 0; i < ramsize ; i += 4) { -#ifndef ALL_PAGES_ALWAYS_MAPPED if (i % size == 0) openwin(card, i / size); if (readl(rambase + i % size) != (i ^ 0x12345678)) break; -#else - if (readl(rambase + i) != (i ^ 0x12345678)) - break; -#endif } return i; @@ -851,7 +707,6 @@ static u32 __devinit sca_detect_ram(card_t *card, u8 __iomem *rambase, u32 ramsi #endif /* NEED_DETECT_RAM */ - static void __devinit sca_init(card_t *card, int wait_states) { sca_out(wait_states, WCRL, card); /* Wait Control */ diff --git a/drivers/net/wan/hd64572.c b/drivers/net/wan/hd64572.c new file mode 100644 index 0000000000000000000000000000000000000000..08b3536944fe034544c74dc2470d7745393b89aa --- /dev/null +++ b/drivers/net/wan/hd64572.c @@ -0,0 +1,640 @@ +/* + * Hitachi (now Renesas) SCA-II HD64572 driver for Linux + * + * Copyright (C) 1998-2008 Krzysztof Halasa + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * Source of information: HD64572 SCA-II User's Manual + * + * We use the following SCA memory map: + * + * Packet buffer descriptor rings - starting from card->rambase: + * rx_ring_buffers * sizeof(pkt_desc) = logical channel #0 RX ring + * tx_ring_buffers * sizeof(pkt_desc) = logical channel #0 TX ring + * rx_ring_buffers * sizeof(pkt_desc) = logical channel #1 RX ring (if used) + * tx_ring_buffers * sizeof(pkt_desc) = logical channel #1 TX ring (if used) + * + * Packet data buffers - starting from card->rambase + buff_offset: + * rx_ring_buffers * HDLC_MAX_MRU = logical channel #0 RX buffers + * tx_ring_buffers * HDLC_MAX_MRU = logical channel #0 TX buffers + * rx_ring_buffers * HDLC_MAX_MRU = logical channel #0 RX buffers (if used) + * tx_ring_buffers * HDLC_MAX_MRU = logical channel #0 TX buffers (if used) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hd64572.h" + +#define NAPI_WEIGHT 16 + +#define get_msci(port) (port->chan ? MSCI1_OFFSET : MSCI0_OFFSET) +#define get_dmac_rx(port) (port->chan ? DMAC1RX_OFFSET : DMAC0RX_OFFSET) +#define get_dmac_tx(port) (port->chan ? DMAC1TX_OFFSET : DMAC0TX_OFFSET) + +#define sca_in(reg, card) readb(card->scabase + (reg)) +#define sca_out(value, reg, card) writeb(value, card->scabase + (reg)) +#define sca_inw(reg, card) readw(card->scabase + (reg)) +#define sca_outw(value, reg, card) writew(value, card->scabase + (reg)) +#define sca_inl(reg, card) readl(card->scabase + (reg)) +#define sca_outl(value, reg, card) writel(value, card->scabase + (reg)) + +static int sca_poll(struct napi_struct *napi, int budget); + +static inline port_t* dev_to_port(struct net_device *dev) +{ + return dev_to_hdlc(dev)->priv; +} + +static inline void enable_intr(port_t *port) +{ + /* enable DMIB and MSCI RXINTA interrupts */ + sca_outl(sca_inl(IER0, port->card) | + (port->chan ? 0x08002200 : 0x00080022), IER0, port->card); +} + +static inline void disable_intr(port_t *port) +{ + sca_outl(sca_inl(IER0, port->card) & + (port->chan ? 0x00FF00FF : 0xFF00FF00), IER0, port->card); +} + +static inline u16 desc_abs_number(port_t *port, u16 desc, int transmit) +{ + u16 rx_buffs = port->card->rx_ring_buffers; + u16 tx_buffs = port->card->tx_ring_buffers; + + desc %= (transmit ? tx_buffs : rx_buffs); // called with "X + 1" etc. + return port->chan * (rx_buffs + tx_buffs) + transmit * rx_buffs + desc; +} + + +static inline u16 desc_offset(port_t *port, u16 desc, int transmit) +{ + /* Descriptor offset always fits in 16 bits */ + return desc_abs_number(port, desc, transmit) * sizeof(pkt_desc); +} + + +static inline pkt_desc __iomem *desc_address(port_t *port, u16 desc, + int transmit) +{ + return (pkt_desc __iomem *)(port->card->rambase + + desc_offset(port, desc, transmit)); +} + + +static inline u32 buffer_offset(port_t *port, u16 desc, int transmit) +{ + return port->card->buff_offset + + desc_abs_number(port, desc, transmit) * (u32)HDLC_MAX_MRU; +} + + +static inline void sca_set_carrier(port_t *port) +{ + if (!(sca_in(get_msci(port) + ST3, port->card) & ST3_DCD)) { +#ifdef DEBUG_LINK + printk(KERN_DEBUG "%s: sca_set_carrier on\n", + port->netdev.name); +#endif + netif_carrier_on(port->netdev); + } else { +#ifdef DEBUG_LINK + printk(KERN_DEBUG "%s: sca_set_carrier off\n", + port->netdev.name); +#endif + netif_carrier_off(port->netdev); + } +} + + +static void sca_init_port(port_t *port) +{ + card_t *card = port->card; + u16 dmac_rx = get_dmac_rx(port), dmac_tx = get_dmac_tx(port); + int transmit, i; + + port->rxin = 0; + port->txin = 0; + port->txlast = 0; + + for (transmit = 0; transmit < 2; transmit++) { + u16 buffs = transmit ? card->tx_ring_buffers + : card->rx_ring_buffers; + + for (i = 0; i < buffs; i++) { + pkt_desc __iomem *desc = desc_address(port, i, transmit); + u16 chain_off = desc_offset(port, i + 1, transmit); + u32 buff_off = buffer_offset(port, i, transmit); + + writel(chain_off, &desc->cp); + writel(buff_off, &desc->bp); + writew(0, &desc->len); + writeb(0, &desc->stat); + } + } + + /* DMA disable - to halt state */ + sca_out(0, DSR_RX(port->chan), card); + sca_out(0, DSR_TX(port->chan), card); + + /* software ABORT - to initial state */ + sca_out(DCR_ABORT, DCR_RX(port->chan), card); + sca_out(DCR_ABORT, DCR_TX(port->chan), card); + + /* current desc addr */ + sca_outl(desc_offset(port, 0, 0), dmac_rx + CDAL, card); + sca_outl(desc_offset(port, card->tx_ring_buffers - 1, 0), + dmac_rx + EDAL, card); + sca_outl(desc_offset(port, 0, 1), dmac_tx + CDAL, card); + sca_outl(desc_offset(port, 0, 1), dmac_tx + EDAL, card); + + /* clear frame end interrupt counter */ + sca_out(DCR_CLEAR_EOF, DCR_RX(port->chan), card); + sca_out(DCR_CLEAR_EOF, DCR_TX(port->chan), card); + + /* Receive */ + sca_outw(HDLC_MAX_MRU, dmac_rx + BFLL, card); /* set buffer length */ + sca_out(0x14, DMR_RX(port->chan), card); /* Chain mode, Multi-frame */ + sca_out(DIR_EOME, DIR_RX(port->chan), card); /* enable interrupts */ + sca_out(DSR_DE, DSR_RX(port->chan), card); /* DMA enable */ + + /* Transmit */ + sca_out(0x14, DMR_TX(port->chan), card); /* Chain mode, Multi-frame */ + sca_out(DIR_EOME, DIR_TX(port->chan), card); /* enable interrupts */ + + sca_set_carrier(port); + netif_napi_add(port->netdev, &port->napi, sca_poll, NAPI_WEIGHT); +} + + +/* MSCI interrupt service */ +static inline void sca_msci_intr(port_t *port) +{ + u16 msci = get_msci(port); + card_t* card = port->card; + + if (sca_in(msci + ST1, card) & ST1_CDCD) { + /* Reset MSCI CDCD status bit */ + sca_out(ST1_CDCD, msci + ST1, card); + sca_set_carrier(port); + } +} + + +static inline void sca_rx(card_t *card, port_t *port, pkt_desc __iomem *desc, + u16 rxin) +{ + struct net_device *dev = port->netdev; + struct sk_buff *skb; + u16 len; + u32 buff; + + len = readw(&desc->len); + skb = dev_alloc_skb(len); + if (!skb) { + dev->stats.rx_dropped++; + return; + } + + buff = buffer_offset(port, rxin, 0); + memcpy_fromio(skb->data, card->rambase + buff, len); + + skb_put(skb, len); +#ifdef DEBUG_PKT + printk(KERN_DEBUG "%s RX(%i):", dev->name, skb->len); + debug_frame(skb); +#endif + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; + skb->protocol = hdlc_type_trans(skb, dev); + netif_receive_skb(skb); +} + + +/* Receive DMA service */ +static inline int sca_rx_done(port_t *port, int budget) +{ + struct net_device *dev = port->netdev; + u16 dmac = get_dmac_rx(port); + card_t *card = port->card; + u8 stat = sca_in(DSR_RX(port->chan), card); /* read DMA Status */ + int received = 0; + + /* Reset DSR status bits */ + sca_out((stat & (DSR_EOT | DSR_EOM | DSR_BOF | DSR_COF)) | DSR_DWE, + DSR_RX(port->chan), card); + + if (stat & DSR_BOF) + /* Dropped one or more frames */ + dev->stats.rx_over_errors++; + + while (received < budget) { + u32 desc_off = desc_offset(port, port->rxin, 0); + pkt_desc __iomem *desc; + u32 cda = sca_inl(dmac + CDAL, card); + + if ((cda >= desc_off) && (cda < desc_off + sizeof(pkt_desc))) + break; /* No frame received */ + + desc = desc_address(port, port->rxin, 0); + stat = readb(&desc->stat); + if (!(stat & ST_RX_EOM)) + port->rxpart = 1; /* partial frame received */ + else if ((stat & ST_ERROR_MASK) || port->rxpart) { + dev->stats.rx_errors++; + if (stat & ST_RX_OVERRUN) + dev->stats.rx_fifo_errors++; + else if ((stat & (ST_RX_SHORT | ST_RX_ABORT | + ST_RX_RESBIT)) || port->rxpart) + dev->stats.rx_frame_errors++; + else if (stat & ST_RX_CRC) + dev->stats.rx_crc_errors++; + if (stat & ST_RX_EOM) + port->rxpart = 0; /* received last fragment */ + } else { + sca_rx(card, port, desc, port->rxin); + received++; + } + + /* Set new error descriptor address */ + sca_outl(desc_off, dmac + EDAL, card); + port->rxin = (port->rxin + 1) % card->rx_ring_buffers; + } + + /* make sure RX DMA is enabled */ + sca_out(DSR_DE, DSR_RX(port->chan), card); + return received; +} + + +/* Transmit DMA service */ +static inline void sca_tx_done(port_t *port) +{ + struct net_device *dev = port->netdev; + card_t* card = port->card; + u8 stat; + + spin_lock(&port->lock); + + stat = sca_in(DSR_TX(port->chan), card); /* read DMA Status */ + + /* Reset DSR status bits */ + sca_out((stat & (DSR_EOT | DSR_EOM | DSR_BOF | DSR_COF)) | DSR_DWE, + DSR_TX(port->chan), card); + + while (1) { + pkt_desc __iomem *desc = desc_address(port, port->txlast, 1); + u8 stat = readb(&desc->stat); + + if (!(stat & ST_TX_OWNRSHP)) + break; /* not yet transmitted */ + if (stat & ST_TX_UNDRRUN) { + dev->stats.tx_errors++; + dev->stats.tx_fifo_errors++; + } else { + dev->stats.tx_packets++; + dev->stats.tx_bytes += readw(&desc->len); + } + writeb(0, &desc->stat); /* Free descriptor */ + port->txlast = (port->txlast + 1) % card->tx_ring_buffers; + } + + netif_wake_queue(dev); + spin_unlock(&port->lock); +} + + +static int sca_poll(struct napi_struct *napi, int budget) +{ + port_t *port = container_of(napi, port_t, napi); + u32 isr0 = sca_inl(ISR0, port->card); + int received = 0; + + if (isr0 & (port->chan ? 0x08000000 : 0x00080000)) + sca_msci_intr(port); + + if (isr0 & (port->chan ? 0x00002000 : 0x00000020)) + sca_tx_done(port); + + if (isr0 & (port->chan ? 0x00000200 : 0x00000002)) + received = sca_rx_done(port, budget); + + if (received < budget) { + netif_rx_complete(napi); + enable_intr(port); + } + + return received; +} + +static irqreturn_t sca_intr(int irq, void *dev_id) +{ + card_t *card = dev_id; + u32 isr0 = sca_inl(ISR0, card); + int i, handled = 0; + + for (i = 0; i < 2; i++) { + port_t *port = get_port(card, i); + if (port && (isr0 & (i ? 0x08002200 : 0x00080022))) { + handled = 1; + disable_intr(port); + netif_rx_schedule(&port->napi); + } + } + + return IRQ_RETVAL(handled); +} + + +static void sca_set_port(port_t *port) +{ + card_t* card = port->card; + u16 msci = get_msci(port); + u8 md2 = sca_in(msci + MD2, card); + unsigned int tmc, br = 10, brv = 1024; + + + if (port->settings.clock_rate > 0) { + /* Try lower br for better accuracy*/ + do { + br--; + brv >>= 1; /* brv = 2^9 = 512 max in specs */ + + /* Baud Rate = CLOCK_BASE / TMC / 2^BR */ + tmc = CLOCK_BASE / brv / port->settings.clock_rate; + }while (br > 1 && tmc <= 128); + + if (tmc < 1) { + tmc = 1; + br = 0; /* For baud=CLOCK_BASE we use tmc=1 br=0 */ + brv = 1; + } else if (tmc > 255) + tmc = 256; /* tmc=0 means 256 - low baud rates */ + + port->settings.clock_rate = CLOCK_BASE / brv / tmc; + } else { + br = 9; /* Minimum clock rate */ + tmc = 256; /* 8bit = 0 */ + port->settings.clock_rate = CLOCK_BASE / (256 * 512); + } + + port->rxs = (port->rxs & ~CLK_BRG_MASK) | br; + port->txs = (port->txs & ~CLK_BRG_MASK) | br; + port->tmc = tmc; + + /* baud divisor - time constant*/ + sca_out(port->tmc, msci + TMCR, card); + sca_out(port->tmc, msci + TMCT, card); + + /* Set BRG bits */ + sca_out(port->rxs, msci + RXS, card); + sca_out(port->txs, msci + TXS, card); + + if (port->settings.loopback) + md2 |= MD2_LOOPBACK; + else + md2 &= ~MD2_LOOPBACK; + + sca_out(md2, msci + MD2, card); + +} + + +static void sca_open(struct net_device *dev) +{ + port_t *port = dev_to_port(dev); + card_t* card = port->card; + u16 msci = get_msci(port); + u8 md0, md2; + + switch(port->encoding) { + case ENCODING_NRZ: md2 = MD2_NRZ; break; + case ENCODING_NRZI: md2 = MD2_NRZI; break; + case ENCODING_FM_MARK: md2 = MD2_FM_MARK; break; + case ENCODING_FM_SPACE: md2 = MD2_FM_SPACE; break; + default: md2 = MD2_MANCHESTER; + } + + if (port->settings.loopback) + md2 |= MD2_LOOPBACK; + + switch(port->parity) { + case PARITY_CRC16_PR0: md0 = MD0_HDLC | MD0_CRC_16_0; break; + case PARITY_CRC16_PR1: md0 = MD0_HDLC | MD0_CRC_16; break; + case PARITY_CRC32_PR1_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU32; break; + case PARITY_CRC16_PR1_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU; break; + default: md0 = MD0_HDLC | MD0_CRC_NONE; + } + + sca_out(CMD_RESET, msci + CMD, card); + sca_out(md0, msci + MD0, card); + sca_out(0x00, msci + MD1, card); /* no address field check */ + sca_out(md2, msci + MD2, card); + sca_out(0x7E, msci + IDL, card); /* flag character 0x7E */ + /* Skip the rest of underrun frame */ + sca_out(CTL_IDLE | CTL_URCT | CTL_URSKP, msci + CTL, card); + sca_out(0x0F, msci + RNR, card); /* +1=RX DMA activation condition */ + sca_out(0x3C, msci + TFS, card); /* +1 = TX start */ + sca_out(0x38, msci + TCR, card); /* =Critical TX DMA activ condition */ + sca_out(0x38, msci + TNR0, card); /* =TX DMA activation condition */ + sca_out(0x3F, msci + TNR1, card); /* +1=TX DMA deactivation condition*/ + +/* We're using the following interrupts: + - RXINTA (DCD changes only) + - DMIB (EOM - single frame transfer complete) +*/ + sca_outl(IE0_RXINTA | IE0_CDCD, msci + IE0, card); + + sca_out(port->tmc, msci + TMCR, card); + sca_out(port->tmc, msci + TMCT, card); + sca_out(port->rxs, msci + RXS, card); + sca_out(port->txs, msci + TXS, card); + sca_out(CMD_TX_ENABLE, msci + CMD, card); + sca_out(CMD_RX_ENABLE, msci + CMD, card); + + sca_set_carrier(port); + enable_intr(port); + napi_enable(&port->napi); + netif_start_queue(dev); +} + + +static void sca_close(struct net_device *dev) +{ + port_t *port = dev_to_port(dev); + + /* reset channel */ + sca_out(CMD_RESET, get_msci(port) + CMD, port->card); + disable_intr(port); + napi_disable(&port->napi); + netif_stop_queue(dev); +} + + +static int sca_attach(struct net_device *dev, unsigned short encoding, + unsigned short parity) +{ + if (encoding != ENCODING_NRZ && + encoding != ENCODING_NRZI && + encoding != ENCODING_FM_MARK && + encoding != ENCODING_FM_SPACE && + encoding != ENCODING_MANCHESTER) + return -EINVAL; + + if (parity != PARITY_NONE && + parity != PARITY_CRC16_PR0 && + parity != PARITY_CRC16_PR1 && + parity != PARITY_CRC32_PR1_CCITT && + parity != PARITY_CRC16_PR1_CCITT) + return -EINVAL; + + dev_to_port(dev)->encoding = encoding; + dev_to_port(dev)->parity = parity; + return 0; +} + + +#ifdef DEBUG_RINGS +static void sca_dump_rings(struct net_device *dev) +{ + port_t *port = dev_to_port(dev); + card_t *card = port->card; + u16 cnt; + + printk(KERN_DEBUG "RX ring: CDA=%u EDA=%u DSR=%02X in=%u %sactive", + sca_inl(get_dmac_rx(port) + CDAL, card), + sca_inl(get_dmac_rx(port) + EDAL, card), + sca_in(DSR_RX(port->chan), card), port->rxin, + sca_in(DSR_RX(port->chan), card) & DSR_DE ? "" : "in"); + for (cnt = 0; cnt < port->card->rx_ring_buffers; cnt++) + printk(" %02X", readb(&(desc_address(port, cnt, 0)->stat))); + + printk("\n" KERN_DEBUG "TX ring: CDA=%u EDA=%u DSR=%02X in=%u " + "last=%u %sactive", + sca_inl(get_dmac_tx(port) + CDAL, card), + sca_inl(get_dmac_tx(port) + EDAL, card), + sca_in(DSR_TX(port->chan), card), port->txin, port->txlast, + sca_in(DSR_TX(port->chan), card) & DSR_DE ? "" : "in"); + + for (cnt = 0; cnt < port->card->tx_ring_buffers; cnt++) + printk(" %02X", readb(&(desc_address(port, cnt, 1)->stat))); + printk("\n"); + + printk(KERN_DEBUG "MSCI: MD: %02x %02x %02x," + " ST: %02x %02x %02x %02x %02x, FST: %02x CST: %02x %02x\n", + sca_in(get_msci(port) + MD0, card), + sca_in(get_msci(port) + MD1, card), + sca_in(get_msci(port) + MD2, card), + sca_in(get_msci(port) + ST0, card), + sca_in(get_msci(port) + ST1, card), + sca_in(get_msci(port) + ST2, card), + sca_in(get_msci(port) + ST3, card), + sca_in(get_msci(port) + ST4, card), + sca_in(get_msci(port) + FST, card), + sca_in(get_msci(port) + CST0, card), + sca_in(get_msci(port) + CST1, card)); + + printk(KERN_DEBUG "ILAR: %02x ISR: %08x %08x\n", sca_in(ILAR, card), + sca_inl(ISR0, card), sca_inl(ISR1, card)); +} +#endif /* DEBUG_RINGS */ + + +static int sca_xmit(struct sk_buff *skb, struct net_device *dev) +{ + port_t *port = dev_to_port(dev); + card_t *card = port->card; + pkt_desc __iomem *desc; + u32 buff, len; + + spin_lock_irq(&port->lock); + + desc = desc_address(port, port->txin + 1, 1); + BUG_ON(readb(&desc->stat)); /* previous xmit should stop queue */ + +#ifdef DEBUG_PKT + printk(KERN_DEBUG "%s TX(%i):", dev->name, skb->len); + debug_frame(skb); +#endif + + desc = desc_address(port, port->txin, 1); + buff = buffer_offset(port, port->txin, 1); + len = skb->len; + memcpy_toio(card->rambase + buff, skb->data, len); + + writew(len, &desc->len); + writeb(ST_TX_EOM, &desc->stat); + dev->trans_start = jiffies; + + port->txin = (port->txin + 1) % card->tx_ring_buffers; + sca_outl(desc_offset(port, port->txin, 1), + get_dmac_tx(port) + EDAL, card); + + sca_out(DSR_DE, DSR_TX(port->chan), card); /* Enable TX DMA */ + + desc = desc_address(port, port->txin + 1, 1); + if (readb(&desc->stat)) /* allow 1 packet gap */ + netif_stop_queue(dev); + + spin_unlock_irq(&port->lock); + + dev_kfree_skb(skb); + return 0; +} + + +static u32 __devinit sca_detect_ram(card_t *card, u8 __iomem *rambase, + u32 ramsize) +{ + /* Round RAM size to 32 bits, fill from end to start */ + u32 i = ramsize &= ~3; + + do { + i -= 4; + writel(i ^ 0x12345678, rambase + i); + } while (i > 0); + + for (i = 0; i < ramsize ; i += 4) { + if (readl(rambase + i) != (i ^ 0x12345678)) + break; + } + + return i; +} + + +static void __devinit sca_init(card_t *card, int wait_states) +{ + sca_out(wait_states, WCRL, card); /* Wait Control */ + sca_out(wait_states, WCRM, card); + sca_out(wait_states, WCRH, card); + + sca_out(0, DMER, card); /* DMA Master disable */ + sca_out(0x03, PCR, card); /* DMA priority */ + sca_out(0, DSR_RX(0), card); /* DMA disable - to halt state */ + sca_out(0, DSR_TX(0), card); + sca_out(0, DSR_RX(1), card); + sca_out(0, DSR_TX(1), card); + sca_out(DMER_DME, DMER, card); /* DMA Master enable */ +} diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c index d3d5055741ad3f181b4fb79bc9cb0099ca5691a1..f1ddd7c3459cdfeeccc1884de43e80e0fb189a9c 100644 --- a/drivers/net/wan/hdlc_fr.c +++ b/drivers/net/wan/hdlc_fr.c @@ -342,7 +342,7 @@ static int fr_hard_header(struct sk_buff **skb_p, u16 dlci) static int pvc_open(struct net_device *dev) { - pvc_device *pvc = dev->priv; + pvc_device *pvc = dev->ml_priv; if ((pvc->frad->flags & IFF_UP) == 0) return -EIO; /* Frad must be UP in order to activate PVC */ @@ -362,7 +362,7 @@ static int pvc_open(struct net_device *dev) static int pvc_close(struct net_device *dev) { - pvc_device *pvc = dev->priv; + pvc_device *pvc = dev->ml_priv; if (--pvc->open_count == 0) { hdlc_device *hdlc = dev_to_hdlc(pvc->frad); @@ -381,7 +381,7 @@ static int pvc_close(struct net_device *dev) static int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - pvc_device *pvc = dev->priv; + pvc_device *pvc = dev->ml_priv; fr_proto_pvc_info info; if (ifr->ifr_settings.type == IF_GET_PROTO) { @@ -409,7 +409,7 @@ static int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) static int pvc_xmit(struct sk_buff *skb, struct net_device *dev) { - pvc_device *pvc = dev->priv; + pvc_device *pvc = dev->ml_priv; if (pvc->state.active) { if (dev->type == ARPHRD_ETHER) { @@ -1111,7 +1111,7 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type) dev->change_mtu = pvc_change_mtu; dev->mtu = HDLC_MAX_MTU; dev->tx_queue_len = 0; - dev->priv = pvc; + dev->ml_priv = pvc; result = dev_alloc_name(dev, dev->name); if (result < 0) { diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c index 4efe9e6d32d5fb5b37b7397a77d4898e3e7db4f4..57fe714c1c7f63376e1694fc84d2f73788e50c2a 100644 --- a/drivers/net/wan/hdlc_ppp.c +++ b/drivers/net/wan/hdlc_ppp.c @@ -2,7 +2,7 @@ * Generic HDLC support routines for Linux * Point-to-point protocol support * - * Copyright (C) 1999 - 2006 Krzysztof Halasa + * Copyright (C) 1999 - 2008 Krzysztof Halasa * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -18,87 +18,633 @@ #include #include #include -#include #include #include -#include +#include + +#define DEBUG_CP 0 /* also bytes# to dump */ +#define DEBUG_STATE 0 +#define DEBUG_HARD_HEADER 0 + +#define HDLC_ADDR_ALLSTATIONS 0xFF +#define HDLC_CTRL_UI 0x03 + +#define PID_LCP 0xC021 +#define PID_IP 0x0021 +#define PID_IPCP 0x8021 +#define PID_IPV6 0x0057 +#define PID_IPV6CP 0x8057 + +enum {IDX_LCP = 0, IDX_IPCP, IDX_IPV6CP, IDX_COUNT}; +enum {CP_CONF_REQ = 1, CP_CONF_ACK, CP_CONF_NAK, CP_CONF_REJ, CP_TERM_REQ, + CP_TERM_ACK, CP_CODE_REJ, LCP_PROTO_REJ, LCP_ECHO_REQ, LCP_ECHO_REPLY, + LCP_DISC_REQ, CP_CODES}; +#if DEBUG_CP +static const char *const code_names[CP_CODES] = { + "0", "ConfReq", "ConfAck", "ConfNak", "ConfRej", "TermReq", + "TermAck", "CodeRej", "ProtoRej", "EchoReq", "EchoReply", "Discard" +}; +static char debug_buffer[64 + 3 * DEBUG_CP]; +#endif + +enum {LCP_OPTION_MRU = 1, LCP_OPTION_ACCM, LCP_OPTION_MAGIC = 5}; + +struct hdlc_header { + u8 address; + u8 control; + __be16 protocol; +}; + +struct cp_header { + u8 code; + u8 id; + __be16 len; +}; + -struct ppp_state { - struct ppp_device pppdev; - struct ppp_device *syncppp_ptr; - int (*old_change_mtu)(struct net_device *dev, int new_mtu); +struct proto { + struct net_device *dev; + struct timer_list timer; + unsigned long timeout; + u16 pid; /* protocol ID */ + u8 state; + u8 cr_id; /* ID of last Configuration-Request */ + u8 restart_counter; }; +struct ppp { + struct proto protos[IDX_COUNT]; + spinlock_t lock; + unsigned long last_pong; + unsigned int req_timeout, cr_retries, term_retries; + unsigned int keepalive_interval, keepalive_timeout; + u8 seq; /* local sequence number for requests */ + u8 echo_id; /* ID of last Echo-Request (LCP) */ +}; + +enum {CLOSED = 0, STOPPED, STOPPING, REQ_SENT, ACK_RECV, ACK_SENT, OPENED, + STATES, STATE_MASK = 0xF}; +enum {START = 0, STOP, TO_GOOD, TO_BAD, RCR_GOOD, RCR_BAD, RCA, RCN, RTR, RTA, + RUC, RXJ_GOOD, RXJ_BAD, EVENTS}; +enum {INV = 0x10, IRC = 0x20, ZRC = 0x40, SCR = 0x80, SCA = 0x100, + SCN = 0x200, STR = 0x400, STA = 0x800, SCJ = 0x1000}; + +#if DEBUG_STATE +static const char *const state_names[STATES] = { + "Closed", "Stopped", "Stopping", "ReqSent", "AckRecv", "AckSent", + "Opened" +}; +static const char *const event_names[EVENTS] = { + "Start", "Stop", "TO+", "TO-", "RCR+", "RCR-", "RCA", "RCN", + "RTR", "RTA", "RUC", "RXJ+", "RXJ-" +}; +#endif + +static struct sk_buff_head tx_queue; /* used when holding the spin lock */ + static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr); +static inline struct ppp* get_ppp(struct net_device *dev) +{ + return (struct ppp *)dev_to_hdlc(dev)->state; +} -static inline struct ppp_state* state(hdlc_device *hdlc) +static inline struct proto* get_proto(struct net_device *dev, u16 pid) { - return(struct ppp_state *)(hdlc->state); + struct ppp *ppp = get_ppp(dev); + + switch (pid) { + case PID_LCP: + return &ppp->protos[IDX_LCP]; + case PID_IPCP: + return &ppp->protos[IDX_IPCP]; + case PID_IPV6CP: + return &ppp->protos[IDX_IPV6CP]; + default: + return NULL; + } } +static inline const char* proto_name(u16 pid) +{ + switch (pid) { + case PID_LCP: + return "LCP"; + case PID_IPCP: + return "IPCP"; + case PID_IPV6CP: + return "IPV6CP"; + default: + return NULL; + } +} -static int ppp_open(struct net_device *dev) +static __be16 ppp_type_trans(struct sk_buff *skb, struct net_device *dev) { - hdlc_device *hdlc = dev_to_hdlc(dev); - int (*old_ioctl)(struct net_device *, struct ifreq *, int); - int result; + struct hdlc_header *data = (struct hdlc_header*)skb->data; + + if (skb->len < sizeof(struct hdlc_header)) + return htons(ETH_P_HDLC); + if (data->address != HDLC_ADDR_ALLSTATIONS || + data->control != HDLC_CTRL_UI) + return htons(ETH_P_HDLC); + + switch (data->protocol) { + case __constant_htons(PID_IP): + skb_pull(skb, sizeof(struct hdlc_header)); + return htons(ETH_P_IP); - dev->ml_priv = &state(hdlc)->syncppp_ptr; - state(hdlc)->syncppp_ptr = &state(hdlc)->pppdev; - state(hdlc)->pppdev.dev = dev; + case __constant_htons(PID_IPV6): + skb_pull(skb, sizeof(struct hdlc_header)); + return htons(ETH_P_IPV6); - old_ioctl = dev->do_ioctl; - state(hdlc)->old_change_mtu = dev->change_mtu; - sppp_attach(&state(hdlc)->pppdev); - /* sppp_attach nukes them. We don't need syncppp's ioctl */ - dev->do_ioctl = old_ioctl; - state(hdlc)->pppdev.sppp.pp_flags &= ~PP_CISCO; - dev->type = ARPHRD_PPP; - result = sppp_open(dev); - if (result) { - sppp_detach(dev); - return result; + default: + return htons(ETH_P_HDLC); } +} - return 0; + +static int ppp_hard_header(struct sk_buff *skb, struct net_device *dev, + u16 type, const void *daddr, const void *saddr, + unsigned int len) +{ + struct hdlc_header *data; +#if DEBUG_HARD_HEADER + printk(KERN_DEBUG "%s: ppp_hard_header() called\n", dev->name); +#endif + + skb_push(skb, sizeof(struct hdlc_header)); + data = (struct hdlc_header*)skb->data; + + data->address = HDLC_ADDR_ALLSTATIONS; + data->control = HDLC_CTRL_UI; + switch (type) { + case ETH_P_IP: + data->protocol = htons(PID_IP); + break; + case ETH_P_IPV6: + data->protocol = htons(PID_IPV6); + break; + case PID_LCP: + case PID_IPCP: + case PID_IPV6CP: + data->protocol = htons(type); + break; + default: /* unknown protocol */ + data->protocol = 0; + } + return sizeof(struct hdlc_header); } +static void ppp_tx_flush(void) +{ + struct sk_buff *skb; + while ((skb = skb_dequeue(&tx_queue)) != NULL) + dev_queue_xmit(skb); +} -static void ppp_close(struct net_device *dev) +static void ppp_tx_cp(struct net_device *dev, u16 pid, u8 code, + u8 id, unsigned int len, const void *data) { - hdlc_device *hdlc = dev_to_hdlc(dev); + struct sk_buff *skb; + struct cp_header *cp; + unsigned int magic_len = 0; + static u32 magic; + +#if DEBUG_CP + int i; + char *ptr; +#endif + + if (pid == PID_LCP && (code == LCP_ECHO_REQ || code == LCP_ECHO_REPLY)) + magic_len = sizeof(magic); + + skb = dev_alloc_skb(sizeof(struct hdlc_header) + + sizeof(struct cp_header) + magic_len + len); + if (!skb) { + printk(KERN_WARNING "%s: out of memory in ppp_tx_cp()\n", + dev->name); + return; + } + skb_reserve(skb, sizeof(struct hdlc_header)); + + cp = (struct cp_header *)skb_put(skb, sizeof(struct cp_header)); + cp->code = code; + cp->id = id; + cp->len = htons(sizeof(struct cp_header) + magic_len + len); + + if (magic_len) + memcpy(skb_put(skb, magic_len), &magic, magic_len); + if (len) + memcpy(skb_put(skb, len), data, len); + +#if DEBUG_CP + BUG_ON(code >= CP_CODES); + ptr = debug_buffer; + *ptr = '\x0'; + for (i = 0; i < min_t(unsigned int, magic_len + len, DEBUG_CP); i++) { + sprintf(ptr, " %02X", skb->data[sizeof(struct cp_header) + i]); + ptr += strlen(ptr); + } + printk(KERN_DEBUG "%s: TX %s [%s id 0x%X]%s\n", dev->name, + proto_name(pid), code_names[code], id, debug_buffer); +#endif - sppp_close(dev); - sppp_detach(dev); + ppp_hard_header(skb, dev, pid, NULL, NULL, 0); - dev->change_mtu = state(hdlc)->old_change_mtu; - dev->mtu = HDLC_MAX_MTU; - dev->hard_header_len = 16; + skb->priority = TC_PRIO_CONTROL; + skb->dev = dev; + skb_reset_network_header(skb); + skb_queue_tail(&tx_queue, skb); } +/* State transition table (compare STD-51) + Events Actions + TO+ = Timeout with counter > 0 irc = Initialize-Restart-Count + TO- = Timeout with counter expired zrc = Zero-Restart-Count + + RCR+ = Receive-Configure-Request (Good) scr = Send-Configure-Request + RCR- = Receive-Configure-Request (Bad) + RCA = Receive-Configure-Ack sca = Send-Configure-Ack + RCN = Receive-Configure-Nak/Rej scn = Send-Configure-Nak/Rej + + RTR = Receive-Terminate-Request str = Send-Terminate-Request + RTA = Receive-Terminate-Ack sta = Send-Terminate-Ack + + RUC = Receive-Unknown-Code scj = Send-Code-Reject + RXJ+ = Receive-Code-Reject (permitted) + or Receive-Protocol-Reject + RXJ- = Receive-Code-Reject (catastrophic) + or Receive-Protocol-Reject +*/ +static int cp_table[EVENTS][STATES] = { + /* CLOSED STOPPED STOPPING REQ_SENT ACK_RECV ACK_SENT OPENED + 0 1 2 3 4 5 6 */ + {IRC|SCR|3, INV , INV , INV , INV , INV , INV }, /* START */ + { INV , 0 , 0 , 0 , 0 , 0 , 0 }, /* STOP */ + { INV , INV ,STR|2, SCR|3 ,SCR|3, SCR|5 , INV }, /* TO+ */ + { INV , INV , 1 , 1 , 1 , 1 , INV }, /* TO- */ + { STA|0 ,IRC|SCR|SCA|5, 2 , SCA|5 ,SCA|6, SCA|5 ,SCR|SCA|5}, /* RCR+ */ + { STA|0 ,IRC|SCR|SCN|3, 2 , SCN|3 ,SCN|4, SCN|3 ,SCR|SCN|3}, /* RCR- */ + { STA|0 , STA|1 , 2 , IRC|4 ,SCR|3, 6 , SCR|3 }, /* RCA */ + { STA|0 , STA|1 , 2 ,IRC|SCR|3,SCR|3,IRC|SCR|5, SCR|3 }, /* RCN */ + { STA|0 , STA|1 ,STA|2, STA|3 ,STA|3, STA|3 ,ZRC|STA|2}, /* RTR */ + { 0 , 1 , 1 , 3 , 3 , 5 , SCR|3 }, /* RTA */ + { SCJ|0 , SCJ|1 ,SCJ|2, SCJ|3 ,SCJ|4, SCJ|5 , SCJ|6 }, /* RUC */ + { 0 , 1 , 2 , 3 , 3 , 5 , 6 }, /* RXJ+ */ + { 0 , 1 , 1 , 1 , 1 , 1 ,IRC|STR|2}, /* RXJ- */ +}; + -static __be16 ppp_type_trans(struct sk_buff *skb, struct net_device *dev) +/* SCA: RCR+ must supply id, len and data + SCN: RCR- must supply code, id, len and data + STA: RTR must supply id + SCJ: RUC must supply CP packet len and data */ +static void ppp_cp_event(struct net_device *dev, u16 pid, u16 event, u8 code, + u8 id, unsigned int len, const void *data) { - return __constant_htons(ETH_P_WAN_PPP); + int old_state, action; + struct ppp *ppp = get_ppp(dev); + struct proto *proto = get_proto(dev, pid); + + old_state = proto->state; + BUG_ON(old_state >= STATES); + BUG_ON(event >= EVENTS); + +#if DEBUG_STATE + printk(KERN_DEBUG "%s: %s ppp_cp_event(%s) %s ...\n", dev->name, + proto_name(pid), event_names[event], state_names[proto->state]); +#endif + + action = cp_table[event][old_state]; + + proto->state = action & STATE_MASK; + if (action & (SCR | STR)) /* set Configure-Req/Terminate-Req timer */ + mod_timer(&proto->timer, proto->timeout = + jiffies + ppp->req_timeout * HZ); + if (action & ZRC) + proto->restart_counter = 0; + if (action & IRC) + proto->restart_counter = (proto->state == STOPPING) ? + ppp->term_retries : ppp->cr_retries; + + if (action & SCR) /* send Configure-Request */ + ppp_tx_cp(dev, pid, CP_CONF_REQ, proto->cr_id = ++ppp->seq, + 0, NULL); + if (action & SCA) /* send Configure-Ack */ + ppp_tx_cp(dev, pid, CP_CONF_ACK, id, len, data); + if (action & SCN) /* send Configure-Nak/Reject */ + ppp_tx_cp(dev, pid, code, id, len, data); + if (action & STR) /* send Terminate-Request */ + ppp_tx_cp(dev, pid, CP_TERM_REQ, ++ppp->seq, 0, NULL); + if (action & STA) /* send Terminate-Ack */ + ppp_tx_cp(dev, pid, CP_TERM_ACK, id, 0, NULL); + if (action & SCJ) /* send Code-Reject */ + ppp_tx_cp(dev, pid, CP_CODE_REJ, ++ppp->seq, len, data); + + if (old_state != OPENED && proto->state == OPENED) { + printk(KERN_INFO "%s: %s up\n", dev->name, proto_name(pid)); + if (pid == PID_LCP) { + netif_dormant_off(dev); + ppp_cp_event(dev, PID_IPCP, START, 0, 0, 0, NULL); + ppp_cp_event(dev, PID_IPV6CP, START, 0, 0, 0, NULL); + ppp->last_pong = jiffies; + mod_timer(&proto->timer, proto->timeout = + jiffies + ppp->keepalive_interval * HZ); + } + } + if (old_state == OPENED && proto->state != OPENED) { + printk(KERN_INFO "%s: %s down\n", dev->name, proto_name(pid)); + if (pid == PID_LCP) { + netif_dormant_on(dev); + ppp_cp_event(dev, PID_IPCP, STOP, 0, 0, 0, NULL); + ppp_cp_event(dev, PID_IPV6CP, STOP, 0, 0, 0, NULL); + } + } + if (old_state != CLOSED && proto->state == CLOSED) + del_timer(&proto->timer); + +#if DEBUG_STATE + printk(KERN_DEBUG "%s: %s ppp_cp_event(%s) ... %s\n", dev->name, + proto_name(pid), event_names[event], state_names[proto->state]); +#endif +} + + +static void ppp_cp_parse_cr(struct net_device *dev, u16 pid, u8 id, + unsigned int req_len, const u8 *data) +{ + static u8 const valid_accm[6] = { LCP_OPTION_ACCM, 6, 0, 0, 0, 0 }; + const u8 *opt; + u8 *out; + unsigned int len = req_len, nak_len = 0, rej_len = 0; + + if (!(out = kmalloc(len, GFP_ATOMIC))) { + dev->stats.rx_dropped++; + return; /* out of memory, ignore CR packet */ + } + + for (opt = data; len; len -= opt[1], opt += opt[1]) { + if (len < 2 || len < opt[1]) { + dev->stats.rx_errors++; + return; /* bad packet, drop silently */ + } + + if (pid == PID_LCP) + switch (opt[0]) { + case LCP_OPTION_MRU: + continue; /* MRU always OK and > 1500 bytes? */ + + case LCP_OPTION_ACCM: /* async control character map */ + if (!memcmp(opt, valid_accm, + sizeof(valid_accm))) + continue; + if (!rej_len) { /* NAK it */ + memcpy(out + nak_len, valid_accm, + sizeof(valid_accm)); + nak_len += sizeof(valid_accm); + continue; + } + break; + case LCP_OPTION_MAGIC: + if (opt[1] != 6 || (!opt[2] && !opt[3] && + !opt[4] && !opt[5])) + break; /* reject invalid magic number */ + continue; + } + /* reject this option */ + memcpy(out + rej_len, opt, opt[1]); + rej_len += opt[1]; + } + + if (rej_len) + ppp_cp_event(dev, pid, RCR_BAD, CP_CONF_REJ, id, rej_len, out); + else if (nak_len) + ppp_cp_event(dev, pid, RCR_BAD, CP_CONF_NAK, id, nak_len, out); + else + ppp_cp_event(dev, pid, RCR_GOOD, CP_CONF_ACK, id, req_len, data); + + kfree(out); +} + +static int ppp_rx(struct sk_buff *skb) +{ + struct hdlc_header *hdr = (struct hdlc_header*)skb->data; + struct net_device *dev = skb->dev; + struct ppp *ppp = get_ppp(dev); + struct proto *proto; + struct cp_header *cp; + unsigned long flags; + unsigned int len; + u16 pid; +#if DEBUG_CP + int i; + char *ptr; +#endif + + spin_lock_irqsave(&ppp->lock, flags); + /* Check HDLC header */ + if (skb->len < sizeof(struct hdlc_header)) + goto rx_error; + cp = (struct cp_header*)skb_pull(skb, sizeof(struct hdlc_header)); + if (hdr->address != HDLC_ADDR_ALLSTATIONS || + hdr->control != HDLC_CTRL_UI) + goto rx_error; + + pid = ntohs(hdr->protocol); + proto = get_proto(dev, pid); + if (!proto) { + if (ppp->protos[IDX_LCP].state == OPENED) + ppp_tx_cp(dev, PID_LCP, LCP_PROTO_REJ, + ++ppp->seq, skb->len + 2, &hdr->protocol); + goto rx_error; + } + + len = ntohs(cp->len); + if (len < sizeof(struct cp_header) /* no complete CP header? */ || + skb->len < len /* truncated packet? */) + goto rx_error; + skb_pull(skb, sizeof(struct cp_header)); + len -= sizeof(struct cp_header); + + /* HDLC and CP headers stripped from skb */ +#if DEBUG_CP + if (cp->code < CP_CODES) + sprintf(debug_buffer, "[%s id 0x%X]", code_names[cp->code], + cp->id); + else + sprintf(debug_buffer, "[code %u id 0x%X]", cp->code, cp->id); + ptr = debug_buffer + strlen(debug_buffer); + for (i = 0; i < min_t(unsigned int, len, DEBUG_CP); i++) { + sprintf(ptr, " %02X", skb->data[i]); + ptr += strlen(ptr); + } + printk(KERN_DEBUG "%s: RX %s %s\n", dev->name, proto_name(pid), + debug_buffer); +#endif + + /* LCP only */ + if (pid == PID_LCP) + switch (cp->code) { + case LCP_PROTO_REJ: + pid = ntohs(*(__be16*)skb->data); + if (pid == PID_LCP || pid == PID_IPCP || + pid == PID_IPV6CP) + ppp_cp_event(dev, pid, RXJ_BAD, 0, 0, + 0, NULL); + goto out; + + case LCP_ECHO_REQ: /* send Echo-Reply */ + if (len >= 4 && proto->state == OPENED) + ppp_tx_cp(dev, PID_LCP, LCP_ECHO_REPLY, + cp->id, len - 4, skb->data + 4); + goto out; + + case LCP_ECHO_REPLY: + if (cp->id == ppp->echo_id) + ppp->last_pong = jiffies; + goto out; + + case LCP_DISC_REQ: /* discard */ + goto out; + } + + /* LCP, IPCP and IPV6CP */ + switch (cp->code) { + case CP_CONF_REQ: + ppp_cp_parse_cr(dev, pid, cp->id, len, skb->data); + goto out; + + case CP_CONF_ACK: + if (cp->id == proto->cr_id) + ppp_cp_event(dev, pid, RCA, 0, 0, 0, NULL); + goto out; + + case CP_CONF_REJ: + case CP_CONF_NAK: + if (cp->id == proto->cr_id) + ppp_cp_event(dev, pid, RCN, 0, 0, 0, NULL); + goto out; + + case CP_TERM_REQ: + ppp_cp_event(dev, pid, RTR, 0, cp->id, 0, NULL); + goto out; + + case CP_TERM_ACK: + ppp_cp_event(dev, pid, RTA, 0, 0, 0, NULL); + goto out; + + case CP_CODE_REJ: + ppp_cp_event(dev, pid, RXJ_BAD, 0, 0, 0, NULL); + goto out; + + default: + len += sizeof(struct cp_header); + if (len > dev->mtu) + len = dev->mtu; + ppp_cp_event(dev, pid, RUC, 0, 0, len, cp); + goto out; + } + goto out; + +rx_error: + dev->stats.rx_errors++; +out: + spin_unlock_irqrestore(&ppp->lock, flags); + dev_kfree_skb_any(skb); + ppp_tx_flush(); + return NET_RX_DROP; } +static void ppp_timer(unsigned long arg) +{ + struct proto *proto = (struct proto *)arg; + struct ppp *ppp = get_ppp(proto->dev); + unsigned long flags; + + spin_lock_irqsave(&ppp->lock, flags); + switch (proto->state) { + case STOPPING: + case REQ_SENT: + case ACK_RECV: + case ACK_SENT: + if (proto->restart_counter) { + ppp_cp_event(proto->dev, proto->pid, TO_GOOD, 0, 0, + 0, NULL); + proto->restart_counter--; + } else + ppp_cp_event(proto->dev, proto->pid, TO_BAD, 0, 0, + 0, NULL); + break; + + case OPENED: + if (proto->pid != PID_LCP) + break; + if (time_after(jiffies, ppp->last_pong + + ppp->keepalive_timeout * HZ)) { + printk(KERN_INFO "%s: Link down\n", proto->dev->name); + ppp_cp_event(proto->dev, PID_LCP, STOP, 0, 0, 0, NULL); + ppp_cp_event(proto->dev, PID_LCP, START, 0, 0, 0, NULL); + } else { /* send keep-alive packet */ + ppp->echo_id = ++ppp->seq; + ppp_tx_cp(proto->dev, PID_LCP, LCP_ECHO_REQ, + ppp->echo_id, 0, NULL); + proto->timer.expires = jiffies + + ppp->keepalive_interval * HZ; + add_timer(&proto->timer); + } + break; + } + spin_unlock_irqrestore(&ppp->lock, flags); + ppp_tx_flush(); +} + + +static void ppp_start(struct net_device *dev) +{ + struct ppp *ppp = get_ppp(dev); + int i; + + for (i = 0; i < IDX_COUNT; i++) { + struct proto *proto = &ppp->protos[i]; + proto->dev = dev; + init_timer(&proto->timer); + proto->timer.function = ppp_timer; + proto->timer.data = (unsigned long)proto; + proto->state = CLOSED; + } + ppp->protos[IDX_LCP].pid = PID_LCP; + ppp->protos[IDX_IPCP].pid = PID_IPCP; + ppp->protos[IDX_IPV6CP].pid = PID_IPV6CP; + + ppp_cp_event(dev, PID_LCP, START, 0, 0, 0, NULL); +} + +static void ppp_stop(struct net_device *dev) +{ + ppp_cp_event(dev, PID_LCP, STOP, 0, 0, 0, NULL); +} static struct hdlc_proto proto = { - .open = ppp_open, - .close = ppp_close, + .start = ppp_start, + .stop = ppp_stop, .type_trans = ppp_type_trans, .ioctl = ppp_ioctl, + .netif_rx = ppp_rx, .module = THIS_MODULE, }; +static const struct header_ops ppp_header_ops = { + .create = ppp_hard_header, +}; static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr) { hdlc_device *hdlc = dev_to_hdlc(dev); + struct ppp *ppp; int result; switch (ifr->ifr_settings.type) { @@ -109,25 +655,35 @@ static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr) return 0; /* return protocol only, no settable parameters */ case IF_PROTO_PPP: - if(!capable(CAP_NET_ADMIN)) + if (!capable(CAP_NET_ADMIN)) return -EPERM; - if(dev->flags & IFF_UP) + if (dev->flags & IFF_UP) return -EBUSY; /* no settable parameters */ - result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT); + result = hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT); if (result) return result; - result = attach_hdlc_protocol(dev, &proto, - sizeof(struct ppp_state)); + result = attach_hdlc_protocol(dev, &proto, sizeof(struct ppp)); if (result) return result; + + ppp = get_ppp(dev); + spin_lock_init(&ppp->lock); + ppp->req_timeout = 2; + ppp->cr_retries = 10; + ppp->term_retries = 2; + ppp->keepalive_interval = 10; + ppp->keepalive_timeout = 60; + dev->hard_start_xmit = hdlc->xmit; + dev->hard_header_len = sizeof(struct hdlc_header); + dev->header_ops = &ppp_header_ops; dev->type = ARPHRD_PPP; - netif_dormant_off(dev); + netif_dormant_on(dev); return 0; } @@ -137,12 +693,11 @@ static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr) static int __init mod_init(void) { + skb_queue_head_init(&tx_queue); register_hdlc_protocol(&proto); return 0; } - - static void __exit mod_exit(void) { unregister_hdlc_protocol(&proto); diff --git a/drivers/net/wan/hostess_sv11.c b/drivers/net/wan/hostess_sv11.c index e299313f828a74e20aee499e39739d1c79eef0fd..af54f0cf1b35fcc2d6f0130411df5432d5b55cc2 100644 --- a/drivers/net/wan/hostess_sv11.c +++ b/drivers/net/wan/hostess_sv11.c @@ -66,7 +66,6 @@ static void hostess_input(struct z8530_channel *c, struct sk_buff *skb) * it right now. */ netif_rx(skb); - c->netdevice->last_rx = jiffies; } /* diff --git a/drivers/net/wan/ixp4xx_hss.c b/drivers/net/wan/ixp4xx_hss.c new file mode 100644 index 0000000000000000000000000000000000000000..0c6802507a79817840e36194a0ec49b0993adb73 --- /dev/null +++ b/drivers/net/wan/ixp4xx_hss.c @@ -0,0 +1,1325 @@ +/* + * Intel IXP4xx HSS (synchronous serial port) driver for Linux + * + * Copyright (C) 2007-2008 Krzysztof HaÅ‚asa + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG_DESC 0 +#define DEBUG_RX 0 +#define DEBUG_TX 0 +#define DEBUG_PKT_BYTES 0 +#define DEBUG_CLOSE 0 + +#define DRV_NAME "ixp4xx_hss" + +#define PKT_EXTRA_FLAGS 0 /* orig 1 */ +#define PKT_NUM_PIPES 1 /* 1, 2 or 4 */ +#define PKT_PIPE_FIFO_SIZEW 4 /* total 4 dwords per HSS */ + +#define RX_DESCS 16 /* also length of all RX queues */ +#define TX_DESCS 16 /* also length of all TX queues */ + +#define POOL_ALLOC_SIZE (sizeof(struct desc) * (RX_DESCS + TX_DESCS)) +#define RX_SIZE (HDLC_MAX_MRU + 4) /* NPE needs more space */ +#define MAX_CLOSE_WAIT 1000 /* microseconds */ +#define HSS_COUNT 2 +#define FRAME_SIZE 256 /* doesn't matter at this point */ +#define FRAME_OFFSET 0 +#define MAX_CHANNELS (FRAME_SIZE / 8) + +#define NAPI_WEIGHT 16 + +/* Queue IDs */ +#define HSS0_CHL_RXTRIG_QUEUE 12 /* orig size = 32 dwords */ +#define HSS0_PKT_RX_QUEUE 13 /* orig size = 32 dwords */ +#define HSS0_PKT_TX0_QUEUE 14 /* orig size = 16 dwords */ +#define HSS0_PKT_TX1_QUEUE 15 +#define HSS0_PKT_TX2_QUEUE 16 +#define HSS0_PKT_TX3_QUEUE 17 +#define HSS0_PKT_RXFREE0_QUEUE 18 /* orig size = 16 dwords */ +#define HSS0_PKT_RXFREE1_QUEUE 19 +#define HSS0_PKT_RXFREE2_QUEUE 20 +#define HSS0_PKT_RXFREE3_QUEUE 21 +#define HSS0_PKT_TXDONE_QUEUE 22 /* orig size = 64 dwords */ + +#define HSS1_CHL_RXTRIG_QUEUE 10 +#define HSS1_PKT_RX_QUEUE 0 +#define HSS1_PKT_TX0_QUEUE 5 +#define HSS1_PKT_TX1_QUEUE 6 +#define HSS1_PKT_TX2_QUEUE 7 +#define HSS1_PKT_TX3_QUEUE 8 +#define HSS1_PKT_RXFREE0_QUEUE 1 +#define HSS1_PKT_RXFREE1_QUEUE 2 +#define HSS1_PKT_RXFREE2_QUEUE 3 +#define HSS1_PKT_RXFREE3_QUEUE 4 +#define HSS1_PKT_TXDONE_QUEUE 9 + +#define NPE_PKT_MODE_HDLC 0 +#define NPE_PKT_MODE_RAW 1 +#define NPE_PKT_MODE_56KMODE 2 +#define NPE_PKT_MODE_56KENDIAN_MSB 4 + +/* PKT_PIPE_HDLC_CFG_WRITE flags */ +#define PKT_HDLC_IDLE_ONES 0x1 /* default = flags */ +#define PKT_HDLC_CRC_32 0x2 /* default = CRC-16 */ +#define PKT_HDLC_MSB_ENDIAN 0x4 /* default = LE */ + + +/* hss_config, PCRs */ +/* Frame sync sampling, default = active low */ +#define PCR_FRM_SYNC_ACTIVE_HIGH 0x40000000 +#define PCR_FRM_SYNC_FALLINGEDGE 0x80000000 +#define PCR_FRM_SYNC_RISINGEDGE 0xC0000000 + +/* Frame sync pin: input (default) or output generated off a given clk edge */ +#define PCR_FRM_SYNC_OUTPUT_FALLING 0x20000000 +#define PCR_FRM_SYNC_OUTPUT_RISING 0x30000000 + +/* Frame and data clock sampling on edge, default = falling */ +#define PCR_FCLK_EDGE_RISING 0x08000000 +#define PCR_DCLK_EDGE_RISING 0x04000000 + +/* Clock direction, default = input */ +#define PCR_SYNC_CLK_DIR_OUTPUT 0x02000000 + +/* Generate/Receive frame pulses, default = enabled */ +#define PCR_FRM_PULSE_DISABLED 0x01000000 + + /* Data rate is full (default) or half the configured clk speed */ +#define PCR_HALF_CLK_RATE 0x00200000 + +/* Invert data between NPE and HSS FIFOs? (default = no) */ +#define PCR_DATA_POLARITY_INVERT 0x00100000 + +/* TX/RX endianness, default = LSB */ +#define PCR_MSB_ENDIAN 0x00080000 + +/* Normal (default) / open drain mode (TX only) */ +#define PCR_TX_PINS_OPEN_DRAIN 0x00040000 + +/* No framing bit transmitted and expected on RX? (default = framing bit) */ +#define PCR_SOF_NO_FBIT 0x00020000 + +/* Drive data pins? */ +#define PCR_TX_DATA_ENABLE 0x00010000 + +/* Voice 56k type: drive the data pins low (default), high, high Z */ +#define PCR_TX_V56K_HIGH 0x00002000 +#define PCR_TX_V56K_HIGH_IMP 0x00004000 + +/* Unassigned type: drive the data pins low (default), high, high Z */ +#define PCR_TX_UNASS_HIGH 0x00000800 +#define PCR_TX_UNASS_HIGH_IMP 0x00001000 + +/* T1 @ 1.544MHz only: Fbit dictated in FIFO (default) or high Z */ +#define PCR_TX_FB_HIGH_IMP 0x00000400 + +/* 56k data endiannes - which bit unused: high (default) or low */ +#define PCR_TX_56KE_BIT_0_UNUSED 0x00000200 + +/* 56k data transmission type: 32/8 bit data (default) or 56K data */ +#define PCR_TX_56KS_56K_DATA 0x00000100 + +/* hss_config, cCR */ +/* Number of packetized clients, default = 1 */ +#define CCR_NPE_HFIFO_2_HDLC 0x04000000 +#define CCR_NPE_HFIFO_3_OR_4HDLC 0x08000000 + +/* default = no loopback */ +#define CCR_LOOPBACK 0x02000000 + +/* HSS number, default = 0 (first) */ +#define CCR_SECOND_HSS 0x01000000 + + +/* hss_config, clkCR: main:10, num:10, denom:12 */ +#define CLK42X_SPEED_EXP ((0x3FF << 22) | ( 2 << 12) | 15) /*65 KHz*/ + +#define CLK42X_SPEED_512KHZ (( 130 << 22) | ( 2 << 12) | 15) +#define CLK42X_SPEED_1536KHZ (( 43 << 22) | ( 18 << 12) | 47) +#define CLK42X_SPEED_1544KHZ (( 43 << 22) | ( 33 << 12) | 192) +#define CLK42X_SPEED_2048KHZ (( 32 << 22) | ( 34 << 12) | 63) +#define CLK42X_SPEED_4096KHZ (( 16 << 22) | ( 34 << 12) | 127) +#define CLK42X_SPEED_8192KHZ (( 8 << 22) | ( 34 << 12) | 255) + +#define CLK46X_SPEED_512KHZ (( 130 << 22) | ( 24 << 12) | 127) +#define CLK46X_SPEED_1536KHZ (( 43 << 22) | (152 << 12) | 383) +#define CLK46X_SPEED_1544KHZ (( 43 << 22) | ( 66 << 12) | 385) +#define CLK46X_SPEED_2048KHZ (( 32 << 22) | (280 << 12) | 511) +#define CLK46X_SPEED_4096KHZ (( 16 << 22) | (280 << 12) | 1023) +#define CLK46X_SPEED_8192KHZ (( 8 << 22) | (280 << 12) | 2047) + + +/* hss_config, LUT entries */ +#define TDMMAP_UNASSIGNED 0 +#define TDMMAP_HDLC 1 /* HDLC - packetized */ +#define TDMMAP_VOICE56K 2 /* Voice56K - 7-bit channelized */ +#define TDMMAP_VOICE64K 3 /* Voice64K - 8-bit channelized */ + +/* offsets into HSS config */ +#define HSS_CONFIG_TX_PCR 0x00 /* port configuration registers */ +#define HSS_CONFIG_RX_PCR 0x04 +#define HSS_CONFIG_CORE_CR 0x08 /* loopback control, HSS# */ +#define HSS_CONFIG_CLOCK_CR 0x0C /* clock generator control */ +#define HSS_CONFIG_TX_FCR 0x10 /* frame configuration registers */ +#define HSS_CONFIG_RX_FCR 0x14 +#define HSS_CONFIG_TX_LUT 0x18 /* channel look-up tables */ +#define HSS_CONFIG_RX_LUT 0x38 + + +/* NPE command codes */ +/* writes the ConfigWord value to the location specified by offset */ +#define PORT_CONFIG_WRITE 0x40 + +/* triggers the NPE to load the contents of the configuration table */ +#define PORT_CONFIG_LOAD 0x41 + +/* triggers the NPE to return an HssErrorReadResponse message */ +#define PORT_ERROR_READ 0x42 + +/* triggers the NPE to reset internal status and enable the HssPacketized + operation for the flow specified by pPipe */ +#define PKT_PIPE_FLOW_ENABLE 0x50 +#define PKT_PIPE_FLOW_DISABLE 0x51 +#define PKT_NUM_PIPES_WRITE 0x52 +#define PKT_PIPE_FIFO_SIZEW_WRITE 0x53 +#define PKT_PIPE_HDLC_CFG_WRITE 0x54 +#define PKT_PIPE_IDLE_PATTERN_WRITE 0x55 +#define PKT_PIPE_RX_SIZE_WRITE 0x56 +#define PKT_PIPE_MODE_WRITE 0x57 + +/* HDLC packet status values - desc->status */ +#define ERR_SHUTDOWN 1 /* stop or shutdown occurrance */ +#define ERR_HDLC_ALIGN 2 /* HDLC alignment error */ +#define ERR_HDLC_FCS 3 /* HDLC Frame Check Sum error */ +#define ERR_RXFREE_Q_EMPTY 4 /* RX-free queue became empty while receiving + this packet (if buf_len < pkt_len) */ +#define ERR_HDLC_TOO_LONG 5 /* HDLC frame size too long */ +#define ERR_HDLC_ABORT 6 /* abort sequence received */ +#define ERR_DISCONNECTING 7 /* disconnect is in progress */ + + +#ifdef __ARMEB__ +typedef struct sk_buff buffer_t; +#define free_buffer dev_kfree_skb +#define free_buffer_irq dev_kfree_skb_irq +#else +typedef void buffer_t; +#define free_buffer kfree +#define free_buffer_irq kfree +#endif + +struct port { + struct device *dev; + struct npe *npe; + struct net_device *netdev; + struct napi_struct napi; + struct hss_plat_info *plat; + buffer_t *rx_buff_tab[RX_DESCS], *tx_buff_tab[TX_DESCS]; + struct desc *desc_tab; /* coherent */ + u32 desc_tab_phys; + unsigned int id; + unsigned int clock_type, clock_rate, loopback; + unsigned int initialized, carrier; + u8 hdlc_cfg; +}; + +/* NPE message structure */ +struct msg { +#ifdef __ARMEB__ + u8 cmd, unused, hss_port, index; + union { + struct { u8 data8a, data8b, data8c, data8d; }; + struct { u16 data16a, data16b; }; + struct { u32 data32; }; + }; +#else + u8 index, hss_port, unused, cmd; + union { + struct { u8 data8d, data8c, data8b, data8a; }; + struct { u16 data16b, data16a; }; + struct { u32 data32; }; + }; +#endif +}; + +/* HDLC packet descriptor */ +struct desc { + u32 next; /* pointer to next buffer, unused */ + +#ifdef __ARMEB__ + u16 buf_len; /* buffer length */ + u16 pkt_len; /* packet length */ + u32 data; /* pointer to data buffer in RAM */ + u8 status; + u8 error_count; + u16 __reserved; +#else + u16 pkt_len; /* packet length */ + u16 buf_len; /* buffer length */ + u32 data; /* pointer to data buffer in RAM */ + u16 __reserved; + u8 error_count; + u8 status; +#endif + u32 __reserved1[4]; +}; + + +#define rx_desc_phys(port, n) ((port)->desc_tab_phys + \ + (n) * sizeof(struct desc)) +#define rx_desc_ptr(port, n) (&(port)->desc_tab[n]) + +#define tx_desc_phys(port, n) ((port)->desc_tab_phys + \ + ((n) + RX_DESCS) * sizeof(struct desc)) +#define tx_desc_ptr(port, n) (&(port)->desc_tab[(n) + RX_DESCS]) + +/***************************************************************************** + * global variables + ****************************************************************************/ + +static int ports_open; +static struct dma_pool *dma_pool; +static spinlock_t npe_lock; + +static const struct { + int tx, txdone, rx, rxfree; +}queue_ids[2] = {{HSS0_PKT_TX0_QUEUE, HSS0_PKT_TXDONE_QUEUE, HSS0_PKT_RX_QUEUE, + HSS0_PKT_RXFREE0_QUEUE}, + {HSS1_PKT_TX0_QUEUE, HSS1_PKT_TXDONE_QUEUE, HSS1_PKT_RX_QUEUE, + HSS1_PKT_RXFREE0_QUEUE}, +}; + +/***************************************************************************** + * utility functions + ****************************************************************************/ + +static inline struct port* dev_to_port(struct net_device *dev) +{ + return dev_to_hdlc(dev)->priv; +} + +#ifndef __ARMEB__ +static inline void memcpy_swab32(u32 *dest, u32 *src, int cnt) +{ + int i; + for (i = 0; i < cnt; i++) + dest[i] = swab32(src[i]); +} +#endif + +/***************************************************************************** + * HSS access + ****************************************************************************/ + +static void hss_npe_send(struct port *port, struct msg *msg, const char* what) +{ + u32 *val = (u32*)msg; + if (npe_send_message(port->npe, msg, what)) { + printk(KERN_CRIT "HSS-%i: unable to send command [%08X:%08X]" + " to %s\n", port->id, val[0], val[1], + npe_name(port->npe)); + BUG(); + } +} + +static void hss_config_set_lut(struct port *port) +{ + struct msg msg; + int ch; + + memset(&msg, 0, sizeof(msg)); + msg.cmd = PORT_CONFIG_WRITE; + msg.hss_port = port->id; + + for (ch = 0; ch < MAX_CHANNELS; ch++) { + msg.data32 >>= 2; + msg.data32 |= TDMMAP_HDLC << 30; + + if (ch % 16 == 15) { + msg.index = HSS_CONFIG_TX_LUT + ((ch / 4) & ~3); + hss_npe_send(port, &msg, "HSS_SET_TX_LUT"); + + msg.index += HSS_CONFIG_RX_LUT - HSS_CONFIG_TX_LUT; + hss_npe_send(port, &msg, "HSS_SET_RX_LUT"); + } + } +} + +static void hss_config(struct port *port) +{ + struct msg msg; + + memset(&msg, 0, sizeof(msg)); + msg.cmd = PORT_CONFIG_WRITE; + msg.hss_port = port->id; + msg.index = HSS_CONFIG_TX_PCR; + msg.data32 = PCR_FRM_SYNC_OUTPUT_RISING | PCR_MSB_ENDIAN | + PCR_TX_DATA_ENABLE | PCR_SOF_NO_FBIT; + if (port->clock_type == CLOCK_INT) + msg.data32 |= PCR_SYNC_CLK_DIR_OUTPUT; + hss_npe_send(port, &msg, "HSS_SET_TX_PCR"); + + msg.index = HSS_CONFIG_RX_PCR; + msg.data32 ^= PCR_TX_DATA_ENABLE | PCR_DCLK_EDGE_RISING; + hss_npe_send(port, &msg, "HSS_SET_RX_PCR"); + + memset(&msg, 0, sizeof(msg)); + msg.cmd = PORT_CONFIG_WRITE; + msg.hss_port = port->id; + msg.index = HSS_CONFIG_CORE_CR; + msg.data32 = (port->loopback ? CCR_LOOPBACK : 0) | + (port->id ? CCR_SECOND_HSS : 0); + hss_npe_send(port, &msg, "HSS_SET_CORE_CR"); + + memset(&msg, 0, sizeof(msg)); + msg.cmd = PORT_CONFIG_WRITE; + msg.hss_port = port->id; + msg.index = HSS_CONFIG_CLOCK_CR; + msg.data32 = CLK42X_SPEED_2048KHZ /* FIXME */; + hss_npe_send(port, &msg, "HSS_SET_CLOCK_CR"); + + memset(&msg, 0, sizeof(msg)); + msg.cmd = PORT_CONFIG_WRITE; + msg.hss_port = port->id; + msg.index = HSS_CONFIG_TX_FCR; + msg.data16a = FRAME_OFFSET; + msg.data16b = FRAME_SIZE - 1; + hss_npe_send(port, &msg, "HSS_SET_TX_FCR"); + + memset(&msg, 0, sizeof(msg)); + msg.cmd = PORT_CONFIG_WRITE; + msg.hss_port = port->id; + msg.index = HSS_CONFIG_RX_FCR; + msg.data16a = FRAME_OFFSET; + msg.data16b = FRAME_SIZE - 1; + hss_npe_send(port, &msg, "HSS_SET_RX_FCR"); + + hss_config_set_lut(port); + + memset(&msg, 0, sizeof(msg)); + msg.cmd = PORT_CONFIG_LOAD; + msg.hss_port = port->id; + hss_npe_send(port, &msg, "HSS_LOAD_CONFIG"); + + if (npe_recv_message(port->npe, &msg, "HSS_LOAD_CONFIG") || + /* HSS_LOAD_CONFIG for port #1 returns port_id = #4 */ + msg.cmd != PORT_CONFIG_LOAD || msg.data32) { + printk(KERN_CRIT "HSS-%i: HSS_LOAD_CONFIG failed\n", + port->id); + BUG(); + } + + /* HDLC may stop working without this - check FIXME */ + npe_recv_message(port->npe, &msg, "FLUSH_IT"); +} + +static void hss_set_hdlc_cfg(struct port *port) +{ + struct msg msg; + + memset(&msg, 0, sizeof(msg)); + msg.cmd = PKT_PIPE_HDLC_CFG_WRITE; + msg.hss_port = port->id; + msg.data8a = port->hdlc_cfg; /* rx_cfg */ + msg.data8b = port->hdlc_cfg | (PKT_EXTRA_FLAGS << 3); /* tx_cfg */ + hss_npe_send(port, &msg, "HSS_SET_HDLC_CFG"); +} + +static u32 hss_get_status(struct port *port) +{ + struct msg msg; + + memset(&msg, 0, sizeof(msg)); + msg.cmd = PORT_ERROR_READ; + msg.hss_port = port->id; + hss_npe_send(port, &msg, "PORT_ERROR_READ"); + if (npe_recv_message(port->npe, &msg, "PORT_ERROR_READ")) { + printk(KERN_CRIT "HSS-%i: unable to read HSS status\n", + port->id); + BUG(); + } + + return msg.data32; +} + +static void hss_start_hdlc(struct port *port) +{ + struct msg msg; + + memset(&msg, 0, sizeof(msg)); + msg.cmd = PKT_PIPE_FLOW_ENABLE; + msg.hss_port = port->id; + msg.data32 = 0; + hss_npe_send(port, &msg, "HSS_ENABLE_PKT_PIPE"); +} + +static void hss_stop_hdlc(struct port *port) +{ + struct msg msg; + + memset(&msg, 0, sizeof(msg)); + msg.cmd = PKT_PIPE_FLOW_DISABLE; + msg.hss_port = port->id; + hss_npe_send(port, &msg, "HSS_DISABLE_PKT_PIPE"); + hss_get_status(port); /* make sure it's halted */ +} + +static int hss_load_firmware(struct port *port) +{ + struct msg msg; + int err; + + if (port->initialized) + return 0; + + if (!npe_running(port->npe) && + (err = npe_load_firmware(port->npe, npe_name(port->npe), + port->dev))) + return err; + + /* HDLC mode configuration */ + memset(&msg, 0, sizeof(msg)); + msg.cmd = PKT_NUM_PIPES_WRITE; + msg.hss_port = port->id; + msg.data8a = PKT_NUM_PIPES; + hss_npe_send(port, &msg, "HSS_SET_PKT_PIPES"); + + msg.cmd = PKT_PIPE_FIFO_SIZEW_WRITE; + msg.data8a = PKT_PIPE_FIFO_SIZEW; + hss_npe_send(port, &msg, "HSS_SET_PKT_FIFO"); + + msg.cmd = PKT_PIPE_MODE_WRITE; + msg.data8a = NPE_PKT_MODE_HDLC; + /* msg.data8b = inv_mask */ + /* msg.data8c = or_mask */ + hss_npe_send(port, &msg, "HSS_SET_PKT_MODE"); + + msg.cmd = PKT_PIPE_RX_SIZE_WRITE; + msg.data16a = HDLC_MAX_MRU; /* including CRC */ + hss_npe_send(port, &msg, "HSS_SET_PKT_RX_SIZE"); + + msg.cmd = PKT_PIPE_IDLE_PATTERN_WRITE; + msg.data32 = 0x7F7F7F7F; /* ??? FIXME */ + hss_npe_send(port, &msg, "HSS_SET_PKT_IDLE"); + + port->initialized = 1; + return 0; +} + +/***************************************************************************** + * packetized (HDLC) operation + ****************************************************************************/ + +static inline void debug_pkt(struct net_device *dev, const char *func, + u8 *data, int len) +{ +#if DEBUG_PKT_BYTES + int i; + + printk(KERN_DEBUG "%s: %s(%i)", dev->name, func, len); + for (i = 0; i < len; i++) { + if (i >= DEBUG_PKT_BYTES) + break; + printk("%s%02X", !(i % 4) ? " " : "", data[i]); + } + printk("\n"); +#endif +} + + +static inline void debug_desc(u32 phys, struct desc *desc) +{ +#if DEBUG_DESC + printk(KERN_DEBUG "%X: %X %3X %3X %08X %X %X\n", + phys, desc->next, desc->buf_len, desc->pkt_len, + desc->data, desc->status, desc->error_count); +#endif +} + +static inline int queue_get_desc(unsigned int queue, struct port *port, + int is_tx) +{ + u32 phys, tab_phys, n_desc; + struct desc *tab; + + if (!(phys = qmgr_get_entry(queue))) + return -1; + + BUG_ON(phys & 0x1F); + tab_phys = is_tx ? tx_desc_phys(port, 0) : rx_desc_phys(port, 0); + tab = is_tx ? tx_desc_ptr(port, 0) : rx_desc_ptr(port, 0); + n_desc = (phys - tab_phys) / sizeof(struct desc); + BUG_ON(n_desc >= (is_tx ? TX_DESCS : RX_DESCS)); + debug_desc(phys, &tab[n_desc]); + BUG_ON(tab[n_desc].next); + return n_desc; +} + +static inline void queue_put_desc(unsigned int queue, u32 phys, + struct desc *desc) +{ + debug_desc(phys, desc); + BUG_ON(phys & 0x1F); + qmgr_put_entry(queue, phys); + BUG_ON(qmgr_stat_overflow(queue)); +} + + +static inline void dma_unmap_tx(struct port *port, struct desc *desc) +{ +#ifdef __ARMEB__ + dma_unmap_single(&port->netdev->dev, desc->data, + desc->buf_len, DMA_TO_DEVICE); +#else + dma_unmap_single(&port->netdev->dev, desc->data & ~3, + ALIGN((desc->data & 3) + desc->buf_len, 4), + DMA_TO_DEVICE); +#endif +} + + +static void hss_hdlc_set_carrier(void *pdev, int carrier) +{ + struct net_device *netdev = pdev; + struct port *port = dev_to_port(netdev); + unsigned long flags; + + spin_lock_irqsave(&npe_lock, flags); + port->carrier = carrier; + if (!port->loopback) { + if (carrier) + netif_carrier_on(netdev); + else + netif_carrier_off(netdev); + } + spin_unlock_irqrestore(&npe_lock, flags); +} + +static void hss_hdlc_rx_irq(void *pdev) +{ + struct net_device *dev = pdev; + struct port *port = dev_to_port(dev); + +#if DEBUG_RX + printk(KERN_DEBUG "%s: hss_hdlc_rx_irq\n", dev->name); +#endif + qmgr_disable_irq(queue_ids[port->id].rx); + netif_rx_schedule(dev, &port->napi); +} + +static int hss_hdlc_poll(struct napi_struct *napi, int budget) +{ + struct port *port = container_of(napi, struct port, napi); + struct net_device *dev = port->netdev; + unsigned int rxq = queue_ids[port->id].rx; + unsigned int rxfreeq = queue_ids[port->id].rxfree; + int received = 0; + +#if DEBUG_RX + printk(KERN_DEBUG "%s: hss_hdlc_poll\n", dev->name); +#endif + + while (received < budget) { + struct sk_buff *skb; + struct desc *desc; + int n; +#ifdef __ARMEB__ + struct sk_buff *temp; + u32 phys; +#endif + + if ((n = queue_get_desc(rxq, port, 0)) < 0) { +#if DEBUG_RX + printk(KERN_DEBUG "%s: hss_hdlc_poll" + " netif_rx_complete\n", dev->name); +#endif + netif_rx_complete(dev, napi); + qmgr_enable_irq(rxq); + if (!qmgr_stat_empty(rxq) && + netif_rx_reschedule(dev, napi)) { +#if DEBUG_RX + printk(KERN_DEBUG "%s: hss_hdlc_poll" + " netif_rx_reschedule succeeded\n", + dev->name); +#endif + qmgr_disable_irq(rxq); + continue; + } +#if DEBUG_RX + printk(KERN_DEBUG "%s: hss_hdlc_poll all done\n", + dev->name); +#endif + return received; /* all work done */ + } + + desc = rx_desc_ptr(port, n); +#if 0 /* FIXME - error_count counts modulo 256, perhaps we should use it */ + if (desc->error_count) + printk(KERN_DEBUG "%s: hss_hdlc_poll status 0x%02X" + " errors %u\n", dev->name, desc->status, + desc->error_count); +#endif + skb = NULL; + switch (desc->status) { + case 0: +#ifdef __ARMEB__ + if ((skb = netdev_alloc_skb(dev, RX_SIZE)) != NULL) { + phys = dma_map_single(&dev->dev, skb->data, + RX_SIZE, + DMA_FROM_DEVICE); + if (dma_mapping_error(&dev->dev, phys)) { + dev_kfree_skb(skb); + skb = NULL; + } + } +#else + skb = netdev_alloc_skb(dev, desc->pkt_len); +#endif + if (!skb) + dev->stats.rx_dropped++; + break; + case ERR_HDLC_ALIGN: + case ERR_HDLC_ABORT: + dev->stats.rx_frame_errors++; + dev->stats.rx_errors++; + break; + case ERR_HDLC_FCS: + dev->stats.rx_crc_errors++; + dev->stats.rx_errors++; + break; + case ERR_HDLC_TOO_LONG: + dev->stats.rx_length_errors++; + dev->stats.rx_errors++; + break; + default: /* FIXME - remove printk */ + printk(KERN_ERR "%s: hss_hdlc_poll: status 0x%02X" + " errors %u\n", dev->name, desc->status, + desc->error_count); + dev->stats.rx_errors++; + } + + if (!skb) { + /* put the desc back on RX-ready queue */ + desc->buf_len = RX_SIZE; + desc->pkt_len = desc->status = 0; + queue_put_desc(rxfreeq, rx_desc_phys(port, n), desc); + continue; + } + + /* process received frame */ +#ifdef __ARMEB__ + temp = skb; + skb = port->rx_buff_tab[n]; + dma_unmap_single(&dev->dev, desc->data, + RX_SIZE, DMA_FROM_DEVICE); +#else + dma_sync_single(&dev->dev, desc->data, + RX_SIZE, DMA_FROM_DEVICE); + memcpy_swab32((u32 *)skb->data, (u32 *)port->rx_buff_tab[n], + ALIGN(desc->pkt_len, 4) / 4); +#endif + skb_put(skb, desc->pkt_len); + + debug_pkt(dev, "hss_hdlc_poll", skb->data, skb->len); + + skb->protocol = hdlc_type_trans(skb, dev); + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; + netif_receive_skb(skb); + + /* put the new buffer on RX-free queue */ +#ifdef __ARMEB__ + port->rx_buff_tab[n] = temp; + desc->data = phys; +#endif + desc->buf_len = RX_SIZE; + desc->pkt_len = 0; + queue_put_desc(rxfreeq, rx_desc_phys(port, n), desc); + received++; + } +#if DEBUG_RX + printk(KERN_DEBUG "hss_hdlc_poll: end, not all work done\n"); +#endif + return received; /* not all work done */ +} + + +static void hss_hdlc_txdone_irq(void *pdev) +{ + struct net_device *dev = pdev; + struct port *port = dev_to_port(dev); + int n_desc; + +#if DEBUG_TX + printk(KERN_DEBUG DRV_NAME ": hss_hdlc_txdone_irq\n"); +#endif + while ((n_desc = queue_get_desc(queue_ids[port->id].txdone, + port, 1)) >= 0) { + struct desc *desc; + int start; + + desc = tx_desc_ptr(port, n_desc); + + dev->stats.tx_packets++; + dev->stats.tx_bytes += desc->pkt_len; + + dma_unmap_tx(port, desc); +#if DEBUG_TX + printk(KERN_DEBUG "%s: hss_hdlc_txdone_irq free %p\n", + dev->name, port->tx_buff_tab[n_desc]); +#endif + free_buffer_irq(port->tx_buff_tab[n_desc]); + port->tx_buff_tab[n_desc] = NULL; + + start = qmgr_stat_empty(port->plat->txreadyq); + queue_put_desc(port->plat->txreadyq, + tx_desc_phys(port, n_desc), desc); + if (start) { +#if DEBUG_TX + printk(KERN_DEBUG "%s: hss_hdlc_txdone_irq xmit" + " ready\n", dev->name); +#endif + netif_wake_queue(dev); + } + } +} + +static int hss_hdlc_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct port *port = dev_to_port(dev); + unsigned int txreadyq = port->plat->txreadyq; + int len, offset, bytes, n; + void *mem; + u32 phys; + struct desc *desc; + +#if DEBUG_TX + printk(KERN_DEBUG "%s: hss_hdlc_xmit\n", dev->name); +#endif + + if (unlikely(skb->len > HDLC_MAX_MRU)) { + dev_kfree_skb(skb); + dev->stats.tx_errors++; + return NETDEV_TX_OK; + } + + debug_pkt(dev, "hss_hdlc_xmit", skb->data, skb->len); + + len = skb->len; +#ifdef __ARMEB__ + offset = 0; /* no need to keep alignment */ + bytes = len; + mem = skb->data; +#else + offset = (int)skb->data & 3; /* keep 32-bit alignment */ + bytes = ALIGN(offset + len, 4); + if (!(mem = kmalloc(bytes, GFP_ATOMIC))) { + dev_kfree_skb(skb); + dev->stats.tx_dropped++; + return NETDEV_TX_OK; + } + memcpy_swab32(mem, (u32 *)((int)skb->data & ~3), bytes / 4); + dev_kfree_skb(skb); +#endif + + phys = dma_map_single(&dev->dev, mem, bytes, DMA_TO_DEVICE); + if (dma_mapping_error(&dev->dev, phys)) { +#ifdef __ARMEB__ + dev_kfree_skb(skb); +#else + kfree(mem); +#endif + dev->stats.tx_dropped++; + return NETDEV_TX_OK; + } + + n = queue_get_desc(txreadyq, port, 1); + BUG_ON(n < 0); + desc = tx_desc_ptr(port, n); + +#ifdef __ARMEB__ + port->tx_buff_tab[n] = skb; +#else + port->tx_buff_tab[n] = mem; +#endif + desc->data = phys + offset; + desc->buf_len = desc->pkt_len = len; + + wmb(); + queue_put_desc(queue_ids[port->id].tx, tx_desc_phys(port, n), desc); + dev->trans_start = jiffies; + + if (qmgr_stat_empty(txreadyq)) { +#if DEBUG_TX + printk(KERN_DEBUG "%s: hss_hdlc_xmit queue full\n", dev->name); +#endif + netif_stop_queue(dev); + /* we could miss TX ready interrupt */ + if (!qmgr_stat_empty(txreadyq)) { +#if DEBUG_TX + printk(KERN_DEBUG "%s: hss_hdlc_xmit ready again\n", + dev->name); +#endif + netif_wake_queue(dev); + } + } + +#if DEBUG_TX + printk(KERN_DEBUG "%s: hss_hdlc_xmit end\n", dev->name); +#endif + return NETDEV_TX_OK; +} + + +static int request_hdlc_queues(struct port *port) +{ + int err; + + err = qmgr_request_queue(queue_ids[port->id].rxfree, RX_DESCS, 0, 0, + "%s:RX-free", port->netdev->name); + if (err) + return err; + + err = qmgr_request_queue(queue_ids[port->id].rx, RX_DESCS, 0, 0, + "%s:RX", port->netdev->name); + if (err) + goto rel_rxfree; + + err = qmgr_request_queue(queue_ids[port->id].tx, TX_DESCS, 0, 0, + "%s:TX", port->netdev->name); + if (err) + goto rel_rx; + + err = qmgr_request_queue(port->plat->txreadyq, TX_DESCS, 0, 0, + "%s:TX-ready", port->netdev->name); + if (err) + goto rel_tx; + + err = qmgr_request_queue(queue_ids[port->id].txdone, TX_DESCS, 0, 0, + "%s:TX-done", port->netdev->name); + if (err) + goto rel_txready; + return 0; + +rel_txready: + qmgr_release_queue(port->plat->txreadyq); +rel_tx: + qmgr_release_queue(queue_ids[port->id].tx); +rel_rx: + qmgr_release_queue(queue_ids[port->id].rx); +rel_rxfree: + qmgr_release_queue(queue_ids[port->id].rxfree); + printk(KERN_DEBUG "%s: unable to request hardware queues\n", + port->netdev->name); + return err; +} + +static void release_hdlc_queues(struct port *port) +{ + qmgr_release_queue(queue_ids[port->id].rxfree); + qmgr_release_queue(queue_ids[port->id].rx); + qmgr_release_queue(queue_ids[port->id].txdone); + qmgr_release_queue(queue_ids[port->id].tx); + qmgr_release_queue(port->plat->txreadyq); +} + +static int init_hdlc_queues(struct port *port) +{ + int i; + + if (!ports_open) + if (!(dma_pool = dma_pool_create(DRV_NAME, NULL, + POOL_ALLOC_SIZE, 32, 0))) + return -ENOMEM; + + if (!(port->desc_tab = dma_pool_alloc(dma_pool, GFP_KERNEL, + &port->desc_tab_phys))) + return -ENOMEM; + memset(port->desc_tab, 0, POOL_ALLOC_SIZE); + memset(port->rx_buff_tab, 0, sizeof(port->rx_buff_tab)); /* tables */ + memset(port->tx_buff_tab, 0, sizeof(port->tx_buff_tab)); + + /* Setup RX buffers */ + for (i = 0; i < RX_DESCS; i++) { + struct desc *desc = rx_desc_ptr(port, i); + buffer_t *buff; + void *data; +#ifdef __ARMEB__ + if (!(buff = netdev_alloc_skb(port->netdev, RX_SIZE))) + return -ENOMEM; + data = buff->data; +#else + if (!(buff = kmalloc(RX_SIZE, GFP_KERNEL))) + return -ENOMEM; + data = buff; +#endif + desc->buf_len = RX_SIZE; + desc->data = dma_map_single(&port->netdev->dev, data, + RX_SIZE, DMA_FROM_DEVICE); + if (dma_mapping_error(&port->netdev->dev, desc->data)) { + free_buffer(buff); + return -EIO; + } + port->rx_buff_tab[i] = buff; + } + + return 0; +} + +static void destroy_hdlc_queues(struct port *port) +{ + int i; + + if (port->desc_tab) { + for (i = 0; i < RX_DESCS; i++) { + struct desc *desc = rx_desc_ptr(port, i); + buffer_t *buff = port->rx_buff_tab[i]; + if (buff) { + dma_unmap_single(&port->netdev->dev, + desc->data, RX_SIZE, + DMA_FROM_DEVICE); + free_buffer(buff); + } + } + for (i = 0; i < TX_DESCS; i++) { + struct desc *desc = tx_desc_ptr(port, i); + buffer_t *buff = port->tx_buff_tab[i]; + if (buff) { + dma_unmap_tx(port, desc); + free_buffer(buff); + } + } + dma_pool_free(dma_pool, port->desc_tab, port->desc_tab_phys); + port->desc_tab = NULL; + } + + if (!ports_open && dma_pool) { + dma_pool_destroy(dma_pool); + dma_pool = NULL; + } +} + +static int hss_hdlc_open(struct net_device *dev) +{ + struct port *port = dev_to_port(dev); + unsigned long flags; + int i, err = 0; + + if ((err = hdlc_open(dev))) + return err; + + if ((err = hss_load_firmware(port))) + goto err_hdlc_close; + + if ((err = request_hdlc_queues(port))) + goto err_hdlc_close; + + if ((err = init_hdlc_queues(port))) + goto err_destroy_queues; + + spin_lock_irqsave(&npe_lock, flags); + if (port->plat->open) + if ((err = port->plat->open(port->id, dev, + hss_hdlc_set_carrier))) + goto err_unlock; + spin_unlock_irqrestore(&npe_lock, flags); + + /* Populate queues with buffers, no failure after this point */ + for (i = 0; i < TX_DESCS; i++) + queue_put_desc(port->plat->txreadyq, + tx_desc_phys(port, i), tx_desc_ptr(port, i)); + + for (i = 0; i < RX_DESCS; i++) + queue_put_desc(queue_ids[port->id].rxfree, + rx_desc_phys(port, i), rx_desc_ptr(port, i)); + + napi_enable(&port->napi); + netif_start_queue(dev); + + qmgr_set_irq(queue_ids[port->id].rx, QUEUE_IRQ_SRC_NOT_EMPTY, + hss_hdlc_rx_irq, dev); + + qmgr_set_irq(queue_ids[port->id].txdone, QUEUE_IRQ_SRC_NOT_EMPTY, + hss_hdlc_txdone_irq, dev); + qmgr_enable_irq(queue_ids[port->id].txdone); + + ports_open++; + + hss_set_hdlc_cfg(port); + hss_config(port); + + hss_start_hdlc(port); + + /* we may already have RX data, enables IRQ */ + netif_rx_schedule(dev, &port->napi); + return 0; + +err_unlock: + spin_unlock_irqrestore(&npe_lock, flags); +err_destroy_queues: + destroy_hdlc_queues(port); + release_hdlc_queues(port); +err_hdlc_close: + hdlc_close(dev); + return err; +} + +static int hss_hdlc_close(struct net_device *dev) +{ + struct port *port = dev_to_port(dev); + unsigned long flags; + int i, buffs = RX_DESCS; /* allocated RX buffers */ + + spin_lock_irqsave(&npe_lock, flags); + ports_open--; + qmgr_disable_irq(queue_ids[port->id].rx); + netif_stop_queue(dev); + napi_disable(&port->napi); + + hss_stop_hdlc(port); + + while (queue_get_desc(queue_ids[port->id].rxfree, port, 0) >= 0) + buffs--; + while (queue_get_desc(queue_ids[port->id].rx, port, 0) >= 0) + buffs--; + + if (buffs) + printk(KERN_CRIT "%s: unable to drain RX queue, %i buffer(s)" + " left in NPE\n", dev->name, buffs); + + buffs = TX_DESCS; + while (queue_get_desc(queue_ids[port->id].tx, port, 1) >= 0) + buffs--; /* cancel TX */ + + i = 0; + do { + while (queue_get_desc(port->plat->txreadyq, port, 1) >= 0) + buffs--; + if (!buffs) + break; + } while (++i < MAX_CLOSE_WAIT); + + if (buffs) + printk(KERN_CRIT "%s: unable to drain TX queue, %i buffer(s) " + "left in NPE\n", dev->name, buffs); +#if DEBUG_CLOSE + if (!buffs) + printk(KERN_DEBUG "Draining TX queues took %i cycles\n", i); +#endif + qmgr_disable_irq(queue_ids[port->id].txdone); + + if (port->plat->close) + port->plat->close(port->id, dev); + spin_unlock_irqrestore(&npe_lock, flags); + + destroy_hdlc_queues(port); + release_hdlc_queues(port); + hdlc_close(dev); + return 0; +} + + +static int hss_hdlc_attach(struct net_device *dev, unsigned short encoding, + unsigned short parity) +{ + struct port *port = dev_to_port(dev); + + if (encoding != ENCODING_NRZ) + return -EINVAL; + + switch(parity) { + case PARITY_CRC16_PR1_CCITT: + port->hdlc_cfg = 0; + return 0; + + case PARITY_CRC32_PR1_CCITT: + port->hdlc_cfg = PKT_HDLC_CRC_32; + return 0; + + default: + return -EINVAL; + } +} + + +static int hss_hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + const size_t size = sizeof(sync_serial_settings); + sync_serial_settings new_line; + sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync; + struct port *port = dev_to_port(dev); + unsigned long flags; + int clk; + + if (cmd != SIOCWANDEV) + return hdlc_ioctl(dev, ifr, cmd); + + switch(ifr->ifr_settings.type) { + case IF_GET_IFACE: + ifr->ifr_settings.type = IF_IFACE_V35; + if (ifr->ifr_settings.size < size) { + ifr->ifr_settings.size = size; /* data size wanted */ + return -ENOBUFS; + } + memset(&new_line, 0, sizeof(new_line)); + new_line.clock_type = port->clock_type; + new_line.clock_rate = 2048000; /* FIXME */ + new_line.loopback = port->loopback; + if (copy_to_user(line, &new_line, size)) + return -EFAULT; + return 0; + + case IF_IFACE_SYNC_SERIAL: + case IF_IFACE_V35: + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + if (copy_from_user(&new_line, line, size)) + return -EFAULT; + + clk = new_line.clock_type; + if (port->plat->set_clock) + clk = port->plat->set_clock(port->id, clk); + + if (clk != CLOCK_EXT && clk != CLOCK_INT) + return -EINVAL; /* No such clock setting */ + + if (new_line.loopback != 0 && new_line.loopback != 1) + return -EINVAL; + + port->clock_type = clk; /* Update settings */ + /* FIXME port->clock_rate = new_line.clock_rate */; + port->loopback = new_line.loopback; + + spin_lock_irqsave(&npe_lock, flags); + + if (dev->flags & IFF_UP) + hss_config(port); + + if (port->loopback || port->carrier) + netif_carrier_on(port->netdev); + else + netif_carrier_off(port->netdev); + spin_unlock_irqrestore(&npe_lock, flags); + + return 0; + + default: + return hdlc_ioctl(dev, ifr, cmd); + } +} + +/***************************************************************************** + * initialization + ****************************************************************************/ + +static int __devinit hss_init_one(struct platform_device *pdev) +{ + struct port *port; + struct net_device *dev; + hdlc_device *hdlc; + int err; + + if ((port = kzalloc(sizeof(*port), GFP_KERNEL)) == NULL) + return -ENOMEM; + + if ((port->npe = npe_request(0)) == NULL) { + err = -ENOSYS; + goto err_free; + } + + if ((port->netdev = dev = alloc_hdlcdev(port)) == NULL) { + err = -ENOMEM; + goto err_plat; + } + + SET_NETDEV_DEV(dev, &pdev->dev); + hdlc = dev_to_hdlc(dev); + hdlc->attach = hss_hdlc_attach; + hdlc->xmit = hss_hdlc_xmit; + dev->open = hss_hdlc_open; + dev->stop = hss_hdlc_close; + dev->do_ioctl = hss_hdlc_ioctl; + dev->tx_queue_len = 100; + port->clock_type = CLOCK_EXT; + port->clock_rate = 2048000; + port->id = pdev->id; + port->dev = &pdev->dev; + port->plat = pdev->dev.platform_data; + netif_napi_add(dev, &port->napi, hss_hdlc_poll, NAPI_WEIGHT); + + if ((err = register_hdlc_device(dev))) + goto err_free_netdev; + + platform_set_drvdata(pdev, port); + + printk(KERN_INFO "%s: HSS-%i\n", dev->name, port->id); + return 0; + +err_free_netdev: + free_netdev(dev); +err_plat: + npe_release(port->npe); +err_free: + kfree(port); + return err; +} + +static int __devexit hss_remove_one(struct platform_device *pdev) +{ + struct port *port = platform_get_drvdata(pdev); + + unregister_hdlc_device(port->netdev); + free_netdev(port->netdev); + npe_release(port->npe); + platform_set_drvdata(pdev, NULL); + kfree(port); + return 0; +} + +static struct platform_driver ixp4xx_hss_driver = { + .driver.name = DRV_NAME, + .probe = hss_init_one, + .remove = hss_remove_one, +}; + +static int __init hss_init_module(void) +{ + if ((ixp4xx_read_feature_bits() & + (IXP4XX_FEATURE_HDLC | IXP4XX_FEATURE_HSS)) != + (IXP4XX_FEATURE_HDLC | IXP4XX_FEATURE_HSS)) + return -ENOSYS; + + spin_lock_init(&npe_lock); + + return platform_driver_register(&ixp4xx_hss_driver); +} + +static void __exit hss_cleanup_module(void) +{ + platform_driver_unregister(&ixp4xx_hss_driver); +} + +MODULE_AUTHOR("Krzysztof Halasa"); +MODULE_DESCRIPTION("Intel IXP4xx HSS driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:ixp4xx_hss"); +module_init(hss_init_module); +module_exit(hss_cleanup_module); diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c index 24fd613466b7ea0925d5c98c5aada6a82a1fc6cc..5b61b3eef45f5b19da53e8e249b02895eaa6657a 100644 --- a/drivers/net/wan/lapbether.c +++ b/drivers/net/wan/lapbether.c @@ -143,7 +143,6 @@ static int lapbeth_data_indication(struct net_device *dev, struct sk_buff *skb) *ptr = 0x00; skb->protocol = x25_type_trans(skb, dev); - skb->dev->last_rx = jiffies; return netif_rx(skb); } @@ -235,7 +234,6 @@ static void lapbeth_connected(struct net_device *dev, int reason) *ptr = 0x01; skb->protocol = x25_type_trans(skb, dev); - skb->dev->last_rx = jiffies; netif_rx(skb); } @@ -253,7 +251,6 @@ static void lapbeth_disconnected(struct net_device *dev, int reason) *ptr = 0x02; skb->protocol = x25_type_trans(skb, dev); - skb->dev->last_rx = jiffies; netif_rx(skb); } diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c index d7bb63e616b5e41f9ca72f2c52fa583dddcff113..feac3b99f8fe7f42192062fca6b63189b73ec62b 100644 --- a/drivers/net/wan/lmc/lmc_main.c +++ b/drivers/net/wan/lmc/lmc_main.c @@ -1594,7 +1594,6 @@ static int lmc_rx(struct net_device *dev) goto skip_packet; } - dev->last_rx = jiffies; sc->lmc_device->stats.rx_packets++; sc->lmc_device->stats.rx_bytes += len; diff --git a/drivers/net/wan/lmc/lmc_proto.c b/drivers/net/wan/lmc/lmc_proto.c index be9877ff551e23da4ca16ad1bc4ac24ae2537901..94b4c208b013e1a0a936ed25afc46785f90ab5a0 100644 --- a/drivers/net/wan/lmc/lmc_proto.c +++ b/drivers/net/wan/lmc/lmc_proto.c @@ -142,7 +142,6 @@ void lmc_proto_netif(lmc_softc_t *sc, struct sk_buff *skb) /*FOLD00*/ case LMC_PPP: case LMC_NET: default: - skb->dev->last_rx = jiffies; netif_rx(skb); break; case LMC_RAW: diff --git a/drivers/net/wan/n2.c b/drivers/net/wan/n2.c index 0a566b0daacb51d0d979cb00af07ae341db76625..697715ae80f46917a463b5be6936c1f200ce8473 100644 --- a/drivers/net/wan/n2.c +++ b/drivers/net/wan/n2.c @@ -53,7 +53,7 @@ static const char* devname = "RISCom/N2"; #define NEED_SCA_MSCI_INTR #define MAX_TX_BUFFERS 10 -static char *hw = NULL; /* pointer to hw=xxx command line string */ +static char *hw; /* pointer to hw=xxx command line string */ /* RISCom/N2 Board Registers */ @@ -145,7 +145,6 @@ static card_t **new_card = &first_card; &(card)->ports[port] : NULL) - static __inline__ u8 sca_get_page(card_t *card) { return inb(card->io + N2_PSR) & PSR_PAGEBITS; @@ -159,9 +158,7 @@ static __inline__ void openwin(card_t *card, u8 page) } - -#include "hd6457x.c" - +#include "hd64570.c" static void n2_set_iface(port_t *port) @@ -478,7 +475,7 @@ static int __init n2_run(unsigned long io, unsigned long irq, n2_destroy_card(card); return -ENOBUFS; } - sca_init_sync_port(port); /* Set up SCA memory */ + sca_init_port(port); /* Set up SCA memory */ printk(KERN_INFO "%s: RISCom/N2 node %d\n", dev->name, port->phy_node); diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c index d0a8d1e352ac1cf2787a3eda74cb2451ec7b27b7..c23fde0c0344cc6893c2d912d9cebfa10ba7e9f6 100644 --- a/drivers/net/wan/pc300_drv.c +++ b/drivers/net/wan/pc300_drv.c @@ -1769,7 +1769,7 @@ cpc_trace(struct net_device *dev, struct sk_buff *skb_main, char rx_tx) static void cpc_tx_timeout(struct net_device *dev) { - pc300dev_t *d = (pc300dev_t *) dev->priv; + pc300dev_t *d = (pc300dev_t *) dev_to_hdlc(dev)->priv; pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; int ch = chan->channel; @@ -1796,7 +1796,7 @@ static void cpc_tx_timeout(struct net_device *dev) static int cpc_queue_xmit(struct sk_buff *skb, struct net_device *dev) { - pc300dev_t *d = (pc300dev_t *) dev->priv; + pc300dev_t *d = (pc300dev_t *) dev_to_hdlc(dev)->priv; pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; int ch = chan->channel; @@ -1874,7 +1874,7 @@ static int cpc_queue_xmit(struct sk_buff *skb, struct net_device *dev) static void cpc_net_rx(struct net_device *dev) { - pc300dev_t *d = (pc300dev_t *) dev->priv; + pc300dev_t *d = (pc300dev_t *) dev_to_hdlc(dev)->priv; pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; int ch = chan->channel; @@ -2522,7 +2522,7 @@ static int cpc_change_mtu(struct net_device *dev, int new_mtu) static int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - pc300dev_t *d = (pc300dev_t *) dev->priv; + pc300dev_t *d = (pc300dev_t *) dev_to_hdlc(dev)->priv; pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; pc300conf_t conf_aux; @@ -2718,9 +2718,8 @@ static int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) } pc300patrntst.num_errors = falc_pattern_test_error(card, ch); - if (!arg - || copy_to_user(arg, &pc300patrntst, - sizeof (pc300patterntst_t))) + if (copy_to_user(arg, &pc300patrntst, + sizeof(pc300patterntst_t))) return -EINVAL; } else { falc_pattern_test(card, ch, pc300patrntst.patrntst_on); @@ -3058,7 +3057,7 @@ static int tx_config(pc300dev_t * d) static int cpc_attach(struct net_device *dev, unsigned short encoding, unsigned short parity) { - pc300dev_t *d = (pc300dev_t *)dev->priv; + pc300dev_t *d = (pc300dev_t *)dev_to_hdlc(dev)->priv; pc300ch_t *chan = (pc300ch_t *)d->chan; pc300_t *card = (pc300_t *)chan->card; pc300chconf_t *conf = (pc300chconf_t *)&chan->conf; @@ -3138,7 +3137,7 @@ static void cpc_closech(pc300dev_t * d) int cpc_open(struct net_device *dev) { - pc300dev_t *d = (pc300dev_t *) dev->priv; + pc300dev_t *d = (pc300dev_t *) dev_to_hdlc(dev)->priv; struct ifreq ifr; int result; @@ -3166,7 +3165,7 @@ int cpc_open(struct net_device *dev) static int cpc_close(struct net_device *dev) { - pc300dev_t *d = (pc300dev_t *) dev->priv; + pc300dev_t *d = (pc300dev_t *) dev_to_hdlc(dev)->priv; pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; unsigned long flags; @@ -3347,7 +3346,7 @@ static void cpc_init_card(pc300_t * card) d->line_on = 0; d->line_off = 0; - dev = alloc_hdlcdev(NULL); + dev = alloc_hdlcdev(d); if (dev == NULL) continue; @@ -3372,7 +3371,6 @@ static void cpc_init_card(pc300_t * card) dev->do_ioctl = cpc_ioctl; if (register_hdlc_device(dev) == 0) { - dev->priv = d; /* We need 'priv', hdlc doesn't */ printk("%s: Cyclades-PC300/", dev->name); switch (card->hw.type) { case PC300_TE: diff --git a/drivers/net/wan/pc300too.c b/drivers/net/wan/pc300too.c index bf1b01590429d00ee45f3947c632726c4078b4de..f247e5d9002a3b8837f64e390583c3efcb1470c5 100644 --- a/drivers/net/wan/pc300too.c +++ b/drivers/net/wan/pc300too.c @@ -1,7 +1,7 @@ /* * Cyclades PC300 synchronous serial card driver for Linux * - * Copyright (C) 2000-2007 Krzysztof Halasa + * Copyright (C) 2000-2008 Krzysztof Halasa * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -11,7 +11,7 @@ * * Sources of information: * Hitachi HD64572 SCA-II User's Manual - * Cyclades PC300 Linux driver + * Original Cyclades PC300 Linux driver * * This driver currently supports only PC300/RSV (V.24/V.35) and * PC300/X21 cards. @@ -37,17 +37,11 @@ #include "hd64572.h" -static const char* version = "Cyclades PC300 driver version: 1.17"; -static const char* devname = "PC300"; - #undef DEBUG_PKT #define DEBUG_RINGS #define PC300_PLX_SIZE 0x80 /* PLX control window size (128 B) */ #define PC300_SCA_SIZE 0x400 /* SCA window size (1 KB) */ -#define ALL_PAGES_ALWAYS_MAPPED -#define NEED_DETECT_RAM -#define NEED_SCA_MSCI_INTR #define MAX_TX_BUFFERS 10 static int pci_clock_freq = 33000000; @@ -81,7 +75,8 @@ typedef struct { typedef struct port_s { - struct net_device *dev; + struct napi_struct napi; + struct net_device *netdev; struct card_s *card; spinlock_t lock; /* TX lock */ sync_serial_settings settings; @@ -93,7 +88,7 @@ typedef struct port_s { u16 txin; /* tx ring buffer 'in' and 'last' pointers */ u16 txlast; u8 rxs, txs, tmc; /* SCA registers */ - u8 phy_node; /* physical port # - 0 or 1 */ + u8 chan; /* physical port # - 0 or 1 */ }port_t; @@ -114,21 +109,10 @@ typedef struct card_s { }card_t; -#define sca_in(reg, card) readb(card->scabase + (reg)) -#define sca_out(value, reg, card) writeb(value, card->scabase + (reg)) -#define sca_inw(reg, card) readw(card->scabase + (reg)) -#define sca_outw(value, reg, card) writew(value, card->scabase + (reg)) -#define sca_inl(reg, card) readl(card->scabase + (reg)) -#define sca_outl(value, reg, card) writel(value, card->scabase + (reg)) - -#define port_to_card(port) (port->card) -#define log_node(port) (port->phy_node) -#define phy_node(port) (port->phy_node) -#define winbase(card) (card->rambase) #define get_port(card, port) ((port) < (card)->n_ports ? \ (&(card)->ports[port]) : (NULL)) -#include "hd6457x.c" +#include "hd64572.c" static void pc300_set_iface(port_t *port) @@ -139,8 +123,8 @@ static void pc300_set_iface(port_t *port) u8 rxs = port->rxs & CLK_BRG_MASK; u8 txs = port->txs & CLK_BRG_MASK; - sca_out(EXS_TES1, (phy_node(port) ? MSCI1_OFFSET : MSCI0_OFFSET) + EXS, - port_to_card(port)); + sca_out(EXS_TES1, (port->chan ? MSCI1_OFFSET : MSCI0_OFFSET) + EXS, + port->card); switch(port->settings.clock_type) { case CLOCK_INT: rxs |= CLK_BRG; /* BRG output */ @@ -172,10 +156,10 @@ static void pc300_set_iface(port_t *port) if (port->card->type == PC300_RSV) { if (port->iface == IF_IFACE_V35) writel(card->init_ctrl_value | - PC300_CHMEDIA_MASK(port->phy_node), init_ctrl); + PC300_CHMEDIA_MASK(port->chan), init_ctrl); else writel(card->init_ctrl_value & - ~PC300_CHMEDIA_MASK(port->phy_node), init_ctrl); + ~PC300_CHMEDIA_MASK(port->chan), init_ctrl); } } @@ -280,10 +264,8 @@ static void pc300_pci_remove_one(struct pci_dev *pdev) card_t *card = pci_get_drvdata(pdev); for (i = 0; i < 2; i++) - if (card->ports[i].card) { - struct net_device *dev = port_to_dev(&card->ports[i]); - unregister_hdlc_device(dev); - } + if (card->ports[i].card) + unregister_hdlc_device(card->ports[i].netdev); if (card->irq) free_irq(card->irq, card); @@ -298,10 +280,10 @@ static void pc300_pci_remove_one(struct pci_dev *pdev) pci_release_regions(pdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); - if (card->ports[0].dev) - free_netdev(card->ports[0].dev); - if (card->ports[1].dev) - free_netdev(card->ports[1].dev); + if (card->ports[0].netdev) + free_netdev(card->ports[0].netdev); + if (card->ports[1].netdev) + free_netdev(card->ports[1].netdev); kfree(card); } @@ -318,12 +300,6 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev, u32 scaphys; /* SCA memory base */ u32 plxphys; /* PLX registers memory base */ -#ifndef MODULE - static int printed_version; - if (!printed_version++) - printk(KERN_INFO "%s\n", version); -#endif - i = pci_enable_device(pdev); if (i) return i; @@ -343,27 +319,6 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev, } pci_set_drvdata(pdev, card); - if (pdev->device == PCI_DEVICE_ID_PC300_TE_1 || - pdev->device == PCI_DEVICE_ID_PC300_TE_2) - card->type = PC300_TE; /* not fully supported */ - else if (card->init_ctrl_value & PC300_CTYPE_MASK) - card->type = PC300_X21; - else - card->type = PC300_RSV; - - if (pdev->device == PCI_DEVICE_ID_PC300_RX_1 || - pdev->device == PCI_DEVICE_ID_PC300_TE_1) - card->n_ports = 1; - else - card->n_ports = 2; - - for (i = 0; i < card->n_ports; i++) - if (!(card->ports[i].dev = alloc_hdlcdev(&card->ports[i]))) { - printk(KERN_ERR "pc300: unable to allocate memory\n"); - pc300_pci_remove_one(pdev); - return -ENOMEM; - } - if (pci_resource_len(pdev, 0) != PC300_PLX_SIZE || pci_resource_len(pdev, 2) != PC300_SCA_SIZE || pci_resource_len(pdev, 3) < 16384) { @@ -372,14 +327,14 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev, return -EFAULT; } - plxphys = pci_resource_start(pdev,0) & PCI_BASE_ADDRESS_MEM_MASK; + plxphys = pci_resource_start(pdev, 0) & PCI_BASE_ADDRESS_MEM_MASK; card->plxbase = ioremap(plxphys, PC300_PLX_SIZE); - scaphys = pci_resource_start(pdev,2) & PCI_BASE_ADDRESS_MEM_MASK; + scaphys = pci_resource_start(pdev, 2) & PCI_BASE_ADDRESS_MEM_MASK; card->scabase = ioremap(scaphys, PC300_SCA_SIZE); - ramphys = pci_resource_start(pdev,3) & PCI_BASE_ADDRESS_MEM_MASK; - card->rambase = ioremap(ramphys, pci_resource_len(pdev,3)); + ramphys = pci_resource_start(pdev, 3) & PCI_BASE_ADDRESS_MEM_MASK; + card->rambase = pci_ioremap_bar(pdev, 3); if (card->plxbase == NULL || card->scabase == NULL || @@ -393,6 +348,27 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev, card->init_ctrl_value = readl(&((plx9050 __iomem *)card->scabase)->init_ctrl); pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, plxphys); + if (pdev->device == PCI_DEVICE_ID_PC300_TE_1 || + pdev->device == PCI_DEVICE_ID_PC300_TE_2) + card->type = PC300_TE; /* not fully supported */ + else if (card->init_ctrl_value & PC300_CTYPE_MASK) + card->type = PC300_X21; + else + card->type = PC300_RSV; + + if (pdev->device == PCI_DEVICE_ID_PC300_RX_1 || + pdev->device == PCI_DEVICE_ID_PC300_TE_1) + card->n_ports = 1; + else + card->n_ports = 2; + + for (i = 0; i < card->n_ports; i++) + if (!(card->ports[i].netdev = alloc_hdlcdev(&card->ports[i]))) { + printk(KERN_ERR "pc300: unable to allocate memory\n"); + pc300_pci_remove_one(pdev); + return -ENOMEM; + } + /* Reset PLX */ p = &card->plxbase->init_ctrl; writel(card->init_ctrl_value | 0x40000000, p); @@ -446,7 +422,7 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev, writew(0x0041, &card->plxbase->intr_ctrl_stat); /* Allocate IRQ */ - if (request_irq(pdev->irq, sca_intr, IRQF_SHARED, devname, card)) { + if (request_irq(pdev->irq, sca_intr, IRQF_SHARED, "pc300", card)) { printk(KERN_WARNING "pc300: could not allocate IRQ%d.\n", pdev->irq); pc300_pci_remove_one(pdev); @@ -463,9 +439,9 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev, for (i = 0; i < card->n_ports; i++) { port_t *port = &card->ports[i]; - struct net_device *dev = port_to_dev(port); + struct net_device *dev = port->netdev; hdlc_device *hdlc = dev_to_hdlc(dev); - port->phy_node = i; + port->chan = i; spin_lock_init(&port->lock); dev->irq = card->irq; @@ -484,6 +460,7 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev, else port->iface = IF_IFACE_V35; + sca_init_port(port); if (register_hdlc_device(dev)) { printk(KERN_ERR "pc300: unable to register hdlc " "device\n"); @@ -491,10 +468,9 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev, pc300_pci_remove_one(pdev); return -ENOBUFS; } - sca_init_sync_port(port); /* Set up SCA memory */ - printk(KERN_INFO "%s: PC300 node %d\n", - dev->name, port->phy_node); + printk(KERN_INFO "%s: PC300 channel %d\n", + dev->name, port->chan); } return 0; } @@ -524,9 +500,6 @@ static struct pci_driver pc300_pci_driver = { static int __init pc300_init_module(void) { -#ifdef MODULE - printk(KERN_INFO "%s\n", version); -#endif if (pci_clock_freq < 1000000 || pci_clock_freq > 80000000) { printk(KERN_ERR "pc300: Invalid PCI clock frequency\n"); return -EINVAL; diff --git a/drivers/net/wan/pci200syn.c b/drivers/net/wan/pci200syn.c index b595b64e753809205151ae658d61ca2014f46d43..1104d3a692f77b52b72bc4b3b6d7cb3056b5646e 100644 --- a/drivers/net/wan/pci200syn.c +++ b/drivers/net/wan/pci200syn.c @@ -1,7 +1,7 @@ /* * Goramo PCI200SYN synchronous serial card driver for Linux * - * Copyright (C) 2002-2003 Krzysztof Halasa + * Copyright (C) 2002-2008 Krzysztof Halasa * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -33,17 +33,11 @@ #include "hd64572.h" -static const char* version = "Goramo PCI200SYN driver version: 1.16"; -static const char* devname = "PCI200SYN"; - #undef DEBUG_PKT #define DEBUG_RINGS #define PCI200SYN_PLX_SIZE 0x80 /* PLX control window size (128b) */ #define PCI200SYN_SCA_SIZE 0x400 /* SCA window size (1Kb) */ -#define ALL_PAGES_ALWAYS_MAPPED -#define NEED_DETECT_RAM -#define NEED_SCA_MSCI_INTR #define MAX_TX_BUFFERS 10 static int pci_clock_freq = 33000000; @@ -68,7 +62,8 @@ typedef struct { typedef struct port_s { - struct net_device *dev; + struct napi_struct napi; + struct net_device *netdev; struct card_s *card; spinlock_t lock; /* TX lock */ sync_serial_settings settings; @@ -79,7 +74,7 @@ typedef struct port_s { u16 txin; /* tx ring buffer 'in' and 'last' pointers */ u16 txlast; u8 rxs, txs, tmc; /* SCA registers */ - u8 phy_node; /* physical port # - 0 or 1 */ + u8 chan; /* physical port # - 0 or 1 */ }port_t; @@ -97,17 +92,6 @@ typedef struct card_s { }card_t; -#define sca_in(reg, card) readb(card->scabase + (reg)) -#define sca_out(value, reg, card) writeb(value, card->scabase + (reg)) -#define sca_inw(reg, card) readw(card->scabase + (reg)) -#define sca_outw(value, reg, card) writew(value, card->scabase + (reg)) -#define sca_inl(reg, card) readl(card->scabase + (reg)) -#define sca_outl(value, reg, card) writel(value, card->scabase + (reg)) - -#define port_to_card(port) (port->card) -#define log_node(port) (port->phy_node) -#define phy_node(port) (port->phy_node) -#define winbase(card) (card->rambase) #define get_port(card, port) (&card->ports[port]) #define sca_flush(card) (sca_in(IER0, card)); @@ -127,7 +111,7 @@ static inline void new_memcpy_toio(char __iomem *dest, char *src, int length) #undef memcpy_toio #define memcpy_toio new_memcpy_toio -#include "hd6457x.c" +#include "hd64572.c" static void pci200_set_iface(port_t *port) @@ -137,8 +121,8 @@ static void pci200_set_iface(port_t *port) u8 rxs = port->rxs & CLK_BRG_MASK; u8 txs = port->txs & CLK_BRG_MASK; - sca_out(EXS_TES1, (phy_node(port) ? MSCI1_OFFSET : MSCI0_OFFSET) + EXS, - port_to_card(port)); + sca_out(EXS_TES1, (port->chan ? MSCI1_OFFSET : MSCI0_OFFSET) + EXS, + port->card); switch(port->settings.clock_type) { case CLOCK_INT: rxs |= CLK_BRG; /* BRG output */ @@ -180,7 +164,7 @@ static int pci200_open(struct net_device *dev) sca_open(dev); pci200_set_iface(port); - sca_flush(port_to_card(port)); + sca_flush(port->card); return 0; } @@ -189,7 +173,7 @@ static int pci200_open(struct net_device *dev) static int pci200_close(struct net_device *dev) { sca_close(dev); - sca_flush(port_to_card(dev_to_port(dev))); + sca_flush(dev_to_port(dev)->card); hdlc_close(dev); return 0; } @@ -242,7 +226,7 @@ static int pci200_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) memcpy(&port->settings, &new_line, size); /* Update settings */ pci200_set_iface(port); - sca_flush(port_to_card(port)); + sca_flush(port->card); return 0; default: @@ -258,10 +242,8 @@ static void pci200_pci_remove_one(struct pci_dev *pdev) card_t *card = pci_get_drvdata(pdev); for (i = 0; i < 2; i++) - if (card->ports[i].card) { - struct net_device *dev = port_to_dev(&card->ports[i]); - unregister_hdlc_device(dev); - } + if (card->ports[i].card) + unregister_hdlc_device(card->ports[i].netdev); if (card->irq) free_irq(card->irq, card); @@ -276,10 +258,10 @@ static void pci200_pci_remove_one(struct pci_dev *pdev) pci_release_regions(pdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); - if (card->ports[0].dev) - free_netdev(card->ports[0].dev); - if (card->ports[1].dev) - free_netdev(card->ports[1].dev); + if (card->ports[0].netdev) + free_netdev(card->ports[0].netdev); + if (card->ports[1].netdev) + free_netdev(card->ports[1].netdev); kfree(card); } @@ -296,12 +278,6 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev, u32 scaphys; /* SCA memory base */ u32 plxphys; /* PLX registers memory base */ -#ifndef MODULE - static int printed_version; - if (!printed_version++) - printk(KERN_INFO "%s\n", version); -#endif - i = pci_enable_device(pdev); if (i) return i; @@ -320,9 +296,9 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev, return -ENOBUFS; } pci_set_drvdata(pdev, card); - card->ports[0].dev = alloc_hdlcdev(&card->ports[0]); - card->ports[1].dev = alloc_hdlcdev(&card->ports[1]); - if (!card->ports[0].dev || !card->ports[1].dev) { + card->ports[0].netdev = alloc_hdlcdev(&card->ports[0]); + card->ports[1].netdev = alloc_hdlcdev(&card->ports[1]); + if (!card->ports[0].netdev || !card->ports[1].netdev) { printk(KERN_ERR "pci200syn: unable to allocate memory\n"); pci200_pci_remove_one(pdev); return -ENOMEM; @@ -343,7 +319,7 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev, card->scabase = ioremap(scaphys, PCI200SYN_SCA_SIZE); ramphys = pci_resource_start(pdev,3) & PCI_BASE_ADDRESS_MEM_MASK; - card->rambase = ioremap(ramphys, pci_resource_len(pdev,3)); + card->rambase = pci_ioremap_bar(pdev, 3); if (card->plxbase == NULL || card->scabase == NULL || @@ -398,7 +374,7 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev, writew(readw(p) | 0x0040, p); /* Allocate IRQ */ - if (request_irq(pdev->irq, sca_intr, IRQF_SHARED, devname, card)) { + if (request_irq(pdev->irq, sca_intr, IRQF_SHARED, "pci200syn", card)) { printk(KERN_WARNING "pci200syn: could not allocate IRQ%d.\n", pdev->irq); pci200_pci_remove_one(pdev); @@ -410,9 +386,9 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev, for (i = 0; i < 2; i++) { port_t *port = &card->ports[i]; - struct net_device *dev = port_to_dev(port); + struct net_device *dev = port->netdev; hdlc_device *hdlc = dev_to_hdlc(dev); - port->phy_node = i; + port->chan = i; spin_lock_init(&port->lock); dev->irq = card->irq; @@ -426,6 +402,7 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev, hdlc->xmit = sca_xmit; port->settings.clock_type = CLOCK_EXT; port->card = card; + sca_init_port(port); if (register_hdlc_device(dev)) { printk(KERN_ERR "pci200syn: unable to register hdlc " "device\n"); @@ -433,10 +410,9 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev, pci200_pci_remove_one(pdev); return -ENOBUFS; } - sca_init_sync_port(port); /* Set up SCA memory */ - printk(KERN_INFO "%s: PCI200SYN node %d\n", - dev->name, port->phy_node); + printk(KERN_INFO "%s: PCI200SYN channel %d\n", + dev->name, port->chan); } sca_flush(card); @@ -464,9 +440,6 @@ static struct pci_driver pci200_pci_driver = { static int __init pci200_init_module(void) { -#ifdef MODULE - printk(KERN_INFO "%s\n", version); -#endif if (pci_clock_freq < 1000000 || pci_clock_freq > 80000000) { printk(KERN_ERR "pci200syn: Invalid PCI clock frequency\n"); return -EINVAL; diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c index ee51b6a5e60569be9d955e2bb0259a5341d0f6f5..0aa28e1d436614bc98fa1954fda862d8eeec8574 100644 --- a/drivers/net/wan/sbni.c +++ b/drivers/net/wan/sbni.c @@ -186,6 +186,7 @@ static unsigned int netcard_portlist[ ] __initdata = { 0x2b0, 0x2b4, 0x2c0, 0x2c4, 0x2d0, 0x2d4, 0x2e0, 0x2e4, 0x2f0, 0x2f4, 0 }; +#define NET_LOCAL_LOCK(dev) (((struct net_local *)netdev_priv(dev))->lock) /* * Look for SBNI card which addr stored in dev->base_addr, if nonzero. @@ -287,7 +288,7 @@ static int __init sbni_init(struct net_device *dev) } -int __init +static int __init sbni_pci_probe( struct net_device *dev ) { struct pci_dev *pdev = NULL; @@ -378,22 +379,23 @@ sbni_probe1( struct net_device *dev, unsigned long ioaddr, int irq ) dev->irq = irq; dev->base_addr = ioaddr; - /* Allocate dev->priv and fill in sbni-specific dev fields. */ - nl = dev->priv; + /* Fill in sbni-specific dev fields. */ + nl = netdev_priv(dev); if( !nl ) { printk( KERN_ERR "%s: unable to get memory!\n", dev->name ); release_region( ioaddr, SBNI_IO_EXTENT ); return NULL; } - dev->priv = nl; memset( nl, 0, sizeof(struct net_local) ); spin_lock_init( &nl->lock ); /* store MAC address (generate if that isn't known) */ *(__be16 *)dev->dev_addr = htons( 0x00ff ); *(__be32 *)(dev->dev_addr + 2) = htonl( 0x01000000 | - ( (mac[num] ? mac[num] : (u32)((long)dev->priv)) & 0x00ffffff) ); + ((mac[num] ? + mac[num] : + (u32)((long)netdev_priv(dev))) & 0x00ffffff)); /* store link settings (speed, receive level ) */ nl->maxframe = DEFAULT_FRAME_LEN; @@ -447,7 +449,7 @@ sbni_start_xmit( struct sk_buff *skb, struct net_device *dev ) /* Looking for idle device in the list */ for( p = dev; p; ) { - struct net_local *nl = (struct net_local *) p->priv; + struct net_local *nl = netdev_priv(p); spin_lock( &nl->lock ); if( nl->tx_buf_p || (nl->state & FL_LINE_DOWN) ) { p = nl->link; @@ -469,7 +471,7 @@ sbni_start_xmit( struct sk_buff *skb, struct net_device *dev ) static int sbni_start_xmit( struct sk_buff *skb, struct net_device *dev ) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); netif_stop_queue( dev ); spin_lock( &nl->lock ); @@ -503,12 +505,12 @@ static irqreturn_t sbni_interrupt( int irq, void *dev_id ) { struct net_device *dev = dev_id; - struct net_local *nl = dev->priv; + struct net_local *nl = netdev_priv(dev); int repeat; spin_lock( &nl->lock ); if( nl->second ) - spin_lock( &((struct net_local *) nl->second->priv)->lock ); + spin_lock(&NET_LOCAL_LOCK(nl->second)); do { repeat = 0; @@ -522,7 +524,7 @@ sbni_interrupt( int irq, void *dev_id ) } while( repeat ); if( nl->second ) - spin_unlock( &((struct net_local *)nl->second->priv)->lock ); + spin_unlock(&NET_LOCAL_LOCK(nl->second)); spin_unlock( &nl->lock ); return IRQ_HANDLED; } @@ -531,7 +533,7 @@ sbni_interrupt( int irq, void *dev_id ) static void handle_channel( struct net_device *dev ) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; int req_ans; @@ -540,7 +542,7 @@ handle_channel( struct net_device *dev ) #ifdef CONFIG_SBNI_MULTILINE /* Lock the master device because we going to change its local data */ if( nl->state & FL_SLAVE ) - spin_lock( &((struct net_local *) nl->master->priv)->lock ); + spin_lock(&NET_LOCAL_LOCK(nl->master)); #endif outb( (inb( ioaddr + CSR0 ) & ~EN_INT) | TR_REQ, ioaddr + CSR0 ); @@ -576,7 +578,7 @@ handle_channel( struct net_device *dev ) #ifdef CONFIG_SBNI_MULTILINE if( nl->state & FL_SLAVE ) - spin_unlock( &((struct net_local *) nl->master->priv)->lock ); + spin_unlock(&NET_LOCAL_LOCK(nl->master)); #endif } @@ -589,7 +591,7 @@ handle_channel( struct net_device *dev ) static int recv_frame( struct net_device *dev ) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; u32 crc = CRC32_INITIAL; @@ -623,7 +625,7 @@ recv_frame( struct net_device *dev ) static void send_frame( struct net_device *dev ) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); u32 crc = CRC32_INITIAL; @@ -680,7 +682,7 @@ send_frame( struct net_device *dev ) static void download_data( struct net_device *dev, u32 *crc_p ) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); struct sk_buff *skb = nl->tx_buf_p; unsigned len = min_t(unsigned int, skb->len - nl->outpos, nl->framelen); @@ -699,7 +701,7 @@ static int upload_data( struct net_device *dev, unsigned framelen, unsigned frameno, unsigned is_first, u32 crc ) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); int frame_ok; @@ -721,9 +723,9 @@ upload_data( struct net_device *dev, unsigned framelen, unsigned frameno, nl->wait_frameno = 0, nl->inppos = 0, #ifdef CONFIG_SBNI_MULTILINE - ((struct net_local *) nl->master->priv) + ((struct net_local *)netdev_priv(nl->master)) ->stats.rx_errors++, - ((struct net_local *) nl->master->priv) + ((struct net_local *)netdev_priv(nl->master)) ->stats.rx_missed_errors++; #else nl->stats.rx_errors++, @@ -740,8 +742,10 @@ upload_data( struct net_device *dev, unsigned framelen, unsigned frameno, */ nl->wait_frameno = 0, #ifdef CONFIG_SBNI_MULTILINE - ((struct net_local *) nl->master->priv)->stats.rx_errors++, - ((struct net_local *) nl->master->priv)->stats.rx_crc_errors++; + ((struct net_local *)netdev_priv(nl->master)) + ->stats.rx_errors++, + ((struct net_local *)netdev_priv(nl->master)) + ->stats.rx_crc_errors++; #else nl->stats.rx_errors++, nl->stats.rx_crc_errors++; @@ -755,8 +759,8 @@ static inline void send_complete( struct net_local *nl ) { #ifdef CONFIG_SBNI_MULTILINE - ((struct net_local *) nl->master->priv)->stats.tx_packets++; - ((struct net_local *) nl->master->priv)->stats.tx_bytes + ((struct net_local *)netdev_priv(nl->master))->stats.tx_packets++; + ((struct net_local *)netdev_priv(nl->master))->stats.tx_bytes += nl->tx_buf_p->len; #else nl->stats.tx_packets++; @@ -775,7 +779,7 @@ send_complete( struct net_local *nl ) static void interpret_ack( struct net_device *dev, unsigned ack ) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); if( ack == FRAME_SENT_OK ) { nl->state &= ~FL_NEED_RESEND; @@ -809,7 +813,7 @@ interpret_ack( struct net_device *dev, unsigned ack ) static int append_frame_to_pkt( struct net_device *dev, unsigned framelen, u32 crc ) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); u8 *p; @@ -840,7 +844,7 @@ append_frame_to_pkt( struct net_device *dev, unsigned framelen, u32 crc ) static void prepare_to_send( struct sk_buff *skb, struct net_device *dev ) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); unsigned int len; @@ -871,15 +875,15 @@ prepare_to_send( struct sk_buff *skb, struct net_device *dev ) static void drop_xmit_queue( struct net_device *dev ) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); if( nl->tx_buf_p ) dev_kfree_skb_any( nl->tx_buf_p ), nl->tx_buf_p = NULL, #ifdef CONFIG_SBNI_MULTILINE - ((struct net_local *) nl->master->priv) + ((struct net_local *)netdev_priv(nl->master)) ->stats.tx_errors++, - ((struct net_local *) nl->master->priv) + ((struct net_local *)netdev_priv(nl->master)) ->stats.tx_carrier_errors++; #else nl->stats.tx_errors++, @@ -903,7 +907,7 @@ drop_xmit_queue( struct net_device *dev ) static void send_frame_header( struct net_device *dev, u32 *crc_p ) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); u32 crc = *crc_p; u32 len_field = nl->framelen + 6; /* CRC + frameno + reserved */ @@ -1005,7 +1009,7 @@ get_rx_buf( struct net_device *dev ) static void indicate_pkt( struct net_device *dev ) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); struct sk_buff *skb = nl->rx_buf_p; skb_put( skb, nl->inppos ); @@ -1013,13 +1017,12 @@ indicate_pkt( struct net_device *dev ) #ifdef CONFIG_SBNI_MULTILINE skb->protocol = eth_type_trans( skb, nl->master ); netif_rx( skb ); - dev->last_rx = jiffies; - ++((struct net_local *) nl->master->priv)->stats.rx_packets; - ((struct net_local *) nl->master->priv)->stats.rx_bytes += nl->inppos; + ++((struct net_local *)netdev_priv(nl->master))->stats.rx_packets; + ((struct net_local *)netdev_priv(nl->master))->stats.rx_bytes += + nl->inppos; #else skb->protocol = eth_type_trans( skb, dev ); netif_rx( skb ); - dev->last_rx = jiffies; ++nl->stats.rx_packets; nl->stats.rx_bytes += nl->inppos; #endif @@ -1038,7 +1041,7 @@ static void sbni_watchdog( unsigned long arg ) { struct net_device *dev = (struct net_device *) arg; - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); struct timer_list *w = &nl->watchdog; unsigned long flags; unsigned char csr0; @@ -1091,7 +1094,7 @@ static unsigned char timeout_rxl_tab[] = { static void card_start( struct net_device *dev ) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); nl->timer_ticks = CHANGE_LEVEL_START_TICKS; nl->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND); @@ -1113,7 +1116,7 @@ card_start( struct net_device *dev ) static void change_level( struct net_device *dev ) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); if( nl->delta_rxl == 0 ) /* do not auto-negotiate RxL */ return; @@ -1137,7 +1140,7 @@ change_level( struct net_device *dev ) static void timeout_change_level( struct net_device *dev ) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); nl->cur_rxl_index = timeout_rxl_tab[ nl->timeout_rxl ]; if( ++nl->timeout_rxl >= 4 ) @@ -1160,7 +1163,7 @@ timeout_change_level( struct net_device *dev ) static int sbni_open( struct net_device *dev ) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); struct timer_list *w = &nl->watchdog; /* @@ -1176,7 +1179,7 @@ sbni_open( struct net_device *dev ) || (*p)->base_addr == dev->base_addr - 4) && (*p)->flags & IFF_UP ) { - ((struct net_local *) ((*p)->priv)) + ((struct net_local *) (netdev_priv(*p))) ->second = dev; printk( KERN_NOTICE "%s: using shared irq " "with %s\n", dev->name, (*p)->name ); @@ -1216,7 +1219,7 @@ sbni_open( struct net_device *dev ) static int sbni_close( struct net_device *dev ) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); if( nl->second && nl->second->flags & IFF_UP ) { printk( KERN_NOTICE "Secondary channel (%s) is active!\n", @@ -1300,7 +1303,7 @@ sbni_card_probe( unsigned long ioaddr ) static int sbni_ioctl( struct net_device *dev, struct ifreq *ifr, int cmd ) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); struct sbni_flags flags; int error = 0; @@ -1390,8 +1393,8 @@ sbni_ioctl( struct net_device *dev, struct ifreq *ifr, int cmd ) static int enslave( struct net_device *dev, struct net_device *slave_dev ) { - struct net_local *nl = (struct net_local *) dev->priv; - struct net_local *snl = (struct net_local *) slave_dev->priv; + struct net_local *nl = netdev_priv(dev); + struct net_local *snl = netdev_priv(slave_dev); if( nl->state & FL_SLAVE ) /* This isn't master or free device */ return -EBUSY; @@ -1425,9 +1428,9 @@ enslave( struct net_device *dev, struct net_device *slave_dev ) static int emancipate( struct net_device *dev ) { - struct net_local *snl = (struct net_local *) dev->priv; + struct net_local *snl = netdev_priv(dev); struct net_device *p = snl->master; - struct net_local *nl = (struct net_local *) p->priv; + struct net_local *nl = netdev_priv(p); if( !(snl->state & FL_SLAVE) ) return -EINVAL; @@ -1438,7 +1441,7 @@ emancipate( struct net_device *dev ) /* exclude from list */ for(;;) { /* must be in list */ - struct net_local *t = (struct net_local *) p->priv; + struct net_local *t = netdev_priv(p); if( t->link == dev ) { t->link = snl->link; break; @@ -1465,7 +1468,7 @@ emancipate( struct net_device *dev ) static struct net_device_stats * sbni_get_stats( struct net_device *dev ) { - return &((struct net_local *) dev->priv)->stats; + return &((struct net_local *)netdev_priv(dev))->stats; } diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c index 73e2f278093220e4bd3f8f5094c9ab55a1d190f5..6a07ba9371dbd5b0cd257eb87c1cf11cecd7bdcd 100644 --- a/drivers/net/wan/sdla.c +++ b/drivers/net/wan/sdla.c @@ -185,7 +185,7 @@ static void sdla_stop(struct net_device *dev) { struct frad_local *flp; - flp = dev->priv; + flp = netdev_priv(dev); switch(flp->type) { case SDLA_S502A: @@ -212,7 +212,7 @@ static void sdla_start(struct net_device *dev) { struct frad_local *flp; - flp = dev->priv; + flp = netdev_priv(dev); switch(flp->type) { case SDLA_S502A: @@ -432,7 +432,7 @@ static int sdla_cmd(struct net_device *dev, int cmd, short dlci, short flags, int ret, waiting, len; long window; - flp = dev->priv; + flp = netdev_priv(dev); window = flp->type == SDLA_S508 ? SDLA_508_CMD_BUF : SDLA_502_CMD_BUF; cmd_buf = (struct sdla_cmd *)(dev->mem_start + (window & SDLA_ADDR_MASK)); ret = 0; @@ -509,7 +509,7 @@ static int sdla_activate(struct net_device *slave, struct net_device *master) struct frad_local *flp; int i; - flp = slave->priv; + flp = netdev_priv(slave); for(i=0;imaster[i] == master) @@ -531,7 +531,7 @@ static int sdla_deactivate(struct net_device *slave, struct net_device *master) struct frad_local *flp; int i; - flp = slave->priv; + flp = netdev_priv(slave); for(i=0;imaster[i] == master) @@ -556,7 +556,7 @@ static int sdla_assoc(struct net_device *slave, struct net_device *master) if (master->type != ARPHRD_DLCI) return(-EINVAL); - flp = slave->priv; + flp = netdev_priv(slave); for(i=0;ipriv; + flp = netdev_priv(slave); for(i=0;imaster[i] == master) @@ -619,7 +619,7 @@ static int sdla_dlci_conf(struct net_device *slave, struct net_device *master, i int i; short len, ret; - flp = slave->priv; + flp = netdev_priv(slave); for(i=0;imaster[i] == master) @@ -628,7 +628,7 @@ static int sdla_dlci_conf(struct net_device *slave, struct net_device *master, i if (i == CONFIG_DLCI_MAX) return(-ENODEV); - dlp = master->priv; + dlp = netdev_priv(master); ret = SDLA_RET_OK; len = sizeof(struct dlci_conf); @@ -659,7 +659,7 @@ static int sdla_transmit(struct sk_buff *skb, struct net_device *dev) unsigned long flags; struct buf_entry *pbuf; - flp = dev->priv; + flp = netdev_priv(dev); ret = 0; accept = 1; @@ -755,7 +755,7 @@ static void sdla_receive(struct net_device *dev) int i=0, received, success, addr, buf_base, buf_top; short dlci, len, len2, split; - flp = dev->priv; + flp = netdev_priv(dev); success = 1; received = addr = buf_top = buf_base = 0; len = dlci = 0; @@ -860,7 +860,7 @@ static void sdla_receive(struct net_device *dev) if (success) { flp->stats.rx_packets++; - dlp = master->priv; + dlp = netdev_priv(master); (*dlp->receive)(skb, master); } @@ -925,7 +925,7 @@ static void sdla_poll(unsigned long device) struct frad_local *flp; dev = (struct net_device *) device; - flp = dev->priv; + flp = netdev_priv(dev); if (sdla_byte(dev, SDLA_502_RCV_BUF)) sdla_receive(dev); @@ -941,7 +941,7 @@ static int sdla_close(struct net_device *dev) int len, i; short dlcis[CONFIG_DLCI_MAX]; - flp = dev->priv; + flp = netdev_priv(dev); len = 0; for(i=0;ipriv; + flp = netdev_priv(dev); if (!flp->initialized) return(-EPERM); @@ -1079,7 +1079,7 @@ static int sdla_open(struct net_device *dev) for(i=0;idlci[i]) { - dlp = flp->master[i]->priv; + dlp = netdev_priv(flp->master[i]); if (dlp->configured) sdla_cmd(dev, SDLA_SET_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0, &dlp->config, sizeof(struct dlci_conf), NULL, NULL); } @@ -1099,7 +1099,7 @@ static int sdla_config(struct net_device *dev, struct frad_conf __user *conf, in if (dev->type == 0xFFFF) return(-EUNATCH); - flp = dev->priv; + flp = netdev_priv(dev); if (!get) { @@ -1230,7 +1230,7 @@ static int sdla_reconfig(struct net_device *dev) struct conf_data data; int i, len; - flp = dev->priv; + flp = netdev_priv(dev); len = 0; for(i=0;ipriv; + flp = netdev_priv(dev); if (!flp->initialized) return(-EINVAL); @@ -1321,7 +1321,7 @@ static int sdla_change_mtu(struct net_device *dev, int new_mtu) { struct frad_local *flp; - flp = dev->priv; + flp = netdev_priv(dev); if (netif_running(dev)) return(-EBUSY); @@ -1338,7 +1338,7 @@ static int sdla_set_config(struct net_device *dev, struct ifmap *map) unsigned base; int err = -EINVAL; - flp = dev->priv; + flp = netdev_priv(dev); if (flp->initialized) return(-EINVAL); @@ -1593,14 +1593,14 @@ static int sdla_set_config(struct net_device *dev, struct ifmap *map) static struct net_device_stats *sdla_stats(struct net_device *dev) { struct frad_local *flp; - flp = dev->priv; + flp = netdev_priv(dev); return(&flp->stats); } static void setup_sdla(struct net_device *dev) { - struct frad_local *flp = dev->priv; + struct frad_local *flp = netdev_priv(dev); netdev_boot_setup_check(dev); @@ -1651,7 +1651,7 @@ static int __init init_sdla(void) static void __exit exit_sdla(void) { - struct frad_local *flp = sdla->priv; + struct frad_local *flp = netdev_priv(sdla); unregister_netdev(sdla); if (flp->initialized) { diff --git a/drivers/net/wan/sealevel.c b/drivers/net/wan/sealevel.c index c0235844a4d594e5cee2b243d4105b54c0f47eb9..0941a26f6e3f9b94d794bc2f43ecce49a35290cb 100644 --- a/drivers/net/wan/sealevel.c +++ b/drivers/net/wan/sealevel.c @@ -68,7 +68,6 @@ static void sealevel_input(struct z8530_channel *c, struct sk_buff *skb) skb_reset_mac_header(skb); skb->dev = c->netdevice; netif_rx(skb); - c->netdevice->last_rx = jiffies; } /* diff --git a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c deleted file mode 100644 index 6e92f7b44b1aa6d315d84898ce6a990b96ed3a0a..0000000000000000000000000000000000000000 --- a/drivers/net/wan/syncppp.c +++ /dev/null @@ -1,1480 +0,0 @@ -/* - * NET3: A (fairly minimal) implementation of synchronous PPP for Linux - * as well as a CISCO HDLC implementation. See the copyright - * message below for the original source. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the license, or (at your option) any later version. - * - * Note however. This code is also used in a different form by FreeBSD. - * Therefore when making any non OS specific change please consider - * contributing it back to the original author under the terms - * below in addition. - * -- Alan - * - * Port for Linux-2.1 by Jan "Yenya" Kasprzak - */ - -/* - * Synchronous PPP/Cisco link level subroutines. - * Keepalive protocol implemented in both Cisco and PPP modes. - * - * Copyright (C) 1994 Cronyx Ltd. - * Author: Serge Vakulenko, - * - * This software is distributed with NO WARRANTIES, not even the implied - * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Authors grant any other persons or organisations permission to use - * or modify this software as long as this message is kept with the software, - * all derivative works or modified versions. - * - * Version 1.9, Wed Oct 4 18:58:15 MSK 1995 - * - * $Id: syncppp.c,v 1.18 2000/04/11 05:25:31 asj Exp $ - */ -#undef DEBUG - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#define MAXALIVECNT 6 /* max. alive packets */ - -#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */ -#define PPP_UI 0x03 /* Unnumbered Information */ -#define PPP_IP 0x0021 /* Internet Protocol */ -#define PPP_ISO 0x0023 /* ISO OSI Protocol */ -#define PPP_XNS 0x0025 /* Xerox NS Protocol */ -#define PPP_IPX 0x002b /* Novell IPX Protocol */ -#define PPP_LCP 0xc021 /* Link Control Protocol */ -#define PPP_IPCP 0x8021 /* Internet Protocol Control Protocol */ - -#define LCP_CONF_REQ 1 /* PPP LCP configure request */ -#define LCP_CONF_ACK 2 /* PPP LCP configure acknowledge */ -#define LCP_CONF_NAK 3 /* PPP LCP configure negative ack */ -#define LCP_CONF_REJ 4 /* PPP LCP configure reject */ -#define LCP_TERM_REQ 5 /* PPP LCP terminate request */ -#define LCP_TERM_ACK 6 /* PPP LCP terminate acknowledge */ -#define LCP_CODE_REJ 7 /* PPP LCP code reject */ -#define LCP_PROTO_REJ 8 /* PPP LCP protocol reject */ -#define LCP_ECHO_REQ 9 /* PPP LCP echo request */ -#define LCP_ECHO_REPLY 10 /* PPP LCP echo reply */ -#define LCP_DISC_REQ 11 /* PPP LCP discard request */ - -#define LCP_OPT_MRU 1 /* maximum receive unit */ -#define LCP_OPT_ASYNC_MAP 2 /* async control character map */ -#define LCP_OPT_AUTH_PROTO 3 /* authentication protocol */ -#define LCP_OPT_QUAL_PROTO 4 /* quality protocol */ -#define LCP_OPT_MAGIC 5 /* magic number */ -#define LCP_OPT_RESERVED 6 /* reserved */ -#define LCP_OPT_PROTO_COMP 7 /* protocol field compression */ -#define LCP_OPT_ADDR_COMP 8 /* address/control field compression */ - -#define IPCP_CONF_REQ LCP_CONF_REQ /* PPP IPCP configure request */ -#define IPCP_CONF_ACK LCP_CONF_ACK /* PPP IPCP configure acknowledge */ -#define IPCP_CONF_NAK LCP_CONF_NAK /* PPP IPCP configure negative ack */ -#define IPCP_CONF_REJ LCP_CONF_REJ /* PPP IPCP configure reject */ -#define IPCP_TERM_REQ LCP_TERM_REQ /* PPP IPCP terminate request */ -#define IPCP_TERM_ACK LCP_TERM_ACK /* PPP IPCP terminate acknowledge */ -#define IPCP_CODE_REJ LCP_CODE_REJ /* PPP IPCP code reject */ - -#define CISCO_MULTICAST 0x8f /* Cisco multicast address */ -#define CISCO_UNICAST 0x0f /* Cisco unicast address */ -#define CISCO_KEEPALIVE 0x8035 /* Cisco keepalive protocol */ -#define CISCO_ADDR_REQ 0 /* Cisco address request */ -#define CISCO_ADDR_REPLY 1 /* Cisco address reply */ -#define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */ - -struct ppp_header { - u8 address; - u8 control; - __be16 protocol; -}; -#define PPP_HEADER_LEN sizeof (struct ppp_header) - -struct lcp_header { - u8 type; - u8 ident; - __be16 len; -}; -#define LCP_HEADER_LEN sizeof (struct lcp_header) - -struct cisco_packet { - __be32 type; - __be32 par1; - __be32 par2; - __be16 rel; - __be16 time0; - __be16 time1; -}; -#define CISCO_PACKET_LEN 18 -#define CISCO_BIG_PACKET_LEN 20 - -static struct sppp *spppq; -static struct timer_list sppp_keepalive_timer; -static DEFINE_SPINLOCK(spppq_lock); - -/* global xmit queue for sending packets while spinlock is held */ -static struct sk_buff_head tx_queue; - -static void sppp_keepalive (unsigned long dummy); -static void sppp_cp_send (struct sppp *sp, u16 proto, u8 type, - u8 ident, u16 len, void *data); -static void sppp_cisco_send (struct sppp *sp, int type, u32 par1, u32 par2); -static void sppp_lcp_input (struct sppp *sp, struct sk_buff *m); -static void sppp_cisco_input (struct sppp *sp, struct sk_buff *m); -static void sppp_ipcp_input (struct sppp *sp, struct sk_buff *m); -static void sppp_lcp_open (struct sppp *sp); -static void sppp_ipcp_open (struct sppp *sp); -static int sppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h, - int len, u32 *magic); -static void sppp_cp_timeout (unsigned long arg); -static char *sppp_lcp_type_name (u8 type); -static char *sppp_ipcp_type_name (u8 type); -static void sppp_print_bytes (u8 *p, u16 len); - -static int debug; - -/* Flush global outgoing packet queue to dev_queue_xmit(). - * - * dev_queue_xmit() must be called with interrupts enabled - * which means it can't be called with spinlocks held. - * If a packet needs to be sent while a spinlock is held, - * then put the packet into tx_queue, and call sppp_flush_xmit() - * after spinlock is released. - */ -static void sppp_flush_xmit(void) -{ - struct sk_buff *skb; - while ((skb = skb_dequeue(&tx_queue)) != NULL) - dev_queue_xmit(skb); -} - -/* - * Interface down stub - */ - -static void if_down(struct net_device *dev) -{ - struct sppp *sp = (struct sppp *)sppp_of(dev); - - sp->pp_link_state=SPPP_LINK_DOWN; -} - -/* - * Timeout routine activations. - */ - -static void sppp_set_timeout(struct sppp *p,int s) -{ - if (! (p->pp_flags & PP_TIMO)) - { - init_timer(&p->pp_timer); - p->pp_timer.function=sppp_cp_timeout; - p->pp_timer.expires=jiffies+s*HZ; - p->pp_timer.data=(unsigned long)p; - p->pp_flags |= PP_TIMO; - add_timer(&p->pp_timer); - } -} - -static void sppp_clear_timeout(struct sppp *p) -{ - if (p->pp_flags & PP_TIMO) - { - del_timer(&p->pp_timer); - p->pp_flags &= ~PP_TIMO; - } -} - -/** - * sppp_input - receive and process a WAN PPP frame - * @skb: The buffer to process - * @dev: The device it arrived on - * - * This can be called directly by cards that do not have - * timing constraints but is normally called from the network layer - * after interrupt servicing to process frames queued via netif_rx(). - * - * We process the options in the card. If the frame is destined for - * the protocol stacks then it requeues the frame for the upper level - * protocol. If it is a control from it is processed and discarded - * here. - */ - -static void sppp_input (struct net_device *dev, struct sk_buff *skb) -{ - struct ppp_header *h; - struct sppp *sp = (struct sppp *)sppp_of(dev); - unsigned long flags; - - skb->dev=dev; - skb_reset_mac_header(skb); - - if (!pskb_may_pull(skb, PPP_HEADER_LEN)) { - /* Too small packet, drop it. */ - if (sp->pp_flags & PP_DEBUG) - printk (KERN_DEBUG "%s: input packet is too small, %d bytes\n", - dev->name, skb->len); - kfree_skb(skb); - return; - } - - /* Get PPP header. */ - h = (struct ppp_header *)skb->data; - skb_pull(skb,sizeof(struct ppp_header)); - - spin_lock_irqsave(&sp->lock, flags); - - switch (h->address) { - default: /* Invalid PPP packet. */ - goto invalid; - case PPP_ALLSTATIONS: - if (h->control != PPP_UI) - goto invalid; - if (sp->pp_flags & PP_CISCO) { - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: PPP packet in Cisco mode <0x%x 0x%x 0x%x>\n", - dev->name, - h->address, h->control, ntohs (h->protocol)); - goto drop; - } - switch (ntohs (h->protocol)) { - default: - if (sp->lcp.state == LCP_STATE_OPENED) - sppp_cp_send (sp, PPP_LCP, LCP_PROTO_REJ, - ++sp->pp_seq, skb->len + 2, - &h->protocol); - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: invalid input protocol <0x%x 0x%x 0x%x>\n", - dev->name, - h->address, h->control, ntohs (h->protocol)); - goto drop; - case PPP_LCP: - sppp_lcp_input (sp, skb); - goto drop; - case PPP_IPCP: - if (sp->lcp.state == LCP_STATE_OPENED) - sppp_ipcp_input (sp, skb); - else - printk(KERN_DEBUG "IPCP when still waiting LCP finish.\n"); - goto drop; - case PPP_IP: - if (sp->ipcp.state == IPCP_STATE_OPENED) { - if(sp->pp_flags&PP_DEBUG) - printk(KERN_DEBUG "Yow an IP frame.\n"); - skb->protocol=htons(ETH_P_IP); - netif_rx(skb); - dev->last_rx = jiffies; - goto done; - } - break; -#ifdef IPX - case PPP_IPX: - /* IPX IPXCP not implemented yet */ - if (sp->lcp.state == LCP_STATE_OPENED) { - skb->protocol=htons(ETH_P_IPX); - netif_rx(skb); - dev->last_rx = jiffies; - goto done; - } - break; -#endif - } - break; - case CISCO_MULTICAST: - case CISCO_UNICAST: - /* Don't check the control field here (RFC 1547). */ - if (! (sp->pp_flags & PP_CISCO)) { - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: Cisco packet in PPP mode <0x%x 0x%x 0x%x>\n", - dev->name, - h->address, h->control, ntohs (h->protocol)); - goto drop; - } - switch (ntohs (h->protocol)) { - default: - goto invalid; - case CISCO_KEEPALIVE: - sppp_cisco_input (sp, skb); - goto drop; -#ifdef CONFIG_INET - case ETH_P_IP: - skb->protocol=htons(ETH_P_IP); - netif_rx(skb); - dev->last_rx = jiffies; - goto done; -#endif -#ifdef CONFIG_IPX - case ETH_P_IPX: - skb->protocol=htons(ETH_P_IPX); - netif_rx(skb); - dev->last_rx = jiffies; - goto done; -#endif - } - break; - } - goto drop; - -invalid: - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: invalid input packet <0x%x 0x%x 0x%x>\n", - dev->name, h->address, h->control, ntohs (h->protocol)); -drop: - kfree_skb(skb); -done: - spin_unlock_irqrestore(&sp->lock, flags); - sppp_flush_xmit(); - return; -} - -/* - * Handle transmit packets. - */ - -static int sppp_hard_header(struct sk_buff *skb, - struct net_device *dev, __u16 type, - const void *daddr, const void *saddr, - unsigned int len) -{ - struct sppp *sp = (struct sppp *)sppp_of(dev); - struct ppp_header *h; - skb_push(skb,sizeof(struct ppp_header)); - h=(struct ppp_header *)skb->data; - if(sp->pp_flags&PP_CISCO) - { - h->address = CISCO_UNICAST; - h->control = 0; - } - else - { - h->address = PPP_ALLSTATIONS; - h->control = PPP_UI; - } - if(sp->pp_flags & PP_CISCO) - { - h->protocol = htons(type); - } - else switch(type) - { - case ETH_P_IP: - h->protocol = htons(PPP_IP); - break; - case ETH_P_IPX: - h->protocol = htons(PPP_IPX); - break; - } - return sizeof(struct ppp_header); -} - -static const struct header_ops sppp_header_ops = { - .create = sppp_hard_header, -}; - -/* - * Send keepalive packets, every 10 seconds. - */ - -static void sppp_keepalive (unsigned long dummy) -{ - struct sppp *sp; - unsigned long flags; - - spin_lock_irqsave(&spppq_lock, flags); - - for (sp=spppq; sp; sp=sp->pp_next) - { - struct net_device *dev = sp->pp_if; - - /* Keepalive mode disabled or channel down? */ - if (! (sp->pp_flags & PP_KEEPALIVE) || - ! (dev->flags & IFF_UP)) - continue; - - spin_lock(&sp->lock); - - /* No keepalive in PPP mode if LCP not opened yet. */ - if (! (sp->pp_flags & PP_CISCO) && - sp->lcp.state != LCP_STATE_OPENED) { - spin_unlock(&sp->lock); - continue; - } - - if (sp->pp_alivecnt == MAXALIVECNT) { - /* No keepalive packets got. Stop the interface. */ - printk (KERN_WARNING "%s: protocol down\n", dev->name); - if_down (dev); - if (! (sp->pp_flags & PP_CISCO)) { - /* Shut down the PPP link. */ - sp->lcp.magic = jiffies; - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; - sppp_clear_timeout (sp); - /* Initiate negotiation. */ - sppp_lcp_open (sp); - } - } - if (sp->pp_alivecnt <= MAXALIVECNT) - ++sp->pp_alivecnt; - if (sp->pp_flags & PP_CISCO) - sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ, ++sp->pp_seq, - sp->pp_rseq); - else if (sp->lcp.state == LCP_STATE_OPENED) { - __be32 nmagic = htonl (sp->lcp.magic); - sp->lcp.echoid = ++sp->pp_seq; - sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REQ, - sp->lcp.echoid, 4, &nmagic); - } - - spin_unlock(&sp->lock); - } - spin_unlock_irqrestore(&spppq_lock, flags); - sppp_flush_xmit(); - sppp_keepalive_timer.expires=jiffies+10*HZ; - add_timer(&sppp_keepalive_timer); -} - -/* - * Handle incoming PPP Link Control Protocol packets. - */ - -static void sppp_lcp_input (struct sppp *sp, struct sk_buff *skb) -{ - struct lcp_header *h; - struct net_device *dev = sp->pp_if; - int len = skb->len; - u8 *p, opt[6]; - u32 rmagic = 0; - - if (!pskb_may_pull(skb, sizeof(struct lcp_header))) { - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: invalid lcp packet length: %d bytes\n", - dev->name, len); - return; - } - h = (struct lcp_header *)skb->data; - skb_pull(skb,sizeof(struct lcp_header *)); - - if (sp->pp_flags & PP_DEBUG) - { - char state = '?'; - switch (sp->lcp.state) { - case LCP_STATE_CLOSED: state = 'C'; break; - case LCP_STATE_ACK_RCVD: state = 'R'; break; - case LCP_STATE_ACK_SENT: state = 'S'; break; - case LCP_STATE_OPENED: state = 'O'; break; - } - printk (KERN_WARNING "%s: lcp input(%c): %d bytes <%s id=%xh len=%xh", - dev->name, state, len, - sppp_lcp_type_name (h->type), h->ident, ntohs (h->len)); - if (len > 4) - sppp_print_bytes ((u8*) (h+1), len-4); - printk (">\n"); - } - if (len > ntohs (h->len)) - len = ntohs (h->len); - switch (h->type) { - default: - /* Unknown packet type -- send Code-Reject packet. */ - sppp_cp_send (sp, PPP_LCP, LCP_CODE_REJ, ++sp->pp_seq, - skb->len, h); - break; - case LCP_CONF_REQ: - if (len < 4) { - if (sp->pp_flags & PP_DEBUG) - printk (KERN_DEBUG"%s: invalid lcp configure request packet length: %d bytes\n", - dev->name, len); - break; - } - if (len>4 && !sppp_lcp_conf_parse_options (sp, h, len, &rmagic)) - goto badreq; - if (rmagic == sp->lcp.magic) { - /* Local and remote magics equal -- loopback? */ - if (sp->pp_loopcnt >= MAXALIVECNT*5) { - printk (KERN_WARNING "%s: loopback\n", - dev->name); - sp->pp_loopcnt = 0; - if (dev->flags & IFF_UP) { - if_down (dev); - } - } else if (sp->pp_flags & PP_DEBUG) - printk (KERN_DEBUG "%s: conf req: magic glitch\n", - dev->name); - ++sp->pp_loopcnt; - - /* MUST send Conf-Nack packet. */ - rmagic = ~sp->lcp.magic; - opt[0] = LCP_OPT_MAGIC; - opt[1] = sizeof (opt); - opt[2] = rmagic >> 24; - opt[3] = rmagic >> 16; - opt[4] = rmagic >> 8; - opt[5] = rmagic; - sppp_cp_send (sp, PPP_LCP, LCP_CONF_NAK, - h->ident, sizeof (opt), &opt); -badreq: - switch (sp->lcp.state) { - case LCP_STATE_OPENED: - /* Initiate renegotiation. */ - sppp_lcp_open (sp); - /* fall through... */ - case LCP_STATE_ACK_SENT: - /* Go to closed state. */ - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; - } - break; - } - /* Send Configure-Ack packet. */ - sp->pp_loopcnt = 0; - if (sp->lcp.state != LCP_STATE_OPENED) { - sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK, - h->ident, len-4, h+1); - } - /* Change the state. */ - switch (sp->lcp.state) { - case LCP_STATE_CLOSED: - sp->lcp.state = LCP_STATE_ACK_SENT; - break; - case LCP_STATE_ACK_RCVD: - sp->lcp.state = LCP_STATE_OPENED; - sppp_ipcp_open (sp); - break; - case LCP_STATE_OPENED: - /* Remote magic changed -- close session. */ - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; - /* Initiate renegotiation. */ - sppp_lcp_open (sp); - /* Send ACK after our REQ in attempt to break loop */ - sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK, - h->ident, len-4, h+1); - sp->lcp.state = LCP_STATE_ACK_SENT; - break; - } - break; - case LCP_CONF_ACK: - if (h->ident != sp->lcp.confid) - break; - sppp_clear_timeout (sp); - if ((sp->pp_link_state != SPPP_LINK_UP) && - (dev->flags & IFF_UP)) { - /* Coming out of loopback mode. */ - sp->pp_link_state=SPPP_LINK_UP; - printk (KERN_INFO "%s: protocol up\n", dev->name); - } - switch (sp->lcp.state) { - case LCP_STATE_CLOSED: - sp->lcp.state = LCP_STATE_ACK_RCVD; - sppp_set_timeout (sp, 5); - break; - case LCP_STATE_ACK_SENT: - sp->lcp.state = LCP_STATE_OPENED; - sppp_ipcp_open (sp); - break; - } - break; - case LCP_CONF_NAK: - if (h->ident != sp->lcp.confid) - break; - p = (u8*) (h+1); - if (len>=10 && p[0] == LCP_OPT_MAGIC && p[1] >= 4) { - rmagic = (u32)p[2] << 24 | - (u32)p[3] << 16 | p[4] << 8 | p[5]; - if (rmagic == ~sp->lcp.magic) { - int newmagic; - if (sp->pp_flags & PP_DEBUG) - printk (KERN_DEBUG "%s: conf nak: magic glitch\n", - dev->name); - get_random_bytes(&newmagic, sizeof(newmagic)); - sp->lcp.magic += newmagic; - } else - sp->lcp.magic = rmagic; - } - if (sp->lcp.state != LCP_STATE_ACK_SENT) { - /* Go to closed state. */ - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; - } - /* The link will be renegotiated after timeout, - * to avoid endless req-nack loop. */ - sppp_clear_timeout (sp); - sppp_set_timeout (sp, 2); - break; - case LCP_CONF_REJ: - if (h->ident != sp->lcp.confid) - break; - sppp_clear_timeout (sp); - /* Initiate renegotiation. */ - sppp_lcp_open (sp); - if (sp->lcp.state != LCP_STATE_ACK_SENT) { - /* Go to closed state. */ - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; - } - break; - case LCP_TERM_REQ: - sppp_clear_timeout (sp); - /* Send Terminate-Ack packet. */ - sppp_cp_send (sp, PPP_LCP, LCP_TERM_ACK, h->ident, 0, NULL); - /* Go to closed state. */ - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; - /* Initiate renegotiation. */ - sppp_lcp_open (sp); - break; - case LCP_TERM_ACK: - case LCP_CODE_REJ: - case LCP_PROTO_REJ: - /* Ignore for now. */ - break; - case LCP_DISC_REQ: - /* Discard the packet. */ - break; - case LCP_ECHO_REQ: - if (sp->lcp.state != LCP_STATE_OPENED) - break; - if (len < 8) { - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: invalid lcp echo request packet length: %d bytes\n", - dev->name, len); - break; - } - if (ntohl (*(__be32*)(h+1)) == sp->lcp.magic) { - /* Line loopback mode detected. */ - printk (KERN_WARNING "%s: loopback\n", dev->name); - if_down (dev); - - /* Shut down the PPP link. */ - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; - sppp_clear_timeout (sp); - /* Initiate negotiation. */ - sppp_lcp_open (sp); - break; - } - *(__be32 *)(h+1) = htonl (sp->lcp.magic); - sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REPLY, h->ident, len-4, h+1); - break; - case LCP_ECHO_REPLY: - if (h->ident != sp->lcp.echoid) - break; - if (len < 8) { - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: invalid lcp echo reply packet length: %d bytes\n", - dev->name, len); - break; - } - if (ntohl(*(__be32 *)(h+1)) != sp->lcp.magic) - sp->pp_alivecnt = 0; - break; - } -} - -/* - * Handle incoming Cisco keepalive protocol packets. - */ - -static void sppp_cisco_input (struct sppp *sp, struct sk_buff *skb) -{ - struct cisco_packet *h; - struct net_device *dev = sp->pp_if; - - if (!pskb_may_pull(skb, sizeof(struct cisco_packet)) - || (skb->len != CISCO_PACKET_LEN - && skb->len != CISCO_BIG_PACKET_LEN)) { - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: invalid cisco packet length: %d bytes\n", - dev->name, skb->len); - return; - } - h = (struct cisco_packet *)skb->data; - skb_pull(skb, sizeof(struct cisco_packet*)); - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: cisco input: %d bytes <%xh %xh %xh %xh %xh-%xh>\n", - dev->name, skb->len, - ntohl (h->type), h->par1, h->par2, h->rel, - h->time0, h->time1); - switch (ntohl (h->type)) { - default: - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: unknown cisco packet type: 0x%x\n", - dev->name, ntohl (h->type)); - break; - case CISCO_ADDR_REPLY: - /* Reply on address request, ignore */ - break; - case CISCO_KEEPALIVE_REQ: - sp->pp_alivecnt = 0; - sp->pp_rseq = ntohl (h->par1); - if (sp->pp_seq == sp->pp_rseq) { - /* Local and remote sequence numbers are equal. - * Probably, the line is in loopback mode. */ - int newseq; - if (sp->pp_loopcnt >= MAXALIVECNT) { - printk (KERN_WARNING "%s: loopback\n", - dev->name); - sp->pp_loopcnt = 0; - if (dev->flags & IFF_UP) { - if_down (dev); - } - } - ++sp->pp_loopcnt; - - /* Generate new local sequence number */ - get_random_bytes(&newseq, sizeof(newseq)); - sp->pp_seq ^= newseq; - break; - } - sp->pp_loopcnt = 0; - if (sp->pp_link_state==SPPP_LINK_DOWN && - (dev->flags & IFF_UP)) { - sp->pp_link_state=SPPP_LINK_UP; - printk (KERN_INFO "%s: protocol up\n", dev->name); - } - break; - case CISCO_ADDR_REQ: - /* Stolen from net/ipv4/devinet.c -- SIOCGIFADDR ioctl */ - { - __be32 addr = 0, mask = htonl(~0U); /* FIXME: is the mask correct? */ -#ifdef CONFIG_INET - struct in_device *in_dev; - struct in_ifaddr *ifa; - - rcu_read_lock(); - if ((in_dev = __in_dev_get_rcu(dev)) != NULL) - { - for (ifa=in_dev->ifa_list; ifa != NULL; - ifa=ifa->ifa_next) { - if (strcmp(dev->name, ifa->ifa_label) == 0) - { - addr = ifa->ifa_local; - mask = ifa->ifa_mask; - break; - } - } - } - rcu_read_unlock(); -#endif - sppp_cisco_send (sp, CISCO_ADDR_REPLY, ntohl(addr), ntohl(mask)); - break; - } - } -} - - -/* - * Send PPP LCP packet. - */ - -static void sppp_cp_send (struct sppp *sp, u16 proto, u8 type, - u8 ident, u16 len, void *data) -{ - struct ppp_header *h; - struct lcp_header *lh; - struct sk_buff *skb; - struct net_device *dev = sp->pp_if; - - skb=alloc_skb(dev->hard_header_len+PPP_HEADER_LEN+LCP_HEADER_LEN+len, - GFP_ATOMIC); - if (skb==NULL) - return; - - skb_reserve(skb,dev->hard_header_len); - - h = (struct ppp_header *)skb_put(skb, sizeof(struct ppp_header)); - h->address = PPP_ALLSTATIONS; /* broadcast address */ - h->control = PPP_UI; /* Unnumbered Info */ - h->protocol = htons (proto); /* Link Control Protocol */ - - lh = (struct lcp_header *)skb_put(skb, sizeof(struct lcp_header)); - lh->type = type; - lh->ident = ident; - lh->len = htons (LCP_HEADER_LEN + len); - - if (len) - memcpy(skb_put(skb,len),data, len); - - if (sp->pp_flags & PP_DEBUG) { - printk (KERN_WARNING "%s: %s output <%s id=%xh len=%xh", - dev->name, - proto==PPP_LCP ? "lcp" : "ipcp", - proto==PPP_LCP ? sppp_lcp_type_name (lh->type) : - sppp_ipcp_type_name (lh->type), lh->ident, - ntohs (lh->len)); - if (len) - sppp_print_bytes ((u8*) (lh+1), len); - printk (">\n"); - } - /* Control is high priority so it doesn't get queued behind data */ - skb->priority=TC_PRIO_CONTROL; - skb->dev = dev; - skb_queue_tail(&tx_queue, skb); -} - -/* - * Send Cisco keepalive packet. - */ - -static void sppp_cisco_send (struct sppp *sp, int type, u32 par1, u32 par2) -{ - struct ppp_header *h; - struct cisco_packet *ch; - struct sk_buff *skb; - struct net_device *dev = sp->pp_if; - u32 t = jiffies * 1000/HZ; - - skb=alloc_skb(dev->hard_header_len+PPP_HEADER_LEN+CISCO_PACKET_LEN, - GFP_ATOMIC); - - if(skb==NULL) - return; - - skb_reserve(skb, dev->hard_header_len); - h = (struct ppp_header *)skb_put (skb, sizeof(struct ppp_header)); - h->address = CISCO_MULTICAST; - h->control = 0; - h->protocol = htons (CISCO_KEEPALIVE); - - ch = (struct cisco_packet*)skb_put(skb, CISCO_PACKET_LEN); - ch->type = htonl (type); - ch->par1 = htonl (par1); - ch->par2 = htonl (par2); - ch->rel = htons(0xffff); - ch->time0 = htons ((u16) (t >> 16)); - ch->time1 = htons ((u16) t); - - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: cisco output: <%xh %xh %xh %xh %xh-%xh>\n", - dev->name, ntohl (ch->type), ch->par1, - ch->par2, ch->rel, ch->time0, ch->time1); - skb->priority=TC_PRIO_CONTROL; - skb->dev = dev; - skb_queue_tail(&tx_queue, skb); -} - -/** - * sppp_close - close down a synchronous PPP or Cisco HDLC link - * @dev: The network device to drop the link of - * - * This drops the logical interface to the channel. It is not - * done politely as we assume we will also be dropping DTR. Any - * timeouts are killed. - */ - -int sppp_close (struct net_device *dev) -{ - struct sppp *sp = (struct sppp *)sppp_of(dev); - unsigned long flags; - - spin_lock_irqsave(&sp->lock, flags); - sp->pp_link_state = SPPP_LINK_DOWN; - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; - sppp_clear_timeout (sp); - spin_unlock_irqrestore(&sp->lock, flags); - - return 0; -} - -EXPORT_SYMBOL(sppp_close); - -/** - * sppp_open - open a synchronous PPP or Cisco HDLC link - * @dev: Network device to activate - * - * Close down any existing synchronous session and commence - * from scratch. In the PPP case this means negotiating LCP/IPCP - * and friends, while for Cisco HDLC we simply need to start sending - * keepalives - */ - -int sppp_open (struct net_device *dev) -{ - struct sppp *sp = (struct sppp *)sppp_of(dev); - unsigned long flags; - - sppp_close(dev); - - spin_lock_irqsave(&sp->lock, flags); - if (!(sp->pp_flags & PP_CISCO)) { - sppp_lcp_open (sp); - } - sp->pp_link_state = SPPP_LINK_DOWN; - spin_unlock_irqrestore(&sp->lock, flags); - sppp_flush_xmit(); - - return 0; -} - -EXPORT_SYMBOL(sppp_open); - -/** - * sppp_reopen - notify of physical link loss - * @dev: Device that lost the link - * - * This function informs the synchronous protocol code that - * the underlying link died (for example a carrier drop on X.21) - * - * We increment the magic numbers to ensure that if the other end - * failed to notice we will correctly start a new session. It happens - * do to the nature of telco circuits is that you can lose carrier on - * one endonly. - * - * Having done this we go back to negotiating. This function may - * be called from an interrupt context. - */ - -int sppp_reopen (struct net_device *dev) -{ - struct sppp *sp = (struct sppp *)sppp_of(dev); - unsigned long flags; - - sppp_close(dev); - - spin_lock_irqsave(&sp->lock, flags); - if (!(sp->pp_flags & PP_CISCO)) - { - sp->lcp.magic = jiffies; - ++sp->pp_seq; - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; - /* Give it a moment for the line to settle then go */ - sppp_set_timeout (sp, 1); - } - sp->pp_link_state=SPPP_LINK_DOWN; - spin_unlock_irqrestore(&sp->lock, flags); - - return 0; -} - -EXPORT_SYMBOL(sppp_reopen); - -/** - * sppp_change_mtu - Change the link MTU - * @dev: Device to change MTU on - * @new_mtu: New MTU - * - * Change the MTU on the link. This can only be called with - * the link down. It returns an error if the link is up or - * the mtu is out of range. - */ - -static int sppp_change_mtu(struct net_device *dev, int new_mtu) -{ - if(new_mtu<128||new_mtu>PPP_MTU||(dev->flags&IFF_UP)) - return -EINVAL; - dev->mtu=new_mtu; - return 0; -} - -/** - * sppp_do_ioctl - Ioctl handler for ppp/hdlc - * @dev: Device subject to ioctl - * @ifr: Interface request block from the user - * @cmd: Command that is being issued - * - * This function handles the ioctls that may be issued by the user - * to control the settings of a PPP/HDLC link. It does both busy - * and security checks. This function is intended to be wrapped by - * callers who wish to add additional ioctl calls of their own. - */ - -int sppp_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - struct sppp *sp = (struct sppp *)sppp_of(dev); - - if(dev->flags&IFF_UP) - return -EBUSY; - - if(!capable(CAP_NET_ADMIN)) - return -EPERM; - - switch(cmd) - { - case SPPPIOCCISCO: - sp->pp_flags|=PP_CISCO; - dev->type = ARPHRD_HDLC; - break; - case SPPPIOCPPP: - sp->pp_flags&=~PP_CISCO; - dev->type = ARPHRD_PPP; - break; - case SPPPIOCDEBUG: - sp->pp_flags&=~PP_DEBUG; - if(ifr->ifr_flags) - sp->pp_flags|=PP_DEBUG; - break; - case SPPPIOCGFLAGS: - if(copy_to_user(ifr->ifr_data, &sp->pp_flags, sizeof(sp->pp_flags))) - return -EFAULT; - break; - case SPPPIOCSFLAGS: - if(copy_from_user(&sp->pp_flags, ifr->ifr_data, sizeof(sp->pp_flags))) - return -EFAULT; - break; - default: - return -EINVAL; - } - return 0; -} - -EXPORT_SYMBOL(sppp_do_ioctl); - -/** - * sppp_attach - attach synchronous PPP/HDLC to a device - * @pd: PPP device to initialise - * - * This initialises the PPP/HDLC support on an interface. At the - * time of calling the dev element must point to the network device - * that this interface is attached to. The interface should not yet - * be registered. - */ - -void sppp_attach(struct ppp_device *pd) -{ - struct net_device *dev = pd->dev; - struct sppp *sp = &pd->sppp; - unsigned long flags; - - /* Make sure embedding is safe for sppp_of */ - BUG_ON(sppp_of(dev) != sp); - - spin_lock_irqsave(&spppq_lock, flags); - /* Initialize keepalive handler. */ - if (! spppq) - { - init_timer(&sppp_keepalive_timer); - sppp_keepalive_timer.expires=jiffies+10*HZ; - sppp_keepalive_timer.function=sppp_keepalive; - add_timer(&sppp_keepalive_timer); - } - /* Insert new entry into the keepalive list. */ - sp->pp_next = spppq; - spppq = sp; - spin_unlock_irqrestore(&spppq_lock, flags); - - sp->pp_loopcnt = 0; - sp->pp_alivecnt = 0; - sp->pp_seq = 0; - sp->pp_rseq = 0; - sp->pp_flags = PP_KEEPALIVE|PP_CISCO|debug;/*PP_DEBUG;*/ - sp->lcp.magic = 0; - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; - sp->pp_if = dev; - spin_lock_init(&sp->lock); - - /* - * Device specific setup. All but interrupt handler and - * hard_start_xmit. - */ - - dev->header_ops = &sppp_header_ops; - - dev->tx_queue_len = 10; - dev->type = ARPHRD_HDLC; - dev->addr_len = 0; - dev->hard_header_len = sizeof(struct ppp_header); - dev->mtu = PPP_MTU; - /* - * These 4 are callers but MUST also call sppp_ functions - */ - dev->do_ioctl = sppp_do_ioctl; -#if 0 - dev->get_stats = NULL; /* Let the driver override these */ - dev->open = sppp_open; - dev->stop = sppp_close; -#endif - dev->change_mtu = sppp_change_mtu; - dev->flags = IFF_MULTICAST|IFF_POINTOPOINT|IFF_NOARP; -} - -EXPORT_SYMBOL(sppp_attach); - -/** - * sppp_detach - release PPP resources from a device - * @dev: Network device to release - * - * Stop and free up any PPP/HDLC resources used by this - * interface. This must be called before the device is - * freed. - */ - -void sppp_detach (struct net_device *dev) -{ - struct sppp **q, *p, *sp = (struct sppp *)sppp_of(dev); - unsigned long flags; - - spin_lock_irqsave(&spppq_lock, flags); - /* Remove the entry from the keepalive list. */ - for (q = &spppq; (p = *q); q = &p->pp_next) - if (p == sp) { - *q = p->pp_next; - break; - } - - /* Stop keepalive handler. */ - if (! spppq) - del_timer(&sppp_keepalive_timer); - sppp_clear_timeout (sp); - spin_unlock_irqrestore(&spppq_lock, flags); -} - -EXPORT_SYMBOL(sppp_detach); - -/* - * Analyze the LCP Configure-Request options list - * for the presence of unknown options. - * If the request contains unknown options, build and - * send Configure-reject packet, containing only unknown options. - */ -static int -sppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h, - int len, u32 *magic) -{ - u8 *buf, *r, *p; - int rlen; - - len -= 4; - buf = r = kmalloc (len, GFP_ATOMIC); - if (! buf) - return (0); - - p = (void*) (h+1); - for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) { - switch (*p) { - case LCP_OPT_MAGIC: - /* Magic number -- extract. */ - if (len >= 6 && p[1] == 6) { - *magic = (u32)p[2] << 24 | - (u32)p[3] << 16 | p[4] << 8 | p[5]; - continue; - } - break; - case LCP_OPT_ASYNC_MAP: - /* Async control character map -- check to be zero. */ - if (len >= 6 && p[1] == 6 && ! p[2] && ! p[3] && - ! p[4] && ! p[5]) - continue; - break; - case LCP_OPT_MRU: - /* Maximum receive unit -- always OK. */ - continue; - default: - /* Others not supported. */ - break; - } - /* Add the option to rejected list. */ - memcpy(r, p, p[1]); - r += p[1]; - rlen += p[1]; - } - if (rlen) - sppp_cp_send (sp, PPP_LCP, LCP_CONF_REJ, h->ident, rlen, buf); - kfree(buf); - return (rlen == 0); -} - -static void sppp_ipcp_input (struct sppp *sp, struct sk_buff *skb) -{ - struct lcp_header *h; - struct net_device *dev = sp->pp_if; - int len = skb->len; - - if (!pskb_may_pull(skb, sizeof(struct lcp_header))) { - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: invalid ipcp packet length: %d bytes\n", - dev->name, len); - return; - } - h = (struct lcp_header *)skb->data; - skb_pull(skb,sizeof(struct lcp_header)); - if (sp->pp_flags & PP_DEBUG) { - printk (KERN_WARNING "%s: ipcp input: %d bytes <%s id=%xh len=%xh", - dev->name, len, - sppp_ipcp_type_name (h->type), h->ident, ntohs (h->len)); - if (len > 4) - sppp_print_bytes ((u8*) (h+1), len-4); - printk (">\n"); - } - if (len > ntohs (h->len)) - len = ntohs (h->len); - switch (h->type) { - default: - /* Unknown packet type -- send Code-Reject packet. */ - sppp_cp_send (sp, PPP_IPCP, IPCP_CODE_REJ, ++sp->pp_seq, len, h); - break; - case IPCP_CONF_REQ: - if (len < 4) { - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: invalid ipcp configure request packet length: %d bytes\n", - dev->name, len); - return; - } - if (len > 4) { - sppp_cp_send (sp, PPP_IPCP, LCP_CONF_REJ, h->ident, - len-4, h+1); - - switch (sp->ipcp.state) { - case IPCP_STATE_OPENED: - /* Initiate renegotiation. */ - sppp_ipcp_open (sp); - /* fall through... */ - case IPCP_STATE_ACK_SENT: - /* Go to closed state. */ - sp->ipcp.state = IPCP_STATE_CLOSED; - } - } else { - /* Send Configure-Ack packet. */ - sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_ACK, h->ident, - 0, NULL); - /* Change the state. */ - if (sp->ipcp.state == IPCP_STATE_ACK_RCVD) - sp->ipcp.state = IPCP_STATE_OPENED; - else - sp->ipcp.state = IPCP_STATE_ACK_SENT; - } - break; - case IPCP_CONF_ACK: - if (h->ident != sp->ipcp.confid) - break; - sppp_clear_timeout (sp); - switch (sp->ipcp.state) { - case IPCP_STATE_CLOSED: - sp->ipcp.state = IPCP_STATE_ACK_RCVD; - sppp_set_timeout (sp, 5); - break; - case IPCP_STATE_ACK_SENT: - sp->ipcp.state = IPCP_STATE_OPENED; - break; - } - break; - case IPCP_CONF_NAK: - case IPCP_CONF_REJ: - if (h->ident != sp->ipcp.confid) - break; - sppp_clear_timeout (sp); - /* Initiate renegotiation. */ - sppp_ipcp_open (sp); - if (sp->ipcp.state != IPCP_STATE_ACK_SENT) - /* Go to closed state. */ - sp->ipcp.state = IPCP_STATE_CLOSED; - break; - case IPCP_TERM_REQ: - /* Send Terminate-Ack packet. */ - sppp_cp_send (sp, PPP_IPCP, IPCP_TERM_ACK, h->ident, 0, NULL); - /* Go to closed state. */ - sp->ipcp.state = IPCP_STATE_CLOSED; - /* Initiate renegotiation. */ - sppp_ipcp_open (sp); - break; - case IPCP_TERM_ACK: - /* Ignore for now. */ - case IPCP_CODE_REJ: - /* Ignore for now. */ - break; - } -} - -static void sppp_lcp_open (struct sppp *sp) -{ - char opt[6]; - - if (! sp->lcp.magic) - sp->lcp.magic = jiffies; - opt[0] = LCP_OPT_MAGIC; - opt[1] = sizeof (opt); - opt[2] = sp->lcp.magic >> 24; - opt[3] = sp->lcp.magic >> 16; - opt[4] = sp->lcp.magic >> 8; - opt[5] = sp->lcp.magic; - sp->lcp.confid = ++sp->pp_seq; - sppp_cp_send (sp, PPP_LCP, LCP_CONF_REQ, sp->lcp.confid, - sizeof (opt), &opt); - sppp_set_timeout (sp, 2); -} - -static void sppp_ipcp_open (struct sppp *sp) -{ - sp->ipcp.confid = ++sp->pp_seq; - sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_REQ, sp->ipcp.confid, 0, NULL); - sppp_set_timeout (sp, 2); -} - -/* - * Process PPP control protocol timeouts. - */ - -static void sppp_cp_timeout (unsigned long arg) -{ - struct sppp *sp = (struct sppp*) arg; - unsigned long flags; - - spin_lock_irqsave(&sp->lock, flags); - - sp->pp_flags &= ~PP_TIMO; - if (! (sp->pp_if->flags & IFF_UP) || (sp->pp_flags & PP_CISCO)) { - spin_unlock_irqrestore(&sp->lock, flags); - return; - } - switch (sp->lcp.state) { - case LCP_STATE_CLOSED: - /* No ACK for Configure-Request, retry. */ - sppp_lcp_open (sp); - break; - case LCP_STATE_ACK_RCVD: - /* ACK got, but no Configure-Request for peer, retry. */ - sppp_lcp_open (sp); - sp->lcp.state = LCP_STATE_CLOSED; - break; - case LCP_STATE_ACK_SENT: - /* ACK sent but no ACK for Configure-Request, retry. */ - sppp_lcp_open (sp); - break; - case LCP_STATE_OPENED: - /* LCP is already OK, try IPCP. */ - switch (sp->ipcp.state) { - case IPCP_STATE_CLOSED: - /* No ACK for Configure-Request, retry. */ - sppp_ipcp_open (sp); - break; - case IPCP_STATE_ACK_RCVD: - /* ACK got, but no Configure-Request for peer, retry. */ - sppp_ipcp_open (sp); - sp->ipcp.state = IPCP_STATE_CLOSED; - break; - case IPCP_STATE_ACK_SENT: - /* ACK sent but no ACK for Configure-Request, retry. */ - sppp_ipcp_open (sp); - break; - case IPCP_STATE_OPENED: - /* IPCP is OK. */ - break; - } - break; - } - spin_unlock_irqrestore(&sp->lock, flags); - sppp_flush_xmit(); -} - -static char *sppp_lcp_type_name (u8 type) -{ - static char buf [8]; - switch (type) { - case LCP_CONF_REQ: return ("conf-req"); - case LCP_CONF_ACK: return ("conf-ack"); - case LCP_CONF_NAK: return ("conf-nack"); - case LCP_CONF_REJ: return ("conf-rej"); - case LCP_TERM_REQ: return ("term-req"); - case LCP_TERM_ACK: return ("term-ack"); - case LCP_CODE_REJ: return ("code-rej"); - case LCP_PROTO_REJ: return ("proto-rej"); - case LCP_ECHO_REQ: return ("echo-req"); - case LCP_ECHO_REPLY: return ("echo-reply"); - case LCP_DISC_REQ: return ("discard-req"); - } - sprintf (buf, "%xh", type); - return (buf); -} - -static char *sppp_ipcp_type_name (u8 type) -{ - static char buf [8]; - switch (type) { - case IPCP_CONF_REQ: return ("conf-req"); - case IPCP_CONF_ACK: return ("conf-ack"); - case IPCP_CONF_NAK: return ("conf-nack"); - case IPCP_CONF_REJ: return ("conf-rej"); - case IPCP_TERM_REQ: return ("term-req"); - case IPCP_TERM_ACK: return ("term-ack"); - case IPCP_CODE_REJ: return ("code-rej"); - } - sprintf (buf, "%xh", type); - return (buf); -} - -static void sppp_print_bytes (u_char *p, u16 len) -{ - printk (" %x", *p++); - while (--len > 0) - printk ("-%x", *p++); -} - -/** - * sppp_rcv - receive and process a WAN PPP frame - * @skb: The buffer to process - * @dev: The device it arrived on - * @p: Unused - * @orig_dev: Unused - * - * Protocol glue. This drives the deferred processing mode the poorer - * cards use. This can be called directly by cards that do not have - * timing constraints but is normally called from the network layer - * after interrupt servicing to process frames queued via netif_rx. - */ - -static int sppp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *p, struct net_device *orig_dev) -{ - if (dev_net(dev) != &init_net) { - kfree_skb(skb); - return 0; - } - - if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) - return NET_RX_DROP; - sppp_input(dev,skb); - return 0; -} - -static struct packet_type sppp_packet_type = { - .type = __constant_htons(ETH_P_WAN_PPP), - .func = sppp_rcv, -}; - -static char banner[] __initdata = - KERN_INFO "Cronyx Ltd, Synchronous PPP and CISCO HDLC (c) 1994\n" - KERN_INFO "Linux port (c) 1998 Building Number Three Ltd & " - "Jan \"Yenya\" Kasprzak.\n"; - -static int __init sync_ppp_init(void) -{ - if(debug) - debug=PP_DEBUG; - printk(banner); - skb_queue_head_init(&tx_queue); - dev_add_pack(&sppp_packet_type); - return 0; -} - - -static void __exit sync_ppp_cleanup(void) -{ - dev_remove_pack(&sppp_packet_type); -} - -module_init(sync_ppp_init); -module_exit(sync_ppp_cleanup); -module_param(debug, int, 0); -MODULE_LICENSE("GPL"); - diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c index a8a5ca0ee6c2dc8d59f16ee5e29a48d2b5db4dce..4bffb67ebcae32b9fbd2676bcb6e151fa16f9edf 100644 --- a/drivers/net/wan/wanxl.c +++ b/drivers/net/wan/wanxl.c @@ -220,7 +220,6 @@ static inline void wanxl_rx_intr(card_t *card) #endif dev->stats.rx_packets++; dev->stats.rx_bytes += skb->len; - dev->last_rx = jiffies; skb->protocol = hdlc_type_trans(skb, dev); netif_rx(skb); skb = NULL; @@ -411,12 +410,12 @@ static int wanxl_open(struct net_device *dev) writel(1 << (DOORBELL_TO_CARD_OPEN_0 + port->node), dbr); timeout = jiffies + HZ; - do + do { if (get_status(port)->open) { netif_start_queue(dev); return 0; } - while (time_after(timeout, jiffies)); + } while (time_after(timeout, jiffies)); printk(KERN_ERR "%s: unable to open port\n", dev->name); /* ask the card to close the port, should it be still alive */ @@ -438,10 +437,10 @@ static int wanxl_close(struct net_device *dev) port->card->plx + PLX_DOORBELL_TO_CARD); timeout = jiffies + HZ; - do + do { if (!get_status(port)->open) break; - while (time_after(timeout, jiffies)); + } while (time_after(timeout, jiffies)); if (get_status(port)->open) printk(KERN_ERR "%s: unable to close port\n", dev->name); diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c index 2a6c7a60756f38a8c5ad00064562c4059de1089c..e6e2ce3e7bcf6a1b15d8b9f3cc79ccf1f2ba57f4 100644 --- a/drivers/net/wan/x25_asy.c +++ b/drivers/net/wan/x25_asy.c @@ -64,7 +64,7 @@ static struct x25_asy *x25_asy_alloc(void) if (dev == NULL) break; - sl = dev->priv; + sl = netdev_priv(dev); /* Not in use ? */ if (!test_and_set_bit(SLF_INUSE, &sl->flags)) return sl; @@ -86,7 +86,7 @@ static struct x25_asy *x25_asy_alloc(void) return NULL; /* Initialize channel control data */ - sl = dev->priv; + sl = netdev_priv(dev); dev->base_addr = i; /* register device so that it can be ifconfig'ed */ @@ -120,7 +120,7 @@ static void x25_asy_free(struct x25_asy *sl) static int x25_asy_change_mtu(struct net_device *dev, int newmtu) { - struct x25_asy *sl = dev->priv; + struct x25_asy *sl = netdev_priv(dev); unsigned char *xbuff, *rbuff; int len = 2 * newmtu; @@ -211,7 +211,6 @@ static void x25_asy_bump(struct x25_asy *sl) printk(KERN_DEBUG "x25_asy: data received err - %d\n", err); } else { netif_rx(skb); - sl->dev->last_rx = jiffies; sl->stats.rx_packets++; } } @@ -243,7 +242,7 @@ static void x25_asy_encaps(struct x25_asy *sl, unsigned char *icp, int len) * if we did not request it before write operation. * 14 Oct 1994 Dmitry Gorodchanin. */ - sl->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); + set_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags); actual = sl->tty->ops->write(sl->tty, sl->xbuff, count); sl->xleft = count - actual; sl->xhead = sl->xbuff + actual; @@ -258,7 +257,7 @@ static void x25_asy_encaps(struct x25_asy *sl, unsigned char *icp, int len) static void x25_asy_write_wakeup(struct tty_struct *tty) { int actual; - struct x25_asy *sl = (struct x25_asy *) tty->disc_data; + struct x25_asy *sl = tty->disc_data; /* First make sure we're connected. */ if (!sl || sl->magic != X25_ASY_MAGIC || !netif_running(sl->dev)) @@ -268,7 +267,7 @@ static void x25_asy_write_wakeup(struct tty_struct *tty) /* Now serial buffer is almost free & we can start * transmission of another packet */ sl->stats.tx_packets++; - tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); x25_asy_unlock(sl); return; } @@ -280,7 +279,7 @@ static void x25_asy_write_wakeup(struct tty_struct *tty) static void x25_asy_timeout(struct net_device *dev) { - struct x25_asy *sl = dev->priv; + struct x25_asy *sl = netdev_priv(dev); spin_lock(&sl->lock); if (netif_queue_stopped(dev)) { @@ -291,7 +290,7 @@ static void x25_asy_timeout(struct net_device *dev) (tty_chars_in_buffer(sl->tty) || sl->xleft) ? "bad line quality" : "driver error"); sl->xleft = 0; - sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + clear_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags); x25_asy_unlock(sl); } spin_unlock(&sl->lock); @@ -301,7 +300,7 @@ static void x25_asy_timeout(struct net_device *dev) static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev) { - struct x25_asy *sl = dev->priv; + struct x25_asy *sl = netdev_priv(dev); int err; if (!netif_running(sl->dev)) { @@ -361,7 +360,6 @@ static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev) static int x25_asy_data_indication(struct net_device *dev, struct sk_buff *skb) { - skb->dev->last_rx = jiffies; return netif_rx(skb); } @@ -373,7 +371,7 @@ static int x25_asy_data_indication(struct net_device *dev, struct sk_buff *skb) static void x25_asy_data_transmit(struct net_device *dev, struct sk_buff *skb) { - struct x25_asy *sl = dev->priv; + struct x25_asy *sl = netdev_priv(dev); spin_lock(&sl->lock); if (netif_queue_stopped(sl->dev) || sl->tty == NULL) { @@ -398,7 +396,7 @@ static void x25_asy_data_transmit(struct net_device *dev, struct sk_buff *skb) static void x25_asy_connected(struct net_device *dev, int reason) { - struct x25_asy *sl = dev->priv; + struct x25_asy *sl = netdev_priv(dev); struct sk_buff *skb; unsigned char *ptr; @@ -413,12 +411,11 @@ static void x25_asy_connected(struct net_device *dev, int reason) skb->protocol = x25_type_trans(skb, sl->dev); netif_rx(skb); - sl->dev->last_rx = jiffies; } static void x25_asy_disconnected(struct net_device *dev, int reason) { - struct x25_asy *sl = dev->priv; + struct x25_asy *sl = netdev_priv(dev); struct sk_buff *skb; unsigned char *ptr; @@ -433,7 +430,6 @@ static void x25_asy_disconnected(struct net_device *dev, int reason) skb->protocol = x25_type_trans(skb, sl->dev); netif_rx(skb); - sl->dev->last_rx = jiffies; } static struct lapb_register_struct x25_asy_callbacks = { @@ -450,7 +446,7 @@ static struct lapb_register_struct x25_asy_callbacks = { /* Open the low-level part of the X.25 channel. Easy! */ static int x25_asy_open(struct net_device *dev) { - struct x25_asy *sl = dev->priv; + struct x25_asy *sl = netdev_priv(dev); unsigned long len; int err; @@ -499,12 +495,12 @@ static int x25_asy_open(struct net_device *dev) /* Close the low-level part of the X.25 channel. Easy! */ static int x25_asy_close(struct net_device *dev) { - struct x25_asy *sl = dev->priv; + struct x25_asy *sl = netdev_priv(dev); int err; spin_lock(&sl->lock); if (sl->tty) - sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + clear_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags); netif_stop_queue(dev); sl->rcount = 0; @@ -527,7 +523,7 @@ static int x25_asy_close(struct net_device *dev) static void x25_asy_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) { - struct x25_asy *sl = (struct x25_asy *) tty->disc_data; + struct x25_asy *sl = tty->disc_data; if (!sl || sl->magic != X25_ASY_MAGIC || !netif_running(sl->dev)) return; @@ -555,7 +551,7 @@ static void x25_asy_receive_buf(struct tty_struct *tty, static int x25_asy_open_tty(struct tty_struct *tty) { - struct x25_asy *sl = (struct x25_asy *) tty->disc_data; + struct x25_asy *sl = tty->disc_data; int err; if (tty->ops->write == NULL) @@ -596,7 +592,7 @@ static int x25_asy_open_tty(struct tty_struct *tty) */ static void x25_asy_close_tty(struct tty_struct *tty) { - struct x25_asy *sl = (struct x25_asy *) tty->disc_data; + struct x25_asy *sl = tty->disc_data; /* First make sure we're connected. */ if (!sl || sl->magic != X25_ASY_MAGIC) @@ -615,7 +611,7 @@ static void x25_asy_close_tty(struct tty_struct *tty) static struct net_device_stats *x25_asy_get_stats(struct net_device *dev) { - struct x25_asy *sl = dev->priv; + struct x25_asy *sl = netdev_priv(dev); return &sl->stats; } @@ -624,7 +620,7 @@ static struct net_device_stats *x25_asy_get_stats(struct net_device *dev) * STANDARD X.25 ENCAPSULATION * ************************************************************************/ -int x25_asy_esc(unsigned char *s, unsigned char *d, int len) +static int x25_asy_esc(unsigned char *s, unsigned char *d, int len) { unsigned char *ptr = d; unsigned char c; @@ -696,7 +692,7 @@ static void x25_asy_unesc(struct x25_asy *sl, unsigned char s) static int x25_asy_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { - struct x25_asy *sl = (struct x25_asy *) tty->disc_data; + struct x25_asy *sl = tty->disc_data; /* First make sure we're connected. */ if (!sl || sl->magic != X25_ASY_MAGIC) @@ -717,7 +713,7 @@ static int x25_asy_ioctl(struct tty_struct *tty, struct file *file, static int x25_asy_open_dev(struct net_device *dev) { - struct x25_asy *sl = dev->priv; + struct x25_asy *sl = netdev_priv(dev); if (sl->tty == NULL) return -ENODEV; return 0; @@ -726,7 +722,7 @@ static int x25_asy_open_dev(struct net_device *dev) /* Initialise the X.25 driver. Called by the device init code */ static void x25_asy_setup(struct net_device *dev) { - struct x25_asy *sl = dev->priv; + struct x25_asy *sl = netdev_priv(dev); sl->magic = X25_ASY_MAGIC; sl->dev = dev; @@ -793,7 +789,7 @@ static void __exit exit_x25_asy(void) for (i = 0; i < x25_asy_maxdev; i++) { dev = x25_asy_devs[i]; if (dev) { - struct x25_asy *sl = dev->priv; + struct x25_asy *sl = netdev_priv(dev); spin_lock_bh(&sl->lock); if (sl->tty) diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c index 5bf7e01ef0e9fe3c408408e24dc8e43a772f6161..3d00971fe5ee6a6dc488d99bf72e262cf06f8a6f 100644 --- a/drivers/net/wan/z85230.c +++ b/drivers/net/wan/z85230.c @@ -601,24 +601,18 @@ static void z8530_dma_status(struct z8530_channel *chan) write_zsctrl(chan, RES_H_IUS); } -struct z8530_irqhandler z8530_dma_sync= -{ +static struct z8530_irqhandler z8530_dma_sync = { z8530_dma_rx, z8530_dma_tx, z8530_dma_status }; -EXPORT_SYMBOL(z8530_dma_sync); - -struct z8530_irqhandler z8530_txdma_sync= -{ +static struct z8530_irqhandler z8530_txdma_sync = { z8530_rx, z8530_dma_tx, z8530_dma_status }; -EXPORT_SYMBOL(z8530_txdma_sync); - /** * z8530_rx_clear - Handle RX events from a stopped chip * @c: Z8530 channel to shut up @@ -710,7 +704,7 @@ EXPORT_SYMBOL(z8530_nop); irqreturn_t z8530_interrupt(int irq, void *dev_id) { struct z8530_dev *dev=dev_id; - u8 intr; + u8 uninitialized_var(intr); static volatile int locker=0; int work=0; struct z8530_irqhandler *irqs; diff --git a/drivers/net/wd.c b/drivers/net/wd.c index fa14255282afe96770d5b44cc887fbaba22814df..3c1edda08d3d5d6827f32618690db332b01b7b55 100644 --- a/drivers/net/wd.c +++ b/drivers/net/wd.c @@ -147,6 +147,20 @@ struct net_device * __init wd_probe(int unit) } #endif +static const struct net_device_ops wd_netdev_ops = { + .ndo_open = wd_open, + .ndo_stop = wd_close, + .ndo_start_xmit = ei_start_xmit, + .ndo_tx_timeout = ei_tx_timeout, + .ndo_get_stats = ei_get_stats, + .ndo_set_multicast_list = ei_set_multicast_list, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = ei_poll, +#endif +}; + static int __init wd_probe1(struct net_device *dev, int ioaddr) { int i; @@ -156,7 +170,6 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr) int word16 = 0; /* 0 = 8 bit, 1 = 16 bit */ const char *model_name; static unsigned version_printed; - DECLARE_MAC_BUF(mac); for (i = 0; i < 8; i++) checksum += inb(ioaddr + 8 + i); @@ -178,8 +191,8 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr) for (i = 0; i < 6; i++) dev->dev_addr[i] = inb(ioaddr + 8 + i); - printk("%s: WD80x3 at %#3x, %s", - dev->name, ioaddr, print_mac(mac, dev->dev_addr)); + printk("%s: WD80x3 at %#3x, %pM", + dev->name, ioaddr, dev->dev_addr); /* The following PureData probe code was contributed by Mike Jagdis . Puredata does software @@ -332,11 +345,8 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr) ei_status.block_input = &wd_block_input; ei_status.block_output = &wd_block_output; ei_status.get_8390_hdr = &wd_get_8390_hdr; - dev->open = &wd_open; - dev->stop = &wd_close; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = ei_poll; -#endif + + dev->netdev_ops = &wd_netdev_ops; NS8390_init(dev, 0); #if 1 @@ -366,8 +376,7 @@ wd_open(struct net_device *dev) outb(ei_status.reg5, ioaddr+WD_CMDREG5); outb(ei_status.reg0, ioaddr); /* WD_CMDREG */ - ei_open(dev); - return 0; + return ei_open(dev); } static void diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 45bdf0b339bb55f0aa132b2256385014079a8731..ea543fcf2687aa9e0bacea24dad83dbe44897233 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -123,154 +123,11 @@ config PCMCIA_RAYCS To compile this driver as a module, choose M here: the module will be called ray_cs. If unsure, say N. -config IPW2100 - tristate "Intel PRO/Wireless 2100 Network Connection" - depends on PCI && WLAN_80211 - select WIRELESS_EXT - select FW_LOADER - select IEEE80211 - ---help--- - A driver for the Intel PRO/Wireless 2100 Network - Connection 802.11b wireless network adapter. - - See for information on - the capabilities currently enabled in this driver and for tips - for debugging issues and problems. - - In order to use this driver, you will need a firmware image for it. - You can obtain the firmware from - . Once you have the firmware image, you - will need to place it in /lib/firmware. - - You will also very likely need the Wireless Tools in order to - configure your card: - - . - - It is recommended that you compile this driver as a module (M) - rather than built-in (Y). This driver requires firmware at device - initialization time, and when built-in this typically happens - before the filesystem is accessible (hence firmware will be - unavailable and initialization will fail). If you do choose to build - this driver into your kernel image, you can avoid this problem by - including the firmware and a firmware loader in an initramfs. - -config IPW2100_MONITOR - bool "Enable promiscuous mode" - depends on IPW2100 - ---help--- - Enables promiscuous/monitor mode support for the ipw2100 driver. - With this feature compiled into the driver, you can switch to - promiscuous mode via the Wireless Tool's Monitor mode. While in this - mode, no packets can be sent. - -config IPW2100_DEBUG - bool "Enable full debugging output in IPW2100 module." - depends on IPW2100 - ---help--- - This option will enable debug tracing output for the IPW2100. - - This will result in the kernel module being ~60k larger. You can - control which debug output is sent to the kernel log by setting the - value in - - /sys/bus/pci/drivers/ipw2100/debug_level - - This entry will only exist if this option is enabled. - - If you are not trying to debug or develop the IPW2100 driver, you - most likely want to say N here. - -config IPW2200 - tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection" - depends on PCI && WLAN_80211 - select WIRELESS_EXT - select FW_LOADER - select IEEE80211 - ---help--- - A driver for the Intel PRO/Wireless 2200BG and 2915ABG Network - Connection adapters. - - See for - information on the capabilities currently enabled in this - driver and for tips for debugging issues and problems. - - In order to use this driver, you will need a firmware image for it. - You can obtain the firmware from - . See the above referenced README.ipw2200 - for information on where to install the firmware images. - - You will also very likely need the Wireless Tools in order to - configure your card: - - . - - It is recommended that you compile this driver as a module (M) - rather than built-in (Y). This driver requires firmware at device - initialization time, and when built-in this typically happens - before the filesystem is accessible (hence firmware will be - unavailable and initialization will fail). If you do choose to build - this driver into your kernel image, you can avoid this problem by - including the firmware and a firmware loader in an initramfs. - -config IPW2200_MONITOR - bool "Enable promiscuous mode" - depends on IPW2200 - ---help--- - Enables promiscuous/monitor mode support for the ipw2200 driver. - With this feature compiled into the driver, you can switch to - promiscuous mode via the Wireless Tool's Monitor mode. While in this - mode, no packets can be sent. - -config IPW2200_RADIOTAP - bool "Enable radiotap format 802.11 raw packet support" - depends on IPW2200_MONITOR - -config IPW2200_PROMISCUOUS - bool "Enable creation of a RF radiotap promiscuous interface" - depends on IPW2200_MONITOR - select IPW2200_RADIOTAP - ---help--- - Enables the creation of a second interface prefixed 'rtap'. - This second interface will provide every received in radiotap - format. - - This is useful for performing wireless network analysis while - maintaining an active association. - - Example usage: - - % modprobe ipw2200 rtap_iface=1 - % ifconfig rtap0 up - % tethereal -i rtap0 - - If you do not specify 'rtap_iface=1' as a module parameter then - the rtap interface will not be created and you will need to turn - it on via sysfs: - - % echo 1 > /sys/bus/pci/drivers/ipw2200/*/rtap_iface - -config IPW2200_QOS - bool "Enable QoS support" - depends on IPW2200 && EXPERIMENTAL - -config IPW2200_DEBUG - bool "Enable full debugging output in IPW2200 module." - depends on IPW2200 - ---help--- - This option will enable low level debug tracing output for IPW2200. - - Note, normal debug code is already compiled in. This low level - debug option enables debug on hot paths (e.g Tx, Rx, ISR) and - will result in the kernel module being ~70 larger. Most users - will typically not need this high verbosity debug information. - - If you are not sure, say N here. - config LIBERTAS tristate "Marvell 8xxx Libertas WLAN driver support" depends on WLAN_80211 select WIRELESS_EXT + select LIB80211 select FW_LOADER ---help--- A library for Marvell Libertas 8xxx devices. @@ -357,6 +214,21 @@ config HERMES configure your card and that /etc/pcmcia/wireless.opts works : +config HERMES_CACHE_FW_ON_INIT + bool "Cache Hermes firmware on driver initialisation" + depends on HERMES + default y + ---help--- + Say Y to cache any firmware required by the Hermes drivers + on startup. The firmware will remain cached until the + driver is unloaded. The cache uses 64K of RAM. + + Otherwise load the firmware from userspace as required. In + this case the driver should be unloaded and restarted + whenever the firmware is changed. + + If you are not sure, say Y. + config APPLE_AIRPORT tristate "Apple Airport support (built-in)" depends on PPC_PMAC && HERMES @@ -651,7 +523,7 @@ config RTL8180 config RTL8187 tristate "Realtek 8187 and 8187B USB support" - depends on MAC80211 && USB && WLAN_80211 && EXPERIMENTAL + depends on MAC80211 && USB && WLAN_80211 select EEPROM_93CX6 ---help--- This is a driver for RTL8187 and RTL8187B based cards. @@ -711,6 +583,7 @@ config MAC80211_HWSIM source "drivers/net/wireless/p54/Kconfig" source "drivers/net/wireless/ath5k/Kconfig" source "drivers/net/wireless/ath9k/Kconfig" +source "drivers/net/wireless/ipw2x00/Kconfig" source "drivers/net/wireless/iwlwifi/Kconfig" source "drivers/net/wireless/hostap/Kconfig" source "drivers/net/wireless/b43/Kconfig" diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 59d2d805f60b4591b1332944b51ac7cf380b5006..ac590e1ca8beecf788cbe10a2d36f4e043e44799 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -2,9 +2,8 @@ # Makefile for the Linux Wireless network device drivers. # -obj-$(CONFIG_IPW2100) += ipw2100.o - -obj-$(CONFIG_IPW2200) += ipw2200.o +obj-$(CONFIG_IPW2100) += ipw2x00/ +obj-$(CONFIG_IPW2200) += ipw2x00/ obj-$(CONFIG_STRIP) += strip.o obj-$(CONFIG_ARLAN) += arlan.o @@ -16,14 +15,7 @@ obj-$(CONFIG_WAVELAN) += wavelan.o obj-$(CONFIG_PCMCIA_NETWAVE) += netwave_cs.o obj-$(CONFIG_PCMCIA_WAVELAN) += wavelan_cs.o -obj-$(CONFIG_HERMES) += orinoco.o hermes.o hermes_dld.o -obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o -obj-$(CONFIG_APPLE_AIRPORT) += airport.o -obj-$(CONFIG_PLX_HERMES) += orinoco_plx.o -obj-$(CONFIG_PCI_HERMES) += orinoco_pci.o -obj-$(CONFIG_TMD_HERMES) += orinoco_tmd.o -obj-$(CONFIG_NORTEL_HERMES) += orinoco_nortel.o -obj-$(CONFIG_PCMCIA_SPECTRUM) += spectrum_cs.o +obj-$(CONFIG_HERMES) += orinoco/ obj-$(CONFIG_AIRO) += airo.o obj-$(CONFIG_AIRO_CS) += airo_cs.o airo.o @@ -38,6 +30,8 @@ obj-$(CONFIG_HOSTAP) += hostap/ obj-$(CONFIG_B43) += b43/ obj-$(CONFIG_B43LEGACY) += b43legacy/ obj-$(CONFIG_ZD1211RW) += zd1211rw/ +obj-$(CONFIG_RTL8180) += rtl818x/ +obj-$(CONFIG_RTL8187) += rtl818x/ # 16-bit wireless PCMCIA client drivers obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o @@ -50,12 +44,6 @@ obj-$(CONFIG_LIBERTAS) += libertas/ obj-$(CONFIG_LIBERTAS_THINFIRM) += libertas_tf/ -rtl8180-objs := rtl8180_dev.o rtl8180_rtl8225.o rtl8180_sa2400.o rtl8180_max2820.o rtl8180_grf5101.o -rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o - -obj-$(CONFIG_RTL8180) += rtl8180.o -obj-$(CONFIG_RTL8187) += rtl8187.o - obj-$(CONFIG_ADM8211) += adm8211.o obj-$(CONFIG_IWLWIFI) += iwlwifi/ diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index b2c050b68890a2f0d496a85d39314c95282d07e9..fc0897fb22390c87d908ceefdc0a4ea05193e383 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -341,15 +341,14 @@ static void adm8211_interrupt_tci(struct ieee80211_hw *dev) pci_unmap_single(priv->pdev, info->mapping, info->skb->len, PCI_DMA_TODEVICE); - memset(&txi->status, 0, sizeof(txi->status)); + ieee80211_tx_info_clear_status(txi); + skb_pull(skb, sizeof(struct adm8211_tx_hdr)); memcpy(skb_push(skb, info->hdrlen), skb->cb, info->hdrlen); - if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK)) { - if (status & TDES0_STATUS_ES) - txi->status.excessive_retries = 1; - else - txi->flags |= IEEE80211_TX_STAT_ACK; - } + if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK) && + !(status & TDES0_STATUS_ES)) + txi->flags |= IEEE80211_TX_STAT_ACK; + ieee80211_tx_status_irqsafe(dev, skb); info->skb = NULL; @@ -1298,25 +1297,10 @@ static void adm8211_set_bssid(struct ieee80211_hw *dev, const u8 *bssid) ADM8211_CSR_WRITE(ABDA1, reg); } -static int adm8211_set_ssid(struct ieee80211_hw *dev, u8 *ssid, size_t ssid_len) -{ - struct adm8211_priv *priv = dev->priv; - u8 buf[36]; - - if (ssid_len > 32) - return -EINVAL; - - memset(buf, 0, sizeof(buf)); - buf[0] = ssid_len; - memcpy(buf + 1, ssid, ssid_len); - adm8211_write_sram_bytes(dev, ADM8211_SRAM_SSID, buf, 33); - /* TODO: configure beacon for adhoc? */ - return 0; -} - -static int adm8211_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) +static int adm8211_config(struct ieee80211_hw *dev, u32 changed) { struct adm8211_priv *priv = dev->priv; + struct ieee80211_conf *conf = &dev->conf; int channel = ieee80211_frequency_to_channel(conf->channel->center_freq); if (channel != priv->channel) { @@ -1338,13 +1322,6 @@ static int adm8211_config_interface(struct ieee80211_hw *dev, memcpy(priv->bssid, conf->bssid, ETH_ALEN); } - if (conf->ssid_len != priv->ssid_len || - memcmp(conf->ssid, priv->ssid, conf->ssid_len)) { - adm8211_set_ssid(dev, conf->ssid, conf->ssid_len); - priv->ssid_len = conf->ssid_len; - memcpy(priv->ssid, conf->ssid, conf->ssid_len); - } - return 0; } @@ -1690,8 +1667,10 @@ static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb) struct ieee80211_hdr *hdr; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_rate *txrate = ieee80211_get_tx_rate(dev, info); + u8 rc_flags; - short_preamble = !!(txrate->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE); + rc_flags = info->control.rates[0].flags; + short_preamble = !!(rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE); plcp_signal = txrate->bitrate; hdr = (struct ieee80211_hdr *)skb->data; @@ -1723,10 +1702,10 @@ static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb) if (short_preamble) txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_SHORT_PREAMBLE); - if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) + if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_RTS); - txhdr->retry_limit = info->control.retry_limit; + txhdr->retry_limit = info->control.rates[0].count; adm8211_tx_raw(dev, skb, plcp_signal, hdrlen); @@ -1791,7 +1770,6 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, int err; u32 reg; u8 perm_addr[ETH_ALEN]; - DECLARE_MAC_BUF(mac); err = pci_enable_device(pdev); if (err) { @@ -1925,8 +1903,8 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, goto err_free_desc; } - printk(KERN_INFO "%s: hwaddr %s, Rev 0x%02x\n", - wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr), + printk(KERN_INFO "%s: hwaddr %pM, Rev 0x%02x\n", + wiphy_name(dev->wiphy), dev->wiphy->perm_addr, pdev->revision); return 0; diff --git a/drivers/net/wireless/adm8211.h b/drivers/net/wireless/adm8211.h index 9b190ee26e903c291fa54aaa0c51e5153ace4d67..4f6ab1322189805660e99b0e5b3bc3acf2fba9d8 100644 --- a/drivers/net/wireless/adm8211.h +++ b/drivers/net/wireless/adm8211.h @@ -553,8 +553,6 @@ struct adm8211_priv { int channel; u8 bssid[ETH_ALEN]; - u8 ssid[32]; - size_t ssid_len; u8 soft_rx_crc; u8 retry_limit; diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 370133e492d259431df941fc3eee94bb770fa117..fc4322ca669fa3a33c56650a784debdc15e8dab3 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -47,10 +47,11 @@ #include #include #include -#include #include #include +#include + #include "airo.h" #define DRV_NAME "airo" @@ -1270,6 +1271,7 @@ static int flashrestart(struct airo_info *ai,struct net_device *dev); #define airo_print_err(name, fmt, args...) \ airo_print(KERN_ERR, name, fmt, ##args) +#define AIRO_FLASH(dev) (((struct airo_info *)dev->ml_priv)->flash) /*********************************************************************** * MIC ROUTINES * @@ -1865,7 +1867,7 @@ static void try_auto_wep(struct airo_info *ai) } static int airo_open(struct net_device *dev) { - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; int rc = 0; if (test_bit(FLAG_FLASHING, &ai->flags)) @@ -1912,7 +1914,7 @@ static int airo_open(struct net_device *dev) { static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) { int npacks, pending; unsigned long flags; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; if (!skb) { airo_print_err(dev->name, "%s: skb == NULL!",__func__); @@ -1956,7 +1958,7 @@ static int mpi_send_packet (struct net_device *dev) unsigned char *buffer; s16 len; __le16 *payloadLen; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; u8 *sendbuf; /* get a packet to send */ @@ -2085,7 +2087,7 @@ static void get_tx_error(struct airo_info *ai, s32 fid) static void airo_end_xmit(struct net_device *dev) { u16 status; int i; - struct airo_info *priv = dev->priv; + struct airo_info *priv = dev->ml_priv; struct sk_buff *skb = priv->xmit.skb; int fid = priv->xmit.fid; u32 *fids = priv->fids; @@ -2111,7 +2113,7 @@ static void airo_end_xmit(struct net_device *dev) { static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) { s16 len; int i, j; - struct airo_info *priv = dev->priv; + struct airo_info *priv = dev->ml_priv; u32 *fids = priv->fids; if ( skb == NULL ) { @@ -2150,7 +2152,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) { static void airo_end_xmit11(struct net_device *dev) { u16 status; int i; - struct airo_info *priv = dev->priv; + struct airo_info *priv = dev->ml_priv; struct sk_buff *skb = priv->xmit11.skb; int fid = priv->xmit11.fid; u32 *fids = priv->fids; @@ -2176,7 +2178,7 @@ static void airo_end_xmit11(struct net_device *dev) { static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) { s16 len; int i, j; - struct airo_info *priv = dev->priv; + struct airo_info *priv = dev->ml_priv; u32 *fids = priv->fids; if (test_bit(FLAG_MPI, &priv->flags)) { @@ -2220,7 +2222,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) { static void airo_read_stats(struct net_device *dev) { - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; StatsRid stats_rid; __le32 *vals = stats_rid.vals; @@ -2254,7 +2256,7 @@ static void airo_read_stats(struct net_device *dev) static struct net_device_stats *airo_get_stats(struct net_device *dev) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; if (!test_bit(JOB_STATS, &local->jobs)) { /* Get stats out of the card if available */ @@ -2281,7 +2283,7 @@ static void airo_set_promisc(struct airo_info *ai) { } static void airo_set_multicast_list(struct net_device *dev) { - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; if ((dev->flags ^ ai->flags) & IFF_PROMISC) { change_bit(FLAG_PROMISC, &ai->flags); @@ -2299,7 +2301,7 @@ static void airo_set_multicast_list(struct net_device *dev) { static int airo_set_mac_address(struct net_device *dev, void *p) { - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; struct sockaddr *addr = p; readConfigRid(ai, 1); @@ -2339,7 +2341,7 @@ static void del_airo_dev(struct airo_info *ai) } static int airo_close(struct net_device *dev) { - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; netif_stop_queue(dev); @@ -2365,7 +2367,7 @@ static int airo_close(struct net_device *dev) { void stop_airo_card( struct net_device *dev, int freeres ) { - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; set_bit(FLAG_RADIO_DOWN, &ai->flags); disable_MAC(ai, 1); @@ -2665,7 +2667,7 @@ static struct net_device *init_wifidev(struct airo_info *ai, struct net_device *dev = alloc_netdev(0, "wifi%d", wifi_setup); if (!dev) return NULL; - dev->priv = ethdev->priv; + dev->ml_priv = ethdev->ml_priv; dev->irq = ethdev->irq; dev->base_addr = ethdev->base_addr; dev->wireless_data = ethdev->wireless_data; @@ -2680,7 +2682,7 @@ static struct net_device *init_wifidev(struct airo_info *ai, } static int reset_card( struct net_device *dev , int lock) { - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; if (lock && down_interruptible(&ai->sem)) return -1; @@ -2757,7 +2759,6 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, struct net_device *dev; struct airo_info *ai; int i, rc; - DECLARE_MAC_BUF(mac); /* Create the network device object. */ dev = alloc_netdev(sizeof(*ai), "", ether_setup); @@ -2766,7 +2767,7 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, return NULL; } - ai = dev->priv; + ai = dev->ml_priv = netdev_priv(dev); ai->wifidev = NULL; ai->flags = 1 << FLAG_RADIO_DOWN; ai->jobs = 0; @@ -2860,15 +2861,14 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, goto err_out_reg; set_bit(FLAG_REGISTERED,&ai->flags); - airo_print_info(dev->name, "MAC enabled %s", - print_mac(mac, dev->dev_addr)); + airo_print_info(dev->name, "MAC enabled %pM", dev->dev_addr); /* Allocate the transmit buffers */ if (probe && !test_bit(FLAG_MPI,&ai->flags)) for( i = 0; i < MAX_FIDS; i++ ) ai->fids[i] = transmit_allocate(ai,AIRO_DEF_MTU,i>=MAX_FIDS/2); - if (setup_proc_entry(dev, dev->priv) < 0) + if (setup_proc_entry(dev, dev->ml_priv) < 0) goto err_out_wifi; return dev; @@ -2917,8 +2917,7 @@ static int waitbusy (struct airo_info *ai) { int reset_airo_card( struct net_device *dev ) { int i; - struct airo_info *ai = dev->priv; - DECLARE_MAC_BUF(mac); + struct airo_info *ai = dev->ml_priv; if (reset_card (dev, 1)) return -1; @@ -2927,8 +2926,7 @@ int reset_airo_card( struct net_device *dev ) airo_print_err(dev->name, "MAC could not be enabled"); return -1; } - airo_print_info(dev->name, "MAC enabled %s", - print_mac(mac, dev->dev_addr)); + airo_print_info(dev->name, "MAC enabled %pM", dev->dev_addr); /* Allocate the transmit buffers if needed */ if (!test_bit(FLAG_MPI,&ai->flags)) for( i = 0; i < MAX_FIDS; i++ ) @@ -2942,7 +2940,7 @@ int reset_airo_card( struct net_device *dev ) EXPORT_SYMBOL(reset_airo_card); static void airo_send_event(struct net_device *dev) { - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; union iwreq_data wrqu; StatusRid status_rid; @@ -3019,7 +3017,7 @@ static void airo_process_scan_results (struct airo_info *ai) { static int airo_thread(void *data) { struct net_device *dev = data; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; int locked; set_freezable(); @@ -3134,7 +3132,7 @@ static irqreturn_t airo_interrupt(int irq, void *dev_id) struct net_device *dev = dev_id; u16 status; u16 fid; - struct airo_info *apriv = dev->priv; + struct airo_info *apriv = dev->ml_priv; u16 savedInterrupts = 0; int handled = 0; @@ -3369,7 +3367,6 @@ static irqreturn_t airo_interrupt(int irq, void *dev_id) skb->protocol = htons(ETH_P_802_2); } else skb->protocol = eth_type_trans(skb,dev); - skb->dev->last_rx = jiffies; skb->ip_summed = CHECKSUM_NONE; netif_rx( skb ); @@ -3599,7 +3596,6 @@ static void mpi_receive_802_3(struct airo_info *ai) skb->ip_summed = CHECKSUM_NONE; skb->protocol = eth_type_trans(skb, ai->dev); - skb->dev->last_rx = jiffies; netif_rx(skb); } badrx: @@ -3611,7 +3607,7 @@ static void mpi_receive_802_3(struct airo_info *ai) } } -void mpi_receive_802_11 (struct airo_info *ai) +static void mpi_receive_802_11(struct airo_info *ai) { RxFid rxd; struct sk_buff *skb = NULL; @@ -3693,7 +3689,6 @@ void mpi_receive_802_11 (struct airo_info *ai) skb->pkt_type = PACKET_OTHERHOST; skb->dev = ai->wifidev; skb->protocol = htons(ETH_P_802_2); - skb->dev->last_rx = jiffies; skb->ip_summed = CHECKSUM_NONE; netif_rx( skb ); badrx: @@ -4604,7 +4599,7 @@ static int proc_status_open(struct inode *inode, struct file *file) struct proc_data *data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; - struct airo_info *apriv = dev->priv; + struct airo_info *apriv = dev->ml_priv; CapabilityRid cap_rid; StatusRid status_rid; u16 mode; @@ -4687,7 +4682,7 @@ static int proc_stats_rid_open( struct inode *inode, struct proc_data *data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; - struct airo_info *apriv = dev->priv; + struct airo_info *apriv = dev->ml_priv; StatsRid stats; int i, j; __le32 *vals = stats.vals; @@ -4750,7 +4745,7 @@ static void proc_config_on_close(struct inode *inode, struct file *file) struct proc_data *data = file->private_data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; char *line; if ( !data->writelen ) return; @@ -4962,7 +4957,7 @@ static int proc_config_open(struct inode *inode, struct file *file) struct proc_data *data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; int i; __le16 mode; @@ -5053,7 +5048,7 @@ static void proc_SSID_on_close(struct inode *inode, struct file *file) struct proc_data *data = (struct proc_data *)file->private_data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; SsidRid SSID_rid; int i; char *p = data->wbuffer; @@ -5096,7 +5091,7 @@ static void proc_APList_on_close( struct inode *inode, struct file *file ) { struct proc_data *data = (struct proc_data *)file->private_data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; APListRid APList_rid; int i; @@ -5191,7 +5186,7 @@ static void proc_wepkey_on_close( struct inode *inode, struct file *file ) { struct proc_data *data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; int i; char key[16]; u16 index = 0; @@ -5233,7 +5228,7 @@ static int proc_wepkey_open( struct inode *inode, struct file *file ) struct proc_data *data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; char *ptr; WepKeyRid wkr; __le16 lastindex; @@ -5282,7 +5277,7 @@ static int proc_SSID_open(struct inode *inode, struct file *file) struct proc_data *data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; int i; char *ptr; SsidRid SSID_rid; @@ -5326,11 +5321,10 @@ static int proc_APList_open( struct inode *inode, struct file *file ) { struct proc_data *data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; int i; char *ptr; APListRid APList_rid; - DECLARE_MAC_BUF(mac); if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) return -ENOMEM; @@ -5354,8 +5348,7 @@ static int proc_APList_open( struct inode *inode, struct file *file ) { // We end when we find a zero MAC if ( !*(int*)APList_rid.ap[i] && !*(int*)&APList_rid.ap[i][2]) break; - ptr += sprintf(ptr, "%s\n", - print_mac(mac, APList_rid.ap[i])); + ptr += sprintf(ptr, "%pM\n", APList_rid.ap[i]); } if (i==0) ptr += sprintf(ptr, "Not using specific APs\n"); @@ -5368,13 +5361,12 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) { struct proc_data *data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; char *ptr; BSSListRid BSSList_rid; int rc; /* If doLoseSync is not 1, we won't do a Lose Sync */ int doLoseSync = -1; - DECLARE_MAC_BUF(mac); if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) return -ENOMEM; @@ -5411,8 +5403,8 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) { we have to add a spin lock... */ rc = readBSSListRid(ai, doLoseSync, &BSSList_rid); while(rc == 0 && BSSList_rid.index != cpu_to_le16(0xffff)) { - ptr += sprintf(ptr, "%s %*s rssi = %d", - print_mac(mac, BSSList_rid.bssid), + ptr += sprintf(ptr, "%pM %*s rssi = %d", + BSSList_rid.bssid, (int)BSSList_rid.ssidLen, BSSList_rid.ssid, le16_to_cpu(BSSList_rid.dBm)); @@ -5447,7 +5439,7 @@ static int proc_close( struct inode *inode, struct file *file ) associated we will check every minute to see if anything has changed. */ static void timer_func( struct net_device *dev ) { - struct airo_info *apriv = dev->priv; + struct airo_info *apriv = dev->ml_priv; /* We don't have a link so try changing the authtype */ readConfigRid(apriv, 0); @@ -5518,7 +5510,7 @@ static void __devexit airo_pci_remove(struct pci_dev *pdev) static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *dev = pci_get_drvdata(pdev); - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; Cmd cmd; Resp rsp; @@ -5550,7 +5542,7 @@ static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state) static int airo_pci_resume(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; pci_power_t prev_state = pdev->current_state; pci_set_power_state(pdev, PCI_D0); @@ -5729,7 +5721,7 @@ static int airo_set_freq(struct net_device *dev, struct iw_freq *fwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; int rc = -EINPROGRESS; /* Call commit handler */ /* If setting by frequency, convert to a channel */ @@ -5774,7 +5766,7 @@ static int airo_get_freq(struct net_device *dev, struct iw_freq *fwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; StatusRid status_rid; /* Card status info */ int ch; @@ -5805,7 +5797,7 @@ static int airo_set_essid(struct net_device *dev, struct iw_point *dwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; SsidRid SSID_rid; /* SSIDs */ /* Reload the list of current SSID */ @@ -5851,7 +5843,7 @@ static int airo_get_essid(struct net_device *dev, struct iw_point *dwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; StatusRid status_rid; /* Card status info */ readStatusRid(local, &status_rid, 1); @@ -5879,7 +5871,7 @@ static int airo_set_wap(struct net_device *dev, struct sockaddr *awrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; Cmd cmd; Resp rsp; APListRid APList_rid; @@ -5916,7 +5908,7 @@ static int airo_get_wap(struct net_device *dev, struct sockaddr *awrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; StatusRid status_rid; /* Card status info */ readStatusRid(local, &status_rid, 1); @@ -5937,7 +5929,7 @@ static int airo_set_nick(struct net_device *dev, struct iw_point *dwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; /* Check the size of the string */ if(dwrq->length > 16) { @@ -5960,7 +5952,7 @@ static int airo_get_nick(struct net_device *dev, struct iw_point *dwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; readConfigRid(local, 1); strncpy(extra, local->config.nodeName, 16); @@ -5979,7 +5971,7 @@ static int airo_set_rate(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; CapabilityRid cap_rid; /* Card capability info */ u8 brate = 0; int i; @@ -6049,7 +6041,7 @@ static int airo_get_rate(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; StatusRid status_rid; /* Card status info */ readStatusRid(local, &status_rid, 1); @@ -6071,7 +6063,7 @@ static int airo_set_rts(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; int rthr = vwrq->value; if(vwrq->disabled) @@ -6095,7 +6087,7 @@ static int airo_get_rts(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; readConfigRid(local, 1); vwrq->value = le16_to_cpu(local->config.rtsThres); @@ -6114,7 +6106,7 @@ static int airo_set_frag(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; int fthr = vwrq->value; if(vwrq->disabled) @@ -6139,7 +6131,7 @@ static int airo_get_frag(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; readConfigRid(local, 1); vwrq->value = le16_to_cpu(local->config.fragThresh); @@ -6158,7 +6150,7 @@ static int airo_set_mode(struct net_device *dev, __u32 *uwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; int reset = 0; readConfigRid(local, 1); @@ -6221,7 +6213,7 @@ static int airo_get_mode(struct net_device *dev, __u32 *uwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; readConfigRid(local, 1); /* If not managed, assume it's ad-hoc */ @@ -6258,7 +6250,7 @@ static int airo_set_encode(struct net_device *dev, struct iw_point *dwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; CapabilityRid cap_rid; /* Card capability info */ int perm = ( dwrq->flags & IW_ENCODE_TEMP ? 0 : 1 ); __le16 currentAuthType = local->config.authType; @@ -6345,7 +6337,7 @@ static int airo_get_encode(struct net_device *dev, struct iw_point *dwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; CapabilityRid cap_rid; /* Card capability info */ @@ -6393,7 +6385,7 @@ static int airo_set_encodeext(struct net_device *dev, union iwreq_data *wrqu, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; struct iw_point *encoding = &wrqu->encoding; struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; CapabilityRid cap_rid; /* Card capability info */ @@ -6479,7 +6471,7 @@ static int airo_get_encodeext(struct net_device *dev, union iwreq_data *wrqu, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; struct iw_point *encoding = &wrqu->encoding; struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; CapabilityRid cap_rid; /* Card capability info */ @@ -6542,7 +6534,7 @@ static int airo_set_auth(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; struct iw_param *param = &wrqu->param; __le16 currentAuthType = local->config.authType; @@ -6610,7 +6602,7 @@ static int airo_get_auth(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; struct iw_param *param = &wrqu->param; __le16 currentAuthType = local->config.authType; @@ -6659,7 +6651,7 @@ static int airo_set_txpow(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; CapabilityRid cap_rid; /* Card capability info */ int i; int rc = -EINVAL; @@ -6696,7 +6688,7 @@ static int airo_get_txpow(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; readConfigRid(local, 1); vwrq->value = le16_to_cpu(local->config.txPower); @@ -6716,7 +6708,7 @@ static int airo_set_retry(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; int rc = -EINVAL; if(vwrq->disabled) { @@ -6754,7 +6746,7 @@ static int airo_get_retry(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; vwrq->disabled = 0; /* Can't be disabled */ @@ -6785,7 +6777,7 @@ static int airo_get_range(struct net_device *dev, struct iw_point *dwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; struct iw_range *range = (struct iw_range *) extra; CapabilityRid cap_rid; /* Card capability info */ int i; @@ -6910,7 +6902,7 @@ static int airo_set_power(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; readConfigRid(local, 1); if (vwrq->disabled) { @@ -6967,7 +6959,7 @@ static int airo_get_power(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; __le16 mode; readConfigRid(local, 1); @@ -6998,7 +6990,7 @@ static int airo_set_sens(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; readConfigRid(local, 1); local->config.rssiThreshold = @@ -7017,7 +7009,7 @@ static int airo_get_sens(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; readConfigRid(local, 1); vwrq->value = le16_to_cpu(local->config.rssiThreshold); @@ -7037,7 +7029,7 @@ static int airo_get_aplist(struct net_device *dev, struct iw_point *dwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; struct sockaddr *address = (struct sockaddr *) extra; struct iw_quality qual[IW_MAX_AP]; BSSListRid BSSList; @@ -7110,7 +7102,7 @@ static int airo_set_scan(struct net_device *dev, struct iw_point *dwrq, char *extra) { - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; Cmd cmd; Resp rsp; int wake = 0; @@ -7156,7 +7148,7 @@ static inline char *airo_translate_scan(struct net_device *dev, char *end_buf, BSSListRid *bss) { - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; struct iw_event iwe; /* Temporary buffer */ __le16 capabilities; char * current_val; /* For rates */ @@ -7274,56 +7266,53 @@ static inline char *airo_translate_scan(struct net_device *dev, if (test_bit(FLAG_WPA_CAPABLE, &ai->flags)) { unsigned int num_null_ies = 0; u16 length = sizeof (bss->extra.iep); - struct ieee80211_info_element *info_element = - (struct ieee80211_info_element *) &bss->extra.iep; + u8 *ie = (void *)&bss->extra.iep; - while ((length >= sizeof(*info_element)) && (num_null_ies < 2)) { - if (sizeof(*info_element) + info_element->len > length) { + while ((length >= 2) && (num_null_ies < 2)) { + if (2 + ie[1] > length) { /* Invalid element, don't continue parsing IE */ break; } - switch (info_element->id) { - case MFIE_TYPE_SSID: + switch (ie[0]) { + case WLAN_EID_SSID: /* Two zero-length SSID elements * mean we're done parsing elements */ - if (!info_element->len) + if (!ie[1]) num_null_ies++; break; - case MFIE_TYPE_GENERIC: - if (info_element->len >= 4 && - info_element->data[0] == 0x00 && - info_element->data[1] == 0x50 && - info_element->data[2] == 0xf2 && - info_element->data[3] == 0x01) { + case WLAN_EID_GENERIC: + if (ie[1] >= 4 && + ie[2] == 0x00 && + ie[3] == 0x50 && + ie[4] == 0xf2 && + ie[5] == 0x01) { iwe.cmd = IWEVGENIE; - iwe.u.data.length = min(info_element->len + 2, - MAX_WPA_IE_LEN); + /* 64 is an arbitrary cut-off */ + iwe.u.data.length = min(ie[1] + 2, + 64); current_ev = iwe_stream_add_point( info, current_ev, - end_buf, &iwe, - (char *) info_element); + end_buf, &iwe, ie); } break; - case MFIE_TYPE_RSN: + case WLAN_EID_RSN: iwe.cmd = IWEVGENIE; - iwe.u.data.length = min(info_element->len + 2, - MAX_WPA_IE_LEN); + /* 64 is an arbitrary cut-off */ + iwe.u.data.length = min(ie[1] + 2, 64); current_ev = iwe_stream_add_point( info, current_ev, end_buf, - &iwe, (char *) info_element); + &iwe, ie); break; default: break; } - length -= sizeof(*info_element) + info_element->len; - info_element = - (struct ieee80211_info_element *)&info_element-> - data[info_element->len]; + length -= 2 + ie[1]; + ie += 2 + ie[1]; } } return current_ev; @@ -7338,7 +7327,7 @@ static int airo_get_scan(struct net_device *dev, struct iw_point *dwrq, char *extra) { - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; BSSListElement *net; int err = 0; char *current_ev = extra; @@ -7382,7 +7371,7 @@ static int airo_config_commit(struct net_device *dev, void *zwrq, /* NULL */ char *extra) /* NULL */ { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; if (!test_bit (FLAG_COMMIT, &local->flags)) return 0; @@ -7527,7 +7516,7 @@ static const struct iw_handler_def airo_handler_def = static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { int rc = 0; - struct airo_info *ai = (struct airo_info *)dev->priv; + struct airo_info *ai = dev->ml_priv; if (ai->power.event) return 0; @@ -7655,7 +7644,7 @@ static void airo_read_wireless_stats(struct airo_info *local) static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; if (!test_bit(JOB_WSTATS, &local->jobs)) { /* Get stats out of the card if available */ @@ -7680,7 +7669,7 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) { unsigned short ridcode; unsigned char *iobuf; int len; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; if (test_bit(FLAG_FLASHING, &ai->flags)) return -EIO; @@ -7746,7 +7735,7 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) { */ static int writerids(struct net_device *dev, aironet_ioctl *comp) { - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; int ridcode; int enabled; static int (* writer)(struct airo_info *, u16 rid, const void *, int, int); @@ -7869,41 +7858,41 @@ static int flashcard(struct net_device *dev, aironet_ioctl *comp) { switch(comp->command) { case AIROFLSHRST: - return cmdreset((struct airo_info *)dev->priv); + return cmdreset((struct airo_info *)dev->ml_priv); case AIROFLSHSTFL: - if (!((struct airo_info *)dev->priv)->flash && - (((struct airo_info *)dev->priv)->flash = kmalloc (FLASHSIZE, GFP_KERNEL)) == NULL) + if (!AIRO_FLASH(dev) && + (AIRO_FLASH(dev) = kmalloc(FLASHSIZE, GFP_KERNEL)) == NULL) return -ENOMEM; - return setflashmode((struct airo_info *)dev->priv); + return setflashmode((struct airo_info *)dev->ml_priv); case AIROFLSHGCHR: /* Get char from aux */ if(comp->len != sizeof(int)) return -EINVAL; if (copy_from_user(&z,comp->data,comp->len)) return -EFAULT; - return flashgchar((struct airo_info *)dev->priv,z,8000); + return flashgchar((struct airo_info *)dev->ml_priv, z, 8000); case AIROFLSHPCHR: /* Send char to card. */ if(comp->len != sizeof(int)) return -EINVAL; if (copy_from_user(&z,comp->data,comp->len)) return -EFAULT; - return flashpchar((struct airo_info *)dev->priv,z,8000); + return flashpchar((struct airo_info *)dev->ml_priv, z, 8000); case AIROFLPUTBUF: /* Send 32k to card */ - if (!((struct airo_info *)dev->priv)->flash) + if (!AIRO_FLASH(dev)) return -ENOMEM; if(comp->len > FLASHSIZE) return -EINVAL; - if(copy_from_user(((struct airo_info *)dev->priv)->flash,comp->data,comp->len)) + if (copy_from_user(AIRO_FLASH(dev), comp->data, comp->len)) return -EFAULT; - flashputbuf((struct airo_info *)dev->priv); + flashputbuf((struct airo_info *)dev->ml_priv); return 0; case AIRORESTART: - if(flashrestart((struct airo_info *)dev->priv,dev)) + if (flashrestart((struct airo_info *)dev->ml_priv, dev)) return -EIO; return 0; } diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c index dec5e874a54db0aef692c1a4c6966631ad144121..bfca15da6f0f844fa379bcb7c7eade8914139e3c 100644 --- a/drivers/net/wireless/arlan-main.c +++ b/drivers/net/wireless/arlan-main.c @@ -1467,19 +1467,17 @@ static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short else if (hw_dst_addr[1] == 0x40) printk(KERN_ERR "%s m/bcast 0x0140 \n", dev->name); while (dmi) - { if (dmi->dmi_addrlen == 6) - { - DECLARE_MAC_BUF(mac); + { + if (dmi->dmi_addrlen == 6) { if (arlan_debug & ARLAN_DEBUG_HEADER_DUMP) - printk(KERN_ERR "%s mcl %s\n", - dev->name, print_mac(mac, dmi->dmi_addr)); + printk(KERN_ERR "%s mcl %pM\n", + dev->name, dmi->dmi_addr); for (i = 0; i < 6; i++) if (dmi->dmi_addr[i] != hw_dst_addr[i]) break; if (i == 6) break; - } - else + } else printk(KERN_ERR "%s: invalid multicast address length given.\n", dev->name); dmi = dmi->next; } @@ -1512,18 +1510,14 @@ static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short { char immedDestAddress[6]; char immedSrcAddress[6]; - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); - DECLARE_MAC_BUF(mac3); - DECLARE_MAC_BUF(mac4); memcpy_fromio(immedDestAddress, arlan->immedDestAddress, 6); memcpy_fromio(immedSrcAddress, arlan->immedSrcAddress, 6); - printk(KERN_WARNING "%s t %s f %s imd %s ims %s\n", - dev->name, print_mac(mac, skbtmp), - print_mac(mac2, &skbtmp[6]), - print_mac(mac3, immedDestAddress), - print_mac(mac4, immedSrcAddress)); + printk(KERN_WARNING "%s t %pM f %pM imd %pM ims %pM\n", + dev->name, skbtmp, + &skbtmp[6], + immedDestAddress, + immedSrcAddress); } skb->protocol = eth_type_trans(skb, dev); IFDEBUG(ARLAN_DEBUG_HEADER_DUMP) @@ -1535,7 +1529,6 @@ static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short printk(KERN_WARNING "arlan kernel pkt type trans %x \n", skb->protocol); } netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } diff --git a/drivers/net/wireless/ath5k/ath5k.h b/drivers/net/wireless/ath5k/ath5k.h index 53ea439aff48a3e22f7f2fa7b63c376fa38c8af3..183ffc8e62cadc4b6b78c339d7a8ec0c4febf481 100644 --- a/drivers/net/wireless/ath5k/ath5k.h +++ b/drivers/net/wireless/ath5k/ath5k.h @@ -507,11 +507,15 @@ enum ath5k_tx_queue_id { #define AR5K_TXQ_FLAG_TXEOLINT_ENABLE 0x0004 /* Enable TXEOL interrupt -not used- */ #define AR5K_TXQ_FLAG_TXDESCINT_ENABLE 0x0008 /* Enable TXDESC interrupt -not used- */ #define AR5K_TXQ_FLAG_TXURNINT_ENABLE 0x0010 /* Enable TXURN interrupt */ -#define AR5K_TXQ_FLAG_BACKOFF_DISABLE 0x0020 /* Disable random post-backoff */ -#define AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE 0x0040 /* Enable ready time expiry policy (?)*/ -#define AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE 0x0080 /* Enable backoff while bursting */ -#define AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS 0x0100 /* Disable backoff while bursting */ -#define AR5K_TXQ_FLAG_COMPRESSION_ENABLE 0x0200 /* Enable hw compression -not implemented-*/ +#define AR5K_TXQ_FLAG_CBRORNINT_ENABLE 0x0020 /* Enable CBRORN interrupt */ +#define AR5K_TXQ_FLAG_CBRURNINT_ENABLE 0x0040 /* Enable CBRURN interrupt */ +#define AR5K_TXQ_FLAG_QTRIGINT_ENABLE 0x0080 /* Enable QTRIG interrupt */ +#define AR5K_TXQ_FLAG_TXNOFRMINT_ENABLE 0x0100 /* Enable TXNOFRM interrupt */ +#define AR5K_TXQ_FLAG_BACKOFF_DISABLE 0x0200 /* Disable random post-backoff */ +#define AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE 0x0300 /* Enable ready time expiry policy (?)*/ +#define AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE 0x0800 /* Enable backoff while bursting */ +#define AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS 0x1000 /* Disable backoff while bursting */ +#define AR5K_TXQ_FLAG_COMPRESSION_ENABLE 0x2000 /* Enable hw compression -not implemented-*/ /* * A struct to hold tx queue's parameters @@ -817,13 +821,6 @@ struct ath5k_athchan_2ghz { return (false); \ } while (0) -enum ath5k_ant_setting { - AR5K_ANT_VARIABLE = 0, /* variable by programming */ - AR5K_ANT_FIXED_A = 1, /* fixed to 11a frequencies */ - AR5K_ANT_FIXED_B = 2, /* fixed to 11b frequencies */ - AR5K_ANT_MAX = 3, -}; - /* * Hardware interrupt abstraction */ @@ -853,7 +850,7 @@ enum ath5k_ant_setting { * checked. We should do this with ath5k_hw_update_mib_counters() but * it seems we should also then do some noise immunity work. * @AR5K_INT_RXPHY: RX PHY Error - * @AR5K_INT_RXKCM: ?? + * @AR5K_INT_RXKCM: RX Key cache miss * @AR5K_INT_SWBA: SoftWare Beacon Alert - indicates its time to send a * beacon that must be handled in software. The alternative is if you * have VEOL support, in that case you let the hardware deal with things. @@ -869,7 +866,7 @@ enum ath5k_ant_setting { * @AR5K_INT_FATAL: Fatal errors were encountered, typically caused by DMA * errors. These types of errors we can enable seem to be of type * AR5K_SIMR2_MCABT, AR5K_SIMR2_SSERR and AR5K_SIMR2_DPERR. - * @AR5K_INT_GLOBAL: Seems to be used to clear and set the IER + * @AR5K_INT_GLOBAL: Used to clear and set the IER * @AR5K_INT_NOCARD: signals the card has been removed * @AR5K_INT_COMMON: common interrupts shared amogst MACs with the same * bit value @@ -881,36 +878,61 @@ enum ath5k_ant_setting { * MACs. */ enum ath5k_int { - AR5K_INT_RX = 0x00000001, /* Not common */ + AR5K_INT_RXOK = 0x00000001, AR5K_INT_RXDESC = 0x00000002, + AR5K_INT_RXERR = 0x00000004, AR5K_INT_RXNOFRM = 0x00000008, AR5K_INT_RXEOL = 0x00000010, AR5K_INT_RXORN = 0x00000020, - AR5K_INT_TX = 0x00000040, /* Not common */ + AR5K_INT_TXOK = 0x00000040, AR5K_INT_TXDESC = 0x00000080, + AR5K_INT_TXERR = 0x00000100, + AR5K_INT_TXNOFRM = 0x00000200, + AR5K_INT_TXEOL = 0x00000400, AR5K_INT_TXURN = 0x00000800, AR5K_INT_MIB = 0x00001000, + AR5K_INT_SWI = 0x00002000, AR5K_INT_RXPHY = 0x00004000, AR5K_INT_RXKCM = 0x00008000, AR5K_INT_SWBA = 0x00010000, + AR5K_INT_BRSSI = 0x00020000, AR5K_INT_BMISS = 0x00040000, - AR5K_INT_BNR = 0x00100000, /* Not common */ - AR5K_INT_GPIO = 0x01000000, - AR5K_INT_FATAL = 0x40000000, /* Not common */ - AR5K_INT_GLOBAL = 0x80000000, - - AR5K_INT_COMMON = AR5K_INT_RXNOFRM - | AR5K_INT_RXDESC - | AR5K_INT_RXEOL - | AR5K_INT_RXORN - | AR5K_INT_TXURN - | AR5K_INT_TXDESC - | AR5K_INT_MIB - | AR5K_INT_RXPHY - | AR5K_INT_RXKCM - | AR5K_INT_SWBA - | AR5K_INT_BMISS - | AR5K_INT_GPIO, + AR5K_INT_FATAL = 0x00080000, /* Non common */ + AR5K_INT_BNR = 0x00100000, /* Non common */ + AR5K_INT_TIM = 0x00200000, /* Non common */ + AR5K_INT_DTIM = 0x00400000, /* Non common */ + AR5K_INT_DTIM_SYNC = 0x00800000, /* Non common */ + AR5K_INT_GPIO = 0x01000000, + AR5K_INT_BCN_TIMEOUT = 0x02000000, /* Non common */ + AR5K_INT_CAB_TIMEOUT = 0x04000000, /* Non common */ + AR5K_INT_RX_DOPPLER = 0x08000000, /* Non common */ + AR5K_INT_QCBRORN = 0x10000000, /* Non common */ + AR5K_INT_QCBRURN = 0x20000000, /* Non common */ + AR5K_INT_QTRIG = 0x40000000, /* Non common */ + AR5K_INT_GLOBAL = 0x80000000, + + AR5K_INT_COMMON = AR5K_INT_RXOK + | AR5K_INT_RXDESC + | AR5K_INT_RXERR + | AR5K_INT_RXNOFRM + | AR5K_INT_RXEOL + | AR5K_INT_RXORN + | AR5K_INT_TXOK + | AR5K_INT_TXDESC + | AR5K_INT_TXERR + | AR5K_INT_TXNOFRM + | AR5K_INT_TXEOL + | AR5K_INT_TXURN + | AR5K_INT_MIB + | AR5K_INT_SWI + | AR5K_INT_RXPHY + | AR5K_INT_RXKCM + | AR5K_INT_SWBA + | AR5K_INT_BRSSI + | AR5K_INT_BMISS + | AR5K_INT_GPIO + | AR5K_INT_GLOBAL, + AR5K_INT_NOCARD = 0xffffffff }; @@ -1030,6 +1052,7 @@ struct ath5k_hw { bool ah_calibration; bool ah_running; bool ah_single_chip; + bool ah_combined_mic; enum ath5k_rfgain ah_rf_gain; u32 ah_mac_srev; @@ -1064,10 +1087,11 @@ struct ath5k_hw { u8 ah_sta_id[ETH_ALEN]; - /* Current BSSID we are trying to assoc to / creating. + /* Current BSSID we are trying to assoc to / create. * This is passed by mac80211 on config_interface() and cached here for * use in resets */ u8 ah_bssid[ETH_ALEN]; + u8 ah_bssid_mask[ETH_ALEN]; u32 ah_gpio[AR5K_MAX_GPIO]; int ah_gpio_npins; @@ -1081,6 +1105,11 @@ struct ath5k_hw { u32 ah_txq_imr_txurn; u32 ah_txq_imr_txdesc; u32 ah_txq_imr_txeol; + u32 ah_txq_imr_cbrorn; + u32 ah_txq_imr_cbrurn; + u32 ah_txq_imr_qtrig; + u32 ah_txq_imr_nofrm; + u32 ah_txq_isr; u32 *ah_rf_banks; size_t ah_rf_banks_size; struct ath5k_gain ah_gain; @@ -1321,4 +1350,9 @@ static inline u32 ath5k_hw_bitswap(u32 val, unsigned int bits) return retval; } +static inline int ath5k_pad_size(int hdrlen) +{ + return (hdrlen < 24) ? 0 : hdrlen & 3; +} + #endif diff --git a/drivers/net/wireless/ath5k/attach.c b/drivers/net/wireless/ath5k/attach.c index 51d569883cdd787a7a9b3de3f567f4e415aa1ea1..dea378f767310818a289667b7b24441beab89713 100644 --- a/drivers/net/wireless/ath5k/attach.c +++ b/drivers/net/wireless/ath5k/attach.c @@ -106,7 +106,7 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) { struct ath5k_hw *ah; struct pci_dev *pdev = sc->pdev; - u8 mac[ETH_ALEN]; + u8 mac[ETH_ALEN] = {}; int ret; u32 srev; @@ -317,15 +317,15 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) goto err_free; } - /* Set MAC address */ - ret = ath5k_eeprom_read_mac(ah, mac); - if (ret) { - ATH5K_ERR(sc, "unable to read address from EEPROM: 0x%04x\n", - sc->pdev->device); - goto err_free; + if (srev >= AR5K_SREV_AR2414) { + ah->ah_combined_mic = true; + AR5K_REG_ENABLE_BITS(ah, AR5K_MISC_MODE, + AR5K_MISC_MODE_COMBINED_MIC); } + /* MAC address is cleared until add_interface */ ath5k_hw_set_lladdr(ah, mac); + /* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */ memset(ah->ah_bssid, 0xff, ETH_ALEN); ath5k_hw_set_associd(ah, ah->ah_bssid, 0); diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 2d14255eb103d60096256eee89c78bbfe68f8550..4af2607deec09ad9582e2aa488723b461daf8416 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -60,6 +60,9 @@ #include "debug.h" static int ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */ +static int modparam_nohwcrypt; +module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); +MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); /******************\ @@ -197,7 +200,7 @@ static int ath5k_pci_resume(struct pci_dev *pdev); #endif /* CONFIG_PM */ static struct pci_driver ath5k_pci_driver = { - .name = "ath5k_pci", + .name = KBUILD_MODNAME, .id_table = ath5k_pci_id_table, .probe = ath5k_pci_probe, .remove = __devexit_p(ath5k_pci_remove), @@ -219,8 +222,7 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); static void ath5k_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); -static int ath5k_config(struct ieee80211_hw *hw, - struct ieee80211_conf *conf); +static int ath5k_config(struct ieee80211_hw *hw, u32 changed); static int ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_if_conf *conf); @@ -238,7 +240,7 @@ static int ath5k_get_tx_stats(struct ieee80211_hw *hw, struct ieee80211_tx_queue_stats *stats); static u64 ath5k_get_tsf(struct ieee80211_hw *hw); static void ath5k_reset_tsf(struct ieee80211_hw *hw); -static int ath5k_beacon_update(struct ieee80211_hw *hw, +static int ath5k_beacon_update(struct ath5k_softc *sc, struct sk_buff *skb); static void ath5k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -548,8 +550,8 @@ ath5k_pci_probe(struct pci_dev *pdev, /* set up multi-rate retry capabilities */ if (sc->ah->ah_version == AR5K_AR5212) { - hw->max_altrates = 3; - hw->max_altrate_tries = 11; + hw->max_rates = 4; + hw->max_rate_tries = 11; } /* Finish private driver data initialization */ @@ -711,7 +713,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) { struct ath5k_softc *sc = hw->priv; struct ath5k_hw *ah = sc->ah; - u8 mac[ETH_ALEN]; + u8 mac[ETH_ALEN] = {}; int ret; ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "devid 0x%x\n", pdev->device); @@ -781,7 +783,13 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc); setup_timer(&sc->calib_tim, ath5k_calibrate, (unsigned long)sc); - ath5k_hw_get_lladdr(ah, mac); + ret = ath5k_eeprom_read_mac(ah, mac); + if (ret) { + ATH5K_ERR(sc, "unable to read address from EEPROM: 0x%04x\n", + sc->pdev->device); + goto err_queues; + } + SET_IEEE80211_PERM_ADDR(hw, mac); /* All MAC address bits matter for ACKs */ memset(sc->bssidmask, 0xff, ETH_ALEN); @@ -1188,7 +1196,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL, (sc->power_level * 2), ieee80211_get_tx_rate(sc->hw, info)->hw_value, - info->control.retry_limit, keyidx, 0, flags, 0, 0); + info->control.rates[0].count, keyidx, 0, flags, 0, 0); if (ret) goto err_unmap; @@ -1200,7 +1208,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) break; mrr_rate[i] = rate->hw_value; - mrr_tries[i] = info->control.retries[i].limit; + mrr_tries[i] = info->control.rates[i + 1].count; } ah->ah_setup_mrr_tx_desc(ah, ds, @@ -1660,7 +1668,7 @@ ath5k_tasklet_rx(unsigned long data) struct ath5k_desc *ds; int ret; int hdrlen; - int pad; + int padsize; spin_lock(&sc->rxbuflock); if (list_empty(&sc->rxbuf)) { @@ -1745,16 +1753,19 @@ ath5k_tasklet_rx(unsigned long data) skb_put(skb, rs.rs_datalen); - /* - * the hardware adds a padding to 4 byte boundaries between - * the header and the payload data if the header length is - * not multiples of 4 - remove it - */ + /* The MAC header is padded to have 32-bit boundary if the + * packet payload is non-zero. The general calculation for + * padsize would take into account odd header lengths: + * padsize = (4 - hdrlen % 4) % 4; However, since only + * even-length headers are used, padding can only be 0 or 2 + * bytes and we can optimize this a bit. In addition, we must + * not try to remove padding from short control frames that do + * not have payload. */ hdrlen = ieee80211_get_hdrlen_from_skb(skb); - if (hdrlen & 3) { - pad = hdrlen % 4; - memmove(skb->data + pad, skb->data, hdrlen); - skb_pull(skb, pad); + padsize = ath5k_pad_size(hdrlen); + if (padsize) { + memmove(skb->data + padsize, skb->data, hdrlen); + skb_pull(skb, padsize); } /* @@ -1785,7 +1796,17 @@ ath5k_tasklet_rx(unsigned long data) rxs.noise = sc->ah->ah_noise_floor; rxs.signal = rxs.noise + rs.rs_rssi; - rxs.qual = rs.rs_rssi * 100 / 64; + + /* An rssi of 35 indicates you should be able use + * 54 Mbps reliably. A more elaborate scheme can be used + * here but it requires a map of SNR/throughput for each + * possible mode used */ + rxs.qual = rs.rs_rssi * 100 / 35; + + /* rssi can be more than 35 though, anything above that + * should be considered at 100% */ + if (rxs.qual > 100) + rxs.qual = 100; rxs.antenna = rs.rs_antenna; rxs.rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate); @@ -1846,30 +1867,26 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, PCI_DMA_TODEVICE); - memset(&info->status, 0, sizeof(info->status)); - info->tx_rate_idx = ath5k_hw_to_driver_rix(sc, - ts.ts_rate[ts.ts_final_idx]); - info->status.retry_count = ts.ts_longretry; - + ieee80211_tx_info_clear_status(info); for (i = 0; i < 4; i++) { - struct ieee80211_tx_altrate *r = - &info->status.retries[i]; + struct ieee80211_tx_rate *r = + &info->status.rates[i]; if (ts.ts_rate[i]) { - r->rate_idx = ath5k_hw_to_driver_rix(sc, ts.ts_rate[i]); - r->limit = ts.ts_retry[i]; + r->idx = ath5k_hw_to_driver_rix(sc, ts.ts_rate[i]); + r->count = ts.ts_retry[i]; } else { - r->rate_idx = -1; - r->limit = 0; + r->idx = -1; + r->count = 0; } } - info->status.excessive_retries = 0; + /* count the successful attempt as well */ + info->status.rates[ts.ts_final_idx].count++; + if (unlikely(ts.ts_status)) { sc->ll_stats.dot11ACKFailureCount++; - if (ts.ts_status & AR5K_TXERR_XRETRY) - info->status.excessive_retries = 1; - else if (ts.ts_status & AR5K_TXERR_FILT) + if (ts.ts_status & AR5K_TXERR_FILT) info->flags |= IEEE80211_TX_STAT_TX_FILTERED; } else { info->flags |= IEEE80211_TX_STAT_ACK; @@ -2143,8 +2160,6 @@ ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf) * * In IBSS mode we use a self-linked tx descriptor if possible. We enable SWBA * interrupts to detect TSF updates only. - * - * AP mode is missing. */ static void ath5k_beacon_config(struct ath5k_softc *sc) @@ -2157,7 +2172,9 @@ ath5k_beacon_config(struct ath5k_softc *sc) if (sc->opmode == NL80211_IFTYPE_STATION) { sc->imask |= AR5K_INT_BMISS; - } else if (sc->opmode == NL80211_IFTYPE_ADHOC) { + } else if (sc->opmode == NL80211_IFTYPE_ADHOC || + sc->opmode == NL80211_IFTYPE_MESH_POINT || + sc->opmode == NL80211_IFTYPE_AP) { /* * In IBSS mode we use a self-linked tx descriptor and let the * hardware send the beacons automatically. We have to load it @@ -2169,13 +2186,15 @@ ath5k_beacon_config(struct ath5k_softc *sc) sc->imask |= AR5K_INT_SWBA; - if (ath5k_hw_hasveol(ah)) { - spin_lock(&sc->block); - ath5k_beacon_send(sc); - spin_unlock(&sc->block); - } + if (sc->opmode == NL80211_IFTYPE_ADHOC) { + if (ath5k_hw_hasveol(ah)) { + spin_lock(&sc->block); + ath5k_beacon_send(sc); + spin_unlock(&sc->block); + } + } else + ath5k_beacon_update_timers(sc, -1); } - /* TODO else AP */ ath5k_hw_set_imr(ah, sc->imask); } @@ -2215,9 +2234,9 @@ ath5k_init(struct ath5k_softc *sc, bool is_resume) */ sc->curchan = sc->hw->conf.channel; sc->curband = &sc->sbands[sc->curchan->band]; - sc->imask = AR5K_INT_RX | AR5K_INT_TX | AR5K_INT_RXEOL | - AR5K_INT_RXORN | AR5K_INT_FATAL | AR5K_INT_GLOBAL | - AR5K_INT_MIB; + sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL | + AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL | + AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_MIB; ret = ath5k_reset(sc, false, false); if (ret) goto done; @@ -2409,9 +2428,10 @@ ath5k_intr(int irq, void *dev_id) /* bump tx trigger level */ ath5k_hw_update_tx_triglevel(ah, true); } - if (status & AR5K_INT_RX) + if (status & (AR5K_INT_RXOK | AR5K_INT_RXERR)) tasklet_schedule(&sc->rxtq); - if (status & AR5K_INT_TX) + if (status & (AR5K_INT_TXOK | AR5K_INT_TXDESC + | AR5K_INT_TXERR | AR5K_INT_TXEOL)) tasklet_schedule(&sc->txtq); if (status & AR5K_INT_BMISS) { } @@ -2527,8 +2547,7 @@ ath5k_register_led(struct ath5k_softc *sc, struct ath5k_led *led, led->led_dev.brightness_set = ath5k_led_brightness_set; err = led_classdev_register(&sc->pdev->dev, &led->led_dev); - if (err) - { + if (err) { ATH5K_WARN(sc, "could not register LED %s\n", name); led->sc = NULL; } @@ -2607,7 +2626,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) struct ath5k_buf *bf; unsigned long flags; int hdrlen; - int pad; + int padsize; ath5k_debug_dump_skb(sc, skb, "TX ", 1); @@ -2619,15 +2638,16 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) * if this is not the case we add the padding after the header */ hdrlen = ieee80211_get_hdrlen_from_skb(skb); - if (hdrlen & 3) { - pad = hdrlen % 4; - if (skb_headroom(skb) < pad) { + padsize = ath5k_pad_size(hdrlen); + if (padsize) { + + if (skb_headroom(skb) < padsize) { ATH5K_ERR(sc, "tx hdrlen not %%4: %d not enough" - " headroom to pad %d\n", hdrlen, pad); + " headroom to pad %d\n", hdrlen, padsize); return -1; } - skb_push(skb, pad); - memmove(skb->data, skb->data+pad, hdrlen); + skb_push(skb, padsize); + memmove(skb->data, skb->data+padsize, hdrlen); } spin_lock_irqsave(&sc->txbuflock, flags); @@ -2746,8 +2766,10 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, sc->vif = conf->vif; switch (conf->type) { + case NL80211_IFTYPE_AP: case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_MONITOR: sc->opmode = conf->type; break; @@ -2759,6 +2781,7 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, /* Set to a reasonable value. Note that this will * be set to mac80211's value at ath5k_config(). */ sc->bintval = 1000; + ath5k_hw_set_lladdr(sc->ah, conf->mac_addr); ret = 0; end: @@ -2771,11 +2794,13 @@ ath5k_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { struct ath5k_softc *sc = hw->priv; + u8 mac[ETH_ALEN] = {}; mutex_lock(&sc->lock); if (sc->vif != conf->vif) goto end; + ath5k_hw_set_lladdr(sc->ah, mac); sc->vif = NULL; end: mutex_unlock(&sc->lock); @@ -2785,10 +2810,10 @@ ath5k_remove_interface(struct ieee80211_hw *hw, * TODO: Phy disable/diversity etc */ static int -ath5k_config(struct ieee80211_hw *hw, - struct ieee80211_conf *conf) +ath5k_config(struct ieee80211_hw *hw, u32 changed) { struct ath5k_softc *sc = hw->priv; + struct ieee80211_conf *conf = &hw->conf; sc->bintval = conf->beacon_int; sc->power_level = conf->power_level; @@ -2809,7 +2834,7 @@ ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ret = -EIO; goto unlock; } - if (conf->bssid) { + if (conf->changed & IEEE80211_IFCC_BSSID && conf->bssid) { /* Cache for later use during resets */ memcpy(ah->ah_bssid, conf->bssid, ETH_ALEN); /* XXX: assoc id is set to 0 for now, mac80211 doesn't have @@ -2817,18 +2842,17 @@ ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ath5k_hw_set_associd(ah, ah->ah_bssid, 0); mmiowb(); } - if (conf->changed & IEEE80211_IFCC_BEACON && - vif->type == NL80211_IFTYPE_ADHOC) { + (vif->type == NL80211_IFTYPE_ADHOC || + vif->type == NL80211_IFTYPE_MESH_POINT || + vif->type == NL80211_IFTYPE_AP)) { struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); if (!beacon) { ret = -ENOMEM; goto unlock; } - /* call old handler for now */ - ath5k_beacon_update(hw, beacon); + ath5k_beacon_update(sc, beacon); } - mutex_unlock(&sc->lock); return ath5k_reset_wake(sc); @@ -2888,9 +2912,9 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw, if (*new_flags & FIF_PROMISC_IN_BSS) { rfilt |= AR5K_RX_FILTER_PROM; __set_bit(ATH_STAT_PROMISC, sc->status); - } - else + } else { __clear_bit(ATH_STAT_PROMISC, sc->status); + } } /* Note, AR5K_RX_FILTER_MCAST is already enabled */ @@ -2948,12 +2972,15 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw, test_bit(ATH_STAT_PROMISC, sc->status)) rfilt |= AR5K_RX_FILTER_PROM; if ((sc->opmode == NL80211_IFTYPE_STATION && sc->assoc) || - sc->opmode == NL80211_IFTYPE_ADHOC) { + sc->opmode == NL80211_IFTYPE_ADHOC || + sc->opmode == NL80211_IFTYPE_AP) rfilt |= AR5K_RX_FILTER_BEACON; - } + if (sc->opmode == NL80211_IFTYPE_MESH_POINT) + rfilt |= AR5K_RX_FILTER_CONTROL | AR5K_RX_FILTER_BEACON | + AR5K_RX_FILTER_PROBEREQ | AR5K_RX_FILTER_PROM; /* Set filters */ - ath5k_hw_set_rx_filter(ah,rfilt); + ath5k_hw_set_rx_filter(ah, rfilt); /* Set multicast bits */ ath5k_hw_set_mcast_filter(ah, mfilt[0], mfilt[1]); @@ -2970,12 +2997,13 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ath5k_softc *sc = hw->priv; int ret = 0; - switch(key->alg) { + if (modparam_nohwcrypt) + return -EOPNOTSUPP; + + switch (key->alg) { case ALG_WEP: - /* XXX: fix hardware encryption, its not working. For now - * allow software encryption */ - /* break; */ case ALG_TKIP: + break; case ALG_CCMP: return -EOPNOTSUPP; default: @@ -2994,6 +3022,8 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, } __set_bit(key->keyidx, sc->keymap); key->hw_key_idx = key->keyidx; + key->flags |= (IEEE80211_KEY_FLAG_GENERATE_IV | + IEEE80211_KEY_FLAG_GENERATE_MMIC); break; case DISABLE_KEY: ath5k_hw_reset_key(sc->ah, key->keyidx); @@ -3060,19 +3090,13 @@ ath5k_reset_tsf(struct ieee80211_hw *hw) } static int -ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) +ath5k_beacon_update(struct ath5k_softc *sc, struct sk_buff *skb) { - struct ath5k_softc *sc = hw->priv; unsigned long flags; int ret; ath5k_debug_dump_skb(sc, skb, "BC ", 1); - if (sc->opmode != NL80211_IFTYPE_ADHOC) { - ret = -EIO; - goto end; - } - spin_lock_irqsave(&sc->block, flags); ath5k_txbuf_free(sc, sc->bbuf); sc->bbuf->skb = skb; @@ -3085,7 +3109,6 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) mmiowb(); } -end: return ret; } static void diff --git a/drivers/net/wireless/ath5k/desc.c b/drivers/net/wireless/ath5k/desc.c index 5e362a7a362007aec0c8bf6800de1d97a587166d..b40a9287a39a8a3be2fd8888c2f5dd8fde484511 100644 --- a/drivers/net/wireless/ath5k/desc.c +++ b/drivers/net/wireless/ath5k/desc.c @@ -71,7 +71,7 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, /* Verify and set frame length */ /* remove padding we might have added before */ - frame_len = pkt_len - (hdr_len & 3) + FCS_LEN; + frame_len = pkt_len - ath5k_pad_size(hdr_len) + FCS_LEN; if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN) return -EINVAL; @@ -202,7 +202,7 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, /* Verify and set frame length */ /* remove padding we might have added before */ - frame_len = pkt_len - (hdr_len & 3) + FCS_LEN; + frame_len = pkt_len - ath5k_pad_size(hdr_len) + FCS_LEN; if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN) return -EINVAL; diff --git a/drivers/net/wireless/ath5k/dma.c b/drivers/net/wireless/ath5k/dma.c index 7adceb2c7fab50c33d4769b04364ec6655b4ad3e..7e2b1a67e5da3c505cddea78fde4406ab80254fd 100644 --- a/drivers/net/wireless/ath5k/dma.c +++ b/drivers/net/wireless/ath5k/dma.c @@ -472,9 +472,6 @@ bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah) * * NOTE: We use read-and-clear register, so after this function is called ISR * is zeroed. - * - * XXX: Why filter interrupts in sw with interrupt_mask ? No benefit at all - * plus it can be misleading (one might thing that we save interrupts this way) */ int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask) { @@ -494,11 +491,16 @@ int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask) } } else { /* - * Read interrupt status from the Read-And-Clear - * shadow register. + * Read interrupt status from Interrupt + * Status Register shadow copy (Read And Clear) + * * Note: PISR/SISR Not available on 5210 */ data = ath5k_hw_reg_read(ah, AR5K_RAC_PISR); + if (unlikely(data == AR5K_INT_NOCARD)) { + *interrupt_mask = data; + return -ENODEV; + } } /* @@ -506,17 +508,9 @@ int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask) */ *interrupt_mask = (data & AR5K_INT_COMMON) & ah->ah_imr; - if (unlikely(data == AR5K_INT_NOCARD)) - return -ENODEV; - - if (data & (AR5K_ISR_RXOK | AR5K_ISR_RXERR)) - *interrupt_mask |= AR5K_INT_RX; - - if (data & (AR5K_ISR_TXOK | AR5K_ISR_TXERR - | AR5K_ISR_TXDESC | AR5K_ISR_TXEOL)) - *interrupt_mask |= AR5K_INT_TX; - if (ah->ah_version != AR5K_AR5210) { + u32 sisr2 = ath5k_hw_reg_read(ah, AR5K_RAC_SISR2); + /*HIU = Host Interface Unit (PCI etc)*/ if (unlikely(data & (AR5K_ISR_HIUERR))) *interrupt_mask |= AR5K_INT_FATAL; @@ -524,24 +518,93 @@ int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask) /*Beacon Not Ready*/ if (unlikely(data & (AR5K_ISR_BNR))) *interrupt_mask |= AR5K_INT_BNR; - } - /* - * XXX: BMISS interrupts may occur after association. - * I found this on 5210 code but it needs testing. If this is - * true we should disable them before assoc and re-enable them - * after a successfull assoc + some jiffies. - */ -#if 0 - interrupt_mask &= ~AR5K_INT_BMISS; -#endif + if (unlikely(sisr2 & (AR5K_SISR2_SSERR | + AR5K_SISR2_DPERR | + AR5K_SISR2_MCABT))) + *interrupt_mask |= AR5K_INT_FATAL; + + if (data & AR5K_ISR_TIM) + *interrupt_mask |= AR5K_INT_TIM; + + if (data & AR5K_ISR_BCNMISC) { + if (sisr2 & AR5K_SISR2_TIM) + *interrupt_mask |= AR5K_INT_TIM; + if (sisr2 & AR5K_SISR2_DTIM) + *interrupt_mask |= AR5K_INT_DTIM; + if (sisr2 & AR5K_SISR2_DTIM_SYNC) + *interrupt_mask |= AR5K_INT_DTIM_SYNC; + if (sisr2 & AR5K_SISR2_BCN_TIMEOUT) + *interrupt_mask |= AR5K_INT_BCN_TIMEOUT; + if (sisr2 & AR5K_SISR2_CAB_TIMEOUT) + *interrupt_mask |= AR5K_INT_CAB_TIMEOUT; + } + + if (data & AR5K_ISR_RXDOPPLER) + *interrupt_mask |= AR5K_INT_RX_DOPPLER; + if (data & AR5K_ISR_QCBRORN) { + *interrupt_mask |= AR5K_INT_QCBRORN; + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR3), + AR5K_SISR3_QCBRORN); + } + if (data & AR5K_ISR_QCBRURN) { + *interrupt_mask |= AR5K_INT_QCBRURN; + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR3), + AR5K_SISR3_QCBRURN); + } + if (data & AR5K_ISR_QTRIG) { + *interrupt_mask |= AR5K_INT_QTRIG; + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR4), + AR5K_SISR4_QTRIG); + } + + if (data & AR5K_ISR_TXOK) + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR0), + AR5K_SISR0_QCU_TXOK); + + if (data & AR5K_ISR_TXDESC) + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR0), + AR5K_SISR0_QCU_TXDESC); + + if (data & AR5K_ISR_TXERR) + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR1), + AR5K_SISR1_QCU_TXERR); + + if (data & AR5K_ISR_TXEOL) + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR1), + AR5K_SISR1_QCU_TXEOL); + + if (data & AR5K_ISR_TXURN) + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR2), + AR5K_SISR2_QCU_TXURN); + } else { + if (unlikely(data & (AR5K_ISR_SSERR | AR5K_ISR_MCABT + | AR5K_ISR_HIUERR | AR5K_ISR_DPERR))) + *interrupt_mask |= AR5K_INT_FATAL; + + /* + * XXX: BMISS interrupts may occur after association. + * I found this on 5210 code but it needs testing. If this is + * true we should disable them before assoc and re-enable them + * after a successfull assoc + some jiffies. + interrupt_mask &= ~AR5K_INT_BMISS; + */ + } /* * In case we didn't handle anything, * print the register value. */ if (unlikely(*interrupt_mask == 0 && net_ratelimit())) - ATH5K_PRINTF("0x%08x\n", data); + ATH5K_PRINTF("ISR: 0x%08x IMR: 0x%08x\n", data, ah->ah_imr); return 0; } @@ -560,14 +623,17 @@ enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask) { enum ath5k_int old_mask, int_mask; + old_mask = ah->ah_imr; + /* * Disable card interrupts to prevent any race conditions - * (they will be re-enabled afterwards). + * (they will be re-enabled afterwards if AR5K_INT GLOBAL + * is set again on the new mask). */ - ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER); - ath5k_hw_reg_read(ah, AR5K_IER); - - old_mask = ah->ah_imr; + if (old_mask & AR5K_INT_GLOBAL) { + ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER); + ath5k_hw_reg_read(ah, AR5K_IER); + } /* * Add additional, chipset-dependent interrupt mask flags @@ -575,30 +641,64 @@ enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask) */ int_mask = new_mask & AR5K_INT_COMMON; - if (new_mask & AR5K_INT_RX) - int_mask |= AR5K_IMR_RXOK | AR5K_IMR_RXERR | AR5K_IMR_RXORN | - AR5K_IMR_RXDESC; - - if (new_mask & AR5K_INT_TX) - int_mask |= AR5K_IMR_TXOK | AR5K_IMR_TXERR | AR5K_IMR_TXDESC | - AR5K_IMR_TXURN; - if (ah->ah_version != AR5K_AR5210) { + /* Preserve per queue TXURN interrupt mask */ + u32 simr2 = ath5k_hw_reg_read(ah, AR5K_SIMR2) + & AR5K_SIMR2_QCU_TXURN; + if (new_mask & AR5K_INT_FATAL) { int_mask |= AR5K_IMR_HIUERR; - AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_MCABT | - AR5K_SIMR2_SSERR | AR5K_SIMR2_DPERR); + simr2 |= (AR5K_SIMR2_MCABT | AR5K_SIMR2_SSERR + | AR5K_SIMR2_DPERR); } + + /*Beacon Not Ready*/ + if (new_mask & AR5K_INT_BNR) + int_mask |= AR5K_INT_BNR; + + if (new_mask & AR5K_INT_TIM) + int_mask |= AR5K_IMR_TIM; + + if (new_mask & AR5K_INT_TIM) + simr2 |= AR5K_SISR2_TIM; + if (new_mask & AR5K_INT_DTIM) + simr2 |= AR5K_SISR2_DTIM; + if (new_mask & AR5K_INT_DTIM_SYNC) + simr2 |= AR5K_SISR2_DTIM_SYNC; + if (new_mask & AR5K_INT_BCN_TIMEOUT) + simr2 |= AR5K_SISR2_BCN_TIMEOUT; + if (new_mask & AR5K_INT_CAB_TIMEOUT) + simr2 |= AR5K_SISR2_CAB_TIMEOUT; + + if (new_mask & AR5K_INT_RX_DOPPLER) + int_mask |= AR5K_IMR_RXDOPPLER; + + /* Note: Per queue interrupt masks + * are set via reset_tx_queue (qcu.c) */ + ath5k_hw_reg_write(ah, int_mask, AR5K_PIMR); + ath5k_hw_reg_write(ah, simr2, AR5K_SIMR2); + + } else { + if (new_mask & AR5K_INT_FATAL) + int_mask |= (AR5K_IMR_SSERR | AR5K_IMR_MCABT + | AR5K_IMR_HIUERR | AR5K_IMR_DPERR); + + ath5k_hw_reg_write(ah, int_mask, AR5K_IMR); } - ath5k_hw_reg_write(ah, int_mask, AR5K_PIMR); + /* If RXNOFRM interrupt is masked disable it + * by setting AR5K_RXNOFRM to zero */ + if (!(new_mask & AR5K_INT_RXNOFRM)) + ath5k_hw_reg_write(ah, 0, AR5K_RXNOFRM); /* Store new interrupt mask */ ah->ah_imr = new_mask; - /* ..re-enable interrupts */ - ath5k_hw_reg_write(ah, AR5K_IER_ENABLE, AR5K_IER); - ath5k_hw_reg_read(ah, AR5K_IER); + /* ..re-enable interrupts if AR5K_INT_GLOBAL is set */ + if (new_mask & AR5K_INT_GLOBAL) { + ath5k_hw_reg_write(ah, AR5K_IER_ENABLE, AR5K_IER); + ath5k_hw_reg_read(ah, AR5K_IER); + } return old_mask; } diff --git a/drivers/net/wireless/ath5k/eeprom.c b/drivers/net/wireless/ath5k/eeprom.c index a883839b6a9f2a2c7249e6f490658fe07f21368d..1cb7edfae625cca6076f45d6b11afa8463ae47cb 100644 --- a/drivers/net/wireless/ath5k/eeprom.c +++ b/drivers/net/wireless/ath5k/eeprom.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2004-2008 Reyk Floeter * Copyright (c) 2006-2008 Nick Kossifidis + * Copyright (c) 2008 Felix Fietkau * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -63,8 +64,8 @@ static int ath5k_hw_eeprom_read(struct ath5k_hw *ah, u32 offset, u16 *data) /* * Translate binary channel representation in EEPROM to frequency */ -static u16 ath5k_eeprom_bin2freq(struct ath5k_hw *ah, u16 bin, - unsigned int mode) +static u16 ath5k_eeprom_bin2freq(struct ath5k_eeprom_info *ee, u16 bin, + unsigned int mode) { u16 val; @@ -72,13 +73,13 @@ static u16 ath5k_eeprom_bin2freq(struct ath5k_hw *ah, u16 bin, return bin; if (mode == AR5K_EEPROM_MODE_11A) { - if (ah->ah_ee_version > AR5K_EEPROM_VERSION_3_2) + if (ee->ee_version > AR5K_EEPROM_VERSION_3_2) val = (5 * bin) + 4800; else val = bin > 62 ? (10 * 62) + (5 * (bin - 62)) + 5100 : (bin * 10) + 5100; } else { - if (ah->ah_ee_version > AR5K_EEPROM_VERSION_3_2) + if (ee->ee_version > AR5K_EEPROM_VERSION_3_2) val = bin + 2300; else val = bin + 2400; @@ -87,6 +88,71 @@ static u16 ath5k_eeprom_bin2freq(struct ath5k_hw *ah, u16 bin, return val; } +/* + * Initialize eeprom & capabilities structs + */ +static int +ath5k_eeprom_init_header(struct ath5k_hw *ah) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + int ret; + u16 val; + + /* Initial TX thermal adjustment values */ + ee->ee_tx_clip = 4; + ee->ee_pwd_84 = ee->ee_pwd_90 = 1; + ee->ee_gain_select = 1; + + /* + * Read values from EEPROM and store them in the capability structure + */ + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MAGIC, ee_magic); + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_PROTECT, ee_protect); + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_REG_DOMAIN, ee_regdomain); + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_VERSION, ee_version); + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_HDR, ee_header); + + /* Return if we have an old EEPROM */ + if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_0) + return 0; + +#ifdef notyet + /* + * Validate the checksum of the EEPROM date. There are some + * devices with invalid EEPROMs. + */ + for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) { + AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val); + cksum ^= val; + } + if (cksum != AR5K_EEPROM_INFO_CKSUM) { + ATH5K_ERR(ah->ah_sc, "Invalid EEPROM checksum 0x%04x\n", cksum); + return -EIO; + } +#endif + + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(ah->ah_ee_version), + ee_ant_gain); + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) { + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0); + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1); + } + + if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_3) { + AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val); + ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7; + ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7; + + AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val); + ee->ee_ob[AR5K_EEPROM_MODE_11G][0] = val & 0x7; + ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7; + } + + return 0; +} + + /* * Read antenna infos from eeprom */ @@ -100,7 +166,7 @@ static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset, AR5K_EEPROM_READ(o++, val); ee->ee_switch_settling[mode] = (val >> 8) & 0x7f; - ee->ee_ant_tx_rx[mode] = (val >> 2) & 0x3f; + ee->ee_atn_tx_rx[mode] = (val >> 2) & 0x3f; ee->ee_ant_control[mode][i] = (val << 4) & 0x3f; AR5K_EEPROM_READ(o++, val); @@ -157,6 +223,30 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset, u16 val; int ret; + ee->ee_n_piers[mode] = 0; + AR5K_EEPROM_READ(o++, val); + ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff); + switch(mode) { + case AR5K_EEPROM_MODE_11A: + ee->ee_ob[mode][3] = (val >> 5) & 0x7; + ee->ee_db[mode][3] = (val >> 2) & 0x7; + ee->ee_ob[mode][2] = (val << 1) & 0x7; + + AR5K_EEPROM_READ(o++, val); + ee->ee_ob[mode][2] |= (val >> 15) & 0x1; + ee->ee_db[mode][2] = (val >> 12) & 0x7; + ee->ee_ob[mode][1] = (val >> 9) & 0x7; + ee->ee_db[mode][1] = (val >> 6) & 0x7; + ee->ee_ob[mode][0] = (val >> 3) & 0x7; + ee->ee_db[mode][0] = val & 0x7; + break; + case AR5K_EEPROM_MODE_11G: + case AR5K_EEPROM_MODE_11B: + ee->ee_ob[mode][1] = (val >> 4) & 0x7; + ee->ee_db[mode][1] = val & 0x7; + break; + } + AR5K_EEPROM_READ(o++, val); ee->ee_tx_end2xlna_enable[mode] = (val >> 8) & 0xff; ee->ee_thr_62[mode] = val & 0xff; @@ -209,8 +299,11 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset, AR5K_EEPROM_READ(o++, val); ee->ee_i_gain[mode] |= (val << 3) & 0x38; - if (mode == AR5K_EEPROM_MODE_11G) + if (mode == AR5K_EEPROM_MODE_11G) { ee->ee_cck_ofdm_power_delta = (val >> 3) & 0xff; + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_6) + ee->ee_scaled_cck_delta = (val >> 11) & 0x1f; + } } if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0 && @@ -219,10 +312,77 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset, ee->ee_q_cal[mode] = (val >> 3) & 0x1f; } - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_6 && - mode == AR5K_EEPROM_MODE_11G) - ee->ee_scaled_cck_delta = (val >> 11) & 0x1f; + if (ah->ah_ee_version < AR5K_EEPROM_VERSION_4_0) + goto done; + + switch(mode) { + case AR5K_EEPROM_MODE_11A: + if (ah->ah_ee_version < AR5K_EEPROM_VERSION_4_1) + break; + + AR5K_EEPROM_READ(o++, val); + ee->ee_margin_tx_rx[mode] = val & 0x3f; + break; + case AR5K_EEPROM_MODE_11B: + AR5K_EEPROM_READ(o++, val); + + ee->ee_pwr_cal_b[0].freq = + ath5k_eeprom_bin2freq(ee, val & 0xff, mode); + if (ee->ee_pwr_cal_b[0].freq != AR5K_EEPROM_CHANNEL_DIS) + ee->ee_n_piers[mode]++; + + ee->ee_pwr_cal_b[1].freq = + ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode); + if (ee->ee_pwr_cal_b[1].freq != AR5K_EEPROM_CHANNEL_DIS) + ee->ee_n_piers[mode]++; + + AR5K_EEPROM_READ(o++, val); + ee->ee_pwr_cal_b[2].freq = + ath5k_eeprom_bin2freq(ee, val & 0xff, mode); + if (ee->ee_pwr_cal_b[2].freq != AR5K_EEPROM_CHANNEL_DIS) + ee->ee_n_piers[mode]++; + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) + ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f; + break; + case AR5K_EEPROM_MODE_11G: + AR5K_EEPROM_READ(o++, val); + + ee->ee_pwr_cal_g[0].freq = + ath5k_eeprom_bin2freq(ee, val & 0xff, mode); + if (ee->ee_pwr_cal_g[0].freq != AR5K_EEPROM_CHANNEL_DIS) + ee->ee_n_piers[mode]++; + + ee->ee_pwr_cal_g[1].freq = + ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode); + if (ee->ee_pwr_cal_g[1].freq != AR5K_EEPROM_CHANNEL_DIS) + ee->ee_n_piers[mode]++; + + AR5K_EEPROM_READ(o++, val); + ee->ee_turbo_max_power[mode] = val & 0x7f; + ee->ee_xr_power[mode] = (val >> 7) & 0x3f; + + AR5K_EEPROM_READ(o++, val); + ee->ee_pwr_cal_g[2].freq = + ath5k_eeprom_bin2freq(ee, val & 0xff, mode); + if (ee->ee_pwr_cal_g[2].freq != AR5K_EEPROM_CHANNEL_DIS) + ee->ee_n_piers[mode]++; + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) + ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f; + + AR5K_EEPROM_READ(o++, val); + ee->ee_i_cal[mode] = (val >> 8) & 0x3f; + ee->ee_q_cal[mode] = (val >> 3) & 0x1f; + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_2) { + AR5K_EEPROM_READ(o++, val); + ee->ee_cck_ofdm_gain_delta = val & 0xff; + } + break; + } + +done: /* return new offset */ *offset = o; @@ -230,204 +390,944 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset, } /* - * Initialize eeprom & capabilities structs + * Read turbo mode information on newer EEPROM versions */ -int ath5k_eeprom_init(struct ath5k_hw *ah) +static int +ath5k_eeprom_read_turbo_modes(struct ath5k_hw *ah, + u32 *offset, unsigned int mode) { struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - unsigned int mode, i; - int ret; - u32 offset; + u32 o = *offset; u16 val; + int ret; - /* Initial TX thermal adjustment values */ - ee->ee_tx_clip = 4; - ee->ee_pwd_84 = ee->ee_pwd_90 = 1; - ee->ee_gain_select = 1; + if (ee->ee_version < AR5K_EEPROM_VERSION_5_0) + return 0; - /* - * Read values from EEPROM and store them in the capability structure - */ - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MAGIC, ee_magic); - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_PROTECT, ee_protect); - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_REG_DOMAIN, ee_regdomain); - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_VERSION, ee_version); - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_HDR, ee_header); + switch (mode){ + case AR5K_EEPROM_MODE_11A: + ee->ee_switch_settling_turbo[mode] = (val >> 6) & 0x7f; - /* Return if we have an old EEPROM */ - if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_0) - return 0; + ee->ee_atn_tx_rx_turbo[mode] = (val >> 13) & 0x7; + AR5K_EEPROM_READ(o++, val); + ee->ee_atn_tx_rx_turbo[mode] |= (val & 0x7) << 3; + ee->ee_margin_tx_rx_turbo[mode] = (val >> 3) & 0x3f; + + ee->ee_adc_desired_size_turbo[mode] = (val >> 9) & 0x7f; + AR5K_EEPROM_READ(o++, val); + ee->ee_adc_desired_size_turbo[mode] |= (val & 0x1) << 7; + ee->ee_pga_desired_size_turbo[mode] = (val >> 1) & 0xff; + + if (AR5K_EEPROM_EEMAP(ee->ee_misc0) >=2) + ee->ee_pd_gain_overlap = (val >> 9) & 0xf; + break; + case AR5K_EEPROM_MODE_11G: + ee->ee_switch_settling_turbo[mode] = (val >> 8) & 0x7f; + + ee->ee_atn_tx_rx_turbo[mode] = (val >> 15) & 0x7; + AR5K_EEPROM_READ(o++, val); + ee->ee_atn_tx_rx_turbo[mode] |= (val & 0x1f) << 1; + ee->ee_margin_tx_rx_turbo[mode] = (val >> 5) & 0x3f; + + ee->ee_adc_desired_size_turbo[mode] = (val >> 11) & 0x7f; + AR5K_EEPROM_READ(o++, val); + ee->ee_adc_desired_size_turbo[mode] |= (val & 0x7) << 5; + ee->ee_pga_desired_size_turbo[mode] = (val >> 3) & 0xff; + break; + } + + /* return new offset */ + *offset = o; + + return 0; +} + + +static int +ath5k_eeprom_init_modes(struct ath5k_hw *ah) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + u32 mode_offset[3]; + unsigned int mode; + u32 offset; + int ret; -#ifdef notyet /* - * Validate the checksum of the EEPROM date. There are some - * devices with invalid EEPROMs. + * Get values for all modes */ - for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) { - AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val); - cksum ^= val; + mode_offset[AR5K_EEPROM_MODE_11A] = AR5K_EEPROM_MODES_11A(ah->ah_ee_version); + mode_offset[AR5K_EEPROM_MODE_11B] = AR5K_EEPROM_MODES_11B(ah->ah_ee_version); + mode_offset[AR5K_EEPROM_MODE_11G] = AR5K_EEPROM_MODES_11G(ah->ah_ee_version); + + ee->ee_turbo_max_power[AR5K_EEPROM_MODE_11A] = + AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header); + + for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++) { + offset = mode_offset[mode]; + + ret = ath5k_eeprom_read_ants(ah, &offset, mode); + if (ret) + return ret; + + ret = ath5k_eeprom_read_modes(ah, &offset, mode); + if (ret) + return ret; + + ret = ath5k_eeprom_read_turbo_modes(ah, &offset, mode); + if (ret) + return ret; } - if (cksum != AR5K_EEPROM_INFO_CKSUM) { - ATH5K_ERR(ah->ah_sc, "Invalid EEPROM checksum 0x%04x\n", cksum); - return -EIO; + + /* override for older eeprom versions for better performance */ + if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2) { + ee->ee_thr_62[AR5K_EEPROM_MODE_11A] = 15; + ee->ee_thr_62[AR5K_EEPROM_MODE_11B] = 28; + ee->ee_thr_62[AR5K_EEPROM_MODE_11G] = 28; } -#endif - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(ah->ah_ee_version), - ee_ant_gain); + return 0; +} - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) { - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0); - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1); - } +static inline void +ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp) +{ + const static u16 intercepts3[] = + { 0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100 }; + const static u16 intercepts3_2[] = + { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 }; + const u16 *ip; + int i; + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_2) + ip = intercepts3_2; + else + ip = intercepts3; - if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_3) { - AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val); - ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7; - ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7; + for (i = 0; i < ARRAY_SIZE(intercepts3); i++) + *vp++ = (ip[i] * max + (100 - ip[i]) * min) / 100; +} - AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val); - ee->ee_ob[AR5K_EEPROM_MODE_11G][0] = val & 0x7; - ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7; +static inline int +ath5k_eeprom_read_freq_list(struct ath5k_hw *ah, int *offset, int max, + struct ath5k_chan_pcal_info *pc, u8 *count) +{ + int o = *offset; + int i = 0; + u8 f1, f2; + int ret; + u16 val; + + while(i < max) { + AR5K_EEPROM_READ(o++, val); + + f1 = (val >> 8) & 0xff; + f2 = val & 0xff; + + if (f1) + pc[i++].freq = f1; + + if (f2) + pc[i++].freq = f2; + + if (!f1 || !f2) + break; } + *offset = o; + *count = i; - /* - * Get conformance test limit values - */ - offset = AR5K_EEPROM_CTL(ah->ah_ee_version); - ee->ee_ctls = AR5K_EEPROM_N_CTLS(ah->ah_ee_version); + return 0; +} + +static int +ath5k_eeprom_init_11a_pcal_freq(struct ath5k_hw *ah, int offset) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_chan_pcal_info *pcal = ee->ee_pwr_cal_a; + int i, ret; + u16 val; + u8 mask; + + if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) { + ath5k_eeprom_read_freq_list(ah, &offset, + AR5K_EEPROM_N_5GHZ_CHAN, pcal, + &ee->ee_n_piers[AR5K_EEPROM_MODE_11A]); + } else { + mask = AR5K_EEPROM_FREQ_M(ah->ah_ee_version); - for (i = 0; i < ee->ee_ctls; i++) { AR5K_EEPROM_READ(offset++, val); - ee->ee_ctl[i] = (val >> 8) & 0xff; - ee->ee_ctl[i + 1] = val & 0xff; + pcal[0].freq = (val >> 9) & mask; + pcal[1].freq = (val >> 2) & mask; + pcal[2].freq = (val << 5) & mask; + + AR5K_EEPROM_READ(offset++, val); + pcal[2].freq |= (val >> 11) & 0x1f; + pcal[3].freq = (val >> 4) & mask; + pcal[4].freq = (val << 3) & mask; + + AR5K_EEPROM_READ(offset++, val); + pcal[4].freq |= (val >> 13) & 0x7; + pcal[5].freq = (val >> 6) & mask; + pcal[6].freq = (val << 1) & mask; + + AR5K_EEPROM_READ(offset++, val); + pcal[6].freq |= (val >> 15) & 0x1; + pcal[7].freq = (val >> 8) & mask; + pcal[8].freq = (val >> 1) & mask; + pcal[9].freq = (val << 6) & mask; + + AR5K_EEPROM_READ(offset++, val); + pcal[9].freq |= (val >> 10) & 0x3f; + ee->ee_n_piers[AR5K_EEPROM_MODE_11A] = 10; } - /* - * Get values for 802.11a (5GHz) - */ - mode = AR5K_EEPROM_MODE_11A; + for(i = 0; i < AR5K_EEPROM_N_5GHZ_CHAN; i += 1) { + pcal[i].freq = ath5k_eeprom_bin2freq(ee, + pcal[i].freq, AR5K_EEPROM_MODE_11A); + } - ee->ee_turbo_max_power[mode] = - AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header); + return 0; +} - offset = AR5K_EEPROM_MODES_11A(ah->ah_ee_version); +static inline int +ath5k_eeprom_init_11bg_2413(struct ath5k_hw *ah, unsigned int mode, int offset) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_chan_pcal_info *pcal; + int i; + + switch(mode) { + case AR5K_EEPROM_MODE_11B: + pcal = ee->ee_pwr_cal_b; + break; + case AR5K_EEPROM_MODE_11G: + pcal = ee->ee_pwr_cal_g; + break; + default: + return -EINVAL; + } - ret = ath5k_eeprom_read_ants(ah, &offset, mode); - if (ret) - return ret; + ath5k_eeprom_read_freq_list(ah, &offset, + AR5K_EEPROM_N_2GHZ_CHAN_2413, pcal, + &ee->ee_n_piers[mode]); + for(i = 0; i < AR5K_EEPROM_N_2GHZ_CHAN_2413; i += 1) { + pcal[i].freq = ath5k_eeprom_bin2freq(ee, + pcal[i].freq, mode); + } - AR5K_EEPROM_READ(offset++, val); - ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff); - ee->ee_ob[mode][3] = (val >> 5) & 0x7; - ee->ee_db[mode][3] = (val >> 2) & 0x7; - ee->ee_ob[mode][2] = (val << 1) & 0x7; - - AR5K_EEPROM_READ(offset++, val); - ee->ee_ob[mode][2] |= (val >> 15) & 0x1; - ee->ee_db[mode][2] = (val >> 12) & 0x7; - ee->ee_ob[mode][1] = (val >> 9) & 0x7; - ee->ee_db[mode][1] = (val >> 6) & 0x7; - ee->ee_ob[mode][0] = (val >> 3) & 0x7; - ee->ee_db[mode][0] = val & 0x7; - - ret = ath5k_eeprom_read_modes(ah, &offset, mode); - if (ret) - return ret; + return 0; +} - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) { - AR5K_EEPROM_READ(offset++, val); - ee->ee_margin_tx_rx[mode] = val & 0x3f; + +static int +ath5k_eeprom_read_pcal_info_5111(struct ath5k_hw *ah, int mode) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_chan_pcal_info *pcal; + int offset, ret; + int i, j; + u16 val; + + offset = AR5K_EEPROM_GROUPS_START(ee->ee_version); + switch(mode) { + case AR5K_EEPROM_MODE_11A: + if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) + return 0; + + ret = ath5k_eeprom_init_11a_pcal_freq(ah, + offset + AR5K_EEPROM_GROUP1_OFFSET); + if (ret < 0) + return ret; + + offset += AR5K_EEPROM_GROUP2_OFFSET; + pcal = ee->ee_pwr_cal_a; + break; + case AR5K_EEPROM_MODE_11B: + if (!AR5K_EEPROM_HDR_11B(ee->ee_header) && + !AR5K_EEPROM_HDR_11G(ee->ee_header)) + return 0; + + pcal = ee->ee_pwr_cal_b; + offset += AR5K_EEPROM_GROUP3_OFFSET; + + /* fixed piers */ + pcal[0].freq = 2412; + pcal[1].freq = 2447; + pcal[2].freq = 2484; + ee->ee_n_piers[mode] = 3; + break; + case AR5K_EEPROM_MODE_11G: + if (!AR5K_EEPROM_HDR_11G(ee->ee_header)) + return 0; + + pcal = ee->ee_pwr_cal_g; + offset += AR5K_EEPROM_GROUP4_OFFSET; + + /* fixed piers */ + pcal[0].freq = 2312; + pcal[1].freq = 2412; + pcal[2].freq = 2484; + ee->ee_n_piers[mode] = 3; + break; + default: + return -EINVAL; } - /* - * Get values for 802.11b (2.4GHz) - */ - mode = AR5K_EEPROM_MODE_11B; - offset = AR5K_EEPROM_MODES_11B(ah->ah_ee_version); + for (i = 0; i < ee->ee_n_piers[mode]; i++) { + struct ath5k_chan_pcal_info_rf5111 *cdata = + &pcal[i].rf5111_info; - ret = ath5k_eeprom_read_ants(ah, &offset, mode); - if (ret) - return ret; + AR5K_EEPROM_READ(offset++, val); + cdata->pcdac_max = ((val >> 10) & AR5K_EEPROM_PCDAC_M); + cdata->pcdac_min = ((val >> 4) & AR5K_EEPROM_PCDAC_M); + cdata->pwr[0] = ((val << 2) & AR5K_EEPROM_POWER_M); - AR5K_EEPROM_READ(offset++, val); - ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff); - ee->ee_ob[mode][1] = (val >> 4) & 0x7; - ee->ee_db[mode][1] = val & 0x7; + AR5K_EEPROM_READ(offset++, val); + cdata->pwr[0] |= ((val >> 14) & 0x3); + cdata->pwr[1] = ((val >> 8) & AR5K_EEPROM_POWER_M); + cdata->pwr[2] = ((val >> 2) & AR5K_EEPROM_POWER_M); + cdata->pwr[3] = ((val << 4) & AR5K_EEPROM_POWER_M); - ret = ath5k_eeprom_read_modes(ah, &offset, mode); - if (ret) - return ret; + AR5K_EEPROM_READ(offset++, val); + cdata->pwr[3] |= ((val >> 12) & 0xf); + cdata->pwr[4] = ((val >> 6) & AR5K_EEPROM_POWER_M); + cdata->pwr[5] = (val & AR5K_EEPROM_POWER_M); - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) { AR5K_EEPROM_READ(offset++, val); - ee->ee_cal_pier[mode][0] = - ath5k_eeprom_bin2freq(ah, val & 0xff, mode); - ee->ee_cal_pier[mode][1] = - ath5k_eeprom_bin2freq(ah, (val >> 8) & 0xff, mode); + cdata->pwr[6] = ((val >> 10) & AR5K_EEPROM_POWER_M); + cdata->pwr[7] = ((val >> 4) & AR5K_EEPROM_POWER_M); + cdata->pwr[8] = ((val << 2) & AR5K_EEPROM_POWER_M); AR5K_EEPROM_READ(offset++, val); - ee->ee_cal_pier[mode][2] = - ath5k_eeprom_bin2freq(ah, val & 0xff, mode); + cdata->pwr[8] |= ((val >> 14) & 0x3); + cdata->pwr[9] = ((val >> 8) & AR5K_EEPROM_POWER_M); + cdata->pwr[10] = ((val >> 2) & AR5K_EEPROM_POWER_M); + + ath5k_get_pcdac_intercepts(ah, cdata->pcdac_min, + cdata->pcdac_max, cdata->pcdac); + + for (j = 0; j < AR5K_EEPROM_N_PCDAC; j++) { + cdata->pwr[j] = (u16) + (AR5K_EEPROM_POWER_STEP * cdata->pwr[j]); + } } - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) - ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f; + return 0; +} - /* - * Get values for 802.11g (2.4GHz) - */ - mode = AR5K_EEPROM_MODE_11G; - offset = AR5K_EEPROM_MODES_11G(ah->ah_ee_version); +static int +ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_chan_pcal_info_rf5112 *chan_pcal_info; + struct ath5k_chan_pcal_info *gen_chan_info; + u32 offset; + unsigned int i, c; + u16 val; + int ret; - ret = ath5k_eeprom_read_ants(ah, &offset, mode); - if (ret) - return ret; + switch (mode) { + case AR5K_EEPROM_MODE_11A: + /* + * Read 5GHz EEPROM channels + */ + offset = AR5K_EEPROM_GROUPS_START(ee->ee_version); + ath5k_eeprom_init_11a_pcal_freq(ah, offset); + + offset += AR5K_EEPROM_GROUP2_OFFSET; + gen_chan_info = ee->ee_pwr_cal_a; + break; + case AR5K_EEPROM_MODE_11B: + offset = AR5K_EEPROM_GROUPS_START(ee->ee_version); + if (AR5K_EEPROM_HDR_11A(ee->ee_header)) + offset += AR5K_EEPROM_GROUP3_OFFSET; + + /* NB: frequency piers parsed during mode init */ + gen_chan_info = ee->ee_pwr_cal_b; + break; + case AR5K_EEPROM_MODE_11G: + offset = AR5K_EEPROM_GROUPS_START(ee->ee_version); + if (AR5K_EEPROM_HDR_11A(ee->ee_header)) + offset += AR5K_EEPROM_GROUP4_OFFSET; + else if (AR5K_EEPROM_HDR_11B(ee->ee_header)) + offset += AR5K_EEPROM_GROUP2_OFFSET; + + /* NB: frequency piers parsed during mode init */ + gen_chan_info = ee->ee_pwr_cal_g; + break; + default: + return -EINVAL; + } - AR5K_EEPROM_READ(offset++, val); - ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff); - ee->ee_ob[mode][1] = (val >> 4) & 0x7; - ee->ee_db[mode][1] = val & 0x7; + for (i = 0; i < ee->ee_n_piers[mode]; i++) { + chan_pcal_info = &gen_chan_info[i].rf5112_info; - ret = ath5k_eeprom_read_modes(ah, &offset, mode); - if (ret) - return ret; + /* Power values in dBm * 4 + * for the lower xpd gain curve + * (0 dBm -> higher output power) */ + for (c = 0; c < AR5K_EEPROM_N_XPD0_POINTS; c++) { + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pwr_x0[c] = (val & 0xff); + chan_pcal_info->pwr_x0[++c] = ((val >> 8) & 0xff); + } - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) { + /* PCDAC steps + * corresponding to the above power + * measurements */ AR5K_EEPROM_READ(offset++, val); - ee->ee_cal_pier[mode][0] = - ath5k_eeprom_bin2freq(ah, val & 0xff, mode); - ee->ee_cal_pier[mode][1] = - ath5k_eeprom_bin2freq(ah, (val >> 8) & 0xff, mode); + chan_pcal_info->pcdac_x0[1] = (val & 0x1f); + chan_pcal_info->pcdac_x0[2] = ((val >> 5) & 0x1f); + chan_pcal_info->pcdac_x0[3] = ((val >> 10) & 0x1f); + /* Power values in dBm * 4 + * for the higher xpd gain curve + * (18 dBm -> lower output power) */ AR5K_EEPROM_READ(offset++, val); - ee->ee_turbo_max_power[mode] = val & 0x7f; - ee->ee_xr_power[mode] = (val >> 7) & 0x3f; + chan_pcal_info->pwr_x3[0] = (val & 0xff); + chan_pcal_info->pwr_x3[1] = ((val >> 8) & 0xff); AR5K_EEPROM_READ(offset++, val); - ee->ee_cal_pier[mode][2] = - ath5k_eeprom_bin2freq(ah, val & 0xff, mode); + chan_pcal_info->pwr_x3[2] = (val & 0xff); + + /* PCDAC steps + * corresponding to the above power + * measurements (static) */ + chan_pcal_info->pcdac_x3[0] = 20; + chan_pcal_info->pcdac_x3[1] = 35; + chan_pcal_info->pcdac_x3[2] = 63; + + if (ee->ee_version >= AR5K_EEPROM_VERSION_4_3) { + chan_pcal_info->pcdac_x0[0] = ((val >> 8) & 0xff); + + /* Last xpd0 power level is also channel maximum */ + gen_chan_info[i].max_pwr = chan_pcal_info->pwr_x0[3]; + } else { + chan_pcal_info->pcdac_x0[0] = 1; + gen_chan_info[i].max_pwr = ((val >> 8) & 0xff); + } - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) - ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f; + /* Recreate pcdac_x0 table for this channel using pcdac steps */ + chan_pcal_info->pcdac_x0[1] += chan_pcal_info->pcdac_x0[0]; + chan_pcal_info->pcdac_x0[2] += chan_pcal_info->pcdac_x0[1]; + chan_pcal_info->pcdac_x0[3] += chan_pcal_info->pcdac_x0[2]; + } + + return 0; +} + +static inline unsigned int +ath5k_pdgains_size_2413(struct ath5k_eeprom_info *ee, unsigned int mode) +{ + static const unsigned int pdgains_size[] = { 4, 6, 9, 12 }; + unsigned int sz; + + sz = pdgains_size[ee->ee_pd_gains[mode] - 1]; + sz *= ee->ee_n_piers[mode]; + + return sz; +} + +static unsigned int +ath5k_cal_data_offset_2413(struct ath5k_eeprom_info *ee, int mode) +{ + u32 offset = AR5K_EEPROM_CAL_DATA_START(ee->ee_misc4); + + switch(mode) { + case AR5K_EEPROM_MODE_11G: + if (AR5K_EEPROM_HDR_11B(ee->ee_header)) + offset += ath5k_pdgains_size_2413(ee, AR5K_EEPROM_MODE_11B) + 2; + /* fall through */ + case AR5K_EEPROM_MODE_11B: + if (AR5K_EEPROM_HDR_11A(ee->ee_header)) + offset += ath5k_pdgains_size_2413(ee, AR5K_EEPROM_MODE_11A) + 5; + /* fall through */ + case AR5K_EEPROM_MODE_11A: + break; + default: + break; + } + + return offset; +} + +static int +ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_chan_pcal_info_rf2413 *chan_pcal_info; + struct ath5k_chan_pcal_info *gen_chan_info; + unsigned int i, c; + u32 offset; + int ret; + u16 val; + u8 pd_gains = 0; + + if (ee->ee_x_gain[mode] & 0x1) pd_gains++; + if ((ee->ee_x_gain[mode] >> 1) & 0x1) pd_gains++; + if ((ee->ee_x_gain[mode] >> 2) & 0x1) pd_gains++; + if ((ee->ee_x_gain[mode] >> 3) & 0x1) pd_gains++; + ee->ee_pd_gains[mode] = pd_gains; + + offset = ath5k_cal_data_offset_2413(ee, mode); + switch (mode) { + case AR5K_EEPROM_MODE_11A: + if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) + return 0; + + ath5k_eeprom_init_11a_pcal_freq(ah, offset); + offset += AR5K_EEPROM_N_5GHZ_CHAN / 2; + gen_chan_info = ee->ee_pwr_cal_a; + break; + case AR5K_EEPROM_MODE_11B: + if (!AR5K_EEPROM_HDR_11B(ee->ee_header)) + return 0; + ath5k_eeprom_init_11bg_2413(ah, mode, offset); + offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; + gen_chan_info = ee->ee_pwr_cal_b; + break; + case AR5K_EEPROM_MODE_11G: + if (!AR5K_EEPROM_HDR_11G(ee->ee_header)) + return 0; + + ath5k_eeprom_init_11bg_2413(ah, mode, offset); + offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; + gen_chan_info = ee->ee_pwr_cal_g; + break; + default: + return -EINVAL; + } + + if (pd_gains == 0) + return 0; + + for (i = 0; i < ee->ee_n_piers[mode]; i++) { + chan_pcal_info = &gen_chan_info[i].rf2413_info; + + /* + * Read pwr_i, pddac_i and the first + * 2 pd points (pwr, pddac) + */ AR5K_EEPROM_READ(offset++, val); - ee->ee_i_cal[mode] = (val >> 8) & 0x3f; - ee->ee_q_cal[mode] = (val >> 3) & 0x1f; + chan_pcal_info->pwr_i[0] = val & 0x1f; + chan_pcal_info->pddac_i[0] = (val >> 5) & 0x7f; + chan_pcal_info->pwr[0][0] = + (val >> 12) & 0xf; - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_2) { + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pddac[0][0] = val & 0x3f; + chan_pcal_info->pwr[0][1] = (val >> 6) & 0xf; + chan_pcal_info->pddac[0][1] = + (val >> 10) & 0x3f; + + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pwr[0][2] = val & 0xf; + chan_pcal_info->pddac[0][2] = + (val >> 4) & 0x3f; + + chan_pcal_info->pwr[0][3] = 0; + chan_pcal_info->pddac[0][3] = 0; + + if (pd_gains > 1) { + /* + * Pd gain 0 is not the last pd gain + * so it only has 2 pd points. + * Continue wih pd gain 1. + */ + chan_pcal_info->pwr_i[1] = (val >> 10) & 0x1f; + + chan_pcal_info->pddac_i[1] = (val >> 15) & 0x1; AR5K_EEPROM_READ(offset++, val); - ee->ee_cck_ofdm_gain_delta = val & 0xff; + chan_pcal_info->pddac_i[1] |= (val & 0x3F) << 1; + + chan_pcal_info->pwr[1][0] = (val >> 6) & 0xf; + chan_pcal_info->pddac[1][0] = + (val >> 10) & 0x3f; + + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pwr[1][1] = val & 0xf; + chan_pcal_info->pddac[1][1] = + (val >> 4) & 0x3f; + chan_pcal_info->pwr[1][2] = + (val >> 10) & 0xf; + + chan_pcal_info->pddac[1][2] = + (val >> 14) & 0x3; + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pddac[1][2] |= + (val & 0xF) << 2; + + chan_pcal_info->pwr[1][3] = 0; + chan_pcal_info->pddac[1][3] = 0; + } else if (pd_gains == 1) { + /* + * Pd gain 0 is the last one so + * read the extra point. + */ + chan_pcal_info->pwr[0][3] = + (val >> 10) & 0xf; + + chan_pcal_info->pddac[0][3] = + (val >> 14) & 0x3; + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pddac[0][3] |= + (val & 0xF) << 2; + } + + /* + * Proceed with the other pd_gains + * as above. + */ + if (pd_gains > 2) { + chan_pcal_info->pwr_i[2] = (val >> 4) & 0x1f; + chan_pcal_info->pddac_i[2] = (val >> 9) & 0x7f; + + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pwr[2][0] = + (val >> 0) & 0xf; + chan_pcal_info->pddac[2][0] = + (val >> 4) & 0x3f; + chan_pcal_info->pwr[2][1] = + (val >> 10) & 0xf; + + chan_pcal_info->pddac[2][1] = + (val >> 14) & 0x3; + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pddac[2][1] |= + (val & 0xF) << 2; + + chan_pcal_info->pwr[2][2] = + (val >> 4) & 0xf; + chan_pcal_info->pddac[2][2] = + (val >> 8) & 0x3f; + + chan_pcal_info->pwr[2][3] = 0; + chan_pcal_info->pddac[2][3] = 0; + } else if (pd_gains == 2) { + chan_pcal_info->pwr[1][3] = + (val >> 4) & 0xf; + chan_pcal_info->pddac[1][3] = + (val >> 8) & 0x3f; + } + + if (pd_gains > 3) { + chan_pcal_info->pwr_i[3] = (val >> 14) & 0x3; + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pwr_i[3] |= ((val >> 0) & 0x7) << 2; + + chan_pcal_info->pddac_i[3] = (val >> 3) & 0x7f; + chan_pcal_info->pwr[3][0] = + (val >> 10) & 0xf; + chan_pcal_info->pddac[3][0] = + (val >> 14) & 0x3; + + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pddac[3][0] |= + (val & 0xF) << 2; + chan_pcal_info->pwr[3][1] = + (val >> 4) & 0xf; + chan_pcal_info->pddac[3][1] = + (val >> 8) & 0x3f; + + chan_pcal_info->pwr[3][2] = + (val >> 14) & 0x3; + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pwr[3][2] |= + ((val >> 0) & 0x3) << 2; + + chan_pcal_info->pddac[3][2] = + (val >> 2) & 0x3f; + chan_pcal_info->pwr[3][3] = + (val >> 8) & 0xf; + + chan_pcal_info->pddac[3][3] = + (val >> 12) & 0xF; + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pddac[3][3] |= + ((val >> 0) & 0x3) << 4; + } else if (pd_gains == 3) { + chan_pcal_info->pwr[2][3] = + (val >> 14) & 0x3; + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pwr[2][3] |= + ((val >> 0) & 0x3) << 2; + + chan_pcal_info->pddac[2][3] = + (val >> 2) & 0x3f; + } + + for (c = 0; c < pd_gains; c++) { + /* Recreate pwr table for this channel using pwr steps */ + chan_pcal_info->pwr[c][0] += chan_pcal_info->pwr_i[c] * 2; + chan_pcal_info->pwr[c][1] += chan_pcal_info->pwr[c][0]; + chan_pcal_info->pwr[c][2] += chan_pcal_info->pwr[c][1]; + chan_pcal_info->pwr[c][3] += chan_pcal_info->pwr[c][2]; + if (chan_pcal_info->pwr[c][3] == chan_pcal_info->pwr[c][2]) + chan_pcal_info->pwr[c][3] = 0; + + /* Recreate pddac table for this channel using pddac steps */ + chan_pcal_info->pddac[c][0] += chan_pcal_info->pddac_i[c]; + chan_pcal_info->pddac[c][1] += chan_pcal_info->pddac[c][0]; + chan_pcal_info->pddac[c][2] += chan_pcal_info->pddac[c][1]; + chan_pcal_info->pddac[c][3] += chan_pcal_info->pddac[c][2]; + if (chan_pcal_info->pddac[c][3] == chan_pcal_info->pddac[c][2]) + chan_pcal_info->pddac[c][3] = 0; } } - /* - * Read 5GHz EEPROM channels - */ + return 0; +} + +/* + * Read per rate target power (this is the maximum tx power + * supported by the card). This info is used when setting + * tx power, no matter the channel. + * + * This also works for v5 EEPROMs. + */ +static int ath5k_eeprom_read_target_rate_pwr_info(struct ath5k_hw *ah, unsigned int mode) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_rate_pcal_info *rate_pcal_info; + u16 *rate_target_pwr_num; + u32 offset; + u16 val; + int ret, i; + + offset = AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1); + rate_target_pwr_num = &ee->ee_rate_target_pwr_num[mode]; + switch (mode) { + case AR5K_EEPROM_MODE_11A: + offset += AR5K_EEPROM_TARGET_PWR_OFF_11A(ee->ee_version); + rate_pcal_info = ee->ee_rate_tpwr_a; + ee->ee_rate_target_pwr_num[mode] = AR5K_EEPROM_N_5GHZ_CHAN; + break; + case AR5K_EEPROM_MODE_11B: + offset += AR5K_EEPROM_TARGET_PWR_OFF_11B(ee->ee_version); + rate_pcal_info = ee->ee_rate_tpwr_b; + ee->ee_rate_target_pwr_num[mode] = 2; /* 3rd is g mode's 1st */ + break; + case AR5K_EEPROM_MODE_11G: + offset += AR5K_EEPROM_TARGET_PWR_OFF_11G(ee->ee_version); + rate_pcal_info = ee->ee_rate_tpwr_g; + ee->ee_rate_target_pwr_num[mode] = AR5K_EEPROM_N_2GHZ_CHAN; + break; + default: + return -EINVAL; + } + + /* Different freq mask for older eeproms (<= v3.2) */ + if (ee->ee_version <= AR5K_EEPROM_VERSION_3_2) { + for (i = 0; i < (*rate_target_pwr_num); i++) { + AR5K_EEPROM_READ(offset++, val); + rate_pcal_info[i].freq = + ath5k_eeprom_bin2freq(ee, (val >> 9) & 0x7f, mode); + + rate_pcal_info[i].target_power_6to24 = ((val >> 3) & 0x3f); + rate_pcal_info[i].target_power_36 = (val << 3) & 0x3f; + + AR5K_EEPROM_READ(offset++, val); + + if (rate_pcal_info[i].freq == AR5K_EEPROM_CHANNEL_DIS || + val == 0) { + (*rate_target_pwr_num) = i; + break; + } + + rate_pcal_info[i].target_power_36 |= ((val >> 13) & 0x7); + rate_pcal_info[i].target_power_48 = ((val >> 7) & 0x3f); + rate_pcal_info[i].target_power_54 = ((val >> 1) & 0x3f); + } + } else { + for (i = 0; i < (*rate_target_pwr_num); i++) { + AR5K_EEPROM_READ(offset++, val); + rate_pcal_info[i].freq = + ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode); + + rate_pcal_info[i].target_power_6to24 = ((val >> 2) & 0x3f); + rate_pcal_info[i].target_power_36 = (val << 4) & 0x3f; + + AR5K_EEPROM_READ(offset++, val); + + if (rate_pcal_info[i].freq == AR5K_EEPROM_CHANNEL_DIS || + val == 0) { + (*rate_target_pwr_num) = i; + break; + } + + rate_pcal_info[i].target_power_36 |= (val >> 12) & 0xf; + rate_pcal_info[i].target_power_48 = ((val >> 6) & 0x3f); + rate_pcal_info[i].target_power_54 = (val & 0x3f); + } + } + + return 0; +} + +static int +ath5k_eeprom_read_pcal_info(struct ath5k_hw *ah) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + int (*read_pcal)(struct ath5k_hw *hw, int mode); + int mode; + int err; + + if ((ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) && + (AR5K_EEPROM_EEMAP(ee->ee_misc0) == 1)) + read_pcal = ath5k_eeprom_read_pcal_info_5112; + else if ((ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_0) && + (AR5K_EEPROM_EEMAP(ee->ee_misc0) == 2)) + read_pcal = ath5k_eeprom_read_pcal_info_2413; + else + read_pcal = ath5k_eeprom_read_pcal_info_5111; + + for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++) { + err = read_pcal(ah, mode); + if (err) + return err; + + err = ath5k_eeprom_read_target_rate_pwr_info(ah, mode); + if (err < 0) + return err; + } + + return 0; +} + +/* Read conformance test limits */ +static int +ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_edge_power *rep; + unsigned int fmask, pmask; + unsigned int ctl_mode; + int ret, i, j; + u32 offset; + u16 val; + + pmask = AR5K_EEPROM_POWER_M; + fmask = AR5K_EEPROM_FREQ_M(ee->ee_version); + offset = AR5K_EEPROM_CTL(ee->ee_version); + ee->ee_ctls = AR5K_EEPROM_N_CTLS(ee->ee_version); + for (i = 0; i < ee->ee_ctls; i += 2) { + AR5K_EEPROM_READ(offset++, val); + ee->ee_ctl[i] = (val >> 8) & 0xff; + ee->ee_ctl[i + 1] = val & 0xff; + } + + offset = AR5K_EEPROM_GROUP8_OFFSET; + if (ee->ee_version >= AR5K_EEPROM_VERSION_4_0) + offset += AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1) - + AR5K_EEPROM_GROUP5_OFFSET; + else + offset += AR5K_EEPROM_GROUPS_START(ee->ee_version); + + rep = ee->ee_ctl_pwr; + for(i = 0; i < ee->ee_ctls; i++) { + switch(ee->ee_ctl[i] & AR5K_CTL_MODE_M) { + case AR5K_CTL_11A: + case AR5K_CTL_TURBO: + ctl_mode = AR5K_EEPROM_MODE_11A; + break; + default: + ctl_mode = AR5K_EEPROM_MODE_11G; + break; + } + if (ee->ee_ctl[i] == 0) { + if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) + offset += 8; + else + offset += 7; + rep += AR5K_EEPROM_N_EDGES; + continue; + } + if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) { + for (j = 0; j < AR5K_EEPROM_N_EDGES; j += 2) { + AR5K_EEPROM_READ(offset++, val); + rep[j].freq = (val >> 8) & fmask; + rep[j + 1].freq = val & fmask; + } + for (j = 0; j < AR5K_EEPROM_N_EDGES; j += 2) { + AR5K_EEPROM_READ(offset++, val); + rep[j].edge = (val >> 8) & pmask; + rep[j].flag = (val >> 14) & 1; + rep[j + 1].edge = val & pmask; + rep[j + 1].flag = (val >> 6) & 1; + } + } else { + AR5K_EEPROM_READ(offset++, val); + rep[0].freq = (val >> 9) & fmask; + rep[1].freq = (val >> 2) & fmask; + rep[2].freq = (val << 5) & fmask; + + AR5K_EEPROM_READ(offset++, val); + rep[2].freq |= (val >> 11) & 0x1f; + rep[3].freq = (val >> 4) & fmask; + rep[4].freq = (val << 3) & fmask; + + AR5K_EEPROM_READ(offset++, val); + rep[4].freq |= (val >> 13) & 0x7; + rep[5].freq = (val >> 6) & fmask; + rep[6].freq = (val << 1) & fmask; + + AR5K_EEPROM_READ(offset++, val); + rep[6].freq |= (val >> 15) & 0x1; + rep[7].freq = (val >> 8) & fmask; + + rep[0].edge = (val >> 2) & pmask; + rep[1].edge = (val << 4) & pmask; + + AR5K_EEPROM_READ(offset++, val); + rep[1].edge |= (val >> 12) & 0xf; + rep[2].edge = (val >> 6) & pmask; + rep[3].edge = val & pmask; + + AR5K_EEPROM_READ(offset++, val); + rep[4].edge = (val >> 10) & pmask; + rep[5].edge = (val >> 4) & pmask; + rep[6].edge = (val << 2) & pmask; + + AR5K_EEPROM_READ(offset++, val); + rep[6].edge |= (val >> 14) & 0x3; + rep[7].edge = (val >> 8) & pmask; + } + for (j = 0; j < AR5K_EEPROM_N_EDGES; j++) { + rep[j].freq = ath5k_eeprom_bin2freq(ee, + rep[j].freq, ctl_mode); + } + rep += AR5K_EEPROM_N_EDGES; + } return 0; } + +/* + * Initialize eeprom power tables + */ +int +ath5k_eeprom_init(struct ath5k_hw *ah) +{ + int err; + + err = ath5k_eeprom_init_header(ah); + if (err < 0) + return err; + + err = ath5k_eeprom_init_modes(ah); + if (err < 0) + return err; + + err = ath5k_eeprom_read_pcal_info(ah); + if (err < 0) + return err; + + err = ath5k_eeprom_read_ctl_info(ah); + if (err < 0) + return err; + + return 0; +} /* * Read the MAC address from eeprom */ diff --git a/drivers/net/wireless/ath5k/eeprom.h b/drivers/net/wireless/ath5k/eeprom.h index a468ecfbb18aa38c433937f8312766d23ca2096c..09eb7d0176a4e93dad5b9691bb03e7fa2025a757 100644 --- a/drivers/net/wireless/ath5k/eeprom.h +++ b/drivers/net/wireless/ath5k/eeprom.h @@ -25,24 +25,8 @@ #define AR5K_EEPROM_MAGIC_5211 0x0000145b /* 5211 */ #define AR5K_EEPROM_MAGIC_5210 0x0000145a /* 5210 */ -#define AR5K_EEPROM_PROTECT 0x003f /* EEPROM protect status */ -#define AR5K_EEPROM_PROTECT_RD_0_31 0x0001 /* Read protection bit for offsets 0x0 - 0x1f */ -#define AR5K_EEPROM_PROTECT_WR_0_31 0x0002 /* Write protection bit for offsets 0x0 - 0x1f */ -#define AR5K_EEPROM_PROTECT_RD_32_63 0x0004 /* 0x20 - 0x3f */ -#define AR5K_EEPROM_PROTECT_WR_32_63 0x0008 -#define AR5K_EEPROM_PROTECT_RD_64_127 0x0010 /* 0x40 - 0x7f */ -#define AR5K_EEPROM_PROTECT_WR_64_127 0x0020 -#define AR5K_EEPROM_PROTECT_RD_128_191 0x0040 /* 0x80 - 0xbf (regdom) */ -#define AR5K_EEPROM_PROTECT_WR_128_191 0x0080 -#define AR5K_EEPROM_PROTECT_RD_192_207 0x0100 /* 0xc0 - 0xcf */ -#define AR5K_EEPROM_PROTECT_WR_192_207 0x0200 -#define AR5K_EEPROM_PROTECT_RD_208_223 0x0400 /* 0xd0 - 0xdf */ -#define AR5K_EEPROM_PROTECT_WR_208_223 0x0800 -#define AR5K_EEPROM_PROTECT_RD_224_239 0x1000 /* 0xe0 - 0xef */ -#define AR5K_EEPROM_PROTECT_WR_224_239 0x2000 -#define AR5K_EEPROM_PROTECT_RD_240_255 0x4000 /* 0xf0 - 0xff */ -#define AR5K_EEPROM_PROTECT_WR_240_255 0x8000 #define AR5K_EEPROM_REG_DOMAIN 0x00bf /* EEPROM regdom */ +#define AR5K_EEPROM_CHECKSUM 0x00c0 /* EEPROM checksum */ #define AR5K_EEPROM_INFO_BASE 0x00c0 /* EEPROM header */ #define AR5K_EEPROM_INFO_MAX (0x400 - AR5K_EEPROM_INFO_BASE) #define AR5K_EEPROM_INFO_CKSUM 0xffff @@ -53,15 +37,19 @@ #define AR5K_EEPROM_VERSION_3_1 0x3001 /* ob/db values for 2Ghz (ar5211_rfregs) */ #define AR5K_EEPROM_VERSION_3_2 0x3002 /* different frequency representation (eeprom_bin2freq) */ #define AR5K_EEPROM_VERSION_3_3 0x3003 /* offsets changed, has 32 CTLs (see below) and ee_false_detect (eeprom_read_modes) */ -#define AR5K_EEPROM_VERSION_3_4 0x3004 /* has ee_i_gain ee_cck_ofdm_power_delta (eeprom_read_modes) */ -#define AR5K_EEPROM_VERSION_4_0 0x4000 /* has ee_misc*, ee_cal_pier, ee_turbo_max_power and ee_xr_power (eeprom_init) */ +#define AR5K_EEPROM_VERSION_3_4 0x3004 /* has ee_i_gain, ee_cck_ofdm_power_delta (eeprom_read_modes) */ +#define AR5K_EEPROM_VERSION_4_0 0x4000 /* has ee_misc, ee_cal_pier, ee_turbo_max_power and ee_xr_power (eeprom_init) */ #define AR5K_EEPROM_VERSION_4_1 0x4001 /* has ee_margin_tx_rx (eeprom_init) */ #define AR5K_EEPROM_VERSION_4_2 0x4002 /* has ee_cck_ofdm_gain_delta (eeprom_init) */ -#define AR5K_EEPROM_VERSION_4_3 0x4003 +#define AR5K_EEPROM_VERSION_4_3 0x4003 /* power calibration changes */ #define AR5K_EEPROM_VERSION_4_4 0x4004 #define AR5K_EEPROM_VERSION_4_5 0x4005 #define AR5K_EEPROM_VERSION_4_6 0x4006 /* has ee_scaled_cck_delta */ -#define AR5K_EEPROM_VERSION_4_7 0x4007 +#define AR5K_EEPROM_VERSION_4_7 0x3007 /* 4007 ? */ +#define AR5K_EEPROM_VERSION_4_9 0x4009 /* EAR futureproofing */ +#define AR5K_EEPROM_VERSION_5_0 0x5000 /* Has 2413 PDADC calibration etc */ +#define AR5K_EEPROM_VERSION_5_1 0x5001 /* Has capability values */ +#define AR5K_EEPROM_VERSION_5_3 0x5003 /* Has spur mitigation tables */ #define AR5K_EEPROM_MODE_11A 0 #define AR5K_EEPROM_MODE_11B 1 @@ -74,8 +62,8 @@ #define AR5K_EEPROM_HDR_T_2GHZ_DIS(_v) (((_v) >> 3) & 0x1) /* Disable turbo for 2Ghz (?) */ #define AR5K_EEPROM_HDR_T_5GHZ_DBM(_v) (((_v) >> 4) & 0x7f) /* Max turbo power for a/XR mode (eeprom_init) */ #define AR5K_EEPROM_HDR_DEVICE(_v) (((_v) >> 11) & 0x7) -#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v) (((_v) >> 15) & 0x1) /* Disable turbo for 5Ghz (?) */ #define AR5K_EEPROM_HDR_RFKILL(_v) (((_v) >> 14) & 0x1) /* Device has RFKill support */ +#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v) (((_v) >> 15) & 0x1) /* Disable turbo for 5Ghz */ #define AR5K_EEPROM_RFKILL_GPIO_SEL 0x0000001c #define AR5K_EEPROM_RFKILL_GPIO_SEL_S 2 @@ -87,27 +75,95 @@ (((_v) >= AR5K_EEPROM_VERSION_3_3) ? _v3_3 : _v3_0) #define AR5K_EEPROM_ANT_GAIN(_v) AR5K_EEPROM_OFF(_v, 0x00c4, 0x00c3) -#define AR5K_EEPROM_ANT_GAIN_5GHZ(_v) ((int8_t)(((_v) >> 8) & 0xff)) -#define AR5K_EEPROM_ANT_GAIN_2GHZ(_v) ((int8_t)((_v) & 0xff)) +#define AR5K_EEPROM_ANT_GAIN_5GHZ(_v) ((s8)(((_v) >> 8) & 0xff)) +#define AR5K_EEPROM_ANT_GAIN_2GHZ(_v) ((s8)((_v) & 0xff)) + +/* Misc values available since EEPROM 4.0 */ +#define AR5K_EEPROM_MISC0 AR5K_EEPROM_INFO(4) +#define AR5K_EEPROM_EARSTART(_v) ((_v) & 0xfff) +#define AR5K_EEPROM_HDR_XR2_DIS(_v) (((_v) >> 12) & 0x1) +#define AR5K_EEPROM_HDR_XR5_DIS(_v) (((_v) >> 13) & 0x1) +#define AR5K_EEPROM_EEMAP(_v) (((_v) >> 14) & 0x3) + +#define AR5K_EEPROM_MISC1 AR5K_EEPROM_INFO(5) +#define AR5K_EEPROM_TARGET_PWRSTART(_v) ((_v) & 0xfff) +#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v) (((_v) >> 14) & 0x1) +#define AR5K_EEPROM_HAS32KHZCRYSTAL_OLD(_v) (((_v) >> 15) & 0x1) + +#define AR5K_EEPROM_MISC2 AR5K_EEPROM_INFO(6) +#define AR5K_EEPROM_EEP_FILE_VERSION(_v) (((_v) >> 8) & 0xff) +#define AR5K_EEPROM_EAR_FILE_VERSION(_v) ((_v) & 0xff) + +#define AR5K_EEPROM_MISC3 AR5K_EEPROM_INFO(7) +#define AR5K_EEPROM_ART_BUILD_NUM(_v) (((_v) >> 10) & 0x3f) +#define AR5K_EEPROM_EAR_FILE_ID(_v) ((_v) & 0xff) + +#define AR5K_EEPROM_MISC4 AR5K_EEPROM_INFO(8) +#define AR5K_EEPROM_CAL_DATA_START(_v) (((_v) >> 4) & 0xfff) +#define AR5K_EEPROM_MASK_R0(_v) (((_v) >> 2) & 0x3) +#define AR5K_EEPROM_MASK_R1(_v) ((_v) & 0x3) + +#define AR5K_EEPROM_MISC5 AR5K_EEPROM_INFO(9) +#define AR5K_EEPROM_COMP_DIS(_v) ((_v) & 0x1) +#define AR5K_EEPROM_AES_DIS(_v) (((_v) >> 1) & 0x1) +#define AR5K_EEPROM_FF_DIS(_v) (((_v) >> 2) & 0x1) +#define AR5K_EEPROM_BURST_DIS(_v) (((_v) >> 3) & 0x1) +#define AR5K_EEPROM_MAX_QCU(_v) (((_v) >> 4) & 0xf) +#define AR5K_EEPROM_HEAVY_CLIP_EN(_v) (((_v) >> 8) & 0x1) +#define AR5K_EEPROM_KEY_CACHE_SIZE(_v) (((_v) >> 12) & 0xf) + +#define AR5K_EEPROM_MISC6 AR5K_EEPROM_INFO(10) +#define AR5K_EEPROM_TX_CHAIN_DIS ((_v) & 0x8) +#define AR5K_EEPROM_RX_CHAIN_DIS (((_v) >> 3) & 0x8) +#define AR5K_EEPROM_FCC_MID_EN (((_v) >> 6) & 0x1) +#define AR5K_EEPROM_JAP_U1EVEN_EN (((_v) >> 7) & 0x1) +#define AR5K_EEPROM_JAP_U2_EN (((_v) >> 8) & 0x1) +#define AR5K_EEPROM_JAP_U1ODD_EN (((_v) >> 9) & 0x1) +#define AR5K_EEPROM_JAP_11A_NEW_EN (((_v) >> 10) & 0x1) /* calibration settings */ #define AR5K_EEPROM_MODES_11A(_v) AR5K_EEPROM_OFF(_v, 0x00c5, 0x00d4) #define AR5K_EEPROM_MODES_11B(_v) AR5K_EEPROM_OFF(_v, 0x00d0, 0x00f2) #define AR5K_EEPROM_MODES_11G(_v) AR5K_EEPROM_OFF(_v, 0x00da, 0x010d) #define AR5K_EEPROM_CTL(_v) AR5K_EEPROM_OFF(_v, 0x00e4, 0x0128) /* Conformance test limits */ +#define AR5K_EEPROM_GROUPS_START(_v) AR5K_EEPROM_OFF(_v, 0x0100, 0x0150) /* Start of Groups */ +#define AR5K_EEPROM_GROUP1_OFFSET 0x0 +#define AR5K_EEPROM_GROUP2_OFFSET 0x5 +#define AR5K_EEPROM_GROUP3_OFFSET 0x37 +#define AR5K_EEPROM_GROUP4_OFFSET 0x46 +#define AR5K_EEPROM_GROUP5_OFFSET 0x55 +#define AR5K_EEPROM_GROUP6_OFFSET 0x65 +#define AR5K_EEPROM_GROUP7_OFFSET 0x69 +#define AR5K_EEPROM_GROUP8_OFFSET 0x6f + +#define AR5K_EEPROM_TARGET_PWR_OFF_11A(_v) AR5K_EEPROM_OFF(_v, AR5K_EEPROM_GROUPS_START(_v) + \ + AR5K_EEPROM_GROUP5_OFFSET, 0x0000) +#define AR5K_EEPROM_TARGET_PWR_OFF_11B(_v) AR5K_EEPROM_OFF(_v, AR5K_EEPROM_GROUPS_START(_v) + \ + AR5K_EEPROM_GROUP6_OFFSET, 0x0010) +#define AR5K_EEPROM_TARGET_PWR_OFF_11G(_v) AR5K_EEPROM_OFF(_v, AR5K_EEPROM_GROUPS_START(_v) + \ + AR5K_EEPROM_GROUP7_OFFSET, 0x0014) /* [3.1 - 3.3] */ #define AR5K_EEPROM_OBDB0_2GHZ 0x00ec #define AR5K_EEPROM_OBDB1_2GHZ 0x00ed -/* Misc values available since EEPROM 4.0 */ -#define AR5K_EEPROM_MISC0 0x00c4 -#define AR5K_EEPROM_EARSTART(_v) ((_v) & 0xfff) -#define AR5K_EEPROM_EEMAP(_v) (((_v) >> 14) & 0x3) -#define AR5K_EEPROM_MISC1 0x00c5 -#define AR5K_EEPROM_TARGET_PWRSTART(_v) ((_v) & 0xfff) -#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v) (((_v) >> 14) & 0x1) - +#define AR5K_EEPROM_PROTECT 0x003f /* EEPROM protect status */ +#define AR5K_EEPROM_PROTECT_RD_0_31 0x0001 /* Read protection bit for offsets 0x0 - 0x1f */ +#define AR5K_EEPROM_PROTECT_WR_0_31 0x0002 /* Write protection bit for offsets 0x0 - 0x1f */ +#define AR5K_EEPROM_PROTECT_RD_32_63 0x0004 /* 0x20 - 0x3f */ +#define AR5K_EEPROM_PROTECT_WR_32_63 0x0008 +#define AR5K_EEPROM_PROTECT_RD_64_127 0x0010 /* 0x40 - 0x7f */ +#define AR5K_EEPROM_PROTECT_WR_64_127 0x0020 +#define AR5K_EEPROM_PROTECT_RD_128_191 0x0040 /* 0x80 - 0xbf (regdom) */ +#define AR5K_EEPROM_PROTECT_WR_128_191 0x0080 +#define AR5K_EEPROM_PROTECT_RD_192_207 0x0100 /* 0xc0 - 0xcf */ +#define AR5K_EEPROM_PROTECT_WR_192_207 0x0200 +#define AR5K_EEPROM_PROTECT_RD_208_223 0x0400 /* 0xd0 - 0xdf */ +#define AR5K_EEPROM_PROTECT_WR_208_223 0x0800 +#define AR5K_EEPROM_PROTECT_RD_224_239 0x1000 /* 0xe0 - 0xef */ +#define AR5K_EEPROM_PROTECT_WR_224_239 0x2000 +#define AR5K_EEPROM_PROTECT_RD_240_255 0x4000 /* 0xf0 - 0xff */ +#define AR5K_EEPROM_PROTECT_WR_240_255 0x8000 /* Some EEPROM defines */ #define AR5K_EEPROM_EEP_SCALE 100 @@ -115,8 +171,11 @@ #define AR5K_EEPROM_N_MODES 3 #define AR5K_EEPROM_N_5GHZ_CHAN 10 #define AR5K_EEPROM_N_2GHZ_CHAN 3 +#define AR5K_EEPROM_N_2GHZ_CHAN_2413 4 #define AR5K_EEPROM_MAX_CHAN 10 +#define AR5K_EEPROM_N_PWR_POINTS_5111 11 #define AR5K_EEPROM_N_PCDAC 11 +#define AR5K_EEPROM_N_PHASE_CAL 5 #define AR5K_EEPROM_N_TEST_FREQ 8 #define AR5K_EEPROM_N_EDGES 8 #define AR5K_EEPROM_N_INTERCEPTS 11 @@ -136,6 +195,8 @@ #define AR5K_EEPROM_N_XPD_PER_CHANNEL 4 #define AR5K_EEPROM_N_XPD0_POINTS 4 #define AR5K_EEPROM_N_XPD3_POINTS 3 +#define AR5K_EEPROM_N_PD_GAINS 4 +#define AR5K_EEPROM_N_PD_POINTS 5 #define AR5K_EEPROM_N_INTERCEPT_10_2GHZ 35 #define AR5K_EEPROM_N_INTERCEPT_10_5GHZ 55 #define AR5K_EEPROM_POWER_M 0x3f @@ -158,8 +219,99 @@ #define AR5K_EEPROM_READ_HDR(_o, _v) \ AR5K_EEPROM_READ(_o, ah->ah_capabilities.cap_eeprom._v); \ -/* Struct to hold EEPROM calibration data */ +enum ath5k_ant_setting { + AR5K_ANT_VARIABLE = 0, /* variable by programming */ + AR5K_ANT_FIXED_A = 1, /* fixed to 11a frequencies */ + AR5K_ANT_FIXED_B = 2, /* fixed to 11b frequencies */ + AR5K_ANT_MAX = 3, +}; + +enum ath5k_ctl_mode { + AR5K_CTL_11A = 0, + AR5K_CTL_11B = 1, + AR5K_CTL_11G = 2, + AR5K_CTL_TURBO = 3, + AR5K_CTL_108G = 4, + AR5K_CTL_2GHT20 = 5, + AR5K_CTL_5GHT20 = 6, + AR5K_CTL_2GHT40 = 7, + AR5K_CTL_5GHT40 = 8, + AR5K_CTL_MODE_M = 15, +}; + +/* Per channel calibration data, used for power table setup */ +struct ath5k_chan_pcal_info_rf5111 { + /* Power levels in half dbm units + * for one power curve. */ + u8 pwr[AR5K_EEPROM_N_PWR_POINTS_5111]; + /* PCDAC table steps + * for the above values */ + u8 pcdac[AR5K_EEPROM_N_PWR_POINTS_5111]; + /* Starting PCDAC step */ + u8 pcdac_min; + /* Final PCDAC step */ + u8 pcdac_max; +}; + +struct ath5k_chan_pcal_info_rf5112 { + /* Power levels in quarter dBm units + * for lower (0) and higher (3) + * level curves */ + s8 pwr_x0[AR5K_EEPROM_N_XPD0_POINTS]; + s8 pwr_x3[AR5K_EEPROM_N_XPD3_POINTS]; + /* PCDAC table steps + * for the above values */ + u8 pcdac_x0[AR5K_EEPROM_N_XPD0_POINTS]; + u8 pcdac_x3[AR5K_EEPROM_N_XPD3_POINTS]; +}; + +struct ath5k_chan_pcal_info_rf2413 { + /* Starting pwr/pddac values */ + s8 pwr_i[AR5K_EEPROM_N_PD_GAINS]; + u8 pddac_i[AR5K_EEPROM_N_PD_GAINS]; + /* (pwr,pddac) points */ + s8 pwr[AR5K_EEPROM_N_PD_GAINS] + [AR5K_EEPROM_N_PD_POINTS]; + u8 pddac[AR5K_EEPROM_N_PD_GAINS] + [AR5K_EEPROM_N_PD_POINTS]; +}; + +struct ath5k_chan_pcal_info { + /* Frequency */ + u16 freq; + /* Max available power */ + s8 max_pwr; + union { + struct ath5k_chan_pcal_info_rf5111 rf5111_info; + struct ath5k_chan_pcal_info_rf5112 rf5112_info; + struct ath5k_chan_pcal_info_rf2413 rf2413_info; + }; +}; + +/* Per rate calibration data for each mode, used for power table setup */ +struct ath5k_rate_pcal_info { + u16 freq; /* Frequency */ + /* Power level for 6-24Mbit/s rates */ + u16 target_power_6to24; + /* Power level for 36Mbit rate */ + u16 target_power_36; + /* Power level for 48Mbit rate */ + u16 target_power_48; + /* Power level for 54Mbit rate */ + u16 target_power_54; +}; + +/* Power edges for conformance test limits */ +struct ath5k_edge_power { + u16 freq; + u16 edge; /* in half dBm */ + bool flag; +}; + +/* EEPROM calibration data */ struct ath5k_eeprom_info { + + /* Header information */ u16 ee_magic; u16 ee_protect; u16 ee_regdomain; @@ -168,6 +320,11 @@ struct ath5k_eeprom_info { u16 ee_ant_gain; u16 ee_misc0; u16 ee_misc1; + u16 ee_misc2; + u16 ee_misc3; + u16 ee_misc4; + u16 ee_misc5; + u16 ee_misc6; u16 ee_cck_ofdm_gain_delta; u16 ee_cck_ofdm_power_delta; u16 ee_scaled_cck_delta; @@ -185,7 +342,7 @@ struct ath5k_eeprom_info { u16 ee_turbo_max_power[AR5K_EEPROM_N_MODES]; u16 ee_xr_power[AR5K_EEPROM_N_MODES]; u16 ee_switch_settling[AR5K_EEPROM_N_MODES]; - u16 ee_ant_tx_rx[AR5K_EEPROM_N_MODES]; + u16 ee_atn_tx_rx[AR5K_EEPROM_N_MODES]; u16 ee_ant_control[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_PCDAC]; u16 ee_ob[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB]; u16 ee_db[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB]; @@ -198,18 +355,40 @@ struct ath5k_eeprom_info { u16 ee_x_gain[AR5K_EEPROM_N_MODES]; u16 ee_i_gain[AR5K_EEPROM_N_MODES]; u16 ee_margin_tx_rx[AR5K_EEPROM_N_MODES]; + u16 ee_switch_settling_turbo[AR5K_EEPROM_N_MODES]; + u16 ee_margin_tx_rx_turbo[AR5K_EEPROM_N_MODES]; + u16 ee_atn_tx_rx_turbo[AR5K_EEPROM_N_MODES]; - /* Unused */ + /* Power calibration data */ u16 ee_false_detect[AR5K_EEPROM_N_MODES]; - u16 ee_cal_pier[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_2GHZ_CHAN]; - u16 ee_channel[AR5K_EEPROM_N_MODES][AR5K_EEPROM_MAX_CHAN]; /*empty*/ + + /* Number of pd gain curves per mode (RF2413) */ + u8 ee_pd_gains[AR5K_EEPROM_N_MODES]; + + u8 ee_n_piers[AR5K_EEPROM_N_MODES]; + struct ath5k_chan_pcal_info ee_pwr_cal_a[AR5K_EEPROM_N_5GHZ_CHAN]; + struct ath5k_chan_pcal_info ee_pwr_cal_b[AR5K_EEPROM_N_2GHZ_CHAN]; + struct ath5k_chan_pcal_info ee_pwr_cal_g[AR5K_EEPROM_N_2GHZ_CHAN]; + + /* Per rate target power levels */ + u16 ee_rate_target_pwr_num[AR5K_EEPROM_N_MODES]; + struct ath5k_rate_pcal_info ee_rate_tpwr_a[AR5K_EEPROM_N_5GHZ_CHAN]; + struct ath5k_rate_pcal_info ee_rate_tpwr_b[AR5K_EEPROM_N_2GHZ_CHAN]; + struct ath5k_rate_pcal_info ee_rate_tpwr_g[AR5K_EEPROM_N_2GHZ_CHAN]; /* Conformance test limits (Unused) */ u16 ee_ctls; u16 ee_ctl[AR5K_EEPROM_MAX_CTLS]; + struct ath5k_edge_power ee_ctl_pwr[AR5K_EEPROM_N_EDGES * AR5K_EEPROM_MAX_CTLS]; /* Noise Floor Calibration settings */ s16 ee_noise_floor_thr[AR5K_EEPROM_N_MODES]; s8 ee_adc_desired_size[AR5K_EEPROM_N_MODES]; s8 ee_pga_desired_size[AR5K_EEPROM_N_MODES]; + s8 ee_adc_desired_size_turbo[AR5K_EEPROM_N_MODES]; + s8 ee_pga_desired_size_turbo[AR5K_EEPROM_N_MODES]; + s8 ee_pd_gain_overlap; + + u32 ee_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX]; }; + diff --git a/drivers/net/wireless/ath5k/initvals.c b/drivers/net/wireless/ath5k/initvals.c index ceaa6c475c0615bb786cf52bb7c0f1838ee557c9..450bd6e945ff152d76d411b7380b38fb84f4baa7 100644 --- a/drivers/net/wireless/ath5k/initvals.c +++ b/drivers/net/wireless/ath5k/initvals.c @@ -1681,7 +1681,7 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel) */ /* For AR5212 and combatible */ - if (ah->ah_version == AR5K_AR5212){ + if (ah->ah_version == AR5K_AR5212) { /* First set of mode-specific settings */ ath5k_hw_ini_mode_registers(ah, @@ -1695,7 +1695,7 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel) ar5212_ini, change_channel); /* Second set of mode-specific settings */ - if (ah->ah_radio == AR5K_RF5111){ + if (ah->ah_radio == AR5K_RF5111) { ath5k_hw_ini_mode_registers(ah, ARRAY_SIZE(ar5212_rf5111_ini_mode_end), @@ -1706,7 +1706,7 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel) ARRAY_SIZE(rf5111_ini_bbgain), rf5111_ini_bbgain, change_channel); - } else if (ah->ah_radio == AR5K_RF5112){ + } else if (ah->ah_radio == AR5K_RF5112) { ath5k_hw_ini_mode_registers(ah, ARRAY_SIZE(ar5212_rf5112_ini_mode_end), @@ -1716,7 +1716,7 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel) ARRAY_SIZE(rf5112_ini_bbgain), rf5112_ini_bbgain, change_channel); - } else if (ah->ah_radio == AR5K_RF5413){ + } else if (ah->ah_radio == AR5K_RF5413) { ath5k_hw_ini_mode_registers(ah, ARRAY_SIZE(rf5413_ini_mode_end), diff --git a/drivers/net/wireless/ath5k/pcu.c b/drivers/net/wireless/ath5k/pcu.c index a47df9a24aa126783497eeb296edad22aa150d0e..0cac05c6a9ce8dda1b1c50a5da26db3c187b9ecb 100644 --- a/drivers/net/wireless/ath5k/pcu.c +++ b/drivers/net/wireless/ath5k/pcu.c @@ -46,34 +46,45 @@ int ath5k_hw_set_opmode(struct ath5k_hw *ah) { u32 pcu_reg, beacon_reg, low_id, high_id; - pcu_reg = 0; + + /* Preserve rest settings */ + pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000; + pcu_reg &= ~(AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_AP + | AR5K_STA_ID1_KEYSRCH_MODE + | (ah->ah_version == AR5K_AR5210 ? + (AR5K_STA_ID1_PWR_SV | AR5K_STA_ID1_NO_PSPOLL) : 0)); + beacon_reg = 0; ATH5K_TRACE(ah->ah_sc); switch (ah->ah_op_mode) { case NL80211_IFTYPE_ADHOC: - pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_DESC_ANTENNA | - (ah->ah_version == AR5K_AR5210 ? - AR5K_STA_ID1_NO_PSPOLL : 0); + pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_KEYSRCH_MODE; beacon_reg |= AR5K_BCR_ADHOC; + if (ah->ah_version == AR5K_AR5210) + pcu_reg |= AR5K_STA_ID1_NO_PSPOLL; + else + AR5K_REG_DISABLE_BITS(ah, AR5K_CFG, AR5K_CFG_ADHOC); break; case NL80211_IFTYPE_AP: case NL80211_IFTYPE_MESH_POINT: - pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_RTS_DEF_ANTENNA | - (ah->ah_version == AR5K_AR5210 ? - AR5K_STA_ID1_NO_PSPOLL : 0); + pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_KEYSRCH_MODE; beacon_reg |= AR5K_BCR_AP; + if (ah->ah_version == AR5K_AR5210) + pcu_reg |= AR5K_STA_ID1_NO_PSPOLL; + else + AR5K_REG_ENABLE_BITS(ah, AR5K_CFG, AR5K_CFG_ADHOC); break; case NL80211_IFTYPE_STATION: - pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA | - (ah->ah_version == AR5K_AR5210 ? + pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE + | (ah->ah_version == AR5K_AR5210 ? AR5K_STA_ID1_PWR_SV : 0); case NL80211_IFTYPE_MONITOR: - pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA | - (ah->ah_version == AR5K_AR5210 ? + pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE + | (ah->ah_version == AR5K_AR5210 ? AR5K_STA_ID1_NO_PSPOLL : 0); break; @@ -130,6 +141,8 @@ void ath5k_hw_update_mib_counters(struct ath5k_hw *ah, ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR); ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE); } + + /* TODO: Handle ANI stats */ } /** @@ -258,16 +271,19 @@ void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac) int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac) { u32 low_id, high_id; + u32 pcu_reg; ATH5K_TRACE(ah->ah_sc); /* Set new station ID */ memcpy(ah->ah_sta_id, mac, ETH_ALEN); + pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000; + low_id = AR5K_LOW_ID(mac); high_id = AR5K_HIGH_ID(mac); ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0); - ath5k_hw_reg_write(ah, high_id, AR5K_STA_ID1); + ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1); return 0; } @@ -290,8 +306,10 @@ void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id) * Set simple BSSID mask on 5212 */ if (ah->ah_version == AR5K_AR5212) { - ath5k_hw_reg_write(ah, 0xffffffff, AR5K_BSS_IDM0); - ath5k_hw_reg_write(ah, 0xffffffff, AR5K_BSS_IDM1); + ath5k_hw_reg_write(ah, AR5K_LOW_ID(ah->ah_bssid_mask), + AR5K_BSS_IDM0); + ath5k_hw_reg_write(ah, AR5K_HIGH_ID(ah->ah_bssid_mask), + AR5K_BSS_IDM1); } /* @@ -415,6 +433,9 @@ int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask) u32 low_id, high_id; ATH5K_TRACE(ah->ah_sc); + /* Cache bssid mask so that we can restore it + * on reset */ + memcpy(ah->ah_bssid_mask, mask, ETH_ALEN); if (ah->ah_version == AR5K_AR5212) { low_id = AR5K_LOW_ID(mask); high_id = AR5K_HIGH_ID(mask); @@ -576,7 +597,7 @@ void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter) filter |= AR5K_RX_FILTER_PROM; } - /*Zero length DMA*/ + /*Zero length DMA (phy error reporting) */ if (data) AR5K_REG_ENABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA); else @@ -661,7 +682,12 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval) * Set the additional timers by mode */ switch (ah->ah_op_mode) { + case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_STATION: + /* In STA mode timer1 is used as next wakeup + * timer and timer2 as next CFP duration start + * timer. Both in 1/8TUs. */ + /* TODO: PCF handling */ if (ah->ah_version == AR5K_AR5210) { timer1 = 0xffffffff; timer2 = 0xffffffff; @@ -669,27 +695,60 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval) timer1 = 0x0000ffff; timer2 = 0x0007ffff; } + /* Mark associated AP as PCF incapable for now */ + AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_PCF); break; - + case NL80211_IFTYPE_ADHOC: + AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG, AR5K_TXCFG_ADHOC_BCN_ATIM); default: + /* On non-STA modes timer1 is used as next DMA + * beacon alert (DBA) timer and timer2 as next + * software beacon alert. Both in 1/8TUs. */ timer1 = (next_beacon - AR5K_TUNE_DMA_BEACON_RESP) << 3; timer2 = (next_beacon - AR5K_TUNE_SW_BEACON_RESP) << 3; + break; } + /* Timer3 marks the end of our ATIM window + * a zero length window is not allowed because + * we 'll get no beacons */ timer3 = next_beacon + (ah->ah_atim_window ? ah->ah_atim_window : 1); /* * Set the beacon register and enable all timers. - * (next beacon, DMA beacon, software beacon, ATIM window time) */ - ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0); + /* When in AP mode zero timer0 to start TSF */ + if (ah->ah_op_mode == NL80211_IFTYPE_AP) + ath5k_hw_reg_write(ah, 0, AR5K_TIMER0); + else + ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0); ath5k_hw_reg_write(ah, timer1, AR5K_TIMER1); ath5k_hw_reg_write(ah, timer2, AR5K_TIMER2); ath5k_hw_reg_write(ah, timer3, AR5K_TIMER3); + /* Force a TSF reset if requested and enable beacons */ + if (interval & AR5K_BEACON_RESET_TSF) + ath5k_hw_reset_tsf(ah); + ath5k_hw_reg_write(ah, interval & (AR5K_BEACON_PERIOD | - AR5K_BEACON_RESET_TSF | AR5K_BEACON_ENABLE), - AR5K_BEACON); + AR5K_BEACON_ENABLE), + AR5K_BEACON); + + /* Flush any pending BMISS interrupts on ISR by + * performing a clear-on-write operation on PISR + * register for the BMISS bit (writing a bit on + * ISR togles a reset for that bit and leaves + * the rest bits intact) */ + if (ah->ah_version == AR5K_AR5210) + ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_ISR); + else + ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_PISR); + + /* TODO: Set enchanced sleep registers on AR5212 + * based on vif->bss_conf params, until then + * disable power save reporting.*/ + AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_PWR_SV); + } #if 0 @@ -899,14 +958,26 @@ int ath5k_hw_beaconq_finish(struct ath5k_hw *ah, unsigned long phys_addr) */ int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry) { - unsigned int i; + unsigned int i, type; + u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET; ATH5K_TRACE(ah->ah_sc); AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); + type = ath5k_hw_reg_read(ah, AR5K_KEYTABLE_TYPE(entry)); + for (i = 0; i < AR5K_KEYCACHE_SIZE; i++) ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i)); + /* Reset associated MIC entry if TKIP + * is enabled located at offset (entry + 64) */ + if (type == AR5K_KEYTABLE_TYPE_TKIP) { + AR5K_ASSERT_ENTRY(micentry, AR5K_KEYTABLE_SIZE); + for (i = 0; i < AR5K_KEYCACHE_SIZE / 2 ; i++) + ath5k_hw_reg_write(ah, 0, + AR5K_KEYTABLE_OFF(micentry, i)); + } + /* * Set NULL encryption on AR5212+ * @@ -916,10 +987,16 @@ int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry) * Note2: Windows driver (ndiswrapper) sets this to * 0x00000714 instead of 0x00000007 */ - if (ah->ah_version > AR5K_AR5211) + if (ah->ah_version > AR5K_AR5211) { ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, AR5K_KEYTABLE_TYPE(entry)); + if (type == AR5K_KEYTABLE_TYPE_TKIP) { + ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, + AR5K_KEYTABLE_TYPE(micentry)); + } + } + return 0; } @@ -936,6 +1013,23 @@ int ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry) AR5K_KEYTABLE_VALID; } +static +int ath5k_keycache_type(const struct ieee80211_key_conf *key) +{ + switch (key->alg) { + case ALG_TKIP: + return AR5K_KEYTABLE_TYPE_TKIP; + case ALG_CCMP: + return AR5K_KEYTABLE_TYPE_CCM; + case ALG_WEP: + if (key->keylen == LEN_WEP40) + return AR5K_KEYTABLE_TYPE_40; + else if (key->keylen == LEN_WEP104) + return AR5K_KEYTABLE_TYPE_104; + } + return -EINVAL; +} + /* * Set a key entry on the table */ @@ -943,40 +1037,53 @@ int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry, const struct ieee80211_key_conf *key, const u8 *mac) { unsigned int i; + int keylen; __le32 key_v[5] = {}; + __le32 key0 = 0, key1 = 0; + __le32 *rxmic, *txmic; u32 keytype; + u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET; + bool is_tkip; + const u8 *key_ptr; ATH5K_TRACE(ah->ah_sc); - /* key->keylen comes in from mac80211 in bytes */ + is_tkip = (key->alg == ALG_TKIP); - if (key->keylen > AR5K_KEYTABLE_SIZE / 8) + /* + * key->keylen comes in from mac80211 in bytes. + * TKIP is 128 bit + 128 bit mic + */ + keylen = (is_tkip) ? (128 / 8) : key->keylen; + + if (entry > AR5K_KEYTABLE_SIZE || + (is_tkip && micentry > AR5K_KEYTABLE_SIZE)) return -EOPNOTSUPP; - switch (key->keylen) { - /* WEP 40-bit = 40-bit entered key + 24 bit IV = 64-bit */ - case 40 / 8: - memcpy(&key_v[0], key->key, 5); - keytype = AR5K_KEYTABLE_TYPE_40; - break; + if (unlikely(keylen > 16)) + return -EOPNOTSUPP; - /* WEP 104-bit = 104-bit entered key + 24-bit IV = 128-bit */ - case 104 / 8: - memcpy(&key_v[0], &key->key[0], 6); - memcpy(&key_v[2], &key->key[6], 6); - memcpy(&key_v[4], &key->key[12], 1); - keytype = AR5K_KEYTABLE_TYPE_104; - break; - /* WEP 128-bit = 128-bit entered key + 24 bit IV = 152-bit */ - case 128 / 8: - memcpy(&key_v[0], &key->key[0], 6); - memcpy(&key_v[2], &key->key[6], 6); - memcpy(&key_v[4], &key->key[12], 4); - keytype = AR5K_KEYTABLE_TYPE_128; - break; + keytype = ath5k_keycache_type(key); + if (keytype < 0) + return keytype; - default: - return -EINVAL; /* shouldn't happen */ + /* + * each key block is 6 bytes wide, written as pairs of + * alternating 32 and 16 bit le values. + */ + key_ptr = key->key; + for (i = 0; keylen >= 6; keylen -= 6) { + memcpy(&key_v[i], key_ptr, 6); + i += 2; + key_ptr += 6; + } + if (keylen) + memcpy(&key_v[i], key_ptr, keylen); + + /* intentionally corrupt key until mic is installed */ + if (is_tkip) { + key0 = key_v[0] = ~key_v[0]; + key1 = key_v[1] = ~key_v[1]; } for (i = 0; i < ARRAY_SIZE(key_v); i++) @@ -985,6 +1092,40 @@ int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry, ath5k_hw_reg_write(ah, keytype, AR5K_KEYTABLE_TYPE(entry)); + if (is_tkip) { + /* Install rx/tx MIC */ + rxmic = (__le32 *) &key->key[16]; + txmic = (__le32 *) &key->key[24]; + + if (ah->ah_combined_mic) { + key_v[0] = rxmic[0]; + key_v[1] = cpu_to_le32(le32_to_cpu(txmic[0]) >> 16); + key_v[2] = rxmic[1]; + key_v[3] = cpu_to_le32(le32_to_cpu(txmic[0]) & 0xffff); + key_v[4] = txmic[1]; + } else { + key_v[0] = rxmic[0]; + key_v[1] = 0; + key_v[2] = rxmic[1]; + key_v[3] = 0; + key_v[4] = 0; + } + for (i = 0; i < ARRAY_SIZE(key_v); i++) + ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]), + AR5K_KEYTABLE_OFF(micentry, i)); + + ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, + AR5K_KEYTABLE_TYPE(micentry)); + ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC0(micentry)); + ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC1(micentry)); + + /* restore first 2 words of key */ + ath5k_hw_reg_write(ah, le32_to_cpu(~key0), + AR5K_KEYTABLE_OFF(entry, 0)); + ath5k_hw_reg_write(ah, le32_to_cpu(~key1), + AR5K_KEYTABLE_OFF(entry, 1)); + } + return ath5k_hw_set_key_lladdr(ah, entry, mac); } diff --git a/drivers/net/wireless/ath5k/phy.c b/drivers/net/wireless/ath5k/phy.c index e43f6563e61a08ab6cbfcaaff1d455c6eb56e8f7..7ba18e09463b2ab981712bbfa87766e1a26a7caa 100644 --- a/drivers/net/wireless/ath5k/phy.c +++ b/drivers/net/wireless/ath5k/phy.c @@ -1412,7 +1412,8 @@ static int ath5k_hw_rf5112_rfregs(struct ath5k_hw *ah, rf_ini = rfregs_2112a; rf_size = ARRAY_SIZE(rfregs_5112a); if (mode < 2) { - ATH5K_ERR(ah->ah_sc,"invalid channel mode: %i\n",mode); + ATH5K_ERR(ah->ah_sc, "invalid channel mode: %i\n", + mode); return -EINVAL; } mode = mode - 2; /*no a/turboa modes for 2112*/ @@ -1708,7 +1709,7 @@ enum ath5k_rfgain ath5k_hw_get_rf_gain(struct ath5k_hw *ah) if (ah->ah_radio >= AR5K_RF5112) { ath5k_hw_rfregs_gainf_corr(ah); ah->ah_gain.g_current = - ah->ah_gain.g_current>=ah->ah_gain.g_f_corr ? + ah->ah_gain.g_current >= ah->ah_gain.g_f_corr ? (ah->ah_gain.g_current-ah->ah_gain.g_f_corr) : 0; } @@ -2195,9 +2196,7 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, return ret; } - ret = ath5k_hw_noise_floor_calibration(ah, channel->center_freq); - if (ret) - return ret; + ath5k_hw_noise_floor_calibration(ah, channel->center_freq); /* * Re-enable RX/TX and beacons diff --git a/drivers/net/wireless/ath5k/qcu.c b/drivers/net/wireless/ath5k/qcu.c index 01bf09176d23b79a993ed5daf4b33b30a22a9cc6..1b7bc50ea8eb212b68fdd51f96283de34998e693 100644 --- a/drivers/net/wireless/ath5k/qcu.c +++ b/drivers/net/wireless/ath5k/qcu.c @@ -432,13 +432,30 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) if (tq->tqi_flags & AR5K_TXQ_FLAG_TXEOLINT_ENABLE) AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txeol, queue); + if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRORNINT_ENABLE) + AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrorn, queue); + + if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRURNINT_ENABLE) + AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrurn, queue); + + if (tq->tqi_flags & AR5K_TXQ_FLAG_QTRIGINT_ENABLE) + AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_qtrig, queue); + + if (tq->tqi_flags & AR5K_TXQ_FLAG_TXNOFRMINT_ENABLE) + AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_nofrm, queue); /* Update secondary interrupt mask registers */ + + /* Filter out inactive queues */ ah->ah_txq_imr_txok &= ah->ah_txq_status; ah->ah_txq_imr_txerr &= ah->ah_txq_status; ah->ah_txq_imr_txurn &= ah->ah_txq_status; ah->ah_txq_imr_txdesc &= ah->ah_txq_status; ah->ah_txq_imr_txeol &= ah->ah_txq_status; + ah->ah_txq_imr_cbrorn &= ah->ah_txq_status; + ah->ah_txq_imr_cbrurn &= ah->ah_txq_status; + ah->ah_txq_imr_qtrig &= ah->ah_txq_status; + ah->ah_txq_imr_nofrm &= ah->ah_txq_status; ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txok, AR5K_SIMR0_QCU_TXOK) | @@ -448,8 +465,24 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) AR5K_SIMR1_QCU_TXERR) | AR5K_REG_SM(ah->ah_txq_imr_txeol, AR5K_SIMR1_QCU_TXEOL), AR5K_SIMR1); - ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txurn, - AR5K_SIMR2_QCU_TXURN), AR5K_SIMR2); + /* Update simr2 but don't overwrite rest simr2 settings */ + AR5K_REG_DISABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_QCU_TXURN); + AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2, + AR5K_REG_SM(ah->ah_txq_imr_txurn, + AR5K_SIMR2_QCU_TXURN)); + ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_cbrorn, + AR5K_SIMR3_QCBRORN) | + AR5K_REG_SM(ah->ah_txq_imr_cbrurn, + AR5K_SIMR3_QCBRURN), AR5K_SIMR3); + ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_qtrig, + AR5K_SIMR4_QTRIG), AR5K_SIMR4); + /* Set TXNOFRM_QCU for the queues with TXNOFRM enabled */ + ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_nofrm, + AR5K_TXNOFRM_QCU), AR5K_TXNOFRM); + /* No queue has TXNOFRM enabled, disable the interrupt + * by setting AR5K_TXNOFRM to zero */ + if (ah->ah_txq_imr_nofrm == 0) + ath5k_hw_reg_write(ah, 0, AR5K_TXNOFRM); } return 0; diff --git a/drivers/net/wireless/ath5k/reg.h b/drivers/net/wireless/ath5k/reg.h index e557fe178bbf9401af6c7846118d0a7f46a16c84..91aaeaf881995c583747feae712254a21e667872 100644 --- a/drivers/net/wireless/ath5k/reg.h +++ b/drivers/net/wireless/ath5k/reg.h @@ -234,6 +234,7 @@ #define AR5K_TXNOFRM 0x004c #define AR5K_TXNOFRM_M 0x000003ff #define AR5K_TXNOFRM_QCU 0x000ffc00 +#define AR5K_TXNOFRM_QCU_S 10 /* * Receive frame gap timeout register @@ -350,7 +351,7 @@ #define AR5K_SISR3 0x0090 /* Register Address [5211+] */ #define AR5K_SISR3_QCBRORN 0x000003ff /* Mask for QCBRORN */ -#define AR5K_SISR3_QCBORN_S 0 +#define AR5K_SISR3_QCBRORN_S 0 #define AR5K_SISR3_QCBRURN 0x03ff0000 /* Mask for QCBRURN */ #define AR5K_SISR3_QCBRURN_S 16 @@ -1113,14 +1114,16 @@ #define AR5K_PCU_MAX 0x8fff /* - * First station id register (MAC address in lower 32 bits) + * First station id register (Lower 32 bits of MAC address) */ -#define AR5K_STA_ID0 0x8000 +#define AR5K_STA_ID0 0x8000 +#define AR5K_STA_ID0_ARRD_L32 0xffffffff /* - * Second station id register (MAC address in upper 16 bits) + * Second station id register (Upper 16 bits of MAC address + PCU settings) */ #define AR5K_STA_ID1 0x8004 /* Register Address */ +#define AR5K_STA_ID1_ADDR_U16 0x0000ffff /* Upper 16 bits of MAC addres */ #define AR5K_STA_ID1_AP 0x00010000 /* Set AP mode */ #define AR5K_STA_ID1_ADHOC 0x00020000 /* Set Ad-Hoc mode */ #define AR5K_STA_ID1_PWR_SV 0x00040000 /* Power save reporting */ @@ -1726,6 +1729,7 @@ #define AR5K_MISC_MODE 0x8120 /* Register Address */ #define AR5K_MISC_MODE_FBSSID_MATCH 0x00000001 /* Force BSSID match */ #define AR5K_MISC_MODE_ACKSIFS_MEM 0x00000002 /* ACK SIFS memory (?) */ +#define AR5K_MISC_MODE_COMBINED_MIC 0x00000004 /* use rx/tx MIC key */ /* more bits */ /* @@ -1810,6 +1814,10 @@ #define AR5K_KEYTABLE_MAC1(_n) AR5K_KEYTABLE_OFF(_n, 7) #define AR5K_KEYTABLE_VALID 0x00008000 +/* If key type is TKIP and MIC is enabled + * MIC key goes in offset entry + 64 */ +#define AR5K_KEYTABLE_MIC_OFFSET 64 + /* WEP 40-bit = 40-bit entered key + 24 bit IV = 64-bit * WEP 104-bit = 104-bit entered key + 24-bit IV = 128-bit * WEP 128-bit = 128-bit entered key + 24 bit IV = 152-bit diff --git a/drivers/net/wireless/ath5k/reset.c b/drivers/net/wireless/ath5k/reset.c index 1b6d45b6772db39c269752e1b5bbef4e328d6389..dc2d7d8bdb7aceda7a27d52571b1047f65e86a3e 100644 --- a/drivers/net/wireless/ath5k/reset.c +++ b/drivers/net/wireless/ath5k/reset.c @@ -674,7 +674,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, (ee->ee_switch_settling[ee_mode] << 7) & 0x3f80, 0xffffc07f); AR5K_REG_MASKED_BITS(ah, AR5K_PHY_GAIN, - (ee->ee_ant_tx_rx[ee_mode] << 12) & 0x3f000, + (ee->ee_atn_tx_rx[ee_mode] << 12) & 0x3f000, 0xfffc0fff); AR5K_REG_MASKED_BITS(ah, AR5K_PHY_DESIRED_SIZE, (ee->ee_adc_desired_size[ee_mode] & 0x00ff) | @@ -842,9 +842,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, * * XXX: Find an interval that's OK for all cards... */ - ret = ath5k_hw_noise_floor_calibration(ah, channel->center_freq); - if (ret) - return ret; + ath5k_hw_noise_floor_calibration(ah, channel->center_freq); /* * Reset queues and start beacon timers at the end of the reset routine @@ -864,8 +862,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, /* Pre-enable interrupts on 5211/5212*/ if (ah->ah_version != AR5K_AR5210) - ath5k_hw_set_imr(ah, AR5K_INT_RX | AR5K_INT_TX | - AR5K_INT_FATAL); + ath5k_hw_set_imr(ah, ah->ah_imr); /* * Set RF kill flags if supported by the device (read from the EEPROM) diff --git a/drivers/net/wireless/ath9k/Kconfig b/drivers/net/wireless/ath9k/Kconfig index 80a69243041346c043de298c75664eb06e0c0afa..c43bd321f97fb6abfbbbce9bca13f37bfd1f5552 100644 --- a/drivers/net/wireless/ath9k/Kconfig +++ b/drivers/net/wireless/ath9k/Kconfig @@ -9,3 +9,14 @@ config ATH9K Atheros IEEE 802.11n AR5008 and AR9001 family of chipsets. If you choose to build a module, it'll be called ath9k. + +config ATH9K_DEBUG + bool "Atheros ath9k debugging" + depends on ATH9K + ---help--- + Say Y, if you need ath9k to display debug messages. + Pass the debug mask as a module parameter: + + modprobe ath9k debug=0x00002000 + + Look in ath9k/core.h for possible debug masks diff --git a/drivers/net/wireless/ath9k/Makefile b/drivers/net/wireless/ath9k/Makefile index a6411517e5f849f79c9e49180783ca11264ba4e5..1209d14613ac49cbdabf8e10fd17cf4257e2b440 100644 --- a/drivers/net/wireless/ath9k/Makefile +++ b/drivers/net/wireless/ath9k/Makefile @@ -1,11 +1,16 @@ ath9k-y += hw.o \ + eeprom.o \ + mac.o \ + calib.o \ + ani.o \ phy.o \ regd.o \ beacon.o \ main.o \ recv.o \ xmit.o \ - rc.o \ - core.o + rc.o + +ath9k-$(CONFIG_ATH9K_DEBUG) += debug.o obj-$(CONFIG_ATH9K) += ath9k.o diff --git a/drivers/net/wireless/ath9k/ani.c b/drivers/net/wireless/ath9k/ani.c new file mode 100644 index 0000000000000000000000000000000000000000..251e2d9a7a4a6d20e772325f6d7449a757f91984 --- /dev/null +++ b/drivers/net/wireless/ath9k/ani.c @@ -0,0 +1,852 @@ +/* + * Copyright (c) 2008 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "core.h" +#include "hw.h" +#include "reg.h" +#include "phy.h" + +static int ath9k_hw_get_ani_channel_idx(struct ath_hal *ah, + struct ath9k_channel *chan) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + int i; + + for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) { + if (ahp->ah_ani[i].c.channel == chan->channel) + return i; + if (ahp->ah_ani[i].c.channel == 0) { + ahp->ah_ani[i].c.channel = chan->channel; + ahp->ah_ani[i].c.channelFlags = chan->channelFlags; + return i; + } + } + + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "No more channel states left. Using channel 0\n"); + + return 0; +} + +static bool ath9k_hw_ani_control(struct ath_hal *ah, + enum ath9k_ani_cmd cmd, int param) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416AniState *aniState = ahp->ah_curani; + + switch (cmd & ahp->ah_ani_function) { + case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{ + u32 level = param; + + if (level >= ARRAY_SIZE(ahp->ah_totalSizeDesired)) { + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "level out of range (%u > %u)\n", + level, + (unsigned)ARRAY_SIZE(ahp->ah_totalSizeDesired)); + return false; + } + + REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, + AR_PHY_DESIRED_SZ_TOT_DES, + ahp->ah_totalSizeDesired[level]); + REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, + AR_PHY_AGC_CTL1_COARSE_LOW, + ahp->ah_coarseLow[level]); + REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, + AR_PHY_AGC_CTL1_COARSE_HIGH, + ahp->ah_coarseHigh[level]); + REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, + AR_PHY_FIND_SIG_FIRPWR, + ahp->ah_firpwr[level]); + + if (level > aniState->noiseImmunityLevel) + ahp->ah_stats.ast_ani_niup++; + else if (level < aniState->noiseImmunityLevel) + ahp->ah_stats.ast_ani_nidown++; + aniState->noiseImmunityLevel = level; + break; + } + case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{ + const int m1ThreshLow[] = { 127, 50 }; + const int m2ThreshLow[] = { 127, 40 }; + const int m1Thresh[] = { 127, 0x4d }; + const int m2Thresh[] = { 127, 0x40 }; + const int m2CountThr[] = { 31, 16 }; + const int m2CountThrLow[] = { 63, 48 }; + u32 on = param ? 1 : 0; + + REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_M1_THRESH_LOW, + m1ThreshLow[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_M2_THRESH_LOW, + m2ThreshLow[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR, + AR_PHY_SFCORR_M1_THRESH, + m1Thresh[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR, + AR_PHY_SFCORR_M2_THRESH, + m2Thresh[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR, + AR_PHY_SFCORR_M2COUNT_THR, + m2CountThr[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, + m2CountThrLow[on]); + + REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, + AR_PHY_SFCORR_EXT_M1_THRESH_LOW, + m1ThreshLow[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, + AR_PHY_SFCORR_EXT_M2_THRESH_LOW, + m2ThreshLow[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, + AR_PHY_SFCORR_EXT_M1_THRESH, + m1Thresh[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, + AR_PHY_SFCORR_EXT_M2_THRESH, + m2Thresh[on]); + + if (on) + REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); + else + REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); + + if (!on != aniState->ofdmWeakSigDetectOff) { + if (on) + ahp->ah_stats.ast_ani_ofdmon++; + else + ahp->ah_stats.ast_ani_ofdmoff++; + aniState->ofdmWeakSigDetectOff = !on; + } + break; + } + case ATH9K_ANI_CCK_WEAK_SIGNAL_THR:{ + const int weakSigThrCck[] = { 8, 6 }; + u32 high = param ? 1 : 0; + + REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT, + AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK, + weakSigThrCck[high]); + if (high != aniState->cckWeakSigThreshold) { + if (high) + ahp->ah_stats.ast_ani_cckhigh++; + else + ahp->ah_stats.ast_ani_ccklow++; + aniState->cckWeakSigThreshold = high; + } + break; + } + case ATH9K_ANI_FIRSTEP_LEVEL:{ + const int firstep[] = { 0, 4, 8 }; + u32 level = param; + + if (level >= ARRAY_SIZE(firstep)) { + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "level out of range (%u > %u)\n", + level, + (unsigned) ARRAY_SIZE(firstep)); + return false; + } + REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, + AR_PHY_FIND_SIG_FIRSTEP, + firstep[level]); + if (level > aniState->firstepLevel) + ahp->ah_stats.ast_ani_stepup++; + else if (level < aniState->firstepLevel) + ahp->ah_stats.ast_ani_stepdown++; + aniState->firstepLevel = level; + break; + } + case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{ + const int cycpwrThr1[] = + { 2, 4, 6, 8, 10, 12, 14, 16 }; + u32 level = param; + + if (level >= ARRAY_SIZE(cycpwrThr1)) { + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "level out of range (%u > %u)\n", + level, + (unsigned) + ARRAY_SIZE(cycpwrThr1)); + return false; + } + REG_RMW_FIELD(ah, AR_PHY_TIMING5, + AR_PHY_TIMING5_CYCPWR_THR1, + cycpwrThr1[level]); + if (level > aniState->spurImmunityLevel) + ahp->ah_stats.ast_ani_spurup++; + else if (level < aniState->spurImmunityLevel) + ahp->ah_stats.ast_ani_spurdown++; + aniState->spurImmunityLevel = level; + break; + } + case ATH9K_ANI_PRESENT: + break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "invalid cmd %u\n", cmd); + return false; + } + + DPRINTF(ah->ah_sc, ATH_DBG_ANI, "ANI parameters:\n"); + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "noiseImmunityLevel=%d, spurImmunityLevel=%d, " + "ofdmWeakSigDetectOff=%d\n", + aniState->noiseImmunityLevel, aniState->spurImmunityLevel, + !aniState->ofdmWeakSigDetectOff); + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "cckWeakSigThreshold=%d, " + "firstepLevel=%d, listenTime=%d\n", + aniState->cckWeakSigThreshold, aniState->firstepLevel, + aniState->listenTime); + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n", + aniState->cycleCount, aniState->ofdmPhyErrCount, + aniState->cckPhyErrCount); + + return true; +} + +static void ath9k_hw_update_mibstats(struct ath_hal *ah, + struct ath9k_mib_stats *stats) +{ + stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL); + stats->rts_bad += REG_READ(ah, AR_RTS_FAIL); + stats->fcs_bad += REG_READ(ah, AR_FCS_FAIL); + stats->rts_good += REG_READ(ah, AR_RTS_OK); + stats->beacons += REG_READ(ah, AR_BEACON_CNT); +} + +static void ath9k_ani_restart(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416AniState *aniState; + + if (!DO_ANI(ah)) + return; + + aniState = ahp->ah_curani; + + aniState->listenTime = 0; + if (ahp->ah_hasHwPhyCounters) { + if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) { + aniState->ofdmPhyErrBase = 0; + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "OFDM Trigger is too high for hw counters\n"); + } else { + aniState->ofdmPhyErrBase = + AR_PHY_COUNTMAX - aniState->ofdmTrigHigh; + } + if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) { + aniState->cckPhyErrBase = 0; + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "CCK Trigger is too high for hw counters\n"); + } else { + aniState->cckPhyErrBase = + AR_PHY_COUNTMAX - aniState->cckTrigHigh; + } + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Writing ofdmbase=%u cckbase=%u\n", + aniState->ofdmPhyErrBase, + aniState->cckPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); + REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); + + ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); + } + aniState->ofdmPhyErrCount = 0; + aniState->cckPhyErrCount = 0; +} + +static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ath9k_channel *chan = ah->ah_curchan; + struct ar5416AniState *aniState; + enum wireless_mode mode; + int32_t rssi; + + if (!DO_ANI(ah)) + return; + + aniState = ahp->ah_curani; + + if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { + if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, + aniState->noiseImmunityLevel + 1)) { + return; + } + } + + if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) { + if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, + aniState->spurImmunityLevel + 1)) { + return; + } + } + + if (ah->ah_opmode == NL80211_IFTYPE_AP) { + if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { + ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel + 1); + } + return; + } + rssi = BEACON_RSSI(ahp); + if (rssi > aniState->rssiThrHigh) { + if (!aniState->ofdmWeakSigDetectOff) { + if (ath9k_hw_ani_control(ah, + ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, + false)) { + ath9k_hw_ani_control(ah, + ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0); + return; + } + } + if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { + ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel + 1); + return; + } + } else if (rssi > aniState->rssiThrLow) { + if (aniState->ofdmWeakSigDetectOff) + ath9k_hw_ani_control(ah, + ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, + true); + if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) + ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel + 1); + return; + } else { + mode = ath9k_hw_chan2wmode(ah, chan); + if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) { + if (!aniState->ofdmWeakSigDetectOff) + ath9k_hw_ani_control(ah, + ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, + false); + if (aniState->firstepLevel > 0) + ath9k_hw_ani_control(ah, + ATH9K_ANI_FIRSTEP_LEVEL, 0); + return; + } + } +} + +static void ath9k_hw_ani_cck_err_trigger(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ath9k_channel *chan = ah->ah_curchan; + struct ar5416AniState *aniState; + enum wireless_mode mode; + int32_t rssi; + + if (!DO_ANI(ah)) + return; + + aniState = ahp->ah_curani; + if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { + if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, + aniState->noiseImmunityLevel + 1)) { + return; + } + } + if (ah->ah_opmode == NL80211_IFTYPE_AP) { + if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { + ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel + 1); + } + return; + } + rssi = BEACON_RSSI(ahp); + if (rssi > aniState->rssiThrLow) { + if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) + ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel + 1); + } else { + mode = ath9k_hw_chan2wmode(ah, chan); + if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) { + if (aniState->firstepLevel > 0) + ath9k_hw_ani_control(ah, + ATH9K_ANI_FIRSTEP_LEVEL, 0); + } + } +} + +static void ath9k_hw_ani_lower_immunity(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416AniState *aniState; + int32_t rssi; + + aniState = ahp->ah_curani; + + if (ah->ah_opmode == NL80211_IFTYPE_AP) { + if (aniState->firstepLevel > 0) { + if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel - 1)) + return; + } + } else { + rssi = BEACON_RSSI(ahp); + if (rssi > aniState->rssiThrHigh) { + /* XXX: Handle me */ + } else if (rssi > aniState->rssiThrLow) { + if (aniState->ofdmWeakSigDetectOff) { + if (ath9k_hw_ani_control(ah, + ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, + true) == true) + return; + } + if (aniState->firstepLevel > 0) { + if (ath9k_hw_ani_control(ah, + ATH9K_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel - 1) == true) + return; + } + } else { + if (aniState->firstepLevel > 0) { + if (ath9k_hw_ani_control(ah, + ATH9K_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel - 1) == true) + return; + } + } + } + + if (aniState->spurImmunityLevel > 0) { + if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, + aniState->spurImmunityLevel - 1)) + return; + } + + if (aniState->noiseImmunityLevel > 0) { + ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, + aniState->noiseImmunityLevel - 1); + return; + } +} + +static int32_t ath9k_hw_ani_get_listen_time(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416AniState *aniState; + u32 txFrameCount, rxFrameCount, cycleCount; + int32_t listenTime; + + txFrameCount = REG_READ(ah, AR_TFCNT); + rxFrameCount = REG_READ(ah, AR_RFCNT); + cycleCount = REG_READ(ah, AR_CCCNT); + + aniState = ahp->ah_curani; + if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) { + + listenTime = 0; + ahp->ah_stats.ast_ani_lzero++; + } else { + int32_t ccdelta = cycleCount - aniState->cycleCount; + int32_t rfdelta = rxFrameCount - aniState->rxFrameCount; + int32_t tfdelta = txFrameCount - aniState->txFrameCount; + listenTime = (ccdelta - rfdelta - tfdelta) / 44000; + } + aniState->cycleCount = cycleCount; + aniState->txFrameCount = txFrameCount; + aniState->rxFrameCount = rxFrameCount; + + return listenTime; +} + +void ath9k_ani_reset(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416AniState *aniState; + struct ath9k_channel *chan = ah->ah_curchan; + int index; + + if (!DO_ANI(ah)) + return; + + index = ath9k_hw_get_ani_channel_idx(ah, chan); + aniState = &ahp->ah_ani[index]; + ahp->ah_curani = aniState; + + if (DO_ANI(ah) && ah->ah_opmode != NL80211_IFTYPE_STATION + && ah->ah_opmode != NL80211_IFTYPE_ADHOC) { + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Reset ANI state opmode %u\n", ah->ah_opmode); + ahp->ah_stats.ast_ani_reset++; + + ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0); + ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0); + ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0); + ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, + !ATH9K_ANI_USE_OFDM_WEAK_SIG); + ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR, + ATH9K_ANI_CCK_WEAK_SIG_THR); + + ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) | + ATH9K_RX_FILTER_PHYERR); + + if (ah->ah_opmode == NL80211_IFTYPE_AP) { + ahp->ah_curani->ofdmTrigHigh = + ah->ah_config.ofdm_trig_high; + ahp->ah_curani->ofdmTrigLow = + ah->ah_config.ofdm_trig_low; + ahp->ah_curani->cckTrigHigh = + ah->ah_config.cck_trig_high; + ahp->ah_curani->cckTrigLow = + ah->ah_config.cck_trig_low; + } + ath9k_ani_restart(ah); + return; + } + + if (aniState->noiseImmunityLevel != 0) + ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, + aniState->noiseImmunityLevel); + if (aniState->spurImmunityLevel != 0) + ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, + aniState->spurImmunityLevel); + if (aniState->ofdmWeakSigDetectOff) + ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, + !aniState->ofdmWeakSigDetectOff); + if (aniState->cckWeakSigThreshold) + ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR, + aniState->cckWeakSigThreshold); + if (aniState->firstepLevel != 0) + ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel); + if (ahp->ah_hasHwPhyCounters) { + ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) & + ~ATH9K_RX_FILTER_PHYERR); + ath9k_ani_restart(ah); + REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); + REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); + + } else { + ath9k_ani_restart(ah); + ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) | + ATH9K_RX_FILTER_PHYERR); + } +} + +void ath9k_hw_ani_monitor(struct ath_hal *ah, + const struct ath9k_node_stats *stats, + struct ath9k_channel *chan) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416AniState *aniState; + int32_t listenTime; + + aniState = ahp->ah_curani; + ahp->ah_stats.ast_nodestats = *stats; + + listenTime = ath9k_hw_ani_get_listen_time(ah); + if (listenTime < 0) { + ahp->ah_stats.ast_ani_lneg++; + ath9k_ani_restart(ah); + return; + } + + aniState->listenTime += listenTime; + + if (ahp->ah_hasHwPhyCounters) { + u32 phyCnt1, phyCnt2; + u32 ofdmPhyErrCnt, cckPhyErrCnt; + + ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); + + phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); + phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); + + if (phyCnt1 < aniState->ofdmPhyErrBase || + phyCnt2 < aniState->cckPhyErrBase) { + if (phyCnt1 < aniState->ofdmPhyErrBase) { + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "phyCnt1 0x%x, resetting " + "counter value to 0x%x\n", + phyCnt1, + aniState->ofdmPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_1, + aniState->ofdmPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_MASK_1, + AR_PHY_ERR_OFDM_TIMING); + } + if (phyCnt2 < aniState->cckPhyErrBase) { + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "phyCnt2 0x%x, resetting " + "counter value to 0x%x\n", + phyCnt2, + aniState->cckPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_2, + aniState->cckPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_MASK_2, + AR_PHY_ERR_CCK_TIMING); + } + return; + } + + ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; + ahp->ah_stats.ast_ani_ofdmerrs += + ofdmPhyErrCnt - aniState->ofdmPhyErrCount; + aniState->ofdmPhyErrCount = ofdmPhyErrCnt; + + cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; + ahp->ah_stats.ast_ani_cckerrs += + cckPhyErrCnt - aniState->cckPhyErrCount; + aniState->cckPhyErrCount = cckPhyErrCnt; + } + + if (!DO_ANI(ah)) + return; + + if (aniState->listenTime > 5 * ahp->ah_aniPeriod) { + if (aniState->ofdmPhyErrCount <= aniState->listenTime * + aniState->ofdmTrigLow / 1000 && + aniState->cckPhyErrCount <= aniState->listenTime * + aniState->cckTrigLow / 1000) + ath9k_hw_ani_lower_immunity(ah); + ath9k_ani_restart(ah); + } else if (aniState->listenTime > ahp->ah_aniPeriod) { + if (aniState->ofdmPhyErrCount > aniState->listenTime * + aniState->ofdmTrigHigh / 1000) { + ath9k_hw_ani_ofdm_err_trigger(ah); + ath9k_ani_restart(ah); + } else if (aniState->cckPhyErrCount > + aniState->listenTime * aniState->cckTrigHigh / + 1000) { + ath9k_hw_ani_cck_err_trigger(ah); + ath9k_ani_restart(ah); + } + } +} + +bool ath9k_hw_phycounters(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + return ahp->ah_hasHwPhyCounters ? true : false; +} + +void ath9k_enable_mib_counters(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Enable MIB counters\n"); + + ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); + + REG_WRITE(ah, AR_FILT_OFDM, 0); + REG_WRITE(ah, AR_FILT_CCK, 0); + REG_WRITE(ah, AR_MIBC, + ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) + & 0x0f); + REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); + REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); +} + +void ath9k_hw_disable_mib_counters(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disable MIB counters\n"); + + REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC | AR_MIBC_CMC); + + ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); + + REG_WRITE(ah, AR_FILT_OFDM, 0); + REG_WRITE(ah, AR_FILT_CCK, 0); +} + +u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah, + u32 *rxc_pcnt, + u32 *rxf_pcnt, + u32 *txf_pcnt) +{ + static u32 cycles, rx_clear, rx_frame, tx_frame; + u32 good = 1; + + u32 rc = REG_READ(ah, AR_RCCNT); + u32 rf = REG_READ(ah, AR_RFCNT); + u32 tf = REG_READ(ah, AR_TFCNT); + u32 cc = REG_READ(ah, AR_CCCNT); + + if (cycles == 0 || cycles > cc) { + DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, + "cycle counter wrap. ExtBusy = 0\n"); + good = 0; + } else { + u32 cc_d = cc - cycles; + u32 rc_d = rc - rx_clear; + u32 rf_d = rf - rx_frame; + u32 tf_d = tf - tx_frame; + + if (cc_d != 0) { + *rxc_pcnt = rc_d * 100 / cc_d; + *rxf_pcnt = rf_d * 100 / cc_d; + *txf_pcnt = tf_d * 100 / cc_d; + } else { + good = 0; + } + } + + cycles = cc; + rx_frame = rf; + rx_clear = rc; + tx_frame = tf; + + return good; +} + +/* + * Process a MIB interrupt. We may potentially be invoked because + * any of the MIB counters overflow/trigger so don't assume we're + * here because a PHY error counter triggered. + */ +void ath9k_hw_procmibevent(struct ath_hal *ah, + const struct ath9k_node_stats *stats) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + u32 phyCnt1, phyCnt2; + + /* Reset these counters regardless */ + REG_WRITE(ah, AR_FILT_OFDM, 0); + REG_WRITE(ah, AR_FILT_CCK, 0); + if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING)) + REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR); + + /* Clear the mib counters and save them in the stats */ + ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); + ahp->ah_stats.ast_nodestats = *stats; + + if (!DO_ANI(ah)) + return; + + /* NB: these are not reset-on-read */ + phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); + phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); + if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) || + ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) { + struct ar5416AniState *aniState = ahp->ah_curani; + u32 ofdmPhyErrCnt, cckPhyErrCnt; + + /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */ + ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; + ahp->ah_stats.ast_ani_ofdmerrs += + ofdmPhyErrCnt - aniState->ofdmPhyErrCount; + aniState->ofdmPhyErrCount = ofdmPhyErrCnt; + + cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; + ahp->ah_stats.ast_ani_cckerrs += + cckPhyErrCnt - aniState->cckPhyErrCount; + aniState->cckPhyErrCount = cckPhyErrCnt; + + /* + * NB: figure out which counter triggered. If both + * trigger we'll only deal with one as the processing + * clobbers the error counter so the trigger threshold + * check will never be true. + */ + if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh) + ath9k_hw_ani_ofdm_err_trigger(ah); + if (aniState->cckPhyErrCount > aniState->cckTrigHigh) + ath9k_hw_ani_cck_err_trigger(ah); + /* NB: always restart to insure the h/w counters are reset */ + ath9k_ani_restart(ah); + } +} + +void ath9k_hw_ani_setup(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + int i; + + const int totalSizeDesired[] = { -55, -55, -55, -55, -62 }; + const int coarseHigh[] = { -14, -14, -14, -14, -12 }; + const int coarseLow[] = { -64, -64, -64, -64, -70 }; + const int firpwr[] = { -78, -78, -78, -78, -80 }; + + for (i = 0; i < 5; i++) { + ahp->ah_totalSizeDesired[i] = totalSizeDesired[i]; + ahp->ah_coarseHigh[i] = coarseHigh[i]; + ahp->ah_coarseLow[i] = coarseLow[i]; + ahp->ah_firpwr[i] = firpwr[i]; + } +} + +void ath9k_hw_ani_attach(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + int i; + + DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Attach ANI\n"); + + ahp->ah_hasHwPhyCounters = 1; + + memset(ahp->ah_ani, 0, sizeof(ahp->ah_ani)); + for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) { + ahp->ah_ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH; + ahp->ah_ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW; + ahp->ah_ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH; + ahp->ah_ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW; + ahp->ah_ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH; + ahp->ah_ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW; + ahp->ah_ani[i].ofdmWeakSigDetectOff = + !ATH9K_ANI_USE_OFDM_WEAK_SIG; + ahp->ah_ani[i].cckWeakSigThreshold = + ATH9K_ANI_CCK_WEAK_SIG_THR; + ahp->ah_ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; + ahp->ah_ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL; + if (ahp->ah_hasHwPhyCounters) { + ahp->ah_ani[i].ofdmPhyErrBase = + AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH; + ahp->ah_ani[i].cckPhyErrBase = + AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH; + } + } + if (ahp->ah_hasHwPhyCounters) { + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Setting OfdmErrBase = 0x%08x\n", + ahp->ah_ani[0].ofdmPhyErrBase); + DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n", + ahp->ah_ani[0].cckPhyErrBase); + + REG_WRITE(ah, AR_PHY_ERR_1, ahp->ah_ani[0].ofdmPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_2, ahp->ah_ani[0].cckPhyErrBase); + ath9k_enable_mib_counters(ah); + } + ahp->ah_aniPeriod = ATH9K_ANI_PERIOD; + if (ah->ah_config.enable_ani) + ahp->ah_procPhyErr |= HAL_PROCESS_ANI; +} + +void ath9k_hw_ani_detach(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Detach ANI\n"); + + if (ahp->ah_hasHwPhyCounters) { + ath9k_hw_disable_mib_counters(ah); + REG_WRITE(ah, AR_PHY_ERR_1, 0); + REG_WRITE(ah, AR_PHY_ERR_2, 0); + } +} diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index accace5f7efb9d809e962c4a32d2120e57182d60..d2781350295348f850c7b0501044a904c8a3ce65 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -26,6 +26,7 @@ #define AR9160_DEVID_PCI 0x0027 #define AR9280_DEVID_PCI 0x0029 #define AR9280_DEVID_PCIE 0x002a +#define AR9285_DEVID_PCIE 0x002b #define AR5416_AR9100_DEVID 0x000b @@ -138,6 +139,19 @@ struct ath_desc { #define ATH9K_TXDESC_NOACK 0x0002 #define ATH9K_TXDESC_RTSENA 0x0004 #define ATH9K_TXDESC_CTSENA 0x0008 +/* ATH9K_TXDESC_INTREQ forces a tx interrupt to be generated for + * the descriptor its marked on. We take a tx interrupt to reap + * descriptors when the h/w hits an EOL condition or + * when the descriptor is specifically marked to generate + * an interrupt with this flag. Descriptors should be + * marked periodically to insure timely replenishing of the + * supply needed for sending frames. Defering interrupts + * reduces system load and potentially allows more concurrent + * work to be done but if done to aggressively can cause + * senders to backup. When the hardware queue is left too + * large rate control information may also be too out of + * date. An Alternative for this is TX interrupt mitigation + * but this needs more testing. */ #define ATH9K_TXDESC_INTREQ 0x0010 #define ATH9K_TXDESC_VEOL 0x0020 #define ATH9K_TXDESC_EXT_ONLY 0x0040 @@ -388,22 +402,6 @@ enum ath9k_int { ATH9K_INT_NOCARD = 0xffffffff }; -struct ath9k_rate_table { - int rateCount; - u8 rateCodeToIndex[256]; - struct { - u8 valid; - u8 phy; - u32 rateKbps; - u8 rateCode; - u8 shortPreamble; - u8 dot11Rate; - u8 controlRate; - u16 lpAckDuration; - u16 spAckDuration; - } info[32]; -}; - #define ATH9K_RATESERIES_RTS_CTS 0x0001 #define ATH9K_RATESERIES_2040 0x0002 #define ATH9K_RATESERIES_HALFGI 0x0004 @@ -479,12 +477,10 @@ struct ath9k_channel { (((_c)->channelFlags & CHANNEL_A_HT20) == CHANNEL_A_HT20) || \ (((_c)->channelFlags & CHANNEL_A_HT40PLUS) == CHANNEL_A_HT40PLUS) || \ (((_c)->channelFlags & CHANNEL_A_HT40MINUS) == CHANNEL_A_HT40MINUS)) -#define IS_CHAN_B(_c) (((_c)->channelFlags & CHANNEL_B) == CHANNEL_B) #define IS_CHAN_G(_c) ((((_c)->channelFlags & (CHANNEL_G)) == CHANNEL_G) || \ (((_c)->channelFlags & CHANNEL_G_HT20) == CHANNEL_G_HT20) || \ (((_c)->channelFlags & CHANNEL_G_HT40PLUS) == CHANNEL_G_HT40PLUS) || \ (((_c)->channelFlags & CHANNEL_G_HT40MINUS) == CHANNEL_G_HT40MINUS)) -#define IS_CHAN_CCK(_c) (((_c)->channelFlags & CHANNEL_CCK) != 0) #define IS_CHAN_OFDM(_c) (((_c)->channelFlags & CHANNEL_OFDM) != 0) #define IS_CHAN_5GHZ(_c) (((_c)->channelFlags & CHANNEL_5GHZ) != 0) #define IS_CHAN_2GHZ(_c) (((_c)->channelFlags & CHANNEL_2GHZ) != 0) @@ -493,6 +489,7 @@ struct ath9k_channel { #define IS_CHAN_QUARTER_RATE(_c) (((_c)->channelFlags & CHANNEL_QUARTER) != 0) /* These macros check chanmode and not channelFlags */ +#define IS_CHAN_B(_c) ((_c)->chanmode == CHANNEL_B) #define IS_CHAN_HT20(_c) (((_c)->chanmode == CHANNEL_A_HT20) || \ ((_c)->chanmode == CHANNEL_G_HT20)) #define IS_CHAN_HT40(_c) (((_c)->chanmode == CHANNEL_A_HT40PLUS) || \ @@ -651,13 +648,6 @@ enum ath9k_ant_setting { ATH9K_ANT_FIXED_B }; -enum ath9k_opmode { - ATH9K_M_STA = 1, - ATH9K_M_IBSS = 0, - ATH9K_M_HOSTAP = 6, - ATH9K_M_MONITOR = 8 -}; - #define ATH9K_SLOT_TIME_6 6 #define ATH9K_SLOT_TIME_9 9 #define ATH9K_SLOT_TIME_20 20 @@ -689,13 +679,19 @@ enum ath9k_ani_cmd { ATH9K_ANI_ALL = 0xff }; -enum phytype { - PHY_DS, - PHY_FH, - PHY_OFDM, - PHY_HT, +enum { + WLAN_RC_PHY_OFDM, + WLAN_RC_PHY_CCK, + WLAN_RC_PHY_HT_20_SS, + WLAN_RC_PHY_HT_20_DS, + WLAN_RC_PHY_HT_40_SS, + WLAN_RC_PHY_HT_40_DS, + WLAN_RC_PHY_HT_20_SS_HGI, + WLAN_RC_PHY_HT_20_DS_HGI, + WLAN_RC_PHY_HT_40_SS_HGI, + WLAN_RC_PHY_HT_40_DS_HGI, + WLAN_RC_PHY_MAX }; -#define PHY_CCK PHY_DS enum ath9k_tp_scale { ATH9K_TP_SCALE_MAX = 0, @@ -778,7 +774,8 @@ struct ath_hal { void __iomem *ah_sh; struct ath_softc *ah_sc; - enum ath9k_opmode ah_opmode; + + enum nl80211_iftype ah_opmode; struct ath9k_ops_config ah_config; struct ath9k_hw_capabilities ah_caps; @@ -815,195 +812,246 @@ struct chan_centers { u16 ext_center; }; -int ath_hal_getcapability(struct ath_hal *ah, - enum ath9k_capability_type type, - u32 capability, - u32 *result); -const struct ath9k_rate_table *ath9k_hw_getratetable(struct ath_hal *ah, - u32 mode); -void ath9k_hw_detach(struct ath_hal *ah); -struct ath_hal *ath9k_hw_attach(u16 devid, - struct ath_softc *sc, - void __iomem *mem, - int *error); -bool ath9k_regd_init_channels(struct ath_hal *ah, - u32 maxchans, u32 *nchans, - u8 *regclassids, - u32 maxregids, u32 *nregids, - u16 cc, - bool enableOutdoor, - bool enableExtendedChannels); +struct ath_rate_table; + +/* Helpers */ + +enum wireless_mode ath9k_hw_chan2wmode(struct ath_hal *ah, + const struct ath9k_channel *chan); +bool ath9k_hw_wait(struct ath_hal *ah, u32 reg, u32 mask, u32 val); +u32 ath9k_hw_reverse_bits(u32 val, u32 n); +bool ath9k_get_channel_edges(struct ath_hal *ah, + u16 flags, u16 *low, + u16 *high); +u16 ath9k_hw_computetxtime(struct ath_hal *ah, + struct ath_rate_table *rates, + u32 frameLen, u16 rateix, + bool shortPreamble); u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags); -enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, - enum ath9k_int ints); -bool ath9k_hw_reset(struct ath_hal *ah, - struct ath9k_channel *chan, +void ath9k_hw_get_channel_centers(struct ath_hal *ah, + struct ath9k_channel *chan, + struct chan_centers *centers); + +/* Attach, Detach */ + +const char *ath9k_hw_probe(u16 vendorid, u16 devid); +void ath9k_hw_detach(struct ath_hal *ah); +struct ath_hal *ath9k_hw_attach(u16 devid, struct ath_softc *sc, + void __iomem *mem, int *error); +void ath9k_hw_rfdetach(struct ath_hal *ah); + + +/* HW Reset */ + +bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan, enum ath9k_ht_macmode macmode, u8 txchainmask, u8 rxchainmask, enum ath9k_ht_extprotspacing extprotspacing, - bool bChannelChange, - int *status); -bool ath9k_hw_phy_disable(struct ath_hal *ah); -void ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan, - bool *isCalDone); -void ath9k_hw_ani_monitor(struct ath_hal *ah, - const struct ath9k_node_stats *stats, - struct ath9k_channel *chan); -bool ath9k_hw_calibrate(struct ath_hal *ah, - struct ath9k_channel *chan, - u8 rxchainmask, - bool longcal, - bool *isCalDone); -s16 ath9k_hw_getchan_noise(struct ath_hal *ah, - struct ath9k_channel *chan); -void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid, - u16 assocId); -void ath9k_hw_setrxfilter(struct ath_hal *ah, u32 bits); -void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid, - u16 assocId); -bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q); -void ath9k_hw_reset_tsf(struct ath_hal *ah); -bool ath9k_hw_keyisvalid(struct ath_hal *ah, u16 entry); -bool ath9k_hw_keysetmac(struct ath_hal *ah, u16 entry, - const u8 *mac); -bool ath9k_hw_set_keycache_entry(struct ath_hal *ah, - u16 entry, - const struct ath9k_keyval *k, - const u8 *mac, - int xorKey); -bool ath9k_hw_set_tsfadjust(struct ath_hal *ah, - u32 setting); -void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore); -bool ath9k_hw_intrpend(struct ath_hal *ah); -bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked); -bool ath9k_hw_updatetxtriglevel(struct ath_hal *ah, - bool bIncTrigLevel); -void ath9k_hw_procmibevent(struct ath_hal *ah, - const struct ath9k_node_stats *stats); -bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set); -void ath9k_hw_set11nmac2040(struct ath_hal *ah, enum ath9k_ht_macmode mode); -bool ath9k_hw_phycounters(struct ath_hal *ah); + bool bChannelChange, int *status); + +/* Key Cache Management */ + bool ath9k_hw_keyreset(struct ath_hal *ah, u16 entry); -bool ath9k_hw_getcapability(struct ath_hal *ah, - enum ath9k_capability_type type, - u32 capability, - u32 *result); -bool ath9k_hw_setcapability(struct ath_hal *ah, - enum ath9k_capability_type type, - u32 capability, - u32 setting, - int *status); -u32 ath9k_hw_getdefantenna(struct ath_hal *ah); -void ath9k_hw_getmac(struct ath_hal *ah, u8 *mac); -void ath9k_hw_getbssidmask(struct ath_hal *ah, u8 *mask); -bool ath9k_hw_setbssidmask(struct ath_hal *ah, - const u8 *mask); +bool ath9k_hw_keysetmac(struct ath_hal *ah, u16 entry, const u8 *mac); +bool ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry, + const struct ath9k_keyval *k, + const u8 *mac, int xorKey); +bool ath9k_hw_keyisvalid(struct ath_hal *ah, u16 entry); + +/* Power Management */ + bool ath9k_hw_setpower(struct ath_hal *ah, enum ath9k_power_mode mode); -enum ath9k_int ath9k_hw_intrget(struct ath_hal *ah); -u64 ath9k_hw_gettsf64(struct ath_hal *ah); +void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore); + +/* Beacon timers */ + +void ath9k_hw_beaconinit(struct ath_hal *ah, u32 next_beacon, u32 beacon_period); +void ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah, + const struct ath9k_beacon_state *bs); +/* HW Capabilities */ + +bool ath9k_hw_fill_cap_info(struct ath_hal *ah); +bool ath9k_hw_getcapability(struct ath_hal *ah, enum ath9k_capability_type type, + u32 capability, u32 *result); +bool ath9k_hw_setcapability(struct ath_hal *ah, enum ath9k_capability_type type, + u32 capability, u32 setting, int *status); + +/* GPIO / RFKILL / Antennae */ + +void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio); +u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio); +void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio, + u32 ah_signal_type); +void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val); +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) +void ath9k_enable_rfkill(struct ath_hal *ah); +#endif +int ath9k_hw_select_antconfig(struct ath_hal *ah, u32 cfg); u32 ath9k_hw_getdefantenna(struct ath_hal *ah); -bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us); +void ath9k_hw_setantenna(struct ath_hal *ah, u32 antenna); bool ath9k_hw_setantennaswitch(struct ath_hal *ah, enum ath9k_ant_setting settings, struct ath9k_channel *chan, u8 *tx_chainmask, u8 *rx_chainmask, u8 *antenna_cfgd); -void ath9k_hw_setantenna(struct ath_hal *ah, u32 antenna); -int ath9k_hw_select_antconfig(struct ath_hal *ah, - u32 cfg); -bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q, - u32 txdp); + +/* General Operation */ + +u32 ath9k_hw_getrxfilter(struct ath_hal *ah); +void ath9k_hw_setrxfilter(struct ath_hal *ah, u32 bits); +bool ath9k_hw_phy_disable(struct ath_hal *ah); +bool ath9k_hw_disable(struct ath_hal *ah); +bool ath9k_hw_set_txpowerlimit(struct ath_hal *ah, u32 limit); +void ath9k_hw_getmac(struct ath_hal *ah, u8 *mac); +bool ath9k_hw_setmac(struct ath_hal *ah, const u8 *mac); +void ath9k_hw_setopmode(struct ath_hal *ah); +void ath9k_hw_setmcastfilter(struct ath_hal *ah, u32 filter0, u32 filter1); +void ath9k_hw_getbssidmask(struct ath_hal *ah, u8 *mask); +bool ath9k_hw_setbssidmask(struct ath_hal *ah, const u8 *mask); +void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid, u16 assocId); +u64 ath9k_hw_gettsf64(struct ath_hal *ah); +void ath9k_hw_reset_tsf(struct ath_hal *ah); +bool ath9k_hw_set_tsfadjust(struct ath_hal *ah, u32 setting); +bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us); +void ath9k_hw_set11nmac2040(struct ath_hal *ah, enum ath9k_ht_macmode mode); + +/* Regulatory */ + +bool ath9k_regd_is_public_safety_sku(struct ath_hal *ah); +struct ath9k_channel* ath9k_regd_check_channel(struct ath_hal *ah, + const struct ath9k_channel *c); +u32 ath9k_regd_get_ctl(struct ath_hal *ah, struct ath9k_channel *chan); +u32 ath9k_regd_get_antenna_allowed(struct ath_hal *ah, + struct ath9k_channel *chan); +bool ath9k_regd_init_channels(struct ath_hal *ah, + u32 maxchans, u32 *nchans, u8 *regclassids, + u32 maxregids, u32 *nregids, u16 cc, + bool enableOutdoor, bool enableExtendedChannels); + +/* ANI */ + +void ath9k_ani_reset(struct ath_hal *ah); +void ath9k_hw_ani_monitor(struct ath_hal *ah, + const struct ath9k_node_stats *stats, + struct ath9k_channel *chan); +bool ath9k_hw_phycounters(struct ath_hal *ah); +void ath9k_enable_mib_counters(struct ath_hal *ah); +void ath9k_hw_disable_mib_counters(struct ath_hal *ah); +u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah, + u32 *rxc_pcnt, + u32 *rxf_pcnt, + u32 *txf_pcnt); +void ath9k_hw_procmibevent(struct ath_hal *ah, + const struct ath9k_node_stats *stats); +void ath9k_hw_ani_setup(struct ath_hal *ah); +void ath9k_hw_ani_attach(struct ath_hal *ah); +void ath9k_hw_ani_detach(struct ath_hal *ah); + +/* Calibration */ + +void ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan, + bool *isCalDone); +void ath9k_hw_start_nfcal(struct ath_hal *ah); +void ath9k_hw_loadnf(struct ath_hal *ah, struct ath9k_channel *chan); +int16_t ath9k_hw_getnf(struct ath_hal *ah, + struct ath9k_channel *chan); +void ath9k_init_nfcal_hist_buffer(struct ath_hal *ah); +s16 ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan); +bool ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan, + u8 rxchainmask, bool longcal, + bool *isCalDone); +bool ath9k_hw_init_cal(struct ath_hal *ah, + struct ath9k_channel *chan); + + +/* EEPROM */ + +int ath9k_hw_set_txpower(struct ath_hal *ah, + struct ath9k_channel *chan, + u16 cfgCtl, + u8 twiceAntennaReduction, + u8 twiceMaxRegulatoryPower, + u8 powerLimit); +void ath9k_hw_set_addac(struct ath_hal *ah, struct ath9k_channel *chan); +bool ath9k_hw_set_power_per_rate_table(struct ath_hal *ah, + struct ath9k_channel *chan, + int16_t *ratesArray, + u16 cfgCtl, + u8 AntennaReduction, + u8 twiceMaxRegulatoryPower, + u8 powerLimit); +bool ath9k_hw_set_power_cal_table(struct ath_hal *ah, + struct ath9k_channel *chan, + int16_t *pTxPowerIndexOffset); +bool ath9k_hw_eeprom_set_board_values(struct ath_hal *ah, + struct ath9k_channel *chan); +int ath9k_hw_get_eeprom_antenna_cfg(struct ath_hal *ah, + struct ath9k_channel *chan, + u8 index, u16 *config); +u8 ath9k_hw_get_num_ant_config(struct ath_hal *ah, + enum ieee80211_band freq_band); +u16 ath9k_hw_eeprom_get_spur_chan(struct ath_hal *ah, u16 i, bool is2GHz); +int ath9k_hw_eeprom_attach(struct ath_hal *ah); + +/* Interrupt Handling */ + +bool ath9k_hw_intrpend(struct ath_hal *ah); +bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked); +enum ath9k_int ath9k_hw_intrget(struct ath_hal *ah); +enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints); + +/* MAC (PCU/QCU) */ + +u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q); +bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q, u32 txdp); bool ath9k_hw_txstart(struct ath_hal *ah, u32 q); -u16 ath9k_hw_computetxtime(struct ath_hal *ah, - const struct ath9k_rate_table *rates, - u32 frameLen, u16 rateix, - bool shortPreamble); +u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q); +bool ath9k_hw_updatetxtriglevel(struct ath_hal *ah, bool bIncTrigLevel); +bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q); +bool ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds, + u32 segLen, bool firstSeg, + bool lastSeg, const struct ath_desc *ds0); +void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds); +int ath9k_hw_txprocdesc(struct ath_hal *ah, struct ath_desc *ds); +void ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds, + u32 pktLen, enum ath9k_pkt_type type, u32 txPower, + u32 keyIx, enum ath9k_key_type keyType, u32 flags); void ath9k_hw_set11n_ratescenario(struct ath_hal *ah, struct ath_desc *ds, struct ath_desc *lastds, u32 durUpdateEn, u32 rtsctsRate, u32 rtsctsDuration, struct ath9k_11n_rate_series series[], u32 nseries, u32 flags); -void ath9k_hw_set11n_burstduration(struct ath_hal *ah, - struct ath_desc *ds, +void ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds, + u32 aggrLen); +void ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds, + u32 numDelims); +void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds); +void ath9k_hw_clr11n_aggr(struct ath_hal *ah, struct ath_desc *ds); +void ath9k_hw_set11n_burstduration(struct ath_hal *ah, struct ath_desc *ds, u32 burstDuration); -void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds); -u32 ath9k_hw_reverse_bits(u32 val, u32 n); -bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q); -u32 ath9k_regd_get_ctl(struct ath_hal *ah, struct ath9k_channel *chan); -u32 ath9k_regd_get_antenna_allowed(struct ath_hal *ah, - struct ath9k_channel *chan); -u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags); -bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q, - struct ath9k_tx_queue_info *qinfo); +void ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah, struct ath_desc *ds, + u32 vmf); +void ath9k_hw_gettxintrtxqs(struct ath_hal *ah, u32 *txqs); bool ath9k_hw_set_txq_props(struct ath_hal *ah, int q, const struct ath9k_tx_queue_info *qinfo); -struct ath9k_channel *ath9k_regd_check_channel(struct ath_hal *ah, - const struct ath9k_channel *c); -void ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds, - u32 pktLen, enum ath9k_pkt_type type, - u32 txPower, u32 keyIx, - enum ath9k_key_type keyType, u32 flags); -bool ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds, - u32 segLen, bool firstSeg, - bool lastSeg, - const struct ath_desc *ds0); -u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah, - u32 *rxc_pcnt, - u32 *rxf_pcnt, - u32 *txf_pcnt); -void ath9k_hw_dmaRegDump(struct ath_hal *ah); -void ath9k_hw_beaconinit(struct ath_hal *ah, - u32 next_beacon, u32 beacon_period); -void ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah, - const struct ath9k_beacon_state *bs); +bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q, + struct ath9k_tx_queue_info *qinfo); +int ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type, + const struct ath9k_tx_queue_info *qinfo); +bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q); +bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q); +int ath9k_hw_rxprocdesc(struct ath_hal *ah, struct ath_desc *ds, + u32 pa, struct ath_desc *nds, u64 tsf); bool ath9k_hw_setuprxdesc(struct ath_hal *ah, struct ath_desc *ds, u32 size, u32 flags); +bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set); void ath9k_hw_putrxbuf(struct ath_hal *ah, u32 rxdp); void ath9k_hw_rxena(struct ath_hal *ah); -void ath9k_hw_setopmode(struct ath_hal *ah); -bool ath9k_hw_setmac(struct ath_hal *ah, const u8 *mac); -void ath9k_hw_setmcastfilter(struct ath_hal *ah, u32 filter0, - u32 filter1); -u32 ath9k_hw_getrxfilter(struct ath_hal *ah); void ath9k_hw_startpcureceive(struct ath_hal *ah); void ath9k_hw_stoppcurecv(struct ath_hal *ah); bool ath9k_hw_stopdmarecv(struct ath_hal *ah); -int ath9k_hw_rxprocdesc(struct ath_hal *ah, - struct ath_desc *ds, u32 pa, - struct ath_desc *nds, u64 tsf); -u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q); -int ath9k_hw_txprocdesc(struct ath_hal *ah, - struct ath_desc *ds); -void ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds, - u32 numDelims); -void ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds, - u32 aggrLen); -void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds); -bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q); -void ath9k_hw_gettxintrtxqs(struct ath_hal *ah, u32 *txqs); -void ath9k_hw_clr11n_aggr(struct ath_hal *ah, struct ath_desc *ds); -void ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah, - struct ath_desc *ds, u32 vmf); -bool ath9k_hw_set_txpowerlimit(struct ath_hal *ah, u32 limit); -bool ath9k_regd_is_public_safety_sku(struct ath_hal *ah); -int ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type, - const struct ath9k_tx_queue_info *qinfo); -u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q); -const char *ath9k_hw_probe(u16 vendorid, u16 devid); -bool ath9k_hw_disable(struct ath_hal *ah); -void ath9k_hw_rfdetach(struct ath_hal *ah); -void ath9k_hw_get_channel_centers(struct ath_hal *ah, - struct ath9k_channel *chan, - struct chan_centers *centers); -bool ath9k_get_channel_edges(struct ath_hal *ah, - u16 flags, u16 *low, - u16 *high); -void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio, - u32 ah_signal_type); -void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 value); -u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio); -void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio); + #endif diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index 4dd1c1bda0fb80958b16066d882d86c7219a3b3e..3ab0b43aaf93f79c6b8af3859f7cf0ea9990e3db 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -14,13 +14,9 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ - /* Implementation of beacon processing. */ - #include "core.h" /* - * Configure parameters for the beacon queue - * * This function will modify certain transmit queue properties depending on * the operating mode of the station (AP or AdHoc). Parameters are AIFS * settings and channel width min/max @@ -30,33 +26,38 @@ static int ath_beaconq_config(struct ath_softc *sc) struct ath_hal *ah = sc->sc_ah; struct ath9k_tx_queue_info qi; - ath9k_hw_get_txq_props(ah, sc->sc_bhalq, &qi); - if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) { + ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi); + if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) { /* Always burst out beacon and CAB traffic. */ qi.tqi_aifs = 1; qi.tqi_cwmin = 0; qi.tqi_cwmax = 0; } else { /* Adhoc mode; important thing is to use 2x cwmin. */ - qi.tqi_aifs = sc->sc_beacon_qi.tqi_aifs; - qi.tqi_cwmin = 2*sc->sc_beacon_qi.tqi_cwmin; - qi.tqi_cwmax = sc->sc_beacon_qi.tqi_cwmax; + qi.tqi_aifs = sc->beacon.beacon_qi.tqi_aifs; + qi.tqi_cwmin = 2*sc->beacon.beacon_qi.tqi_cwmin; + qi.tqi_cwmax = sc->beacon.beacon_qi.tqi_cwmax; } - if (!ath9k_hw_set_txq_props(ah, sc->sc_bhalq, &qi)) { + if (!ath9k_hw_set_txq_props(ah, sc->beacon.beaconq, &qi)) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to update h/w beacon queue parameters\n", - __func__); + "unable to update h/w beacon queue parameters\n"); return 0; } else { - ath9k_hw_resettxqueue(ah, sc->sc_bhalq); /* push to h/w */ + ath9k_hw_resettxqueue(ah, sc->beacon.beaconq); /* push to h/w */ return 1; } } +static void ath_bstuck_process(struct ath_softc *sc) +{ + DPRINTF(sc, ATH_DBG_BEACON, + "stuck beacon; resetting (bmiss count %u)\n", + sc->beacon.bmisscnt); + ath_reset(sc, false); +} + /* - * Setup the beacon frame for transmit. - * * Associates the beacon frame buffer with a transmit descriptor. Will set * up all required antenna switch parameters, rate codes, and channel flags. * Beacons are always sent out at the lowest rate, and are not retried. @@ -68,21 +69,20 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_hal *ah = sc->sc_ah; struct ath_desc *ds; struct ath9k_11n_rate_series series[4]; - const struct ath9k_rate_table *rt; + struct ath_rate_table *rt; int flags, antenna; u8 rix, rate; int ctsrate = 0; int ctsduration = 0; - DPRINTF(sc, ATH_DBG_BEACON, "%s: m %p len %u\n", - __func__, skb, skb->len); + DPRINTF(sc, ATH_DBG_BEACON, "m %p len %u\n", skb, skb->len); /* setup descriptors */ ds = bf->bf_desc; flags = ATH9K_TXDESC_NOACK; - if (sc->sc_ah->ah_opmode == ATH9K_M_IBSS && + if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC && (ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) { ds->ds_link = bf->bf_daddr; /* self-linked */ flags |= ATH9K_TXDESC_VEOL; @@ -96,7 +96,7 @@ static void ath_beacon_setup(struct ath_softc *sc, * SWBA's * XXX assumes two antenna */ - antenna = ((sc->ast_be_xmit / sc->sc_nbcnvaps) & 1 ? 2 : 1); + antenna = ((sc->beacon.ast_be_xmit / sc->sc_nbcnvaps) & 1 ? 2 : 1); } ds->ds_data = bf->bf_buf_addr; @@ -106,15 +106,15 @@ static void ath_beacon_setup(struct ath_softc *sc, * XXX everything at min xmit rate */ rix = 0; - rt = sc->sc_currates; - rate = rt->info[rix].rateCode; + rt = sc->cur_rate_table; + rate = rt->info[rix].ratecode; if (sc->sc_flags & SC_OP_PREAMBLE_SHORT) - rate |= rt->info[rix].shortPreamble; + rate |= rt->info[rix].short_preamble; ath9k_hw_set11n_txdesc(ah, ds, skb->len + FCS_LEN, /* frame length */ ATH9K_PKT_TYPE_BEACON, /* Atheros packet type */ - avp->av_btxctl.txpower, /* txpower XXX */ + MAX_RATE_POWER, /* FIXME */ ATH9K_TXKEYIX_INVALID, /* no encryption */ ATH9K_KEY_TYPE_CLEAR, /* no encryption */ flags /* no ack, @@ -138,31 +138,26 @@ static void ath_beacon_setup(struct ath_softc *sc, ctsrate, ctsduration, series, 4, 0); } -/* - * Generate beacon frame and queue cab data for a vap. - * - * Updates the contents of the beacon frame. It is assumed that the buffer for - * the beacon frame has been allocated in the ATH object, and simply needs to - * be filled for this cycle. Also, any CAB (crap after beacon?) traffic will - * be added to the beacon frame at this point. -*/ +/* Generate beacon frame and queue cab data for a vap */ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) { struct ath_buf *bf; struct ath_vap *avp; struct sk_buff *skb; struct ath_txq *cabq; + struct ieee80211_vif *vif; struct ieee80211_tx_info *info; int cabq_depth; - avp = sc->sc_vaps[if_id]; - ASSERT(avp); + vif = sc->sc_vaps[if_id]; + ASSERT(vif); - cabq = sc->sc_cabq; + avp = (void *)vif->drv_priv; + cabq = sc->beacon.cabq; if (avp->av_bcbuf == NULL) { - DPRINTF(sc, ATH_DBG_BEACON, "%s: avp=%p av_bcbuf=%p\n", - __func__, avp, avp->av_bcbuf); + DPRINTF(sc, ATH_DBG_BEACON, "avp=%p av_bcbuf=%p\n", + avp, avp->av_bcbuf); return NULL; } @@ -172,9 +167,10 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) pci_unmap_single(sc->pdev, bf->bf_dmacontext, skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb_any(skb); } - skb = ieee80211_beacon_get(sc->hw, avp->av_if_data); + skb = ieee80211_beacon_get(sc->hw, vif); bf->bf_mpdu = skb; if (skb == NULL) return NULL; @@ -186,17 +182,24 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) * TX frames) */ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - sc->seq_no += 0x10; + sc->tx.seq_no += 0x10; hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); - hdr->seq_ctrl |= cpu_to_le16(sc->seq_no); + hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no); } bf->bf_buf_addr = bf->bf_dmacontext = pci_map_single(sc->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); + if (unlikely(pci_dma_mapping_error(sc->pdev, bf->bf_buf_addr))) { + dev_kfree_skb_any(skb); + bf->bf_mpdu = NULL; + DPRINTF(sc, ATH_DBG_CONFIG, + "pci_dma_mapping_error() on beaconing\n"); + return NULL; + } - skb = ieee80211_get_buffered_bc(sc->hw, avp->av_if_data); + skb = ieee80211_get_buffered_bc(sc->hw, vif); /* * if the CABQ traffic from previous DTIM is pending and the current @@ -219,7 +222,7 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) if (sc->sc_nvaps > 1) { ath_tx_draintxq(sc, cabq, false); DPRINTF(sc, ATH_DBG_BEACON, - "%s: flush previous cabq traffic\n", __func__); + "flush previous cabq traffic\n"); } } @@ -232,7 +235,7 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) */ while (skb) { ath_tx_cabq(sc, skb); - skb = ieee80211_get_buffered_bc(sc->hw, avp->av_if_data); + skb = ieee80211_get_buffered_bc(sc->hw, vif); } return bf; @@ -244,17 +247,20 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) */ static void ath_beacon_start_adhoc(struct ath_softc *sc, int if_id) { + struct ieee80211_vif *vif; struct ath_hal *ah = sc->sc_ah; struct ath_buf *bf; struct ath_vap *avp; struct sk_buff *skb; - avp = sc->sc_vaps[if_id]; - ASSERT(avp); + vif = sc->sc_vaps[if_id]; + ASSERT(vif); + + avp = (void *)vif->drv_priv; if (avp->av_bcbuf == NULL) { - DPRINTF(sc, ATH_DBG_BEACON, "%s: avp=%p av_bcbuf=%p\n", - __func__, avp, avp != NULL ? avp->av_bcbuf : NULL); + DPRINTF(sc, ATH_DBG_BEACON, "avp=%p av_bcbuf=%p\n", + avp, avp != NULL ? avp->av_bcbuf : NULL); return; } bf = avp->av_bcbuf; @@ -264,20 +270,12 @@ static void ath_beacon_start_adhoc(struct ath_softc *sc, int if_id) ath_beacon_setup(sc, avp, bf); /* NB: caller is known to have already stopped tx dma */ - ath9k_hw_puttxbuf(ah, sc->sc_bhalq, bf->bf_daddr); - ath9k_hw_txstart(ah, sc->sc_bhalq); - DPRINTF(sc, ATH_DBG_BEACON, "%s: TXDP%u = %llx (%p)\n", __func__, - sc->sc_bhalq, ito64(bf->bf_daddr), bf->bf_desc); + ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bf->bf_daddr); + ath9k_hw_txstart(ah, sc->beacon.beaconq); + DPRINTF(sc, ATH_DBG_BEACON, "TXDP%u = %llx (%p)\n", + sc->beacon.beaconq, ito64(bf->bf_daddr), bf->bf_desc); } -/* - * Setup a h/w transmit queue for beacons. - * - * This function allocates an information structure (struct ath9k_txq_info) - * on the stack, sets some specific parameters (zero out channel width - * min/max, and enable aifs). The info structure does not need to be - * persistant. -*/ int ath_beaconq_setup(struct ath_hal *ah) { struct ath9k_tx_queue_info qi; @@ -290,35 +288,29 @@ int ath_beaconq_setup(struct ath_hal *ah) return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi); } - -/* - * Allocate and setup an initial beacon frame. - * - * Allocate a beacon state variable for a specific VAP instance created on - * the ATH interface. This routine also calculates the beacon "slot" for - * staggared beacons in the mBSSID case. -*/ int ath_beacon_alloc(struct ath_softc *sc, int if_id) { + struct ieee80211_vif *vif; struct ath_vap *avp; struct ieee80211_hdr *hdr; struct ath_buf *bf; struct sk_buff *skb; __le64 tstamp; - avp = sc->sc_vaps[if_id]; - ASSERT(avp); + vif = sc->sc_vaps[if_id]; + ASSERT(vif); + + avp = (void *)vif->drv_priv; /* Allocate a beacon descriptor if we haven't done so. */ if (!avp->av_bcbuf) { /* Allocate beacon state for hostap/ibss. We know * a buffer is available. */ - - avp->av_bcbuf = list_first_entry(&sc->sc_bbuf, + avp->av_bcbuf = list_first_entry(&sc->beacon.bbuf, struct ath_buf, list); list_del(&avp->av_bcbuf->list); - if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP || + if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP || !(sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) { int slot; /* @@ -327,13 +319,13 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) */ avp->av_bslot = 0; for (slot = 0; slot < ATH_BCBUF; slot++) - if (sc->sc_bslot[slot] == ATH_IF_ID_ANY) { + if (sc->beacon.bslot[slot] == ATH_IF_ID_ANY) { /* * XXX hack, space out slots to better * deal with misses */ if (slot+1 < ATH_BCBUF && - sc->sc_bslot[slot+1] == + sc->beacon.bslot[slot+1] == ATH_IF_ID_ANY) { avp->av_bslot = slot+1; break; @@ -341,8 +333,8 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) avp->av_bslot = slot; /* NB: keep looking for a double slot */ } - BUG_ON(sc->sc_bslot[avp->av_bslot] != ATH_IF_ID_ANY); - sc->sc_bslot[avp->av_bslot] = if_id; + BUG_ON(sc->beacon.bslot[avp->av_bslot] != ATH_IF_ID_ANY); + sc->beacon.bslot[avp->av_bslot] = if_id; sc->sc_nbcnvaps++; } } @@ -363,15 +355,14 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) * FIXME: Fill avp->av_btxctl.txpower and * avp->av_btxctl.shortPreamble */ - skb = ieee80211_beacon_get(sc->hw, avp->av_if_data); + skb = ieee80211_beacon_get(sc->hw, vif); if (skb == NULL) { - DPRINTF(sc, ATH_DBG_BEACON, "%s: cannot get skb\n", - __func__); + DPRINTF(sc, ATH_DBG_BEACON, "cannot get skb\n"); return -ENOMEM; } tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; - sc->bc_tstamp = le64_to_cpu(tstamp); + sc->beacon.bc_tstamp = le64_to_cpu(tstamp); /* * Calculate a TSF adjustment factor required for @@ -402,36 +393,36 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) val = cpu_to_le64(tsfadjust << 10); /* TU->TSF */ DPRINTF(sc, ATH_DBG_BEACON, - "%s: %s beacons, bslot %d intval %u tsfadjust %llu\n", - __func__, "stagger", + "stagger beacons, bslot %d intval %u tsfadjust %llu\n", avp->av_bslot, intval, (unsigned long long)tsfadjust); hdr = (struct ieee80211_hdr *)skb->data; memcpy(&hdr[1], &val, sizeof(val)); } + bf->bf_mpdu = skb; bf->bf_buf_addr = bf->bf_dmacontext = pci_map_single(sc->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); - bf->bf_mpdu = skb; + if (unlikely(pci_dma_mapping_error(sc->pdev, bf->bf_buf_addr))) { + dev_kfree_skb_any(skb); + bf->bf_mpdu = NULL; + DPRINTF(sc, ATH_DBG_CONFIG, + "pci_dma_mapping_error() on beacon alloc\n"); + return -ENOMEM; + } return 0; } -/* - * Reclaim beacon resources and return buffer to the pool. - * - * Checks the VAP to put the beacon frame buffer back to the ATH object - * queue, and de-allocates any skbs that were sent as CAB traffic. -*/ void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp) { if (avp->av_bcbuf != NULL) { struct ath_buf *bf; if (avp->av_bslot != -1) { - sc->sc_bslot[avp->av_bslot] = ATH_IF_ID_ANY; + sc->beacon.bslot[avp->av_bslot] = ATH_IF_ID_ANY; sc->sc_nbcnvaps--; } @@ -444,19 +435,12 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp) dev_kfree_skb_any(skb); bf->bf_mpdu = NULL; } - list_add_tail(&bf->list, &sc->sc_bbuf); + list_add_tail(&bf->list, &sc->beacon.bbuf); avp->av_bcbuf = NULL; } } -/* - * Tasklet for Sending Beacons - * - * Transmit one or more beacon frames at SWBA. Dynamic updates to the frame - * contents are done as needed and the slot time is also adjusted based on - * current state. -*/ void ath9k_beacon_tasklet(unsigned long data) { struct ath_softc *sc = (struct ath_softc *)data; @@ -473,9 +457,7 @@ void ath9k_beacon_tasklet(unsigned long data) if (sc->sc_flags & SC_OP_NO_RESET) { show_cycles = ath9k_hw_GetMibCycleCountsPct(ah, - &rx_clear, - &rx_frame, - &tx_frame); + &rx_clear, &rx_frame, &tx_frame); } /* @@ -487,67 +469,65 @@ void ath9k_beacon_tasklet(unsigned long data) * * FIXME: Clean up this mess !! */ - if (ath9k_hw_numtxpending(ah, sc->sc_bhalq) != 0) { - sc->sc_bmisscount++; + if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0) { + sc->beacon.bmisscnt++; /* XXX: doth needs the chanchange IE countdown decremented. * We should consider adding a mac80211 call to indicate * a beacon miss so appropriate action could be taken * (in that layer). */ - if (sc->sc_bmisscount < BSTUCK_THRESH) { + if (sc->beacon.bmisscnt < BSTUCK_THRESH) { if (sc->sc_flags & SC_OP_NO_RESET) { DPRINTF(sc, ATH_DBG_BEACON, - "%s: missed %u consecutive beacons\n", - __func__, sc->sc_bmisscount); + "missed %u consecutive beacons\n", + sc->beacon.bmisscnt); if (show_cycles) { /* * Display cycle counter stats from HW * to aide in debug of stickiness. */ DPRINTF(sc, ATH_DBG_BEACON, - "%s: busy times: rx_clear=%d, " + "busy times: rx_clear=%d, " "rx_frame=%d, tx_frame=%d\n", - __func__, rx_clear, rx_frame, + rx_clear, rx_frame, tx_frame); } else { DPRINTF(sc, ATH_DBG_BEACON, - "%s: unable to obtain " - "busy times\n", __func__); + "unable to obtain " + "busy times\n"); } } else { DPRINTF(sc, ATH_DBG_BEACON, - "%s: missed %u consecutive beacons\n", - __func__, sc->sc_bmisscount); + "missed %u consecutive beacons\n", + sc->beacon.bmisscnt); } - } else if (sc->sc_bmisscount >= BSTUCK_THRESH) { + } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) { if (sc->sc_flags & SC_OP_NO_RESET) { - if (sc->sc_bmisscount == BSTUCK_THRESH) { + if (sc->beacon.bmisscnt == BSTUCK_THRESH) { DPRINTF(sc, ATH_DBG_BEACON, - "%s: beacon is officially " - "stuck\n", __func__); - ath9k_hw_dmaRegDump(ah); + "beacon is officially " + "stuck\n"); } } else { DPRINTF(sc, ATH_DBG_BEACON, - "%s: beacon is officially stuck\n", - __func__); + "beacon is officially stuck\n"); ath_bstuck_process(sc); } } return; } - if (sc->sc_bmisscount != 0) { + if (sc->beacon.bmisscnt != 0) { if (sc->sc_flags & SC_OP_NO_RESET) { DPRINTF(sc, ATH_DBG_BEACON, - "%s: resume beacon xmit after %u misses\n", - __func__, sc->sc_bmisscount); + "resume beacon xmit after %u misses\n", + sc->beacon.bmisscnt); } else { DPRINTF(sc, ATH_DBG_BEACON, - "%s: resume beacon xmit after %u misses\n", - __func__, sc->sc_bmisscount); + "resume beacon xmit after %u misses\n", + sc->beacon.bmisscnt); } - sc->sc_bmisscount = 0; + sc->beacon.bmisscnt = 0; } /* @@ -562,11 +542,11 @@ void ath9k_beacon_tasklet(unsigned long data) tsf = ath9k_hw_gettsf64(ah); tsftu = TSF_TO_TU(tsf>>32, tsf); slot = ((tsftu % intval) * ATH_BCBUF) / intval; - if_id = sc->sc_bslot[(slot + 1) % ATH_BCBUF]; + if_id = sc->beacon.bslot[(slot + 1) % ATH_BCBUF]; DPRINTF(sc, ATH_DBG_BEACON, - "%s: slot %d [tsf %llu tsftu %u intval %u] if_id %d\n", - __func__, slot, (unsigned long long)tsf, tsftu, + "slot %d [tsf %llu tsftu %u intval %u] if_id %d\n", + slot, (unsigned long long)tsf, tsftu, intval, if_id); bfaddr = 0; @@ -594,47 +574,33 @@ void ath9k_beacon_tasklet(unsigned long data) * set to ATH_BCBUF so this check is a noop. */ /* XXX locking */ - if (sc->sc_updateslot == UPDATE) { - sc->sc_updateslot = COMMIT; /* commit next beacon */ - sc->sc_slotupdate = slot; - } else if (sc->sc_updateslot == COMMIT && sc->sc_slotupdate == slot) - ath_setslottime(sc); /* commit change to hardware */ - + if (sc->beacon.updateslot == UPDATE) { + sc->beacon.updateslot = COMMIT; /* commit next beacon */ + sc->beacon.slotupdate = slot; + } else if (sc->beacon.updateslot == COMMIT && sc->beacon.slotupdate == slot) { + ath9k_hw_setslottime(sc->sc_ah, sc->beacon.slottime); + sc->beacon.updateslot = OK; + } if (bfaddr != 0) { /* * Stop any current dma and put the new frame(s) on the queue. * This should never fail since we check above that no frames * are still pending on the queue. */ - if (!ath9k_hw_stoptxdma(ah, sc->sc_bhalq)) { + if (!ath9k_hw_stoptxdma(ah, sc->beacon.beaconq)) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: beacon queue %u did not stop?\n", - __func__, sc->sc_bhalq); + "beacon queue %u did not stop?\n", sc->beacon.beaconq); /* NB: the HAL still stops DMA, so proceed */ } /* NB: cabq traffic should already be queued and primed */ - ath9k_hw_puttxbuf(ah, sc->sc_bhalq, bfaddr); - ath9k_hw_txstart(ah, sc->sc_bhalq); + ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bfaddr); + ath9k_hw_txstart(ah, sc->beacon.beaconq); - sc->ast_be_xmit += bc; /* XXX per-vap? */ + sc->beacon.ast_be_xmit += bc; /* XXX per-vap? */ } } -/* - * Tasklet for Beacon Stuck processing - * - * Processing for Beacon Stuck. - * Basically resets the chip. -*/ -void ath_bstuck_process(struct ath_softc *sc) -{ - DPRINTF(sc, ATH_DBG_BEACON, - "%s: stuck beacon; resetting (bmiss count %u)\n", - __func__, sc->sc_bmisscount); - ath_reset(sc, false); -} - /* * Configure the beacon and sleep timers. * @@ -652,15 +618,21 @@ void ath_bstuck_process(struct ath_softc *sc) */ void ath_beacon_config(struct ath_softc *sc, int if_id) { + struct ieee80211_vif *vif; struct ath_hal *ah = sc->sc_ah; struct ath_beacon_config conf; - enum ath9k_opmode av_opmode; + struct ath_vap *avp; + enum nl80211_iftype opmode; u32 nexttbtt, intval; - if (if_id != ATH_IF_ID_ANY) - av_opmode = sc->sc_vaps[if_id]->av_opmode; - else - av_opmode = sc->sc_ah->ah_opmode; + if (if_id != ATH_IF_ID_ANY) { + vif = sc->sc_vaps[if_id]; + ASSERT(vif); + avp = (void *)vif->drv_priv; + opmode = avp->av_opmode; + } else { + opmode = sc->sc_ah->ah_opmode; + } memset(&conf, 0, sizeof(struct ath_beacon_config)); @@ -672,10 +644,10 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) conf.bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf.beacon_interval; /* extract tstamp from last beacon and convert to TU */ - nexttbtt = TSF_TO_TU(sc->bc_tstamp >> 32, sc->bc_tstamp); + nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp); /* XXX conditionalize multi-bss support? */ - if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) { + if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) { /* * For multi-bss ap support beacons are either staggered * evenly over N slots or burst together. For the former @@ -694,11 +666,11 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) else if (intval) /* NB: can be 0 for monitor mode */ nexttbtt = roundup(nexttbtt, intval); - DPRINTF(sc, ATH_DBG_BEACON, "%s: nexttbtt %u intval %u (%u)\n", - __func__, nexttbtt, intval, conf.beacon_interval); + DPRINTF(sc, ATH_DBG_BEACON, "nexttbtt %u intval %u (%u)\n", + nexttbtt, intval, conf.beacon_interval); - /* Check for ATH9K_M_HOSTAP and sc_nostabeacons for WDS client */ - if (sc->sc_ah->ah_opmode == ATH9K_M_STA) { + /* Check for NL80211_IFTYPE_AP and sc_nostabeacons for WDS client */ + if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION) { struct ath9k_beacon_state bs; u64 tsf; u32 tsftu; @@ -782,7 +754,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) bs.bs_sleepduration = bs.bs_dtimperiod; DPRINTF(sc, ATH_DBG_BEACON, - "%s: tsf %llu " + "tsf %llu " "tsf:tu %u " "intval %u " "nexttbtt %u " @@ -794,7 +766,6 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) "maxdur %u " "next %u " "timoffset %u\n", - __func__, (unsigned long long)tsf, tsftu, bs.bs_intval, bs.bs_nexttbtt, @@ -818,7 +789,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) ath9k_hw_set_interrupts(ah, 0); if (nexttbtt == intval) intval |= ATH9K_BEACON_RESET_TSF; - if (sc->sc_ah->ah_opmode == ATH9K_M_IBSS) { + if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC) { /* * Pull nexttbtt forward to reflect the current * TSF @@ -834,8 +805,8 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) } #undef FUDGE DPRINTF(sc, ATH_DBG_BEACON, - "%s: IBSS nexttbtt %u intval %u (%u)\n", - __func__, nexttbtt, + "IBSS nexttbtt %u intval %u (%u)\n", + nexttbtt, intval & ~ATH9K_BEACON_RESET_TSF, conf.beacon_interval); @@ -850,7 +821,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) if (!(ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) sc->sc_imask |= ATH9K_INT_SWBA; ath_beaconq_config(sc); - } else if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) { + } else if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) { /* * In AP mode we enable the beacon timers and * SWBA interrupts to prepare beacon frames. @@ -860,20 +831,18 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) ath_beaconq_config(sc); } ath9k_hw_beaconinit(ah, nexttbtt, intval); - sc->sc_bmisscount = 0; + sc->beacon.bmisscnt = 0; ath9k_hw_set_interrupts(ah, sc->sc_imask); /* * When using a self-linked beacon descriptor in * ibss mode load it once here. */ - if (sc->sc_ah->ah_opmode == ATH9K_M_IBSS && + if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC && (ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) ath_beacon_start_adhoc(sc, 0); } } -/* Function to collect beacon rssi data and resync beacon if necessary */ - void ath_beacon_sync(struct ath_softc *sc, int if_id) { /* diff --git a/drivers/net/wireless/ath9k/calib.c b/drivers/net/wireless/ath9k/calib.c new file mode 100644 index 0000000000000000000000000000000000000000..3c7454fc51bdf0f24f1c70475352c85443236818 --- /dev/null +++ b/drivers/net/wireless/ath9k/calib.c @@ -0,0 +1,1021 @@ +/* + * Copyright (c) 2008 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "core.h" +#include "hw.h" +#include "reg.h" +#include "phy.h" + +static const int16_t NOISE_FLOOR[] = { -96, -93, -98, -96, -93, -96 }; + +/* We can tune this as we go by monitoring really low values */ +#define ATH9K_NF_TOO_LOW -60 + +/* AR5416 may return very high value (like -31 dBm), in those cases the nf + * is incorrect and we should use the static NF value. Later we can try to + * find out why they are reporting these values */ + +static bool ath9k_hw_nf_in_range(struct ath_hal *ah, s16 nf) +{ + if (nf > ATH9K_NF_TOO_LOW) { + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "noise floor value detected (%d) is " + "lower than what we think is a " + "reasonable value (%d)\n", + nf, ATH9K_NF_TOO_LOW); + return false; + } + return true; +} + +static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer) +{ + int16_t nfval; + int16_t sort[ATH9K_NF_CAL_HIST_MAX]; + int i, j; + + for (i = 0; i < ATH9K_NF_CAL_HIST_MAX; i++) + sort[i] = nfCalBuffer[i]; + + for (i = 0; i < ATH9K_NF_CAL_HIST_MAX - 1; i++) { + for (j = 1; j < ATH9K_NF_CAL_HIST_MAX - i; j++) { + if (sort[j] > sort[j - 1]) { + nfval = sort[j]; + sort[j] = sort[j - 1]; + sort[j - 1] = nfval; + } + } + } + nfval = sort[(ATH9K_NF_CAL_HIST_MAX - 1) >> 1]; + + return nfval; +} + +static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h, + int16_t *nfarray) +{ + int i; + + for (i = 0; i < NUM_NF_READINGS; i++) { + h[i].nfCalBuffer[h[i].currIndex] = nfarray[i]; + + if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX) + h[i].currIndex = 0; + + if (h[i].invalidNFcount > 0) { + if (nfarray[i] < AR_PHY_CCA_MIN_BAD_VALUE || + nfarray[i] > AR_PHY_CCA_MAX_HIGH_VALUE) { + h[i].invalidNFcount = ATH9K_NF_CAL_HIST_MAX; + } else { + h[i].invalidNFcount--; + h[i].privNF = nfarray[i]; + } + } else { + h[i].privNF = + ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer); + } + } + return; +} + +static void ath9k_hw_do_getnf(struct ath_hal *ah, + int16_t nfarray[NUM_NF_READINGS]) +{ + int16_t nf; + + if (AR_SREV_9280_10_OR_LATER(ah)) + nf = MS(REG_READ(ah, AR_PHY_CCA), AR9280_PHY_MINCCA_PWR); + else + nf = MS(REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR); + + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "NF calibrated [ctl] [chain 0] is %d\n", nf); + nfarray[0] = nf; + + if (AR_SREV_9280_10_OR_LATER(ah)) + nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), + AR9280_PHY_CH1_MINCCA_PWR); + else + nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), + AR_PHY_CH1_MINCCA_PWR); + + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "NF calibrated [ctl] [chain 1] is %d\n", nf); + nfarray[1] = nf; + + if (!AR_SREV_9280(ah)) { + nf = MS(REG_READ(ah, AR_PHY_CH2_CCA), + AR_PHY_CH2_MINCCA_PWR); + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "NF calibrated [ctl] [chain 2] is %d\n", nf); + nfarray[2] = nf; + } + + if (AR_SREV_9280_10_OR_LATER(ah)) + nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), + AR9280_PHY_EXT_MINCCA_PWR); + else + nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), + AR_PHY_EXT_MINCCA_PWR); + + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "NF calibrated [ext] [chain 0] is %d\n", nf); + nfarray[3] = nf; + + if (AR_SREV_9280_10_OR_LATER(ah)) + nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), + AR9280_PHY_CH1_EXT_MINCCA_PWR); + else + nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), + AR_PHY_CH1_EXT_MINCCA_PWR); + + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "NF calibrated [ext] [chain 1] is %d\n", nf); + nfarray[4] = nf; + + if (!AR_SREV_9280(ah)) { + nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA), + AR_PHY_CH2_EXT_MINCCA_PWR); + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "NF calibrated [ext] [chain 2] is %d\n", nf); + nfarray[5] = nf; + } +} + +static bool getNoiseFloorThresh(struct ath_hal *ah, + const struct ath9k_channel *chan, + int16_t *nft) +{ + switch (chan->chanmode) { + case CHANNEL_A: + case CHANNEL_A_HT20: + case CHANNEL_A_HT40PLUS: + case CHANNEL_A_HT40MINUS: + *nft = (int8_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_5); + break; + case CHANNEL_B: + case CHANNEL_G: + case CHANNEL_G_HT20: + case CHANNEL_G_HT40PLUS: + case CHANNEL_G_HT40MINUS: + *nft = (int8_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_2); + break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, + "invalid channel flags 0x%x\n", chan->channelFlags); + return false; + } + + return true; +} + +static void ath9k_hw_setup_calibration(struct ath_hal *ah, + struct hal_cal_list *currCal) +{ + REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0), + AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX, + currCal->calData->calCountMax); + + switch (currCal->calData->calType) { + case IQ_MISMATCH_CAL: + REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "starting IQ Mismatch Calibration\n"); + break; + case ADC_GAIN_CAL: + REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "starting ADC Gain Calibration\n"); + break; + case ADC_DC_CAL: + REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "starting ADC DC Calibration\n"); + break; + case ADC_DC_INIT_CAL: + REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "starting Init ADC DC Calibration\n"); + break; + } + + REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0), + AR_PHY_TIMING_CTRL4_DO_CAL); +} + +static void ath9k_hw_reset_calibration(struct ath_hal *ah, + struct hal_cal_list *currCal) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + int i; + + ath9k_hw_setup_calibration(ah, currCal); + + currCal->calState = CAL_RUNNING; + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + ahp->ah_Meas0.sign[i] = 0; + ahp->ah_Meas1.sign[i] = 0; + ahp->ah_Meas2.sign[i] = 0; + ahp->ah_Meas3.sign[i] = 0; + } + + ahp->ah_CalSamples = 0; +} + +static void ath9k_hw_per_calibration(struct ath_hal *ah, + struct ath9k_channel *ichan, + u8 rxchainmask, + struct hal_cal_list *currCal, + bool *isCalDone) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + *isCalDone = false; + + if (currCal->calState == CAL_RUNNING) { + if (!(REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) & + AR_PHY_TIMING_CTRL4_DO_CAL)) { + + currCal->calData->calCollect(ah); + ahp->ah_CalSamples++; + + if (ahp->ah_CalSamples >= currCal->calData->calNumSamples) { + int i, numChains = 0; + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + if (rxchainmask & (1 << i)) + numChains++; + } + + currCal->calData->calPostProc(ah, numChains); + ichan->CalValid |= currCal->calData->calType; + currCal->calState = CAL_DONE; + *isCalDone = true; + } else { + ath9k_hw_setup_calibration(ah, currCal); + } + } + } else if (!(ichan->CalValid & currCal->calData->calType)) { + ath9k_hw_reset_calibration(ah, currCal); + } +} + +static bool ath9k_hw_iscal_supported(struct ath_hal *ah, + struct ath9k_channel *chan, + enum hal_cal_types calType) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + bool retval = false; + + switch (calType & ahp->ah_suppCals) { + case IQ_MISMATCH_CAL: + if (!IS_CHAN_B(chan)) + retval = true; + break; + case ADC_GAIN_CAL: + case ADC_DC_CAL: + if (!IS_CHAN_B(chan) + && !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan))) + retval = true; + break; + } + + return retval; +} + +static void ath9k_hw_iqcal_collect(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + int i; + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + ahp->ah_totalPowerMeasI[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); + ahp->ah_totalPowerMeasQ[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); + ahp->ah_totalIqCorrMeas[i] += + (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", + ahp->ah_CalSamples, i, ahp->ah_totalPowerMeasI[i], + ahp->ah_totalPowerMeasQ[i], + ahp->ah_totalIqCorrMeas[i]); + } +} + +static void ath9k_hw_adc_gaincal_collect(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + int i; + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + ahp->ah_totalAdcIOddPhase[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); + ahp->ah_totalAdcIEvenPhase[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); + ahp->ah_totalAdcQOddPhase[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); + ahp->ah_totalAdcQEvenPhase[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "%d: Chn %d oddi=0x%08x; eveni=0x%08x; " + "oddq=0x%08x; evenq=0x%08x;\n", + ahp->ah_CalSamples, i, + ahp->ah_totalAdcIOddPhase[i], + ahp->ah_totalAdcIEvenPhase[i], + ahp->ah_totalAdcQOddPhase[i], + ahp->ah_totalAdcQEvenPhase[i]); + } +} + +static void ath9k_hw_adc_dccal_collect(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + int i; + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + ahp->ah_totalAdcDcOffsetIOddPhase[i] += + (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); + ahp->ah_totalAdcDcOffsetIEvenPhase[i] += + (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); + ahp->ah_totalAdcDcOffsetQOddPhase[i] += + (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); + ahp->ah_totalAdcDcOffsetQEvenPhase[i] += + (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "%d: Chn %d oddi=0x%08x; eveni=0x%08x; " + "oddq=0x%08x; evenq=0x%08x;\n", + ahp->ah_CalSamples, i, + ahp->ah_totalAdcDcOffsetIOddPhase[i], + ahp->ah_totalAdcDcOffsetIEvenPhase[i], + ahp->ah_totalAdcDcOffsetQOddPhase[i], + ahp->ah_totalAdcDcOffsetQEvenPhase[i]); + } +} + +static void ath9k_hw_iqcalibrate(struct ath_hal *ah, u8 numChains) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + u32 powerMeasQ, powerMeasI, iqCorrMeas; + u32 qCoffDenom, iCoffDenom; + int32_t qCoff, iCoff; + int iqCorrNeg, i; + + for (i = 0; i < numChains; i++) { + powerMeasI = ahp->ah_totalPowerMeasI[i]; + powerMeasQ = ahp->ah_totalPowerMeasQ[i]; + iqCorrMeas = ahp->ah_totalIqCorrMeas[i]; + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Starting IQ Cal and Correction for Chain %d\n", + i); + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Orignal: Chn %diq_corr_meas = 0x%08x\n", + i, ahp->ah_totalIqCorrMeas[i]); + + iqCorrNeg = 0; + + if (iqCorrMeas > 0x80000000) { + iqCorrMeas = (0xffffffff - iqCorrMeas) + 1; + iqCorrNeg = 1; + } + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n", + iqCorrNeg); + + iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128; + qCoffDenom = powerMeasQ / 64; + + if (powerMeasQ != 0) { + iCoff = iqCorrMeas / iCoffDenom; + qCoff = powerMeasI / qCoffDenom - 64; + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d iCoff = 0x%08x\n", i, iCoff); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d qCoff = 0x%08x\n", i, qCoff); + + iCoff = iCoff & 0x3f; + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "New: Chn %d iCoff = 0x%08x\n", i, iCoff); + if (iqCorrNeg == 0x0) + iCoff = 0x40 - iCoff; + + if (qCoff > 15) + qCoff = 15; + else if (qCoff <= -16) + qCoff = 16; + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d : iCoff = 0x%x qCoff = 0x%x\n", + i, iCoff, qCoff); + + REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF, + iCoff); + REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), + AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF, + qCoff); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "IQ Cal and Correction done for Chain %d\n", + i); + } + } + + REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0), + AR_PHY_TIMING_CTRL4_IQCORR_ENABLE); +} + +static void ath9k_hw_adc_gaincal_calibrate(struct ath_hal *ah, u8 numChains) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, qEvenMeasOffset; + u32 qGainMismatch, iGainMismatch, val, i; + + for (i = 0; i < numChains; i++) { + iOddMeasOffset = ahp->ah_totalAdcIOddPhase[i]; + iEvenMeasOffset = ahp->ah_totalAdcIEvenPhase[i]; + qOddMeasOffset = ahp->ah_totalAdcQOddPhase[i]; + qEvenMeasOffset = ahp->ah_totalAdcQEvenPhase[i]; + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Starting ADC Gain Cal for Chain %d\n", i); + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_odd_i = 0x%08x\n", i, + iOddMeasOffset); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_even_i = 0x%08x\n", i, + iEvenMeasOffset); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_odd_q = 0x%08x\n", i, + qOddMeasOffset); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_even_q = 0x%08x\n", i, + qEvenMeasOffset); + + if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) { + iGainMismatch = + ((iEvenMeasOffset * 32) / + iOddMeasOffset) & 0x3f; + qGainMismatch = + ((qOddMeasOffset * 32) / + qEvenMeasOffset) & 0x3f; + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d gain_mismatch_i = 0x%08x\n", i, + iGainMismatch); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d gain_mismatch_q = 0x%08x\n", i, + qGainMismatch); + + val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); + val &= 0xfffff000; + val |= (qGainMismatch) | (iGainMismatch << 6); + REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "ADC Gain Cal done for Chain %d\n", i); + } + } + + REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), + REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) | + AR_PHY_NEW_ADC_GAIN_CORR_ENABLE); +} + +static void ath9k_hw_adc_dccal_calibrate(struct ath_hal *ah, u8 numChains) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + u32 iOddMeasOffset, iEvenMeasOffset, val, i; + int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch; + const struct hal_percal_data *calData = + ahp->ah_cal_list_curr->calData; + u32 numSamples = + (1 << (calData->calCountMax + 5)) * calData->calNumSamples; + + for (i = 0; i < numChains; i++) { + iOddMeasOffset = ahp->ah_totalAdcDcOffsetIOddPhase[i]; + iEvenMeasOffset = ahp->ah_totalAdcDcOffsetIEvenPhase[i]; + qOddMeasOffset = ahp->ah_totalAdcDcOffsetQOddPhase[i]; + qEvenMeasOffset = ahp->ah_totalAdcDcOffsetQEvenPhase[i]; + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Starting ADC DC Offset Cal for Chain %d\n", i); + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_odd_i = %d\n", i, + iOddMeasOffset); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_even_i = %d\n", i, + iEvenMeasOffset); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_odd_q = %d\n", i, + qOddMeasOffset); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_even_q = %d\n", i, + qEvenMeasOffset); + + iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) / + numSamples) & 0x1ff; + qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) / + numSamples) & 0x1ff; + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d dc_offset_mismatch_i = 0x%08x\n", i, + iDcMismatch); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d dc_offset_mismatch_q = 0x%08x\n", i, + qDcMismatch); + + val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); + val &= 0xc0000fff; + val |= (qDcMismatch << 12) | (iDcMismatch << 21); + REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "ADC DC Offset Cal done for Chain %d\n", i); + } + + REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), + REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) | + AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE); +} + +void ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan, + bool *isCalDone) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ath9k_channel *ichan = + ath9k_regd_check_channel(ah, chan); + struct hal_cal_list *currCal = ahp->ah_cal_list_curr; + + *isCalDone = true; + + if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah)) + return; + + if (currCal == NULL) + return; + + if (ichan == NULL) { + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "invalid channel %u/0x%x; no mapping\n", + chan->channel, chan->channelFlags); + return; + } + + + if (currCal->calState != CAL_DONE) { + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Calibration state incorrect, %d\n", + currCal->calState); + return; + } + + + if (!ath9k_hw_iscal_supported(ah, chan, currCal->calData->calType)) + return; + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Resetting Cal %d state for channel %u/0x%x\n", + currCal->calData->calType, chan->channel, + chan->channelFlags); + + ichan->CalValid &= ~currCal->calData->calType; + currCal->calState = CAL_WAITING; + + *isCalDone = false; +} + +void ath9k_hw_start_nfcal(struct ath_hal *ah) +{ + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_ENABLE_NF); + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_NO_UPDATE_NF); + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); +} + +void ath9k_hw_loadnf(struct ath_hal *ah, struct ath9k_channel *chan) +{ + struct ath9k_nfcal_hist *h; + int i, j; + int32_t val; + const u32 ar5416_cca_regs[6] = { + AR_PHY_CCA, + AR_PHY_CH1_CCA, + AR_PHY_CH2_CCA, + AR_PHY_EXT_CCA, + AR_PHY_CH1_EXT_CCA, + AR_PHY_CH2_EXT_CCA + }; + u8 chainmask; + + if (AR_SREV_9280(ah)) + chainmask = 0x1B; + else + chainmask = 0x3F; + +#ifdef ATH_NF_PER_CHAN + h = chan->nfCalHist; +#else + h = ah->nfCalHist; +#endif + + for (i = 0; i < NUM_NF_READINGS; i++) { + if (chainmask & (1 << i)) { + val = REG_READ(ah, ar5416_cca_regs[i]); + val &= 0xFFFFFE00; + val |= (((u32) (h[i].privNF) << 1) & 0x1ff); + REG_WRITE(ah, ar5416_cca_regs[i], val); + } + } + + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_ENABLE_NF); + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_NO_UPDATE_NF); + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); + + for (j = 0; j < 1000; j++) { + if ((REG_READ(ah, AR_PHY_AGC_CONTROL) & + AR_PHY_AGC_CONTROL_NF) == 0) + break; + udelay(10); + } + + for (i = 0; i < NUM_NF_READINGS; i++) { + if (chainmask & (1 << i)) { + val = REG_READ(ah, ar5416_cca_regs[i]); + val &= 0xFFFFFE00; + val |= (((u32) (-50) << 1) & 0x1ff); + REG_WRITE(ah, ar5416_cca_regs[i], val); + } + } +} + +int16_t ath9k_hw_getnf(struct ath_hal *ah, + struct ath9k_channel *chan) +{ + int16_t nf, nfThresh; + int16_t nfarray[NUM_NF_READINGS] = { 0 }; + struct ath9k_nfcal_hist *h; + u8 chainmask; + + if (AR_SREV_9280(ah)) + chainmask = 0x1B; + else + chainmask = 0x3F; + + chan->channelFlags &= (~CHANNEL_CW_INT); + if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) { + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "NF did not complete in calibration window\n"); + nf = 0; + chan->rawNoiseFloor = nf; + return chan->rawNoiseFloor; + } else { + ath9k_hw_do_getnf(ah, nfarray); + nf = nfarray[0]; + if (getNoiseFloorThresh(ah, chan, &nfThresh) + && nf > nfThresh) { + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "noise floor failed detected; " + "detected %d, threshold %d\n", + nf, nfThresh); + chan->channelFlags |= CHANNEL_CW_INT; + } + } + +#ifdef ATH_NF_PER_CHAN + h = chan->nfCalHist; +#else + h = ah->nfCalHist; +#endif + + ath9k_hw_update_nfcal_hist_buffer(h, nfarray); + chan->rawNoiseFloor = h[0].privNF; + + return chan->rawNoiseFloor; +} + +void ath9k_init_nfcal_hist_buffer(struct ath_hal *ah) +{ + int i, j; + + for (i = 0; i < NUM_NF_READINGS; i++) { + ah->nfCalHist[i].currIndex = 0; + ah->nfCalHist[i].privNF = AR_PHY_CCA_MAX_GOOD_VALUE; + ah->nfCalHist[i].invalidNFcount = + AR_PHY_CCA_FILTERWINDOW_LENGTH; + for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) { + ah->nfCalHist[i].nfCalBuffer[j] = + AR_PHY_CCA_MAX_GOOD_VALUE; + } + } + return; +} + +s16 ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan) +{ + struct ath9k_channel *ichan; + s16 nf; + + ichan = ath9k_regd_check_channel(ah, chan); + if (ichan == NULL) { + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "invalid channel %u/0x%x; no mapping\n", + chan->channel, chan->channelFlags); + return ATH_DEFAULT_NOISE_FLOOR; + } + if (ichan->rawNoiseFloor == 0) { + enum wireless_mode mode = ath9k_hw_chan2wmode(ah, chan); + nf = NOISE_FLOOR[mode]; + } else + nf = ichan->rawNoiseFloor; + + if (!ath9k_hw_nf_in_range(ah, nf)) + nf = ATH_DEFAULT_NOISE_FLOOR; + + return nf; +} + +bool ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan, + u8 rxchainmask, bool longcal, + bool *isCalDone) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct hal_cal_list *currCal = ahp->ah_cal_list_curr; + struct ath9k_channel *ichan = ath9k_regd_check_channel(ah, chan); + + *isCalDone = true; + + if (ichan == NULL) { + DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, + "invalid channel %u/0x%x; no mapping\n", + chan->channel, chan->channelFlags); + return false; + } + + if (currCal && + (currCal->calState == CAL_RUNNING || + currCal->calState == CAL_WAITING)) { + ath9k_hw_per_calibration(ah, ichan, rxchainmask, currCal, + isCalDone); + if (*isCalDone) { + ahp->ah_cal_list_curr = currCal = currCal->calNext; + + if (currCal->calState == CAL_WAITING) { + *isCalDone = false; + ath9k_hw_reset_calibration(ah, currCal); + } + } + } + + if (longcal) { + ath9k_hw_getnf(ah, ichan); + ath9k_hw_loadnf(ah, ah->ah_curchan); + ath9k_hw_start_nfcal(ah); + + if ((ichan->channelFlags & CHANNEL_CW_INT) != 0) { + chan->channelFlags |= CHANNEL_CW_INT; + ichan->channelFlags &= ~CHANNEL_CW_INT; + } + } + + return true; +} + +static inline void ath9k_hw_9285_pa_cal(struct ath_hal *ah) +{ + + u32 regVal; + int i, offset, offs_6_1, offs_0; + u32 ccomp_org, reg_field; + u32 regList[][2] = { + { 0x786c, 0 }, + { 0x7854, 0 }, + { 0x7820, 0 }, + { 0x7824, 0 }, + { 0x7868, 0 }, + { 0x783c, 0 }, + { 0x7838, 0 }, + }; + + if (AR_SREV_9285_11(ah)) { + REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); + udelay(10); + } + + for (i = 0; i < ARRAY_SIZE(regList); i++) + regList[i][1] = REG_READ(ah, regList[i][0]); + + regVal = REG_READ(ah, 0x7834); + regVal &= (~(0x1)); + REG_WRITE(ah, 0x7834, regVal); + regVal = REG_READ(ah, 0x9808); + regVal |= (0x1 << 27); + REG_WRITE(ah, 0x9808, regVal); + + REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1); + REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1); + REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1); + REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1); + REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0); + REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0); + REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0); + REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 1); + REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0); + REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0); + REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7); + REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0); + ccomp_org = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_CCOMP); + REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 7); + + REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0); + udelay(30); + REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, 0); + REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 0); + + for (i = 6; i > 0; i--) { + regVal = REG_READ(ah, 0x7834); + regVal |= (1 << (19 + i)); + REG_WRITE(ah, 0x7834, regVal); + udelay(1); + regVal = REG_READ(ah, 0x7834); + regVal &= (~(0x1 << (19 + i))); + reg_field = MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9); + regVal |= (reg_field << (19 + i)); + REG_WRITE(ah, 0x7834, regVal); + } + + REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 1); + udelay(1); + reg_field = MS(REG_READ(ah, AR9285_AN_RF2G9), AR9285_AN_RXTXBB1_SPARE9); + REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, reg_field); + offs_6_1 = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_OFFS); + offs_0 = MS(REG_READ(ah, AR9285_AN_RF2G3), AR9285_AN_RF2G3_PDVCCOMP); + + offset = (offs_6_1<<1) | offs_0; + offset = offset - 0; + offs_6_1 = offset>>1; + offs_0 = offset & 1; + + REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, offs_6_1); + REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, offs_0); + + regVal = REG_READ(ah, 0x7834); + regVal |= 0x1; + REG_WRITE(ah, 0x7834, regVal); + regVal = REG_READ(ah, 0x9808); + regVal &= (~(0x1 << 27)); + REG_WRITE(ah, 0x9808, regVal); + + for (i = 0; i < ARRAY_SIZE(regList); i++) + REG_WRITE(ah, regList[i][0], regList[i][1]); + + REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, ccomp_org); + + if (AR_SREV_9285_11(ah)) + REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT); + +} + +bool ath9k_hw_init_cal(struct ath_hal *ah, + struct ath9k_channel *chan) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ath9k_channel *ichan = ath9k_regd_check_channel(ah, chan); + + REG_WRITE(ah, AR_PHY_AGC_CONTROL, + REG_READ(ah, AR_PHY_AGC_CONTROL) | + AR_PHY_AGC_CONTROL_CAL); + + if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) { + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "offset calibration failed to complete in 1ms; " + "noisy environment?\n"); + return false; + } + + if (AR_SREV_9285(ah) && AR_SREV_9285_11_OR_LATER(ah)) + ath9k_hw_9285_pa_cal(ah); + + REG_WRITE(ah, AR_PHY_AGC_CONTROL, + REG_READ(ah, AR_PHY_AGC_CONTROL) | + AR_PHY_AGC_CONTROL_NF); + + ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = NULL; + + if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) { + if (ath9k_hw_iscal_supported(ah, chan, ADC_GAIN_CAL)) { + INIT_CAL(&ahp->ah_adcGainCalData); + INSERT_CAL(ahp, &ahp->ah_adcGainCalData); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "enabling ADC Gain Calibration.\n"); + } + if (ath9k_hw_iscal_supported(ah, chan, ADC_DC_CAL)) { + INIT_CAL(&ahp->ah_adcDcCalData); + INSERT_CAL(ahp, &ahp->ah_adcDcCalData); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "enabling ADC DC Calibration.\n"); + } + if (ath9k_hw_iscal_supported(ah, chan, IQ_MISMATCH_CAL)) { + INIT_CAL(&ahp->ah_iqCalData); + INSERT_CAL(ahp, &ahp->ah_iqCalData); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "enabling IQ Calibration.\n"); + } + + ahp->ah_cal_list_curr = ahp->ah_cal_list; + + if (ahp->ah_cal_list_curr) + ath9k_hw_reset_calibration(ah, ahp->ah_cal_list_curr); + } + + ichan->CalValid = 0; + + return true; +} + +const struct hal_percal_data iq_cal_multi_sample = { + IQ_MISMATCH_CAL, + MAX_CAL_SAMPLES, + PER_MIN_LOG_COUNT, + ath9k_hw_iqcal_collect, + ath9k_hw_iqcalibrate +}; +const struct hal_percal_data iq_cal_single_sample = { + IQ_MISMATCH_CAL, + MIN_CAL_SAMPLES, + PER_MAX_LOG_COUNT, + ath9k_hw_iqcal_collect, + ath9k_hw_iqcalibrate +}; +const struct hal_percal_data adc_gain_cal_multi_sample = { + ADC_GAIN_CAL, + MAX_CAL_SAMPLES, + PER_MIN_LOG_COUNT, + ath9k_hw_adc_gaincal_collect, + ath9k_hw_adc_gaincal_calibrate +}; +const struct hal_percal_data adc_gain_cal_single_sample = { + ADC_GAIN_CAL, + MIN_CAL_SAMPLES, + PER_MAX_LOG_COUNT, + ath9k_hw_adc_gaincal_collect, + ath9k_hw_adc_gaincal_calibrate +}; +const struct hal_percal_data adc_dc_cal_multi_sample = { + ADC_DC_CAL, + MAX_CAL_SAMPLES, + PER_MIN_LOG_COUNT, + ath9k_hw_adc_dccal_collect, + ath9k_hw_adc_dccal_calibrate +}; +const struct hal_percal_data adc_dc_cal_single_sample = { + ADC_DC_CAL, + MIN_CAL_SAMPLES, + PER_MAX_LOG_COUNT, + ath9k_hw_adc_dccal_collect, + ath9k_hw_adc_dccal_calibrate +}; +const struct hal_percal_data adc_init_dc_cal = { + ADC_DC_INIT_CAL, + MIN_CAL_SAMPLES, + INIT_LOG_COUNT, + ath9k_hw_adc_dccal_collect, + ath9k_hw_adc_dccal_calibrate +}; diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c deleted file mode 100644 index c5033f6f42acd3c6ddf4cf7d00835adf9c9b665e..0000000000000000000000000000000000000000 --- a/drivers/net/wireless/ath9k/core.c +++ /dev/null @@ -1,1886 +0,0 @@ -/* - * Copyright (c) 2008, Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - - /* Implementation of the main "ATH" layer. */ - -#include "core.h" -#include "regd.h" - -static int ath_outdoor; /* enable outdoor use */ - -static u32 ath_chainmask_sel_up_rssi_thres = - ATH_CHAINMASK_SEL_UP_RSSI_THRES; -static u32 ath_chainmask_sel_down_rssi_thres = - ATH_CHAINMASK_SEL_DOWN_RSSI_THRES; -static u32 ath_chainmask_sel_period = - ATH_CHAINMASK_SEL_TIMEOUT; - -/* return bus cachesize in 4B word units */ - -static void bus_read_cachesize(struct ath_softc *sc, int *csz) -{ - u8 u8tmp; - - pci_read_config_byte(sc->pdev, PCI_CACHE_LINE_SIZE, (u8 *)&u8tmp); - *csz = (int)u8tmp; - - /* - * This check was put in to avoid "unplesant" consequences if - * the bootrom has not fully initialized all PCI devices. - * Sometimes the cache line size register is not set - */ - - if (*csz == 0) - *csz = DEFAULT_CACHELINE >> 2; /* Use the default size */ -} - -/* - * Set current operating mode - * - * This function initializes and fills the rate table in the ATH object based - * on the operating mode. -*/ -static void ath_setcurmode(struct ath_softc *sc, enum wireless_mode mode) -{ - const struct ath9k_rate_table *rt; - int i; - - memset(sc->sc_rixmap, 0xff, sizeof(sc->sc_rixmap)); - rt = ath9k_hw_getratetable(sc->sc_ah, mode); - BUG_ON(!rt); - - for (i = 0; i < rt->rateCount; i++) - sc->sc_rixmap[rt->info[i].rateCode] = (u8) i; - - memset(sc->sc_hwmap, 0, sizeof(sc->sc_hwmap)); - for (i = 0; i < 256; i++) { - u8 ix = rt->rateCodeToIndex[i]; - - if (ix == 0xff) - continue; - - sc->sc_hwmap[i].ieeerate = - rt->info[ix].dot11Rate & IEEE80211_RATE_VAL; - sc->sc_hwmap[i].rateKbps = rt->info[ix].rateKbps; - - if (rt->info[ix].shortPreamble || - rt->info[ix].phy == PHY_OFDM) { - /* XXX: Handle this */ - } - - /* NB: this uses the last entry if the rate isn't found */ - /* XXX beware of overlow */ - } - sc->sc_currates = rt; - sc->sc_curmode = mode; - /* - * All protection frames are transmited at 2Mb/s for - * 11g, otherwise at 1Mb/s. - * XXX select protection rate index from rate table. - */ - sc->sc_protrix = (mode == ATH9K_MODE_11G ? 1 : 0); -} - -/* - * Set up rate table (legacy rates) - */ -static void ath_setup_rates(struct ath_softc *sc, enum ieee80211_band band) -{ - struct ath_hal *ah = sc->sc_ah; - const struct ath9k_rate_table *rt = NULL; - struct ieee80211_supported_band *sband; - struct ieee80211_rate *rate; - int i, maxrates; - - switch (band) { - case IEEE80211_BAND_2GHZ: - rt = ath9k_hw_getratetable(ah, ATH9K_MODE_11G); - break; - case IEEE80211_BAND_5GHZ: - rt = ath9k_hw_getratetable(ah, ATH9K_MODE_11A); - break; - default: - break; - } - - if (rt == NULL) - return; - - sband = &sc->sbands[band]; - rate = sc->rates[band]; - - if (rt->rateCount > ATH_RATE_MAX) - maxrates = ATH_RATE_MAX; - else - maxrates = rt->rateCount; - - for (i = 0; i < maxrates; i++) { - rate[i].bitrate = rt->info[i].rateKbps / 100; - rate[i].hw_value = rt->info[i].rateCode; - sband->n_bitrates++; - DPRINTF(sc, ATH_DBG_CONFIG, - "%s: Rate: %2dMbps, ratecode: %2d\n", - __func__, - rate[i].bitrate / 10, - rate[i].hw_value); - } -} - -/* - * Set up channel list - */ -static int ath_setup_channels(struct ath_softc *sc) -{ - struct ath_hal *ah = sc->sc_ah; - int nchan, i, a = 0, b = 0; - u8 regclassids[ATH_REGCLASSIDS_MAX]; - u32 nregclass = 0; - struct ieee80211_supported_band *band_2ghz; - struct ieee80211_supported_band *band_5ghz; - struct ieee80211_channel *chan_2ghz; - struct ieee80211_channel *chan_5ghz; - struct ath9k_channel *c; - - /* Fill in ah->ah_channels */ - if (!ath9k_regd_init_channels(ah, - ATH_CHAN_MAX, - (u32 *)&nchan, - regclassids, - ATH_REGCLASSIDS_MAX, - &nregclass, - CTRY_DEFAULT, - false, - 1)) { - u32 rd = ah->ah_currentRD; - - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to collect channel list; " - "regdomain likely %u country code %u\n", - __func__, rd, CTRY_DEFAULT); - return -EINVAL; - } - - band_2ghz = &sc->sbands[IEEE80211_BAND_2GHZ]; - band_5ghz = &sc->sbands[IEEE80211_BAND_5GHZ]; - chan_2ghz = sc->channels[IEEE80211_BAND_2GHZ]; - chan_5ghz = sc->channels[IEEE80211_BAND_5GHZ]; - - for (i = 0; i < nchan; i++) { - c = &ah->ah_channels[i]; - if (IS_CHAN_2GHZ(c)) { - chan_2ghz[a].band = IEEE80211_BAND_2GHZ; - chan_2ghz[a].center_freq = c->channel; - chan_2ghz[a].max_power = c->maxTxPower; - - if (c->privFlags & CHANNEL_DISALLOW_ADHOC) - chan_2ghz[a].flags |= - IEEE80211_CHAN_NO_IBSS; - if (c->channelFlags & CHANNEL_PASSIVE) - chan_2ghz[a].flags |= - IEEE80211_CHAN_PASSIVE_SCAN; - - band_2ghz->n_channels = ++a; - - DPRINTF(sc, ATH_DBG_CONFIG, - "%s: 2MHz channel: %d, " - "channelFlags: 0x%x\n", - __func__, - c->channel, - c->channelFlags); - } else if (IS_CHAN_5GHZ(c)) { - chan_5ghz[b].band = IEEE80211_BAND_5GHZ; - chan_5ghz[b].center_freq = c->channel; - chan_5ghz[b].max_power = c->maxTxPower; - - if (c->privFlags & CHANNEL_DISALLOW_ADHOC) - chan_5ghz[b].flags |= - IEEE80211_CHAN_NO_IBSS; - if (c->channelFlags & CHANNEL_PASSIVE) - chan_5ghz[b].flags |= - IEEE80211_CHAN_PASSIVE_SCAN; - - band_5ghz->n_channels = ++b; - - DPRINTF(sc, ATH_DBG_CONFIG, - "%s: 5MHz channel: %d, " - "channelFlags: 0x%x\n", - __func__, - c->channel, - c->channelFlags); - } - } - - return 0; -} - -/* - * Determine mode from channel flags - * - * This routine will provide the enumerated WIRELESSS_MODE value based - * on the settings of the channel flags. If no valid set of flags - * exist, the lowest mode (11b) is selected. -*/ - -static enum wireless_mode ath_chan2mode(struct ath9k_channel *chan) -{ - if (chan->chanmode == CHANNEL_A) - return ATH9K_MODE_11A; - else if (chan->chanmode == CHANNEL_G) - return ATH9K_MODE_11G; - else if (chan->chanmode == CHANNEL_B) - return ATH9K_MODE_11B; - else if (chan->chanmode == CHANNEL_A_HT20) - return ATH9K_MODE_11NA_HT20; - else if (chan->chanmode == CHANNEL_G_HT20) - return ATH9K_MODE_11NG_HT20; - else if (chan->chanmode == CHANNEL_A_HT40PLUS) - return ATH9K_MODE_11NA_HT40PLUS; - else if (chan->chanmode == CHANNEL_A_HT40MINUS) - return ATH9K_MODE_11NA_HT40MINUS; - else if (chan->chanmode == CHANNEL_G_HT40PLUS) - return ATH9K_MODE_11NG_HT40PLUS; - else if (chan->chanmode == CHANNEL_G_HT40MINUS) - return ATH9K_MODE_11NG_HT40MINUS; - - WARN_ON(1); /* should not get here */ - - return ATH9K_MODE_11B; -} - -/* - * Stop the device, grabbing the top-level lock to protect - * against concurrent entry through ath_init (which can happen - * if another thread does a system call and the thread doing the - * stop is preempted). - */ - -static int ath_stop(struct ath_softc *sc) -{ - struct ath_hal *ah = sc->sc_ah; - - DPRINTF(sc, ATH_DBG_CONFIG, "%s: invalid %ld\n", - __func__, sc->sc_flags & SC_OP_INVALID); - - /* - * Shutdown the hardware and driver: - * stop output from above - * turn off timers - * disable interrupts - * clear transmit machinery - * clear receive machinery - * turn off the radio - * reclaim beacon resources - * - * Note that some of this work is not possible if the - * hardware is gone (invalid). - */ - - ath_draintxq(sc, false); - if (!(sc->sc_flags & SC_OP_INVALID)) { - ath_stoprecv(sc); - ath9k_hw_phy_disable(ah); - } else - sc->sc_rxlink = NULL; - - return 0; -} - -/* - * Set the current channel - * - * Set/change channels. If the channel is really being changed, it's done - * by reseting the chip. To accomplish this we must first cleanup any pending - * DMA, then restart stuff after a la ath_init. -*/ -int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) -{ - struct ath_hal *ah = sc->sc_ah; - bool fastcc = true, stopped; - - if (sc->sc_flags & SC_OP_INVALID) /* the device is invalid or removed */ - return -EIO; - - DPRINTF(sc, ATH_DBG_CONFIG, - "%s: %u (%u MHz) -> %u (%u MHz), cflags:%x\n", - __func__, - ath9k_hw_mhz2ieee(ah, sc->sc_ah->ah_curchan->channel, - sc->sc_ah->ah_curchan->channelFlags), - sc->sc_ah->ah_curchan->channel, - ath9k_hw_mhz2ieee(ah, hchan->channel, hchan->channelFlags), - hchan->channel, hchan->channelFlags); - - if (hchan->channel != sc->sc_ah->ah_curchan->channel || - hchan->channelFlags != sc->sc_ah->ah_curchan->channelFlags || - (sc->sc_flags & SC_OP_CHAINMASK_UPDATE) || - (sc->sc_flags & SC_OP_FULL_RESET)) { - int status; - /* - * This is only performed if the channel settings have - * actually changed. - * - * To switch channels clear any pending DMA operations; - * wait long enough for the RX fifo to drain, reset the - * hardware at the new frequency, and then re-enable - * the relevant bits of the h/w. - */ - ath9k_hw_set_interrupts(ah, 0); /* disable interrupts */ - ath_draintxq(sc, false); /* clear pending tx frames */ - stopped = ath_stoprecv(sc); /* turn off frame recv */ - - /* XXX: do not flush receive queue here. We don't want - * to flush data frames already in queue because of - * changing channel. */ - - if (!stopped || (sc->sc_flags & SC_OP_FULL_RESET)) - fastcc = false; - - spin_lock_bh(&sc->sc_resetlock); - if (!ath9k_hw_reset(ah, hchan, - sc->sc_ht_info.tx_chan_width, - sc->sc_tx_chainmask, - sc->sc_rx_chainmask, - sc->sc_ht_extprotspacing, - fastcc, &status)) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to reset channel %u (%uMhz) " - "flags 0x%x hal status %u\n", __func__, - ath9k_hw_mhz2ieee(ah, hchan->channel, - hchan->channelFlags), - hchan->channel, hchan->channelFlags, status); - spin_unlock_bh(&sc->sc_resetlock); - return -EIO; - } - spin_unlock_bh(&sc->sc_resetlock); - - sc->sc_flags &= ~SC_OP_CHAINMASK_UPDATE; - sc->sc_flags &= ~SC_OP_FULL_RESET; - - /* Re-enable rx framework */ - if (ath_startrecv(sc) != 0) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to restart recv logic\n", __func__); - return -EIO; - } - /* - * Change channels and update the h/w rate map - * if we're switching; e.g. 11a to 11b/g. - */ - ath_setcurmode(sc, ath_chan2mode(hchan)); - - ath_update_txpow(sc); /* update tx power state */ - /* - * Re-enable interrupts. - */ - ath9k_hw_set_interrupts(ah, sc->sc_imask); - } - return 0; -} - -/**********************/ -/* Chainmask Handling */ -/**********************/ - -static void ath_chainmask_sel_timertimeout(unsigned long data) -{ - struct ath_chainmask_sel *cm = (struct ath_chainmask_sel *)data; - cm->switch_allowed = 1; -} - -/* Start chainmask select timer */ -static void ath_chainmask_sel_timerstart(struct ath_chainmask_sel *cm) -{ - cm->switch_allowed = 0; - mod_timer(&cm->timer, ath_chainmask_sel_period); -} - -/* Stop chainmask select timer */ -static void ath_chainmask_sel_timerstop(struct ath_chainmask_sel *cm) -{ - cm->switch_allowed = 0; - del_timer_sync(&cm->timer); -} - -static void ath_chainmask_sel_init(struct ath_softc *sc, struct ath_node *an) -{ - struct ath_chainmask_sel *cm = &an->an_chainmask_sel; - - memset(cm, 0, sizeof(struct ath_chainmask_sel)); - - cm->cur_tx_mask = sc->sc_tx_chainmask; - cm->cur_rx_mask = sc->sc_rx_chainmask; - cm->tx_avgrssi = ATH_RSSI_DUMMY_MARKER; - setup_timer(&cm->timer, - ath_chainmask_sel_timertimeout, (unsigned long) cm); -} - -int ath_chainmask_sel_logic(struct ath_softc *sc, struct ath_node *an) -{ - struct ath_chainmask_sel *cm = &an->an_chainmask_sel; - - /* - * Disable auto-swtiching in one of the following if conditions. - * sc_chainmask_auto_sel is used for internal global auto-switching - * enabled/disabled setting - */ - if (sc->sc_ah->ah_caps.tx_chainmask != ATH_CHAINMASK_SEL_3X3) { - cm->cur_tx_mask = sc->sc_tx_chainmask; - return cm->cur_tx_mask; - } - - if (cm->tx_avgrssi == ATH_RSSI_DUMMY_MARKER) - return cm->cur_tx_mask; - - if (cm->switch_allowed) { - /* Switch down from tx 3 to tx 2. */ - if (cm->cur_tx_mask == ATH_CHAINMASK_SEL_3X3 && - ATH_RSSI_OUT(cm->tx_avgrssi) >= - ath_chainmask_sel_down_rssi_thres) { - cm->cur_tx_mask = sc->sc_tx_chainmask; - - /* Don't let another switch happen until - * this timer expires */ - ath_chainmask_sel_timerstart(cm); - } - /* Switch up from tx 2 to 3. */ - else if (cm->cur_tx_mask == sc->sc_tx_chainmask && - ATH_RSSI_OUT(cm->tx_avgrssi) <= - ath_chainmask_sel_up_rssi_thres) { - cm->cur_tx_mask = ATH_CHAINMASK_SEL_3X3; - - /* Don't let another switch happen - * until this timer expires */ - ath_chainmask_sel_timerstart(cm); - } - } - - return cm->cur_tx_mask; -} - -/* - * Update tx/rx chainmask. For legacy association, - * hard code chainmask to 1x1, for 11n association, use - * the chainmask configuration. - */ - -void ath_update_chainmask(struct ath_softc *sc, int is_ht) -{ - sc->sc_flags |= SC_OP_CHAINMASK_UPDATE; - if (is_ht) { - sc->sc_tx_chainmask = sc->sc_ah->ah_caps.tx_chainmask; - sc->sc_rx_chainmask = sc->sc_ah->ah_caps.rx_chainmask; - } else { - sc->sc_tx_chainmask = 1; - sc->sc_rx_chainmask = 1; - } - - DPRINTF(sc, ATH_DBG_CONFIG, "%s: tx chmask: %d, rx chmask: %d\n", - __func__, sc->sc_tx_chainmask, sc->sc_rx_chainmask); -} - -/*******/ -/* ANI */ -/*******/ - -/* - * This routine performs the periodic noise floor calibration function - * that is used to adjust and optimize the chip performance. This - * takes environmental changes (location, temperature) into account. - * When the task is complete, it reschedules itself depending on the - * appropriate interval that was calculated. - */ - -static void ath_ani_calibrate(unsigned long data) -{ - struct ath_softc *sc; - struct ath_hal *ah; - bool longcal = false; - bool shortcal = false; - bool aniflag = false; - unsigned int timestamp = jiffies_to_msecs(jiffies); - u32 cal_interval; - - sc = (struct ath_softc *)data; - ah = sc->sc_ah; - - /* - * don't calibrate when we're scanning. - * we are most likely not on our home channel. - */ - if (sc->rx_filter & FIF_BCN_PRBRESP_PROMISC) - return; - - /* Long calibration runs independently of short calibration. */ - if ((timestamp - sc->sc_ani.sc_longcal_timer) >= ATH_LONG_CALINTERVAL) { - longcal = true; - DPRINTF(sc, ATH_DBG_ANI, "%s: longcal @%lu\n", - __func__, jiffies); - sc->sc_ani.sc_longcal_timer = timestamp; - } - - /* Short calibration applies only while sc_caldone is false */ - if (!sc->sc_ani.sc_caldone) { - if ((timestamp - sc->sc_ani.sc_shortcal_timer) >= - ATH_SHORT_CALINTERVAL) { - shortcal = true; - DPRINTF(sc, ATH_DBG_ANI, "%s: shortcal @%lu\n", - __func__, jiffies); - sc->sc_ani.sc_shortcal_timer = timestamp; - sc->sc_ani.sc_resetcal_timer = timestamp; - } - } else { - if ((timestamp - sc->sc_ani.sc_resetcal_timer) >= - ATH_RESTART_CALINTERVAL) { - ath9k_hw_reset_calvalid(ah, ah->ah_curchan, - &sc->sc_ani.sc_caldone); - if (sc->sc_ani.sc_caldone) - sc->sc_ani.sc_resetcal_timer = timestamp; - } - } - - /* Verify whether we must check ANI */ - if ((timestamp - sc->sc_ani.sc_checkani_timer) >= - ATH_ANI_POLLINTERVAL) { - aniflag = true; - sc->sc_ani.sc_checkani_timer = timestamp; - } - - /* Skip all processing if there's nothing to do. */ - if (longcal || shortcal || aniflag) { - /* Call ANI routine if necessary */ - if (aniflag) - ath9k_hw_ani_monitor(ah, &sc->sc_halstats, - ah->ah_curchan); - - /* Perform calibration if necessary */ - if (longcal || shortcal) { - bool iscaldone = false; - - if (ath9k_hw_calibrate(ah, ah->ah_curchan, - sc->sc_rx_chainmask, longcal, - &iscaldone)) { - if (longcal) - sc->sc_ani.sc_noise_floor = - ath9k_hw_getchan_noise(ah, - ah->ah_curchan); - - DPRINTF(sc, ATH_DBG_ANI, - "%s: calibrate chan %u/%x nf: %d\n", - __func__, - ah->ah_curchan->channel, - ah->ah_curchan->channelFlags, - sc->sc_ani.sc_noise_floor); - } else { - DPRINTF(sc, ATH_DBG_ANY, - "%s: calibrate chan %u/%x failed\n", - __func__, - ah->ah_curchan->channel, - ah->ah_curchan->channelFlags); - } - sc->sc_ani.sc_caldone = iscaldone; - } - } - - /* - * Set timer interval based on previous results. - * The interval must be the shortest necessary to satisfy ANI, - * short calibration and long calibration. - */ - - cal_interval = ATH_ANI_POLLINTERVAL; - if (!sc->sc_ani.sc_caldone) - cal_interval = min(cal_interval, (u32)ATH_SHORT_CALINTERVAL); - - mod_timer(&sc->sc_ani.timer, jiffies + msecs_to_jiffies(cal_interval)); -} - -/******************/ -/* VAP management */ -/******************/ - -int ath_vap_attach(struct ath_softc *sc, - int if_id, - struct ieee80211_vif *if_data, - enum ath9k_opmode opmode) -{ - struct ath_vap *avp; - - if (if_id >= ATH_BCBUF || sc->sc_vaps[if_id] != NULL) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Invalid interface id = %u\n", __func__, if_id); - return -EINVAL; - } - - switch (opmode) { - case ATH9K_M_STA: - case ATH9K_M_IBSS: - case ATH9K_M_MONITOR: - break; - case ATH9K_M_HOSTAP: - /* XXX not right, beacon buffer is allocated on RUN trans */ - if (list_empty(&sc->sc_bbuf)) - return -ENOMEM; - break; - default: - return -EINVAL; - } - - /* create ath_vap */ - avp = kmalloc(sizeof(struct ath_vap), GFP_KERNEL); - if (avp == NULL) - return -ENOMEM; - - memset(avp, 0, sizeof(struct ath_vap)); - avp->av_if_data = if_data; - /* Set the VAP opmode */ - avp->av_opmode = opmode; - avp->av_bslot = -1; - - if (opmode == ATH9K_M_HOSTAP) - ath9k_hw_set_tsfadjust(sc->sc_ah, 1); - - sc->sc_vaps[if_id] = avp; - sc->sc_nvaps++; - /* Set the device opmode */ - sc->sc_ah->ah_opmode = opmode; - - /* default VAP configuration */ - avp->av_config.av_fixed_rateset = IEEE80211_FIXED_RATE_NONE; - avp->av_config.av_fixed_retryset = 0x03030303; - - return 0; -} - -int ath_vap_detach(struct ath_softc *sc, int if_id) -{ - struct ath_hal *ah = sc->sc_ah; - struct ath_vap *avp; - - avp = sc->sc_vaps[if_id]; - if (avp == NULL) { - DPRINTF(sc, ATH_DBG_FATAL, "%s: invalid interface id %u\n", - __func__, if_id); - return -EINVAL; - } - - /* - * Quiesce the hardware while we remove the vap. In - * particular we need to reclaim all references to the - * vap state by any frames pending on the tx queues. - * - * XXX can we do this w/o affecting other vap's? - */ - ath9k_hw_set_interrupts(ah, 0); /* disable interrupts */ - ath_draintxq(sc, false); /* stop xmit side */ - ath_stoprecv(sc); /* stop recv side */ - ath_flushrecv(sc); /* flush recv queue */ - - kfree(avp); - sc->sc_vaps[if_id] = NULL; - sc->sc_nvaps--; - - return 0; -} - -int ath_vap_config(struct ath_softc *sc, - int if_id, struct ath_vap_config *if_config) -{ - struct ath_vap *avp; - - if (if_id >= ATH_BCBUF) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Invalid interface id = %u\n", __func__, if_id); - return -EINVAL; - } - - avp = sc->sc_vaps[if_id]; - ASSERT(avp != NULL); - - if (avp) - memcpy(&avp->av_config, if_config, sizeof(avp->av_config)); - - return 0; -} - -/********/ -/* Core */ -/********/ - -int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) -{ - struct ath_hal *ah = sc->sc_ah; - int status; - int error = 0; - - DPRINTF(sc, ATH_DBG_CONFIG, "%s: mode %d\n", - __func__, sc->sc_ah->ah_opmode); - - /* - * Stop anything previously setup. This is safe - * whether this is the first time through or not. - */ - ath_stop(sc); - - /* Initialize chanmask selection */ - sc->sc_tx_chainmask = ah->ah_caps.tx_chainmask; - sc->sc_rx_chainmask = ah->ah_caps.rx_chainmask; - - /* Reset SERDES registers */ - ath9k_hw_configpcipowersave(ah, 0); - - /* - * The basic interface to setting the hardware in a good - * state is ``reset''. On return the hardware is known to - * be powered up and with interrupts disabled. This must - * be followed by initialization of the appropriate bits - * and then setup of the interrupt mask. - */ - - spin_lock_bh(&sc->sc_resetlock); - if (!ath9k_hw_reset(ah, initial_chan, - sc->sc_ht_info.tx_chan_width, - sc->sc_tx_chainmask, sc->sc_rx_chainmask, - sc->sc_ht_extprotspacing, false, &status)) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to reset hardware; hal status %u " - "(freq %u flags 0x%x)\n", __func__, status, - initial_chan->channel, initial_chan->channelFlags); - error = -EIO; - spin_unlock_bh(&sc->sc_resetlock); - goto done; - } - spin_unlock_bh(&sc->sc_resetlock); - /* - * This is needed only to setup initial state - * but it's best done after a reset. - */ - ath_update_txpow(sc); - - /* - * Setup the hardware after reset: - * The receive engine is set going. - * Frame transmit is handled entirely - * in the frame output path; there's nothing to do - * here except setup the interrupt mask. - */ - if (ath_startrecv(sc) != 0) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to start recv logic\n", __func__); - error = -EIO; - goto done; - } - /* Setup our intr mask. */ - sc->sc_imask = ATH9K_INT_RX | ATH9K_INT_TX - | ATH9K_INT_RXEOL | ATH9K_INT_RXORN - | ATH9K_INT_FATAL | ATH9K_INT_GLOBAL; - - if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_GTT) - sc->sc_imask |= ATH9K_INT_GTT; - - if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) - sc->sc_imask |= ATH9K_INT_CST; - - /* - * Enable MIB interrupts when there are hardware phy counters. - * Note we only do this (at the moment) for station mode. - */ - if (ath9k_hw_phycounters(ah) && - ((sc->sc_ah->ah_opmode == ATH9K_M_STA) || - (sc->sc_ah->ah_opmode == ATH9K_M_IBSS))) - sc->sc_imask |= ATH9K_INT_MIB; - /* - * Some hardware processes the TIM IE and fires an - * interrupt when the TIM bit is set. For hardware - * that does, if not overridden by configuration, - * enable the TIM interrupt when operating as station. - */ - if ((ah->ah_caps.hw_caps & ATH9K_HW_CAP_ENHANCEDPM) && - (sc->sc_ah->ah_opmode == ATH9K_M_STA) && - !sc->sc_config.swBeaconProcess) - sc->sc_imask |= ATH9K_INT_TIM; - /* - * Don't enable interrupts here as we've not yet built our - * vap and node data structures, which will be needed as soon - * as we start receiving. - */ - ath_setcurmode(sc, ath_chan2mode(initial_chan)); - - /* XXX: we must make sure h/w is ready and clear invalid flag - * before turning on interrupt. */ - sc->sc_flags &= ~SC_OP_INVALID; -done: - return error; -} - -int ath_reset(struct ath_softc *sc, bool retry_tx) -{ - struct ath_hal *ah = sc->sc_ah; - int status; - int error = 0; - - ath9k_hw_set_interrupts(ah, 0); /* disable interrupts */ - ath_draintxq(sc, retry_tx); /* stop xmit */ - ath_stoprecv(sc); /* stop recv */ - ath_flushrecv(sc); /* flush recv queue */ - - /* Reset chip */ - spin_lock_bh(&sc->sc_resetlock); - if (!ath9k_hw_reset(ah, sc->sc_ah->ah_curchan, - sc->sc_ht_info.tx_chan_width, - sc->sc_tx_chainmask, sc->sc_rx_chainmask, - sc->sc_ht_extprotspacing, false, &status)) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to reset hardware; hal status %u\n", - __func__, status); - error = -EIO; - } - spin_unlock_bh(&sc->sc_resetlock); - - if (ath_startrecv(sc) != 0) /* restart recv */ - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to start recv logic\n", __func__); - - /* - * We may be doing a reset in response to a request - * that changes the channel so update any state that - * might change as a result. - */ - ath_setcurmode(sc, ath_chan2mode(sc->sc_ah->ah_curchan)); - - ath_update_txpow(sc); - - if (sc->sc_flags & SC_OP_BEACONS) - ath_beacon_config(sc, ATH_IF_ID_ANY); /* restart beacons */ - - ath9k_hw_set_interrupts(ah, sc->sc_imask); - - /* Restart the txq */ - if (retry_tx) { - int i; - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { - if (ATH_TXQ_SETUP(sc, i)) { - spin_lock_bh(&sc->sc_txq[i].axq_lock); - ath_txq_schedule(sc, &sc->sc_txq[i]); - spin_unlock_bh(&sc->sc_txq[i].axq_lock); - } - } - } - - return error; -} - -int ath_suspend(struct ath_softc *sc) -{ - struct ath_hal *ah = sc->sc_ah; - - /* No I/O if device has been surprise removed */ - if (sc->sc_flags & SC_OP_INVALID) - return -EIO; - - /* Shut off the interrupt before setting sc->sc_invalid to '1' */ - ath9k_hw_set_interrupts(ah, 0); - - /* XXX: we must make sure h/w will not generate any interrupt - * before setting the invalid flag. */ - sc->sc_flags |= SC_OP_INVALID; - - /* disable HAL and put h/w to sleep */ - ath9k_hw_disable(sc->sc_ah); - - ath9k_hw_configpcipowersave(sc->sc_ah, 1); - - return 0; -} - -/* Interrupt handler. Most of the actual processing is deferred. - * It's the caller's responsibility to ensure the chip is awake. */ - -irqreturn_t ath_isr(int irq, void *dev) -{ - struct ath_softc *sc = dev; - struct ath_hal *ah = sc->sc_ah; - enum ath9k_int status; - bool sched = false; - - do { - if (sc->sc_flags & SC_OP_INVALID) { - /* - * The hardware is not ready/present, don't - * touch anything. Note this can happen early - * on if the IRQ is shared. - */ - return IRQ_NONE; - } - if (!ath9k_hw_intrpend(ah)) { /* shared irq, not for us */ - return IRQ_NONE; - } - - /* - * Figure out the reason(s) for the interrupt. Note - * that the hal returns a pseudo-ISR that may include - * bits we haven't explicitly enabled so we mask the - * value to insure we only process bits we requested. - */ - ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */ - - status &= sc->sc_imask; /* discard unasked-for bits */ - - /* - * If there are no status bits set, then this interrupt was not - * for me (should have been caught above). - */ - - if (!status) - return IRQ_NONE; - - sc->sc_intrstatus = status; - - if (status & ATH9K_INT_FATAL) { - /* need a chip reset */ - sched = true; - } else if (status & ATH9K_INT_RXORN) { - /* need a chip reset */ - sched = true; - } else { - if (status & ATH9K_INT_SWBA) { - /* schedule a tasklet for beacon handling */ - tasklet_schedule(&sc->bcon_tasklet); - } - if (status & ATH9K_INT_RXEOL) { - /* - * NB: the hardware should re-read the link when - * RXE bit is written, but it doesn't work - * at least on older hardware revs. - */ - sched = true; - } - - if (status & ATH9K_INT_TXURN) - /* bump tx trigger level */ - ath9k_hw_updatetxtriglevel(ah, true); - /* XXX: optimize this */ - if (status & ATH9K_INT_RX) - sched = true; - if (status & ATH9K_INT_TX) - sched = true; - if (status & ATH9K_INT_BMISS) - sched = true; - /* carrier sense timeout */ - if (status & ATH9K_INT_CST) - sched = true; - if (status & ATH9K_INT_MIB) { - /* - * Disable interrupts until we service the MIB - * interrupt; otherwise it will continue to - * fire. - */ - ath9k_hw_set_interrupts(ah, 0); - /* - * Let the hal handle the event. We assume - * it will clear whatever condition caused - * the interrupt. - */ - ath9k_hw_procmibevent(ah, &sc->sc_halstats); - ath9k_hw_set_interrupts(ah, sc->sc_imask); - } - if (status & ATH9K_INT_TIM_TIMER) { - if (!(ah->ah_caps.hw_caps & - ATH9K_HW_CAP_AUTOSLEEP)) { - /* Clear RxAbort bit so that we can - * receive frames */ - ath9k_hw_setrxabort(ah, 0); - sched = true; - } - } - } - } while (0); - - if (sched) { - /* turn off every interrupt except SWBA */ - ath9k_hw_set_interrupts(ah, (sc->sc_imask & ATH9K_INT_SWBA)); - tasklet_schedule(&sc->intr_tq); - } - - return IRQ_HANDLED; -} - -/* Deferred interrupt processing */ - -static void ath9k_tasklet(unsigned long data) -{ - struct ath_softc *sc = (struct ath_softc *)data; - u32 status = sc->sc_intrstatus; - - if (status & ATH9K_INT_FATAL) { - /* need a chip reset */ - ath_reset(sc, false); - return; - } else { - - if (status & - (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN)) { - /* XXX: fill me in */ - /* - if (status & ATH9K_INT_RXORN) { - } - if (status & ATH9K_INT_RXEOL) { - } - */ - spin_lock_bh(&sc->sc_rxflushlock); - ath_rx_tasklet(sc, 0); - spin_unlock_bh(&sc->sc_rxflushlock); - } - /* XXX: optimize this */ - if (status & ATH9K_INT_TX) - ath_tx_tasklet(sc); - /* XXX: fill me in */ - /* - if (status & ATH9K_INT_BMISS) { - } - if (status & (ATH9K_INT_TIM | ATH9K_INT_DTIMSYNC)) { - if (status & ATH9K_INT_TIM) { - } - if (status & ATH9K_INT_DTIMSYNC) { - } - } - */ - } - - /* re-enable hardware interrupt */ - ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask); -} - -int ath_init(u16 devid, struct ath_softc *sc) -{ - struct ath_hal *ah = NULL; - int status; - int error = 0, i; - int csz = 0; - - /* XXX: hardware will not be ready until ath_open() being called */ - sc->sc_flags |= SC_OP_INVALID; - - sc->sc_debug = DBG_DEFAULT; - DPRINTF(sc, ATH_DBG_CONFIG, "%s: devid 0x%x\n", __func__, devid); - - /* Initialize tasklet */ - tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); - tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet, - (unsigned long)sc); - - /* - * Cache line size is used to size and align various - * structures used to communicate with the hardware. - */ - bus_read_cachesize(sc, &csz); - /* XXX assert csz is non-zero */ - sc->sc_cachelsz = csz << 2; /* convert to bytes */ - - spin_lock_init(&sc->sc_resetlock); - - ah = ath9k_hw_attach(devid, sc, sc->mem, &status); - if (ah == NULL) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to attach hardware; HAL status %u\n", - __func__, status); - error = -ENXIO; - goto bad; - } - sc->sc_ah = ah; - - /* Initializes the noise floor to a reasonable default value. - * Later on this will be updated during ANI processing. */ - sc->sc_ani.sc_noise_floor = ATH_DEFAULT_NOISE_FLOOR; - - /* Get the hardware key cache size. */ - sc->sc_keymax = ah->ah_caps.keycache_size; - if (sc->sc_keymax > ATH_KEYMAX) { - DPRINTF(sc, ATH_DBG_KEYCACHE, - "%s: Warning, using only %u entries in %u key cache\n", - __func__, ATH_KEYMAX, sc->sc_keymax); - sc->sc_keymax = ATH_KEYMAX; - } - - /* - * Reset the key cache since some parts do not - * reset the contents on initial power up. - */ - for (i = 0; i < sc->sc_keymax; i++) - ath9k_hw_keyreset(ah, (u16) i); - /* - * Mark key cache slots associated with global keys - * as in use. If we knew TKIP was not to be used we - * could leave the +32, +64, and +32+64 slots free. - * XXX only for splitmic. - */ - for (i = 0; i < IEEE80211_WEP_NKID; i++) { - set_bit(i, sc->sc_keymap); - set_bit(i + 32, sc->sc_keymap); - set_bit(i + 64, sc->sc_keymap); - set_bit(i + 32 + 64, sc->sc_keymap); - } - /* - * Collect the channel list using the default country - * code and including outdoor channels. The 802.11 layer - * is resposible for filtering this list based on settings - * like the phy mode. - */ - error = ath_setup_channels(sc); - if (error) - goto bad; - - /* default to STA mode */ - sc->sc_ah->ah_opmode = ATH9K_M_MONITOR; - - /* Setup rate tables */ - - ath_setup_rates(sc, IEEE80211_BAND_2GHZ); - ath_setup_rates(sc, IEEE80211_BAND_5GHZ); - - /* NB: setup here so ath_rate_update is happy */ - ath_setcurmode(sc, ATH9K_MODE_11A); - - /* - * Allocate hardware transmit queues: one queue for - * beacon frames and one data queue for each QoS - * priority. Note that the hal handles reseting - * these queues at the needed time. - */ - sc->sc_bhalq = ath_beaconq_setup(ah); - if (sc->sc_bhalq == -1) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to setup a beacon xmit queue\n", __func__); - error = -EIO; - goto bad2; - } - sc->sc_cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0); - if (sc->sc_cabq == NULL) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to setup CAB xmit queue\n", __func__); - error = -EIO; - goto bad2; - } - - sc->sc_config.cabqReadytime = ATH_CABQ_READY_TIME; - ath_cabq_update(sc); - - for (i = 0; i < ARRAY_SIZE(sc->sc_haltype2q); i++) - sc->sc_haltype2q[i] = -1; - - /* Setup data queues */ - /* NB: ensure BK queue is the lowest priority h/w queue */ - if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to setup xmit queue for BK traffic\n", - __func__); - error = -EIO; - goto bad2; - } - - if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to setup xmit queue for BE traffic\n", - __func__); - error = -EIO; - goto bad2; - } - if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to setup xmit queue for VI traffic\n", - __func__); - error = -EIO; - goto bad2; - } - if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to setup xmit queue for VO traffic\n", - __func__); - error = -EIO; - goto bad2; - } - - setup_timer(&sc->sc_ani.timer, ath_ani_calibrate, (unsigned long)sc); - - sc->sc_rc = ath_rate_attach(ah); - if (sc->sc_rc == NULL) { - error = -EIO; - goto bad2; - } - - if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, - ATH9K_CIPHER_TKIP, NULL)) { - /* - * Whether we should enable h/w TKIP MIC. - * XXX: if we don't support WME TKIP MIC, then we wouldn't - * report WMM capable, so it's always safe to turn on - * TKIP MIC in this case. - */ - ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_TKIP_MIC, - 0, 1, NULL); - } - - /* - * Check whether the separate key cache entries - * are required to handle both tx+rx MIC keys. - * With split mic keys the number of stations is limited - * to 27 otherwise 59. - */ - if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, - ATH9K_CIPHER_TKIP, NULL) - && ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, - ATH9K_CIPHER_MIC, NULL) - && ath9k_hw_getcapability(ah, ATH9K_CAP_TKIP_SPLIT, - 0, NULL)) - sc->sc_splitmic = 1; - - /* turn on mcast key search if possible */ - if (!ath9k_hw_getcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL)) - (void)ath9k_hw_setcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 1, - 1, NULL); - - sc->sc_config.txpowlimit = ATH_TXPOWER_MAX; - sc->sc_config.txpowlimit_override = 0; - - /* 11n Capabilities */ - if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) { - sc->sc_flags |= SC_OP_TXAGGR; - sc->sc_flags |= SC_OP_RXAGGR; - } - - sc->sc_tx_chainmask = ah->ah_caps.tx_chainmask; - sc->sc_rx_chainmask = ah->ah_caps.rx_chainmask; - - ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL); - sc->sc_defant = ath9k_hw_getdefantenna(ah); - - ath9k_hw_getmac(ah, sc->sc_myaddr); - if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) { - ath9k_hw_getbssidmask(ah, sc->sc_bssidmask); - ATH_SET_VAP_BSSID_MASK(sc->sc_bssidmask); - ath9k_hw_setbssidmask(ah, sc->sc_bssidmask); - } - sc->sc_slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */ - - /* initialize beacon slots */ - for (i = 0; i < ARRAY_SIZE(sc->sc_bslot); i++) - sc->sc_bslot[i] = ATH_IF_ID_ANY; - - /* save MISC configurations */ - sc->sc_config.swBeaconProcess = 1; - -#ifdef CONFIG_SLOW_ANT_DIV - /* range is 40 - 255, we use something in the middle */ - ath_slow_ant_div_init(&sc->sc_antdiv, sc, 0x127); -#endif - - return 0; -bad2: - /* cleanup tx queues */ - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) - if (ATH_TXQ_SETUP(sc, i)) - ath_tx_cleanupq(sc, &sc->sc_txq[i]); -bad: - if (ah) - ath9k_hw_detach(ah); - return error; -} - -void ath_deinit(struct ath_softc *sc) -{ - struct ath_hal *ah = sc->sc_ah; - int i; - - DPRINTF(sc, ATH_DBG_CONFIG, "%s\n", __func__); - - tasklet_kill(&sc->intr_tq); - tasklet_kill(&sc->bcon_tasklet); - ath_stop(sc); - if (!(sc->sc_flags & SC_OP_INVALID)) - ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); - ath_rate_detach(sc->sc_rc); - /* cleanup tx queues */ - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) - if (ATH_TXQ_SETUP(sc, i)) - ath_tx_cleanupq(sc, &sc->sc_txq[i]); - ath9k_hw_detach(ah); -} - -/*******************/ -/* Node Management */ -/*******************/ - -struct ath_node *ath_node_attach(struct ath_softc *sc, u8 *addr, int if_id) -{ - struct ath_vap *avp; - struct ath_node *an; - DECLARE_MAC_BUF(mac); - - avp = sc->sc_vaps[if_id]; - ASSERT(avp != NULL); - - /* mac80211 sta_notify callback is from an IRQ context, so no sleep */ - an = kmalloc(sizeof(struct ath_node), GFP_ATOMIC); - if (an == NULL) - return NULL; - memset(an, 0, sizeof(*an)); - - an->an_sc = sc; - memcpy(an->an_addr, addr, ETH_ALEN); - atomic_set(&an->an_refcnt, 1); - - /* set up per-node tx/rx state */ - ath_tx_node_init(sc, an); - ath_rx_node_init(sc, an); - - ath_chainmask_sel_init(sc, an); - ath_chainmask_sel_timerstart(&an->an_chainmask_sel); - list_add(&an->list, &sc->node_list); - - return an; -} - -void ath_node_detach(struct ath_softc *sc, struct ath_node *an, bool bh_flag) -{ - unsigned long flags; - - DECLARE_MAC_BUF(mac); - - ath_chainmask_sel_timerstop(&an->an_chainmask_sel); - an->an_flags |= ATH_NODE_CLEAN; - ath_tx_node_cleanup(sc, an, bh_flag); - ath_rx_node_cleanup(sc, an); - - ath_tx_node_free(sc, an); - ath_rx_node_free(sc, an); - - spin_lock_irqsave(&sc->node_lock, flags); - - list_del(&an->list); - - spin_unlock_irqrestore(&sc->node_lock, flags); - - kfree(an); -} - -/* Finds a node and increases the refcnt if found */ - -struct ath_node *ath_node_get(struct ath_softc *sc, u8 *addr) -{ - struct ath_node *an = NULL, *an_found = NULL; - - if (list_empty(&sc->node_list)) /* FIXME */ - goto out; - list_for_each_entry(an, &sc->node_list, list) { - if (!compare_ether_addr(an->an_addr, addr)) { - atomic_inc(&an->an_refcnt); - an_found = an; - break; - } - } -out: - return an_found; -} - -/* Decrements the refcnt and if it drops to zero, detach the node */ - -void ath_node_put(struct ath_softc *sc, struct ath_node *an, bool bh_flag) -{ - if (atomic_dec_and_test(&an->an_refcnt)) - ath_node_detach(sc, an, bh_flag); -} - -/* Finds a node, doesn't increment refcnt. Caller must hold sc->node_lock */ -struct ath_node *ath_node_find(struct ath_softc *sc, u8 *addr) -{ - struct ath_node *an = NULL, *an_found = NULL; - - if (list_empty(&sc->node_list)) - return NULL; - - list_for_each_entry(an, &sc->node_list, list) - if (!compare_ether_addr(an->an_addr, addr)) { - an_found = an; - break; - } - - return an_found; -} - -/* - * Set up New Node - * - * Setup driver-specific state for a newly associated node. This routine - * really only applies if compression or XR are enabled, there is no code - * covering any other cases. -*/ - -void ath_newassoc(struct ath_softc *sc, - struct ath_node *an, int isnew, int isuapsd) -{ - int tidno; - - /* if station reassociates, tear down the aggregation state. */ - if (!isnew) { - for (tidno = 0; tidno < WME_NUM_TID; tidno++) { - if (sc->sc_flags & SC_OP_TXAGGR) - ath_tx_aggr_teardown(sc, an, tidno); - if (sc->sc_flags & SC_OP_RXAGGR) - ath_rx_aggr_teardown(sc, an, tidno); - } - } - an->an_flags = 0; -} - -/**************/ -/* Encryption */ -/**************/ - -void ath_key_reset(struct ath_softc *sc, u16 keyix, int freeslot) -{ - ath9k_hw_keyreset(sc->sc_ah, keyix); - if (freeslot) - clear_bit(keyix, sc->sc_keymap); -} - -int ath_keyset(struct ath_softc *sc, - u16 keyix, - struct ath9k_keyval *hk, - const u8 mac[ETH_ALEN]) -{ - bool status; - - status = ath9k_hw_set_keycache_entry(sc->sc_ah, - keyix, hk, mac, false); - - return status != false; -} - -/***********************/ -/* TX Power/Regulatory */ -/***********************/ - -/* - * Set Transmit power in HAL - * - * This routine makes the actual HAL calls to set the new transmit power - * limit. -*/ - -void ath_update_txpow(struct ath_softc *sc) -{ - struct ath_hal *ah = sc->sc_ah; - u32 txpow; - - if (sc->sc_curtxpow != sc->sc_config.txpowlimit) { - ath9k_hw_set_txpowerlimit(ah, sc->sc_config.txpowlimit); - /* read back in case value is clamped */ - ath9k_hw_getcapability(ah, ATH9K_CAP_TXPOW, 1, &txpow); - sc->sc_curtxpow = txpow; - } -} - -/* Return the current country and domain information */ -void ath_get_currentCountry(struct ath_softc *sc, - struct ath9k_country_entry *ctry) -{ - ath9k_regd_get_current_country(sc->sc_ah, ctry); - - /* If HAL not specific yet, since it is band dependent, - * use the one we passed in. */ - if (ctry->countryCode == CTRY_DEFAULT) { - ctry->iso[0] = 0; - ctry->iso[1] = 0; - } else if (ctry->iso[0] && ctry->iso[1]) { - if (!ctry->iso[2]) { - if (ath_outdoor) - ctry->iso[2] = 'O'; - else - ctry->iso[2] = 'I'; - } - } -} - -/**************************/ -/* Slow Antenna Diversity */ -/**************************/ - -void ath_slow_ant_div_init(struct ath_antdiv *antdiv, - struct ath_softc *sc, - int32_t rssitrig) -{ - int trig; - - /* antdivf_rssitrig can range from 40 - 0xff */ - trig = (rssitrig > 0xff) ? 0xff : rssitrig; - trig = (rssitrig < 40) ? 40 : rssitrig; - - antdiv->antdiv_sc = sc; - antdiv->antdivf_rssitrig = trig; -} - -void ath_slow_ant_div_start(struct ath_antdiv *antdiv, - u8 num_antcfg, - const u8 *bssid) -{ - antdiv->antdiv_num_antcfg = - num_antcfg < ATH_ANT_DIV_MAX_CFG ? - num_antcfg : ATH_ANT_DIV_MAX_CFG; - antdiv->antdiv_state = ATH_ANT_DIV_IDLE; - antdiv->antdiv_curcfg = 0; - antdiv->antdiv_bestcfg = 0; - antdiv->antdiv_laststatetsf = 0; - - memcpy(antdiv->antdiv_bssid, bssid, sizeof(antdiv->antdiv_bssid)); - - antdiv->antdiv_start = 1; -} - -void ath_slow_ant_div_stop(struct ath_antdiv *antdiv) -{ - antdiv->antdiv_start = 0; -} - -static int32_t ath_find_max_val(int32_t *val, - u8 num_val, u8 *max_index) -{ - u32 MaxVal = *val++; - u32 cur_index = 0; - - *max_index = 0; - while (++cur_index < num_val) { - if (*val > MaxVal) { - MaxVal = *val; - *max_index = cur_index; - } - - val++; - } - - return MaxVal; -} - -void ath_slow_ant_div(struct ath_antdiv *antdiv, - struct ieee80211_hdr *hdr, - struct ath_rx_status *rx_stats) -{ - struct ath_softc *sc = antdiv->antdiv_sc; - struct ath_hal *ah = sc->sc_ah; - u64 curtsf = 0; - u8 bestcfg, curcfg = antdiv->antdiv_curcfg; - __le16 fc = hdr->frame_control; - - if (antdiv->antdiv_start && ieee80211_is_beacon(fc) - && !compare_ether_addr(hdr->addr3, antdiv->antdiv_bssid)) { - antdiv->antdiv_lastbrssi[curcfg] = rx_stats->rs_rssi; - antdiv->antdiv_lastbtsf[curcfg] = ath9k_hw_gettsf64(sc->sc_ah); - curtsf = antdiv->antdiv_lastbtsf[curcfg]; - } else { - return; - } - - switch (antdiv->antdiv_state) { - case ATH_ANT_DIV_IDLE: - if ((antdiv->antdiv_lastbrssi[curcfg] < - antdiv->antdivf_rssitrig) - && ((curtsf - antdiv->antdiv_laststatetsf) > - ATH_ANT_DIV_MIN_IDLE_US)) { - - curcfg++; - if (curcfg == antdiv->antdiv_num_antcfg) - curcfg = 0; - - if (!ath9k_hw_select_antconfig(ah, curcfg)) { - antdiv->antdiv_bestcfg = antdiv->antdiv_curcfg; - antdiv->antdiv_curcfg = curcfg; - antdiv->antdiv_laststatetsf = curtsf; - antdiv->antdiv_state = ATH_ANT_DIV_SCAN; - } - } - break; - - case ATH_ANT_DIV_SCAN: - if ((curtsf - antdiv->antdiv_laststatetsf) < - ATH_ANT_DIV_MIN_SCAN_US) - break; - - curcfg++; - if (curcfg == antdiv->antdiv_num_antcfg) - curcfg = 0; - - if (curcfg == antdiv->antdiv_bestcfg) { - ath_find_max_val(antdiv->antdiv_lastbrssi, - antdiv->antdiv_num_antcfg, &bestcfg); - if (!ath9k_hw_select_antconfig(ah, bestcfg)) { - antdiv->antdiv_bestcfg = bestcfg; - antdiv->antdiv_curcfg = bestcfg; - antdiv->antdiv_laststatetsf = curtsf; - antdiv->antdiv_state = ATH_ANT_DIV_IDLE; - } - } else { - if (!ath9k_hw_select_antconfig(ah, curcfg)) { - antdiv->antdiv_curcfg = curcfg; - antdiv->antdiv_laststatetsf = curtsf; - antdiv->antdiv_state = ATH_ANT_DIV_SCAN; - } - } - - break; - } -} - -/***********************/ -/* Descriptor Handling */ -/***********************/ - -/* - * Set up DMA descriptors - * - * This function will allocate both the DMA descriptor structure, and the - * buffers it contains. These are used to contain the descriptors used - * by the system. -*/ - -int ath_descdma_setup(struct ath_softc *sc, - struct ath_descdma *dd, - struct list_head *head, - const char *name, - int nbuf, - int ndesc) -{ -#define DS2PHYS(_dd, _ds) \ - ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc)) -#define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0) -#define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096) - - struct ath_desc *ds; - struct ath_buf *bf; - int i, bsize, error; - - DPRINTF(sc, ATH_DBG_CONFIG, "%s: %s DMA: %u buffers %u desc/buf\n", - __func__, name, nbuf, ndesc); - - /* ath_desc must be a multiple of DWORDs */ - if ((sizeof(struct ath_desc) % 4) != 0) { - DPRINTF(sc, ATH_DBG_FATAL, "%s: ath_desc not DWORD aligned\n", - __func__); - ASSERT((sizeof(struct ath_desc) % 4) == 0); - error = -ENOMEM; - goto fail; - } - - dd->dd_name = name; - dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc; - - /* - * Need additional DMA memory because we can't use - * descriptors that cross the 4K page boundary. Assume - * one skipped descriptor per 4K page. - */ - if (!(sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) { - u32 ndesc_skipped = - ATH_DESC_4KB_BOUND_NUM_SKIPPED(dd->dd_desc_len); - u32 dma_len; - - while (ndesc_skipped) { - dma_len = ndesc_skipped * sizeof(struct ath_desc); - dd->dd_desc_len += dma_len; - - ndesc_skipped = ATH_DESC_4KB_BOUND_NUM_SKIPPED(dma_len); - }; - } - - /* allocate descriptors */ - dd->dd_desc = pci_alloc_consistent(sc->pdev, - dd->dd_desc_len, - &dd->dd_desc_paddr); - if (dd->dd_desc == NULL) { - error = -ENOMEM; - goto fail; - } - ds = dd->dd_desc; - DPRINTF(sc, ATH_DBG_CONFIG, "%s: %s DMA map: %p (%u) -> %llx (%u)\n", - __func__, dd->dd_name, ds, (u32) dd->dd_desc_len, - ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len); - - /* allocate buffers */ - bsize = sizeof(struct ath_buf) * nbuf; - bf = kmalloc(bsize, GFP_KERNEL); - if (bf == NULL) { - error = -ENOMEM; - goto fail2; - } - memset(bf, 0, bsize); - dd->dd_bufptr = bf; - - INIT_LIST_HEAD(head); - for (i = 0; i < nbuf; i++, bf++, ds += ndesc) { - bf->bf_desc = ds; - bf->bf_daddr = DS2PHYS(dd, ds); - - if (!(sc->sc_ah->ah_caps.hw_caps & - ATH9K_HW_CAP_4KB_SPLITTRANS)) { - /* - * Skip descriptor addresses which can cause 4KB - * boundary crossing (addr + length) with a 32 dword - * descriptor fetch. - */ - while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) { - ASSERT((caddr_t) bf->bf_desc < - ((caddr_t) dd->dd_desc + - dd->dd_desc_len)); - - ds += ndesc; - bf->bf_desc = ds; - bf->bf_daddr = DS2PHYS(dd, ds); - } - } - list_add_tail(&bf->list, head); - } - return 0; -fail2: - pci_free_consistent(sc->pdev, - dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr); -fail: - memset(dd, 0, sizeof(*dd)); - return error; -#undef ATH_DESC_4KB_BOUND_CHECK -#undef ATH_DESC_4KB_BOUND_NUM_SKIPPED -#undef DS2PHYS -} - -/* - * Cleanup DMA descriptors - * - * This function will free the DMA block that was allocated for the descriptor - * pool. Since this was allocated as one "chunk", it is freed in the same - * manner. -*/ - -void ath_descdma_cleanup(struct ath_softc *sc, - struct ath_descdma *dd, - struct list_head *head) -{ - /* Free memory associated with descriptors */ - pci_free_consistent(sc->pdev, - dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr); - - INIT_LIST_HEAD(head); - kfree(dd->dd_bufptr); - memset(dd, 0, sizeof(*dd)); -} - -/*************/ -/* Utilities */ -/*************/ - -int ath_get_hal_qnum(u16 queue, struct ath_softc *sc) -{ - int qnum; - - switch (queue) { - case 0: - qnum = sc->sc_haltype2q[ATH9K_WME_AC_VO]; - break; - case 1: - qnum = sc->sc_haltype2q[ATH9K_WME_AC_VI]; - break; - case 2: - qnum = sc->sc_haltype2q[ATH9K_WME_AC_BE]; - break; - case 3: - qnum = sc->sc_haltype2q[ATH9K_WME_AC_BK]; - break; - default: - qnum = sc->sc_haltype2q[ATH9K_WME_AC_BE]; - break; - } - - return qnum; -} - -int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc) -{ - int qnum; - - switch (queue) { - case ATH9K_WME_AC_VO: - qnum = 0; - break; - case ATH9K_WME_AC_VI: - qnum = 1; - break; - case ATH9K_WME_AC_BE: - qnum = 2; - break; - case ATH9K_WME_AC_BK: - qnum = 3; - break; - default: - qnum = -1; - break; - } - - return qnum; -} - - -/* - * Expand time stamp to TSF - * - * Extend 15-bit time stamp from rx descriptor to - * a full 64-bit TSF using the current h/w TSF. -*/ - -u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp) -{ - u64 tsf; - - tsf = ath9k_hw_gettsf64(sc->sc_ah); - if ((tsf & 0x7fff) < rstamp) - tsf -= 0x8000; - return (tsf & ~0x7fff) | rstamp; -} - -/* - * Set Default Antenna - * - * Call into the HAL to set the default antenna to use. Not really valid for - * MIMO technology. -*/ - -void ath_setdefantenna(void *context, u32 antenna) -{ - struct ath_softc *sc = (struct ath_softc *)context; - struct ath_hal *ah = sc->sc_ah; - - /* XXX block beacon interrupts */ - ath9k_hw_setantenna(ah, antenna); - sc->sc_defant = antenna; - sc->sc_rxotherant = 0; -} - -/* - * Set Slot Time - * - * This will wake up the chip if required, and set the slot time for the - * frame (maximum transmit time). Slot time is assumed to be already set - * in the ATH object member sc_slottime -*/ - -void ath_setslottime(struct ath_softc *sc) -{ - ath9k_hw_setslottime(sc->sc_ah, sc->sc_slottime); - sc->sc_updateslot = OK; -} diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index cb3e61e57c4d9a82218c6c7220fdef0f26fa3e77..4ca2aed236e090d081e6649f019cf81da86273c0 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -17,27 +17,8 @@ #ifndef CORE_H #define CORE_H -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include #include #include #include @@ -47,10 +28,6 @@ struct ath_node; -/******************/ -/* Utility macros */ -/******************/ - /* Macro to expand scalars to 64-bit objects */ #define ito64(x) (sizeof(x) == 8) ? \ @@ -84,94 +61,125 @@ struct ath_node; #define TSF_TO_TU(_h,_l) \ ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) -#define ATH9K_BH_STATUS_INTACT 0 -#define ATH9K_BH_STATUS_CHANGE 1 - -#define ATH_TXQ_SETUP(sc, i) ((sc)->sc_txqsetup & (1<tx.txqsetup & (1<sc_debug & (_m)) \ - printk(_fmt , ##__VA_ARGS__); \ - } while (0) +#ifdef CONFIG_ATH9K_DEBUG + +/** + * struct ath_interrupt_stats - Contains statistics about interrupts + * @total: Total no. of interrupts generated so far + * @rxok: RX with no errors + * @rxeol: RX with no more RXDESC available + * @rxorn: RX FIFO overrun + * @txok: TX completed at the requested rate + * @txurn: TX FIFO underrun + * @mib: MIB regs reaching its threshold + * @rxphyerr: RX with phy errors + * @rx_keycache_miss: RX with key cache misses + * @swba: Software Beacon Alert + * @bmiss: Beacon Miss + * @bnr: Beacon Not Ready + * @cst: Carrier Sense TImeout + * @gtt: Global TX Timeout + * @tim: RX beacon TIM occurrence + * @cabend: RX End of CAB traffic + * @dtimsync: DTIM sync lossage + * @dtim: RX Beacon with DTIM + */ +struct ath_interrupt_stats { + u32 total; + u32 rxok; + u32 rxeol; + u32 rxorn; + u32 txok; + u32 txeol; + u32 txurn; + u32 mib; + u32 rxphyerr; + u32 rx_keycache_miss; + u32 swba; + u32 bmiss; + u32 bnr; + u32 cst; + u32 gtt; + u32 tim; + u32 cabend; + u32 dtimsync; + u32 dtim; +}; + +struct ath_stats { + struct ath_interrupt_stats istats; +}; + +struct ath9k_debug { + int debug_mask; + struct dentry *debugfs_root; + struct dentry *debugfs_phy; + struct dentry *debugfs_dma; + struct dentry *debugfs_interrupt; + struct ath_stats stats; +}; + +void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...); +int ath9k_init_debug(struct ath_softc *sc); +void ath9k_exit_debug(struct ath_softc *sc); +void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status); + +#else + +static inline void DPRINTF(struct ath_softc *sc, int dbg_mask, + const char *fmt, ...) +{ +} + +static inline int ath9k_init_debug(struct ath_softc *sc) +{ + return 0; +} -/***************************/ -/* Load-time Configuration */ -/***************************/ +static inline void ath9k_exit_debug(struct ath_softc *sc) +{ +} + +static inline void ath_debug_stat_interrupt(struct ath_softc *sc, + enum ath9k_int status) +{ +} + +#endif /* CONFIG_ATH9K_DEBUG */ -/* Per-instance load-time (note: NOT run-time) configurations - * for Atheros Device */ struct ath_config { u32 ath_aggr_prot; u16 txpowlimit; u16 txpowlimit_override; - u8 cabqReadytime; /* Cabq Readytime % */ - u8 swBeaconProcess; /* Process received beacons in SW (vs HW) */ -}; - -/***********************/ -/* Chainmask Selection */ -/***********************/ - -#define ATH_CHAINMASK_SEL_TIMEOUT 6000 -/* Default - Number of last RSSI values that is used for - * chainmask selection */ -#define ATH_CHAINMASK_SEL_RSSI_CNT 10 -/* Means use 3x3 chainmask instead of configured chainmask */ -#define ATH_CHAINMASK_SEL_3X3 7 -/* Default - Rssi threshold below which we have to switch to 3x3 */ -#define ATH_CHAINMASK_SEL_UP_RSSI_THRES 20 -/* Default - Rssi threshold above which we have to switch to - * user configured values */ -#define ATH_CHAINMASK_SEL_DOWN_RSSI_THRES 35 -/* Struct to store the chainmask select related info */ -struct ath_chainmask_sel { - struct timer_list timer; - int cur_tx_mask; /* user configured or 3x3 */ - int cur_rx_mask; /* user configured or 3x3 */ - int tx_avgrssi; - u8 switch_allowed:1, /* timer will set this */ - cm_sel_enabled : 1; + u8 cabqReadytime; + u8 swBeaconProcess; }; -int ath_chainmask_sel_logic(struct ath_softc *sc, struct ath_node *an); -void ath_update_chainmask(struct ath_softc *sc, int is_ht); - /*************************/ /* Descriptor Management */ /*************************/ @@ -200,15 +208,14 @@ enum buffer_type { }; struct ath_buf_state { - int bfs_nframes; /* # frames in aggregate */ - u16 bfs_al; /* length of aggregate */ - u16 bfs_frmlen; /* length of frame */ - int bfs_seqno; /* sequence number */ - int bfs_tidno; /* tid of this frame */ - int bfs_retries; /* current retries */ - struct ath_rc_series bfs_rcs[4]; /* rate series */ - u32 bf_type; /* BUF_* (enum buffer_type) */ - /* key type use to encrypt this frame */ + int bfs_nframes; /* # frames in aggregate */ + u16 bfs_al; /* length of aggregate */ + u16 bfs_frmlen; /* length of frame */ + int bfs_seqno; /* sequence number */ + int bfs_tidno; /* tid of this frame */ + int bfs_retries; /* current retries */ + u32 bf_type; /* BUF_* (enum buffer_type) */ + u32 bfs_keyix; enum ath9k_key_type bfs_keytype; }; @@ -219,6 +226,7 @@ struct ath_buf_state { #define bf_seqno bf_state.bfs_seqno #define bf_tidno bf_state.bfs_tidno #define bf_rcs bf_state.bfs_rcs +#define bf_keyix bf_state.bfs_keyix #define bf_keytype bf_state.bfs_keytype #define bf_isdata(bf) (bf->bf_state.bf_type & BUF_DATA) #define bf_isaggr(bf) (bf->bf_state.bf_type & BUF_AGGR) @@ -242,9 +250,7 @@ struct ath_buf { an aggregate) */ struct ath_buf *bf_lastfrm; /* last buf of this frame */ struct ath_buf *bf_next; /* next subframe in the aggregate */ - struct ath_buf *bf_rifslast; /* last buf for RIFS burst */ void *bf_mpdu; /* enclosing frame structure */ - void *bf_node; /* pointer to the node */ struct ath_desc *bf_desc; /* virtual addr of desc */ dma_addr_t bf_daddr; /* physical addr of desc */ dma_addr_t bf_buf_addr; /* physical addr of data buffer */ @@ -254,13 +260,6 @@ struct ath_buf { dma_addr_t bf_dmacontext; }; -/* - * reset the rx buffer. - * any new fields added to the athbuf and require - * reset need to be added to this macro. - * currently bf_status is the only one requires that - * requires reset. - */ #define ATH_RXBUF_RESET(_bf) ((_bf)->bf_status = 0) /* hw processing complete, desc processed by hal */ @@ -281,159 +280,81 @@ struct ath_descdma { dma_addr_t dd_dmacontext; }; -/* Abstraction of a received RX MPDU/MMPDU, or a RX fragment */ - -struct ath_rx_context { - struct ath_buf *ctx_rxbuf; /* associated ath_buf for rx */ -}; -#define ATH_RX_CONTEXT(skb) ((struct ath_rx_context *)skb->cb) - -int ath_descdma_setup(struct ath_softc *sc, - struct ath_descdma *dd, - struct list_head *head, - const char *name, - int nbuf, - int ndesc); -int ath_desc_alloc(struct ath_softc *sc); -void ath_desc_free(struct ath_softc *sc); -void ath_descdma_cleanup(struct ath_softc *sc, - struct ath_descdma *dd, +int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, + struct list_head *head, const char *name, + int nbuf, int ndesc); +void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, struct list_head *head); -/******/ -/* RX */ -/******/ - -#define ATH_MAX_ANTENNA 3 -#define ATH_RXBUF 512 -#define ATH_RX_TIMEOUT 40 /* 40 milliseconds */ -#define WME_NUM_TID 16 -#define IEEE80211_BAR_CTL_TID_M 0xF000 /* tid mask */ -#define IEEE80211_BAR_CTL_TID_S 12 /* tid shift */ - -enum ATH_RX_TYPE { - ATH_RX_NON_CONSUMED = 0, - ATH_RX_CONSUMED -}; - -/* per frame rx status block */ -struct ath_recv_status { - u64 tsf; /* mac tsf */ - int8_t rssi; /* RSSI (noise floor ajusted) */ - int8_t rssictl[ATH_MAX_ANTENNA]; /* RSSI (noise floor ajusted) */ - int8_t rssiextn[ATH_MAX_ANTENNA]; /* RSSI (noise floor ajusted) */ - int8_t abs_rssi; /* absolute RSSI */ - u8 rateieee; /* data rate received (IEEE rate code) */ - u8 ratecode; /* phy rate code */ - int rateKbps; /* data rate received (Kbps) */ - int antenna; /* rx antenna */ - int flags; /* status of associated skb */ -#define ATH_RX_FCS_ERROR 0x01 -#define ATH_RX_MIC_ERROR 0x02 -#define ATH_RX_DECRYPT_ERROR 0x04 -#define ATH_RX_RSSI_VALID 0x08 -/* if any of ctl,extn chainrssis are valid */ -#define ATH_RX_CHAIN_RSSI_VALID 0x10 -/* if extn chain rssis are valid */ -#define ATH_RX_RSSI_EXTN_VALID 0x20 -/* set if 40Mhz, clear if 20Mhz */ -#define ATH_RX_40MHZ 0x40 -/* set if short GI, clear if full GI */ -#define ATH_RX_SHORT_GI 0x80 -}; - -struct ath_rxbuf { - struct sk_buff *rx_wbuf; - unsigned long rx_time; /* system time when received */ - struct ath_recv_status rx_status; /* cached rx status */ -}; - -/* Per-TID aggregate receiver state for a node */ -struct ath_arx_tid { - struct ath_node *an; - struct ath_rxbuf *rxbuf; /* re-ordering buffer */ - struct timer_list timer; - spinlock_t tidlock; - int baw_head; /* seq_next at head */ - int baw_tail; /* tail of block-ack window */ - int seq_reset; /* need to reset start sequence */ - int addba_exchangecomplete; - u16 seq_next; /* next expected sequence */ - u16 baw_size; /* block-ack window size */ -}; - -/* Per-node receiver aggregate state */ -struct ath_arx { - struct ath_arx_tid tid[WME_NUM_TID]; -}; - -int ath_startrecv(struct ath_softc *sc); -bool ath_stoprecv(struct ath_softc *sc); -void ath_flushrecv(struct ath_softc *sc); -u32 ath_calcrxfilter(struct ath_softc *sc); -void ath_rx_node_init(struct ath_softc *sc, struct ath_node *an); -void ath_rx_node_free(struct ath_softc *sc, struct ath_node *an); -void ath_rx_node_cleanup(struct ath_softc *sc, struct ath_node *an); -void ath_handle_rx_intr(struct ath_softc *sc); -int ath_rx_init(struct ath_softc *sc, int nbufs); -void ath_rx_cleanup(struct ath_softc *sc); -int ath_rx_tasklet(struct ath_softc *sc, int flush); -int ath_rx_input(struct ath_softc *sc, - struct ath_node *node, - int is_ampdu, - struct sk_buff *skb, - struct ath_recv_status *rx_status, - enum ATH_RX_TYPE *status); -int _ath_rx_indicate(struct ath_softc *sc, - struct sk_buff *skb, - struct ath_recv_status *status, - u16 keyix); -int ath_rx_subframe(struct ath_node *an, struct sk_buff *skb, - struct ath_recv_status *status); - -/******/ -/* TX */ -/******/ +/***********/ +/* RX / TX */ +/***********/ +#define ATH_MAX_ANTENNA 3 +#define ATH_RXBUF 512 +#define WME_NUM_TID 16 #define ATH_TXBUF 512 -/* max number of transmit attempts (tries) */ #define ATH_TXMAXTRY 13 -/* max number of 11n transmit attempts (tries) */ #define ATH_11N_TXMAXTRY 10 -/* max number of tries for management and control frames */ #define ATH_MGT_TXMAXTRY 4 #define WME_BA_BMP_SIZE 64 #define WME_MAX_BA WME_BA_BMP_SIZE #define ATH_TID_MAX_BUFS (2 * WME_MAX_BA) + #define TID_TO_WME_AC(_tid) \ ((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \ (((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK : \ (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \ WME_AC_VO) +#define WME_AC_BE 0 +#define WME_AC_BK 1 +#define WME_AC_VI 2 +#define WME_AC_VO 3 +#define WME_NUM_AC 4 + +#define ADDBA_EXCHANGE_ATTEMPTS 10 +#define ATH_AGGR_DELIM_SZ 4 +#define ATH_AGGR_MINPLEN 256 /* in bytes, minimum packet length */ +/* number of delimiters for encryption padding */ +#define ATH_AGGR_ENCRYPTDELIM 10 +/* minimum h/w qdepth to be sustained to maximize aggregation */ +#define ATH_AGGR_MIN_QDEPTH 2 +#define ATH_AMPDU_SUBFRAME_DEFAULT 32 +#define IEEE80211_SEQ_SEQ_SHIFT 4 +#define IEEE80211_SEQ_MAX 4096 +#define IEEE80211_MIN_AMPDU_BUF 0x8 +#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13 + +/* return whether a bit at index _n in bitmap _bm is set + * _sz is the size of the bitmap */ +#define ATH_BA_ISSET(_bm, _n) (((_n) < (WME_BA_BMP_SIZE)) && \ + ((_bm)[(_n) >> 5] & (1 << ((_n) & 31)))) + +/* return block-ack bitmap index given sequence and starting sequence */ +#define ATH_BA_INDEX(_st, _seq) (((_seq) - (_st)) & (IEEE80211_SEQ_MAX - 1)) + +/* returns delimiter padding required given the packet length */ +#define ATH_AGGR_GET_NDELIM(_len) \ + (((((_len) + ATH_AGGR_DELIM_SZ) < ATH_AGGR_MINPLEN) ? \ + (ATH_AGGR_MINPLEN - (_len) - ATH_AGGR_DELIM_SZ) : 0) >> 2) + +#define BAW_WITHIN(_start, _bawsz, _seqno) \ + ((((_seqno) - (_start)) & 4095) < (_bawsz)) -/* Wireless Multimedia Extension Defines */ -#define WME_AC_BE 0 /* best effort */ -#define WME_AC_BK 1 /* background */ -#define WME_AC_VI 2 /* video */ -#define WME_AC_VO 3 /* voice */ -#define WME_NUM_AC 4 +#define ATH_DS_BA_SEQ(_ds) ((_ds)->ds_us.tx.ts_seqnum) +#define ATH_DS_BA_BITMAP(_ds) (&(_ds)->ds_us.tx.ba_low) +#define ATH_DS_TX_BA(_ds) ((_ds)->ds_us.tx.ts_flags & ATH9K_TX_BA) +#define ATH_AN_2_TID(_an, _tidno) (&(_an)->tid[(_tidno)]) -enum ATH_SM_PWRSAV{ - ATH_SM_ENABLE, - ATH_SM_PWRSAV_STATIC, - ATH_SM_PWRSAV_DYNAMIC, +enum ATH_AGGR_STATUS { + ATH_AGGR_DONE, + ATH_AGGR_BAW_CLOSED, + ATH_AGGR_LIMITED, + ATH_AGGR_SHORTPKT, + ATH_AGGR_8K_LIMITED, }; -/* - * Data transmit queue state. One of these exists for each - * hardware transmit queue. Packets sent to us from above - * are assigned to queues based on their priority. Not all - * devices support a complete set of hardware transmit queues. - * For those devices the array sc_ac2q will map multiple - * priorities to fewer hardware queues (typically all to one - * hardware queue). - */ struct ath_txq { u32 axq_qnum; /* hardware q number */ u32 *axq_link; /* link ptr in last TX desc */ @@ -443,10 +364,6 @@ struct ath_txq { u32 axq_depth; /* queue depth */ u8 axq_aggr_depth; /* aggregates queued */ u32 axq_totalqueued; /* total ever queued */ - - /* count to determine if descriptor should generate int on this txq. */ - u32 axq_intrcnt; - bool stopped; /* Is mac80211 queue stopped ? */ struct ath_buf *axq_linkbuf; /* virtual addr of last buffer*/ @@ -460,6 +377,10 @@ struct ath_txq { struct list_head axq_acq; }; +#define AGGR_CLEANUP BIT(1) +#define AGGR_ADDBA_COMPLETE BIT(2) +#define AGGR_ADDBA_PROGRESS BIT(3) + /* per TID aggregate tx state for a destination */ struct ath_atx_tid { struct list_head list; /* round-robin tid entry */ @@ -475,9 +396,7 @@ struct ath_atx_tid { int baw_tail; /* next unused tx buffer slot */ int sched; int paused; - int cleanup_inprogress; - u32 addba_exchangecomplete:1; - int32_t addba_exchangeinprogress; + u8 state; int addba_exchangeattempts; }; @@ -490,32 +409,10 @@ struct ath_atx_ac { struct list_head tid_q; /* queue of TIDs with buffers */ }; -/* per dest tx state */ -struct ath_atx { - struct ath_atx_tid tid[WME_NUM_TID]; - struct ath_atx_ac ac[WME_NUM_AC]; -}; - /* per-frame tx control block */ struct ath_tx_control { - struct ath_node *an; + struct ath_txq *txq; int if_id; - int qnum; - u32 ht:1; - u32 ps:1; - u32 use_minrate:1; - enum ath9k_pkt_type atype; - enum ath9k_key_type keytype; - u32 flags; - u16 seqno; - u16 tidno; - u16 txpower; - u16 frmlen; - u32 keyix; - int min_rate; - int mcast_rate; - struct ath_softc *dev; - dma_addr_t dmacontext; }; /* per frame tx status block */ @@ -528,21 +425,63 @@ struct ath_xmit_status { #define ATH_TX_BAR 0x04 }; +/* All RSSI values are noise floor adjusted */ struct ath_tx_stat { - int rssi; /* RSSI (noise floor ajusted) */ - int rssictl[ATH_MAX_ANTENNA]; /* RSSI (noise floor ajusted) */ - int rssiextn[ATH_MAX_ANTENNA]; /* RSSI (noise floor ajusted) */ - int rateieee; /* data rate xmitted (IEEE rate code) */ - int rateKbps; /* data rate xmitted (Kbps) */ - int ratecode; /* phy rate code */ - int flags; /* validity flags */ -/* if any of ctl,extn chain rssis are valid */ -#define ATH_TX_CHAIN_RSSI_VALID 0x01 -/* if extn chain rssis are valid */ -#define ATH_TX_RSSI_EXTN_VALID 0x02 + int rssi; + int rssictl[ATH_MAX_ANTENNA]; + int rssiextn[ATH_MAX_ANTENNA]; + int rateieee; + int rateKbps; + int ratecode; + int flags; u32 airtime; /* time on air per final tx rate */ }; +struct aggr_rifs_param { + int param_max_frames; + int param_max_len; + int param_rl; + int param_al; + struct ath_rc_series *param_rcs; +}; + +struct ath_node { + struct ath_softc *an_sc; + struct ath_atx_tid tid[WME_NUM_TID]; + struct ath_atx_ac ac[WME_NUM_AC]; + u16 maxampdu; + u8 mpdudensity; +}; + +struct ath_tx { + u16 seq_no; + u32 txqsetup; + int hwq_map[ATH9K_WME_AC_VO+1]; + spinlock_t txbuflock; + struct list_head txbuf; + struct ath_txq txq[ATH9K_NUM_TX_QUEUES]; + struct ath_descdma txdma; +}; + +struct ath_rx { + u8 defant; + u8 rxotherant; + u32 *rxlink; + int bufsize; + unsigned int rxfilter; + spinlock_t rxflushlock; + spinlock_t rxbuflock; + struct list_head rxbuf; + struct ath_descdma rxdma; +}; + +int ath_startrecv(struct ath_softc *sc); +bool ath_stoprecv(struct ath_softc *sc); +void ath_flushrecv(struct ath_softc *sc); +u32 ath_calcrxfilter(struct ath_softc *sc); +int ath_rx_init(struct ath_softc *sc, int nbufs); +void ath_rx_cleanup(struct ath_softc *sc); +int ath_rx_tasklet(struct ath_softc *sc, int flush); struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype); void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq); int ath_tx_setup(struct ath_softc *sc, int haltype); @@ -550,139 +489,51 @@ void ath_draintxq(struct ath_softc *sc, bool retry_tx); void ath_tx_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx); void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an); -void ath_tx_node_cleanup(struct ath_softc *sc, - struct ath_node *an, bool bh_flag); +void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an); void ath_tx_node_free(struct ath_softc *sc, struct ath_node *an); void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq); int ath_tx_init(struct ath_softc *sc, int nbufs); int ath_tx_cleanup(struct ath_softc *sc); int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype); +struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb); int ath_txq_update(struct ath_softc *sc, int qnum, struct ath9k_tx_queue_info *q); -int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb); +int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb, + struct ath_tx_control *txctl); void ath_tx_tasklet(struct ath_softc *sc); u32 ath_txq_depth(struct ath_softc *sc, int qnum); u32 ath_txq_aggr_depth(struct ath_softc *sc, int qnum); -void ath_notify_txq_status(struct ath_softc *sc, u16 queue_depth); -void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, - struct ath_xmit_status *tx_status, struct ath_node *an); void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb); +void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid); +bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno); +void ath_tx_aggr_teardown(struct ath_softc *sc, struct ath_node *an, u8 tidno); +int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, + u16 tid, u16 *ssn); +int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); +void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); -/**********************/ -/* Node / Aggregation */ -/**********************/ - -/* indicates the node is clened up */ -#define ATH_NODE_CLEAN 0x1 -/* indicates the node is 80211 power save */ -#define ATH_NODE_PWRSAVE 0x2 - -#define ADDBA_EXCHANGE_ATTEMPTS 10 -#define ATH_AGGR_DELIM_SZ 4 /* delimiter size */ -#define ATH_AGGR_MINPLEN 256 /* in bytes, minimum packet length */ -/* number of delimiters for encryption padding */ -#define ATH_AGGR_ENCRYPTDELIM 10 -/* minimum h/w qdepth to be sustained to maximize aggregation */ -#define ATH_AGGR_MIN_QDEPTH 2 -#define ATH_AMPDU_SUBFRAME_DEFAULT 32 -#define IEEE80211_SEQ_SEQ_SHIFT 4 -#define IEEE80211_SEQ_MAX 4096 -#define IEEE80211_MIN_AMPDU_BUF 0x8 - -/* return whether a bit at index _n in bitmap _bm is set - * _sz is the size of the bitmap */ -#define ATH_BA_ISSET(_bm, _n) (((_n) < (WME_BA_BMP_SIZE)) && \ - ((_bm)[(_n) >> 5] & (1 << ((_n) & 31)))) - -/* return block-ack bitmap index given sequence and starting sequence */ -#define ATH_BA_INDEX(_st, _seq) (((_seq) - (_st)) & (IEEE80211_SEQ_MAX - 1)) - -/* returns delimiter padding required given the packet length */ -#define ATH_AGGR_GET_NDELIM(_len) \ - (((((_len) + ATH_AGGR_DELIM_SZ) < ATH_AGGR_MINPLEN) ? \ - (ATH_AGGR_MINPLEN - (_len) - ATH_AGGR_DELIM_SZ) : 0) >> 2) - -#define BAW_WITHIN(_start, _bawsz, _seqno) \ - ((((_seqno) - (_start)) & 4095) < (_bawsz)) - -#define ATH_DS_BA_SEQ(_ds) ((_ds)->ds_us.tx.ts_seqnum) -#define ATH_DS_BA_BITMAP(_ds) (&(_ds)->ds_us.tx.ba_low) -#define ATH_DS_TX_BA(_ds) ((_ds)->ds_us.tx.ts_flags & ATH9K_TX_BA) -#define ATH_AN_2_TID(_an, _tidno) (&(_an)->an_aggr.tx.tid[(_tidno)]) - -enum ATH_AGGR_STATUS { - ATH_AGGR_DONE, - ATH_AGGR_BAW_CLOSED, - ATH_AGGR_LIMITED, - ATH_AGGR_SHORTPKT, - ATH_AGGR_8K_LIMITED, -}; - -enum ATH_AGGR_CHECK { - AGGR_NOT_REQUIRED, - AGGR_REQUIRED, - AGGR_CLEANUP_PROGRESS, - AGGR_EXCHANGE_PROGRESS, - AGGR_EXCHANGE_DONE -}; +/********/ +/* VAPs */ +/********/ -struct aggr_rifs_param { - int param_max_frames; - int param_max_len; - int param_rl; - int param_al; - struct ath_rc_series *param_rcs; -}; +/* + * Define the scheme that we select MAC address for multiple + * BSS on the same radio. The very first VAP will just use the MAC + * address from the EEPROM. For the next 3 VAPs, we set the + * U/L bit (bit 1) in MAC address, and use the next two bits as the + * index of the VAP. + */ -/* Per-node aggregation state */ -struct ath_node_aggr { - struct ath_atx tx; /* node transmit state */ - struct ath_arx rx; /* node receive state */ -}; +#define ATH_SET_VAP_BSSID_MASK(bssid_mask) \ + ((bssid_mask)[0] &= ~(((ATH_BCBUF-1)<<2)|0x02)) -/* driver-specific node state */ -struct ath_node { - struct list_head list; - struct ath_softc *an_sc; - atomic_t an_refcnt; - struct ath_chainmask_sel an_chainmask_sel; - struct ath_node_aggr an_aggr; - u8 an_smmode; /* SM Power save mode */ - u8 an_flags; - u8 an_addr[ETH_ALEN]; +struct ath_vap { + int av_bslot; + enum nl80211_iftype av_opmode; + struct ath_buf *av_bcbuf; + struct ath_tx_control av_btxctl; }; -void ath_tx_resume_tid(struct ath_softc *sc, - struct ath_atx_tid *tid); -enum ATH_AGGR_CHECK ath_tx_aggr_check(struct ath_softc *sc, - struct ath_node *an, u8 tidno); -void ath_tx_aggr_teardown(struct ath_softc *sc, - struct ath_node *an, u8 tidno); -void ath_rx_aggr_teardown(struct ath_softc *sc, - struct ath_node *an, u8 tidno); -int ath_rx_aggr_start(struct ath_softc *sc, - const u8 *addr, - u16 tid, - u16 *ssn); -int ath_rx_aggr_stop(struct ath_softc *sc, - const u8 *addr, - u16 tid); -int ath_tx_aggr_start(struct ath_softc *sc, - const u8 *addr, - u16 tid, - u16 *ssn); -int ath_tx_aggr_stop(struct ath_softc *sc, - const u8 *addr, - u16 tid); -void ath_newassoc(struct ath_softc *sc, - struct ath_node *node, int isnew, int isuapsd); -struct ath_node *ath_node_attach(struct ath_softc *sc, - u8 addr[ETH_ALEN], int if_id); -void ath_node_detach(struct ath_softc *sc, struct ath_node *an, bool bh_flag); -struct ath_node *ath_node_get(struct ath_softc *sc, u8 addr[ETH_ALEN]); -void ath_node_put(struct ath_softc *sc, struct ath_node *an, bool bh_flag); -struct ath_node *ath_node_find(struct ath_softc *sc, u8 *addr); - /*******************/ /* Beacon Handling */ /*******************/ @@ -693,12 +544,11 @@ struct ath_node *ath_node_find(struct ath_softc *sc, u8 *addr); * number of beacon intervals, the game's up. */ #define BSTUCK_THRESH (9 * ATH_BCBUF) -#define ATH_BCBUF 4 /* number of beacon buffers */ -#define ATH_DEFAULT_BINTVAL 100 /* default beacon interval in TU */ +#define ATH_BCBUF 1 +#define ATH_DEFAULT_BINTVAL 100 /* TU */ #define ATH_DEFAULT_BMISS_LIMIT 10 #define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024) -/* beacon configuration */ struct ath_beacon_config { u16 beacon_interval; u16 listen_interval; @@ -712,93 +562,32 @@ struct ath_beacon_config { } u; /* last received beacon/probe response timestamp of this BSS. */ }; +struct ath_beacon { + enum { + OK, /* no change needed */ + UPDATE, /* update pending */ + COMMIT /* beacon sent, commit change */ + } updateslot; /* slot time update fsm */ + + u32 beaconq; + u32 bmisscnt; + u32 ast_be_xmit; + u64 bc_tstamp; + int bslot[ATH_BCBUF]; + int slottime; + int slotupdate; + struct ath9k_tx_queue_info beacon_qi; + struct ath_descdma bdma; + struct ath_txq *cabq; + struct list_head bbuf; +}; + void ath9k_beacon_tasklet(unsigned long data); void ath_beacon_config(struct ath_softc *sc, int if_id); int ath_beaconq_setup(struct ath_hal *ah); int ath_beacon_alloc(struct ath_softc *sc, int if_id); -void ath_bstuck_process(struct ath_softc *sc); void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp); void ath_beacon_sync(struct ath_softc *sc, int if_id); -void ath_get_beaconconfig(struct ath_softc *sc, - int if_id, - struct ath_beacon_config *conf); -/********/ -/* VAPs */ -/********/ - -/* - * Define the scheme that we select MAC address for multiple - * BSS on the same radio. The very first VAP will just use the MAC - * address from the EEPROM. For the next 3 VAPs, we set the - * U/L bit (bit 1) in MAC address, and use the next two bits as the - * index of the VAP. - */ - -#define ATH_SET_VAP_BSSID_MASK(bssid_mask) \ - ((bssid_mask)[0] &= ~(((ATH_BCBUF-1)<<2)|0x02)) - -/* VAP configuration (from protocol layer) */ -struct ath_vap_config { - u32 av_fixed_rateset; - u32 av_fixed_retryset; -}; - -/* driver-specific vap state */ -struct ath_vap { - struct ieee80211_vif *av_if_data; - enum ath9k_opmode av_opmode; /* VAP operational mode */ - struct ath_buf *av_bcbuf; /* beacon buffer */ - struct ath_tx_control av_btxctl; /* txctl information for beacon */ - int av_bslot; /* beacon slot index */ - struct ath_vap_config av_config;/* vap configuration parameters*/ - struct ath_rate_node *rc_node; -}; - -int ath_vap_attach(struct ath_softc *sc, - int if_id, - struct ieee80211_vif *if_data, - enum ath9k_opmode opmode); -int ath_vap_detach(struct ath_softc *sc, int if_id); -int ath_vap_config(struct ath_softc *sc, - int if_id, struct ath_vap_config *if_config); - -/*********************/ -/* Antenna diversity */ -/*********************/ - -#define ATH_ANT_DIV_MAX_CFG 2 -#define ATH_ANT_DIV_MIN_IDLE_US 1000000 /* us */ -#define ATH_ANT_DIV_MIN_SCAN_US 50000 /* us */ - -enum ATH_ANT_DIV_STATE{ - ATH_ANT_DIV_IDLE, - ATH_ANT_DIV_SCAN, /* evaluating antenna */ -}; - -struct ath_antdiv { - struct ath_softc *antdiv_sc; - u8 antdiv_start; - enum ATH_ANT_DIV_STATE antdiv_state; - u8 antdiv_num_antcfg; - u8 antdiv_curcfg; - u8 antdiv_bestcfg; - int32_t antdivf_rssitrig; - int32_t antdiv_lastbrssi[ATH_ANT_DIV_MAX_CFG]; - u64 antdiv_lastbtsf[ATH_ANT_DIV_MAX_CFG]; - u64 antdiv_laststatetsf; - u8 antdiv_bssid[ETH_ALEN]; -}; - -void ath_slow_ant_div_init(struct ath_antdiv *antdiv, - struct ath_softc *sc, int32_t rssitrig); -void ath_slow_ant_div_start(struct ath_antdiv *antdiv, - u8 num_antcfg, - const u8 *bssid); -void ath_slow_ant_div_stop(struct ath_antdiv *antdiv); -void ath_slow_ant_div(struct ath_antdiv *antdiv, - struct ieee80211_hdr *wh, - struct ath_rx_status *rx_stats); -void ath_setdefantenna(void *sc, u32 antenna); /*******/ /* ANI */ @@ -863,7 +652,7 @@ struct ath_rfkill { #define DEFAULT_CACHELINE 32 #define ATH_DEFAULT_NOISE_FLOOR -95 #define ATH_REGCLASSIDS_MAX 10 -#define ATH_CABQ_READY_TIME 80 /* % of beacon interval */ +#define ATH_CABQ_READY_TIME 80 /* % of beacon interval */ #define ATH_MAX_SW_RETRIES 10 #define ATH_CHAN_MAX 255 #define IEEE80211_WEP_NKID 4 /* number of key ids */ @@ -876,34 +665,12 @@ struct ath_rfkill { * Different parts have different size key caches. We handle * up to ATH_KEYMAX entries (could dynamically allocate state). */ -#define ATH_KEYMAX 128 /* max key cache size we handle */ +#define ATH_KEYMAX 128 /* max key cache size we handle */ #define ATH_IF_ID_ANY 0xff #define ATH_TXPOWER_MAX 100 /* .5 dBm units */ - -#define RSSI_LPF_THRESHOLD -20 -#define ATH_RSSI_EP_MULTIPLIER (1<<7) /* pow2 to optimize out * and / */ -#define ATH_RATE_DUMMY_MARKER 0 -#define ATH_RSSI_LPF_LEN 10 -#define ATH_RSSI_DUMMY_MARKER 0x127 - -#define ATH_EP_MUL(x, mul) ((x) * (mul)) -#define ATH_EP_RND(x, mul) \ - ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul)) -#define ATH_RSSI_OUT(x) \ - (((x) != ATH_RSSI_DUMMY_MARKER) ? \ - (ATH_EP_RND((x), ATH_RSSI_EP_MULTIPLIER)) : ATH_RSSI_DUMMY_MARKER) -#define ATH_RSSI_IN(x) \ - (ATH_EP_MUL((x), ATH_RSSI_EP_MULTIPLIER)) -#define ATH_LPF_RSSI(x, y, len) \ - ((x != ATH_RSSI_DUMMY_MARKER) ? \ - (((x) * ((len) - 1) + (y)) / (len)) : (y)) -#define ATH_RSSI_LPF(x, y) do { \ - if ((y) >= RSSI_LPF_THRESHOLD) \ - x = ATH_LPF_RSSI((x), \ - ATH_RSSI_IN((y)), ATH_RSSI_LPF_LEN); \ - } while (0) - +#define ATH_RSSI_DUMMY_MARKER 0x127 +#define ATH_RATE_DUMMY_MARKER 0 enum PROT_MODE { PROT_M_NONE = 0, @@ -911,19 +678,6 @@ enum PROT_MODE { PROT_M_CTSONLY }; -enum RATE_TYPE { - NORMAL_RATE = 0, - HALF_RATE, - QUARTER_RATE -}; - -struct ath_ht_info { - enum ath9k_ht_macmode tx_chan_width; - u16 maxampdu; - u8 mpdudensity; - u8 ext_chan_offset; -}; - #define SC_OP_INVALID BIT(0) #define SC_OP_BEACONS BIT(1) #define SC_OP_RXAGGR BIT(2) @@ -944,141 +698,57 @@ struct ath_softc { struct pci_dev *pdev; struct tasklet_struct intr_tq; struct tasklet_struct bcon_tasklet; - struct ath_config sc_config; struct ath_hal *sc_ah; - struct ath_rate_softc *sc_rc; void __iomem *mem; + spinlock_t sc_resetlock; + struct mutex mutex; u8 sc_curbssid[ETH_ALEN]; u8 sc_myaddr[ETH_ALEN]; u8 sc_bssidmask[ETH_ALEN]; - - int sc_debug; u32 sc_intrstatus; u32 sc_flags; /* SC_OP_* */ - unsigned int rx_filter; u16 sc_curtxpow; u16 sc_curaid; u16 sc_cachelsz; - int sc_slotupdate; /* slot to next advance fsm */ - int sc_slottime; - int sc_bslot[ATH_BCBUF]; + u8 sc_nbcnvaps; + u16 sc_nvaps; u8 sc_tx_chainmask; u8 sc_rx_chainmask; + u32 sc_keymax; + DECLARE_BITMAP(sc_keymap, ATH_KEYMAX); + u8 sc_splitmic; + u8 sc_protrix; enum ath9k_int sc_imask; - enum wireless_mode sc_curmode; /* current phy mode */ enum PROT_MODE sc_protmode; - - u8 sc_nbcnvaps; /* # of vaps sending beacons */ - u16 sc_nvaps; /* # of active virtual ap's */ - struct ath_vap *sc_vaps[ATH_BCBUF]; - - u8 sc_mcastantenna; - u8 sc_defant; /* current default antenna */ - u8 sc_rxotherant; /* rx's on non-default antenna */ - - struct ath9k_node_stats sc_halstats; /* station-mode rssi stats */ - struct list_head node_list; - struct ath_ht_info sc_ht_info; enum ath9k_ht_extprotspacing sc_ht_extprotspacing; + enum ath9k_ht_macmode tx_chan_width; -#ifdef CONFIG_SLOW_ANT_DIV - struct ath_antdiv sc_antdiv; -#endif - enum { - OK, /* no change needed */ - UPDATE, /* update pending */ - COMMIT /* beacon sent, commit change */ - } sc_updateslot; /* slot time update fsm */ - - /* Crypto */ - u32 sc_keymax; /* size of key cache */ - DECLARE_BITMAP(sc_keymap, ATH_KEYMAX); /* key use bit map */ - u8 sc_splitmic; /* split TKIP MIC keys */ - - /* RX */ - struct list_head sc_rxbuf; - struct ath_descdma sc_rxdma; - int sc_rxbufsize; /* rx size based on mtu */ - u32 *sc_rxlink; /* link ptr in last RX desc */ - - /* TX */ - struct list_head sc_txbuf; - struct ath_txq sc_txq[ATH9K_NUM_TX_QUEUES]; - struct ath_descdma sc_txdma; - u32 sc_txqsetup; - u32 sc_txintrperiod; /* tx interrupt batching */ - int sc_haltype2q[ATH9K_WME_AC_VO+1]; /* HAL WME AC -> h/w qnum */ - u16 seq_no; /* TX sequence number */ - - /* Beacon */ - struct ath9k_tx_queue_info sc_beacon_qi; - struct ath_descdma sc_bdma; - struct ath_txq *sc_cabq; - struct list_head sc_bbuf; - u32 sc_bhalq; - u32 sc_bmisscount; - u32 ast_be_xmit; /* beacons transmitted */ - u64 bc_tstamp; - - /* Rate */ + struct ath_config sc_config; + struct ath_rx rx; + struct ath_tx tx; + struct ath_beacon beacon; + struct ieee80211_vif *sc_vaps[ATH_BCBUF]; struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX]; - const struct ath9k_rate_table *sc_currates; - u8 sc_rixmap[256]; /* IEEE to h/w rate table ix */ - u8 sc_protrix; /* protection rate index */ - struct { - u32 rateKbps; /* transfer rate in kbs */ - u8 ieeerate; /* IEEE rate */ - } sc_hwmap[256]; /* h/w rate ix mappings */ - - /* Channel, Band */ + struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX]; + struct ath_rate_table *cur_rate_table; struct ieee80211_channel channels[IEEE80211_NUM_BANDS][ATH_CHAN_MAX]; struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; - - /* Locks */ - spinlock_t sc_rxflushlock; - spinlock_t sc_rxbuflock; - spinlock_t sc_txbuflock; - spinlock_t sc_resetlock; - spinlock_t node_lock; - - /* LEDs */ struct ath_led radio_led; struct ath_led assoc_led; struct ath_led tx_led; struct ath_led rx_led; - - /* Rfkill */ struct ath_rfkill rf_kill; - - /* ANI */ struct ath_ani sc_ani; + struct ath9k_node_stats sc_halstats; +#ifdef CONFIG_ATH9K_DEBUG + struct ath9k_debug sc_debug; +#endif }; -int ath_init(u16 devid, struct ath_softc *sc); -void ath_deinit(struct ath_softc *sc); -int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan); -int ath_suspend(struct ath_softc *sc); -irqreturn_t ath_isr(int irq, void *dev); int ath_reset(struct ath_softc *sc, bool retry_tx); -int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan); - -/*********************/ -/* Utility Functions */ -/*********************/ - -void ath_key_reset(struct ath_softc *sc, u16 keyix, int freeslot); -int ath_keyset(struct ath_softc *sc, - u16 keyix, - struct ath9k_keyval *hk, - const u8 mac[ETH_ALEN]); int ath_get_hal_qnum(u16 queue, struct ath_softc *sc); int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc); -void ath_setslottime(struct ath_softc *sc); -void ath_update_txpow(struct ath_softc *sc); int ath_cabq_update(struct ath_softc *); -void ath_get_currentCountry(struct ath_softc *sc, - struct ath9k_country_entry *ctry); -u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp); #endif /* CORE_H */ diff --git a/drivers/net/wireless/ath9k/debug.c b/drivers/net/wireless/ath9k/debug.c new file mode 100644 index 0000000000000000000000000000000000000000..a80ed576830f0238f07ac003a8c8c579d52c86cc --- /dev/null +++ b/drivers/net/wireless/ath9k/debug.c @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2008 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "core.h" +#include "reg.h" +#include "hw.h" + +static unsigned int ath9k_debug = DBG_DEFAULT; +module_param_named(debug, ath9k_debug, uint, 0); + +void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...) +{ + if (!sc) + return; + + if (sc->sc_debug.debug_mask & dbg_mask) { + va_list args; + + va_start(args, fmt); + printk(KERN_DEBUG "ath9k: "); + vprintk(fmt, args); + va_end(args); + } +} + +static int ath9k_debugfs_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t read_file_dma(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + struct ath_hal *ah = sc->sc_ah; + char buf[1024]; + unsigned int len = 0; + u32 val[ATH9K_NUM_DMA_DEBUG_REGS]; + int i, qcuOffset = 0, dcuOffset = 0; + u32 *qcuBase = &val[0], *dcuBase = &val[4]; + + REG_WRITE(ah, AR_MACMISC, + ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) | + (AR_MACMISC_MISC_OBS_BUS_1 << + AR_MACMISC_MISC_OBS_BUS_MSB_S))); + + len += snprintf(buf + len, sizeof(buf) - len, + "Raw DMA Debug values:\n"); + + for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) { + if (i % 4 == 0) + len += snprintf(buf + len, sizeof(buf) - len, "\n"); + + val[i] = REG_READ(ah, AR_DMADBG_0 + (i * sizeof(u32))); + len += snprintf(buf + len, sizeof(buf) - len, "%d: %08x ", + i, val[i]); + } + + len += snprintf(buf + len, sizeof(buf) - len, "\n\n"); + len += snprintf(buf + len, sizeof(buf) - len, + "Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n"); + + for (i = 0; i < ATH9K_NUM_QUEUES; i++, qcuOffset += 4, dcuOffset += 5) { + if (i == 8) { + qcuOffset = 0; + qcuBase++; + } + + if (i == 6) { + dcuOffset = 0; + dcuBase++; + } + + len += snprintf(buf + len, sizeof(buf) - len, + "%2d %2x %1x %2x %2x\n", + i, (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset, + (*qcuBase & (0x8 << qcuOffset)) >> (qcuOffset + 3), + val[2] & (0x7 << (i * 3)) >> (i * 3), + (*dcuBase & (0x1f << dcuOffset)) >> dcuOffset); + } + + len += snprintf(buf + len, sizeof(buf) - len, "\n"); + + len += snprintf(buf + len, sizeof(buf) - len, + "qcu_stitch state: %2x qcu_fetch state: %2x\n", + (val[3] & 0x003c0000) >> 18, (val[3] & 0x03c00000) >> 22); + len += snprintf(buf + len, sizeof(buf) - len, + "qcu_complete state: %2x dcu_complete state: %2x\n", + (val[3] & 0x1c000000) >> 26, (val[6] & 0x3)); + len += snprintf(buf + len, sizeof(buf) - len, + "dcu_arb state: %2x dcu_fp state: %2x\n", + (val[5] & 0x06000000) >> 25, (val[5] & 0x38000000) >> 27); + len += snprintf(buf + len, sizeof(buf) - len, + "chan_idle_dur: %3d chan_idle_dur_valid: %1d\n", + (val[6] & 0x000003fc) >> 2, (val[6] & 0x00000400) >> 10); + len += snprintf(buf + len, sizeof(buf) - len, + "txfifo_valid_0: %1d txfifo_valid_1: %1d\n", + (val[6] & 0x00000800) >> 11, (val[6] & 0x00001000) >> 12); + len += snprintf(buf + len, sizeof(buf) - len, + "txfifo_dcu_num_0: %2d txfifo_dcu_num_1: %2d\n", + (val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17); + + len += snprintf(buf + len, sizeof(buf) - len, "pcu observe: 0x%x \n", + REG_READ(ah, AR_OBS_BUS_1)); + len += snprintf(buf + len, sizeof(buf) - len, + "AR_CR: 0x%x \n", REG_READ(ah, AR_CR)); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_dma = { + .read = read_file_dma, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE +}; + + +void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status) +{ + if (status) + sc->sc_debug.stats.istats.total++; + if (status & ATH9K_INT_RX) + sc->sc_debug.stats.istats.rxok++; + if (status & ATH9K_INT_RXEOL) + sc->sc_debug.stats.istats.rxeol++; + if (status & ATH9K_INT_RXORN) + sc->sc_debug.stats.istats.rxorn++; + if (status & ATH9K_INT_TX) + sc->sc_debug.stats.istats.txok++; + if (status & ATH9K_INT_TXURN) + sc->sc_debug.stats.istats.txurn++; + if (status & ATH9K_INT_MIB) + sc->sc_debug.stats.istats.mib++; + if (status & ATH9K_INT_RXPHY) + sc->sc_debug.stats.istats.rxphyerr++; + if (status & ATH9K_INT_RXKCM) + sc->sc_debug.stats.istats.rx_keycache_miss++; + if (status & ATH9K_INT_SWBA) + sc->sc_debug.stats.istats.swba++; + if (status & ATH9K_INT_BMISS) + sc->sc_debug.stats.istats.bmiss++; + if (status & ATH9K_INT_BNR) + sc->sc_debug.stats.istats.bnr++; + if (status & ATH9K_INT_CST) + sc->sc_debug.stats.istats.cst++; + if (status & ATH9K_INT_GTT) + sc->sc_debug.stats.istats.gtt++; + if (status & ATH9K_INT_TIM) + sc->sc_debug.stats.istats.tim++; + if (status & ATH9K_INT_CABEND) + sc->sc_debug.stats.istats.cabend++; + if (status & ATH9K_INT_DTIMSYNC) + sc->sc_debug.stats.istats.dtimsync++; + if (status & ATH9K_INT_DTIM) + sc->sc_debug.stats.istats.dtim++; +} + +static ssize_t read_file_interrupt(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + char buf[512]; + unsigned int len = 0; + + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "RX", sc->sc_debug.stats.istats.rxok); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "RXEOL", sc->sc_debug.stats.istats.rxeol); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "RXORN", sc->sc_debug.stats.istats.rxorn); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "TX", sc->sc_debug.stats.istats.txok); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "TXURN", sc->sc_debug.stats.istats.txurn); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "MIB", sc->sc_debug.stats.istats.mib); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "RXPHY", sc->sc_debug.stats.istats.rxphyerr); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "RXKCM", sc->sc_debug.stats.istats.rx_keycache_miss); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "SWBA", sc->sc_debug.stats.istats.swba); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "BMISS", sc->sc_debug.stats.istats.bmiss); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "BNR", sc->sc_debug.stats.istats.bnr); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "CST", sc->sc_debug.stats.istats.cst); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "GTT", sc->sc_debug.stats.istats.gtt); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "TIM", sc->sc_debug.stats.istats.tim); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "CABEND", sc->sc_debug.stats.istats.cabend); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "DTIMSYNC", sc->sc_debug.stats.istats.dtimsync); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "DTIM", sc->sc_debug.stats.istats.dtim); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "TOTAL", sc->sc_debug.stats.istats.total); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_interrupt = { + .read = read_file_interrupt, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE +}; + +int ath9k_init_debug(struct ath_softc *sc) +{ + sc->sc_debug.debug_mask = ath9k_debug; + + sc->sc_debug.debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL); + if (!sc->sc_debug.debugfs_root) + goto err; + + sc->sc_debug.debugfs_phy = debugfs_create_dir(wiphy_name(sc->hw->wiphy), + sc->sc_debug.debugfs_root); + if (!sc->sc_debug.debugfs_phy) + goto err; + + sc->sc_debug.debugfs_dma = debugfs_create_file("dma", S_IRUGO, + sc->sc_debug.debugfs_phy, sc, &fops_dma); + if (!sc->sc_debug.debugfs_dma) + goto err; + + sc->sc_debug.debugfs_interrupt = debugfs_create_file("interrupt", + S_IRUGO, + sc->sc_debug.debugfs_phy, + sc, &fops_interrupt); + if (!sc->sc_debug.debugfs_interrupt) + goto err; + + return 0; +err: + ath9k_exit_debug(sc); + return -ENOMEM; +} + +void ath9k_exit_debug(struct ath_softc *sc) +{ + debugfs_remove(sc->sc_debug.debugfs_interrupt); + debugfs_remove(sc->sc_debug.debugfs_dma); + debugfs_remove(sc->sc_debug.debugfs_phy); + debugfs_remove(sc->sc_debug.debugfs_root); +} diff --git a/drivers/net/wireless/ath9k/eeprom.c b/drivers/net/wireless/ath9k/eeprom.c new file mode 100644 index 0000000000000000000000000000000000000000..acd6c5374d44c1cca46ecaca40009f9051ec11cf --- /dev/null +++ b/drivers/net/wireless/ath9k/eeprom.c @@ -0,0 +1,2824 @@ +/* + * Copyright (c) 2008 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "core.h" +#include "hw.h" +#include "reg.h" +#include "phy.h" + +static void ath9k_hw_analog_shift_rmw(struct ath_hal *ah, + u32 reg, u32 mask, + u32 shift, u32 val) +{ + u32 regVal; + + regVal = REG_READ(ah, reg) & ~mask; + regVal |= (val << shift) & mask; + + REG_WRITE(ah, reg, regVal); + + if (ah->ah_config.analog_shiftreg) + udelay(100); + + return; +} + +static inline u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz) +{ + + if (fbin == AR5416_BCHAN_UNUSED) + return fbin; + + return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin)); +} + +static inline int16_t ath9k_hw_interpolate(u16 target, + u16 srcLeft, u16 srcRight, + int16_t targetLeft, + int16_t targetRight) +{ + int16_t rv; + + if (srcRight == srcLeft) { + rv = targetLeft; + } else { + rv = (int16_t) (((target - srcLeft) * targetRight + + (srcRight - target) * targetLeft) / + (srcRight - srcLeft)); + } + return rv; +} + +static inline bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, + u16 listSize, u16 *indexL, + u16 *indexR) +{ + u16 i; + + if (target <= pList[0]) { + *indexL = *indexR = 0; + return true; + } + if (target >= pList[listSize - 1]) { + *indexL = *indexR = (u16) (listSize - 1); + return true; + } + + for (i = 0; i < listSize - 1; i++) { + if (pList[i] == target) { + *indexL = *indexR = i; + return true; + } + if (target < pList[i + 1]) { + *indexL = i; + *indexR = (u16) (i + 1); + return false; + } + } + return false; +} + +static bool ath9k_hw_eeprom_read(struct ath_hal *ah, u32 off, u16 *data) +{ + (void)REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S)); + + if (!ath9k_hw_wait(ah, + AR_EEPROM_STATUS_DATA, + AR_EEPROM_STATUS_DATA_BUSY | + AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0)) { + return false; + } + + *data = MS(REG_READ(ah, AR_EEPROM_STATUS_DATA), + AR_EEPROM_STATUS_DATA_VAL); + + return true; +} + +static int ath9k_hw_flash_map(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + ahp->ah_cal_mem = ioremap(AR5416_EEPROM_START_ADDR, AR5416_EEPROM_MAX); + + if (!ahp->ah_cal_mem) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "cannot remap eeprom region \n"); + return -EIO; + } + + return 0; +} + +static bool ath9k_hw_flash_read(struct ath_hal *ah, u32 off, u16 *data) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + *data = ioread16(ahp->ah_cal_mem + off); + + return true; +} + +static inline bool ath9k_hw_nvram_read(struct ath_hal *ah, u32 off, u16 *data) +{ + if (ath9k_hw_use_flash(ah)) + return ath9k_hw_flash_read(ah, off, data); + else + return ath9k_hw_eeprom_read(ah, off, data); +} + +static bool ath9k_hw_fill_4k_eeprom(struct ath_hal *ah) +{ +#define SIZE_EEPROM_4K (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_4k *eep = &ahp->ah_eeprom.map4k; + u16 *eep_data; + int addr, eep_start_loc = 0; + + eep_start_loc = 64; + + if (!ath9k_hw_use_flash(ah)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Reading from EEPROM, not flash\n"); + } + + eep_data = (u16 *)eep; + + for (addr = 0; addr < SIZE_EEPROM_4K; addr++) { + if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Unable to read eeprom region \n"); + return false; + } + eep_data++; + } + return true; +#undef SIZE_EEPROM_4K +} + +static bool ath9k_hw_fill_def_eeprom(struct ath_hal *ah) +{ +#define SIZE_EEPROM_DEF (sizeof(struct ar5416_eeprom_def) / sizeof(u16)) + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def; + u16 *eep_data; + int addr, ar5416_eep_start_loc = 0x100; + + eep_data = (u16 *)eep; + + for (addr = 0; addr < SIZE_EEPROM_DEF; addr++) { + if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc, + eep_data)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Unable to read eeprom region\n"); + return false; + } + eep_data++; + } + return true; +#undef SIZE_EEPROM_DEF +} + +static bool (*ath9k_fill_eeprom[]) (struct ath_hal *) = { + ath9k_hw_fill_def_eeprom, + ath9k_hw_fill_4k_eeprom +}; + +static inline bool ath9k_hw_fill_eeprom(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + return ath9k_fill_eeprom[ahp->ah_eep_map](ah); +} + +static int ath9k_hw_check_def_eeprom(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_def *eep = + (struct ar5416_eeprom_def *) &ahp->ah_eeprom.def; + u16 *eepdata, temp, magic, magic2; + u32 sum = 0, el; + bool need_swap = false; + int i, addr, size; + + if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, + &magic)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Reading Magic # failed\n"); + return false; + } + + if (!ath9k_hw_use_flash(ah)) { + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Read Magic = 0x%04X\n", magic); + + if (magic != AR5416_EEPROM_MAGIC) { + magic2 = swab16(magic); + + if (magic2 == AR5416_EEPROM_MAGIC) { + size = sizeof(struct ar5416_eeprom_def); + need_swap = true; + eepdata = (u16 *) (&ahp->ah_eeprom); + + for (addr = 0; addr < size / sizeof(u16); addr++) { + temp = swab16(*eepdata); + *eepdata = temp; + eepdata++; + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "0x%04X ", *eepdata); + + if (((addr + 1) % 6) == 0) + DPRINTF(ah->ah_sc, + ATH_DBG_EEPROM, "\n"); + } + } else { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Invalid EEPROM Magic. " + "endianness mismatch.\n"); + return -EINVAL; + } + } + } + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", + need_swap ? "True" : "False"); + + if (need_swap) + el = swab16(ahp->ah_eeprom.def.baseEepHeader.length); + else + el = ahp->ah_eeprom.def.baseEepHeader.length; + + if (el > sizeof(struct ar5416_eeprom_def)) + el = sizeof(struct ar5416_eeprom_def) / sizeof(u16); + else + el = el / sizeof(u16); + + eepdata = (u16 *)(&ahp->ah_eeprom); + + for (i = 0; i < el; i++) + sum ^= *eepdata++; + + if (need_swap) { + u32 integer, j; + u16 word; + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "EEPROM Endianness is not native.. Changing \n"); + + word = swab16(eep->baseEepHeader.length); + eep->baseEepHeader.length = word; + + word = swab16(eep->baseEepHeader.checksum); + eep->baseEepHeader.checksum = word; + + word = swab16(eep->baseEepHeader.version); + eep->baseEepHeader.version = word; + + word = swab16(eep->baseEepHeader.regDmn[0]); + eep->baseEepHeader.regDmn[0] = word; + + word = swab16(eep->baseEepHeader.regDmn[1]); + eep->baseEepHeader.regDmn[1] = word; + + word = swab16(eep->baseEepHeader.rfSilent); + eep->baseEepHeader.rfSilent = word; + + word = swab16(eep->baseEepHeader.blueToothOptions); + eep->baseEepHeader.blueToothOptions = word; + + word = swab16(eep->baseEepHeader.deviceCap); + eep->baseEepHeader.deviceCap = word; + + for (j = 0; j < ARRAY_SIZE(eep->modalHeader); j++) { + struct modal_eep_header *pModal = + &eep->modalHeader[j]; + integer = swab32(pModal->antCtrlCommon); + pModal->antCtrlCommon = integer; + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + integer = swab32(pModal->antCtrlChain[i]); + pModal->antCtrlChain[i] = integer; + } + + for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { + word = swab16(pModal->spurChans[i].spurChan); + pModal->spurChans[i].spurChan = word; + } + } + } + + if (sum != 0xffff || ar5416_get_eep_ver(ahp) != AR5416_EEP_VER || + ar5416_get_eep_rev(ahp) < AR5416_EEP_NO_BACK_VER) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Bad EEPROM checksum 0x%x or revision 0x%04x\n", + sum, ar5416_get_eep_ver(ahp)); + return -EINVAL; + } + + return 0; +} + +static int ath9k_hw_check_4k_eeprom(struct ath_hal *ah) +{ +#define EEPROM_4K_SIZE (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_4k *eep = + (struct ar5416_eeprom_4k *) &ahp->ah_eeprom.map4k; + u16 *eepdata, temp, magic, magic2; + u32 sum = 0, el; + bool need_swap = false; + int i, addr; + + + if (!ath9k_hw_use_flash(ah)) { + + if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, + &magic)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Reading Magic # failed\n"); + return false; + } + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Read Magic = 0x%04X\n", magic); + + if (magic != AR5416_EEPROM_MAGIC) { + magic2 = swab16(magic); + + if (magic2 == AR5416_EEPROM_MAGIC) { + need_swap = true; + eepdata = (u16 *) (&ahp->ah_eeprom); + + for (addr = 0; addr < EEPROM_4K_SIZE; addr++) { + temp = swab16(*eepdata); + *eepdata = temp; + eepdata++; + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "0x%04X ", *eepdata); + + if (((addr + 1) % 6) == 0) + DPRINTF(ah->ah_sc, + ATH_DBG_EEPROM, "\n"); + } + } else { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Invalid EEPROM Magic. " + "endianness mismatch.\n"); + return -EINVAL; + } + } + } + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", + need_swap ? "True" : "False"); + + if (need_swap) + el = swab16(ahp->ah_eeprom.map4k.baseEepHeader.length); + else + el = ahp->ah_eeprom.map4k.baseEepHeader.length; + + if (el > sizeof(struct ar5416_eeprom_def)) + el = sizeof(struct ar5416_eeprom_4k) / sizeof(u16); + else + el = el / sizeof(u16); + + eepdata = (u16 *)(&ahp->ah_eeprom); + + for (i = 0; i < el; i++) + sum ^= *eepdata++; + + if (need_swap) { + u32 integer; + u16 word; + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "EEPROM Endianness is not native.. Changing \n"); + + word = swab16(eep->baseEepHeader.length); + eep->baseEepHeader.length = word; + + word = swab16(eep->baseEepHeader.checksum); + eep->baseEepHeader.checksum = word; + + word = swab16(eep->baseEepHeader.version); + eep->baseEepHeader.version = word; + + word = swab16(eep->baseEepHeader.regDmn[0]); + eep->baseEepHeader.regDmn[0] = word; + + word = swab16(eep->baseEepHeader.regDmn[1]); + eep->baseEepHeader.regDmn[1] = word; + + word = swab16(eep->baseEepHeader.rfSilent); + eep->baseEepHeader.rfSilent = word; + + word = swab16(eep->baseEepHeader.blueToothOptions); + eep->baseEepHeader.blueToothOptions = word; + + word = swab16(eep->baseEepHeader.deviceCap); + eep->baseEepHeader.deviceCap = word; + + integer = swab32(eep->modalHeader.antCtrlCommon); + eep->modalHeader.antCtrlCommon = integer; + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + integer = swab32(eep->modalHeader.antCtrlChain[i]); + eep->modalHeader.antCtrlChain[i] = integer; + } + + for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { + word = swab16(eep->modalHeader.spurChans[i].spurChan); + eep->modalHeader.spurChans[i].spurChan = word; + } + } + + if (sum != 0xffff || ar5416_get_eep4k_ver(ahp) != AR5416_EEP_VER || + ar5416_get_eep4k_rev(ahp) < AR5416_EEP_NO_BACK_VER) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Bad EEPROM checksum 0x%x or revision 0x%04x\n", + sum, ar5416_get_eep4k_ver(ahp)); + return -EINVAL; + } + + return 0; +#undef EEPROM_4K_SIZE +} + +static int (*ath9k_check_eeprom[]) (struct ath_hal *) = { + ath9k_hw_check_def_eeprom, + ath9k_hw_check_4k_eeprom +}; + +static inline int ath9k_hw_check_eeprom(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + return ath9k_check_eeprom[ahp->ah_eep_map](ah); +} + +static inline bool ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, + u8 *pVpdList, u16 numIntercepts, + u8 *pRetVpdList) +{ + u16 i, k; + u8 currPwr = pwrMin; + u16 idxL = 0, idxR = 0; + + for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) { + ath9k_hw_get_lower_upper_index(currPwr, pPwrList, + numIntercepts, &(idxL), + &(idxR)); + if (idxR < 1) + idxR = 1; + if (idxL == numIntercepts - 1) + idxL = (u16) (numIntercepts - 2); + if (pPwrList[idxL] == pPwrList[idxR]) + k = pVpdList[idxL]; + else + k = (u16)(((currPwr - pPwrList[idxL]) * pVpdList[idxR] + + (pPwrList[idxR] - currPwr) * pVpdList[idxL]) / + (pPwrList[idxR] - pPwrList[idxL])); + pRetVpdList[i] = (u8) k; + currPwr += 2; + } + + return true; +} + +static void ath9k_hw_get_4k_gain_boundaries_pdadcs(struct ath_hal *ah, + struct ath9k_channel *chan, + struct cal_data_per_freq_4k *pRawDataSet, + u8 *bChans, u16 availPiers, + u16 tPdGainOverlap, int16_t *pMinCalPower, + u16 *pPdGainBoundaries, u8 *pPDADCValues, + u16 numXpdGains) +{ +#define TMP_VAL_VPD_TABLE \ + ((vpdTableI[i][sizeCurrVpdTable - 1] + (ss - maxIndex + 1) * vpdStep)); + int i, j, k; + int16_t ss; + u16 idxL = 0, idxR = 0, numPiers; + static u8 vpdTableL[AR5416_EEP4K_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + static u8 vpdTableR[AR5416_EEP4K_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + static u8 vpdTableI[AR5416_EEP4K_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + + u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; + u8 minPwrT4[AR5416_EEP4K_NUM_PD_GAINS]; + u8 maxPwrT4[AR5416_EEP4K_NUM_PD_GAINS]; + int16_t vpdStep; + int16_t tmpVal; + u16 sizeCurrVpdTable, maxIndex, tgtIndex; + bool match; + int16_t minDelta = 0; + struct chan_centers centers; +#define PD_GAIN_BOUNDARY_DEFAULT 58; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + for (numPiers = 0; numPiers < availPiers; numPiers++) { + if (bChans[numPiers] == AR5416_BCHAN_UNUSED) + break; + } + + match = ath9k_hw_get_lower_upper_index( + (u8)FREQ2FBIN(centers.synth_center, + IS_CHAN_2GHZ(chan)), bChans, numPiers, + &idxL, &idxR); + + if (match) { + for (i = 0; i < numXpdGains; i++) { + minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; + maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pRawDataSet[idxL].pwrPdg[i], + pRawDataSet[idxL].vpdPdg[i], + AR5416_EEP4K_PD_GAIN_ICEPTS, + vpdTableI[i]); + } + } else { + for (i = 0; i < numXpdGains; i++) { + pVpdL = pRawDataSet[idxL].vpdPdg[i]; + pPwrL = pRawDataSet[idxL].pwrPdg[i]; + pVpdR = pRawDataSet[idxR].vpdPdg[i]; + pPwrR = pRawDataSet[idxR].pwrPdg[i]; + + minPwrT4[i] = max(pPwrL[0], pPwrR[0]); + + maxPwrT4[i] = + min(pPwrL[AR5416_EEP4K_PD_GAIN_ICEPTS - 1], + pPwrR[AR5416_EEP4K_PD_GAIN_ICEPTS - 1]); + + + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pPwrL, pVpdL, + AR5416_EEP4K_PD_GAIN_ICEPTS, + vpdTableL[i]); + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pPwrR, pVpdR, + AR5416_EEP4K_PD_GAIN_ICEPTS, + vpdTableR[i]); + + for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { + vpdTableI[i][j] = + (u8)(ath9k_hw_interpolate((u16) + FREQ2FBIN(centers. + synth_center, + IS_CHAN_2GHZ + (chan)), + bChans[idxL], bChans[idxR], + vpdTableL[i][j], vpdTableR[i][j])); + } + } + } + + *pMinCalPower = (int16_t)(minPwrT4[0] / 2); + + k = 0; + + for (i = 0; i < numXpdGains; i++) { + if (i == (numXpdGains - 1)) + pPdGainBoundaries[i] = + (u16)(maxPwrT4[i] / 2); + else + pPdGainBoundaries[i] = + (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4); + + pPdGainBoundaries[i] = + min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]); + + if ((i == 0) && !AR_SREV_5416_V20_OR_LATER(ah)) { + minDelta = pPdGainBoundaries[0] - 23; + pPdGainBoundaries[0] = 23; + } else { + minDelta = 0; + } + + if (i == 0) { + if (AR_SREV_9280_10_OR_LATER(ah)) + ss = (int16_t)(0 - (minPwrT4[i] / 2)); + else + ss = 0; + } else { + ss = (int16_t)((pPdGainBoundaries[i - 1] - + (minPwrT4[i] / 2)) - + tPdGainOverlap + 1 + minDelta); + } + vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); + + while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); + pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); + ss++; + } + + sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); + tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap - + (minPwrT4[i] / 2)); + maxIndex = (tgtIndex < sizeCurrVpdTable) ? + tgtIndex : sizeCurrVpdTable; + + while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) + pPDADCValues[k++] = vpdTableI[i][ss++]; + + vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - + vpdTableI[i][sizeCurrVpdTable - 2]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); + + if (tgtIndex > maxIndex) { + while ((ss <= tgtIndex) && + (k < (AR5416_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t) TMP_VAL_VPD_TABLE; + pPDADCValues[k++] = (u8)((tmpVal > 255) ? + 255 : tmpVal); + ss++; + } + } + } + + while (i < AR5416_EEP4K_PD_GAINS_IN_MASK) { + pPdGainBoundaries[i] = PD_GAIN_BOUNDARY_DEFAULT; + i++; + } + + while (k < AR5416_NUM_PDADC_VALUES) { + pPDADCValues[k] = pPDADCValues[k - 1]; + k++; + } + + return; +#undef TMP_VAL_VPD_TABLE +} + +static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hal *ah, + struct ath9k_channel *chan, + struct cal_data_per_freq *pRawDataSet, + u8 *bChans, u16 availPiers, + u16 tPdGainOverlap, int16_t *pMinCalPower, + u16 *pPdGainBoundaries, u8 *pPDADCValues, + u16 numXpdGains) +{ + int i, j, k; + int16_t ss; + u16 idxL = 0, idxR = 0, numPiers; + static u8 vpdTableL[AR5416_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + static u8 vpdTableR[AR5416_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + static u8 vpdTableI[AR5416_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + + u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; + u8 minPwrT4[AR5416_NUM_PD_GAINS]; + u8 maxPwrT4[AR5416_NUM_PD_GAINS]; + int16_t vpdStep; + int16_t tmpVal; + u16 sizeCurrVpdTable, maxIndex, tgtIndex; + bool match; + int16_t minDelta = 0; + struct chan_centers centers; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + for (numPiers = 0; numPiers < availPiers; numPiers++) { + if (bChans[numPiers] == AR5416_BCHAN_UNUSED) + break; + } + + match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center, + IS_CHAN_2GHZ(chan)), + bChans, numPiers, &idxL, &idxR); + + if (match) { + for (i = 0; i < numXpdGains; i++) { + minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; + maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pRawDataSet[idxL].pwrPdg[i], + pRawDataSet[idxL].vpdPdg[i], + AR5416_PD_GAIN_ICEPTS, + vpdTableI[i]); + } + } else { + for (i = 0; i < numXpdGains; i++) { + pVpdL = pRawDataSet[idxL].vpdPdg[i]; + pPwrL = pRawDataSet[idxL].pwrPdg[i]; + pVpdR = pRawDataSet[idxR].vpdPdg[i]; + pPwrR = pRawDataSet[idxR].pwrPdg[i]; + + minPwrT4[i] = max(pPwrL[0], pPwrR[0]); + + maxPwrT4[i] = + min(pPwrL[AR5416_PD_GAIN_ICEPTS - 1], + pPwrR[AR5416_PD_GAIN_ICEPTS - 1]); + + + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pPwrL, pVpdL, + AR5416_PD_GAIN_ICEPTS, + vpdTableL[i]); + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pPwrR, pVpdR, + AR5416_PD_GAIN_ICEPTS, + vpdTableR[i]); + + for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { + vpdTableI[i][j] = + (u8)(ath9k_hw_interpolate((u16) + FREQ2FBIN(centers. + synth_center, + IS_CHAN_2GHZ + (chan)), + bChans[idxL], bChans[idxR], + vpdTableL[i][j], vpdTableR[i][j])); + } + } + } + + *pMinCalPower = (int16_t)(minPwrT4[0] / 2); + + k = 0; + + for (i = 0; i < numXpdGains; i++) { + if (i == (numXpdGains - 1)) + pPdGainBoundaries[i] = + (u16)(maxPwrT4[i] / 2); + else + pPdGainBoundaries[i] = + (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4); + + pPdGainBoundaries[i] = + min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]); + + if ((i == 0) && !AR_SREV_5416_V20_OR_LATER(ah)) { + minDelta = pPdGainBoundaries[0] - 23; + pPdGainBoundaries[0] = 23; + } else { + minDelta = 0; + } + + if (i == 0) { + if (AR_SREV_9280_10_OR_LATER(ah)) + ss = (int16_t)(0 - (minPwrT4[i] / 2)); + else + ss = 0; + } else { + ss = (int16_t)((pPdGainBoundaries[i - 1] - + (minPwrT4[i] / 2)) - + tPdGainOverlap + 1 + minDelta); + } + vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); + + while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); + pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); + ss++; + } + + sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); + tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap - + (minPwrT4[i] / 2)); + maxIndex = (tgtIndex < sizeCurrVpdTable) ? + tgtIndex : sizeCurrVpdTable; + + while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { + pPDADCValues[k++] = vpdTableI[i][ss++]; + } + + vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - + vpdTableI[i][sizeCurrVpdTable - 2]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); + + if (tgtIndex > maxIndex) { + while ((ss <= tgtIndex) && + (k < (AR5416_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] + + (ss - maxIndex + 1) * vpdStep)); + pPDADCValues[k++] = (u8)((tmpVal > 255) ? + 255 : tmpVal); + ss++; + } + } + } + + while (i < AR5416_PD_GAINS_IN_MASK) { + pPdGainBoundaries[i] = pPdGainBoundaries[i - 1]; + i++; + } + + while (k < AR5416_NUM_PDADC_VALUES) { + pPDADCValues[k] = pPDADCValues[k - 1]; + k++; + } + + return; +} + +static void ath9k_hw_get_legacy_target_powers(struct ath_hal *ah, + struct ath9k_channel *chan, + struct cal_target_power_leg *powInfo, + u16 numChannels, + struct cal_target_power_leg *pNewPower, + u16 numRates, bool isExtTarget) +{ + struct chan_centers centers; + u16 clo, chi; + int i; + int matchIndex = -1, lowIndex = -1; + u16 freq; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + freq = (isExtTarget) ? centers.ext_center : centers.ctl_center; + + if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, + IS_CHAN_2GHZ(chan))) { + matchIndex = 0; + } else { + for (i = 0; (i < numChannels) && + (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { + if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel, + IS_CHAN_2GHZ(chan))) { + matchIndex = i; + break; + } else if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel, + IS_CHAN_2GHZ(chan))) && + (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel, + IS_CHAN_2GHZ(chan)))) { + lowIndex = i - 1; + break; + } + } + if ((matchIndex == -1) && (lowIndex == -1)) + matchIndex = i - 1; + } + + if (matchIndex != -1) { + *pNewPower = powInfo[matchIndex]; + } else { + clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel, + IS_CHAN_2GHZ(chan)); + chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel, + IS_CHAN_2GHZ(chan)); + + for (i = 0; i < numRates; i++) { + pNewPower->tPow2x[i] = + (u8)ath9k_hw_interpolate(freq, clo, chi, + powInfo[lowIndex].tPow2x[i], + powInfo[lowIndex + 1].tPow2x[i]); + } + } +} + +static void ath9k_hw_get_target_powers(struct ath_hal *ah, + struct ath9k_channel *chan, + struct cal_target_power_ht *powInfo, + u16 numChannels, + struct cal_target_power_ht *pNewPower, + u16 numRates, bool isHt40Target) +{ + struct chan_centers centers; + u16 clo, chi; + int i; + int matchIndex = -1, lowIndex = -1; + u16 freq; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + freq = isHt40Target ? centers.synth_center : centers.ctl_center; + + if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) { + matchIndex = 0; + } else { + for (i = 0; (i < numChannels) && + (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { + if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel, + IS_CHAN_2GHZ(chan))) { + matchIndex = i; + break; + } else + if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel, + IS_CHAN_2GHZ(chan))) && + (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel, + IS_CHAN_2GHZ(chan)))) { + lowIndex = i - 1; + break; + } + } + if ((matchIndex == -1) && (lowIndex == -1)) + matchIndex = i - 1; + } + + if (matchIndex != -1) { + *pNewPower = powInfo[matchIndex]; + } else { + clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel, + IS_CHAN_2GHZ(chan)); + chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel, + IS_CHAN_2GHZ(chan)); + + for (i = 0; i < numRates; i++) { + pNewPower->tPow2x[i] = (u8)ath9k_hw_interpolate(freq, + clo, chi, + powInfo[lowIndex].tPow2x[i], + powInfo[lowIndex + 1].tPow2x[i]); + } + } +} + +static u16 ath9k_hw_get_max_edge_power(u16 freq, + struct cal_ctl_edges *pRdEdgesPower, + bool is2GHz, int num_band_edges) +{ + u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + int i; + + for (i = 0; (i < num_band_edges) && + (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) { + if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) { + twiceMaxEdgePower = pRdEdgesPower[i].tPower; + break; + } else if ((i > 0) && + (freq < ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, + is2GHz))) { + if (ath9k_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel, + is2GHz) < freq && + pRdEdgesPower[i - 1].flag) { + twiceMaxEdgePower = + pRdEdgesPower[i - 1].tPower; + } + break; + } + } + + return twiceMaxEdgePower; +} + +static bool ath9k_hw_set_def_power_cal_table(struct ath_hal *ah, + struct ath9k_channel *chan, + int16_t *pTxPowerIndexOffset) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_def *pEepData = &ahp->ah_eeprom.def; + struct cal_data_per_freq *pRawDataset; + u8 *pCalBChans = NULL; + u16 pdGainOverlap_t2; + static u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; + u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK]; + u16 numPiers, i, j; + int16_t tMinCalPower; + u16 numXpdGain, xpdMask; + u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 }; + u32 reg32, regOffset, regChainOffset; + int16_t modalIdx; + + modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0; + xpdMask = pEepData->modalHeader[modalIdx].xpdGain; + + if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_2) { + pdGainOverlap_t2 = + pEepData->modalHeader[modalIdx].pdGainOverlap; + } else { + pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), + AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); + } + + if (IS_CHAN_2GHZ(chan)) { + pCalBChans = pEepData->calFreqPier2G; + numPiers = AR5416_NUM_2G_CAL_PIERS; + } else { + pCalBChans = pEepData->calFreqPier5G; + numPiers = AR5416_NUM_5G_CAL_PIERS; + } + + numXpdGain = 0; + + for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { + if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) { + if (numXpdGain >= AR5416_NUM_PD_GAINS) + break; + xpdGainValues[numXpdGain] = + (u16)(AR5416_PD_GAINS_IN_MASK - i); + numXpdGain++; + } + } + + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, + (numXpdGain - 1) & 0x3); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, + xpdGainValues[0]); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, + xpdGainValues[1]); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, + xpdGainValues[2]); + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + if (AR_SREV_5416_V20_OR_LATER(ah) && + (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5) && + (i != 0)) { + regChainOffset = (i == 1) ? 0x2000 : 0x1000; + } else + regChainOffset = i * 0x1000; + + if (pEepData->baseEepHeader.txMask & (1 << i)) { + if (IS_CHAN_2GHZ(chan)) + pRawDataset = pEepData->calPierData2G[i]; + else + pRawDataset = pEepData->calPierData5G[i]; + + ath9k_hw_get_def_gain_boundaries_pdadcs(ah, chan, + pRawDataset, pCalBChans, + numPiers, pdGainOverlap_t2, + &tMinCalPower, gainBoundaries, + pdadcValues, numXpdGain); + + if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) { + REG_WRITE(ah, + AR_PHY_TPCRG5 + regChainOffset, + SM(pdGainOverlap_t2, + AR_PHY_TPCRG5_PD_GAIN_OVERLAP) + | SM(gainBoundaries[0], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) + | SM(gainBoundaries[1], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) + | SM(gainBoundaries[2], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) + | SM(gainBoundaries[3], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); + } + + regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; + for (j = 0; j < 32; j++) { + reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) | + ((pdadcValues[4 * j + 1] & 0xFF) << 8) | + ((pdadcValues[4 * j + 2] & 0xFF) << 16)| + ((pdadcValues[4 * j + 3] & 0xFF) << 24); + REG_WRITE(ah, regOffset, reg32); + + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "PDADC (%d,%4x): %4.4x %8.8x\n", + i, regChainOffset, regOffset, + reg32); + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "PDADC: Chain %d | PDADC %3d " + "Value %3d | PDADC %3d Value %3d | " + "PDADC %3d Value %3d | PDADC %3d " + "Value %3d |\n", + i, 4 * j, pdadcValues[4 * j], + 4 * j + 1, pdadcValues[4 * j + 1], + 4 * j + 2, pdadcValues[4 * j + 2], + 4 * j + 3, + pdadcValues[4 * j + 3]); + + regOffset += 4; + } + } + } + + *pTxPowerIndexOffset = 0; + + return true; +} + +static bool ath9k_hw_set_4k_power_cal_table(struct ath_hal *ah, + struct ath9k_channel *chan, + int16_t *pTxPowerIndexOffset) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_4k *pEepData = &ahp->ah_eeprom.map4k; + struct cal_data_per_freq_4k *pRawDataset; + u8 *pCalBChans = NULL; + u16 pdGainOverlap_t2; + static u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; + u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK]; + u16 numPiers, i, j; + int16_t tMinCalPower; + u16 numXpdGain, xpdMask; + u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 }; + u32 reg32, regOffset, regChainOffset; + + xpdMask = pEepData->modalHeader.xpdGain; + + if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_2) { + pdGainOverlap_t2 = + pEepData->modalHeader.pdGainOverlap; + } else { + pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), + AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); + } + + pCalBChans = pEepData->calFreqPier2G; + numPiers = AR5416_NUM_2G_CAL_PIERS; + + numXpdGain = 0; + + for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { + if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) { + if (numXpdGain >= AR5416_NUM_PD_GAINS) + break; + xpdGainValues[numXpdGain] = + (u16)(AR5416_PD_GAINS_IN_MASK - i); + numXpdGain++; + } + } + + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, + (numXpdGain - 1) & 0x3); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, + xpdGainValues[0]); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, + xpdGainValues[1]); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, + xpdGainValues[2]); + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + if (AR_SREV_5416_V20_OR_LATER(ah) && + (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5) && + (i != 0)) { + regChainOffset = (i == 1) ? 0x2000 : 0x1000; + } else + regChainOffset = i * 0x1000; + + if (pEepData->baseEepHeader.txMask & (1 << i)) { + pRawDataset = pEepData->calPierData2G[i]; + + ath9k_hw_get_4k_gain_boundaries_pdadcs(ah, chan, + pRawDataset, pCalBChans, + numPiers, pdGainOverlap_t2, + &tMinCalPower, gainBoundaries, + pdadcValues, numXpdGain); + + if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) { + REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset, + SM(pdGainOverlap_t2, + AR_PHY_TPCRG5_PD_GAIN_OVERLAP) + | SM(gainBoundaries[0], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) + | SM(gainBoundaries[1], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) + | SM(gainBoundaries[2], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) + | SM(gainBoundaries[3], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); + } + + regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; + for (j = 0; j < 32; j++) { + reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) | + ((pdadcValues[4 * j + 1] & 0xFF) << 8) | + ((pdadcValues[4 * j + 2] & 0xFF) << 16)| + ((pdadcValues[4 * j + 3] & 0xFF) << 24); + REG_WRITE(ah, regOffset, reg32); + + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "PDADC (%d,%4x): %4.4x %8.8x\n", + i, regChainOffset, regOffset, + reg32); + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "PDADC: Chain %d | " + "PDADC %3d Value %3d | " + "PDADC %3d Value %3d | " + "PDADC %3d Value %3d | " + "PDADC %3d Value %3d |\n", + i, 4 * j, pdadcValues[4 * j], + 4 * j + 1, pdadcValues[4 * j + 1], + 4 * j + 2, pdadcValues[4 * j + 2], + 4 * j + 3, + pdadcValues[4 * j + 3]); + + regOffset += 4; + } + } + } + + *pTxPowerIndexOffset = 0; + + return true; +} + +static bool ath9k_hw_set_def_power_per_rate_table(struct ath_hal *ah, + struct ath9k_channel *chan, + int16_t *ratesArray, + u16 cfgCtl, + u16 AntennaReduction, + u16 twiceMaxRegulatoryPower, + u16 powerLimit) +{ +#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */ +#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 /* 10*log10(3)*2 */ + + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_def *pEepData = &ahp->ah_eeprom.def; + u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + static const u16 tpScaleReductionTable[5] = + { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; + + int i; + int16_t twiceLargestAntenna; + struct cal_ctl_data *rep; + struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { + 0, { 0, 0, 0, 0} + }; + struct cal_target_power_leg targetPowerOfdmExt = { + 0, { 0, 0, 0, 0} }, targetPowerCckExt = { + 0, { 0, 0, 0, 0 } + }; + struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = { + 0, {0, 0, 0, 0} + }; + u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; + u16 ctlModesFor11a[] = + { CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 }; + u16 ctlModesFor11g[] = + { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, + CTL_2GHT40 + }; + u16 numCtlModes, *pCtlMode, ctlMode, freq; + struct chan_centers centers; + int tx_chainmask; + u16 twiceMinEdgePower; + + tx_chainmask = ahp->ah_txchainmask; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + twiceLargestAntenna = max( + pEepData->modalHeader + [IS_CHAN_2GHZ(chan)].antennaGainCh[0], + pEepData->modalHeader + [IS_CHAN_2GHZ(chan)].antennaGainCh[1]); + + twiceLargestAntenna = max((u8)twiceLargestAntenna, + pEepData->modalHeader + [IS_CHAN_2GHZ(chan)].antennaGainCh[2]); + + twiceLargestAntenna = (int16_t)min(AntennaReduction - + twiceLargestAntenna, 0); + + maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; + + if (ah->ah_tpScale != ATH9K_TP_SCALE_MAX) { + maxRegAllowedPower -= + (tpScaleReductionTable[(ah->ah_tpScale)] * 2); + } + + scaledPower = min(powerLimit, maxRegAllowedPower); + + switch (ar5416_get_ntxchains(tx_chainmask)) { + case 1: + break; + case 2: + scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN; + break; + case 3: + scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN; + break; + } + + scaledPower = max((u16)0, scaledPower); + + if (IS_CHAN_2GHZ(chan)) { + numCtlModes = ARRAY_SIZE(ctlModesFor11g) - + SUB_NUM_CTL_MODES_AT_2G_40; + pCtlMode = ctlModesFor11g; + + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPowerCck, + AR5416_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCck, 4, false); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower2G, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdm, 4, false); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower2GHT20, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerHt20, 8, false); + + if (IS_CHAN_HT40(chan)) { + numCtlModes = ARRAY_SIZE(ctlModesFor11g); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower2GHT40, + AR5416_NUM_2G_40_TARGET_POWERS, + &targetPowerHt40, 8, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPowerCck, + AR5416_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCckExt, 4, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower2G, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdmExt, 4, true); + } + } else { + numCtlModes = ARRAY_SIZE(ctlModesFor11a) - + SUB_NUM_CTL_MODES_AT_5G_40; + pCtlMode = ctlModesFor11a; + + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower5G, + AR5416_NUM_5G_20_TARGET_POWERS, + &targetPowerOfdm, 4, false); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower5GHT20, + AR5416_NUM_5G_20_TARGET_POWERS, + &targetPowerHt20, 8, false); + + if (IS_CHAN_HT40(chan)) { + numCtlModes = ARRAY_SIZE(ctlModesFor11a); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower5GHT40, + AR5416_NUM_5G_40_TARGET_POWERS, + &targetPowerHt40, 8, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower5G, + AR5416_NUM_5G_20_TARGET_POWERS, + &targetPowerOfdmExt, 4, true); + } + } + + for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { + bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || + (pCtlMode[ctlMode] == CTL_2GHT40); + if (isHt40CtlMode) + freq = centers.synth_center; + else if (pCtlMode[ctlMode] & EXT_ADDITIVE) + freq = centers.ext_center; + else + freq = centers.ctl_center; + + if (ar5416_get_eep_ver(ahp) == 14 && ar5416_get_eep_rev(ahp) <= 2) + twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, " + "EXT_ADDITIVE %d\n", + ctlMode, numCtlModes, isHt40CtlMode, + (pCtlMode[ctlMode] & EXT_ADDITIVE)); + + for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + " LOOP-Ctlidx %d: cfgCtl 0x%2.2x " + "pCtlMode 0x%2.2x ctlIndex 0x%2.2x " + "chan %d\n", + i, cfgCtl, pCtlMode[ctlMode], + pEepData->ctlIndex[i], chan->channel); + + if ((((cfgCtl & ~CTL_MODE_M) | + (pCtlMode[ctlMode] & CTL_MODE_M)) == + pEepData->ctlIndex[i]) || + (((cfgCtl & ~CTL_MODE_M) | + (pCtlMode[ctlMode] & CTL_MODE_M)) == + ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) { + rep = &(pEepData->ctlData[i]); + + twiceMinEdgePower = ath9k_hw_get_max_edge_power(freq, + rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1], + IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES); + + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + " MATCH-EE_IDX %d: ch %d is2 %d " + "2xMinEdge %d chainmask %d chains %d\n", + i, freq, IS_CHAN_2GHZ(chan), + twiceMinEdgePower, tx_chainmask, + ar5416_get_ntxchains + (tx_chainmask)); + if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { + twiceMaxEdgePower = min(twiceMaxEdgePower, + twiceMinEdgePower); + } else { + twiceMaxEdgePower = twiceMinEdgePower; + break; + } + } + } + + minCtlPower = min(twiceMaxEdgePower, scaledPower); + + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + " SEL-Min ctlMode %d pCtlMode %d " + "2xMaxEdge %d sP %d minCtlPwr %d\n", + ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, + scaledPower, minCtlPower); + + switch (pCtlMode[ctlMode]) { + case CTL_11B: + for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) { + targetPowerCck.tPow2x[i] = + min((u16)targetPowerCck.tPow2x[i], + minCtlPower); + } + break; + case CTL_11A: + case CTL_11G: + for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) { + targetPowerOfdm.tPow2x[i] = + min((u16)targetPowerOfdm.tPow2x[i], + minCtlPower); + } + break; + case CTL_5GHT20: + case CTL_2GHT20: + for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) { + targetPowerHt20.tPow2x[i] = + min((u16)targetPowerHt20.tPow2x[i], + minCtlPower); + } + break; + case CTL_11B_EXT: + targetPowerCckExt.tPow2x[0] = min((u16) + targetPowerCckExt.tPow2x[0], + minCtlPower); + break; + case CTL_11A_EXT: + case CTL_11G_EXT: + targetPowerOfdmExt.tPow2x[0] = min((u16) + targetPowerOfdmExt.tPow2x[0], + minCtlPower); + break; + case CTL_5GHT40: + case CTL_2GHT40: + for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { + targetPowerHt40.tPow2x[i] = + min((u16)targetPowerHt40.tPow2x[i], + minCtlPower); + } + break; + default: + break; + } + } + + ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = + ratesArray[rate18mb] = ratesArray[rate24mb] = + targetPowerOfdm.tPow2x[0]; + ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; + ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; + ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; + ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; + + for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) + ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; + + if (IS_CHAN_2GHZ(chan)) { + ratesArray[rate1l] = targetPowerCck.tPow2x[0]; + ratesArray[rate2s] = ratesArray[rate2l] = + targetPowerCck.tPow2x[1]; + ratesArray[rate5_5s] = ratesArray[rate5_5l] = + targetPowerCck.tPow2x[2]; + ; + ratesArray[rate11s] = ratesArray[rate11l] = + targetPowerCck.tPow2x[3]; + ; + } + if (IS_CHAN_HT40(chan)) { + for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { + ratesArray[rateHt40_0 + i] = + targetPowerHt40.tPow2x[i]; + } + ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; + ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; + ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; + if (IS_CHAN_2GHZ(chan)) { + ratesArray[rateExtCck] = + targetPowerCckExt.tPow2x[0]; + } + } + return true; +} + +static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hal *ah, + struct ath9k_channel *chan, + int16_t *ratesArray, + u16 cfgCtl, + u16 AntennaReduction, + u16 twiceMaxRegulatoryPower, + u16 powerLimit) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_4k *pEepData = &ahp->ah_eeprom.map4k; + u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + static const u16 tpScaleReductionTable[5] = + { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; + + int i; + int16_t twiceLargestAntenna; + struct cal_ctl_data_4k *rep; + struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { + 0, { 0, 0, 0, 0} + }; + struct cal_target_power_leg targetPowerOfdmExt = { + 0, { 0, 0, 0, 0} }, targetPowerCckExt = { + 0, { 0, 0, 0, 0 } + }; + struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = { + 0, {0, 0, 0, 0} + }; + u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; + u16 ctlModesFor11g[] = + { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, + CTL_2GHT40 + }; + u16 numCtlModes, *pCtlMode, ctlMode, freq; + struct chan_centers centers; + int tx_chainmask; + u16 twiceMinEdgePower; + + tx_chainmask = ahp->ah_txchainmask; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + twiceLargestAntenna = pEepData->modalHeader.antennaGainCh[0]; + + twiceLargestAntenna = (int16_t)min(AntennaReduction - + twiceLargestAntenna, 0); + + maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; + + if (ah->ah_tpScale != ATH9K_TP_SCALE_MAX) { + maxRegAllowedPower -= + (tpScaleReductionTable[(ah->ah_tpScale)] * 2); + } + + scaledPower = min(powerLimit, maxRegAllowedPower); + scaledPower = max((u16)0, scaledPower); + + numCtlModes = ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; + pCtlMode = ctlModesFor11g; + + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPowerCck, + AR5416_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCck, 4, false); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower2G, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdm, 4, false); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower2GHT20, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerHt20, 8, false); + + if (IS_CHAN_HT40(chan)) { + numCtlModes = ARRAY_SIZE(ctlModesFor11g); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower2GHT40, + AR5416_NUM_2G_40_TARGET_POWERS, + &targetPowerHt40, 8, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPowerCck, + AR5416_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCckExt, 4, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower2G, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdmExt, 4, true); + } + + for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { + bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || + (pCtlMode[ctlMode] == CTL_2GHT40); + if (isHt40CtlMode) + freq = centers.synth_center; + else if (pCtlMode[ctlMode] & EXT_ADDITIVE) + freq = centers.ext_center; + else + freq = centers.ctl_center; + + if (ar5416_get_eep_ver(ahp) == 14 && + ar5416_get_eep_rev(ahp) <= 2) + twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, " + "EXT_ADDITIVE %d\n", + ctlMode, numCtlModes, isHt40CtlMode, + (pCtlMode[ctlMode] & EXT_ADDITIVE)); + + for (i = 0; (i < AR5416_NUM_CTLS) && + pEepData->ctlIndex[i]; i++) { + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + " LOOP-Ctlidx %d: cfgCtl 0x%2.2x " + "pCtlMode 0x%2.2x ctlIndex 0x%2.2x " + "chan %d\n", + i, cfgCtl, pCtlMode[ctlMode], + pEepData->ctlIndex[i], chan->channel); + + if ((((cfgCtl & ~CTL_MODE_M) | + (pCtlMode[ctlMode] & CTL_MODE_M)) == + pEepData->ctlIndex[i]) || + (((cfgCtl & ~CTL_MODE_M) | + (pCtlMode[ctlMode] & CTL_MODE_M)) == + ((pEepData->ctlIndex[i] & CTL_MODE_M) | + SD_NO_CTL))) { + rep = &(pEepData->ctlData[i]); + + twiceMinEdgePower = + ath9k_hw_get_max_edge_power(freq, + rep->ctlEdges[ar5416_get_ntxchains + (tx_chainmask) - 1], + IS_CHAN_2GHZ(chan), + AR5416_EEP4K_NUM_BAND_EDGES); + + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + " MATCH-EE_IDX %d: ch %d is2 %d " + "2xMinEdge %d chainmask %d chains %d\n", + i, freq, IS_CHAN_2GHZ(chan), + twiceMinEdgePower, tx_chainmask, + ar5416_get_ntxchains + (tx_chainmask)); + if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { + twiceMaxEdgePower = + min(twiceMaxEdgePower, + twiceMinEdgePower); + } else { + twiceMaxEdgePower = twiceMinEdgePower; + break; + } + } + } + + minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower); + + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + " SEL-Min ctlMode %d pCtlMode %d " + "2xMaxEdge %d sP %d minCtlPwr %d\n", + ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, + scaledPower, minCtlPower); + + switch (pCtlMode[ctlMode]) { + case CTL_11B: + for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); + i++) { + targetPowerCck.tPow2x[i] = + min((u16)targetPowerCck.tPow2x[i], + minCtlPower); + } + break; + case CTL_11G: + for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); + i++) { + targetPowerOfdm.tPow2x[i] = + min((u16)targetPowerOfdm.tPow2x[i], + minCtlPower); + } + break; + case CTL_2GHT20: + for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); + i++) { + targetPowerHt20.tPow2x[i] = + min((u16)targetPowerHt20.tPow2x[i], + minCtlPower); + } + break; + case CTL_11B_EXT: + targetPowerCckExt.tPow2x[0] = min((u16) + targetPowerCckExt.tPow2x[0], + minCtlPower); + break; + case CTL_11G_EXT: + targetPowerOfdmExt.tPow2x[0] = min((u16) + targetPowerOfdmExt.tPow2x[0], + minCtlPower); + break; + case CTL_2GHT40: + for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); + i++) { + targetPowerHt40.tPow2x[i] = + min((u16)targetPowerHt40.tPow2x[i], + minCtlPower); + } + break; + default: + break; + } + } + + ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = + ratesArray[rate18mb] = ratesArray[rate24mb] = + targetPowerOfdm.tPow2x[0]; + ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; + ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; + ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; + ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; + + for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) + ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; + + ratesArray[rate1l] = targetPowerCck.tPow2x[0]; + ratesArray[rate2s] = ratesArray[rate2l] = targetPowerCck.tPow2x[1]; + ratesArray[rate5_5s] = ratesArray[rate5_5l] = targetPowerCck.tPow2x[2]; + ratesArray[rate11s] = ratesArray[rate11l] = targetPowerCck.tPow2x[3]; + + if (IS_CHAN_HT40(chan)) { + for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { + ratesArray[rateHt40_0 + i] = + targetPowerHt40.tPow2x[i]; + } + ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; + ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; + ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; + ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; + } + return true; +} + +static int ath9k_hw_def_set_txpower(struct ath_hal *ah, + struct ath9k_channel *chan, + u16 cfgCtl, + u8 twiceAntennaReduction, + u8 twiceMaxRegulatoryPower, + u8 powerLimit) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_def *pEepData = &ahp->ah_eeprom.def; + struct modal_eep_header *pModal = + &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]); + int16_t ratesArray[Ar5416RateSize]; + int16_t txPowerIndexOffset = 0; + u8 ht40PowerIncForPdadc = 2; + int i; + + memset(ratesArray, 0, sizeof(ratesArray)); + + if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_2) { + ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; + } + + if (!ath9k_hw_set_def_power_per_rate_table(ah, chan, + &ratesArray[0], cfgCtl, + twiceAntennaReduction, + twiceMaxRegulatoryPower, + powerLimit)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "ath9k_hw_set_txpower: unable to set " + "tx power per rate table\n"); + return -EIO; + } + + if (!ath9k_hw_set_def_power_cal_table(ah, chan, &txPowerIndexOffset)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "ath9k_hw_set_txpower: unable to set power table\n"); + return -EIO; + } + + for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { + ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); + if (ratesArray[i] > AR5416_MAX_RATE_POWER) + ratesArray[i] = AR5416_MAX_RATE_POWER; + } + + if (AR_SREV_9280_10_OR_LATER(ah)) { + for (i = 0; i < Ar5416RateSize; i++) + ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; + } + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, + ATH9K_POW_SM(ratesArray[rate18mb], 24) + | ATH9K_POW_SM(ratesArray[rate12mb], 16) + | ATH9K_POW_SM(ratesArray[rate9mb], 8) + | ATH9K_POW_SM(ratesArray[rate6mb], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, + ATH9K_POW_SM(ratesArray[rate54mb], 24) + | ATH9K_POW_SM(ratesArray[rate48mb], 16) + | ATH9K_POW_SM(ratesArray[rate36mb], 8) + | ATH9K_POW_SM(ratesArray[rate24mb], 0)); + + if (IS_CHAN_2GHZ(chan)) { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, + ATH9K_POW_SM(ratesArray[rate2s], 24) + | ATH9K_POW_SM(ratesArray[rate2l], 16) + | ATH9K_POW_SM(ratesArray[rateXr], 8) + | ATH9K_POW_SM(ratesArray[rate1l], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, + ATH9K_POW_SM(ratesArray[rate11s], 24) + | ATH9K_POW_SM(ratesArray[rate11l], 16) + | ATH9K_POW_SM(ratesArray[rate5_5s], 8) + | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); + } + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, + ATH9K_POW_SM(ratesArray[rateHt20_3], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, + ATH9K_POW_SM(ratesArray[rateHt20_7], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); + + if (IS_CHAN_HT40(chan)) { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, + ATH9K_POW_SM(ratesArray[rateHt40_3] + + ht40PowerIncForPdadc, 24) + | ATH9K_POW_SM(ratesArray[rateHt40_2] + + ht40PowerIncForPdadc, 16) + | ATH9K_POW_SM(ratesArray[rateHt40_1] + + ht40PowerIncForPdadc, 8) + | ATH9K_POW_SM(ratesArray[rateHt40_0] + + ht40PowerIncForPdadc, 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, + ATH9K_POW_SM(ratesArray[rateHt40_7] + + ht40PowerIncForPdadc, 24) + | ATH9K_POW_SM(ratesArray[rateHt40_6] + + ht40PowerIncForPdadc, 16) + | ATH9K_POW_SM(ratesArray[rateHt40_5] + + ht40PowerIncForPdadc, 8) + | ATH9K_POW_SM(ratesArray[rateHt40_4] + + ht40PowerIncForPdadc, 0)); + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, + ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) + | ATH9K_POW_SM(ratesArray[rateExtCck], 16) + | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) + | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); + } + + REG_WRITE(ah, AR_PHY_POWER_TX_SUB, + ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6) + | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0)); + + i = rate6mb; + + if (IS_CHAN_HT40(chan)) + i = rateHt40_0; + else if (IS_CHAN_HT20(chan)) + i = rateHt20_0; + + if (AR_SREV_9280_10_OR_LATER(ah)) + ah->ah_maxPowerLevel = + ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; + else + ah->ah_maxPowerLevel = ratesArray[i]; + + return 0; +} + +static int ath9k_hw_4k_set_txpower(struct ath_hal *ah, + struct ath9k_channel *chan, + u16 cfgCtl, + u8 twiceAntennaReduction, + u8 twiceMaxRegulatoryPower, + u8 powerLimit) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_4k *pEepData = &ahp->ah_eeprom.map4k; + struct modal_eep_4k_header *pModal = &pEepData->modalHeader; + int16_t ratesArray[Ar5416RateSize]; + int16_t txPowerIndexOffset = 0; + u8 ht40PowerIncForPdadc = 2; + int i; + + memset(ratesArray, 0, sizeof(ratesArray)); + + if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_2) { + ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; + } + + if (!ath9k_hw_set_4k_power_per_rate_table(ah, chan, + &ratesArray[0], cfgCtl, + twiceAntennaReduction, + twiceMaxRegulatoryPower, + powerLimit)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "ath9k_hw_set_txpower: unable to set " + "tx power per rate table\n"); + return -EIO; + } + + if (!ath9k_hw_set_4k_power_cal_table(ah, chan, &txPowerIndexOffset)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "ath9k_hw_set_txpower: unable to set power table\n"); + return -EIO; + } + + for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { + ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); + if (ratesArray[i] > AR5416_MAX_RATE_POWER) + ratesArray[i] = AR5416_MAX_RATE_POWER; + } + + if (AR_SREV_9280_10_OR_LATER(ah)) { + for (i = 0; i < Ar5416RateSize; i++) + ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; + } + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, + ATH9K_POW_SM(ratesArray[rate18mb], 24) + | ATH9K_POW_SM(ratesArray[rate12mb], 16) + | ATH9K_POW_SM(ratesArray[rate9mb], 8) + | ATH9K_POW_SM(ratesArray[rate6mb], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, + ATH9K_POW_SM(ratesArray[rate54mb], 24) + | ATH9K_POW_SM(ratesArray[rate48mb], 16) + | ATH9K_POW_SM(ratesArray[rate36mb], 8) + | ATH9K_POW_SM(ratesArray[rate24mb], 0)); + + if (IS_CHAN_2GHZ(chan)) { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, + ATH9K_POW_SM(ratesArray[rate2s], 24) + | ATH9K_POW_SM(ratesArray[rate2l], 16) + | ATH9K_POW_SM(ratesArray[rateXr], 8) + | ATH9K_POW_SM(ratesArray[rate1l], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, + ATH9K_POW_SM(ratesArray[rate11s], 24) + | ATH9K_POW_SM(ratesArray[rate11l], 16) + | ATH9K_POW_SM(ratesArray[rate5_5s], 8) + | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); + } + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, + ATH9K_POW_SM(ratesArray[rateHt20_3], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, + ATH9K_POW_SM(ratesArray[rateHt20_7], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); + + if (IS_CHAN_HT40(chan)) { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, + ATH9K_POW_SM(ratesArray[rateHt40_3] + + ht40PowerIncForPdadc, 24) + | ATH9K_POW_SM(ratesArray[rateHt40_2] + + ht40PowerIncForPdadc, 16) + | ATH9K_POW_SM(ratesArray[rateHt40_1] + + ht40PowerIncForPdadc, 8) + | ATH9K_POW_SM(ratesArray[rateHt40_0] + + ht40PowerIncForPdadc, 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, + ATH9K_POW_SM(ratesArray[rateHt40_7] + + ht40PowerIncForPdadc, 24) + | ATH9K_POW_SM(ratesArray[rateHt40_6] + + ht40PowerIncForPdadc, 16) + | ATH9K_POW_SM(ratesArray[rateHt40_5] + + ht40PowerIncForPdadc, 8) + | ATH9K_POW_SM(ratesArray[rateHt40_4] + + ht40PowerIncForPdadc, 0)); + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, + ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) + | ATH9K_POW_SM(ratesArray[rateExtCck], 16) + | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) + | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); + } + + i = rate6mb; + + if (IS_CHAN_HT40(chan)) + i = rateHt40_0; + else if (IS_CHAN_HT20(chan)) + i = rateHt20_0; + + if (AR_SREV_9280_10_OR_LATER(ah)) + ah->ah_maxPowerLevel = + ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; + else + ah->ah_maxPowerLevel = ratesArray[i]; + + return 0; +} + +static int (*ath9k_set_txpower[]) (struct ath_hal *, + struct ath9k_channel *, + u16, u8, u8, u8) = { + ath9k_hw_def_set_txpower, + ath9k_hw_4k_set_txpower +}; + +int ath9k_hw_set_txpower(struct ath_hal *ah, + struct ath9k_channel *chan, + u16 cfgCtl, + u8 twiceAntennaReduction, + u8 twiceMaxRegulatoryPower, + u8 powerLimit) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + return ath9k_set_txpower[ahp->ah_eep_map](ah, chan, cfgCtl, + twiceAntennaReduction, twiceMaxRegulatoryPower, + powerLimit); +} + +static void ath9k_hw_set_def_addac(struct ath_hal *ah, + struct ath9k_channel *chan) +{ +#define XPA_LVL_FREQ(cnt) (pModal->xpaBiasLvlFreq[cnt]) + struct modal_eep_header *pModal; + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def; + u8 biaslevel; + + if (ah->ah_macVersion != AR_SREV_VERSION_9160) + return; + + if (ar5416_get_eep_rev(ahp) < AR5416_EEP_MINOR_VER_7) + return; + + pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); + + if (pModal->xpaBiasLvl != 0xff) { + biaslevel = pModal->xpaBiasLvl; + } else { + u16 resetFreqBin, freqBin, freqCount = 0; + struct chan_centers centers; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + resetFreqBin = FREQ2FBIN(centers.synth_center, + IS_CHAN_2GHZ(chan)); + freqBin = XPA_LVL_FREQ(0) & 0xff; + biaslevel = (u8) (XPA_LVL_FREQ(0) >> 14); + + freqCount++; + + while (freqCount < 3) { + if (XPA_LVL_FREQ(freqCount) == 0x0) + break; + + freqBin = XPA_LVL_FREQ(freqCount) & 0xff; + if (resetFreqBin >= freqBin) + biaslevel = (u8)(XPA_LVL_FREQ(freqCount) >> 14); + else + break; + freqCount++; + } + } + + if (IS_CHAN_2GHZ(chan)) { + INI_RA(&ahp->ah_iniAddac, 7, 1) = (INI_RA(&ahp->ah_iniAddac, + 7, 1) & (~0x18)) | biaslevel << 3; + } else { + INI_RA(&ahp->ah_iniAddac, 6, 1) = (INI_RA(&ahp->ah_iniAddac, + 6, 1) & (~0xc0)) | biaslevel << 6; + } +#undef XPA_LVL_FREQ +} + +static void ath9k_hw_set_4k_addac(struct ath_hal *ah, + struct ath9k_channel *chan) +{ + struct modal_eep_4k_header *pModal; + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_4k *eep = &ahp->ah_eeprom.map4k; + u8 biaslevel; + + if (ah->ah_macVersion != AR_SREV_VERSION_9160) + return; + + if (ar5416_get_eep_rev(ahp) < AR5416_EEP_MINOR_VER_7) + return; + + pModal = &eep->modalHeader; + + if (pModal->xpaBiasLvl != 0xff) { + biaslevel = pModal->xpaBiasLvl; + INI_RA(&ahp->ah_iniAddac, 7, 1) = + (INI_RA(&ahp->ah_iniAddac, 7, 1) & (~0x18)) | biaslevel << 3; + } +} + +static void (*ath9k_set_addac[]) (struct ath_hal *, struct ath9k_channel *) = { + ath9k_hw_set_def_addac, + ath9k_hw_set_4k_addac +}; + +void ath9k_hw_set_addac(struct ath_hal *ah, struct ath9k_channel *chan) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + ath9k_set_addac[ahp->ah_eep_map](ah, chan); +} + + + +/* XXX: Clean me up, make me more legible */ +static bool ath9k_hw_eeprom_set_def_board_values(struct ath_hal *ah, + struct ath9k_channel *chan) +{ + struct modal_eep_header *pModal; + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def; + int i, regChainOffset; + u8 txRxAttenLocal; + u16 ant_config; + + pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); + + txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44; + + ath9k_hw_get_eeprom_antenna_cfg(ah, chan, 0, &ant_config); + REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config); + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + if (AR_SREV_9280(ah)) { + if (i >= 2) + break; + } + + if (AR_SREV_5416_V20_OR_LATER(ah) && + (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5) + && (i != 0)) + regChainOffset = (i == 1) ? 0x2000 : 0x1000; + else + regChainOffset = i * 0x1000; + + REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, + pModal->antCtrlChain[i]); + + REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, + (REG_READ(ah, + AR_PHY_TIMING_CTRL4(0) + + regChainOffset) & + ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | + SM(pModal->iqCalICh[i], + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | + SM(pModal->iqCalQCh[i], + AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); + + if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) { + if ((eep->baseEepHeader.version & + AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_3) { + txRxAttenLocal = pModal->txRxAttenCh[i]; + if (AR_SREV_9280_10_OR_LATER(ah)) { + REG_RMW_FIELD(ah, + AR_PHY_GAIN_2GHZ + + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, + pModal-> + bswMargin[i]); + REG_RMW_FIELD(ah, + AR_PHY_GAIN_2GHZ + + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN1_DB, + pModal-> + bswAtten[i]); + REG_RMW_FIELD(ah, + AR_PHY_GAIN_2GHZ + + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, + pModal-> + xatten2Margin[i]); + REG_RMW_FIELD(ah, + AR_PHY_GAIN_2GHZ + + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN2_DB, + pModal-> + xatten2Db[i]); + } else { + REG_WRITE(ah, + AR_PHY_GAIN_2GHZ + + regChainOffset, + (REG_READ(ah, + AR_PHY_GAIN_2GHZ + + regChainOffset) & + ~AR_PHY_GAIN_2GHZ_BSW_MARGIN) + | SM(pModal-> + bswMargin[i], + AR_PHY_GAIN_2GHZ_BSW_MARGIN)); + REG_WRITE(ah, + AR_PHY_GAIN_2GHZ + + regChainOffset, + (REG_READ(ah, + AR_PHY_GAIN_2GHZ + + regChainOffset) & + ~AR_PHY_GAIN_2GHZ_BSW_ATTEN) + | SM(pModal->bswAtten[i], + AR_PHY_GAIN_2GHZ_BSW_ATTEN)); + } + } + if (AR_SREV_9280_10_OR_LATER(ah)) { + REG_RMW_FIELD(ah, + AR_PHY_RXGAIN + + regChainOffset, + AR9280_PHY_RXGAIN_TXRX_ATTEN, + txRxAttenLocal); + REG_RMW_FIELD(ah, + AR_PHY_RXGAIN + + regChainOffset, + AR9280_PHY_RXGAIN_TXRX_MARGIN, + pModal->rxTxMarginCh[i]); + } else { + REG_WRITE(ah, + AR_PHY_RXGAIN + regChainOffset, + (REG_READ(ah, + AR_PHY_RXGAIN + + regChainOffset) & + ~AR_PHY_RXGAIN_TXRX_ATTEN) | + SM(txRxAttenLocal, + AR_PHY_RXGAIN_TXRX_ATTEN)); + REG_WRITE(ah, + AR_PHY_GAIN_2GHZ + + regChainOffset, + (REG_READ(ah, + AR_PHY_GAIN_2GHZ + + regChainOffset) & + ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) | + SM(pModal->rxTxMarginCh[i], + AR_PHY_GAIN_2GHZ_RXTX_MARGIN)); + } + } + } + + if (AR_SREV_9280_10_OR_LATER(ah)) { + if (IS_CHAN_2GHZ(chan)) { + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0, + AR_AN_RF2G1_CH0_OB, + AR_AN_RF2G1_CH0_OB_S, + pModal->ob); + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0, + AR_AN_RF2G1_CH0_DB, + AR_AN_RF2G1_CH0_DB_S, + pModal->db); + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1, + AR_AN_RF2G1_CH1_OB, + AR_AN_RF2G1_CH1_OB_S, + pModal->ob_ch1); + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1, + AR_AN_RF2G1_CH1_DB, + AR_AN_RF2G1_CH1_DB_S, + pModal->db_ch1); + } else { + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0, + AR_AN_RF5G1_CH0_OB5, + AR_AN_RF5G1_CH0_OB5_S, + pModal->ob); + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0, + AR_AN_RF5G1_CH0_DB5, + AR_AN_RF5G1_CH0_DB5_S, + pModal->db); + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1, + AR_AN_RF5G1_CH1_OB5, + AR_AN_RF5G1_CH1_OB5_S, + pModal->ob_ch1); + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1, + AR_AN_RF5G1_CH1_DB5, + AR_AN_RF5G1_CH1_DB5_S, + pModal->db_ch1); + } + ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2, + AR_AN_TOP2_XPABIAS_LVL, + AR_AN_TOP2_XPABIAS_LVL_S, + pModal->xpaBiasLvl); + ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2, + AR_AN_TOP2_LOCALBIAS, + AR_AN_TOP2_LOCALBIAS_S, + pModal->local_bias); + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "ForceXPAon: %d\n", + pModal->force_xpaon); + REG_RMW_FIELD(ah, AR_PHY_XPA_CFG, AR_PHY_FORCE_XPA_CFG, + pModal->force_xpaon); + } + + REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, + pModal->switchSettling); + REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, + pModal->adcDesiredSize); + + if (!AR_SREV_9280_10_OR_LATER(ah)) + REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, + AR_PHY_DESIRED_SZ_PGA, + pModal->pgaDesiredSize); + + REG_WRITE(ah, AR_PHY_RF_CTL4, + SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) + | SM(pModal->txEndToXpaOff, + AR_PHY_RF_CTL4_TX_END_XPAB_OFF) + | SM(pModal->txFrameToXpaOn, + AR_PHY_RF_CTL4_FRAME_XPAA_ON) + | SM(pModal->txFrameToXpaOn, + AR_PHY_RF_CTL4_FRAME_XPAB_ON)); + + REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, + pModal->txEndToRxOn); + if (AR_SREV_9280_10_OR_LATER(ah)) { + REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, + pModal->thresh62); + REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, + AR_PHY_EXT_CCA0_THRESH62, + pModal->thresh62); + } else { + REG_RMW_FIELD(ah, AR_PHY_CCA, AR_PHY_CCA_THRESH62, + pModal->thresh62); + REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, + AR_PHY_EXT_CCA_THRESH62, + pModal->thresh62); + } + + if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_2) { + REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, + AR_PHY_TX_END_DATA_START, + pModal->txFrameToDataStart); + REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON, + pModal->txFrameToPaOn); + } + + if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_3) { + if (IS_CHAN_HT40(chan)) + REG_RMW_FIELD(ah, AR_PHY_SETTLING, + AR_PHY_SETTLING_SWITCH, + pModal->swSettleHt40); + } + + return true; +} + +static bool ath9k_hw_eeprom_set_4k_board_values(struct ath_hal *ah, + struct ath9k_channel *chan) +{ + struct modal_eep_4k_header *pModal; + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_4k *eep = &ahp->ah_eeprom.map4k; + int regChainOffset; + u8 txRxAttenLocal; + u16 ant_config = 0; + u8 ob[5], db1[5], db2[5]; + u8 ant_div_control1, ant_div_control2; + u32 regVal; + + + pModal = &eep->modalHeader; + + txRxAttenLocal = 23; + + ath9k_hw_get_eeprom_antenna_cfg(ah, chan, 0, &ant_config); + REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config); + + regChainOffset = 0; + REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, + pModal->antCtrlChain[0]); + + REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, + (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) & + ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | + SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | + SM(pModal->iqCalQCh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); + + if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_3) { + txRxAttenLocal = pModal->txRxAttenCh[0]; + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, pModal->bswMargin[0]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, + pModal->xatten2Margin[0]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]); + } + + REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, + AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); + REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, + AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); + + if (AR_SREV_9285_11(ah)) + REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); + + /* Initialize Ant Diversity settings from EEPROM */ + if (pModal->version == 3) { + ant_div_control1 = ((pModal->ob_234 >> 12) & 0xf); + ant_div_control2 = ((pModal->db1_234 >> 12) & 0xf); + regVal = REG_READ(ah, 0x99ac); + regVal &= (~(0x7f000000)); + regVal |= ((ant_div_control1 & 0x1) << 24); + regVal |= (((ant_div_control1 >> 1) & 0x1) << 29); + regVal |= (((ant_div_control1 >> 2) & 0x1) << 30); + regVal |= ((ant_div_control2 & 0x3) << 25); + regVal |= (((ant_div_control2 >> 2) & 0x3) << 27); + REG_WRITE(ah, 0x99ac, regVal); + regVal = REG_READ(ah, 0x99ac); + regVal = REG_READ(ah, 0xa208); + regVal &= (~(0x1 << 13)); + regVal |= (((ant_div_control1 >> 3) & 0x1) << 13); + REG_WRITE(ah, 0xa208, regVal); + regVal = REG_READ(ah, 0xa208); + } + + if (pModal->version >= 2) { + ob[0] = (pModal->ob_01 & 0xf); + ob[1] = (pModal->ob_01 >> 4) & 0xf; + ob[2] = (pModal->ob_234 & 0xf); + ob[3] = ((pModal->ob_234 >> 4) & 0xf); + ob[4] = ((pModal->ob_234 >> 8) & 0xf); + + db1[0] = (pModal->db1_01 & 0xf); + db1[1] = ((pModal->db1_01 >> 4) & 0xf); + db1[2] = (pModal->db1_234 & 0xf); + db1[3] = ((pModal->db1_234 >> 4) & 0xf); + db1[4] = ((pModal->db1_234 >> 8) & 0xf); + + db2[0] = (pModal->db2_01 & 0xf); + db2[1] = ((pModal->db2_01 >> 4) & 0xf); + db2[2] = (pModal->db2_234 & 0xf); + db2[3] = ((pModal->db2_234 >> 4) & 0xf); + db2[4] = ((pModal->db2_234 >> 8) & 0xf); + + } else if (pModal->version == 1) { + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "EEPROM Model version is set to 1 \n"); + ob[0] = (pModal->ob_01 & 0xf); + ob[1] = ob[2] = ob[3] = ob[4] = (pModal->ob_01 >> 4) & 0xf; + db1[0] = (pModal->db1_01 & 0xf); + db1[1] = db1[2] = db1[3] = + db1[4] = ((pModal->db1_01 >> 4) & 0xf); + db2[0] = (pModal->db2_01 & 0xf); + db2[1] = db2[2] = db2[3] = + db2[4] = ((pModal->db2_01 >> 4) & 0xf); + } else { + int i; + for (i = 0; i < 5; i++) { + ob[i] = pModal->ob_01; + db1[i] = pModal->db1_01; + db2[i] = pModal->db1_01; + } + } + + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_0, AR9285_AN_RF2G3_OB_0_S, ob[0]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_1, AR9285_AN_RF2G3_OB_1_S, ob[1]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_2, AR9285_AN_RF2G3_OB_2_S, ob[2]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_3, AR9285_AN_RF2G3_OB_3_S, ob[3]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_4, AR9285_AN_RF2G3_OB_4_S, ob[4]); + + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_DB1_0, AR9285_AN_RF2G3_DB1_0_S, db1[0]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_DB1_1, AR9285_AN_RF2G3_DB1_1_S, db1[1]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_DB1_2, AR9285_AN_RF2G3_DB1_2_S, db1[2]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB1_3, AR9285_AN_RF2G4_DB1_3_S, db1[3]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB1_4, AR9285_AN_RF2G4_DB1_4_S, db1[4]); + + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_0, AR9285_AN_RF2G4_DB2_0_S, db2[0]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_1, AR9285_AN_RF2G4_DB2_1_S, db2[1]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_2, AR9285_AN_RF2G4_DB2_2_S, db2[2]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_3, AR9285_AN_RF2G4_DB2_3_S, db2[3]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_4, AR9285_AN_RF2G4_DB2_4_S, db2[4]); + + + if (AR_SREV_9285_11(ah)) + REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT); + + REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, + pModal->switchSettling); + REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, + pModal->adcDesiredSize); + + REG_WRITE(ah, AR_PHY_RF_CTL4, + SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) | + SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) | + SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) | + SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON)); + + REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, + pModal->txEndToRxOn); + REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, + pModal->thresh62); + REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, AR_PHY_EXT_CCA0_THRESH62, + pModal->thresh62); + + if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_2) { + REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_DATA_START, + pModal->txFrameToDataStart); + REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON, + pModal->txFrameToPaOn); + } + + if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_3) { + if (IS_CHAN_HT40(chan)) + REG_RMW_FIELD(ah, AR_PHY_SETTLING, + AR_PHY_SETTLING_SWITCH, + pModal->swSettleHt40); + } + + return true; +} + +static bool (*ath9k_eeprom_set_board_values[])(struct ath_hal *, + struct ath9k_channel *) = { + ath9k_hw_eeprom_set_def_board_values, + ath9k_hw_eeprom_set_4k_board_values +}; + +bool ath9k_hw_eeprom_set_board_values(struct ath_hal *ah, + struct ath9k_channel *chan) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + return ath9k_eeprom_set_board_values[ahp->ah_eep_map](ah, chan); +} + +static int ath9k_hw_get_def_eeprom_antenna_cfg(struct ath_hal *ah, + struct ath9k_channel *chan, + u8 index, u16 *config) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def; + struct modal_eep_header *pModal = + &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); + struct base_eep_header *pBase = &eep->baseEepHeader; + + switch (index) { + case 0: + *config = pModal->antCtrlCommon & 0xFFFF; + return 0; + case 1: + if (pBase->version >= 0x0E0D) { + if (pModal->useAnt1) { + *config = + ((pModal->antCtrlCommon & 0xFFFF0000) >> 16); + return 0; + } + } + break; + default: + break; + } + + return -EINVAL; +} + +static int ath9k_hw_get_4k_eeprom_antenna_cfg(struct ath_hal *ah, + struct ath9k_channel *chan, + u8 index, u16 *config) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_4k *eep = &ahp->ah_eeprom.map4k; + struct modal_eep_4k_header *pModal = &eep->modalHeader; + + switch (index) { + case 0: + *config = pModal->antCtrlCommon & 0xFFFF; + return 0; + default: + break; + } + + return -EINVAL; +} + +static int (*ath9k_get_eeprom_antenna_cfg[])(struct ath_hal *, + struct ath9k_channel *, + u8, u16 *) = { + ath9k_hw_get_def_eeprom_antenna_cfg, + ath9k_hw_get_4k_eeprom_antenna_cfg +}; + +int ath9k_hw_get_eeprom_antenna_cfg(struct ath_hal *ah, + struct ath9k_channel *chan, + u8 index, u16 *config) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + return ath9k_get_eeprom_antenna_cfg[ahp->ah_eep_map](ah, chan, + index, config); +} + +static u8 ath9k_hw_get_4k_num_ant_config(struct ath_hal *ah, + enum ieee80211_band freq_band) +{ + return 1; +} + +static u8 ath9k_hw_get_def_num_ant_config(struct ath_hal *ah, + enum ieee80211_band freq_band) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def; + struct modal_eep_header *pModal = + &(eep->modalHeader[ATH9K_HAL_FREQ_BAND_2GHZ == freq_band]); + struct base_eep_header *pBase = &eep->baseEepHeader; + u8 num_ant_config; + + num_ant_config = 1; + + if (pBase->version >= 0x0E0D) + if (pModal->useAnt1) + num_ant_config += 1; + + return num_ant_config; +} + +static u8 (*ath9k_get_num_ant_config[])(struct ath_hal *, + enum ieee80211_band) = { + ath9k_hw_get_def_num_ant_config, + ath9k_hw_get_4k_num_ant_config +}; + +u8 ath9k_hw_get_num_ant_config(struct ath_hal *ah, + enum ieee80211_band freq_band) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + return ath9k_get_num_ant_config[ahp->ah_eep_map](ah, freq_band); +} + +u16 ath9k_hw_eeprom_get_spur_chan(struct ath_hal *ah, u16 i, bool is2GHz) +{ +#define EEP_MAP4K_SPURCHAN \ + (ahp->ah_eeprom.map4k.modalHeader.spurChans[i].spurChan) +#define EEP_DEF_SPURCHAN \ + (ahp->ah_eeprom.def.modalHeader[is2GHz].spurChans[i].spurChan) + struct ath_hal_5416 *ahp = AH5416(ah); + u16 spur_val = AR_NO_SPUR; + + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Getting spur idx %d is2Ghz. %d val %x\n", + i, is2GHz, ah->ah_config.spurchans[i][is2GHz]); + + switch (ah->ah_config.spurmode) { + case SPUR_DISABLE: + break; + case SPUR_ENABLE_IOCTL: + spur_val = ah->ah_config.spurchans[i][is2GHz]; + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Getting spur val from new loc. %d\n", spur_val); + break; + case SPUR_ENABLE_EEPROM: + if (ahp->ah_eep_map == EEP_MAP_4KBITS) + spur_val = EEP_MAP4K_SPURCHAN; + else + spur_val = EEP_DEF_SPURCHAN; + break; + + } + + return spur_val; +#undef EEP_DEF_SPURCHAN +#undef EEP_MAP4K_SPURCHAN +} + +static u32 ath9k_hw_get_eeprom_4k(struct ath_hal *ah, + enum eeprom_param param) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_4k *eep = &ahp->ah_eeprom.map4k; + struct modal_eep_4k_header *pModal = &eep->modalHeader; + struct base_eep_header_4k *pBase = &eep->baseEepHeader; + + switch (param) { + case EEP_NFTHRESH_2: + return pModal[1].noiseFloorThreshCh[0]; + case AR_EEPROM_MAC(0): + return pBase->macAddr[0] << 8 | pBase->macAddr[1]; + case AR_EEPROM_MAC(1): + return pBase->macAddr[2] << 8 | pBase->macAddr[3]; + case AR_EEPROM_MAC(2): + return pBase->macAddr[4] << 8 | pBase->macAddr[5]; + case EEP_REG_0: + return pBase->regDmn[0]; + case EEP_REG_1: + return pBase->regDmn[1]; + case EEP_OP_CAP: + return pBase->deviceCap; + case EEP_OP_MODE: + return pBase->opCapFlags; + case EEP_RF_SILENT: + return pBase->rfSilent; + case EEP_OB_2: + return pModal->ob_01; + case EEP_DB_2: + return pModal->db1_01; + case EEP_MINOR_REV: + return pBase->version & AR5416_EEP_VER_MINOR_MASK; + case EEP_TX_MASK: + return pBase->txMask; + case EEP_RX_MASK: + return pBase->rxMask; + default: + return 0; + } +} + +static u32 ath9k_hw_get_eeprom_def(struct ath_hal *ah, + enum eeprom_param param) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def; + struct modal_eep_header *pModal = eep->modalHeader; + struct base_eep_header *pBase = &eep->baseEepHeader; + + switch (param) { + case EEP_NFTHRESH_5: + return pModal[0].noiseFloorThreshCh[0]; + case EEP_NFTHRESH_2: + return pModal[1].noiseFloorThreshCh[0]; + case AR_EEPROM_MAC(0): + return pBase->macAddr[0] << 8 | pBase->macAddr[1]; + case AR_EEPROM_MAC(1): + return pBase->macAddr[2] << 8 | pBase->macAddr[3]; + case AR_EEPROM_MAC(2): + return pBase->macAddr[4] << 8 | pBase->macAddr[5]; + case EEP_REG_0: + return pBase->regDmn[0]; + case EEP_REG_1: + return pBase->regDmn[1]; + case EEP_OP_CAP: + return pBase->deviceCap; + case EEP_OP_MODE: + return pBase->opCapFlags; + case EEP_RF_SILENT: + return pBase->rfSilent; + case EEP_OB_5: + return pModal[0].ob; + case EEP_DB_5: + return pModal[0].db; + case EEP_OB_2: + return pModal[1].ob; + case EEP_DB_2: + return pModal[1].db; + case EEP_MINOR_REV: + return pBase->version & AR5416_EEP_VER_MINOR_MASK; + case EEP_TX_MASK: + return pBase->txMask; + case EEP_RX_MASK: + return pBase->rxMask; + case EEP_RXGAIN_TYPE: + return pBase->rxGainType; + case EEP_TXGAIN_TYPE: + return pBase->txGainType; + + default: + return 0; + } +} + +static u32 (*ath9k_get_eeprom[])(struct ath_hal *, enum eeprom_param) = { + ath9k_hw_get_eeprom_def, + ath9k_hw_get_eeprom_4k +}; + +u32 ath9k_hw_get_eeprom(struct ath_hal *ah, + enum eeprom_param param) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + return ath9k_get_eeprom[ahp->ah_eep_map](ah, param); +} + +int ath9k_hw_eeprom_attach(struct ath_hal *ah) +{ + int status; + struct ath_hal_5416 *ahp = AH5416(ah); + + if (ath9k_hw_use_flash(ah)) + ath9k_hw_flash_map(ah); + + if (AR_SREV_9285(ah)) + ahp->ah_eep_map = EEP_MAP_4KBITS; + else + ahp->ah_eep_map = EEP_MAP_DEFAULT; + + if (!ath9k_hw_fill_eeprom(ah)) + return -EIO; + + status = ath9k_hw_check_eeprom(ah); + + return status; +} diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index 98bc25c9b3cf4f5f5ddf3e22b92d0cbd12c60a3d..34474edefc97ee4ff472be082d15ebbcad7c9a20 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -23,195 +23,78 @@ #include "phy.h" #include "initvals.h" -static void ath9k_hw_iqcal_collect(struct ath_hal *ah); -static void ath9k_hw_iqcalibrate(struct ath_hal *ah, u8 numChains); -static void ath9k_hw_adc_gaincal_collect(struct ath_hal *ah); -static void ath9k_hw_adc_gaincal_calibrate(struct ath_hal *ah, - u8 numChains); -static void ath9k_hw_adc_dccal_collect(struct ath_hal *ah); -static void ath9k_hw_adc_dccal_calibrate(struct ath_hal *ah, - u8 numChains); - static const u8 CLOCK_RATE[] = { 40, 80, 22, 44, 88, 40 }; -static const int16_t NOISE_FLOOR[] = { -96, -93, -98, -96, -93, -96 }; - -static const struct hal_percal_data iq_cal_multi_sample = { - IQ_MISMATCH_CAL, - MAX_CAL_SAMPLES, - PER_MIN_LOG_COUNT, - ath9k_hw_iqcal_collect, - ath9k_hw_iqcalibrate -}; -static const struct hal_percal_data iq_cal_single_sample = { - IQ_MISMATCH_CAL, - MIN_CAL_SAMPLES, - PER_MAX_LOG_COUNT, - ath9k_hw_iqcal_collect, - ath9k_hw_iqcalibrate -}; -static const struct hal_percal_data adc_gain_cal_multi_sample = { - ADC_GAIN_CAL, - MAX_CAL_SAMPLES, - PER_MIN_LOG_COUNT, - ath9k_hw_adc_gaincal_collect, - ath9k_hw_adc_gaincal_calibrate -}; -static const struct hal_percal_data adc_gain_cal_single_sample = { - ADC_GAIN_CAL, - MIN_CAL_SAMPLES, - PER_MAX_LOG_COUNT, - ath9k_hw_adc_gaincal_collect, - ath9k_hw_adc_gaincal_calibrate -}; -static const struct hal_percal_data adc_dc_cal_multi_sample = { - ADC_DC_CAL, - MAX_CAL_SAMPLES, - PER_MIN_LOG_COUNT, - ath9k_hw_adc_dccal_collect, - ath9k_hw_adc_dccal_calibrate -}; -static const struct hal_percal_data adc_dc_cal_single_sample = { - ADC_DC_CAL, - MIN_CAL_SAMPLES, - PER_MAX_LOG_COUNT, - ath9k_hw_adc_dccal_collect, - ath9k_hw_adc_dccal_calibrate -}; -static const struct hal_percal_data adc_init_dc_cal = { - ADC_DC_INIT_CAL, - MIN_CAL_SAMPLES, - INIT_LOG_COUNT, - ath9k_hw_adc_dccal_collect, - ath9k_hw_adc_dccal_calibrate -}; - -static struct ath9k_rate_table ar5416_11a_table = { - 8, - {0}, - { - {true, PHY_OFDM, 6000, 0x0b, 0x00, (0x80 | 12), 0}, - {true, PHY_OFDM, 9000, 0x0f, 0x00, 18, 0}, - {true, PHY_OFDM, 12000, 0x0a, 0x00, (0x80 | 24), 2}, - {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 2}, - {true, PHY_OFDM, 24000, 0x09, 0x00, (0x80 | 48), 4}, - {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 4}, - {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 4}, - {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 4} - }, -}; - -static struct ath9k_rate_table ar5416_11b_table = { - 4, - {0}, - { - {true, PHY_CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0}, - {true, PHY_CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1}, - {true, PHY_CCK, 5500, 0x19, 0x04, (0x80 | 11), 1}, - {true, PHY_CCK, 11000, 0x18, 0x04, (0x80 | 22), 1} - }, -}; - -static struct ath9k_rate_table ar5416_11g_table = { - 12, - {0}, - { - {true, PHY_CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0}, - {true, PHY_CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1}, - {true, PHY_CCK, 5500, 0x19, 0x04, (0x80 | 11), 2}, - {true, PHY_CCK, 11000, 0x18, 0x04, (0x80 | 22), 3}, - - {false, PHY_OFDM, 6000, 0x0b, 0x00, 12, 4}, - {false, PHY_OFDM, 9000, 0x0f, 0x00, 18, 4}, - {true, PHY_OFDM, 12000, 0x0a, 0x00, 24, 6}, - {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 6}, - {true, PHY_OFDM, 24000, 0x09, 0x00, 48, 8}, - {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 8}, - {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 8}, - {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 8} - }, -}; - -static struct ath9k_rate_table ar5416_11ng_table = { - 28, - {0}, - { - {true, PHY_CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0}, - {true, PHY_CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1}, - {true, PHY_CCK, 5500, 0x19, 0x04, (0x80 | 11), 2}, - {true, PHY_CCK, 11000, 0x18, 0x04, (0x80 | 22), 3}, - - {false, PHY_OFDM, 6000, 0x0b, 0x00, 12, 4}, - {false, PHY_OFDM, 9000, 0x0f, 0x00, 18, 4}, - {true, PHY_OFDM, 12000, 0x0a, 0x00, 24, 6}, - {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 6}, - {true, PHY_OFDM, 24000, 0x09, 0x00, 48, 8}, - {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 8}, - {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 8}, - {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 8}, - {true, PHY_HT, 6500, 0x80, 0x00, 0, 4}, - {true, PHY_HT, 13000, 0x81, 0x00, 1, 6}, - {true, PHY_HT, 19500, 0x82, 0x00, 2, 6}, - {true, PHY_HT, 26000, 0x83, 0x00, 3, 8}, - {true, PHY_HT, 39000, 0x84, 0x00, 4, 8}, - {true, PHY_HT, 52000, 0x85, 0x00, 5, 8}, - {true, PHY_HT, 58500, 0x86, 0x00, 6, 8}, - {true, PHY_HT, 65000, 0x87, 0x00, 7, 8}, - {true, PHY_HT, 13000, 0x88, 0x00, 8, 4}, - {true, PHY_HT, 26000, 0x89, 0x00, 9, 6}, - {true, PHY_HT, 39000, 0x8a, 0x00, 10, 6}, - {true, PHY_HT, 52000, 0x8b, 0x00, 11, 8}, - {true, PHY_HT, 78000, 0x8c, 0x00, 12, 8}, - {true, PHY_HT, 104000, 0x8d, 0x00, 13, 8}, - {true, PHY_HT, 117000, 0x8e, 0x00, 14, 8}, - {true, PHY_HT, 130000, 0x8f, 0x00, 15, 8}, - }, -}; - -static struct ath9k_rate_table ar5416_11na_table = { - 24, - {0}, - { - {true, PHY_OFDM, 6000, 0x0b, 0x00, (0x80 | 12), 0}, - {true, PHY_OFDM, 9000, 0x0f, 0x00, 18, 0}, - {true, PHY_OFDM, 12000, 0x0a, 0x00, (0x80 | 24), 2}, - {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 2}, - {true, PHY_OFDM, 24000, 0x09, 0x00, (0x80 | 48), 4}, - {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 4}, - {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 4}, - {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 4}, - {true, PHY_HT, 6500, 0x80, 0x00, 0, 0}, - {true, PHY_HT, 13000, 0x81, 0x00, 1, 2}, - {true, PHY_HT, 19500, 0x82, 0x00, 2, 2}, - {true, PHY_HT, 26000, 0x83, 0x00, 3, 4}, - {true, PHY_HT, 39000, 0x84, 0x00, 4, 4}, - {true, PHY_HT, 52000, 0x85, 0x00, 5, 4}, - {true, PHY_HT, 58500, 0x86, 0x00, 6, 4}, - {true, PHY_HT, 65000, 0x87, 0x00, 7, 4}, - {true, PHY_HT, 13000, 0x88, 0x00, 8, 0}, - {true, PHY_HT, 26000, 0x89, 0x00, 9, 2}, - {true, PHY_HT, 39000, 0x8a, 0x00, 10, 2}, - {true, PHY_HT, 52000, 0x8b, 0x00, 11, 4}, - {true, PHY_HT, 78000, 0x8c, 0x00, 12, 4}, - {true, PHY_HT, 104000, 0x8d, 0x00, 13, 4}, - {true, PHY_HT, 117000, 0x8e, 0x00, 14, 4}, - {true, PHY_HT, 130000, 0x8f, 0x00, 15, 4}, - }, -}; - -static enum wireless_mode ath9k_hw_chan2wmode(struct ath_hal *ah, - const struct ath9k_channel *chan) + +extern struct hal_percal_data iq_cal_multi_sample; +extern struct hal_percal_data iq_cal_single_sample; +extern struct hal_percal_data adc_gain_cal_multi_sample; +extern struct hal_percal_data adc_gain_cal_single_sample; +extern struct hal_percal_data adc_dc_cal_multi_sample; +extern struct hal_percal_data adc_dc_cal_single_sample; +extern struct hal_percal_data adc_init_dc_cal; + +static bool ath9k_hw_set_reset_reg(struct ath_hal *ah, u32 type); +static void ath9k_hw_set_regs(struct ath_hal *ah, struct ath9k_channel *chan, + enum ath9k_ht_macmode macmode); +static u32 ath9k_hw_ini_fixup(struct ath_hal *ah, + struct ar5416_eeprom_def *pEepData, + u32 reg, u32 value); +static void ath9k_hw_9280_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan); +static void ath9k_hw_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan); + +/********************/ +/* Helper Functions */ +/********************/ + +static u32 ath9k_hw_mac_usec(struct ath_hal *ah, u32 clks) +{ + if (ah->ah_curchan != NULL) + return clks / CLOCK_RATE[ath9k_hw_chan2wmode(ah, ah->ah_curchan)]; + else + return clks / CLOCK_RATE[ATH9K_MODE_11B]; +} + +static u32 ath9k_hw_mac_to_usec(struct ath_hal *ah, u32 clks) +{ + struct ath9k_channel *chan = ah->ah_curchan; + + if (chan && IS_CHAN_HT40(chan)) + return ath9k_hw_mac_usec(ah, clks) / 2; + else + return ath9k_hw_mac_usec(ah, clks); +} + +static u32 ath9k_hw_mac_clks(struct ath_hal *ah, u32 usecs) +{ + if (ah->ah_curchan != NULL) + return usecs * CLOCK_RATE[ath9k_hw_chan2wmode(ah, + ah->ah_curchan)]; + else + return usecs * CLOCK_RATE[ATH9K_MODE_11B]; +} + +static u32 ath9k_hw_mac_to_clks(struct ath_hal *ah, u32 usecs) +{ + struct ath9k_channel *chan = ah->ah_curchan; + + if (chan && IS_CHAN_HT40(chan)) + return ath9k_hw_mac_clks(ah, usecs) * 2; + else + return ath9k_hw_mac_clks(ah, usecs); +} + +enum wireless_mode ath9k_hw_chan2wmode(struct ath_hal *ah, + const struct ath9k_channel *chan) { - if (IS_CHAN_CCK(chan)) - return ATH9K_MODE_11A; + if (IS_CHAN_B(chan)) + return ATH9K_MODE_11B; if (IS_CHAN_G(chan)) return ATH9K_MODE_11G; + return ATH9K_MODE_11A; } -static bool ath9k_hw_wait(struct ath_hal *ah, - u32 reg, - u32 mask, - u32 val) +bool ath9k_hw_wait(struct ath_hal *ah, u32 reg, u32 mask, u32 val) { int i; @@ -221,54 +104,178 @@ static bool ath9k_hw_wait(struct ath_hal *ah, udelay(AH_TIME_QUANTUM); } - DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO, - "%s: timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n", - __func__, reg, REG_READ(ah, reg), mask, val); + + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n", + reg, REG_READ(ah, reg), mask, val); + return false; } -static bool ath9k_hw_eeprom_read(struct ath_hal *ah, u32 off, - u16 *data) +u32 ath9k_hw_reverse_bits(u32 val, u32 n) { - (void) REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S)); + u32 retval; + int i; - if (!ath9k_hw_wait(ah, - AR_EEPROM_STATUS_DATA, - AR_EEPROM_STATUS_DATA_BUSY | - AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0)) { - return false; + for (i = 0, retval = 0; i < n; i++) { + retval = (retval << 1) | (val & 1); + val >>= 1; } + return retval; +} - *data = MS(REG_READ(ah, AR_EEPROM_STATUS_DATA), - AR_EEPROM_STATUS_DATA_VAL); +bool ath9k_get_channel_edges(struct ath_hal *ah, + u16 flags, u16 *low, + u16 *high) +{ + struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - return true; + if (flags & CHANNEL_5GHZ) { + *low = pCap->low_5ghz_chan; + *high = pCap->high_5ghz_chan; + return true; + } + if ((flags & CHANNEL_2GHZ)) { + *low = pCap->low_2ghz_chan; + *high = pCap->high_2ghz_chan; + return true; + } + return false; } -static int ath9k_hw_flash_map(struct ath_hal *ah) +u16 ath9k_hw_computetxtime(struct ath_hal *ah, + struct ath_rate_table *rates, + u32 frameLen, u16 rateix, + bool shortPreamble) { - struct ath_hal_5416 *ahp = AH5416(ah); + u32 bitsPerSymbol, numBits, numSymbols, phyTime, txTime; + u32 kbps; - ahp->ah_cal_mem = ioremap(AR5416_EEPROM_START_ADDR, AR5416_EEPROM_MAX); + kbps = rates->info[rateix].ratekbps; - if (!ahp->ah_cal_mem) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "%s: cannot remap eeprom region \n", __func__); - return -EIO; + if (kbps == 0) + return 0; + + switch (rates->info[rateix].phy) { + case WLAN_RC_PHY_CCK: + phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS; + if (shortPreamble && rates->info[rateix].short_preamble) + phyTime >>= 1; + numBits = frameLen << 3; + txTime = CCK_SIFS_TIME + phyTime + ((numBits * 1000) / kbps); + break; + case WLAN_RC_PHY_OFDM: + if (ah->ah_curchan && IS_CHAN_QUARTER_RATE(ah->ah_curchan)) { + bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_QUARTER) / 1000; + numBits = OFDM_PLCP_BITS + (frameLen << 3); + numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol); + txTime = OFDM_SIFS_TIME_QUARTER + + OFDM_PREAMBLE_TIME_QUARTER + + (numSymbols * OFDM_SYMBOL_TIME_QUARTER); + } else if (ah->ah_curchan && + IS_CHAN_HALF_RATE(ah->ah_curchan)) { + bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_HALF) / 1000; + numBits = OFDM_PLCP_BITS + (frameLen << 3); + numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol); + txTime = OFDM_SIFS_TIME_HALF + + OFDM_PREAMBLE_TIME_HALF + + (numSymbols * OFDM_SYMBOL_TIME_HALF); + } else { + bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME) / 1000; + numBits = OFDM_PLCP_BITS + (frameLen << 3); + numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol); + txTime = OFDM_SIFS_TIME + OFDM_PREAMBLE_TIME + + (numSymbols * OFDM_SYMBOL_TIME); + } + break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "Unknown phy %u (rate ix %u)\n", + rates->info[rateix].phy, rateix); + txTime = 0; + break; } - return 0; + return txTime; +} + +u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags) +{ + if (flags & CHANNEL_2GHZ) { + if (freq == 2484) + return 14; + if (freq < 2484) + return (freq - 2407) / 5; + else + return 15 + ((freq - 2512) / 20); + } else if (flags & CHANNEL_5GHZ) { + if (ath9k_regd_is_public_safety_sku(ah) && + IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq)) { + return ((freq * 10) + + (((freq % 5) == 2) ? 5 : 0) - 49400) / 5; + } else if ((flags & CHANNEL_A) && (freq <= 5000)) { + return (freq - 4000) / 5; + } else { + return (freq - 5000) / 5; + } + } else { + if (freq == 2484) + return 14; + if (freq < 2484) + return (freq - 2407) / 5; + if (freq < 5000) { + if (ath9k_regd_is_public_safety_sku(ah) + && IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq)) { + return ((freq * 10) + + (((freq % 5) == + 2) ? 5 : 0) - 49400) / 5; + } else if (freq > 4900) { + return (freq - 4000) / 5; + } else { + return 15 + ((freq - 2512) / 20); + } + } + return (freq - 5000) / 5; + } } -static bool ath9k_hw_flash_read(struct ath_hal *ah, u32 off, - u16 *data) +void ath9k_hw_get_channel_centers(struct ath_hal *ah, + struct ath9k_channel *chan, + struct chan_centers *centers) { + int8_t extoff; struct ath_hal_5416 *ahp = AH5416(ah); - *data = ioread16(ahp->ah_cal_mem + off); - return true; + if (!IS_CHAN_HT40(chan)) { + centers->ctl_center = centers->ext_center = + centers->synth_center = chan->channel; + return; + } + + if ((chan->chanmode == CHANNEL_A_HT40PLUS) || + (chan->chanmode == CHANNEL_G_HT40PLUS)) { + centers->synth_center = + chan->channel + HT40_CHANNEL_CENTER_SHIFT; + extoff = 1; + } else { + centers->synth_center = + chan->channel - HT40_CHANNEL_CENTER_SHIFT; + extoff = -1; + } + + centers->ctl_center = + centers->synth_center - (extoff * HT40_CHANNEL_CENTER_SHIFT); + centers->ext_center = + centers->synth_center + (extoff * + ((ahp->ah_extprotspacing == ATH9K_HT_EXTPROTSPACING_20) ? + HT40_CHANNEL_CENTER_SHIFT : 15)); + } +/******************/ +/* Chip Revisions */ +/******************/ + static void ath9k_hw_read_revisions(struct ath_hal *ah) { u32 val; @@ -277,14 +284,9 @@ static void ath9k_hw_read_revisions(struct ath_hal *ah) if (val == 0xFF) { val = REG_READ(ah, AR_SREV); - - ah->ah_macVersion = - (val & AR_SREV_VERSION2) >> AR_SREV_TYPE2_S; - + ah->ah_macVersion = (val & AR_SREV_VERSION2) >> AR_SREV_TYPE2_S; ah->ah_macRev = MS(val, AR_SREV_REVISION2); - ah->ah_isPciExpress = - (val & AR_SREV_TYPE2_HOST_MODE) ? 0 : 1; - + ah->ah_isPciExpress = (val & AR_SREV_TYPE2_HOST_MODE) ? 0 : 1; } else { if (!AR_SREV_9100(ah)) ah->ah_macVersion = MS(val, AR_SREV_VERSION); @@ -296,4828 +298,736 @@ static void ath9k_hw_read_revisions(struct ath_hal *ah) } } -u32 ath9k_hw_reverse_bits(u32 val, u32 n) -{ - u32 retval; - int i; - - for (i = 0, retval = 0; i < n; i++) { - retval = (retval << 1) | (val & 1); - val >>= 1; - } - return retval; -} - -static void ath9k_hw_set_defaults(struct ath_hal *ah) +static int ath9k_hw_get_radiorev(struct ath_hal *ah) { + u32 val; int i; - ah->ah_config.dma_beacon_response_time = 2; - ah->ah_config.sw_beacon_response_time = 10; - ah->ah_config.additional_swba_backoff = 0; - ah->ah_config.ack_6mb = 0x0; - ah->ah_config.cwm_ignore_extcca = 0; - ah->ah_config.pcie_powersave_enable = 0; - ah->ah_config.pcie_l1skp_enable = 0; - ah->ah_config.pcie_clock_req = 0; - ah->ah_config.pcie_power_reset = 0x100; - ah->ah_config.pcie_restore = 0; - ah->ah_config.pcie_waen = 0; - ah->ah_config.analog_shiftreg = 1; - ah->ah_config.ht_enable = 1; - ah->ah_config.ofdm_trig_low = 200; - ah->ah_config.ofdm_trig_high = 500; - ah->ah_config.cck_trig_high = 200; - ah->ah_config.cck_trig_low = 100; - ah->ah_config.enable_ani = 1; - ah->ah_config.noise_immunity_level = 4; - ah->ah_config.ofdm_weaksignal_det = 1; - ah->ah_config.cck_weaksignal_thr = 0; - ah->ah_config.spur_immunity_level = 2; - ah->ah_config.firstep_level = 0; - ah->ah_config.rssi_thr_high = 40; - ah->ah_config.rssi_thr_low = 7; - ah->ah_config.diversity_control = 0; - ah->ah_config.antenna_switch_swap = 0; + REG_WRITE(ah, AR_PHY(0x36), 0x00007058); - for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { - ah->ah_config.spurchans[i][0] = AR_NO_SPUR; - ah->ah_config.spurchans[i][1] = AR_NO_SPUR; - } + for (i = 0; i < 8; i++) + REG_WRITE(ah, AR_PHY(0x20), 0x00010000); + val = (REG_READ(ah, AR_PHY(256)) >> 24) & 0xff; + val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4); - ah->ah_config.intr_mitigation = 0; + return ath9k_hw_reverse_bits(val, 8); } -static void ath9k_hw_override_ini(struct ath_hal *ah, - struct ath9k_channel *chan) +/************************************/ +/* HW Attach, Detach, Init Routines */ +/************************************/ + +static void ath9k_hw_disablepcie(struct ath_hal *ah) { - if (!AR_SREV_5416_V20_OR_LATER(ah) - || AR_SREV_9280_10_OR_LATER(ah)) + if (!AR_SREV_9100(ah)) return; - REG_WRITE(ah, 0x9800 + (651 << 2), 0x11); + REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00); + REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924); + REG_WRITE(ah, AR_PCIE_SERDES, 0x28000029); + REG_WRITE(ah, AR_PCIE_SERDES, 0x57160824); + REG_WRITE(ah, AR_PCIE_SERDES, 0x25980579); + REG_WRITE(ah, AR_PCIE_SERDES, 0x00000000); + REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40); + REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554); + REG_WRITE(ah, AR_PCIE_SERDES, 0x000e1007); + + REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); } -static void ath9k_hw_init_bb(struct ath_hal *ah, - struct ath9k_channel *chan) +static bool ath9k_hw_chip_test(struct ath_hal *ah) { - u32 synthDelay; + u32 regAddr[2] = { AR_STA_ID0, AR_PHY_BASE + (8 << 2) }; + u32 regHold[2]; + u32 patternData[4] = { 0x55555555, + 0xaaaaaaaa, + 0x66666666, + 0x99999999 }; + int i, j; - synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; - if (IS_CHAN_CCK(chan)) - synthDelay = (4 * synthDelay) / 22; - else - synthDelay /= 10; - - REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); + for (i = 0; i < 2; i++) { + u32 addr = regAddr[i]; + u32 wrData, rdData; - udelay(synthDelay + BASE_ACTIVATE_DELAY); + regHold[i] = REG_READ(ah, addr); + for (j = 0; j < 0x100; j++) { + wrData = (j << 16) | j; + REG_WRITE(ah, addr, wrData); + rdData = REG_READ(ah, addr); + if (rdData != wrData) { + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "address test failed " + "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n", + addr, wrData, rdData); + return false; + } + } + for (j = 0; j < 4; j++) { + wrData = patternData[j]; + REG_WRITE(ah, addr, wrData); + rdData = REG_READ(ah, addr); + if (wrData != rdData) { + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "address test failed " + "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n", + addr, wrData, rdData); + return false; + } + } + REG_WRITE(ah, regAddr[i], regHold[i]); + } + udelay(100); + return true; } -static void ath9k_hw_init_interrupt_masks(struct ath_hal *ah, - enum ath9k_opmode opmode) +static const char *ath9k_hw_devname(u16 devid) { - struct ath_hal_5416 *ahp = AH5416(ah); - - ahp->ah_maskReg = AR_IMR_TXERR | - AR_IMR_TXURN | - AR_IMR_RXERR | - AR_IMR_RXORN | - AR_IMR_BCNMISC; - - if (ahp->ah_intrMitigation) - ahp->ah_maskReg |= AR_IMR_RXINTM | AR_IMR_RXMINTR; - else - ahp->ah_maskReg |= AR_IMR_RXOK; + switch (devid) { + case AR5416_DEVID_PCI: + return "Atheros 5416"; + case AR5416_DEVID_PCIE: + return "Atheros 5418"; + case AR9160_DEVID_PCI: + return "Atheros 9160"; + case AR9280_DEVID_PCI: + case AR9280_DEVID_PCIE: + return "Atheros 9280"; + case AR9285_DEVID_PCIE: + return "Atheros 9285"; + } - ahp->ah_maskReg |= AR_IMR_TXOK; + return NULL; +} - if (opmode == ATH9K_M_HOSTAP) - ahp->ah_maskReg |= AR_IMR_MIB; +static void ath9k_hw_set_defaults(struct ath_hal *ah) +{ + int i; - REG_WRITE(ah, AR_IMR, ahp->ah_maskReg); - REG_WRITE(ah, AR_IMR_S2, REG_READ(ah, AR_IMR_S2) | AR_IMR_S2_GTT); + ah->ah_config.dma_beacon_response_time = 2; + ah->ah_config.sw_beacon_response_time = 10; + ah->ah_config.additional_swba_backoff = 0; + ah->ah_config.ack_6mb = 0x0; + ah->ah_config.cwm_ignore_extcca = 0; + ah->ah_config.pcie_powersave_enable = 0; + ah->ah_config.pcie_l1skp_enable = 0; + ah->ah_config.pcie_clock_req = 0; + ah->ah_config.pcie_power_reset = 0x100; + ah->ah_config.pcie_restore = 0; + ah->ah_config.pcie_waen = 0; + ah->ah_config.analog_shiftreg = 1; + ah->ah_config.ht_enable = 1; + ah->ah_config.ofdm_trig_low = 200; + ah->ah_config.ofdm_trig_high = 500; + ah->ah_config.cck_trig_high = 200; + ah->ah_config.cck_trig_low = 100; + ah->ah_config.enable_ani = 1; + ah->ah_config.noise_immunity_level = 4; + ah->ah_config.ofdm_weaksignal_det = 1; + ah->ah_config.cck_weaksignal_thr = 0; + ah->ah_config.spur_immunity_level = 2; + ah->ah_config.firstep_level = 0; + ah->ah_config.rssi_thr_high = 40; + ah->ah_config.rssi_thr_low = 7; + ah->ah_config.diversity_control = 0; + ah->ah_config.antenna_switch_swap = 0; - if (!AR_SREV_9100(ah)) { - REG_WRITE(ah, AR_INTR_SYNC_CAUSE, 0xFFFFFFFF); - REG_WRITE(ah, AR_INTR_SYNC_ENABLE, AR_INTR_SYNC_DEFAULT); - REG_WRITE(ah, AR_INTR_SYNC_MASK, 0); + for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { + ah->ah_config.spurchans[i][0] = AR_NO_SPUR; + ah->ah_config.spurchans[i][1] = AR_NO_SPUR; } + + ah->ah_config.intr_mitigation = 1; } -static void ath9k_hw_init_qos(struct ath_hal *ah) +static struct ath_hal_5416 *ath9k_hw_newstate(u16 devid, + struct ath_softc *sc, + void __iomem *mem, + int *status) { - REG_WRITE(ah, AR_MIC_QOS_CONTROL, 0x100aa); - REG_WRITE(ah, AR_MIC_QOS_SELECT, 0x3210); - - REG_WRITE(ah, AR_QOS_NO_ACK, - SM(2, AR_QOS_NO_ACK_TWO_BIT) | - SM(5, AR_QOS_NO_ACK_BIT_OFF) | - SM(0, AR_QOS_NO_ACK_BYTE_OFF)); + static const u8 defbssidmask[ETH_ALEN] = + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + struct ath_hal_5416 *ahp; + struct ath_hal *ah; - REG_WRITE(ah, AR_TXOP_X, AR_TXOP_X_VAL); - REG_WRITE(ah, AR_TXOP_0_3, 0xFFFFFFFF); - REG_WRITE(ah, AR_TXOP_4_7, 0xFFFFFFFF); - REG_WRITE(ah, AR_TXOP_8_11, 0xFFFFFFFF); - REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF); -} + ahp = kzalloc(sizeof(struct ath_hal_5416), GFP_KERNEL); + if (ahp == NULL) { + DPRINTF(sc, ATH_DBG_FATAL, + "Cannot allocate memory for state block\n"); + *status = -ENOMEM; + return NULL; + } -static void ath9k_hw_analog_shift_rmw(struct ath_hal *ah, - u32 reg, - u32 mask, - u32 shift, - u32 val) -{ - u32 regVal; + ah = &ahp->ah; + ah->ah_sc = sc; + ah->ah_sh = mem; + ah->ah_magic = AR5416_MAGIC; + ah->ah_countryCode = CTRY_DEFAULT; + ah->ah_devid = devid; + ah->ah_subvendorid = 0; - regVal = REG_READ(ah, reg) & ~mask; - regVal |= (val << shift) & mask; + ah->ah_flags = 0; + if ((devid == AR5416_AR9100_DEVID)) + ah->ah_macVersion = AR_SREV_VERSION_9100; + if (!AR_SREV_9100(ah)) + ah->ah_flags = AH_USE_EEPROM; - REG_WRITE(ah, reg, regVal); + ah->ah_powerLimit = MAX_RATE_POWER; + ah->ah_tpScale = ATH9K_TP_SCALE_MAX; + ahp->ah_atimWindow = 0; + ahp->ah_diversityControl = ah->ah_config.diversity_control; + ahp->ah_antennaSwitchSwap = + ah->ah_config.antenna_switch_swap; + ahp->ah_staId1Defaults = AR_STA_ID1_CRPT_MIC_ENABLE; + ahp->ah_beaconInterval = 100; + ahp->ah_enable32kHzClock = DONT_USE_32KHZ; + ahp->ah_slottime = (u32) -1; + ahp->ah_acktimeout = (u32) -1; + ahp->ah_ctstimeout = (u32) -1; + ahp->ah_globaltxtimeout = (u32) -1; + memcpy(&ahp->ah_bssidmask, defbssidmask, ETH_ALEN); - if (ah->ah_config.analog_shiftreg) - udelay(100); + ahp->ah_gBeaconRate = 0; - return; + return ahp; } -static u8 ath9k_hw_get_num_ant_config(struct ath_hal_5416 *ahp, - enum ieee80211_band freq_band) +static int ath9k_hw_rfattach(struct ath_hal *ah) { - struct ar5416_eeprom *eep = &ahp->ah_eeprom; - struct modal_eep_header *pModal = - &(eep->modalHeader[IEEE80211_BAND_5GHZ == freq_band]); - struct base_eep_header *pBase = &eep->baseEepHeader; - u8 num_ant_config; - - num_ant_config = 1; + bool rfStatus = false; + int ecode = 0; - if (pBase->version >= 0x0E0D) - if (pModal->useAnt1) - num_ant_config += 1; + rfStatus = ath9k_hw_init_rf(ah, &ecode); + if (!rfStatus) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, + "RF setup failed, status %u\n", ecode); + return ecode; + } - return num_ant_config; + return 0; } -static int -ath9k_hw_get_eeprom_antenna_cfg(struct ath_hal_5416 *ahp, - struct ath9k_channel *chan, - u8 index, - u16 *config) +static int ath9k_hw_rf_claim(struct ath_hal *ah) { - struct ar5416_eeprom *eep = &ahp->ah_eeprom; - struct modal_eep_header *pModal = - &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); - struct base_eep_header *pBase = &eep->baseEepHeader; + u32 val; + + REG_WRITE(ah, AR_PHY(0), 0x00000007); - switch (index) { + val = ath9k_hw_get_radiorev(ah); + switch (val & AR_RADIO_SREV_MAJOR) { case 0: - *config = pModal->antCtrlCommon & 0xFFFF; - return 0; - case 1: - if (pBase->version >= 0x0E0D) { - if (pModal->useAnt1) { - *config = - ((pModal->antCtrlCommon & 0xFFFF0000) >> 16); - return 0; - } - } + val = AR_RAD5133_SREV_MAJOR; break; - default: + case AR_RAD5133_SREV_MAJOR: + case AR_RAD5122_SREV_MAJOR: + case AR_RAD2133_SREV_MAJOR: + case AR_RAD2122_SREV_MAJOR: break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, + "5G Radio Chip Rev 0x%02X is not " + "supported by this driver\n", + ah->ah_analog5GhzRev); + return -EOPNOTSUPP; } - return -EINVAL; -} + ah->ah_analog5GhzRev = val; -static inline bool ath9k_hw_nvram_read(struct ath_hal *ah, - u32 off, - u16 *data) -{ - if (ath9k_hw_use_flash(ah)) - return ath9k_hw_flash_read(ah, off, data); - else - return ath9k_hw_eeprom_read(ah, off, data); + return 0; } -static bool ath9k_hw_fill_eeprom(struct ath_hal *ah) +static int ath9k_hw_init_macaddr(struct ath_hal *ah) { + u32 sum; + int i; + u16 eeval; struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom *eep = &ahp->ah_eeprom; - u16 *eep_data; - int addr, ar5416_eep_start_loc = 0; - if (!ath9k_hw_use_flash(ah)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "%s: Reading from EEPROM, not flash\n", __func__); - ar5416_eep_start_loc = 256; + sum = 0; + for (i = 0; i < 3; i++) { + eeval = ath9k_hw_get_eeprom(ah, AR_EEPROM_MAC(i)); + sum += eeval; + ahp->ah_macaddr[2 * i] = eeval >> 8; + ahp->ah_macaddr[2 * i + 1] = eeval & 0xff; } - if (AR_SREV_9100(ah)) - ar5416_eep_start_loc = 256; - - eep_data = (u16 *) eep; - for (addr = 0; - addr < sizeof(struct ar5416_eeprom) / sizeof(u16); - addr++) { - if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc, - eep_data)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "%s: Unable to read eeprom region \n", - __func__); - return false; - } - eep_data++; + if (sum == 0 || sum == 0xffff * 3) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "mac address read failed: %pM\n", + ahp->ah_macaddr); + return -EADDRNOTAVAIL; } - return true; + + return 0; } -/* XXX: Clean me up, make me more legible */ -static bool -ath9k_hw_eeprom_set_board_values(struct ath_hal *ah, - struct ath9k_channel *chan) +static void ath9k_hw_init_rxgain_ini(struct ath_hal *ah) { - struct modal_eep_header *pModal; - int i, regChainOffset; + u32 rxgain_type; struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom *eep = &ahp->ah_eeprom; - u8 txRxAttenLocal; - u16 ant_config; - pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); + if (ath9k_hw_get_eeprom(ah, EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_17) { + rxgain_type = ath9k_hw_get_eeprom(ah, EEP_RXGAIN_TYPE); - txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44; + if (rxgain_type == AR5416_EEP_RXGAIN_13DB_BACKOFF) + INIT_INI_ARRAY(&ahp->ah_iniModesRxGain, + ar9280Modes_backoff_13db_rxgain_9280_2, + ARRAY_SIZE(ar9280Modes_backoff_13db_rxgain_9280_2), 6); + else if (rxgain_type == AR5416_EEP_RXGAIN_23DB_BACKOFF) + INIT_INI_ARRAY(&ahp->ah_iniModesRxGain, + ar9280Modes_backoff_23db_rxgain_9280_2, + ARRAY_SIZE(ar9280Modes_backoff_23db_rxgain_9280_2), 6); + else + INIT_INI_ARRAY(&ahp->ah_iniModesRxGain, + ar9280Modes_original_rxgain_9280_2, + ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 6); + } else + INIT_INI_ARRAY(&ahp->ah_iniModesRxGain, + ar9280Modes_original_rxgain_9280_2, + ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 6); +} - ath9k_hw_get_eeprom_antenna_cfg(ahp, chan, 1, &ant_config); - REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config); +static void ath9k_hw_init_txgain_ini(struct ath_hal *ah) +{ + u32 txgain_type; + struct ath_hal_5416 *ahp = AH5416(ah); - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - if (AR_SREV_9280(ah)) { - if (i >= 2) - break; - } + if (ath9k_hw_get_eeprom(ah, EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_19) { + txgain_type = ath9k_hw_get_eeprom(ah, EEP_TXGAIN_TYPE); - if (AR_SREV_5416_V20_OR_LATER(ah) && - (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5) - && (i != 0)) - regChainOffset = (i == 1) ? 0x2000 : 0x1000; + if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER) + INIT_INI_ARRAY(&ahp->ah_iniModesTxGain, + ar9280Modes_high_power_tx_gain_9280_2, + ARRAY_SIZE(ar9280Modes_high_power_tx_gain_9280_2), 6); else - regChainOffset = i * 0x1000; - - REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, - pModal->antCtrlChain[i]); - - REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, - (REG_READ(ah, - AR_PHY_TIMING_CTRL4(0) + - regChainOffset) & - ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | - AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | - SM(pModal->iqCalICh[i], - AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | - SM(pModal->iqCalQCh[i], - AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); - - if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) { - if ((eep->baseEepHeader.version & - AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_3) { - txRxAttenLocal = pModal->txRxAttenCh[i]; - if (AR_SREV_9280_10_OR_LATER(ah)) { - REG_RMW_FIELD(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, - pModal-> - bswMargin[i]); - REG_RMW_FIELD(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN1_DB, - pModal-> - bswAtten[i]); - REG_RMW_FIELD(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, - pModal-> - xatten2Margin[i]); - REG_RMW_FIELD(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN2_DB, - pModal-> - xatten2Db[i]); - } else { - REG_WRITE(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset, - (REG_READ(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset) & - ~AR_PHY_GAIN_2GHZ_BSW_MARGIN) - | SM(pModal-> - bswMargin[i], - AR_PHY_GAIN_2GHZ_BSW_MARGIN)); - REG_WRITE(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset, - (REG_READ(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset) & - ~AR_PHY_GAIN_2GHZ_BSW_ATTEN) - | SM(pModal->bswAtten[i], - AR_PHY_GAIN_2GHZ_BSW_ATTEN)); - } - } - if (AR_SREV_9280_10_OR_LATER(ah)) { - REG_RMW_FIELD(ah, - AR_PHY_RXGAIN + - regChainOffset, - AR9280_PHY_RXGAIN_TXRX_ATTEN, - txRxAttenLocal); - REG_RMW_FIELD(ah, - AR_PHY_RXGAIN + - regChainOffset, - AR9280_PHY_RXGAIN_TXRX_MARGIN, - pModal->rxTxMarginCh[i]); - } else { - REG_WRITE(ah, - AR_PHY_RXGAIN + regChainOffset, - (REG_READ(ah, - AR_PHY_RXGAIN + - regChainOffset) & - ~AR_PHY_RXGAIN_TXRX_ATTEN) | - SM(txRxAttenLocal, - AR_PHY_RXGAIN_TXRX_ATTEN)); - REG_WRITE(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset, - (REG_READ(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset) & - ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) | - SM(pModal->rxTxMarginCh[i], - AR_PHY_GAIN_2GHZ_RXTX_MARGIN)); - } - } - } + INIT_INI_ARRAY(&ahp->ah_iniModesTxGain, + ar9280Modes_original_tx_gain_9280_2, + ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 6); + } else + INIT_INI_ARRAY(&ahp->ah_iniModesTxGain, + ar9280Modes_original_tx_gain_9280_2, + ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 6); +} - if (AR_SREV_9280_10_OR_LATER(ah)) { - if (IS_CHAN_2GHZ(chan)) { - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0, - AR_AN_RF2G1_CH0_OB, - AR_AN_RF2G1_CH0_OB_S, - pModal->ob); - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0, - AR_AN_RF2G1_CH0_DB, - AR_AN_RF2G1_CH0_DB_S, - pModal->db); - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1, - AR_AN_RF2G1_CH1_OB, - AR_AN_RF2G1_CH1_OB_S, - pModal->ob_ch1); - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1, - AR_AN_RF2G1_CH1_DB, - AR_AN_RF2G1_CH1_DB_S, - pModal->db_ch1); - } else { - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0, - AR_AN_RF5G1_CH0_OB5, - AR_AN_RF5G1_CH0_OB5_S, - pModal->ob); - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0, - AR_AN_RF5G1_CH0_DB5, - AR_AN_RF5G1_CH0_DB5_S, - pModal->db); - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1, - AR_AN_RF5G1_CH1_OB5, - AR_AN_RF5G1_CH1_OB5_S, - pModal->ob_ch1); - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1, - AR_AN_RF5G1_CH1_DB5, - AR_AN_RF5G1_CH1_DB5_S, - pModal->db_ch1); - } - ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2, - AR_AN_TOP2_XPABIAS_LVL, - AR_AN_TOP2_XPABIAS_LVL_S, - pModal->xpaBiasLvl); - ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2, - AR_AN_TOP2_LOCALBIAS, - AR_AN_TOP2_LOCALBIAS_S, - pModal->local_bias); - DPRINTF(ah->ah_sc, ATH_DBG_ANY, "ForceXPAon: %d\n", - pModal->force_xpaon); - REG_RMW_FIELD(ah, AR_PHY_XPA_CFG, AR_PHY_FORCE_XPA_CFG, - pModal->force_xpaon); +static int ath9k_hw_post_attach(struct ath_hal *ah) +{ + int ecode; + + if (!ath9k_hw_chip_test(ah)) { + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "hardware self-test failed\n"); + return -ENODEV; } - REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, - pModal->switchSettling); - REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, - pModal->adcDesiredSize); + ecode = ath9k_hw_rf_claim(ah); + if (ecode != 0) + return ecode; - if (!AR_SREV_9280_10_OR_LATER(ah)) - REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, - AR_PHY_DESIRED_SZ_PGA, - pModal->pgaDesiredSize); - - REG_WRITE(ah, AR_PHY_RF_CTL4, - SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) - | SM(pModal->txEndToXpaOff, - AR_PHY_RF_CTL4_TX_END_XPAB_OFF) - | SM(pModal->txFrameToXpaOn, - AR_PHY_RF_CTL4_FRAME_XPAA_ON) - | SM(pModal->txFrameToXpaOn, - AR_PHY_RF_CTL4_FRAME_XPAB_ON)); - - REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, - pModal->txEndToRxOn); - if (AR_SREV_9280_10_OR_LATER(ah)) { - REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, - pModal->thresh62); - REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, - AR_PHY_EXT_CCA0_THRESH62, - pModal->thresh62); - } else { - REG_RMW_FIELD(ah, AR_PHY_CCA, AR_PHY_CCA_THRESH62, - pModal->thresh62); - REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, - AR_PHY_EXT_CCA_THRESH62, - pModal->thresh62); - } + ecode = ath9k_hw_eeprom_attach(ah); + if (ecode != 0) + return ecode; + ecode = ath9k_hw_rfattach(ah); + if (ecode != 0) + return ecode; - if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_2) { - REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, - AR_PHY_TX_END_DATA_START, - pModal->txFrameToDataStart); - REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON, - pModal->txFrameToPaOn); + if (!AR_SREV_9100(ah)) { + ath9k_hw_ani_setup(ah); + ath9k_hw_ani_attach(ah); } - if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_3) { - if (IS_CHAN_HT40(chan)) - REG_RMW_FIELD(ah, AR_PHY_SETTLING, - AR_PHY_SETTLING_SWITCH, - pModal->swSettleHt40); - } + return 0; +} - return true; -} - -static int ath9k_hw_check_eeprom(struct ath_hal *ah) +static struct ath_hal *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, + void __iomem *mem, int *status) { - u32 sum = 0, el; - u16 *eepdata; - int i; - struct ath_hal_5416 *ahp = AH5416(ah); - bool need_swap = false; - struct ar5416_eeprom *eep = - (struct ar5416_eeprom *) &ahp->ah_eeprom; - - if (!ath9k_hw_use_flash(ah)) { - u16 magic, magic2; - int addr; - - if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, - &magic)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "%s: Reading Magic # failed\n", __func__); - return false; - } - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "%s: Read Magic = 0x%04X\n", - __func__, magic); - - if (magic != AR5416_EEPROM_MAGIC) { - magic2 = swab16(magic); - - if (magic2 == AR5416_EEPROM_MAGIC) { - need_swap = true; - eepdata = (u16 *) (&ahp->ah_eeprom); - - for (addr = 0; - addr < - sizeof(struct ar5416_eeprom) / - sizeof(u16); addr++) { - u16 temp; - - temp = swab16(*eepdata); - *eepdata = temp; - eepdata++; - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "0x%04X ", *eepdata); - if (((addr + 1) % 6) == 0) - DPRINTF(ah->ah_sc, - ATH_DBG_EEPROM, - "\n"); - } - } else { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Invalid EEPROM Magic. " - "endianness missmatch.\n"); - return -EINVAL; - } + struct ath_hal_5416 *ahp; + struct ath_hal *ah; + int ecode; + u32 i, j; + + ahp = ath9k_hw_newstate(devid, sc, mem, status); + if (ahp == NULL) + return NULL; + + ah = &ahp->ah; + + ath9k_hw_set_defaults(ah); + + if (ah->ah_config.intr_mitigation != 0) + ahp->ah_intrMitigation = true; + + if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "Couldn't reset chip\n"); + ecode = -EIO; + goto bad; + } + + if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "Couldn't wakeup chip\n"); + ecode = -EIO; + goto bad; + } + + if (ah->ah_config.serialize_regmode == SER_REG_MODE_AUTO) { + if (ah->ah_macVersion == AR_SREV_VERSION_5416_PCI) { + ah->ah_config.serialize_regmode = + SER_REG_MODE_ON; + } else { + ah->ah_config.serialize_regmode = + SER_REG_MODE_OFF; } } - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", - need_swap ? "True" : "False"); - if (need_swap) - el = swab16(ahp->ah_eeprom.baseEepHeader.length); - else - el = ahp->ah_eeprom.baseEepHeader.length; + DPRINTF(ah->ah_sc, ATH_DBG_RESET, + "serialize_regmode is %d\n", + ah->ah_config.serialize_regmode); - if (el > sizeof(struct ar5416_eeprom)) - el = sizeof(struct ar5416_eeprom) / sizeof(u16); - else - el = el / sizeof(u16); + if ((ah->ah_macVersion != AR_SREV_VERSION_5416_PCI) && + (ah->ah_macVersion != AR_SREV_VERSION_5416_PCIE) && + (ah->ah_macVersion != AR_SREV_VERSION_9160) && + (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah)) && (!AR_SREV_9285(ah))) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, + "Mac Chip Rev 0x%02x.%x is not supported by " + "this driver\n", ah->ah_macVersion, ah->ah_macRev); + ecode = -EOPNOTSUPP; + goto bad; + } - eepdata = (u16 *) (&ahp->ah_eeprom); + if (AR_SREV_9100(ah)) { + ahp->ah_iqCalData.calData = &iq_cal_multi_sample; + ahp->ah_suppCals = IQ_MISMATCH_CAL; + ah->ah_isPciExpress = false; + } + ah->ah_phyRev = REG_READ(ah, AR_PHY_CHIP_ID); - for (i = 0; i < el; i++) - sum ^= *eepdata++; + if (AR_SREV_9160_10_OR_LATER(ah)) { + if (AR_SREV_9280_10_OR_LATER(ah)) { + ahp->ah_iqCalData.calData = &iq_cal_single_sample; + ahp->ah_adcGainCalData.calData = + &adc_gain_cal_single_sample; + ahp->ah_adcDcCalData.calData = + &adc_dc_cal_single_sample; + ahp->ah_adcDcCalInitData.calData = + &adc_init_dc_cal; + } else { + ahp->ah_iqCalData.calData = &iq_cal_multi_sample; + ahp->ah_adcGainCalData.calData = + &adc_gain_cal_multi_sample; + ahp->ah_adcDcCalData.calData = + &adc_dc_cal_multi_sample; + ahp->ah_adcDcCalInitData.calData = + &adc_init_dc_cal; + } + ahp->ah_suppCals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL; + } - if (need_swap) { - u32 integer, j; - u16 word; + if (AR_SREV_9160(ah)) { + ah->ah_config.enable_ani = 1; + ahp->ah_ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL | + ATH9K_ANI_FIRSTEP_LEVEL); + } else { + ahp->ah_ani_function = ATH9K_ANI_ALL; + if (AR_SREV_9280_10_OR_LATER(ah)) { + ahp->ah_ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL; + } + } - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "EEPROM Endianness is not native.. Changing \n"); + DPRINTF(ah->ah_sc, ATH_DBG_RESET, + "This Mac Chip Rev 0x%02x.%x is \n", + ah->ah_macVersion, ah->ah_macRev); - word = swab16(eep->baseEepHeader.length); - eep->baseEepHeader.length = word; + if (AR_SREV_9285_12_OR_LATER(ah)) { + INIT_INI_ARRAY(&ahp->ah_iniModes, ar9285Modes_9285_1_2, + ARRAY_SIZE(ar9285Modes_9285_1_2), 6); + INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9285Common_9285_1_2, + ARRAY_SIZE(ar9285Common_9285_1_2), 2); - word = swab16(eep->baseEepHeader.checksum); - eep->baseEepHeader.checksum = word; + if (ah->ah_config.pcie_clock_req) { + INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes, + ar9285PciePhy_clkreq_off_L1_9285_1_2, + ARRAY_SIZE(ar9285PciePhy_clkreq_off_L1_9285_1_2), 2); + } else { + INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes, + ar9285PciePhy_clkreq_always_on_L1_9285_1_2, + ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285_1_2), + 2); + } + } else if (AR_SREV_9285_10_OR_LATER(ah)) { + INIT_INI_ARRAY(&ahp->ah_iniModes, ar9285Modes_9285, + ARRAY_SIZE(ar9285Modes_9285), 6); + INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9285Common_9285, + ARRAY_SIZE(ar9285Common_9285), 2); - word = swab16(eep->baseEepHeader.version); - eep->baseEepHeader.version = word; + if (ah->ah_config.pcie_clock_req) { + INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes, + ar9285PciePhy_clkreq_off_L1_9285, + ARRAY_SIZE(ar9285PciePhy_clkreq_off_L1_9285), 2); + } else { + INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes, + ar9285PciePhy_clkreq_always_on_L1_9285, + ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285), 2); + } + } else if (AR_SREV_9280_20_OR_LATER(ah)) { + INIT_INI_ARRAY(&ahp->ah_iniModes, ar9280Modes_9280_2, + ARRAY_SIZE(ar9280Modes_9280_2), 6); + INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9280Common_9280_2, + ARRAY_SIZE(ar9280Common_9280_2), 2); - word = swab16(eep->baseEepHeader.regDmn[0]); - eep->baseEepHeader.regDmn[0] = word; + if (ah->ah_config.pcie_clock_req) { + INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes, + ar9280PciePhy_clkreq_off_L1_9280, + ARRAY_SIZE(ar9280PciePhy_clkreq_off_L1_9280),2); + } else { + INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes, + ar9280PciePhy_clkreq_always_on_L1_9280, + ARRAY_SIZE(ar9280PciePhy_clkreq_always_on_L1_9280), 2); + } + INIT_INI_ARRAY(&ahp->ah_iniModesAdditional, + ar9280Modes_fast_clock_9280_2, + ARRAY_SIZE(ar9280Modes_fast_clock_9280_2), 3); + } else if (AR_SREV_9280_10_OR_LATER(ah)) { + INIT_INI_ARRAY(&ahp->ah_iniModes, ar9280Modes_9280, + ARRAY_SIZE(ar9280Modes_9280), 6); + INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9280Common_9280, + ARRAY_SIZE(ar9280Common_9280), 2); + } else if (AR_SREV_9160_10_OR_LATER(ah)) { + INIT_INI_ARRAY(&ahp->ah_iniModes, ar5416Modes_9160, + ARRAY_SIZE(ar5416Modes_9160), 6); + INIT_INI_ARRAY(&ahp->ah_iniCommon, ar5416Common_9160, + ARRAY_SIZE(ar5416Common_9160), 2); + INIT_INI_ARRAY(&ahp->ah_iniBank0, ar5416Bank0_9160, + ARRAY_SIZE(ar5416Bank0_9160), 2); + INIT_INI_ARRAY(&ahp->ah_iniBB_RfGain, ar5416BB_RfGain_9160, + ARRAY_SIZE(ar5416BB_RfGain_9160), 3); + INIT_INI_ARRAY(&ahp->ah_iniBank1, ar5416Bank1_9160, + ARRAY_SIZE(ar5416Bank1_9160), 2); + INIT_INI_ARRAY(&ahp->ah_iniBank2, ar5416Bank2_9160, + ARRAY_SIZE(ar5416Bank2_9160), 2); + INIT_INI_ARRAY(&ahp->ah_iniBank3, ar5416Bank3_9160, + ARRAY_SIZE(ar5416Bank3_9160), 3); + INIT_INI_ARRAY(&ahp->ah_iniBank6, ar5416Bank6_9160, + ARRAY_SIZE(ar5416Bank6_9160), 3); + INIT_INI_ARRAY(&ahp->ah_iniBank6TPC, ar5416Bank6TPC_9160, + ARRAY_SIZE(ar5416Bank6TPC_9160), 3); + INIT_INI_ARRAY(&ahp->ah_iniBank7, ar5416Bank7_9160, + ARRAY_SIZE(ar5416Bank7_9160), 2); + if (AR_SREV_9160_11(ah)) { + INIT_INI_ARRAY(&ahp->ah_iniAddac, + ar5416Addac_91601_1, + ARRAY_SIZE(ar5416Addac_91601_1), 2); + } else { + INIT_INI_ARRAY(&ahp->ah_iniAddac, ar5416Addac_9160, + ARRAY_SIZE(ar5416Addac_9160), 2); + } + } else if (AR_SREV_9100_OR_LATER(ah)) { + INIT_INI_ARRAY(&ahp->ah_iniModes, ar5416Modes_9100, + ARRAY_SIZE(ar5416Modes_9100), 6); + INIT_INI_ARRAY(&ahp->ah_iniCommon, ar5416Common_9100, + ARRAY_SIZE(ar5416Common_9100), 2); + INIT_INI_ARRAY(&ahp->ah_iniBank0, ar5416Bank0_9100, + ARRAY_SIZE(ar5416Bank0_9100), 2); + INIT_INI_ARRAY(&ahp->ah_iniBB_RfGain, ar5416BB_RfGain_9100, + ARRAY_SIZE(ar5416BB_RfGain_9100), 3); + INIT_INI_ARRAY(&ahp->ah_iniBank1, ar5416Bank1_9100, + ARRAY_SIZE(ar5416Bank1_9100), 2); + INIT_INI_ARRAY(&ahp->ah_iniBank2, ar5416Bank2_9100, + ARRAY_SIZE(ar5416Bank2_9100), 2); + INIT_INI_ARRAY(&ahp->ah_iniBank3, ar5416Bank3_9100, + ARRAY_SIZE(ar5416Bank3_9100), 3); + INIT_INI_ARRAY(&ahp->ah_iniBank6, ar5416Bank6_9100, + ARRAY_SIZE(ar5416Bank6_9100), 3); + INIT_INI_ARRAY(&ahp->ah_iniBank6TPC, ar5416Bank6TPC_9100, + ARRAY_SIZE(ar5416Bank6TPC_9100), 3); + INIT_INI_ARRAY(&ahp->ah_iniBank7, ar5416Bank7_9100, + ARRAY_SIZE(ar5416Bank7_9100), 2); + INIT_INI_ARRAY(&ahp->ah_iniAddac, ar5416Addac_9100, + ARRAY_SIZE(ar5416Addac_9100), 2); + } else { + INIT_INI_ARRAY(&ahp->ah_iniModes, ar5416Modes, + ARRAY_SIZE(ar5416Modes), 6); + INIT_INI_ARRAY(&ahp->ah_iniCommon, ar5416Common, + ARRAY_SIZE(ar5416Common), 2); + INIT_INI_ARRAY(&ahp->ah_iniBank0, ar5416Bank0, + ARRAY_SIZE(ar5416Bank0), 2); + INIT_INI_ARRAY(&ahp->ah_iniBB_RfGain, ar5416BB_RfGain, + ARRAY_SIZE(ar5416BB_RfGain), 3); + INIT_INI_ARRAY(&ahp->ah_iniBank1, ar5416Bank1, + ARRAY_SIZE(ar5416Bank1), 2); + INIT_INI_ARRAY(&ahp->ah_iniBank2, ar5416Bank2, + ARRAY_SIZE(ar5416Bank2), 2); + INIT_INI_ARRAY(&ahp->ah_iniBank3, ar5416Bank3, + ARRAY_SIZE(ar5416Bank3), 3); + INIT_INI_ARRAY(&ahp->ah_iniBank6, ar5416Bank6, + ARRAY_SIZE(ar5416Bank6), 3); + INIT_INI_ARRAY(&ahp->ah_iniBank6TPC, ar5416Bank6TPC, + ARRAY_SIZE(ar5416Bank6TPC), 3); + INIT_INI_ARRAY(&ahp->ah_iniBank7, ar5416Bank7, + ARRAY_SIZE(ar5416Bank7), 2); + INIT_INI_ARRAY(&ahp->ah_iniAddac, ar5416Addac, + ARRAY_SIZE(ar5416Addac), 2); + } - word = swab16(eep->baseEepHeader.regDmn[1]); - eep->baseEepHeader.regDmn[1] = word; + if (ah->ah_isPciExpress) + ath9k_hw_configpcipowersave(ah, 0); + else + ath9k_hw_disablepcie(ah); - word = swab16(eep->baseEepHeader.rfSilent); - eep->baseEepHeader.rfSilent = word; + ecode = ath9k_hw_post_attach(ah); + if (ecode != 0) + goto bad; - word = swab16(eep->baseEepHeader.blueToothOptions); - eep->baseEepHeader.blueToothOptions = word; + /* rxgain table */ + if (AR_SREV_9280_20(ah)) + ath9k_hw_init_rxgain_ini(ah); - word = swab16(eep->baseEepHeader.deviceCap); - eep->baseEepHeader.deviceCap = word; + /* txgain table */ + if (AR_SREV_9280_20(ah)) + ath9k_hw_init_txgain_ini(ah); - for (j = 0; j < ARRAY_SIZE(eep->modalHeader); j++) { - struct modal_eep_header *pModal = - &eep->modalHeader[j]; - integer = swab32(pModal->antCtrlCommon); - pModal->antCtrlCommon = integer; + if (ah->ah_devid == AR9280_DEVID_PCI) { + for (i = 0; i < ahp->ah_iniModes.ia_rows; i++) { + u32 reg = INI_RA(&ahp->ah_iniModes, i, 0); - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - integer = swab32(pModal->antCtrlChain[i]); - pModal->antCtrlChain[i] = integer; - } + for (j = 1; j < ahp->ah_iniModes.ia_columns; j++) { + u32 val = INI_RA(&ahp->ah_iniModes, i, j); - for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { - word = swab16(pModal->spurChans[i].spurChan); - pModal->spurChans[i].spurChan = word; + INI_RA(&ahp->ah_iniModes, i, j) = + ath9k_hw_ini_fixup(ah, + &ahp->ah_eeprom.def, + reg, val); } } } - if (sum != 0xffff || ar5416_get_eep_ver(ahp) != AR5416_EEP_VER || - ar5416_get_eep_rev(ahp) < AR5416_EEP_NO_BACK_VER) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Bad EEPROM checksum 0x%x or revision 0x%04x\n", - sum, ar5416_get_eep_ver(ahp)); - return -EINVAL; + if (!ath9k_hw_fill_cap_info(ah)) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, + "failed ath9k_hw_fill_cap_info\n"); + ecode = -EINVAL; + goto bad; } - return 0; + ecode = ath9k_hw_init_macaddr(ah); + if (ecode != 0) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, + "failed initializing mac address\n"); + goto bad; + } + + if (AR_SREV_9285(ah)) + ah->ah_txTrigLevel = (AR_FTRIG_256B >> AR_FTRIG_S); + else + ah->ah_txTrigLevel = (AR_FTRIG_512B >> AR_FTRIG_S); + + ath9k_init_nfcal_hist_buffer(ah); + + return ah; +bad: + if (ahp) + ath9k_hw_detach((struct ath_hal *) ahp); + if (status) + *status = ecode; + + return NULL; } -static bool ath9k_hw_chip_test(struct ath_hal *ah) +static void ath9k_hw_init_bb(struct ath_hal *ah, + struct ath9k_channel *chan) { - u32 regAddr[2] = { AR_STA_ID0, AR_PHY_BASE + (8 << 2) }; - u32 regHold[2]; - u32 patternData[4] = { 0x55555555, - 0xaaaaaaaa, - 0x66666666, - 0x99999999 }; - int i, j; + u32 synthDelay; - for (i = 0; i < 2; i++) { - u32 addr = regAddr[i]; - u32 wrData, rdData; + synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; + if (IS_CHAN_B(chan)) + synthDelay = (4 * synthDelay) / 22; + else + synthDelay /= 10; - regHold[i] = REG_READ(ah, addr); - for (j = 0; j < 0x100; j++) { - wrData = (j << 16) | j; - REG_WRITE(ah, addr, wrData); - rdData = REG_READ(ah, addr); - if (rdData != wrData) { - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "%s: address test failed " - "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n", - __func__, addr, wrData, rdData); - return false; - } - } - for (j = 0; j < 4; j++) { - wrData = patternData[j]; - REG_WRITE(ah, addr, wrData); - rdData = REG_READ(ah, addr); - if (wrData != rdData) { - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "%s: address test failed " - "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n", - __func__, addr, wrData, rdData); - return false; - } - } - REG_WRITE(ah, regAddr[i], regHold[i]); - } - udelay(100); - return true; -} - -u32 ath9k_hw_getrxfilter(struct ath_hal *ah) -{ - u32 bits = REG_READ(ah, AR_RX_FILTER); - u32 phybits = REG_READ(ah, AR_PHY_ERR); + REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); - if (phybits & AR_PHY_ERR_RADAR) - bits |= ATH9K_RX_FILTER_PHYRADAR; - if (phybits & (AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING)) - bits |= ATH9K_RX_FILTER_PHYERR; - return bits; + udelay(synthDelay + BASE_ACTIVATE_DELAY); } -void ath9k_hw_setrxfilter(struct ath_hal *ah, u32 bits) +static void ath9k_hw_init_qos(struct ath_hal *ah) { - u32 phybits; + REG_WRITE(ah, AR_MIC_QOS_CONTROL, 0x100aa); + REG_WRITE(ah, AR_MIC_QOS_SELECT, 0x3210); - REG_WRITE(ah, AR_RX_FILTER, (bits & 0xffff) | AR_RX_COMPR_BAR); - phybits = 0; - if (bits & ATH9K_RX_FILTER_PHYRADAR) - phybits |= AR_PHY_ERR_RADAR; - if (bits & ATH9K_RX_FILTER_PHYERR) - phybits |= AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING; - REG_WRITE(ah, AR_PHY_ERR, phybits); + REG_WRITE(ah, AR_QOS_NO_ACK, + SM(2, AR_QOS_NO_ACK_TWO_BIT) | + SM(5, AR_QOS_NO_ACK_BIT_OFF) | + SM(0, AR_QOS_NO_ACK_BYTE_OFF)); - if (phybits) - REG_WRITE(ah, AR_RXCFG, - REG_READ(ah, AR_RXCFG) | AR_RXCFG_ZLFDMA); - else - REG_WRITE(ah, AR_RXCFG, - REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA); + REG_WRITE(ah, AR_TXOP_X, AR_TXOP_X_VAL); + REG_WRITE(ah, AR_TXOP_0_3, 0xFFFFFFFF); + REG_WRITE(ah, AR_TXOP_4_7, 0xFFFFFFFF); + REG_WRITE(ah, AR_TXOP_8_11, 0xFFFFFFFF); + REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF); } -bool ath9k_hw_setcapability(struct ath_hal *ah, - enum ath9k_capability_type type, - u32 capability, - u32 setting, - int *status) +static void ath9k_hw_init_pll(struct ath_hal *ah, + struct ath9k_channel *chan) { - struct ath_hal_5416 *ahp = AH5416(ah); - u32 v; + u32 pll; - switch (type) { - case ATH9K_CAP_TKIP_MIC: - if (setting) - ahp->ah_staId1Defaults |= - AR_STA_ID1_CRPT_MIC_ENABLE; - else - ahp->ah_staId1Defaults &= - ~AR_STA_ID1_CRPT_MIC_ENABLE; - return true; - case ATH9K_CAP_DIVERSITY: - v = REG_READ(ah, AR_PHY_CCK_DETECT); - if (setting) - v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; - else - v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; - REG_WRITE(ah, AR_PHY_CCK_DETECT, v); - return true; - case ATH9K_CAP_MCAST_KEYSRCH: - if (setting) - ahp->ah_staId1Defaults |= AR_STA_ID1_MCAST_KSRCH; - else - ahp->ah_staId1Defaults &= ~AR_STA_ID1_MCAST_KSRCH; - return true; - case ATH9K_CAP_TSF_ADJUST: - if (setting) - ahp->ah_miscMode |= AR_PCU_TX_ADD_TSF; + if (AR_SREV_9100(ah)) { + if (chan && IS_CHAN_5GHZ(chan)) + pll = 0x1450; else - ahp->ah_miscMode &= ~AR_PCU_TX_ADD_TSF; - return true; - default: - return false; - } -} - -void ath9k_hw_dmaRegDump(struct ath_hal *ah) -{ - u32 val[ATH9K_NUM_DMA_DEBUG_REGS]; - int qcuOffset = 0, dcuOffset = 0; - u32 *qcuBase = &val[0], *dcuBase = &val[4]; - int i; - - REG_WRITE(ah, AR_MACMISC, - ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) | - (AR_MACMISC_MISC_OBS_BUS_1 << - AR_MACMISC_MISC_OBS_BUS_MSB_S))); - - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "Raw DMA Debug values:\n"); - for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) { - if (i % 4 == 0) - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "\n"); - - val[i] = REG_READ(ah, AR_DMADBG_0 + (i * sizeof(u32))); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "%d: %08x ", i, val[i]); - } - - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "\n\n"); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n"); - - for (i = 0; i < ATH9K_NUM_QUEUES; - i++, qcuOffset += 4, dcuOffset += 5) { - if (i == 8) { - qcuOffset = 0; - qcuBase++; - } - - if (i == 6) { - dcuOffset = 0; - dcuBase++; - } - - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "%2d %2x %1x %2x %2x\n", - i, (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset, - (*qcuBase & (0x8 << qcuOffset)) >> (qcuOffset + - 3), - val[2] & (0x7 << (i * 3)) >> (i * 3), - (*dcuBase & (0x1f << dcuOffset)) >> dcuOffset); - } - - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "\n"); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "qcu_stitch state: %2x qcu_fetch state: %2x\n", - (val[3] & 0x003c0000) >> 18, (val[3] & 0x03c00000) >> 22); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "qcu_complete state: %2x dcu_complete state: %2x\n", - (val[3] & 0x1c000000) >> 26, (val[6] & 0x3)); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "dcu_arb state: %2x dcu_fp state: %2x\n", - (val[5] & 0x06000000) >> 25, (val[5] & 0x38000000) >> 27); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "chan_idle_dur: %3d chan_idle_dur_valid: %1d\n", - (val[6] & 0x000003fc) >> 2, (val[6] & 0x00000400) >> 10); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "txfifo_valid_0: %1d txfifo_valid_1: %1d\n", - (val[6] & 0x00000800) >> 11, (val[6] & 0x00001000) >> 12); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "txfifo_dcu_num_0: %2d txfifo_dcu_num_1: %2d\n", - (val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17); - - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "pcu observe 0x%x \n", - REG_READ(ah, AR_OBS_BUS_1)); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "AR_CR 0x%x \n", REG_READ(ah, AR_CR)); -} - -u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah, - u32 *rxc_pcnt, - u32 *rxf_pcnt, - u32 *txf_pcnt) -{ - static u32 cycles, rx_clear, rx_frame, tx_frame; - u32 good = 1; - - u32 rc = REG_READ(ah, AR_RCCNT); - u32 rf = REG_READ(ah, AR_RFCNT); - u32 tf = REG_READ(ah, AR_TFCNT); - u32 cc = REG_READ(ah, AR_CCCNT); - - if (cycles == 0 || cycles > cc) { - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: cycle counter wrap. ExtBusy = 0\n", - __func__); - good = 0; + pll = 0x1458; } else { - u32 cc_d = cc - cycles; - u32 rc_d = rc - rx_clear; - u32 rf_d = rf - rx_frame; - u32 tf_d = tf - tx_frame; - - if (cc_d != 0) { - *rxc_pcnt = rc_d * 100 / cc_d; - *rxf_pcnt = rf_d * 100 / cc_d; - *txf_pcnt = tf_d * 100 / cc_d; - } else { - good = 0; - } - } - - cycles = cc; - rx_frame = rf; - rx_clear = rc; - tx_frame = tf; - - return good; -} - -void ath9k_hw_set11nmac2040(struct ath_hal *ah, enum ath9k_ht_macmode mode) -{ - u32 macmode; - - if (mode == ATH9K_HT_MACMODE_2040 && - !ah->ah_config.cwm_ignore_extcca) - macmode = AR_2040_JOINED_RX_CLEAR; - else - macmode = 0; - - REG_WRITE(ah, AR_2040_MODE, macmode); -} - -static void ath9k_hw_mark_phy_inactive(struct ath_hal *ah) -{ - REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); -} - - -static struct ath_hal_5416 *ath9k_hw_newstate(u16 devid, - struct ath_softc *sc, - void __iomem *mem, - int *status) -{ - static const u8 defbssidmask[ETH_ALEN] = - { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - struct ath_hal_5416 *ahp; - struct ath_hal *ah; - - ahp = kzalloc(sizeof(struct ath_hal_5416), GFP_KERNEL); - if (ahp == NULL) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: cannot allocate memory for state block\n", - __func__); - *status = -ENOMEM; - return NULL; - } - - ah = &ahp->ah; - - ah->ah_sc = sc; - ah->ah_sh = mem; - - ah->ah_magic = AR5416_MAGIC; - ah->ah_countryCode = CTRY_DEFAULT; - - ah->ah_devid = devid; - ah->ah_subvendorid = 0; - - ah->ah_flags = 0; - if ((devid == AR5416_AR9100_DEVID)) - ah->ah_macVersion = AR_SREV_VERSION_9100; - if (!AR_SREV_9100(ah)) - ah->ah_flags = AH_USE_EEPROM; - - ah->ah_powerLimit = MAX_RATE_POWER; - ah->ah_tpScale = ATH9K_TP_SCALE_MAX; - - ahp->ah_atimWindow = 0; - ahp->ah_diversityControl = ah->ah_config.diversity_control; - ahp->ah_antennaSwitchSwap = - ah->ah_config.antenna_switch_swap; - - ahp->ah_staId1Defaults = AR_STA_ID1_CRPT_MIC_ENABLE; - ahp->ah_beaconInterval = 100; - ahp->ah_enable32kHzClock = DONT_USE_32KHZ; - ahp->ah_slottime = (u32) -1; - ahp->ah_acktimeout = (u32) -1; - ahp->ah_ctstimeout = (u32) -1; - ahp->ah_globaltxtimeout = (u32) -1; - memcpy(&ahp->ah_bssidmask, defbssidmask, ETH_ALEN); - - ahp->ah_gBeaconRate = 0; - - return ahp; -} - -static int ath9k_hw_eeprom_attach(struct ath_hal *ah) -{ - int status; - - if (ath9k_hw_use_flash(ah)) - ath9k_hw_flash_map(ah); - - if (!ath9k_hw_fill_eeprom(ah)) - return -EIO; - - status = ath9k_hw_check_eeprom(ah); - - return status; -} - -u32 ath9k_hw_get_eeprom(struct ath_hal_5416 *ahp, - enum eeprom_param param) -{ - struct ar5416_eeprom *eep = &ahp->ah_eeprom; - struct modal_eep_header *pModal = eep->modalHeader; - struct base_eep_header *pBase = &eep->baseEepHeader; - - switch (param) { - case EEP_NFTHRESH_5: - return -pModal[0].noiseFloorThreshCh[0]; - case EEP_NFTHRESH_2: - return -pModal[1].noiseFloorThreshCh[0]; - case AR_EEPROM_MAC(0): - return pBase->macAddr[0] << 8 | pBase->macAddr[1]; - case AR_EEPROM_MAC(1): - return pBase->macAddr[2] << 8 | pBase->macAddr[3]; - case AR_EEPROM_MAC(2): - return pBase->macAddr[4] << 8 | pBase->macAddr[5]; - case EEP_REG_0: - return pBase->regDmn[0]; - case EEP_REG_1: - return pBase->regDmn[1]; - case EEP_OP_CAP: - return pBase->deviceCap; - case EEP_OP_MODE: - return pBase->opCapFlags; - case EEP_RF_SILENT: - return pBase->rfSilent; - case EEP_OB_5: - return pModal[0].ob; - case EEP_DB_5: - return pModal[0].db; - case EEP_OB_2: - return pModal[1].ob; - case EEP_DB_2: - return pModal[1].db; - case EEP_MINOR_REV: - return pBase->version & AR5416_EEP_VER_MINOR_MASK; - case EEP_TX_MASK: - return pBase->txMask; - case EEP_RX_MASK: - return pBase->rxMask; - default: - return 0; - } -} - -static int ath9k_hw_get_radiorev(struct ath_hal *ah) -{ - u32 val; - int i; - - REG_WRITE(ah, AR_PHY(0x36), 0x00007058); - for (i = 0; i < 8; i++) - REG_WRITE(ah, AR_PHY(0x20), 0x00010000); - val = (REG_READ(ah, AR_PHY(256)) >> 24) & 0xff; - val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4); - return ath9k_hw_reverse_bits(val, 8); -} + if (AR_SREV_9280_10_OR_LATER(ah)) { + pll = SM(0x5, AR_RTC_9160_PLL_REFDIV); -static int ath9k_hw_init_macaddr(struct ath_hal *ah) -{ - u32 sum; - int i; - u16 eeval; - struct ath_hal_5416 *ahp = AH5416(ah); - DECLARE_MAC_BUF(mac); - - sum = 0; - for (i = 0; i < 3; i++) { - eeval = ath9k_hw_get_eeprom(ahp, AR_EEPROM_MAC(i)); - sum += eeval; - ahp->ah_macaddr[2 * i] = eeval >> 8; - ahp->ah_macaddr[2 * i + 1] = eeval & 0xff; - } - if (sum == 0 || sum == 0xffff * 3) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "%s: mac address read failed: %s\n", __func__, - print_mac(mac, ahp->ah_macaddr)); - return -EADDRNOTAVAIL; - } - - return 0; -} - -static inline int16_t ath9k_hw_interpolate(u16 target, - u16 srcLeft, - u16 srcRight, - int16_t targetLeft, - int16_t targetRight) -{ - int16_t rv; - - if (srcRight == srcLeft) { - rv = targetLeft; - } else { - rv = (int16_t) (((target - srcLeft) * targetRight + - (srcRight - target) * targetLeft) / - (srcRight - srcLeft)); - } - return rv; -} - -static inline u16 ath9k_hw_fbin2freq(u8 fbin, - bool is2GHz) -{ - - if (fbin == AR5416_BCHAN_UNUSED) - return fbin; - - return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin)); -} - -static u16 ath9k_hw_eeprom_get_spur_chan(struct ath_hal *ah, - u16 i, - bool is2GHz) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom *eep = - (struct ar5416_eeprom *) &ahp->ah_eeprom; - u16 spur_val = AR_NO_SPUR; - - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "Getting spur idx %d is2Ghz. %d val %x\n", - i, is2GHz, ah->ah_config.spurchans[i][is2GHz]); - - switch (ah->ah_config.spurmode) { - case SPUR_DISABLE: - break; - case SPUR_ENABLE_IOCTL: - spur_val = ah->ah_config.spurchans[i][is2GHz]; - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "Getting spur val from new loc. %d\n", spur_val); - break; - case SPUR_ENABLE_EEPROM: - spur_val = eep->modalHeader[is2GHz].spurChans[i].spurChan; - break; - - } - return spur_val; -} - -static int ath9k_hw_rfattach(struct ath_hal *ah) -{ - bool rfStatus = false; - int ecode = 0; - - rfStatus = ath9k_hw_init_rf(ah, &ecode); - if (!rfStatus) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s: RF setup failed, status %u\n", __func__, - ecode); - return ecode; - } - - return 0; -} - -static int ath9k_hw_rf_claim(struct ath_hal *ah) -{ - u32 val; - - REG_WRITE(ah, AR_PHY(0), 0x00000007); - - val = ath9k_hw_get_radiorev(ah); - switch (val & AR_RADIO_SREV_MAJOR) { - case 0: - val = AR_RAD5133_SREV_MAJOR; - break; - case AR_RAD5133_SREV_MAJOR: - case AR_RAD5122_SREV_MAJOR: - case AR_RAD2133_SREV_MAJOR: - case AR_RAD2122_SREV_MAJOR: - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: 5G Radio Chip Rev 0x%02X is not " - "supported by this driver\n", - __func__, ah->ah_analog5GhzRev); - return -EOPNOTSUPP; - } - - ah->ah_analog5GhzRev = val; - - return 0; -} - -static void ath9k_hw_init_pll(struct ath_hal *ah, - struct ath9k_channel *chan) -{ - u32 pll; - - if (AR_SREV_9100(ah)) { - if (chan && IS_CHAN_5GHZ(chan)) - pll = 0x1450; - else - pll = 0x1458; - } else { - if (AR_SREV_9280_10_OR_LATER(ah)) { - pll = SM(0x5, AR_RTC_9160_PLL_REFDIV); - - if (chan && IS_CHAN_HALF_RATE(chan)) - pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL); - else if (chan && IS_CHAN_QUARTER_RATE(chan)) - pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL); + if (chan && IS_CHAN_HALF_RATE(chan)) + pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL); + else if (chan && IS_CHAN_QUARTER_RATE(chan)) + pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL); if (chan && IS_CHAN_5GHZ(chan)) { pll |= SM(0x28, AR_RTC_9160_PLL_DIV); - if (AR_SREV_9280_20(ah)) { - if (((chan->channel % 20) == 0) - || ((chan->channel % 10) == 0)) - pll = 0x2850; - else - pll = 0x142c; - } - } else { - pll |= SM(0x2c, AR_RTC_9160_PLL_DIV); - } - - } else if (AR_SREV_9160_10_OR_LATER(ah)) { - - pll = SM(0x5, AR_RTC_9160_PLL_REFDIV); - - if (chan && IS_CHAN_HALF_RATE(chan)) - pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL); - else if (chan && IS_CHAN_QUARTER_RATE(chan)) - pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL); - - if (chan && IS_CHAN_5GHZ(chan)) - pll |= SM(0x50, AR_RTC_9160_PLL_DIV); - else - pll |= SM(0x58, AR_RTC_9160_PLL_DIV); - } else { - pll = AR_RTC_PLL_REFDIV_5 | AR_RTC_PLL_DIV2; - - if (chan && IS_CHAN_HALF_RATE(chan)) - pll |= SM(0x1, AR_RTC_PLL_CLKSEL); - else if (chan && IS_CHAN_QUARTER_RATE(chan)) - pll |= SM(0x2, AR_RTC_PLL_CLKSEL); - - if (chan && IS_CHAN_5GHZ(chan)) - pll |= SM(0xa, AR_RTC_PLL_DIV); - else - pll |= SM(0xb, AR_RTC_PLL_DIV); - } - } - REG_WRITE(ah, (u16) (AR_RTC_PLL_CONTROL), pll); - - udelay(RTC_PLL_SETTLE_DELAY); - - REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK); -} - -static void ath9k_hw_set_regs(struct ath_hal *ah, struct ath9k_channel *chan, - enum ath9k_ht_macmode macmode) -{ - u32 phymode; - struct ath_hal_5416 *ahp = AH5416(ah); - - phymode = AR_PHY_FC_HT_EN | AR_PHY_FC_SHORT_GI_40 - | AR_PHY_FC_SINGLE_HT_LTF1 | AR_PHY_FC_WALSH; - - if (IS_CHAN_HT40(chan)) { - phymode |= AR_PHY_FC_DYN2040_EN; - - if ((chan->chanmode == CHANNEL_A_HT40PLUS) || - (chan->chanmode == CHANNEL_G_HT40PLUS)) - phymode |= AR_PHY_FC_DYN2040_PRI_CH; - - if (ahp->ah_extprotspacing == ATH9K_HT_EXTPROTSPACING_25) - phymode |= AR_PHY_FC_DYN2040_EXT_CH; - } - REG_WRITE(ah, AR_PHY_TURBO, phymode); - - ath9k_hw_set11nmac2040(ah, macmode); - - REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S); - REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S); -} - -static void ath9k_hw_set_operating_mode(struct ath_hal *ah, int opmode) -{ - u32 val; - - val = REG_READ(ah, AR_STA_ID1); - val &= ~(AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC); - switch (opmode) { - case ATH9K_M_HOSTAP: - REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_STA_AP - | AR_STA_ID1_KSRCH_MODE); - REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); - break; - case ATH9K_M_IBSS: - REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_ADHOC - | AR_STA_ID1_KSRCH_MODE); - REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); - break; - case ATH9K_M_STA: - case ATH9K_M_MONITOR: - REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE); - break; - } -} - -static void -ath9k_hw_set_rfmode(struct ath_hal *ah, struct ath9k_channel *chan) -{ - u32 rfMode = 0; - - if (chan == NULL) - return; - - rfMode |= (IS_CHAN_B(chan) || IS_CHAN_G(chan)) - ? AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM; - - if (!AR_SREV_9280_10_OR_LATER(ah)) - rfMode |= (IS_CHAN_5GHZ(chan)) ? AR_PHY_MODE_RF5GHZ : - AR_PHY_MODE_RF2GHZ; - - if (AR_SREV_9280_20(ah) && IS_CHAN_A_5MHZ_SPACED(chan)) - rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE); - - REG_WRITE(ah, AR_PHY_MODE, rfMode); -} - -static bool ath9k_hw_set_reset(struct ath_hal *ah, int type) -{ - u32 rst_flags; - u32 tmpReg; - - REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | - AR_RTC_FORCE_WAKE_ON_INT); - - if (AR_SREV_9100(ah)) { - rst_flags = AR_RTC_RC_MAC_WARM | AR_RTC_RC_MAC_COLD | - AR_RTC_RC_COLD_RESET | AR_RTC_RC_WARM_RESET; - } else { - tmpReg = REG_READ(ah, AR_INTR_SYNC_CAUSE); - if (tmpReg & - (AR_INTR_SYNC_LOCAL_TIMEOUT | - AR_INTR_SYNC_RADM_CPL_TIMEOUT)) { - REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0); - REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF); - } else { - REG_WRITE(ah, AR_RC, AR_RC_AHB); - } - - rst_flags = AR_RTC_RC_MAC_WARM; - if (type == ATH9K_RESET_COLD) - rst_flags |= AR_RTC_RC_MAC_COLD; - } - - REG_WRITE(ah, (u16) (AR_RTC_RC), rst_flags); - udelay(50); - - REG_WRITE(ah, (u16) (AR_RTC_RC), 0); - if (!ath9k_hw_wait(ah, (u16) (AR_RTC_RC), AR_RTC_RC_M, 0)) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s: RTC stuck in MAC reset\n", - __func__); - return false; - } - - if (!AR_SREV_9100(ah)) - REG_WRITE(ah, AR_RC, 0); - - ath9k_hw_init_pll(ah, NULL); - - if (AR_SREV_9100(ah)) - udelay(50); - - return true; -} - -static bool ath9k_hw_set_reset_power_on(struct ath_hal *ah) -{ - REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | - AR_RTC_FORCE_WAKE_ON_INT); - - REG_WRITE(ah, (u16) (AR_RTC_RESET), 0); - REG_WRITE(ah, (u16) (AR_RTC_RESET), 1); - - if (!ath9k_hw_wait(ah, - AR_RTC_STATUS, - AR_RTC_STATUS_M, - AR_RTC_STATUS_ON)) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: RTC not waking up\n", - __func__); - return false; - } - - ath9k_hw_read_revisions(ah); - - return ath9k_hw_set_reset(ah, ATH9K_RESET_WARM); -} - -static bool ath9k_hw_set_reset_reg(struct ath_hal *ah, - u32 type) -{ - REG_WRITE(ah, AR_RTC_FORCE_WAKE, - AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); - - switch (type) { - case ATH9K_RESET_POWER_ON: - return ath9k_hw_set_reset_power_on(ah); - break; - case ATH9K_RESET_WARM: - case ATH9K_RESET_COLD: - return ath9k_hw_set_reset(ah, type); - break; - default: - return false; - } -} - -static -struct ath9k_channel *ath9k_hw_check_chan(struct ath_hal *ah, - struct ath9k_channel *chan) -{ - if (!(IS_CHAN_2GHZ(chan) ^ IS_CHAN_5GHZ(chan))) { - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: invalid channel %u/0x%x; not marked as " - "2GHz or 5GHz\n", __func__, chan->channel, - chan->channelFlags); - return NULL; - } - - if (!IS_CHAN_OFDM(chan) && - !IS_CHAN_CCK(chan) && - !IS_CHAN_HT20(chan) && - !IS_CHAN_HT40(chan)) { - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: invalid channel %u/0x%x; not marked as " - "OFDM or CCK or HT20 or HT40PLUS or HT40MINUS\n", - __func__, chan->channel, chan->channelFlags); - return NULL; - } - - return ath9k_regd_check_channel(ah, chan); -} - -static inline bool -ath9k_hw_get_lower_upper_index(u8 target, - u8 *pList, - u16 listSize, - u16 *indexL, - u16 *indexR) -{ - u16 i; - - if (target <= pList[0]) { - *indexL = *indexR = 0; - return true; - } - if (target >= pList[listSize - 1]) { - *indexL = *indexR = (u16) (listSize - 1); - return true; - } - - for (i = 0; i < listSize - 1; i++) { - if (pList[i] == target) { - *indexL = *indexR = i; - return true; - } - if (target < pList[i + 1]) { - *indexL = i; - *indexR = (u16) (i + 1); - return false; - } - } - return false; -} - -static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer) -{ - int16_t nfval; - int16_t sort[ATH9K_NF_CAL_HIST_MAX]; - int i, j; - - for (i = 0; i < ATH9K_NF_CAL_HIST_MAX; i++) - sort[i] = nfCalBuffer[i]; - - for (i = 0; i < ATH9K_NF_CAL_HIST_MAX - 1; i++) { - for (j = 1; j < ATH9K_NF_CAL_HIST_MAX - i; j++) { - if (sort[j] > sort[j - 1]) { - nfval = sort[j]; - sort[j] = sort[j - 1]; - sort[j - 1] = nfval; - } - } - } - nfval = sort[(ATH9K_NF_CAL_HIST_MAX - 1) >> 1]; - - return nfval; -} - -static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h, - int16_t *nfarray) -{ - int i; - - for (i = 0; i < NUM_NF_READINGS; i++) { - h[i].nfCalBuffer[h[i].currIndex] = nfarray[i]; - - if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX) - h[i].currIndex = 0; - - if (h[i].invalidNFcount > 0) { - if (nfarray[i] < AR_PHY_CCA_MIN_BAD_VALUE - || nfarray[i] > AR_PHY_CCA_MAX_HIGH_VALUE) { - h[i].invalidNFcount = ATH9K_NF_CAL_HIST_MAX; - } else { - h[i].invalidNFcount--; - h[i].privNF = nfarray[i]; - } - } else { - h[i].privNF = - ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer); - } - } - return; -} - -static void ar5416GetNoiseFloor(struct ath_hal *ah, - int16_t nfarray[NUM_NF_READINGS]) -{ - int16_t nf; - - if (AR_SREV_9280_10_OR_LATER(ah)) - nf = MS(REG_READ(ah, AR_PHY_CCA), AR9280_PHY_MINCCA_PWR); - else - nf = MS(REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR); - - if (nf & 0x100) - nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "NF calibrated [ctl] [chain 0] is %d\n", nf); - nfarray[0] = nf; - - if (AR_SREV_9280_10_OR_LATER(ah)) - nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), - AR9280_PHY_CH1_MINCCA_PWR); - else - nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), - AR_PHY_CH1_MINCCA_PWR); - - if (nf & 0x100) - nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL, - "NF calibrated [ctl] [chain 1] is %d\n", nf); - nfarray[1] = nf; - - if (!AR_SREV_9280(ah)) { - nf = MS(REG_READ(ah, AR_PHY_CH2_CCA), - AR_PHY_CH2_MINCCA_PWR); - if (nf & 0x100) - nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL, - "NF calibrated [ctl] [chain 2] is %d\n", nf); - nfarray[2] = nf; - } - - if (AR_SREV_9280_10_OR_LATER(ah)) - nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), - AR9280_PHY_EXT_MINCCA_PWR); - else - nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), - AR_PHY_EXT_MINCCA_PWR); - - if (nf & 0x100) - nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL, - "NF calibrated [ext] [chain 0] is %d\n", nf); - nfarray[3] = nf; - - if (AR_SREV_9280_10_OR_LATER(ah)) - nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), - AR9280_PHY_CH1_EXT_MINCCA_PWR); - else - nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), - AR_PHY_CH1_EXT_MINCCA_PWR); - - if (nf & 0x100) - nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "NF calibrated [ext] [chain 1] is %d\n", nf); - nfarray[4] = nf; - - if (!AR_SREV_9280(ah)) { - nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA), - AR_PHY_CH2_EXT_MINCCA_PWR); - if (nf & 0x100) - nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL, - "NF calibrated [ext] [chain 2] is %d\n", nf); - nfarray[5] = nf; - } -} - -static bool -getNoiseFloorThresh(struct ath_hal *ah, - const struct ath9k_channel *chan, - int16_t *nft) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - - switch (chan->chanmode) { - case CHANNEL_A: - case CHANNEL_A_HT20: - case CHANNEL_A_HT40PLUS: - case CHANNEL_A_HT40MINUS: - *nft = (int16_t) ath9k_hw_get_eeprom(ahp, EEP_NFTHRESH_5); - break; - case CHANNEL_B: - case CHANNEL_G: - case CHANNEL_G_HT20: - case CHANNEL_G_HT40PLUS: - case CHANNEL_G_HT40MINUS: - *nft = (int16_t) ath9k_hw_get_eeprom(ahp, EEP_NFTHRESH_2); - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: invalid channel flags 0x%x\n", __func__, - chan->channelFlags); - return false; - } - return true; -} - -static void ath9k_hw_start_nfcal(struct ath_hal *ah) -{ - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, - AR_PHY_AGC_CONTROL_ENABLE_NF); - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, - AR_PHY_AGC_CONTROL_NO_UPDATE_NF); - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); -} - -static void -ath9k_hw_loadnf(struct ath_hal *ah, struct ath9k_channel *chan) -{ - struct ath9k_nfcal_hist *h; - int i, j; - int32_t val; - const u32 ar5416_cca_regs[6] = { - AR_PHY_CCA, - AR_PHY_CH1_CCA, - AR_PHY_CH2_CCA, - AR_PHY_EXT_CCA, - AR_PHY_CH1_EXT_CCA, - AR_PHY_CH2_EXT_CCA - }; - u8 chainmask; - - if (AR_SREV_9280(ah)) - chainmask = 0x1B; - else - chainmask = 0x3F; - -#ifdef ATH_NF_PER_CHAN - h = chan->nfCalHist; -#else - h = ah->nfCalHist; -#endif - - for (i = 0; i < NUM_NF_READINGS; i++) { - if (chainmask & (1 << i)) { - val = REG_READ(ah, ar5416_cca_regs[i]); - val &= 0xFFFFFE00; - val |= (((u32) (h[i].privNF) << 1) & 0x1ff); - REG_WRITE(ah, ar5416_cca_regs[i], val); - } - } - - REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, - AR_PHY_AGC_CONTROL_ENABLE_NF); - REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, - AR_PHY_AGC_CONTROL_NO_UPDATE_NF); - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); - - for (j = 0; j < 1000; j++) { - if ((REG_READ(ah, AR_PHY_AGC_CONTROL) & - AR_PHY_AGC_CONTROL_NF) == 0) - break; - udelay(10); - } - - for (i = 0; i < NUM_NF_READINGS; i++) { - if (chainmask & (1 << i)) { - val = REG_READ(ah, ar5416_cca_regs[i]); - val &= 0xFFFFFE00; - val |= (((u32) (-50) << 1) & 0x1ff); - REG_WRITE(ah, ar5416_cca_regs[i], val); - } - } -} - -static int16_t ath9k_hw_getnf(struct ath_hal *ah, - struct ath9k_channel *chan) -{ - int16_t nf, nfThresh; - int16_t nfarray[NUM_NF_READINGS] = { 0 }; - struct ath9k_nfcal_hist *h; - u8 chainmask; - - if (AR_SREV_9280(ah)) - chainmask = 0x1B; - else - chainmask = 0x3F; - - chan->channelFlags &= (~CHANNEL_CW_INT); - if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: NF did not complete in calibration window\n", - __func__); - nf = 0; - chan->rawNoiseFloor = nf; - return chan->rawNoiseFloor; - } else { - ar5416GetNoiseFloor(ah, nfarray); - nf = nfarray[0]; - if (getNoiseFloorThresh(ah, chan, &nfThresh) - && nf > nfThresh) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: noise floor failed detected; " - "detected %d, threshold %d\n", __func__, - nf, nfThresh); - chan->channelFlags |= CHANNEL_CW_INT; - } - } - -#ifdef ATH_NF_PER_CHAN - h = chan->nfCalHist; -#else - h = ah->nfCalHist; -#endif - - ath9k_hw_update_nfcal_hist_buffer(h, nfarray); - chan->rawNoiseFloor = h[0].privNF; - - return chan->rawNoiseFloor; -} - -static void ath9k_hw_update_mibstats(struct ath_hal *ah, - struct ath9k_mib_stats *stats) -{ - stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL); - stats->rts_bad += REG_READ(ah, AR_RTS_FAIL); - stats->fcs_bad += REG_READ(ah, AR_FCS_FAIL); - stats->rts_good += REG_READ(ah, AR_RTS_OK); - stats->beacons += REG_READ(ah, AR_BEACON_CNT); -} - -static void ath9k_enable_mib_counters(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Enable mib counters\n"); - - ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); - - REG_WRITE(ah, AR_FILT_OFDM, 0); - REG_WRITE(ah, AR_FILT_CCK, 0); - REG_WRITE(ah, AR_MIBC, - ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) - & 0x0f); - REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); - REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); -} - -static void ath9k_hw_disable_mib_counters(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disabling MIB counters\n"); - - REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC | AR_MIBC_CMC); - - ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); - - REG_WRITE(ah, AR_FILT_OFDM, 0); - REG_WRITE(ah, AR_FILT_CCK, 0); -} - -static int ath9k_hw_get_ani_channel_idx(struct ath_hal *ah, - struct ath9k_channel *chan) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - int i; - - for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) { - if (ahp->ah_ani[i].c.channel == chan->channel) - return i; - if (ahp->ah_ani[i].c.channel == 0) { - ahp->ah_ani[i].c.channel = chan->channel; - ahp->ah_ani[i].c.channelFlags = chan->channelFlags; - return i; - } - } - - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "No more channel states left. Using channel 0\n"); - return 0; -} - -static void ath9k_hw_ani_attach(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - int i; - - ahp->ah_hasHwPhyCounters = 1; - - memset(ahp->ah_ani, 0, sizeof(ahp->ah_ani)); - for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) { - ahp->ah_ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH; - ahp->ah_ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW; - ahp->ah_ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH; - ahp->ah_ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW; - ahp->ah_ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH; - ahp->ah_ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW; - ahp->ah_ani[i].ofdmWeakSigDetectOff = - !ATH9K_ANI_USE_OFDM_WEAK_SIG; - ahp->ah_ani[i].cckWeakSigThreshold = - ATH9K_ANI_CCK_WEAK_SIG_THR; - ahp->ah_ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; - ahp->ah_ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL; - if (ahp->ah_hasHwPhyCounters) { - ahp->ah_ani[i].ofdmPhyErrBase = - AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH; - ahp->ah_ani[i].cckPhyErrBase = - AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH; - } - } - if (ahp->ah_hasHwPhyCounters) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "Setting OfdmErrBase = 0x%08x\n", - ahp->ah_ani[0].ofdmPhyErrBase); - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n", - ahp->ah_ani[0].cckPhyErrBase); - - REG_WRITE(ah, AR_PHY_ERR_1, ahp->ah_ani[0].ofdmPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_2, ahp->ah_ani[0].cckPhyErrBase); - ath9k_enable_mib_counters(ah); - } - ahp->ah_aniPeriod = ATH9K_ANI_PERIOD; - if (ah->ah_config.enable_ani) - ahp->ah_procPhyErr |= HAL_PROCESS_ANI; -} - -static void ath9k_hw_ani_setup(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - int i; - - const int totalSizeDesired[] = { -55, -55, -55, -55, -62 }; - const int coarseHigh[] = { -14, -14, -14, -14, -12 }; - const int coarseLow[] = { -64, -64, -64, -64, -70 }; - const int firpwr[] = { -78, -78, -78, -78, -80 }; - - for (i = 0; i < 5; i++) { - ahp->ah_totalSizeDesired[i] = totalSizeDesired[i]; - ahp->ah_coarseHigh[i] = coarseHigh[i]; - ahp->ah_coarseLow[i] = coarseLow[i]; - ahp->ah_firpwr[i] = firpwr[i]; - } -} - -static void ath9k_hw_ani_detach(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Detaching Ani\n"); - if (ahp->ah_hasHwPhyCounters) { - ath9k_hw_disable_mib_counters(ah); - REG_WRITE(ah, AR_PHY_ERR_1, 0); - REG_WRITE(ah, AR_PHY_ERR_2, 0); - } -} - - -static bool ath9k_hw_ani_control(struct ath_hal *ah, - enum ath9k_ani_cmd cmd, int param) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416AniState *aniState = ahp->ah_curani; - - switch (cmd & ahp->ah_ani_function) { - case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{ - u32 level = param; - - if (level >= ARRAY_SIZE(ahp->ah_totalSizeDesired)) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "%s: level out of range (%u > %u)\n", - __func__, level, - (unsigned) ARRAY_SIZE(ahp-> - ah_totalSizeDesired)); - return false; - } - - REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, - AR_PHY_DESIRED_SZ_TOT_DES, - ahp->ah_totalSizeDesired[level]); - REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, - AR_PHY_AGC_CTL1_COARSE_LOW, - ahp->ah_coarseLow[level]); - REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, - AR_PHY_AGC_CTL1_COARSE_HIGH, - ahp->ah_coarseHigh[level]); - REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, - AR_PHY_FIND_SIG_FIRPWR, - ahp->ah_firpwr[level]); - - if (level > aniState->noiseImmunityLevel) - ahp->ah_stats.ast_ani_niup++; - else if (level < aniState->noiseImmunityLevel) - ahp->ah_stats.ast_ani_nidown++; - aniState->noiseImmunityLevel = level; - break; - } - case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{ - const int m1ThreshLow[] = { 127, 50 }; - const int m2ThreshLow[] = { 127, 40 }; - const int m1Thresh[] = { 127, 0x4d }; - const int m2Thresh[] = { 127, 0x40 }; - const int m2CountThr[] = { 31, 16 }; - const int m2CountThrLow[] = { 63, 48 }; - u32 on = param ? 1 : 0; - - REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, - AR_PHY_SFCORR_LOW_M1_THRESH_LOW, - m1ThreshLow[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, - AR_PHY_SFCORR_LOW_M2_THRESH_LOW, - m2ThreshLow[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR, - AR_PHY_SFCORR_M1_THRESH, - m1Thresh[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR, - AR_PHY_SFCORR_M2_THRESH, - m2Thresh[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR, - AR_PHY_SFCORR_M2COUNT_THR, - m2CountThr[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, - AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, - m2CountThrLow[on]); - - REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, - AR_PHY_SFCORR_EXT_M1_THRESH_LOW, - m1ThreshLow[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, - AR_PHY_SFCORR_EXT_M2_THRESH_LOW, - m2ThreshLow[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, - AR_PHY_SFCORR_EXT_M1_THRESH, - m1Thresh[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, - AR_PHY_SFCORR_EXT_M2_THRESH, - m2Thresh[on]); - - if (on) - REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, - AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); - else - REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW, - AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); - - if (!on != aniState->ofdmWeakSigDetectOff) { - if (on) - ahp->ah_stats.ast_ani_ofdmon++; - else - ahp->ah_stats.ast_ani_ofdmoff++; - aniState->ofdmWeakSigDetectOff = !on; - } - break; - } - case ATH9K_ANI_CCK_WEAK_SIGNAL_THR:{ - const int weakSigThrCck[] = { 8, 6 }; - u32 high = param ? 1 : 0; - - REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT, - AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK, - weakSigThrCck[high]); - if (high != aniState->cckWeakSigThreshold) { - if (high) - ahp->ah_stats.ast_ani_cckhigh++; - else - ahp->ah_stats.ast_ani_ccklow++; - aniState->cckWeakSigThreshold = high; - } - break; - } - case ATH9K_ANI_FIRSTEP_LEVEL:{ - const int firstep[] = { 0, 4, 8 }; - u32 level = param; - - if (level >= ARRAY_SIZE(firstep)) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "%s: level out of range (%u > %u)\n", - __func__, level, - (unsigned) ARRAY_SIZE(firstep)); - return false; - } - REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, - AR_PHY_FIND_SIG_FIRSTEP, - firstep[level]); - if (level > aniState->firstepLevel) - ahp->ah_stats.ast_ani_stepup++; - else if (level < aniState->firstepLevel) - ahp->ah_stats.ast_ani_stepdown++; - aniState->firstepLevel = level; - break; - } - case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{ - const int cycpwrThr1[] = - { 2, 4, 6, 8, 10, 12, 14, 16 }; - u32 level = param; - - if (level >= ARRAY_SIZE(cycpwrThr1)) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "%s: level out of range (%u > %u)\n", - __func__, level, - (unsigned) - ARRAY_SIZE(cycpwrThr1)); - return false; - } - REG_RMW_FIELD(ah, AR_PHY_TIMING5, - AR_PHY_TIMING5_CYCPWR_THR1, - cycpwrThr1[level]); - if (level > aniState->spurImmunityLevel) - ahp->ah_stats.ast_ani_spurup++; - else if (level < aniState->spurImmunityLevel) - ahp->ah_stats.ast_ani_spurdown++; - aniState->spurImmunityLevel = level; - break; - } - case ATH9K_ANI_PRESENT: - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "%s: invalid cmd %u\n", __func__, cmd); - return false; - } - - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "%s: ANI parameters:\n", __func__); - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "noiseImmunityLevel=%d, spurImmunityLevel=%d, " - "ofdmWeakSigDetectOff=%d\n", - aniState->noiseImmunityLevel, aniState->spurImmunityLevel, - !aniState->ofdmWeakSigDetectOff); - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "cckWeakSigThreshold=%d, " - "firstepLevel=%d, listenTime=%d\n", - aniState->cckWeakSigThreshold, aniState->firstepLevel, - aniState->listenTime); - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n", - aniState->cycleCount, aniState->ofdmPhyErrCount, - aniState->cckPhyErrCount); - return true; -} - -static void ath9k_ani_restart(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416AniState *aniState; - - if (!DO_ANI(ah)) - return; - - aniState = ahp->ah_curani; - - aniState->listenTime = 0; - if (ahp->ah_hasHwPhyCounters) { - if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) { - aniState->ofdmPhyErrBase = 0; - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "OFDM Trigger is too high for hw counters\n"); - } else { - aniState->ofdmPhyErrBase = - AR_PHY_COUNTMAX - aniState->ofdmTrigHigh; - } - if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) { - aniState->cckPhyErrBase = 0; - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "CCK Trigger is too high for hw counters\n"); - } else { - aniState->cckPhyErrBase = - AR_PHY_COUNTMAX - aniState->cckTrigHigh; - } - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "%s: Writing ofdmbase=%u cckbase=%u\n", - __func__, aniState->ofdmPhyErrBase, - aniState->cckPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); - REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); - - ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); - } - aniState->ofdmPhyErrCount = 0; - aniState->cckPhyErrCount = 0; -} - -static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_channel *chan = ah->ah_curchan; - struct ar5416AniState *aniState; - enum wireless_mode mode; - int32_t rssi; - - if (!DO_ANI(ah)) - return; - - aniState = ahp->ah_curani; - - if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { - if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, - aniState->noiseImmunityLevel + 1)) { - return; - } - } - - if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) { - if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, - aniState->spurImmunityLevel + 1)) { - return; - } - } - - if (ah->ah_opmode == ATH9K_M_HOSTAP) { - if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { - ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel + 1); - } - return; - } - rssi = BEACON_RSSI(ahp); - if (rssi > aniState->rssiThrHigh) { - if (!aniState->ofdmWeakSigDetectOff) { - if (ath9k_hw_ani_control(ah, - ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, - false)) { - ath9k_hw_ani_control(ah, - ATH9K_ANI_SPUR_IMMUNITY_LEVEL, - 0); - return; - } - } - if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { - ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel + 1); - return; - } - } else if (rssi > aniState->rssiThrLow) { - if (aniState->ofdmWeakSigDetectOff) - ath9k_hw_ani_control(ah, - ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, - true); - if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) - ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel + 1); - return; - } else { - mode = ath9k_hw_chan2wmode(ah, chan); - if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) { - if (!aniState->ofdmWeakSigDetectOff) - ath9k_hw_ani_control(ah, - ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, - false); - if (aniState->firstepLevel > 0) - ath9k_hw_ani_control(ah, - ATH9K_ANI_FIRSTEP_LEVEL, - 0); - return; - } - } -} - -static void ath9k_hw_ani_cck_err_trigger(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_channel *chan = ah->ah_curchan; - struct ar5416AniState *aniState; - enum wireless_mode mode; - int32_t rssi; - - if (!DO_ANI(ah)) - return; - - aniState = ahp->ah_curani; - if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { - if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, - aniState->noiseImmunityLevel + 1)) { - return; - } - } - if (ah->ah_opmode == ATH9K_M_HOSTAP) { - if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { - ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel + 1); - } - return; - } - rssi = BEACON_RSSI(ahp); - if (rssi > aniState->rssiThrLow) { - if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) - ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel + 1); - } else { - mode = ath9k_hw_chan2wmode(ah, chan); - if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) { - if (aniState->firstepLevel > 0) - ath9k_hw_ani_control(ah, - ATH9K_ANI_FIRSTEP_LEVEL, - 0); - } - } -} - -static void ath9k_ani_reset(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416AniState *aniState; - struct ath9k_channel *chan = ah->ah_curchan; - int index; - - if (!DO_ANI(ah)) - return; - - index = ath9k_hw_get_ani_channel_idx(ah, chan); - aniState = &ahp->ah_ani[index]; - ahp->ah_curani = aniState; - - if (DO_ANI(ah) && ah->ah_opmode != ATH9K_M_STA - && ah->ah_opmode != ATH9K_M_IBSS) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "%s: Reset ANI state opmode %u\n", __func__, - ah->ah_opmode); - ahp->ah_stats.ast_ani_reset++; - ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0); - ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0); - ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0); - ath9k_hw_ani_control(ah, - ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, - !ATH9K_ANI_USE_OFDM_WEAK_SIG); - ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR, - ATH9K_ANI_CCK_WEAK_SIG_THR); - ath9k_hw_setrxfilter(ah, - ath9k_hw_getrxfilter(ah) | - ATH9K_RX_FILTER_PHYERR); - if (ah->ah_opmode == ATH9K_M_HOSTAP) { - ahp->ah_curani->ofdmTrigHigh = - ah->ah_config.ofdm_trig_high; - ahp->ah_curani->ofdmTrigLow = - ah->ah_config.ofdm_trig_low; - ahp->ah_curani->cckTrigHigh = - ah->ah_config.cck_trig_high; - ahp->ah_curani->cckTrigLow = - ah->ah_config.cck_trig_low; - } - ath9k_ani_restart(ah); - return; - } - - if (aniState->noiseImmunityLevel != 0) - ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, - aniState->noiseImmunityLevel); - if (aniState->spurImmunityLevel != 0) - ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, - aniState->spurImmunityLevel); - if (aniState->ofdmWeakSigDetectOff) - ath9k_hw_ani_control(ah, - ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, - !aniState->ofdmWeakSigDetectOff); - if (aniState->cckWeakSigThreshold) - ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR, - aniState->cckWeakSigThreshold); - if (aniState->firstepLevel != 0) - ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel); - if (ahp->ah_hasHwPhyCounters) { - ath9k_hw_setrxfilter(ah, - ath9k_hw_getrxfilter(ah) & - ~ATH9K_RX_FILTER_PHYERR); - ath9k_ani_restart(ah); - REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); - REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); - - } else { - ath9k_ani_restart(ah); - ath9k_hw_setrxfilter(ah, - ath9k_hw_getrxfilter(ah) | - ATH9K_RX_FILTER_PHYERR); - } -} - -/* - * Process a MIB interrupt. We may potentially be invoked because - * any of the MIB counters overflow/trigger so don't assume we're - * here because a PHY error counter triggered. - */ -void ath9k_hw_procmibevent(struct ath_hal *ah, - const struct ath9k_node_stats *stats) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - u32 phyCnt1, phyCnt2; - - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Processing Mib Intr\n"); - /* Reset these counters regardless */ - REG_WRITE(ah, AR_FILT_OFDM, 0); - REG_WRITE(ah, AR_FILT_CCK, 0); - if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING)) - REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR); - - /* Clear the mib counters and save them in the stats */ - ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); - ahp->ah_stats.ast_nodestats = *stats; - - if (!DO_ANI(ah)) - return; - - /* NB: these are not reset-on-read */ - phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); - phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); - if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) || - ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) { - struct ar5416AniState *aniState = ahp->ah_curani; - u32 ofdmPhyErrCnt, cckPhyErrCnt; - - /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */ - ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; - ahp->ah_stats.ast_ani_ofdmerrs += - ofdmPhyErrCnt - aniState->ofdmPhyErrCount; - aniState->ofdmPhyErrCount = ofdmPhyErrCnt; - - cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; - ahp->ah_stats.ast_ani_cckerrs += - cckPhyErrCnt - aniState->cckPhyErrCount; - aniState->cckPhyErrCount = cckPhyErrCnt; - - /* - * NB: figure out which counter triggered. If both - * trigger we'll only deal with one as the processing - * clobbers the error counter so the trigger threshold - * check will never be true. - */ - if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh) - ath9k_hw_ani_ofdm_err_trigger(ah); - if (aniState->cckPhyErrCount > aniState->cckTrigHigh) - ath9k_hw_ani_cck_err_trigger(ah); - /* NB: always restart to insure the h/w counters are reset */ - ath9k_ani_restart(ah); - } -} - -static void ath9k_hw_ani_lower_immunity(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416AniState *aniState; - int32_t rssi; - - aniState = ahp->ah_curani; - - if (ah->ah_opmode == ATH9K_M_HOSTAP) { - if (aniState->firstepLevel > 0) { - if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel - 1)) { - return; - } - } - } else { - rssi = BEACON_RSSI(ahp); - if (rssi > aniState->rssiThrHigh) { - /* XXX: Handle me */ - } else if (rssi > aniState->rssiThrLow) { - if (aniState->ofdmWeakSigDetectOff) { - if (ath9k_hw_ani_control(ah, - ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, - true) == - true) { - return; - } - } - if (aniState->firstepLevel > 0) { - if (ath9k_hw_ani_control - (ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel - 1) == - true) { - return; - } - } - } else { - if (aniState->firstepLevel > 0) { - if (ath9k_hw_ani_control - (ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel - 1) == - true) { - return; - } - } - } - } - - if (aniState->spurImmunityLevel > 0) { - if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, - aniState->spurImmunityLevel - 1)) { - return; - } - } - - if (aniState->noiseImmunityLevel > 0) { - ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, - aniState->noiseImmunityLevel - 1); - return; - } -} - -static int32_t ath9k_hw_ani_get_listen_time(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416AniState *aniState; - u32 txFrameCount, rxFrameCount, cycleCount; - int32_t listenTime; - - txFrameCount = REG_READ(ah, AR_TFCNT); - rxFrameCount = REG_READ(ah, AR_RFCNT); - cycleCount = REG_READ(ah, AR_CCCNT); - - aniState = ahp->ah_curani; - if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) { - - listenTime = 0; - ahp->ah_stats.ast_ani_lzero++; - } else { - int32_t ccdelta = cycleCount - aniState->cycleCount; - int32_t rfdelta = rxFrameCount - aniState->rxFrameCount; - int32_t tfdelta = txFrameCount - aniState->txFrameCount; - listenTime = (ccdelta - rfdelta - tfdelta) / 44000; - } - aniState->cycleCount = cycleCount; - aniState->txFrameCount = txFrameCount; - aniState->rxFrameCount = rxFrameCount; - - return listenTime; -} - -void ath9k_hw_ani_monitor(struct ath_hal *ah, - const struct ath9k_node_stats *stats, - struct ath9k_channel *chan) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416AniState *aniState; - int32_t listenTime; - - aniState = ahp->ah_curani; - ahp->ah_stats.ast_nodestats = *stats; - - listenTime = ath9k_hw_ani_get_listen_time(ah); - if (listenTime < 0) { - ahp->ah_stats.ast_ani_lneg++; - ath9k_ani_restart(ah); - return; - } - - aniState->listenTime += listenTime; - - if (ahp->ah_hasHwPhyCounters) { - u32 phyCnt1, phyCnt2; - u32 ofdmPhyErrCnt, cckPhyErrCnt; - - ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); - - phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); - phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); - - if (phyCnt1 < aniState->ofdmPhyErrBase || - phyCnt2 < aniState->cckPhyErrBase) { - if (phyCnt1 < aniState->ofdmPhyErrBase) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "%s: phyCnt1 0x%x, resetting " - "counter value to 0x%x\n", - __func__, phyCnt1, - aniState->ofdmPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_1, - aniState->ofdmPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_MASK_1, - AR_PHY_ERR_OFDM_TIMING); - } - if (phyCnt2 < aniState->cckPhyErrBase) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "%s: phyCnt2 0x%x, resetting " - "counter value to 0x%x\n", - __func__, phyCnt2, - aniState->cckPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_2, - aniState->cckPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_MASK_2, - AR_PHY_ERR_CCK_TIMING); - } - return; - } - - ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; - ahp->ah_stats.ast_ani_ofdmerrs += - ofdmPhyErrCnt - aniState->ofdmPhyErrCount; - aniState->ofdmPhyErrCount = ofdmPhyErrCnt; - - cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; - ahp->ah_stats.ast_ani_cckerrs += - cckPhyErrCnt - aniState->cckPhyErrCount; - aniState->cckPhyErrCount = cckPhyErrCnt; - } - - if (!DO_ANI(ah)) - return; - - if (aniState->listenTime > 5 * ahp->ah_aniPeriod) { - if (aniState->ofdmPhyErrCount <= aniState->listenTime * - aniState->ofdmTrigLow / 1000 && - aniState->cckPhyErrCount <= aniState->listenTime * - aniState->cckTrigLow / 1000) - ath9k_hw_ani_lower_immunity(ah); - ath9k_ani_restart(ah); - } else if (aniState->listenTime > ahp->ah_aniPeriod) { - if (aniState->ofdmPhyErrCount > aniState->listenTime * - aniState->ofdmTrigHigh / 1000) { - ath9k_hw_ani_ofdm_err_trigger(ah); - ath9k_ani_restart(ah); - } else if (aniState->cckPhyErrCount > - aniState->listenTime * aniState->cckTrigHigh / - 1000) { - ath9k_hw_ani_cck_err_trigger(ah); - ath9k_ani_restart(ah); - } - } -} - -#ifndef ATH_NF_PER_CHAN -static void ath9k_init_nfcal_hist_buffer(struct ath_hal *ah) -{ - int i, j; - - for (i = 0; i < NUM_NF_READINGS; i++) { - ah->nfCalHist[i].currIndex = 0; - ah->nfCalHist[i].privNF = AR_PHY_CCA_MAX_GOOD_VALUE; - ah->nfCalHist[i].invalidNFcount = - AR_PHY_CCA_FILTERWINDOW_LENGTH; - for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) { - ah->nfCalHist[i].nfCalBuffer[j] = - AR_PHY_CCA_MAX_GOOD_VALUE; - } - } - return; -} -#endif - -static void ath9k_hw_gpio_cfg_output_mux(struct ath_hal *ah, - u32 gpio, u32 type) -{ - int addr; - u32 gpio_shift, tmp; - - if (gpio > 11) - addr = AR_GPIO_OUTPUT_MUX3; - else if (gpio > 5) - addr = AR_GPIO_OUTPUT_MUX2; - else - addr = AR_GPIO_OUTPUT_MUX1; - - gpio_shift = (gpio % 6) * 5; - - if (AR_SREV_9280_20_OR_LATER(ah) - || (addr != AR_GPIO_OUTPUT_MUX1)) { - REG_RMW(ah, addr, (type << gpio_shift), - (0x1f << gpio_shift)); - } else { - tmp = REG_READ(ah, addr); - tmp = ((tmp & 0x1F0) << 1) | (tmp & ~0x1F0); - tmp &= ~(0x1f << gpio_shift); - tmp |= (type << gpio_shift); - REG_WRITE(ah, addr, tmp); - } -} - -void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio, - u32 ah_signal_type) -{ - u32 gpio_shift; - - ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type); - - gpio_shift = 2 * gpio; - - REG_RMW(ah, - AR_GPIO_OE_OUT, - (AR_GPIO_OE_OUT_DRV_ALL << gpio_shift), - (AR_GPIO_OE_OUT_DRV << gpio_shift)); -} - -void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val) -{ - REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio), - AR_GPIO_BIT(gpio)); -} - -/* - * Configure GPIO Input lines - */ -void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio) -{ - u32 gpio_shift; - - ASSERT(gpio < ah->ah_caps.num_gpio_pins); - - gpio_shift = gpio << 1; - - REG_RMW(ah, - AR_GPIO_OE_OUT, - (AR_GPIO_OE_OUT_DRV_NO << gpio_shift), - (AR_GPIO_OE_OUT_DRV << gpio_shift)); -} - -#ifdef CONFIG_RFKILL -static void ath9k_enable_rfkill(struct ath_hal *ah) -{ - REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, - AR_GPIO_INPUT_EN_VAL_RFSILENT_BB); - - REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2, - AR_GPIO_INPUT_MUX2_RFSILENT); - - ath9k_hw_cfg_gpio_input(ah, ah->ah_rfkill_gpio); - REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB); -} -#endif - -u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio) -{ - if (gpio >= ah->ah_caps.num_gpio_pins) - return 0xffffffff; - - if (AR_SREV_9280_10_OR_LATER(ah)) { - return (MS - (REG_READ(ah, AR_GPIO_IN_OUT), - AR928X_GPIO_IN_VAL) & AR_GPIO_BIT(gpio)) != 0; - } else { - return (MS(REG_READ(ah, AR_GPIO_IN_OUT), AR_GPIO_IN_VAL) & - AR_GPIO_BIT(gpio)) != 0; - } -} - -static int ath9k_hw_post_attach(struct ath_hal *ah) -{ - int ecode; - - if (!ath9k_hw_chip_test(ah)) { - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "%s: hardware self-test failed\n", __func__); - return -ENODEV; - } - - ecode = ath9k_hw_rf_claim(ah); - if (ecode != 0) - return ecode; - - ecode = ath9k_hw_eeprom_attach(ah); - if (ecode != 0) - return ecode; - ecode = ath9k_hw_rfattach(ah); - if (ecode != 0) - return ecode; - - if (!AR_SREV_9100(ah)) { - ath9k_hw_ani_setup(ah); - ath9k_hw_ani_attach(ah); - } - return 0; -} - -static u32 ath9k_hw_ini_fixup(struct ath_hal *ah, - struct ar5416_eeprom *pEepData, - u32 reg, u32 value) -{ - struct base_eep_header *pBase = &(pEepData->baseEepHeader); - - switch (ah->ah_devid) { - case AR9280_DEVID_PCI: - if (reg == 0x7894) { - DPRINTF(ah->ah_sc, ATH_DBG_ANY, - "ini VAL: %x EEPROM: %x\n", value, - (pBase->version & 0xff)); - - if ((pBase->version & 0xff) > 0x0a) { - DPRINTF(ah->ah_sc, ATH_DBG_ANY, - "PWDCLKIND: %d\n", - pBase->pwdclkind); - value &= ~AR_AN_TOP2_PWDCLKIND; - value |= AR_AN_TOP2_PWDCLKIND & (pBase-> - pwdclkind << AR_AN_TOP2_PWDCLKIND_S); - } else { - DPRINTF(ah->ah_sc, ATH_DBG_ANY, - "PWDCLKIND Earlier Rev\n"); - } - - DPRINTF(ah->ah_sc, ATH_DBG_ANY, - "final ini VAL: %x\n", value); - } - break; - } - return value; -} - -static bool ath9k_hw_fill_cap_info(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - u16 capField = 0, eeval; - - eeval = ath9k_hw_get_eeprom(ahp, EEP_REG_0); - - ah->ah_currentRD = eeval; - - eeval = ath9k_hw_get_eeprom(ahp, EEP_REG_1); - ah->ah_currentRDExt = eeval; - - capField = ath9k_hw_get_eeprom(ahp, EEP_OP_CAP); - - if (ah->ah_opmode != ATH9K_M_HOSTAP && - ah->ah_subvendorid == AR_SUBVENDOR_ID_NEW_A) { - if (ah->ah_currentRD == 0x64 || ah->ah_currentRD == 0x65) - ah->ah_currentRD += 5; - else if (ah->ah_currentRD == 0x41) - ah->ah_currentRD = 0x43; - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: regdomain mapped to 0x%x\n", __func__, - ah->ah_currentRD); - } - - eeval = ath9k_hw_get_eeprom(ahp, EEP_OP_MODE); - bitmap_zero(pCap->wireless_modes, ATH9K_MODE_MAX); - - if (eeval & AR5416_OPFLAGS_11A) { - set_bit(ATH9K_MODE_11A, pCap->wireless_modes); - if (ah->ah_config.ht_enable) { - if (!(eeval & AR5416_OPFLAGS_N_5G_HT20)) - set_bit(ATH9K_MODE_11NA_HT20, - pCap->wireless_modes); - if (!(eeval & AR5416_OPFLAGS_N_5G_HT40)) { - set_bit(ATH9K_MODE_11NA_HT40PLUS, - pCap->wireless_modes); - set_bit(ATH9K_MODE_11NA_HT40MINUS, - pCap->wireless_modes); - } - } - } - - if (eeval & AR5416_OPFLAGS_11G) { - set_bit(ATH9K_MODE_11B, pCap->wireless_modes); - set_bit(ATH9K_MODE_11G, pCap->wireless_modes); - if (ah->ah_config.ht_enable) { - if (!(eeval & AR5416_OPFLAGS_N_2G_HT20)) - set_bit(ATH9K_MODE_11NG_HT20, - pCap->wireless_modes); - if (!(eeval & AR5416_OPFLAGS_N_2G_HT40)) { - set_bit(ATH9K_MODE_11NG_HT40PLUS, - pCap->wireless_modes); - set_bit(ATH9K_MODE_11NG_HT40MINUS, - pCap->wireless_modes); - } - } - } - - pCap->tx_chainmask = ath9k_hw_get_eeprom(ahp, EEP_TX_MASK); - if ((ah->ah_isPciExpress) - || (eeval & AR5416_OPFLAGS_11A)) { - pCap->rx_chainmask = - ath9k_hw_get_eeprom(ahp, EEP_RX_MASK); - } else { - pCap->rx_chainmask = - (ath9k_hw_gpio_get(ah, 0)) ? 0x5 : 0x7; - } - - if (!(AR_SREV_9280(ah) && (ah->ah_macRev == 0))) - ahp->ah_miscMode |= AR_PCU_MIC_NEW_LOC_ENA; - - pCap->low_2ghz_chan = 2312; - pCap->high_2ghz_chan = 2732; - - pCap->low_5ghz_chan = 4920; - pCap->high_5ghz_chan = 6100; - - pCap->hw_caps &= ~ATH9K_HW_CAP_CIPHER_CKIP; - pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_TKIP; - pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_AESCCM; - - pCap->hw_caps &= ~ATH9K_HW_CAP_MIC_CKIP; - pCap->hw_caps |= ATH9K_HW_CAP_MIC_TKIP; - pCap->hw_caps |= ATH9K_HW_CAP_MIC_AESCCM; - - pCap->hw_caps |= ATH9K_HW_CAP_CHAN_SPREAD; - - if (ah->ah_config.ht_enable) - pCap->hw_caps |= ATH9K_HW_CAP_HT; - else - pCap->hw_caps &= ~ATH9K_HW_CAP_HT; - - pCap->hw_caps |= ATH9K_HW_CAP_GTT; - pCap->hw_caps |= ATH9K_HW_CAP_VEOL; - pCap->hw_caps |= ATH9K_HW_CAP_BSSIDMASK; - pCap->hw_caps &= ~ATH9K_HW_CAP_MCAST_KEYSEARCH; - - if (capField & AR_EEPROM_EEPCAP_MAXQCU) - pCap->total_queues = - MS(capField, AR_EEPROM_EEPCAP_MAXQCU); - else - pCap->total_queues = ATH9K_NUM_TX_QUEUES; - - if (capField & AR_EEPROM_EEPCAP_KC_ENTRIES) - pCap->keycache_size = - 1 << MS(capField, AR_EEPROM_EEPCAP_KC_ENTRIES); - else - pCap->keycache_size = AR_KEYTABLE_SIZE; - - pCap->hw_caps |= ATH9K_HW_CAP_FASTCC; - pCap->num_mr_retries = 4; - pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD; - - if (AR_SREV_9280_10_OR_LATER(ah)) - pCap->num_gpio_pins = AR928X_NUM_GPIO; - else - pCap->num_gpio_pins = AR_NUM_GPIO; - - if (AR_SREV_9280_10_OR_LATER(ah)) { - pCap->hw_caps |= ATH9K_HW_CAP_WOW; - pCap->hw_caps |= ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT; - } else { - pCap->hw_caps &= ~ATH9K_HW_CAP_WOW; - pCap->hw_caps &= ~ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT; - } - - if (AR_SREV_9160_10_OR_LATER(ah) || AR_SREV_9100(ah)) { - pCap->hw_caps |= ATH9K_HW_CAP_CST; - pCap->rts_aggr_limit = ATH_AMPDU_LIMIT_MAX; - } else { - pCap->rts_aggr_limit = (8 * 1024); - } - - pCap->hw_caps |= ATH9K_HW_CAP_ENHANCEDPM; - -#ifdef CONFIG_RFKILL - ah->ah_rfsilent = ath9k_hw_get_eeprom(ahp, EEP_RF_SILENT); - if (ah->ah_rfsilent & EEP_RFSILENT_ENABLED) { - ah->ah_rfkill_gpio = - MS(ah->ah_rfsilent, EEP_RFSILENT_GPIO_SEL); - ah->ah_rfkill_polarity = - MS(ah->ah_rfsilent, EEP_RFSILENT_POLARITY); - - pCap->hw_caps |= ATH9K_HW_CAP_RFSILENT; - } -#endif - - if ((ah->ah_macVersion == AR_SREV_VERSION_5416_PCI) || - (ah->ah_macVersion == AR_SREV_VERSION_5416_PCIE) || - (ah->ah_macVersion == AR_SREV_VERSION_9160) || - (ah->ah_macVersion == AR_SREV_VERSION_9100) || - (ah->ah_macVersion == AR_SREV_VERSION_9280)) - pCap->hw_caps &= ~ATH9K_HW_CAP_AUTOSLEEP; - else - pCap->hw_caps |= ATH9K_HW_CAP_AUTOSLEEP; - - if (AR_SREV_9280(ah)) - pCap->hw_caps &= ~ATH9K_HW_CAP_4KB_SPLITTRANS; - else - pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS; - - if (ah->ah_currentRDExt & (1 << REG_EXT_JAPAN_MIDBAND)) { - pCap->reg_cap = - AR_EEPROM_EEREGCAP_EN_KK_NEW_11A | - AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN | - AR_EEPROM_EEREGCAP_EN_KK_U2 | - AR_EEPROM_EEREGCAP_EN_KK_MIDBAND; - } else { - pCap->reg_cap = - AR_EEPROM_EEREGCAP_EN_KK_NEW_11A | - AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN; - } - - pCap->reg_cap |= AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND; - - pCap->num_antcfg_5ghz = - ath9k_hw_get_num_ant_config(ahp, IEEE80211_BAND_5GHZ); - pCap->num_antcfg_2ghz = - ath9k_hw_get_num_ant_config(ahp, IEEE80211_BAND_2GHZ); - - return true; -} - -static void ar5416DisablePciePhy(struct ath_hal *ah) -{ - if (!AR_SREV_9100(ah)) - return; - - REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00); - REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924); - REG_WRITE(ah, AR_PCIE_SERDES, 0x28000029); - REG_WRITE(ah, AR_PCIE_SERDES, 0x57160824); - REG_WRITE(ah, AR_PCIE_SERDES, 0x25980579); - REG_WRITE(ah, AR_PCIE_SERDES, 0x00000000); - REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40); - REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554); - REG_WRITE(ah, AR_PCIE_SERDES, 0x000e1007); - - REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); -} - -static void ath9k_set_power_sleep(struct ath_hal *ah, int setChip) -{ - REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); - if (setChip) { - REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, - AR_RTC_FORCE_WAKE_EN); - if (!AR_SREV_9100(ah)) - REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF); - - REG_CLR_BIT(ah, (u16) (AR_RTC_RESET), - AR_RTC_RESET_EN); - } -} - -static void ath9k_set_power_network_sleep(struct ath_hal *ah, int setChip) -{ - REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); - if (setChip) { - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - - if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { - REG_WRITE(ah, AR_RTC_FORCE_WAKE, - AR_RTC_FORCE_WAKE_ON_INT); - } else { - REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, - AR_RTC_FORCE_WAKE_EN); - } - } -} - -static bool ath9k_hw_set_power_awake(struct ath_hal *ah, - int setChip) -{ - u32 val; - int i; - - if (setChip) { - if ((REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M) == - AR_RTC_STATUS_SHUTDOWN) { - if (ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON) - != true) { - return false; - } - } - if (AR_SREV_9100(ah)) - REG_SET_BIT(ah, AR_RTC_RESET, - AR_RTC_RESET_EN); - - REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, - AR_RTC_FORCE_WAKE_EN); - udelay(50); - - for (i = POWER_UP_TIME / 50; i > 0; i--) { - val = REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M; - if (val == AR_RTC_STATUS_ON) - break; - udelay(50); - REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, - AR_RTC_FORCE_WAKE_EN); - } - if (i == 0) { - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, - "%s: Failed to wakeup in %uus\n", - __func__, POWER_UP_TIME / 20); - return false; - } - } - - REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); - return true; -} - -bool ath9k_hw_setpower(struct ath_hal *ah, - enum ath9k_power_mode mode) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - static const char *modes[] = { - "AWAKE", - "FULL-SLEEP", - "NETWORK SLEEP", - "UNDEFINED" - }; - int status = true, setChip = true; - - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, "%s: %s -> %s (%s)\n", __func__, - modes[ahp->ah_powerMode], modes[mode], - setChip ? "set chip " : ""); - - switch (mode) { - case ATH9K_PM_AWAKE: - status = ath9k_hw_set_power_awake(ah, setChip); - break; - case ATH9K_PM_FULL_SLEEP: - ath9k_set_power_sleep(ah, setChip); - ahp->ah_chipFullSleep = true; - break; - case ATH9K_PM_NETWORK_SLEEP: - ath9k_set_power_network_sleep(ah, setChip); - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, - "%s: unknown power mode %u\n", __func__, mode); - return false; - } - ahp->ah_powerMode = mode; - return status; -} - -static struct ath_hal *ath9k_hw_do_attach(u16 devid, - struct ath_softc *sc, - void __iomem *mem, - int *status) -{ - struct ath_hal_5416 *ahp; - struct ath_hal *ah; - int ecode; -#ifndef CONFIG_SLOW_ANT_DIV - u32 i; - u32 j; -#endif - - ahp = ath9k_hw_newstate(devid, sc, mem, status); - if (ahp == NULL) - return NULL; - - ah = &ahp->ah; - - ath9k_hw_set_defaults(ah); - - if (ah->ah_config.intr_mitigation != 0) - ahp->ah_intrMitigation = true; - - if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: couldn't reset chip\n", - __func__); - ecode = -EIO; - goto bad; - } - - if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: couldn't wakeup chip\n", - __func__); - ecode = -EIO; - goto bad; - } - - if (ah->ah_config.serialize_regmode == SER_REG_MODE_AUTO) { - if (ah->ah_macVersion == AR_SREV_VERSION_5416_PCI) { - ah->ah_config.serialize_regmode = - SER_REG_MODE_ON; - } else { - ah->ah_config.serialize_regmode = - SER_REG_MODE_OFF; - } - } - DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s: serialize_regmode is %d\n", - __func__, ah->ah_config.serialize_regmode); - - if ((ah->ah_macVersion != AR_SREV_VERSION_5416_PCI) && - (ah->ah_macVersion != AR_SREV_VERSION_5416_PCIE) && - (ah->ah_macVersion != AR_SREV_VERSION_9160) && - (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah))) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s: Mac Chip Rev 0x%02x.%x is not supported by " - "this driver\n", __func__, - ah->ah_macVersion, ah->ah_macRev); - ecode = -EOPNOTSUPP; - goto bad; - } - - if (AR_SREV_9100(ah)) { - ahp->ah_iqCalData.calData = &iq_cal_multi_sample; - ahp->ah_suppCals = IQ_MISMATCH_CAL; - ah->ah_isPciExpress = false; - } - ah->ah_phyRev = REG_READ(ah, AR_PHY_CHIP_ID); - - if (AR_SREV_9160_10_OR_LATER(ah)) { - if (AR_SREV_9280_10_OR_LATER(ah)) { - ahp->ah_iqCalData.calData = &iq_cal_single_sample; - ahp->ah_adcGainCalData.calData = - &adc_gain_cal_single_sample; - ahp->ah_adcDcCalData.calData = - &adc_dc_cal_single_sample; - ahp->ah_adcDcCalInitData.calData = - &adc_init_dc_cal; - } else { - ahp->ah_iqCalData.calData = &iq_cal_multi_sample; - ahp->ah_adcGainCalData.calData = - &adc_gain_cal_multi_sample; - ahp->ah_adcDcCalData.calData = - &adc_dc_cal_multi_sample; - ahp->ah_adcDcCalInitData.calData = - &adc_init_dc_cal; - } - ahp->ah_suppCals = - ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL; - } - - if (AR_SREV_9160(ah)) { - ah->ah_config.enable_ani = 1; - ahp->ah_ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL | - ATH9K_ANI_FIRSTEP_LEVEL); - } else { - ahp->ah_ani_function = ATH9K_ANI_ALL; - if (AR_SREV_9280_10_OR_LATER(ah)) { - ahp->ah_ani_function &= - ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL; - } - } - - DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s: This Mac Chip Rev 0x%02x.%x is \n", __func__, - ah->ah_macVersion, ah->ah_macRev); - - if (AR_SREV_9280_20_OR_LATER(ah)) { - INIT_INI_ARRAY(&ahp->ah_iniModes, ar9280Modes_9280_2, - ARRAY_SIZE(ar9280Modes_9280_2), 6); - INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9280Common_9280_2, - ARRAY_SIZE(ar9280Common_9280_2), 2); - - if (ah->ah_config.pcie_clock_req) { - INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes, - ar9280PciePhy_clkreq_off_L1_9280, - ARRAY_SIZE - (ar9280PciePhy_clkreq_off_L1_9280), - 2); - } else { - INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes, - ar9280PciePhy_clkreq_always_on_L1_9280, - ARRAY_SIZE - (ar9280PciePhy_clkreq_always_on_L1_9280), - 2); - } - INIT_INI_ARRAY(&ahp->ah_iniModesAdditional, - ar9280Modes_fast_clock_9280_2, - ARRAY_SIZE(ar9280Modes_fast_clock_9280_2), - 3); - } else if (AR_SREV_9280_10_OR_LATER(ah)) { - INIT_INI_ARRAY(&ahp->ah_iniModes, ar9280Modes_9280, - ARRAY_SIZE(ar9280Modes_9280), 6); - INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9280Common_9280, - ARRAY_SIZE(ar9280Common_9280), 2); - } else if (AR_SREV_9160_10_OR_LATER(ah)) { - INIT_INI_ARRAY(&ahp->ah_iniModes, ar5416Modes_9160, - ARRAY_SIZE(ar5416Modes_9160), 6); - INIT_INI_ARRAY(&ahp->ah_iniCommon, ar5416Common_9160, - ARRAY_SIZE(ar5416Common_9160), 2); - INIT_INI_ARRAY(&ahp->ah_iniBank0, ar5416Bank0_9160, - ARRAY_SIZE(ar5416Bank0_9160), 2); - INIT_INI_ARRAY(&ahp->ah_iniBB_RfGain, ar5416BB_RfGain_9160, - ARRAY_SIZE(ar5416BB_RfGain_9160), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank1, ar5416Bank1_9160, - ARRAY_SIZE(ar5416Bank1_9160), 2); - INIT_INI_ARRAY(&ahp->ah_iniBank2, ar5416Bank2_9160, - ARRAY_SIZE(ar5416Bank2_9160), 2); - INIT_INI_ARRAY(&ahp->ah_iniBank3, ar5416Bank3_9160, - ARRAY_SIZE(ar5416Bank3_9160), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank6, ar5416Bank6_9160, - ARRAY_SIZE(ar5416Bank6_9160), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank6TPC, ar5416Bank6TPC_9160, - ARRAY_SIZE(ar5416Bank6TPC_9160), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank7, ar5416Bank7_9160, - ARRAY_SIZE(ar5416Bank7_9160), 2); - if (AR_SREV_9160_11(ah)) { - INIT_INI_ARRAY(&ahp->ah_iniAddac, - ar5416Addac_91601_1, - ARRAY_SIZE(ar5416Addac_91601_1), 2); - } else { - INIT_INI_ARRAY(&ahp->ah_iniAddac, ar5416Addac_9160, - ARRAY_SIZE(ar5416Addac_9160), 2); - } - } else if (AR_SREV_9100_OR_LATER(ah)) { - INIT_INI_ARRAY(&ahp->ah_iniModes, ar5416Modes_9100, - ARRAY_SIZE(ar5416Modes_9100), 6); - INIT_INI_ARRAY(&ahp->ah_iniCommon, ar5416Common_9100, - ARRAY_SIZE(ar5416Common_9100), 2); - INIT_INI_ARRAY(&ahp->ah_iniBank0, ar5416Bank0_9100, - ARRAY_SIZE(ar5416Bank0_9100), 2); - INIT_INI_ARRAY(&ahp->ah_iniBB_RfGain, ar5416BB_RfGain_9100, - ARRAY_SIZE(ar5416BB_RfGain_9100), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank1, ar5416Bank1_9100, - ARRAY_SIZE(ar5416Bank1_9100), 2); - INIT_INI_ARRAY(&ahp->ah_iniBank2, ar5416Bank2_9100, - ARRAY_SIZE(ar5416Bank2_9100), 2); - INIT_INI_ARRAY(&ahp->ah_iniBank3, ar5416Bank3_9100, - ARRAY_SIZE(ar5416Bank3_9100), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank6, ar5416Bank6_9100, - ARRAY_SIZE(ar5416Bank6_9100), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank6TPC, ar5416Bank6TPC_9100, - ARRAY_SIZE(ar5416Bank6TPC_9100), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank7, ar5416Bank7_9100, - ARRAY_SIZE(ar5416Bank7_9100), 2); - INIT_INI_ARRAY(&ahp->ah_iniAddac, ar5416Addac_9100, - ARRAY_SIZE(ar5416Addac_9100), 2); - } else { - INIT_INI_ARRAY(&ahp->ah_iniModes, ar5416Modes, - ARRAY_SIZE(ar5416Modes), 6); - INIT_INI_ARRAY(&ahp->ah_iniCommon, ar5416Common, - ARRAY_SIZE(ar5416Common), 2); - INIT_INI_ARRAY(&ahp->ah_iniBank0, ar5416Bank0, - ARRAY_SIZE(ar5416Bank0), 2); - INIT_INI_ARRAY(&ahp->ah_iniBB_RfGain, ar5416BB_RfGain, - ARRAY_SIZE(ar5416BB_RfGain), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank1, ar5416Bank1, - ARRAY_SIZE(ar5416Bank1), 2); - INIT_INI_ARRAY(&ahp->ah_iniBank2, ar5416Bank2, - ARRAY_SIZE(ar5416Bank2), 2); - INIT_INI_ARRAY(&ahp->ah_iniBank3, ar5416Bank3, - ARRAY_SIZE(ar5416Bank3), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank6, ar5416Bank6, - ARRAY_SIZE(ar5416Bank6), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank6TPC, ar5416Bank6TPC, - ARRAY_SIZE(ar5416Bank6TPC), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank7, ar5416Bank7, - ARRAY_SIZE(ar5416Bank7), 2); - INIT_INI_ARRAY(&ahp->ah_iniAddac, ar5416Addac, - ARRAY_SIZE(ar5416Addac), 2); - } - - if (ah->ah_isPciExpress) - ath9k_hw_configpcipowersave(ah, 0); - else - ar5416DisablePciePhy(ah); - - ecode = ath9k_hw_post_attach(ah); - if (ecode != 0) - goto bad; - -#ifndef CONFIG_SLOW_ANT_DIV - if (ah->ah_devid == AR9280_DEVID_PCI) { - for (i = 0; i < ahp->ah_iniModes.ia_rows; i++) { - u32 reg = INI_RA(&ahp->ah_iniModes, i, 0); - - for (j = 1; j < ahp->ah_iniModes.ia_columns; j++) { - u32 val = INI_RA(&ahp->ah_iniModes, i, j); - - INI_RA(&ahp->ah_iniModes, i, j) = - ath9k_hw_ini_fixup(ah, &ahp->ah_eeprom, - reg, val); - } - } - } -#endif - - if (!ath9k_hw_fill_cap_info(ah)) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s:failed ath9k_hw_fill_cap_info\n", __func__); - ecode = -EINVAL; - goto bad; - } - - ecode = ath9k_hw_init_macaddr(ah); - if (ecode != 0) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s: failed initializing mac address\n", - __func__); - goto bad; - } - - if (AR_SREV_9285(ah)) - ah->ah_txTrigLevel = (AR_FTRIG_256B >> AR_FTRIG_S); - else - ah->ah_txTrigLevel = (AR_FTRIG_512B >> AR_FTRIG_S); - -#ifndef ATH_NF_PER_CHAN - - ath9k_init_nfcal_hist_buffer(ah); -#endif - - return ah; - -bad: - if (ahp) - ath9k_hw_detach((struct ath_hal *) ahp); - if (status) - *status = ecode; - return NULL; -} - -void ath9k_hw_detach(struct ath_hal *ah) -{ - if (!AR_SREV_9100(ah)) - ath9k_hw_ani_detach(ah); - ath9k_hw_rfdetach(ah); - - ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); - kfree(ah); -} - -bool ath9k_get_channel_edges(struct ath_hal *ah, - u16 flags, u16 *low, - u16 *high) -{ - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - - if (flags & CHANNEL_5GHZ) { - *low = pCap->low_5ghz_chan; - *high = pCap->high_5ghz_chan; - return true; - } - if ((flags & CHANNEL_2GHZ)) { - *low = pCap->low_2ghz_chan; - *high = pCap->high_2ghz_chan; - - return true; - } - return false; -} - -static inline bool ath9k_hw_fill_vpd_table(u8 pwrMin, - u8 pwrMax, - u8 *pPwrList, - u8 *pVpdList, - u16 - numIntercepts, - u8 *pRetVpdList) -{ - u16 i, k; - u8 currPwr = pwrMin; - u16 idxL = 0, idxR = 0; - - for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) { - ath9k_hw_get_lower_upper_index(currPwr, pPwrList, - numIntercepts, &(idxL), - &(idxR)); - if (idxR < 1) - idxR = 1; - if (idxL == numIntercepts - 1) - idxL = (u16) (numIntercepts - 2); - if (pPwrList[idxL] == pPwrList[idxR]) - k = pVpdList[idxL]; - else - k = (u16) (((currPwr - - pPwrList[idxL]) * - pVpdList[idxR] + - (pPwrList[idxR] - - currPwr) * pVpdList[idxL]) / - (pPwrList[idxR] - - pPwrList[idxL])); - pRetVpdList[i] = (u8) k; - currPwr += 2; - } - - return true; -} - -static void -ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hal *ah, - struct ath9k_channel *chan, - struct cal_data_per_freq *pRawDataSet, - u8 *bChans, - u16 availPiers, - u16 tPdGainOverlap, - int16_t *pMinCalPower, - u16 *pPdGainBoundaries, - u8 *pPDADCValues, - u16 numXpdGains) -{ - int i, j, k; - int16_t ss; - u16 idxL = 0, idxR = 0, numPiers; - static u8 vpdTableL[AR5416_NUM_PD_GAINS] - [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - static u8 vpdTableR[AR5416_NUM_PD_GAINS] - [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - static u8 vpdTableI[AR5416_NUM_PD_GAINS] - [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - - u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; - u8 minPwrT4[AR5416_NUM_PD_GAINS]; - u8 maxPwrT4[AR5416_NUM_PD_GAINS]; - int16_t vpdStep; - int16_t tmpVal; - u16 sizeCurrVpdTable, maxIndex, tgtIndex; - bool match; - int16_t minDelta = 0; - struct chan_centers centers; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - - for (numPiers = 0; numPiers < availPiers; numPiers++) { - if (bChans[numPiers] == AR5416_BCHAN_UNUSED) - break; - } - - match = ath9k_hw_get_lower_upper_index((u8) - FREQ2FBIN(centers. - synth_center, - IS_CHAN_2GHZ - (chan)), bChans, - numPiers, &idxL, &idxR); - - if (match) { - for (i = 0; i < numXpdGains; i++) { - minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; - maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; - ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], - pRawDataSet[idxL]. - pwrPdg[i], - pRawDataSet[idxL]. - vpdPdg[i], - AR5416_PD_GAIN_ICEPTS, - vpdTableI[i]); - } - } else { - for (i = 0; i < numXpdGains; i++) { - pVpdL = pRawDataSet[idxL].vpdPdg[i]; - pPwrL = pRawDataSet[idxL].pwrPdg[i]; - pVpdR = pRawDataSet[idxR].vpdPdg[i]; - pPwrR = pRawDataSet[idxR].pwrPdg[i]; - - minPwrT4[i] = max(pPwrL[0], pPwrR[0]); - - maxPwrT4[i] = - min(pPwrL[AR5416_PD_GAIN_ICEPTS - 1], - pPwrR[AR5416_PD_GAIN_ICEPTS - 1]); - - - ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], - pPwrL, pVpdL, - AR5416_PD_GAIN_ICEPTS, - vpdTableL[i]); - ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], - pPwrR, pVpdR, - AR5416_PD_GAIN_ICEPTS, - vpdTableR[i]); - - for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { - vpdTableI[i][j] = - (u8) (ath9k_hw_interpolate - ((u16) - FREQ2FBIN(centers. - synth_center, - IS_CHAN_2GHZ - (chan)), - bChans[idxL], - bChans[idxR], vpdTableL[i] - [j], vpdTableR[i] - [j])); - } - } - } - - *pMinCalPower = (int16_t) (minPwrT4[0] / 2); - - k = 0; - for (i = 0; i < numXpdGains; i++) { - if (i == (numXpdGains - 1)) - pPdGainBoundaries[i] = - (u16) (maxPwrT4[i] / 2); - else - pPdGainBoundaries[i] = - (u16) ((maxPwrT4[i] + - minPwrT4[i + 1]) / 4); - - pPdGainBoundaries[i] = - min((u16) AR5416_MAX_RATE_POWER, - pPdGainBoundaries[i]); - - if ((i == 0) && !AR_SREV_5416_V20_OR_LATER(ah)) { - minDelta = pPdGainBoundaries[0] - 23; - pPdGainBoundaries[0] = 23; - } else { - minDelta = 0; - } - - if (i == 0) { - if (AR_SREV_9280_10_OR_LATER(ah)) - ss = (int16_t) (0 - (minPwrT4[i] / 2)); - else - ss = 0; - } else { - ss = (int16_t) ((pPdGainBoundaries[i - 1] - - (minPwrT4[i] / 2)) - - tPdGainOverlap + 1 + minDelta); - } - vpdStep = (int16_t) (vpdTableI[i][1] - vpdTableI[i][0]); - vpdStep = (int16_t) ((vpdStep < 1) ? 1 : vpdStep); - - while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { - tmpVal = (int16_t) (vpdTableI[i][0] + ss * vpdStep); - pPDADCValues[k++] = - (u8) ((tmpVal < 0) ? 0 : tmpVal); - ss++; - } - - sizeCurrVpdTable = - (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); - tgtIndex = (u8) (pPdGainBoundaries[i] + tPdGainOverlap - - (minPwrT4[i] / 2)); - maxIndex = (tgtIndex < - sizeCurrVpdTable) ? tgtIndex : sizeCurrVpdTable; - - while ((ss < maxIndex) - && (k < (AR5416_NUM_PDADC_VALUES - 1))) { - pPDADCValues[k++] = vpdTableI[i][ss++]; - } - - vpdStep = (int16_t) (vpdTableI[i][sizeCurrVpdTable - 1] - - vpdTableI[i][sizeCurrVpdTable - 2]); - vpdStep = (int16_t) ((vpdStep < 1) ? 1 : vpdStep); - - if (tgtIndex > maxIndex) { - while ((ss <= tgtIndex) - && (k < (AR5416_NUM_PDADC_VALUES - 1))) { - tmpVal = (int16_t) ((vpdTableI[i] - [sizeCurrVpdTable - - 1] + (ss - maxIndex + - 1) * vpdStep)); - pPDADCValues[k++] = (u8) ((tmpVal > - 255) ? 255 : tmpVal); - ss++; - } - } - } - - while (i < AR5416_PD_GAINS_IN_MASK) { - pPdGainBoundaries[i] = pPdGainBoundaries[i - 1]; - i++; - } - - while (k < AR5416_NUM_PDADC_VALUES) { - pPDADCValues[k] = pPDADCValues[k - 1]; - k++; - } - return; -} - -static bool -ath9k_hw_set_power_cal_table(struct ath_hal *ah, - struct ar5416_eeprom *pEepData, - struct ath9k_channel *chan, - int16_t *pTxPowerIndexOffset) -{ - struct cal_data_per_freq *pRawDataset; - u8 *pCalBChans = NULL; - u16 pdGainOverlap_t2; - static u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; - u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK]; - u16 numPiers, i, j; - int16_t tMinCalPower; - u16 numXpdGain, xpdMask; - u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 }; - u32 reg32, regOffset, regChainOffset; - int16_t modalIdx; - struct ath_hal_5416 *ahp = AH5416(ah); - - modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0; - xpdMask = pEepData->modalHeader[modalIdx].xpdGain; - - if ((pEepData->baseEepHeader. - version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_2) { - pdGainOverlap_t2 = - pEepData->modalHeader[modalIdx].pdGainOverlap; - } else { - pdGainOverlap_t2 = - (u16) (MS - (REG_READ(ah, AR_PHY_TPCRG5), - AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); - } - - if (IS_CHAN_2GHZ(chan)) { - pCalBChans = pEepData->calFreqPier2G; - numPiers = AR5416_NUM_2G_CAL_PIERS; - } else { - pCalBChans = pEepData->calFreqPier5G; - numPiers = AR5416_NUM_5G_CAL_PIERS; - } - - numXpdGain = 0; - - for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { - if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) { - if (numXpdGain >= AR5416_NUM_PD_GAINS) - break; - xpdGainValues[numXpdGain] = - (u16) (AR5416_PD_GAINS_IN_MASK - i); - numXpdGain++; - } - } - - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, - (numXpdGain - 1) & 0x3); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, - xpdGainValues[0]); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, - xpdGainValues[1]); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, - xpdGainValues[2]); - - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - if (AR_SREV_5416_V20_OR_LATER(ah) && - (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5) - && (i != 0)) { - regChainOffset = (i == 1) ? 0x2000 : 0x1000; - } else - regChainOffset = i * 0x1000; - if (pEepData->baseEepHeader.txMask & (1 << i)) { - if (IS_CHAN_2GHZ(chan)) - pRawDataset = pEepData->calPierData2G[i]; - else - pRawDataset = pEepData->calPierData5G[i]; - - ath9k_hw_get_gain_boundaries_pdadcs(ah, chan, - pRawDataset, - pCalBChans, - numPiers, - pdGainOverlap_t2, - &tMinCalPower, - gainBoundaries, - pdadcValues, - numXpdGain); - - if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) { - - REG_WRITE(ah, - AR_PHY_TPCRG5 + regChainOffset, - SM(pdGainOverlap_t2, - AR_PHY_TPCRG5_PD_GAIN_OVERLAP) - | SM(gainBoundaries[0], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) - | SM(gainBoundaries[1], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) - | SM(gainBoundaries[2], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) - | SM(gainBoundaries[3], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); - } - - regOffset = - AR_PHY_BASE + (672 << 2) + regChainOffset; - for (j = 0; j < 32; j++) { - reg32 = - ((pdadcValues[4 * j + 0] & 0xFF) << 0) - | ((pdadcValues[4 * j + 1] & 0xFF) << - 8) | ((pdadcValues[4 * j + 2] & - 0xFF) << 16) | - ((pdadcValues[4 * j + 3] & 0xFF) << - 24); - REG_WRITE(ah, regOffset, reg32); - - DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO, - "PDADC (%d,%4x): %4.4x %8.8x\n", - i, regChainOffset, regOffset, - reg32); - DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO, - "PDADC: Chain %d | PDADC %3d Value %3d | " - "PDADC %3d Value %3d | PDADC %3d Value %3d | " - "PDADC %3d Value %3d |\n", - i, 4 * j, pdadcValues[4 * j], - 4 * j + 1, pdadcValues[4 * j + 1], - 4 * j + 2, pdadcValues[4 * j + 2], - 4 * j + 3, - pdadcValues[4 * j + 3]); - - regOffset += 4; - } - } - } - *pTxPowerIndexOffset = 0; - - return true; -} - -void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - u8 i; - - if (ah->ah_isPciExpress != true) - return; - - if (ah->ah_config.pcie_powersave_enable == 2) - return; - - if (restore) - return; - - if (AR_SREV_9280_20_OR_LATER(ah)) { - for (i = 0; i < ahp->ah_iniPcieSerdes.ia_rows; i++) { - REG_WRITE(ah, INI_RA(&ahp->ah_iniPcieSerdes, i, 0), - INI_RA(&ahp->ah_iniPcieSerdes, i, 1)); - } - udelay(1000); - } else if (AR_SREV_9280(ah) - && (ah->ah_macRev == AR_SREV_REVISION_9280_10)) { - REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fd00); - REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924); - - REG_WRITE(ah, AR_PCIE_SERDES, 0xa8000019); - REG_WRITE(ah, AR_PCIE_SERDES, 0x13160820); - REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980560); - - if (ah->ah_config.pcie_clock_req) - REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffc); - else - REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffd); - - REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40); - REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554); - REG_WRITE(ah, AR_PCIE_SERDES, 0x00043007); - - REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); - - udelay(1000); - } else { - REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00); - REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924); - REG_WRITE(ah, AR_PCIE_SERDES, 0x28000039); - REG_WRITE(ah, AR_PCIE_SERDES, 0x53160824); - REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980579); - REG_WRITE(ah, AR_PCIE_SERDES, 0x001defff); - REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40); - REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554); - REG_WRITE(ah, AR_PCIE_SERDES, 0x000e3007); - REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); - } - - REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA); - - if (ah->ah_config.pcie_waen) { - REG_WRITE(ah, AR_WA, ah->ah_config.pcie_waen); - } else { - if (AR_SREV_9280(ah)) - REG_WRITE(ah, AR_WA, 0x0040073f); - else - REG_WRITE(ah, AR_WA, 0x0000073f); - } -} - -static void -ath9k_hw_get_legacy_target_powers(struct ath_hal *ah, - struct ath9k_channel *chan, - struct cal_target_power_leg *powInfo, - u16 numChannels, - struct cal_target_power_leg *pNewPower, - u16 numRates, - bool isExtTarget) -{ - u16 clo, chi; - int i; - int matchIndex = -1, lowIndex = -1; - u16 freq; - struct chan_centers centers; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - freq = (isExtTarget) ? centers.ext_center : centers.ctl_center; - - if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, - IS_CHAN_2GHZ(chan))) { - matchIndex = 0; - } else { - for (i = 0; (i < numChannels) - && (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { - if (freq == - ath9k_hw_fbin2freq(powInfo[i].bChannel, - IS_CHAN_2GHZ(chan))) { - matchIndex = i; - break; - } else if ((freq < - ath9k_hw_fbin2freq(powInfo[i].bChannel, - IS_CHAN_2GHZ(chan))) - && (freq > - ath9k_hw_fbin2freq(powInfo[i - 1]. - bChannel, - IS_CHAN_2GHZ - (chan)))) { - lowIndex = i - 1; - break; - } - } - if ((matchIndex == -1) && (lowIndex == -1)) - matchIndex = i - 1; - } - - if (matchIndex != -1) { - *pNewPower = powInfo[matchIndex]; - } else { - clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel, - IS_CHAN_2GHZ(chan)); - chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel, - IS_CHAN_2GHZ(chan)); - - for (i = 0; i < numRates; i++) { - pNewPower->tPow2x[i] = - (u8) ath9k_hw_interpolate(freq, clo, chi, - powInfo - [lowIndex]. - tPow2x[i], - powInfo - [lowIndex + - 1].tPow2x[i]); - } - } -} - -static void -ath9k_hw_get_target_powers(struct ath_hal *ah, - struct ath9k_channel *chan, - struct cal_target_power_ht *powInfo, - u16 numChannels, - struct cal_target_power_ht *pNewPower, - u16 numRates, - bool isHt40Target) -{ - u16 clo, chi; - int i; - int matchIndex = -1, lowIndex = -1; - u16 freq; - struct chan_centers centers; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - freq = isHt40Target ? centers.synth_center : centers.ctl_center; - - if (freq <= - ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) { - matchIndex = 0; - } else { - for (i = 0; (i < numChannels) - && (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { - if (freq == - ath9k_hw_fbin2freq(powInfo[i].bChannel, - IS_CHAN_2GHZ(chan))) { - matchIndex = i; - break; - } else - if ((freq < - ath9k_hw_fbin2freq(powInfo[i].bChannel, - IS_CHAN_2GHZ(chan))) - && (freq > - ath9k_hw_fbin2freq(powInfo[i - 1]. - bChannel, - IS_CHAN_2GHZ - (chan)))) { - lowIndex = i - 1; - break; - } - } - if ((matchIndex == -1) && (lowIndex == -1)) - matchIndex = i - 1; - } - - if (matchIndex != -1) { - *pNewPower = powInfo[matchIndex]; - } else { - clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel, - IS_CHAN_2GHZ(chan)); - chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel, - IS_CHAN_2GHZ(chan)); - - for (i = 0; i < numRates; i++) { - pNewPower->tPow2x[i] = - (u8) ath9k_hw_interpolate(freq, clo, chi, - powInfo - [lowIndex]. - tPow2x[i], - powInfo - [lowIndex + - 1].tPow2x[i]); - } - } -} - -static u16 -ath9k_hw_get_max_edge_power(u16 freq, - struct cal_ctl_edges *pRdEdgesPower, - bool is2GHz) -{ - u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - int i; - - for (i = 0; (i < AR5416_NUM_BAND_EDGES) - && (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) { - if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, - is2GHz)) { - twiceMaxEdgePower = pRdEdgesPower[i].tPower; - break; - } else if ((i > 0) - && (freq < - ath9k_hw_fbin2freq(pRdEdgesPower[i]. - bChannel, is2GHz))) { - if (ath9k_hw_fbin2freq - (pRdEdgesPower[i - 1].bChannel, is2GHz) < freq - && pRdEdgesPower[i - 1].flag) { - twiceMaxEdgePower = - pRdEdgesPower[i - 1].tPower; - } - break; - } - } - return twiceMaxEdgePower; -} - -static bool -ath9k_hw_set_power_per_rate_table(struct ath_hal *ah, - struct ar5416_eeprom *pEepData, - struct ath9k_channel *chan, - int16_t *ratesArray, - u16 cfgCtl, - u8 AntennaReduction, - u8 twiceMaxRegulatoryPower, - u8 powerLimit) -{ - u8 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - static const u16 tpScaleReductionTable[5] = - { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; - - int i; - int8_t twiceLargestAntenna; - struct cal_ctl_data *rep; - struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { - 0, { 0, 0, 0, 0} - }; - struct cal_target_power_leg targetPowerOfdmExt = { - 0, { 0, 0, 0, 0} }, targetPowerCckExt = { - 0, { 0, 0, 0, 0 } - }; - struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = { - 0, {0, 0, 0, 0} - }; - u8 scaledPower = 0, minCtlPower, maxRegAllowedPower; - u16 ctlModesFor11a[] = - { CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 }; - u16 ctlModesFor11g[] = - { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, - CTL_2GHT40 - }; - u16 numCtlModes, *pCtlMode, ctlMode, freq; - struct chan_centers centers; - int tx_chainmask; - u8 twiceMinEdgePower; - struct ath_hal_5416 *ahp = AH5416(ah); - - tx_chainmask = ahp->ah_txchainmask; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - - twiceLargestAntenna = max( - pEepData->modalHeader - [IS_CHAN_2GHZ(chan)].antennaGainCh[0], - pEepData->modalHeader - [IS_CHAN_2GHZ(chan)].antennaGainCh[1]); - - twiceLargestAntenna = max((u8) twiceLargestAntenna, - pEepData->modalHeader - [IS_CHAN_2GHZ(chan)].antennaGainCh[2]); - - twiceLargestAntenna = - (int8_t) min(AntennaReduction - twiceLargestAntenna, 0); - - maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; - - if (ah->ah_tpScale != ATH9K_TP_SCALE_MAX) { - maxRegAllowedPower -= - (tpScaleReductionTable[(ah->ah_tpScale)] * 2); - } - - scaledPower = min(powerLimit, maxRegAllowedPower); - - switch (ar5416_get_ntxchains(tx_chainmask)) { - case 1: - break; - case 2: - scaledPower -= - pEepData->modalHeader[IS_CHAN_2GHZ(chan)]. - pwrDecreaseFor2Chain; - break; - case 3: - scaledPower -= - pEepData->modalHeader[IS_CHAN_2GHZ(chan)]. - pwrDecreaseFor3Chain; - break; - } - - scaledPower = max(0, (int32_t) scaledPower); - - if (IS_CHAN_2GHZ(chan)) { - numCtlModes = - ARRAY_SIZE(ctlModesFor11g) - - SUB_NUM_CTL_MODES_AT_2G_40; - pCtlMode = ctlModesFor11g; - - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData-> - calTargetPowerCck, - AR5416_NUM_2G_CCK_TARGET_POWERS, - &targetPowerCck, 4, - false); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData-> - calTargetPower2G, - AR5416_NUM_2G_20_TARGET_POWERS, - &targetPowerOfdm, 4, - false); - ath9k_hw_get_target_powers(ah, chan, - pEepData->calTargetPower2GHT20, - AR5416_NUM_2G_20_TARGET_POWERS, - &targetPowerHt20, 8, false); - - if (IS_CHAN_HT40(chan)) { - numCtlModes = ARRAY_SIZE(ctlModesFor11g); - ath9k_hw_get_target_powers(ah, chan, - pEepData-> - calTargetPower2GHT40, - AR5416_NUM_2G_40_TARGET_POWERS, - &targetPowerHt40, 8, - true); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData-> - calTargetPowerCck, - AR5416_NUM_2G_CCK_TARGET_POWERS, - &targetPowerCckExt, - 4, true); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData-> - calTargetPower2G, - AR5416_NUM_2G_20_TARGET_POWERS, - &targetPowerOfdmExt, - 4, true); - } - } else { - - numCtlModes = - ARRAY_SIZE(ctlModesFor11a) - - SUB_NUM_CTL_MODES_AT_5G_40; - pCtlMode = ctlModesFor11a; - - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData-> - calTargetPower5G, - AR5416_NUM_5G_20_TARGET_POWERS, - &targetPowerOfdm, 4, - false); - ath9k_hw_get_target_powers(ah, chan, - pEepData->calTargetPower5GHT20, - AR5416_NUM_5G_20_TARGET_POWERS, - &targetPowerHt20, 8, false); - - if (IS_CHAN_HT40(chan)) { - numCtlModes = ARRAY_SIZE(ctlModesFor11a); - ath9k_hw_get_target_powers(ah, chan, - pEepData-> - calTargetPower5GHT40, - AR5416_NUM_5G_40_TARGET_POWERS, - &targetPowerHt40, 8, - true); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData-> - calTargetPower5G, - AR5416_NUM_5G_20_TARGET_POWERS, - &targetPowerOfdmExt, - 4, true); - } - } - - for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { - bool isHt40CtlMode = - (pCtlMode[ctlMode] == CTL_5GHT40) - || (pCtlMode[ctlMode] == CTL_2GHT40); - if (isHt40CtlMode) - freq = centers.synth_center; - else if (pCtlMode[ctlMode] & EXT_ADDITIVE) - freq = centers.ext_center; - else - freq = centers.ctl_center; - - if (ar5416_get_eep_ver(ahp) == 14 - && ar5416_get_eep_rev(ahp) <= 2) - twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, - "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, " - "EXT_ADDITIVE %d\n", - ctlMode, numCtlModes, isHt40CtlMode, - (pCtlMode[ctlMode] & EXT_ADDITIVE)); - - for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; - i++) { - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, - " LOOP-Ctlidx %d: cfgCtl 0x%2.2x " - "pCtlMode 0x%2.2x ctlIndex 0x%2.2x " - "chan %d\n", - i, cfgCtl, pCtlMode[ctlMode], - pEepData->ctlIndex[i], chan->channel); - - if ((((cfgCtl & ~CTL_MODE_M) | - (pCtlMode[ctlMode] & CTL_MODE_M)) == - pEepData->ctlIndex[i]) - || - (((cfgCtl & ~CTL_MODE_M) | - (pCtlMode[ctlMode] & CTL_MODE_M)) == - ((pEepData-> - ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) { - rep = &(pEepData->ctlData[i]); - - twiceMinEdgePower = - ath9k_hw_get_max_edge_power(freq, - rep-> - ctlEdges - [ar5416_get_ntxchains - (tx_chainmask) - - 1], - IS_CHAN_2GHZ - (chan)); - - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, - " MATCH-EE_IDX %d: ch %d is2 %d " - "2xMinEdge %d chainmask %d chains %d\n", - i, freq, IS_CHAN_2GHZ(chan), - twiceMinEdgePower, tx_chainmask, - ar5416_get_ntxchains - (tx_chainmask)); - if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { - twiceMaxEdgePower = - min(twiceMaxEdgePower, - twiceMinEdgePower); - } else { - twiceMaxEdgePower = - twiceMinEdgePower; - break; - } - } - } - - minCtlPower = min(twiceMaxEdgePower, scaledPower); - - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, - " SEL-Min ctlMode %d pCtlMode %d " - "2xMaxEdge %d sP %d minCtlPwr %d\n", - ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, - scaledPower, minCtlPower); - - switch (pCtlMode[ctlMode]) { - case CTL_11B: - for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); - i++) { - targetPowerCck.tPow2x[i] = - min(targetPowerCck.tPow2x[i], - minCtlPower); - } - break; - case CTL_11A: - case CTL_11G: - for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); - i++) { - targetPowerOfdm.tPow2x[i] = - min(targetPowerOfdm.tPow2x[i], - minCtlPower); - } - break; - case CTL_5GHT20: - case CTL_2GHT20: - for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); - i++) { - targetPowerHt20.tPow2x[i] = - min(targetPowerHt20.tPow2x[i], - minCtlPower); - } - break; - case CTL_11B_EXT: - targetPowerCckExt.tPow2x[0] = - min(targetPowerCckExt.tPow2x[0], minCtlPower); - break; - case CTL_11A_EXT: - case CTL_11G_EXT: - targetPowerOfdmExt.tPow2x[0] = - min(targetPowerOfdmExt.tPow2x[0], minCtlPower); - break; - case CTL_5GHT40: - case CTL_2GHT40: - for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); - i++) { - targetPowerHt40.tPow2x[i] = - min(targetPowerHt40.tPow2x[i], - minCtlPower); - } - break; - default: - break; - } - } - - ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = - ratesArray[rate18mb] = ratesArray[rate24mb] = - targetPowerOfdm.tPow2x[0]; - ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; - ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; - ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; - ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; - - for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) - ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; - - if (IS_CHAN_2GHZ(chan)) { - ratesArray[rate1l] = targetPowerCck.tPow2x[0]; - ratesArray[rate2s] = ratesArray[rate2l] = - targetPowerCck.tPow2x[1]; - ratesArray[rate5_5s] = ratesArray[rate5_5l] = - targetPowerCck.tPow2x[2]; - ; - ratesArray[rate11s] = ratesArray[rate11l] = - targetPowerCck.tPow2x[3]; - ; - } - if (IS_CHAN_HT40(chan)) { - for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { - ratesArray[rateHt40_0 + i] = - targetPowerHt40.tPow2x[i]; - } - ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; - ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; - ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; - if (IS_CHAN_2GHZ(chan)) { - ratesArray[rateExtCck] = - targetPowerCckExt.tPow2x[0]; - } - } - return true; -} - -static int -ath9k_hw_set_txpower(struct ath_hal *ah, - struct ar5416_eeprom *pEepData, - struct ath9k_channel *chan, - u16 cfgCtl, - u8 twiceAntennaReduction, - u8 twiceMaxRegulatoryPower, - u8 powerLimit) -{ - struct modal_eep_header *pModal = - &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]); - int16_t ratesArray[Ar5416RateSize]; - int16_t txPowerIndexOffset = 0; - u8 ht40PowerIncForPdadc = 2; - int i; - - memset(ratesArray, 0, sizeof(ratesArray)); - - if ((pEepData->baseEepHeader. - version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_2) { - ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; - } - - if (!ath9k_hw_set_power_per_rate_table(ah, pEepData, chan, - &ratesArray[0], cfgCtl, - twiceAntennaReduction, - twiceMaxRegulatoryPower, - powerLimit)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "ath9k_hw_set_txpower: unable to set " - "tx power per rate table\n"); - return -EIO; - } - - if (!ath9k_hw_set_power_cal_table - (ah, pEepData, chan, &txPowerIndexOffset)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "ath9k_hw_set_txpower: unable to set power table\n"); - return -EIO; - } - - for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { - ratesArray[i] = - (int16_t) (txPowerIndexOffset + ratesArray[i]); - if (ratesArray[i] > AR5416_MAX_RATE_POWER) - ratesArray[i] = AR5416_MAX_RATE_POWER; - } - - if (AR_SREV_9280_10_OR_LATER(ah)) { - for (i = 0; i < Ar5416RateSize; i++) - ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; - } - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, - ATH9K_POW_SM(ratesArray[rate18mb], 24) - | ATH9K_POW_SM(ratesArray[rate12mb], 16) - | ATH9K_POW_SM(ratesArray[rate9mb], 8) - | ATH9K_POW_SM(ratesArray[rate6mb], 0) - ); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, - ATH9K_POW_SM(ratesArray[rate54mb], 24) - | ATH9K_POW_SM(ratesArray[rate48mb], 16) - | ATH9K_POW_SM(ratesArray[rate36mb], 8) - | ATH9K_POW_SM(ratesArray[rate24mb], 0) - ); - - if (IS_CHAN_2GHZ(chan)) { - REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, - ATH9K_POW_SM(ratesArray[rate2s], 24) - | ATH9K_POW_SM(ratesArray[rate2l], 16) - | ATH9K_POW_SM(ratesArray[rateXr], 8) - | ATH9K_POW_SM(ratesArray[rate1l], 0) - ); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, - ATH9K_POW_SM(ratesArray[rate11s], 24) - | ATH9K_POW_SM(ratesArray[rate11l], 16) - | ATH9K_POW_SM(ratesArray[rate5_5s], 8) - | ATH9K_POW_SM(ratesArray[rate5_5l], 0) - ); - } - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, - ATH9K_POW_SM(ratesArray[rateHt20_3], 24) - | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) - | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) - | ATH9K_POW_SM(ratesArray[rateHt20_0], 0) - ); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, - ATH9K_POW_SM(ratesArray[rateHt20_7], 24) - | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) - | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) - | ATH9K_POW_SM(ratesArray[rateHt20_4], 0) - ); - - if (IS_CHAN_HT40(chan)) { - REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, - ATH9K_POW_SM(ratesArray[rateHt40_3] + - ht40PowerIncForPdadc, 24) - | ATH9K_POW_SM(ratesArray[rateHt40_2] + - ht40PowerIncForPdadc, 16) - | ATH9K_POW_SM(ratesArray[rateHt40_1] + - ht40PowerIncForPdadc, 8) - | ATH9K_POW_SM(ratesArray[rateHt40_0] + - ht40PowerIncForPdadc, 0) - ); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, - ATH9K_POW_SM(ratesArray[rateHt40_7] + - ht40PowerIncForPdadc, 24) - | ATH9K_POW_SM(ratesArray[rateHt40_6] + - ht40PowerIncForPdadc, 16) - | ATH9K_POW_SM(ratesArray[rateHt40_5] + - ht40PowerIncForPdadc, 8) - | ATH9K_POW_SM(ratesArray[rateHt40_4] + - ht40PowerIncForPdadc, 0) - ); - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, - ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) - | ATH9K_POW_SM(ratesArray[rateExtCck], 16) - | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) - | ATH9K_POW_SM(ratesArray[rateDupCck], 0) - ); - } - - REG_WRITE(ah, AR_PHY_POWER_TX_SUB, - ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6) - | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0) - ); - - i = rate6mb; - if (IS_CHAN_HT40(chan)) - i = rateHt40_0; - else if (IS_CHAN_HT20(chan)) - i = rateHt20_0; - - if (AR_SREV_9280_10_OR_LATER(ah)) - ah->ah_maxPowerLevel = - ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; - else - ah->ah_maxPowerLevel = ratesArray[i]; - - return 0; -} - -static inline void ath9k_hw_get_delta_slope_vals(struct ath_hal *ah, - u32 coef_scaled, - u32 *coef_mantissa, - u32 *coef_exponent) -{ - u32 coef_exp, coef_man; - - for (coef_exp = 31; coef_exp > 0; coef_exp--) - if ((coef_scaled >> coef_exp) & 0x1) - break; - - coef_exp = 14 - (coef_exp - COEF_SCALE_S); - - coef_man = coef_scaled + (1 << (COEF_SCALE_S - coef_exp - 1)); - - *coef_mantissa = coef_man >> (COEF_SCALE_S - coef_exp); - *coef_exponent = coef_exp - 16; -} - -static void -ath9k_hw_set_delta_slope(struct ath_hal *ah, - struct ath9k_channel *chan) -{ - u32 coef_scaled, ds_coef_exp, ds_coef_man; - u32 clockMhzScaled = 0x64000000; - struct chan_centers centers; - - if (IS_CHAN_HALF_RATE(chan)) - clockMhzScaled = clockMhzScaled >> 1; - else if (IS_CHAN_QUARTER_RATE(chan)) - clockMhzScaled = clockMhzScaled >> 2; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - coef_scaled = clockMhzScaled / centers.synth_center; - - ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man, - &ds_coef_exp); - - REG_RMW_FIELD(ah, AR_PHY_TIMING3, - AR_PHY_TIMING3_DSC_MAN, ds_coef_man); - REG_RMW_FIELD(ah, AR_PHY_TIMING3, - AR_PHY_TIMING3_DSC_EXP, ds_coef_exp); - - coef_scaled = (9 * coef_scaled) / 10; - - ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man, - &ds_coef_exp); - - REG_RMW_FIELD(ah, AR_PHY_HALFGI, - AR_PHY_HALFGI_DSC_MAN, ds_coef_man); - REG_RMW_FIELD(ah, AR_PHY_HALFGI, - AR_PHY_HALFGI_DSC_EXP, ds_coef_exp); -} - -static void ath9k_hw_9280_spur_mitigate(struct ath_hal *ah, - struct ath9k_channel *chan) -{ - int bb_spur = AR_NO_SPUR; - int freq; - int bin, cur_bin; - int bb_spur_off, spur_subchannel_sd; - int spur_freq_sd; - int spur_delta_phase; - int denominator; - int upper, lower, cur_vit_mask; - int tmp, newVal; - int i; - int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, - AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 - }; - int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, - AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 - }; - int inc[4] = { 0, 100, 0, 0 }; - struct chan_centers centers; - - int8_t mask_m[123]; - int8_t mask_p[123]; - int8_t mask_amt; - int tmp_mask; - int cur_bb_spur; - bool is2GHz = IS_CHAN_2GHZ(chan); - - memset(&mask_m, 0, sizeof(int8_t) * 123); - memset(&mask_p, 0, sizeof(int8_t) * 123); - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - freq = centers.synth_center; - - ah->ah_config.spurmode = SPUR_ENABLE_EEPROM; - for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { - cur_bb_spur = ath9k_hw_eeprom_get_spur_chan(ah, i, is2GHz); - - if (is2GHz) - cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_2GHZ; - else - cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_5GHZ; - - if (AR_NO_SPUR == cur_bb_spur) - break; - cur_bb_spur = cur_bb_spur - freq; - - if (IS_CHAN_HT40(chan)) { - if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT40) && - (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT40)) { - bb_spur = cur_bb_spur; - break; - } - } else if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT20) && - (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT20)) { - bb_spur = cur_bb_spur; - break; - } - } - - if (AR_NO_SPUR == bb_spur) { - REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, - AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); - return; - } else { - REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, - AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); - } - - bin = bb_spur * 320; - - tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0)); - - newVal = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | - AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER | - AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK | - AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK); - REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), newVal); - - newVal = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | - AR_PHY_SPUR_REG_ENABLE_MASK_PPM | - AR_PHY_SPUR_REG_MASK_RATE_SELECT | - AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | - SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); - REG_WRITE(ah, AR_PHY_SPUR_REG, newVal); - - if (IS_CHAN_HT40(chan)) { - if (bb_spur < 0) { - spur_subchannel_sd = 1; - bb_spur_off = bb_spur + 10; - } else { - spur_subchannel_sd = 0; - bb_spur_off = bb_spur - 10; - } - } else { - spur_subchannel_sd = 0; - bb_spur_off = bb_spur; - } - - if (IS_CHAN_HT40(chan)) - spur_delta_phase = - ((bb_spur * 262144) / - 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; - else - spur_delta_phase = - ((bb_spur * 524288) / - 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; - - denominator = IS_CHAN_2GHZ(chan) ? 44 : 40; - spur_freq_sd = ((bb_spur_off * 2048) / denominator) & 0x3ff; - - newVal = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | - SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | - SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); - REG_WRITE(ah, AR_PHY_TIMING11, newVal); - - newVal = spur_subchannel_sd << AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S; - REG_WRITE(ah, AR_PHY_SFCORR_EXT, newVal); - - cur_bin = -6000; - upper = bin + 100; - lower = bin - 100; - - for (i = 0; i < 4; i++) { - int pilot_mask = 0; - int chan_mask = 0; - int bp = 0; - for (bp = 0; bp < 30; bp++) { - if ((cur_bin > lower) && (cur_bin < upper)) { - pilot_mask = pilot_mask | 0x1 << bp; - chan_mask = chan_mask | 0x1 << bp; - } - cur_bin += 100; - } - cur_bin += inc[i]; - REG_WRITE(ah, pilot_mask_reg[i], pilot_mask); - REG_WRITE(ah, chan_mask_reg[i], chan_mask); - } - - cur_vit_mask = 6100; - upper = bin + 120; - lower = bin - 120; - - for (i = 0; i < 123; i++) { - if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { - - /* workaround for gcc bug #37014 */ - volatile int tmp = abs(cur_vit_mask - bin); - - if (tmp < 75) - mask_amt = 1; - else - mask_amt = 0; - if (cur_vit_mask < 0) - mask_m[abs(cur_vit_mask / 100)] = mask_amt; - else - mask_p[cur_vit_mask / 100] = mask_amt; - } - cur_vit_mask -= 100; - } - - tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28) - | (mask_m[48] << 26) | (mask_m[49] << 24) - | (mask_m[50] << 22) | (mask_m[51] << 20) - | (mask_m[52] << 18) | (mask_m[53] << 16) - | (mask_m[54] << 14) | (mask_m[55] << 12) - | (mask_m[56] << 10) | (mask_m[57] << 8) - | (mask_m[58] << 6) | (mask_m[59] << 4) - | (mask_m[60] << 2) | (mask_m[61] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask); - REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask); - - tmp_mask = (mask_m[31] << 28) - | (mask_m[32] << 26) | (mask_m[33] << 24) - | (mask_m[34] << 22) | (mask_m[35] << 20) - | (mask_m[36] << 18) | (mask_m[37] << 16) - | (mask_m[48] << 14) | (mask_m[39] << 12) - | (mask_m[40] << 10) | (mask_m[41] << 8) - | (mask_m[42] << 6) | (mask_m[43] << 4) - | (mask_m[44] << 2) | (mask_m[45] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask); - - tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28) - | (mask_m[18] << 26) | (mask_m[18] << 24) - | (mask_m[20] << 22) | (mask_m[20] << 20) - | (mask_m[22] << 18) | (mask_m[22] << 16) - | (mask_m[24] << 14) | (mask_m[24] << 12) - | (mask_m[25] << 10) | (mask_m[26] << 8) - | (mask_m[27] << 6) | (mask_m[28] << 4) - | (mask_m[29] << 2) | (mask_m[30] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask); - - tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28) - | (mask_m[2] << 26) | (mask_m[3] << 24) - | (mask_m[4] << 22) | (mask_m[5] << 20) - | (mask_m[6] << 18) | (mask_m[7] << 16) - | (mask_m[8] << 14) | (mask_m[9] << 12) - | (mask_m[10] << 10) | (mask_m[11] << 8) - | (mask_m[12] << 6) | (mask_m[13] << 4) - | (mask_m[14] << 2) | (mask_m[15] << 0); - REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask); - - tmp_mask = (mask_p[15] << 28) - | (mask_p[14] << 26) | (mask_p[13] << 24) - | (mask_p[12] << 22) | (mask_p[11] << 20) - | (mask_p[10] << 18) | (mask_p[9] << 16) - | (mask_p[8] << 14) | (mask_p[7] << 12) - | (mask_p[6] << 10) | (mask_p[5] << 8) - | (mask_p[4] << 6) | (mask_p[3] << 4) - | (mask_p[2] << 2) | (mask_p[1] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask); - - tmp_mask = (mask_p[30] << 28) - | (mask_p[29] << 26) | (mask_p[28] << 24) - | (mask_p[27] << 22) | (mask_p[26] << 20) - | (mask_p[25] << 18) | (mask_p[24] << 16) - | (mask_p[23] << 14) | (mask_p[22] << 12) - | (mask_p[21] << 10) | (mask_p[20] << 8) - | (mask_p[19] << 6) | (mask_p[18] << 4) - | (mask_p[17] << 2) | (mask_p[16] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask); - - tmp_mask = (mask_p[45] << 28) - | (mask_p[44] << 26) | (mask_p[43] << 24) - | (mask_p[42] << 22) | (mask_p[41] << 20) - | (mask_p[40] << 18) | (mask_p[39] << 16) - | (mask_p[38] << 14) | (mask_p[37] << 12) - | (mask_p[36] << 10) | (mask_p[35] << 8) - | (mask_p[34] << 6) | (mask_p[33] << 4) - | (mask_p[32] << 2) | (mask_p[31] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask); - - tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28) - | (mask_p[59] << 26) | (mask_p[58] << 24) - | (mask_p[57] << 22) | (mask_p[56] << 20) - | (mask_p[55] << 18) | (mask_p[54] << 16) - | (mask_p[53] << 14) | (mask_p[52] << 12) - | (mask_p[51] << 10) | (mask_p[50] << 8) - | (mask_p[49] << 6) | (mask_p[48] << 4) - | (mask_p[47] << 2) | (mask_p[46] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); -} - -static void ath9k_hw_spur_mitigate(struct ath_hal *ah, - struct ath9k_channel *chan) -{ - int bb_spur = AR_NO_SPUR; - int bin, cur_bin; - int spur_freq_sd; - int spur_delta_phase; - int denominator; - int upper, lower, cur_vit_mask; - int tmp, new; - int i; - int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, - AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 - }; - int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, - AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 - }; - int inc[4] = { 0, 100, 0, 0 }; - - int8_t mask_m[123]; - int8_t mask_p[123]; - int8_t mask_amt; - int tmp_mask; - int cur_bb_spur; - bool is2GHz = IS_CHAN_2GHZ(chan); - - memset(&mask_m, 0, sizeof(int8_t) * 123); - memset(&mask_p, 0, sizeof(int8_t) * 123); - - for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { - cur_bb_spur = ath9k_hw_eeprom_get_spur_chan(ah, i, is2GHz); - if (AR_NO_SPUR == cur_bb_spur) - break; - cur_bb_spur = cur_bb_spur - (chan->channel * 10); - if ((cur_bb_spur > -95) && (cur_bb_spur < 95)) { - bb_spur = cur_bb_spur; - break; - } - } - - if (AR_NO_SPUR == bb_spur) - return; - - bin = bb_spur * 32; - - tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0)); - new = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | - AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER | - AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK | - AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK); - - REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), new); - - new = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | - AR_PHY_SPUR_REG_ENABLE_MASK_PPM | - AR_PHY_SPUR_REG_MASK_RATE_SELECT | - AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | - SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); - REG_WRITE(ah, AR_PHY_SPUR_REG, new); - - spur_delta_phase = ((bb_spur * 524288) / 100) & - AR_PHY_TIMING11_SPUR_DELTA_PHASE; - - denominator = IS_CHAN_2GHZ(chan) ? 440 : 400; - spur_freq_sd = ((bb_spur * 2048) / denominator) & 0x3ff; - - new = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | - SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | - SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); - REG_WRITE(ah, AR_PHY_TIMING11, new); - - cur_bin = -6000; - upper = bin + 100; - lower = bin - 100; - - for (i = 0; i < 4; i++) { - int pilot_mask = 0; - int chan_mask = 0; - int bp = 0; - for (bp = 0; bp < 30; bp++) { - if ((cur_bin > lower) && (cur_bin < upper)) { - pilot_mask = pilot_mask | 0x1 << bp; - chan_mask = chan_mask | 0x1 << bp; - } - cur_bin += 100; - } - cur_bin += inc[i]; - REG_WRITE(ah, pilot_mask_reg[i], pilot_mask); - REG_WRITE(ah, chan_mask_reg[i], chan_mask); - } - - cur_vit_mask = 6100; - upper = bin + 120; - lower = bin - 120; - - for (i = 0; i < 123; i++) { - if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { - - /* workaround for gcc bug #37014 */ - volatile int tmp = abs(cur_vit_mask - bin); - - if (tmp < 75) - mask_amt = 1; - else - mask_amt = 0; - if (cur_vit_mask < 0) - mask_m[abs(cur_vit_mask / 100)] = mask_amt; - else - mask_p[cur_vit_mask / 100] = mask_amt; - } - cur_vit_mask -= 100; - } - - tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28) - | (mask_m[48] << 26) | (mask_m[49] << 24) - | (mask_m[50] << 22) | (mask_m[51] << 20) - | (mask_m[52] << 18) | (mask_m[53] << 16) - | (mask_m[54] << 14) | (mask_m[55] << 12) - | (mask_m[56] << 10) | (mask_m[57] << 8) - | (mask_m[58] << 6) | (mask_m[59] << 4) - | (mask_m[60] << 2) | (mask_m[61] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask); - REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask); - - tmp_mask = (mask_m[31] << 28) - | (mask_m[32] << 26) | (mask_m[33] << 24) - | (mask_m[34] << 22) | (mask_m[35] << 20) - | (mask_m[36] << 18) | (mask_m[37] << 16) - | (mask_m[48] << 14) | (mask_m[39] << 12) - | (mask_m[40] << 10) | (mask_m[41] << 8) - | (mask_m[42] << 6) | (mask_m[43] << 4) - | (mask_m[44] << 2) | (mask_m[45] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask); + if (AR_SREV_9280_20(ah)) { + if (((chan->channel % 20) == 0) + || ((chan->channel % 10) == 0)) + pll = 0x2850; + else + pll = 0x142c; + } + } else { + pll |= SM(0x2c, AR_RTC_9160_PLL_DIV); + } - tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28) - | (mask_m[18] << 26) | (mask_m[18] << 24) - | (mask_m[20] << 22) | (mask_m[20] << 20) - | (mask_m[22] << 18) | (mask_m[22] << 16) - | (mask_m[24] << 14) | (mask_m[24] << 12) - | (mask_m[25] << 10) | (mask_m[26] << 8) - | (mask_m[27] << 6) | (mask_m[28] << 4) - | (mask_m[29] << 2) | (mask_m[30] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask); + } else if (AR_SREV_9160_10_OR_LATER(ah)) { - tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28) - | (mask_m[2] << 26) | (mask_m[3] << 24) - | (mask_m[4] << 22) | (mask_m[5] << 20) - | (mask_m[6] << 18) | (mask_m[7] << 16) - | (mask_m[8] << 14) | (mask_m[9] << 12) - | (mask_m[10] << 10) | (mask_m[11] << 8) - | (mask_m[12] << 6) | (mask_m[13] << 4) - | (mask_m[14] << 2) | (mask_m[15] << 0); - REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask); + pll = SM(0x5, AR_RTC_9160_PLL_REFDIV); - tmp_mask = (mask_p[15] << 28) - | (mask_p[14] << 26) | (mask_p[13] << 24) - | (mask_p[12] << 22) | (mask_p[11] << 20) - | (mask_p[10] << 18) | (mask_p[9] << 16) - | (mask_p[8] << 14) | (mask_p[7] << 12) - | (mask_p[6] << 10) | (mask_p[5] << 8) - | (mask_p[4] << 6) | (mask_p[3] << 4) - | (mask_p[2] << 2) | (mask_p[1] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask); + if (chan && IS_CHAN_HALF_RATE(chan)) + pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL); + else if (chan && IS_CHAN_QUARTER_RATE(chan)) + pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL); - tmp_mask = (mask_p[30] << 28) - | (mask_p[29] << 26) | (mask_p[28] << 24) - | (mask_p[27] << 22) | (mask_p[26] << 20) - | (mask_p[25] << 18) | (mask_p[24] << 16) - | (mask_p[23] << 14) | (mask_p[22] << 12) - | (mask_p[21] << 10) | (mask_p[20] << 8) - | (mask_p[19] << 6) | (mask_p[18] << 4) - | (mask_p[17] << 2) | (mask_p[16] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask); + if (chan && IS_CHAN_5GHZ(chan)) + pll |= SM(0x50, AR_RTC_9160_PLL_DIV); + else + pll |= SM(0x58, AR_RTC_9160_PLL_DIV); + } else { + pll = AR_RTC_PLL_REFDIV_5 | AR_RTC_PLL_DIV2; - tmp_mask = (mask_p[45] << 28) - | (mask_p[44] << 26) | (mask_p[43] << 24) - | (mask_p[42] << 22) | (mask_p[41] << 20) - | (mask_p[40] << 18) | (mask_p[39] << 16) - | (mask_p[38] << 14) | (mask_p[37] << 12) - | (mask_p[36] << 10) | (mask_p[35] << 8) - | (mask_p[34] << 6) | (mask_p[33] << 4) - | (mask_p[32] << 2) | (mask_p[31] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask); + if (chan && IS_CHAN_HALF_RATE(chan)) + pll |= SM(0x1, AR_RTC_PLL_CLKSEL); + else if (chan && IS_CHAN_QUARTER_RATE(chan)) + pll |= SM(0x2, AR_RTC_PLL_CLKSEL); - tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28) - | (mask_p[59] << 26) | (mask_p[58] << 24) - | (mask_p[57] << 22) | (mask_p[56] << 20) - | (mask_p[55] << 18) | (mask_p[54] << 16) - | (mask_p[53] << 14) | (mask_p[52] << 12) - | (mask_p[51] << 10) | (mask_p[50] << 8) - | (mask_p[49] << 6) | (mask_p[48] << 4) - | (mask_p[47] << 2) | (mask_p[46] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); + if (chan && IS_CHAN_5GHZ(chan)) + pll |= SM(0xa, AR_RTC_PLL_DIV); + else + pll |= SM(0xb, AR_RTC_PLL_DIV); + } + } + REG_WRITE(ah, (u16) (AR_RTC_PLL_CONTROL), pll); + + udelay(RTC_PLL_SETTLE_DELAY); + + REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK); } static void ath9k_hw_init_chain_masks(struct ath_hal *ah) @@ -5140,8 +1050,6 @@ static void ath9k_hw_init_chain_masks(struct ath_hal *ah) } case 0x1: case 0x2: - if (!AR_SREV_9280(ah)) - break; case 0x7: REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask); REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask); @@ -5160,102 +1068,35 @@ static void ath9k_hw_init_chain_masks(struct ath_hal *ah) REG_READ(ah, AR_PHY_ANALOG_SWAP) | 0x00000001); } -static void ath9k_hw_set_addac(struct ath_hal *ah, - struct ath9k_channel *chan) +static void ath9k_hw_init_interrupt_masks(struct ath_hal *ah, + enum nl80211_iftype opmode) { - struct modal_eep_header *pModal; struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom *eep = &ahp->ah_eeprom; - u8 biaslevel; - - if (ah->ah_macVersion != AR_SREV_VERSION_9160) - return; - - if (ar5416_get_eep_rev(ahp) < AR5416_EEP_MINOR_VER_7) - return; - - pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); - - if (pModal->xpaBiasLvl != 0xff) { - biaslevel = pModal->xpaBiasLvl; - } else { - - u16 resetFreqBin, freqBin, freqCount = 0; - struct chan_centers centers; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - resetFreqBin = - FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)); - freqBin = pModal->xpaBiasLvlFreq[0] & 0xff; - biaslevel = (u8) (pModal->xpaBiasLvlFreq[0] >> 14); - - freqCount++; - - while (freqCount < 3) { - if (pModal->xpaBiasLvlFreq[freqCount] == 0x0) - break; - - freqBin = pModal->xpaBiasLvlFreq[freqCount] & 0xff; - if (resetFreqBin >= freqBin) { - biaslevel = - (u8) (pModal-> - xpaBiasLvlFreq[freqCount] - >> 14); - } else { - break; - } - freqCount++; - } - } - - if (IS_CHAN_2GHZ(chan)) { - INI_RA(&ahp->ah_iniAddac, 7, 1) = - (INI_RA(&ahp->ah_iniAddac, 7, 1) & (~0x18)) | biaslevel - << 3; - } else { - INI_RA(&ahp->ah_iniAddac, 6, 1) = - (INI_RA(&ahp->ah_iniAddac, 6, 1) & (~0xc0)) | biaslevel - << 6; - } -} + ahp->ah_maskReg = AR_IMR_TXERR | + AR_IMR_TXURN | + AR_IMR_RXERR | + AR_IMR_RXORN | + AR_IMR_BCNMISC; -static u32 ath9k_hw_mac_usec(struct ath_hal *ah, u32 clks) -{ - if (ah->ah_curchan != NULL) - return clks / - CLOCK_RATE[ath9k_hw_chan2wmode(ah, ah->ah_curchan)]; + if (ahp->ah_intrMitigation) + ahp->ah_maskReg |= AR_IMR_RXINTM | AR_IMR_RXMINTR; else - return clks / CLOCK_RATE[ATH9K_MODE_11B]; -} - -static u32 ath9k_hw_mac_to_usec(struct ath_hal *ah, u32 clks) -{ - struct ath9k_channel *chan = ah->ah_curchan; + ahp->ah_maskReg |= AR_IMR_RXOK; - if (chan && IS_CHAN_HT40(chan)) - return ath9k_hw_mac_usec(ah, clks) / 2; - else - return ath9k_hw_mac_usec(ah, clks); -} + ahp->ah_maskReg |= AR_IMR_TXOK; -static u32 ath9k_hw_mac_clks(struct ath_hal *ah, u32 usecs) -{ - if (ah->ah_curchan != NULL) - return usecs * CLOCK_RATE[ath9k_hw_chan2wmode(ah, - ah->ah_curchan)]; - else - return usecs * CLOCK_RATE[ATH9K_MODE_11B]; -} + if (opmode == NL80211_IFTYPE_AP) + ahp->ah_maskReg |= AR_IMR_MIB; -static u32 ath9k_hw_mac_to_clks(struct ath_hal *ah, u32 usecs) -{ - struct ath9k_channel *chan = ah->ah_curchan; + REG_WRITE(ah, AR_IMR, ahp->ah_maskReg); + REG_WRITE(ah, AR_IMR_S2, REG_READ(ah, AR_IMR_S2) | AR_IMR_S2_GTT); - if (chan && IS_CHAN_HT40(chan)) - return ath9k_hw_mac_clks(ah, usecs) * 2; - else - return ath9k_hw_mac_clks(ah, usecs); + if (!AR_SREV_9100(ah)) { + REG_WRITE(ah, AR_INTR_SYNC_CAUSE, 0xFFFFFFFF); + REG_WRITE(ah, AR_INTR_SYNC_ENABLE, AR_INTR_SYNC_DEFAULT); + REG_WRITE(ah, AR_INTR_SYNC_MASK, 0); + } } static bool ath9k_hw_set_ack_timeout(struct ath_hal *ah, u32 us) @@ -5263,8 +1104,7 @@ static bool ath9k_hw_set_ack_timeout(struct ath_hal *ah, u32 us) struct ath_hal_5416 *ahp = AH5416(ah); if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: bad ack timeout %u\n", - __func__, us); + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad ack timeout %u\n", us); ahp->ah_acktimeout = (u32) -1; return false; } else { @@ -5280,8 +1120,7 @@ static bool ath9k_hw_set_cts_timeout(struct ath_hal *ah, u32 us) struct ath_hal_5416 *ahp = AH5416(ah); if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: bad cts timeout %u\n", - __func__, us); + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad cts timeout %u\n", us); ahp->ah_ctstimeout = (u32) -1; return false; } else { @@ -5291,14 +1130,14 @@ static bool ath9k_hw_set_cts_timeout(struct ath_hal *ah, u32 us) return true; } } -static bool ath9k_hw_set_global_txtimeout(struct ath_hal *ah, - u32 tu) + +static bool ath9k_hw_set_global_txtimeout(struct ath_hal *ah, u32 tu) { struct ath_hal_5416 *ahp = AH5416(ah); if (tu > 0xFFFF) { DPRINTF(ah->ah_sc, ATH_DBG_XMIT, - "%s: bad global tx timeout %u\n", __func__, tu); + "bad global tx timeout %u\n", tu); ahp->ah_globaltxtimeout = (u32) -1; return false; } else { @@ -5308,45 +1147,135 @@ static bool ath9k_hw_set_global_txtimeout(struct ath_hal *ah, } } -bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us) -{ - struct ath_hal_5416 *ahp = AH5416(ah); +static void ath9k_hw_init_user_settings(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "ahp->ah_miscMode 0x%x\n", + ahp->ah_miscMode); + + if (ahp->ah_miscMode != 0) + REG_WRITE(ah, AR_PCU_MISC, + REG_READ(ah, AR_PCU_MISC) | ahp->ah_miscMode); + if (ahp->ah_slottime != (u32) -1) + ath9k_hw_setslottime(ah, ahp->ah_slottime); + if (ahp->ah_acktimeout != (u32) -1) + ath9k_hw_set_ack_timeout(ah, ahp->ah_acktimeout); + if (ahp->ah_ctstimeout != (u32) -1) + ath9k_hw_set_cts_timeout(ah, ahp->ah_ctstimeout); + if (ahp->ah_globaltxtimeout != (u32) -1) + ath9k_hw_set_global_txtimeout(ah, ahp->ah_globaltxtimeout); +} + +const char *ath9k_hw_probe(u16 vendorid, u16 devid) +{ + return vendorid == ATHEROS_VENDOR_ID ? + ath9k_hw_devname(devid) : NULL; +} + +void ath9k_hw_detach(struct ath_hal *ah) +{ + if (!AR_SREV_9100(ah)) + ath9k_hw_ani_detach(ah); + + ath9k_hw_rfdetach(ah); + ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); + kfree(ah); +} + +struct ath_hal *ath9k_hw_attach(u16 devid, struct ath_softc *sc, + void __iomem *mem, int *error) +{ + struct ath_hal *ah = NULL; + + switch (devid) { + case AR5416_DEVID_PCI: + case AR5416_DEVID_PCIE: + case AR9160_DEVID_PCI: + case AR9280_DEVID_PCI: + case AR9280_DEVID_PCIE: + case AR9285_DEVID_PCIE: + ah = ath9k_hw_do_attach(devid, sc, mem, error); + break; + default: + *error = -ENXIO; + break; + } + + return ah; +} + +/*******/ +/* INI */ +/*******/ + +static void ath9k_hw_override_ini(struct ath_hal *ah, + struct ath9k_channel *chan) +{ + /* + * Set the RX_ABORT and RX_DIS and clear if off only after + * RXE is set for MAC. This prevents frames with corrupted + * descriptor status. + */ + REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); + + + if (!AR_SREV_5416_V20_OR_LATER(ah) || + AR_SREV_9280_10_OR_LATER(ah)) + return; + + REG_WRITE(ah, 0x9800 + (651 << 2), 0x11); +} + +static u32 ath9k_hw_def_ini_fixup(struct ath_hal *ah, + struct ar5416_eeprom_def *pEepData, + u32 reg, u32 value) +{ + struct base_eep_header *pBase = &(pEepData->baseEepHeader); + + switch (ah->ah_devid) { + case AR9280_DEVID_PCI: + if (reg == 0x7894) { + DPRINTF(ah->ah_sc, ATH_DBG_ANY, + "ini VAL: %x EEPROM: %x\n", value, + (pBase->version & 0xff)); + + if ((pBase->version & 0xff) > 0x0a) { + DPRINTF(ah->ah_sc, ATH_DBG_ANY, + "PWDCLKIND: %d\n", + pBase->pwdclkind); + value &= ~AR_AN_TOP2_PWDCLKIND; + value |= AR_AN_TOP2_PWDCLKIND & + (pBase->pwdclkind << AR_AN_TOP2_PWDCLKIND_S); + } else { + DPRINTF(ah->ah_sc, ATH_DBG_ANY, + "PWDCLKIND Earlier Rev\n"); + } - if (us < ATH9K_SLOT_TIME_9 || us > ath9k_hw_mac_to_usec(ah, 0xffff)) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: bad slot time %u\n", - __func__, us); - ahp->ah_slottime = (u32) -1; - return false; - } else { - REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath9k_hw_mac_to_clks(ah, us)); - ahp->ah_slottime = us; - return true; + DPRINTF(ah->ah_sc, ATH_DBG_ANY, + "final ini VAL: %x\n", value); + } + break; } + + return value; } -static void ath9k_hw_init_user_settings(struct ath_hal *ah) +static u32 ath9k_hw_ini_fixup(struct ath_hal *ah, + struct ar5416_eeprom_def *pEepData, + u32 reg, u32 value) { struct ath_hal_5416 *ahp = AH5416(ah); - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "--AP %s ahp->ah_miscMode 0x%x\n", - __func__, ahp->ah_miscMode); - if (ahp->ah_miscMode != 0) - REG_WRITE(ah, AR_PCU_MISC, - REG_READ(ah, AR_PCU_MISC) | ahp->ah_miscMode); - if (ahp->ah_slottime != (u32) -1) - ath9k_hw_setslottime(ah, ahp->ah_slottime); - if (ahp->ah_acktimeout != (u32) -1) - ath9k_hw_set_ack_timeout(ah, ahp->ah_acktimeout); - if (ahp->ah_ctstimeout != (u32) -1) - ath9k_hw_set_cts_timeout(ah, ahp->ah_ctstimeout); - if (ahp->ah_globaltxtimeout != (u32) -1) - ath9k_hw_set_global_txtimeout(ah, ahp->ah_globaltxtimeout); + if (ahp->ah_eep_map == EEP_MAP_4KBITS) + return value; + else + return ath9k_hw_def_ini_fixup(ah, pEepData, reg, value); } -static int -ath9k_hw_process_ini(struct ath_hal *ah, - struct ath9k_channel *chan, - enum ath9k_ht_macmode macmode) +static int ath9k_hw_process_ini(struct ath_hal *ah, + struct ath9k_channel *chan, + enum ath9k_ht_macmode macmode) { int i, regWrites = 0; struct ath_hal_5416 *ahp = AH5416(ah); @@ -5397,26 +1326,20 @@ ath9k_hw_process_ini(struct ath_hal *ah, memcpy(ahp->ah_addac5416_21, ahp->ah_iniAddac.ia_array, addacSize); - (ahp->ah_addac5416_21)[31 * - ahp->ah_iniAddac.ia_columns + 1] = 0; + (ahp->ah_addac5416_21)[31 * ahp->ah_iniAddac.ia_columns + 1] = 0; temp.ia_array = ahp->ah_addac5416_21; temp.ia_columns = ahp->ah_iniAddac.ia_columns; temp.ia_rows = ahp->ah_iniAddac.ia_rows; REG_WRITE_ARRAY(&temp, 1, regWrites); } + REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC); for (i = 0; i < ahp->ah_iniModes.ia_rows; i++) { u32 reg = INI_RA(&ahp->ah_iniModes, i, 0); u32 val = INI_RA(&ahp->ah_iniModes, i, modesIndex); -#ifdef CONFIG_SLOW_ANT_DIV - if (ah->ah_devid == AR9280_DEVID_PCI) - val = ath9k_hw_ini_fixup(ah, &ahp->ah_eeprom, reg, - val); -#endif - REG_WRITE(ah, reg, val); if (reg >= 0x7800 && reg < 0x78a0 @@ -5427,6 +1350,12 @@ ath9k_hw_process_ini(struct ath_hal *ah, DO_DELAY(regWrites); } + if (AR_SREV_9280(ah)) + REG_WRITE_ARRAY(&ahp->ah_iniModesRxGain, modesIndex, regWrites); + + if (AR_SREV_9280(ah)) + REG_WRITE_ARRAY(&ahp->ah_iniModesTxGain, modesIndex, regWrites); + for (i = 0; i < ahp->ah_iniCommon.ia_rows; i++) { u32 reg = INI_RA(&ahp->ah_iniCommon, i, 0); u32 val = INI_RA(&ahp->ah_iniCommon, i, 1); @@ -5452,7 +1381,7 @@ ath9k_hw_process_ini(struct ath_hal *ah, ath9k_hw_set_regs(ah, chan, macmode); ath9k_hw_init_chain_masks(ah); - status = ath9k_hw_set_txpower(ah, &ahp->ah_eeprom, chan, + status = ath9k_hw_set_txpower(ah, chan, ath9k_regd_get_ctl(ah, chan), ath9k_regd_get_antenna_allowed(ah, chan), @@ -5461,178 +1390,324 @@ ath9k_hw_process_ini(struct ath_hal *ah, (u32) ah->ah_powerLimit)); if (status != 0) { DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, - "%s: error init'ing transmit power\n", __func__); + "error init'ing transmit power\n"); return -EIO; } if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) { DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "%s: ar5416SetRfRegs failed\n", __func__); + "ar5416SetRfRegs failed\n"); return -EIO; } return 0; } -static void ath9k_hw_setup_calibration(struct ath_hal *ah, - struct hal_cal_list *currCal) +/****************************************/ +/* Reset and Channel Switching Routines */ +/****************************************/ + +static void ath9k_hw_set_rfmode(struct ath_hal *ah, struct ath9k_channel *chan) { - REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0), - AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX, - currCal->calData->calCountMax); - - switch (currCal->calData->calType) { - case IQ_MISMATCH_CAL: - REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: starting IQ Mismatch Calibration\n", - __func__); - break; - case ADC_GAIN_CAL: - REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: starting ADC Gain Calibration\n", __func__); + u32 rfMode = 0; + + if (chan == NULL) + return; + + rfMode |= (IS_CHAN_B(chan) || IS_CHAN_G(chan)) + ? AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM; + + if (!AR_SREV_9280_10_OR_LATER(ah)) + rfMode |= (IS_CHAN_5GHZ(chan)) ? + AR_PHY_MODE_RF5GHZ : AR_PHY_MODE_RF2GHZ; + + if (AR_SREV_9280_20(ah) && IS_CHAN_A_5MHZ_SPACED(chan)) + rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE); + + REG_WRITE(ah, AR_PHY_MODE, rfMode); +} + +static void ath9k_hw_mark_phy_inactive(struct ath_hal *ah) +{ + REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); +} + +static inline void ath9k_hw_set_dma(struct ath_hal *ah) +{ + u32 regval; + + regval = REG_READ(ah, AR_AHB_MODE); + REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN); + + regval = REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK; + REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B); + + REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, ah->ah_txTrigLevel); + + regval = REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK; + REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B); + + REG_WRITE(ah, AR_RXFIFO_CFG, 0x200); + + if (AR_SREV_9285(ah)) { + REG_WRITE(ah, AR_PCU_TXBUF_CTRL, + AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE); + } else { + REG_WRITE(ah, AR_PCU_TXBUF_CTRL, + AR_PCU_TXBUF_CTRL_USABLE_SIZE); + } +} + +static void ath9k_hw_set_operating_mode(struct ath_hal *ah, int opmode) +{ + u32 val; + + val = REG_READ(ah, AR_STA_ID1); + val &= ~(AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC); + switch (opmode) { + case NL80211_IFTYPE_AP: + REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_STA_AP + | AR_STA_ID1_KSRCH_MODE); + REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); break; - case ADC_DC_CAL: - REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: starting ADC DC Calibration\n", __func__); + case NL80211_IFTYPE_ADHOC: + REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_ADHOC + | AR_STA_ID1_KSRCH_MODE); + REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); break; - case ADC_DC_INIT_CAL: - REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: starting Init ADC DC Calibration\n", - __func__); + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_MONITOR: + REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE); break; } +} + +static inline void ath9k_hw_get_delta_slope_vals(struct ath_hal *ah, + u32 coef_scaled, + u32 *coef_mantissa, + u32 *coef_exponent) +{ + u32 coef_exp, coef_man; + + for (coef_exp = 31; coef_exp > 0; coef_exp--) + if ((coef_scaled >> coef_exp) & 0x1) + break; + + coef_exp = 14 - (coef_exp - COEF_SCALE_S); + + coef_man = coef_scaled + (1 << (COEF_SCALE_S - coef_exp - 1)); - REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0), - AR_PHY_TIMING_CTRL4_DO_CAL); + *coef_mantissa = coef_man >> (COEF_SCALE_S - coef_exp); + *coef_exponent = coef_exp - 16; } -static void ath9k_hw_reset_calibration(struct ath_hal *ah, - struct hal_cal_list *currCal) +static void ath9k_hw_set_delta_slope(struct ath_hal *ah, + struct ath9k_channel *chan) { - struct ath_hal_5416 *ahp = AH5416(ah); - int i; + u32 coef_scaled, ds_coef_exp, ds_coef_man; + u32 clockMhzScaled = 0x64000000; + struct chan_centers centers; + + if (IS_CHAN_HALF_RATE(chan)) + clockMhzScaled = clockMhzScaled >> 1; + else if (IS_CHAN_QUARTER_RATE(chan)) + clockMhzScaled = clockMhzScaled >> 2; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + coef_scaled = clockMhzScaled / centers.synth_center; + + ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man, + &ds_coef_exp); + + REG_RMW_FIELD(ah, AR_PHY_TIMING3, + AR_PHY_TIMING3_DSC_MAN, ds_coef_man); + REG_RMW_FIELD(ah, AR_PHY_TIMING3, + AR_PHY_TIMING3_DSC_EXP, ds_coef_exp); + + coef_scaled = (9 * coef_scaled) / 10; + + ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man, + &ds_coef_exp); + + REG_RMW_FIELD(ah, AR_PHY_HALFGI, + AR_PHY_HALFGI_DSC_MAN, ds_coef_man); + REG_RMW_FIELD(ah, AR_PHY_HALFGI, + AR_PHY_HALFGI_DSC_EXP, ds_coef_exp); +} + +static bool ath9k_hw_set_reset(struct ath_hal *ah, int type) +{ + u32 rst_flags; + u32 tmpReg; + + REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | + AR_RTC_FORCE_WAKE_ON_INT); + + if (AR_SREV_9100(ah)) { + rst_flags = AR_RTC_RC_MAC_WARM | AR_RTC_RC_MAC_COLD | + AR_RTC_RC_COLD_RESET | AR_RTC_RC_WARM_RESET; + } else { + tmpReg = REG_READ(ah, AR_INTR_SYNC_CAUSE); + if (tmpReg & + (AR_INTR_SYNC_LOCAL_TIMEOUT | + AR_INTR_SYNC_RADM_CPL_TIMEOUT)) { + REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0); + REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF); + } else { + REG_WRITE(ah, AR_RC, AR_RC_AHB); + } + + rst_flags = AR_RTC_RC_MAC_WARM; + if (type == ATH9K_RESET_COLD) + rst_flags |= AR_RTC_RC_MAC_COLD; + } + + REG_WRITE(ah, (u16) (AR_RTC_RC), rst_flags); + udelay(50); + + REG_WRITE(ah, (u16) (AR_RTC_RC), 0); + if (!ath9k_hw_wait(ah, (u16) (AR_RTC_RC), AR_RTC_RC_M, 0)) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, + "RTC stuck in MAC reset\n"); + return false; + } + + if (!AR_SREV_9100(ah)) + REG_WRITE(ah, AR_RC, 0); + + ath9k_hw_init_pll(ah, NULL); - ath9k_hw_setup_calibration(ah, currCal); + if (AR_SREV_9100(ah)) + udelay(50); + + return true; +} + +static bool ath9k_hw_set_reset_power_on(struct ath_hal *ah) +{ + REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | + AR_RTC_FORCE_WAKE_ON_INT); - currCal->calState = CAL_RUNNING; + REG_WRITE(ah, (u16) (AR_RTC_RESET), 0); + REG_WRITE(ah, (u16) (AR_RTC_RESET), 1); - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - ahp->ah_Meas0.sign[i] = 0; - ahp->ah_Meas1.sign[i] = 0; - ahp->ah_Meas2.sign[i] = 0; - ahp->ah_Meas3.sign[i] = 0; + if (!ath9k_hw_wait(ah, + AR_RTC_STATUS, + AR_RTC_STATUS_M, + AR_RTC_STATUS_ON)) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "RTC not waking up\n"); + return false; } - ahp->ah_CalSamples = 0; + ath9k_hw_read_revisions(ah); + + return ath9k_hw_set_reset(ah, ATH9K_RESET_WARM); } -static void -ath9k_hw_per_calibration(struct ath_hal *ah, - struct ath9k_channel *ichan, - u8 rxchainmask, - struct hal_cal_list *currCal, - bool *isCalDone) +static bool ath9k_hw_set_reset_reg(struct ath_hal *ah, u32 type) { - struct ath_hal_5416 *ahp = AH5416(ah); + REG_WRITE(ah, AR_RTC_FORCE_WAKE, + AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); - *isCalDone = false; + switch (type) { + case ATH9K_RESET_POWER_ON: + return ath9k_hw_set_reset_power_on(ah); + break; + case ATH9K_RESET_WARM: + case ATH9K_RESET_COLD: + return ath9k_hw_set_reset(ah, type); + break; + default: + return false; + } +} - if (currCal->calState == CAL_RUNNING) { - if (!(REG_READ(ah, - AR_PHY_TIMING_CTRL4(0)) & - AR_PHY_TIMING_CTRL4_DO_CAL)) { +static void ath9k_hw_set_regs(struct ath_hal *ah, struct ath9k_channel *chan, + enum ath9k_ht_macmode macmode) +{ + u32 phymode; + u32 enableDacFifo = 0; + struct ath_hal_5416 *ahp = AH5416(ah); - currCal->calData->calCollect(ah); + if (AR_SREV_9285_10_OR_LATER(ah)) + enableDacFifo = (REG_READ(ah, AR_PHY_TURBO) & + AR_PHY_FC_ENABLE_DAC_FIFO); - ahp->ah_CalSamples++; + phymode = AR_PHY_FC_HT_EN | AR_PHY_FC_SHORT_GI_40 + | AR_PHY_FC_SINGLE_HT_LTF1 | AR_PHY_FC_WALSH | enableDacFifo; - if (ahp->ah_CalSamples >= - currCal->calData->calNumSamples) { - int i, numChains = 0; - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - if (rxchainmask & (1 << i)) - numChains++; - } + if (IS_CHAN_HT40(chan)) { + phymode |= AR_PHY_FC_DYN2040_EN; - currCal->calData->calPostProc(ah, - numChains); + if ((chan->chanmode == CHANNEL_A_HT40PLUS) || + (chan->chanmode == CHANNEL_G_HT40PLUS)) + phymode |= AR_PHY_FC_DYN2040_PRI_CH; - ichan->CalValid |= - currCal->calData->calType; - currCal->calState = CAL_DONE; - *isCalDone = true; - } else { - ath9k_hw_setup_calibration(ah, currCal); - } - } - } else if (!(ichan->CalValid & currCal->calData->calType)) { - ath9k_hw_reset_calibration(ah, currCal); + if (ahp->ah_extprotspacing == ATH9K_HT_EXTPROTSPACING_25) + phymode |= AR_PHY_FC_DYN2040_EXT_CH; } + REG_WRITE(ah, AR_PHY_TURBO, phymode); + + ath9k_hw_set11nmac2040(ah, macmode); + + REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S); + REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S); } -static inline bool ath9k_hw_run_init_cals(struct ath_hal *ah, - int init_cal_count) +static bool ath9k_hw_chip_reset(struct ath_hal *ah, + struct ath9k_channel *chan) { struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_channel ichan; - bool isCalDone; - struct hal_cal_list *currCal = ahp->ah_cal_list_curr; - const struct hal_percal_data *calData = currCal->calData; - int i; - if (currCal == NULL) + if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM)) return false; - ichan.CalValid = 0; + if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) + return false; - for (i = 0; i < init_cal_count; i++) { - ath9k_hw_reset_calibration(ah, currCal); + ahp->ah_chipFullSleep = false; - if (!ath9k_hw_wait(ah, AR_PHY_TIMING_CTRL4(0), - AR_PHY_TIMING_CTRL4_DO_CAL, 0)) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: Cal %d failed to complete in 100ms.\n", - __func__, calData->calType); + ath9k_hw_init_pll(ah, chan); - ahp->ah_cal_list = ahp->ah_cal_list_last = - ahp->ah_cal_list_curr = NULL; - return false; - } + ath9k_hw_set_rfmode(ah, chan); - ath9k_hw_per_calibration(ah, &ichan, ahp->ah_rxchainmask, - currCal, &isCalDone); - if (!isCalDone) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: Not able to run Init Cal %d.\n", - __func__, calData->calType); - } - if (currCal->calNext) { - currCal = currCal->calNext; - calData = currCal->calData; - } + return true; +} + +static struct ath9k_channel *ath9k_hw_check_chan(struct ath_hal *ah, + struct ath9k_channel *chan) +{ + if (!(IS_CHAN_2GHZ(chan) ^ IS_CHAN_5GHZ(chan))) { + DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, + "invalid channel %u/0x%x; not marked as " + "2GHz or 5GHz\n", chan->channel, chan->channelFlags); + return NULL; } - ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = NULL; - return true; + if (!IS_CHAN_OFDM(chan) && + !IS_CHAN_B(chan) && + !IS_CHAN_HT20(chan) && + !IS_CHAN_HT40(chan)) { + DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, + "invalid channel %u/0x%x; not marked as " + "OFDM or CCK or HT20 or HT40PLUS or HT40MINUS\n", + chan->channel, chan->channelFlags); + return NULL; + } + + return ath9k_regd_check_channel(ah, chan); } -static bool -ath9k_hw_channel_change(struct ath_hal *ah, - struct ath9k_channel *chan, - enum ath9k_ht_macmode macmode) +static bool ath9k_hw_channel_change(struct ath_hal *ah, + struct ath9k_channel *chan, + enum ath9k_ht_macmode macmode) { u32 synthDelay, qnum; - struct ath_hal_5416 *ahp = AH5416(ah); for (qnum = 0; qnum < AR_NUM_QCU; qnum++) { if (ath9k_hw_numtxpending(ah, qnum)) { DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, - "%s: Transmit frames pending on queue %d\n", - __func__, qnum); + "Transmit frames pending on queue %d\n", qnum); return false; } } @@ -5640,8 +1715,8 @@ ath9k_hw_channel_change(struct ath_hal *ah, REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN); if (!ath9k_hw_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN, AR_PHY_RFBUS_GRANT_EN)) { - DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO, - "%s: Could not kill baseband RX\n", __func__); + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "Could not kill baseband RX\n"); return false; } @@ -5650,30 +1725,30 @@ ath9k_hw_channel_change(struct ath_hal *ah, if (AR_SREV_9280_10_OR_LATER(ah)) { if (!(ath9k_hw_ar9280_set_channel(ah, chan))) { DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: failed to set channel\n", __func__); + "failed to set channel\n"); return false; } } else { if (!(ath9k_hw_set_channel(ah, chan))) { DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: failed to set channel\n", __func__); + "failed to set channel\n"); return false; } } - if (ath9k_hw_set_txpower(ah, &ahp->ah_eeprom, chan, + if (ath9k_hw_set_txpower(ah, chan, ath9k_regd_get_ctl(ah, chan), ath9k_regd_get_antenna_allowed(ah, chan), chan->maxRegTxPower * 2, min((u32) MAX_RATE_POWER, (u32) ah->ah_powerLimit)) != 0) { DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "%s: error init'ing transmit power\n", __func__); + "error init'ing transmit power\n"); return false; } synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; - if (IS_CHAN_CCK(chan)) + if (IS_CHAN_B(chan)) synthDelay = (4 * synthDelay) / 22; else synthDelay /= 10; @@ -5690,182 +1765,468 @@ ath9k_hw_channel_change(struct ath_hal *ah, else ath9k_hw_spur_mitigate(ah, chan); - if (!chan->oneTimeCalsDone) - chan->oneTimeCalsDone = true; + if (!chan->oneTimeCalsDone) + chan->oneTimeCalsDone = true; + + return true; +} + +static void ath9k_hw_9280_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan) +{ + int bb_spur = AR_NO_SPUR; + int freq; + int bin, cur_bin; + int bb_spur_off, spur_subchannel_sd; + int spur_freq_sd; + int spur_delta_phase; + int denominator; + int upper, lower, cur_vit_mask; + int tmp, newVal; + int i; + int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, + AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 + }; + int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, + AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 + }; + int inc[4] = { 0, 100, 0, 0 }; + struct chan_centers centers; + + int8_t mask_m[123]; + int8_t mask_p[123]; + int8_t mask_amt; + int tmp_mask; + int cur_bb_spur; + bool is2GHz = IS_CHAN_2GHZ(chan); + + memset(&mask_m, 0, sizeof(int8_t) * 123); + memset(&mask_p, 0, sizeof(int8_t) * 123); + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + freq = centers.synth_center; + + ah->ah_config.spurmode = SPUR_ENABLE_EEPROM; + for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { + cur_bb_spur = ath9k_hw_eeprom_get_spur_chan(ah, i, is2GHz); + + if (is2GHz) + cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_2GHZ; + else + cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_5GHZ; + + if (AR_NO_SPUR == cur_bb_spur) + break; + cur_bb_spur = cur_bb_spur - freq; + + if (IS_CHAN_HT40(chan)) { + if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT40) && + (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT40)) { + bb_spur = cur_bb_spur; + break; + } + } else if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT20) && + (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT20)) { + bb_spur = cur_bb_spur; + break; + } + } + + if (AR_NO_SPUR == bb_spur) { + REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, + AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); + return; + } else { + REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, + AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); + } + + bin = bb_spur * 320; + + tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0)); + + newVal = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | + AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER | + AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK | + AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK); + REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), newVal); + + newVal = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | + AR_PHY_SPUR_REG_ENABLE_MASK_PPM | + AR_PHY_SPUR_REG_MASK_RATE_SELECT | + AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | + SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); + REG_WRITE(ah, AR_PHY_SPUR_REG, newVal); + + if (IS_CHAN_HT40(chan)) { + if (bb_spur < 0) { + spur_subchannel_sd = 1; + bb_spur_off = bb_spur + 10; + } else { + spur_subchannel_sd = 0; + bb_spur_off = bb_spur - 10; + } + } else { + spur_subchannel_sd = 0; + bb_spur_off = bb_spur; + } + + if (IS_CHAN_HT40(chan)) + spur_delta_phase = + ((bb_spur * 262144) / + 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; + else + spur_delta_phase = + ((bb_spur * 524288) / + 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; + + denominator = IS_CHAN_2GHZ(chan) ? 44 : 40; + spur_freq_sd = ((bb_spur_off * 2048) / denominator) & 0x3ff; + + newVal = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | + SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | + SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); + REG_WRITE(ah, AR_PHY_TIMING11, newVal); + + newVal = spur_subchannel_sd << AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S; + REG_WRITE(ah, AR_PHY_SFCORR_EXT, newVal); + + cur_bin = -6000; + upper = bin + 100; + lower = bin - 100; + + for (i = 0; i < 4; i++) { + int pilot_mask = 0; + int chan_mask = 0; + int bp = 0; + for (bp = 0; bp < 30; bp++) { + if ((cur_bin > lower) && (cur_bin < upper)) { + pilot_mask = pilot_mask | 0x1 << bp; + chan_mask = chan_mask | 0x1 << bp; + } + cur_bin += 100; + } + cur_bin += inc[i]; + REG_WRITE(ah, pilot_mask_reg[i], pilot_mask); + REG_WRITE(ah, chan_mask_reg[i], chan_mask); + } + + cur_vit_mask = 6100; + upper = bin + 120; + lower = bin - 120; + + for (i = 0; i < 123; i++) { + if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { + + /* workaround for gcc bug #37014 */ + volatile int tmp = abs(cur_vit_mask - bin); + + if (tmp < 75) + mask_amt = 1; + else + mask_amt = 0; + if (cur_vit_mask < 0) + mask_m[abs(cur_vit_mask / 100)] = mask_amt; + else + mask_p[cur_vit_mask / 100] = mask_amt; + } + cur_vit_mask -= 100; + } + + tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28) + | (mask_m[48] << 26) | (mask_m[49] << 24) + | (mask_m[50] << 22) | (mask_m[51] << 20) + | (mask_m[52] << 18) | (mask_m[53] << 16) + | (mask_m[54] << 14) | (mask_m[55] << 12) + | (mask_m[56] << 10) | (mask_m[57] << 8) + | (mask_m[58] << 6) | (mask_m[59] << 4) + | (mask_m[60] << 2) | (mask_m[61] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask); + REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask); + + tmp_mask = (mask_m[31] << 28) + | (mask_m[32] << 26) | (mask_m[33] << 24) + | (mask_m[34] << 22) | (mask_m[35] << 20) + | (mask_m[36] << 18) | (mask_m[37] << 16) + | (mask_m[48] << 14) | (mask_m[39] << 12) + | (mask_m[40] << 10) | (mask_m[41] << 8) + | (mask_m[42] << 6) | (mask_m[43] << 4) + | (mask_m[44] << 2) | (mask_m[45] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask); + + tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28) + | (mask_m[18] << 26) | (mask_m[18] << 24) + | (mask_m[20] << 22) | (mask_m[20] << 20) + | (mask_m[22] << 18) | (mask_m[22] << 16) + | (mask_m[24] << 14) | (mask_m[24] << 12) + | (mask_m[25] << 10) | (mask_m[26] << 8) + | (mask_m[27] << 6) | (mask_m[28] << 4) + | (mask_m[29] << 2) | (mask_m[30] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask); + + tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28) + | (mask_m[2] << 26) | (mask_m[3] << 24) + | (mask_m[4] << 22) | (mask_m[5] << 20) + | (mask_m[6] << 18) | (mask_m[7] << 16) + | (mask_m[8] << 14) | (mask_m[9] << 12) + | (mask_m[10] << 10) | (mask_m[11] << 8) + | (mask_m[12] << 6) | (mask_m[13] << 4) + | (mask_m[14] << 2) | (mask_m[15] << 0); + REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask); + + tmp_mask = (mask_p[15] << 28) + | (mask_p[14] << 26) | (mask_p[13] << 24) + | (mask_p[12] << 22) | (mask_p[11] << 20) + | (mask_p[10] << 18) | (mask_p[9] << 16) + | (mask_p[8] << 14) | (mask_p[7] << 12) + | (mask_p[6] << 10) | (mask_p[5] << 8) + | (mask_p[4] << 6) | (mask_p[3] << 4) + | (mask_p[2] << 2) | (mask_p[1] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask); + + tmp_mask = (mask_p[30] << 28) + | (mask_p[29] << 26) | (mask_p[28] << 24) + | (mask_p[27] << 22) | (mask_p[26] << 20) + | (mask_p[25] << 18) | (mask_p[24] << 16) + | (mask_p[23] << 14) | (mask_p[22] << 12) + | (mask_p[21] << 10) | (mask_p[20] << 8) + | (mask_p[19] << 6) | (mask_p[18] << 4) + | (mask_p[17] << 2) | (mask_p[16] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask); + + tmp_mask = (mask_p[45] << 28) + | (mask_p[44] << 26) | (mask_p[43] << 24) + | (mask_p[42] << 22) | (mask_p[41] << 20) + | (mask_p[40] << 18) | (mask_p[39] << 16) + | (mask_p[38] << 14) | (mask_p[37] << 12) + | (mask_p[36] << 10) | (mask_p[35] << 8) + | (mask_p[34] << 6) | (mask_p[33] << 4) + | (mask_p[32] << 2) | (mask_p[31] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask); - return true; + tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28) + | (mask_p[59] << 26) | (mask_p[58] << 24) + | (mask_p[57] << 22) | (mask_p[56] << 20) + | (mask_p[55] << 18) | (mask_p[54] << 16) + | (mask_p[53] << 14) | (mask_p[52] << 12) + | (mask_p[51] << 10) | (mask_p[50] << 8) + | (mask_p[49] << 6) | (mask_p[48] << 4) + | (mask_p[47] << 2) | (mask_p[46] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); } -static bool ath9k_hw_chip_reset(struct ath_hal *ah, - struct ath9k_channel *chan) +static void ath9k_hw_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan) { - struct ath_hal_5416 *ahp = AH5416(ah); - - if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM)) - return false; + int bb_spur = AR_NO_SPUR; + int bin, cur_bin; + int spur_freq_sd; + int spur_delta_phase; + int denominator; + int upper, lower, cur_vit_mask; + int tmp, new; + int i; + int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, + AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 + }; + int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, + AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 + }; + int inc[4] = { 0, 100, 0, 0 }; - if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) - return false; + int8_t mask_m[123]; + int8_t mask_p[123]; + int8_t mask_amt; + int tmp_mask; + int cur_bb_spur; + bool is2GHz = IS_CHAN_2GHZ(chan); - ahp->ah_chipFullSleep = false; + memset(&mask_m, 0, sizeof(int8_t) * 123); + memset(&mask_p, 0, sizeof(int8_t) * 123); - ath9k_hw_init_pll(ah, chan); + for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { + cur_bb_spur = ath9k_hw_eeprom_get_spur_chan(ah, i, is2GHz); + if (AR_NO_SPUR == cur_bb_spur) + break; + cur_bb_spur = cur_bb_spur - (chan->channel * 10); + if ((cur_bb_spur > -95) && (cur_bb_spur < 95)) { + bb_spur = cur_bb_spur; + break; + } + } - ath9k_hw_set_rfmode(ah, chan); + if (AR_NO_SPUR == bb_spur) + return; - return true; -} + bin = bb_spur * 32; -static inline void ath9k_hw_set_dma(struct ath_hal *ah) -{ - u32 regval; + tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0)); + new = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | + AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER | + AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK | + AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK); - regval = REG_READ(ah, AR_AHB_MODE); - REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN); + REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), new); - regval = REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK; - REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B); + new = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | + AR_PHY_SPUR_REG_ENABLE_MASK_PPM | + AR_PHY_SPUR_REG_MASK_RATE_SELECT | + AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | + SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); + REG_WRITE(ah, AR_PHY_SPUR_REG, new); - REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, ah->ah_txTrigLevel); + spur_delta_phase = ((bb_spur * 524288) / 100) & + AR_PHY_TIMING11_SPUR_DELTA_PHASE; - regval = REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK; - REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B); + denominator = IS_CHAN_2GHZ(chan) ? 440 : 400; + spur_freq_sd = ((bb_spur * 2048) / denominator) & 0x3ff; - REG_WRITE(ah, AR_RXFIFO_CFG, 0x200); + new = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | + SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | + SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); + REG_WRITE(ah, AR_PHY_TIMING11, new); - if (AR_SREV_9285(ah)) { - REG_WRITE(ah, AR_PCU_TXBUF_CTRL, - AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE); - } else { - REG_WRITE(ah, AR_PCU_TXBUF_CTRL, - AR_PCU_TXBUF_CTRL_USABLE_SIZE); - } -} + cur_bin = -6000; + upper = bin + 100; + lower = bin - 100; -bool ath9k_hw_stopdmarecv(struct ath_hal *ah) -{ - REG_WRITE(ah, AR_CR, AR_CR_RXD); - if (!ath9k_hw_wait(ah, AR_CR, AR_CR_RXE, 0)) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, - "%s: dma failed to stop in 10ms\n" - "AR_CR=0x%08x\nAR_DIAG_SW=0x%08x\n", - __func__, - REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW)); - return false; - } else { - return true; + for (i = 0; i < 4; i++) { + int pilot_mask = 0; + int chan_mask = 0; + int bp = 0; + for (bp = 0; bp < 30; bp++) { + if ((cur_bin > lower) && (cur_bin < upper)) { + pilot_mask = pilot_mask | 0x1 << bp; + chan_mask = chan_mask | 0x1 << bp; + } + cur_bin += 100; + } + cur_bin += inc[i]; + REG_WRITE(ah, pilot_mask_reg[i], pilot_mask); + REG_WRITE(ah, chan_mask_reg[i], chan_mask); } -} - -void ath9k_hw_startpcureceive(struct ath_hal *ah) -{ - REG_CLR_BIT(ah, AR_DIAG_SW, - (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); - ath9k_enable_mib_counters(ah); - - ath9k_ani_reset(ah); -} - -void ath9k_hw_stoppcurecv(struct ath_hal *ah) -{ - REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS); + cur_vit_mask = 6100; + upper = bin + 120; + lower = bin - 120; - ath9k_hw_disable_mib_counters(ah); -} + for (i = 0; i < 123; i++) { + if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { -static bool ath9k_hw_iscal_supported(struct ath_hal *ah, - struct ath9k_channel *chan, - enum hal_cal_types calType) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - bool retval = false; + /* workaround for gcc bug #37014 */ + volatile int tmp = abs(cur_vit_mask - bin); - switch (calType & ahp->ah_suppCals) { - case IQ_MISMATCH_CAL: - if (!IS_CHAN_B(chan)) - retval = true; - break; - case ADC_GAIN_CAL: - case ADC_DC_CAL: - if (!IS_CHAN_B(chan) - && !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan))) - retval = true; - break; + if (tmp < 75) + mask_amt = 1; + else + mask_amt = 0; + if (cur_vit_mask < 0) + mask_m[abs(cur_vit_mask / 100)] = mask_amt; + else + mask_p[cur_vit_mask / 100] = mask_amt; + } + cur_vit_mask -= 100; } - return retval; -} - -static bool ath9k_hw_init_cal(struct ath_hal *ah, - struct ath9k_channel *chan) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_channel *ichan = - ath9k_regd_check_channel(ah, chan); - - REG_WRITE(ah, AR_PHY_AGC_CONTROL, - REG_READ(ah, AR_PHY_AGC_CONTROL) | - AR_PHY_AGC_CONTROL_CAL); - - if (!ath9k_hw_wait - (ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: offset calibration failed to complete in 1ms; " - "noisy environment?\n", __func__); - return false; - } + tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28) + | (mask_m[48] << 26) | (mask_m[49] << 24) + | (mask_m[50] << 22) | (mask_m[51] << 20) + | (mask_m[52] << 18) | (mask_m[53] << 16) + | (mask_m[54] << 14) | (mask_m[55] << 12) + | (mask_m[56] << 10) | (mask_m[57] << 8) + | (mask_m[58] << 6) | (mask_m[59] << 4) + | (mask_m[60] << 2) | (mask_m[61] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask); + REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask); - REG_WRITE(ah, AR_PHY_AGC_CONTROL, - REG_READ(ah, AR_PHY_AGC_CONTROL) | - AR_PHY_AGC_CONTROL_NF); + tmp_mask = (mask_m[31] << 28) + | (mask_m[32] << 26) | (mask_m[33] << 24) + | (mask_m[34] << 22) | (mask_m[35] << 20) + | (mask_m[36] << 18) | (mask_m[37] << 16) + | (mask_m[48] << 14) | (mask_m[39] << 12) + | (mask_m[40] << 10) | (mask_m[41] << 8) + | (mask_m[42] << 6) | (mask_m[43] << 4) + | (mask_m[44] << 2) | (mask_m[45] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask); - ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = - NULL; + tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28) + | (mask_m[18] << 26) | (mask_m[18] << 24) + | (mask_m[20] << 22) | (mask_m[20] << 20) + | (mask_m[22] << 18) | (mask_m[22] << 16) + | (mask_m[24] << 14) | (mask_m[24] << 12) + | (mask_m[25] << 10) | (mask_m[26] << 8) + | (mask_m[27] << 6) | (mask_m[28] << 4) + | (mask_m[29] << 2) | (mask_m[30] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask); - if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) { - if (ath9k_hw_iscal_supported(ah, chan, ADC_GAIN_CAL)) { - INIT_CAL(&ahp->ah_adcGainCalData); - INSERT_CAL(ahp, &ahp->ah_adcGainCalData); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: enabling ADC Gain Calibration.\n", - __func__); - } - if (ath9k_hw_iscal_supported(ah, chan, ADC_DC_CAL)) { - INIT_CAL(&ahp->ah_adcDcCalData); - INSERT_CAL(ahp, &ahp->ah_adcDcCalData); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: enabling ADC DC Calibration.\n", - __func__); - } - if (ath9k_hw_iscal_supported(ah, chan, IQ_MISMATCH_CAL)) { - INIT_CAL(&ahp->ah_iqCalData); - INSERT_CAL(ahp, &ahp->ah_iqCalData); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: enabling IQ Calibration.\n", - __func__); - } + tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28) + | (mask_m[2] << 26) | (mask_m[3] << 24) + | (mask_m[4] << 22) | (mask_m[5] << 20) + | (mask_m[6] << 18) | (mask_m[7] << 16) + | (mask_m[8] << 14) | (mask_m[9] << 12) + | (mask_m[10] << 10) | (mask_m[11] << 8) + | (mask_m[12] << 6) | (mask_m[13] << 4) + | (mask_m[14] << 2) | (mask_m[15] << 0); + REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask); - ahp->ah_cal_list_curr = ahp->ah_cal_list; + tmp_mask = (mask_p[15] << 28) + | (mask_p[14] << 26) | (mask_p[13] << 24) + | (mask_p[12] << 22) | (mask_p[11] << 20) + | (mask_p[10] << 18) | (mask_p[9] << 16) + | (mask_p[8] << 14) | (mask_p[7] << 12) + | (mask_p[6] << 10) | (mask_p[5] << 8) + | (mask_p[4] << 6) | (mask_p[3] << 4) + | (mask_p[2] << 2) | (mask_p[1] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask); - if (ahp->ah_cal_list_curr) - ath9k_hw_reset_calibration(ah, - ahp->ah_cal_list_curr); - } + tmp_mask = (mask_p[30] << 28) + | (mask_p[29] << 26) | (mask_p[28] << 24) + | (mask_p[27] << 22) | (mask_p[26] << 20) + | (mask_p[25] << 18) | (mask_p[24] << 16) + | (mask_p[23] << 14) | (mask_p[22] << 12) + | (mask_p[21] << 10) | (mask_p[20] << 8) + | (mask_p[19] << 6) | (mask_p[18] << 4) + | (mask_p[17] << 2) | (mask_p[16] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask); - ichan->CalValid = 0; + tmp_mask = (mask_p[45] << 28) + | (mask_p[44] << 26) | (mask_p[43] << 24) + | (mask_p[42] << 22) | (mask_p[41] << 20) + | (mask_p[40] << 18) | (mask_p[39] << 16) + | (mask_p[38] << 14) | (mask_p[37] << 12) + | (mask_p[36] << 10) | (mask_p[35] << 8) + | (mask_p[34] << 6) | (mask_p[33] << 4) + | (mask_p[32] << 2) | (mask_p[31] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask); - return true; + tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28) + | (mask_p[59] << 26) | (mask_p[58] << 24) + | (mask_p[57] << 22) | (mask_p[56] << 20) + | (mask_p[55] << 18) | (mask_p[54] << 16) + | (mask_p[53] << 14) | (mask_p[52] << 12) + | (mask_p[51] << 10) | (mask_p[50] << 8) + | (mask_p[49] << 6) | (mask_p[48] << 4) + | (mask_p[47] << 2) | (mask_p[46] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); } - -bool ath9k_hw_reset(struct ath_hal *ah, - struct ath9k_channel *chan, +bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan, enum ath9k_ht_macmode macmode, u8 txchainmask, u8 rxchainmask, enum ath9k_ht_extprotspacing extprotspacing, - bool bChannelChange, - int *status) + bool bChannelChange, int *status) { u32 saveLedState; struct ath_hal_5416 *ahp = AH5416(ah); @@ -5886,8 +2247,8 @@ bool ath9k_hw_reset(struct ath_hal *ah, if (ath9k_hw_check_chan(ah, chan) == NULL) { DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: invalid channel %u/0x%x; no mapping\n", - __func__, chan->channel, chan->channelFlags); + "invalid channel %u/0x%x; no mapping\n", + chan->channel, chan->channelFlags); ecode = -EINVAL; goto bad; } @@ -5907,8 +2268,7 @@ bool ath9k_hw_reset(struct ath_hal *ah, ((chan->channelFlags & CHANNEL_ALL) == (ah->ah_curchan->channelFlags & CHANNEL_ALL)) && (!AR_SREV_9280(ah) || (!IS_CHAN_A_5MHZ_SPACED(chan) && - !IS_CHAN_A_5MHZ_SPACED(ah-> - ah_curchan)))) { + !IS_CHAN_A_5MHZ_SPACED(ah->ah_curchan)))) { if (ath9k_hw_channel_change(ah, chan, macmode)) { ath9k_hw_loadnf(ah, ah->ah_curchan); @@ -5930,8 +2290,7 @@ bool ath9k_hw_reset(struct ath_hal *ah, ath9k_hw_mark_phy_inactive(ah); if (!ath9k_hw_chip_reset(ah, chan)) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: chip reset failed\n", - __func__); + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "chip reset failed\n"); ecode = -EINVAL; goto bad; } @@ -5965,7 +2324,7 @@ bool ath9k_hw_reset(struct ath_hal *ah, if (!ath9k_hw_eeprom_set_board_values(ah, chan)) { DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "%s: error setting board options\n", __func__); + "error setting board options\n"); ecode = -EIO; goto bad; } @@ -6016,7 +2375,7 @@ bool ath9k_hw_reset(struct ath_hal *ah, ath9k_hw_init_interrupt_masks(ah, ah->ah_opmode); ath9k_hw_init_qos(ah); -#ifdef CONFIG_RFKILL +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) ath9k_enable_rfkill(ah); #endif @@ -6055,15 +2414,13 @@ bool ath9k_hw_reset(struct ath_hal *ah, mask = REG_READ(ah, AR_CFG); if (mask & (AR_CFG_SWRB | AR_CFG_SWTB | AR_CFG_SWRG)) { DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s CFG Byte Swap Set 0x%x\n", __func__, - mask); + "CFG Byte Swap Set 0x%x\n", mask); } else { mask = INIT_CONFIG_STATUS | AR_CFG_SWRB | AR_CFG_SWTB; REG_WRITE(ah, AR_CFG, mask); DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s Setting CFG 0x%x\n", __func__, - REG_READ(ah, AR_CFG)); + "Setting CFG 0x%x\n", REG_READ(ah, AR_CFG)); } } else { #ifdef __BIG_ENDIAN @@ -6078,693 +2435,402 @@ bool ath9k_hw_reset(struct ath_hal *ah, return false; } -bool ath9k_hw_phy_disable(struct ath_hal *ah) -{ - return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM); -} - -bool ath9k_hw_disable(struct ath_hal *ah) -{ - if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) - return false; - - return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_COLD); -} +/************************/ +/* Key Cache Management */ +/************************/ -bool -ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan, - u8 rxchainmask, bool longcal, - bool *isCalDone) +bool ath9k_hw_keyreset(struct ath_hal *ah, u16 entry) { - struct ath_hal_5416 *ahp = AH5416(ah); - struct hal_cal_list *currCal = ahp->ah_cal_list_curr; - struct ath9k_channel *ichan = - ath9k_regd_check_channel(ah, chan); - - *isCalDone = true; + u32 keyType; - if (ichan == NULL) { - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: invalid channel %u/0x%x; no mapping\n", - __func__, chan->channel, chan->channelFlags); + if (entry >= ah->ah_caps.keycache_size) { + DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, + "entry %u out of range\n", entry); return false; } - if (currCal && - (currCal->calState == CAL_RUNNING || - currCal->calState == CAL_WAITING)) { - ath9k_hw_per_calibration(ah, ichan, rxchainmask, currCal, - isCalDone); - if (*isCalDone) { - ahp->ah_cal_list_curr = currCal = currCal->calNext; - - if (currCal->calState == CAL_WAITING) { - *isCalDone = false; - ath9k_hw_reset_calibration(ah, currCal); - } - } - } - - if (longcal) { - ath9k_hw_getnf(ah, ichan); - ath9k_hw_loadnf(ah, ah->ah_curchan); - ath9k_hw_start_nfcal(ah); - - if ((ichan->channelFlags & CHANNEL_CW_INT) != 0) { - - chan->channelFlags |= CHANNEL_CW_INT; - ichan->channelFlags &= ~CHANNEL_CW_INT; - } - } - - return true; -} - -static void ath9k_hw_iqcal_collect(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - int i; - - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - ahp->ah_totalPowerMeasI[i] += - REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); - ahp->ah_totalPowerMeasQ[i] += - REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); - ahp->ah_totalIqCorrMeas[i] += - (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", - ahp->ah_CalSamples, i, ahp->ah_totalPowerMeasI[i], - ahp->ah_totalPowerMeasQ[i], - ahp->ah_totalIqCorrMeas[i]); - } -} - -static void ath9k_hw_adc_gaincal_collect(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - int i; - - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - ahp->ah_totalAdcIOddPhase[i] += - REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); - ahp->ah_totalAdcIEvenPhase[i] += - REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); - ahp->ah_totalAdcQOddPhase[i] += - REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); - ahp->ah_totalAdcQEvenPhase[i] += - REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%d: Chn %d oddi=0x%08x; eveni=0x%08x; " - "oddq=0x%08x; evenq=0x%08x;\n", - ahp->ah_CalSamples, i, - ahp->ah_totalAdcIOddPhase[i], - ahp->ah_totalAdcIEvenPhase[i], - ahp->ah_totalAdcQOddPhase[i], - ahp->ah_totalAdcQEvenPhase[i]); - } -} - -static void ath9k_hw_adc_dccal_collect(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - int i; - - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - ahp->ah_totalAdcDcOffsetIOddPhase[i] += - (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); - ahp->ah_totalAdcDcOffsetIEvenPhase[i] += - (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); - ahp->ah_totalAdcDcOffsetQOddPhase[i] += - (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); - ahp->ah_totalAdcDcOffsetQEvenPhase[i] += - (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%d: Chn %d oddi=0x%08x; eveni=0x%08x; " - "oddq=0x%08x; evenq=0x%08x;\n", - ahp->ah_CalSamples, i, - ahp->ah_totalAdcDcOffsetIOddPhase[i], - ahp->ah_totalAdcDcOffsetIEvenPhase[i], - ahp->ah_totalAdcDcOffsetQOddPhase[i], - ahp->ah_totalAdcDcOffsetQEvenPhase[i]); - } -} - -static void ath9k_hw_iqcalibrate(struct ath_hal *ah, u8 numChains) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - u32 powerMeasQ, powerMeasI, iqCorrMeas; - u32 qCoffDenom, iCoffDenom; - int32_t qCoff, iCoff; - int iqCorrNeg, i; - - for (i = 0; i < numChains; i++) { - powerMeasI = ahp->ah_totalPowerMeasI[i]; - powerMeasQ = ahp->ah_totalPowerMeasQ[i]; - iqCorrMeas = ahp->ah_totalIqCorrMeas[i]; - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Starting IQ Cal and Correction for Chain %d\n", - i); - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Orignal: Chn %diq_corr_meas = 0x%08x\n", - i, ahp->ah_totalIqCorrMeas[i]); - - iqCorrNeg = 0; - - - if (iqCorrMeas > 0x80000000) { - iqCorrMeas = (0xffffffff - iqCorrMeas) + 1; - iqCorrNeg = 1; - } - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n", - iqCorrNeg); - - iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128; - qCoffDenom = powerMeasQ / 64; - - if (powerMeasQ != 0) { - - iCoff = iqCorrMeas / iCoffDenom; - qCoff = powerMeasI / qCoffDenom - 64; - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d iCoff = 0x%08x\n", i, iCoff); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d qCoff = 0x%08x\n", i, qCoff); - - - iCoff = iCoff & 0x3f; - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "New: Chn %d iCoff = 0x%08x\n", i, iCoff); - if (iqCorrNeg == 0x0) - iCoff = 0x40 - iCoff; - - if (qCoff > 15) - qCoff = 15; - else if (qCoff <= -16) - qCoff = 16; - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d : iCoff = 0x%x qCoff = 0x%x\n", - i, iCoff, qCoff); - - REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), - AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF, - iCoff); - REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), - AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF, - qCoff); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "IQ Cal and Correction done for Chain %d\n", - i); - } - } + keyType = REG_READ(ah, AR_KEYTABLE_TYPE(entry)); - REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0), - AR_PHY_TIMING_CTRL4_IQCORR_ENABLE); -} + REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), 0); + REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), AR_KEYTABLE_TYPE_CLR); + REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), 0); + REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), 0); -static void -ath9k_hw_adc_gaincal_calibrate(struct ath_hal *ah, u8 numChains) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, - qEvenMeasOffset; - u32 qGainMismatch, iGainMismatch, val, i; - - for (i = 0; i < numChains; i++) { - iOddMeasOffset = ahp->ah_totalAdcIOddPhase[i]; - iEvenMeasOffset = ahp->ah_totalAdcIEvenPhase[i]; - qOddMeasOffset = ahp->ah_totalAdcQOddPhase[i]; - qEvenMeasOffset = ahp->ah_totalAdcQEvenPhase[i]; - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Starting ADC Gain Cal for Chain %d\n", i); - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_odd_i = 0x%08x\n", i, - iOddMeasOffset); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_even_i = 0x%08x\n", i, - iEvenMeasOffset); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_odd_q = 0x%08x\n", i, - qOddMeasOffset); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_even_q = 0x%08x\n", i, - qEvenMeasOffset); - - if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) { - iGainMismatch = - ((iEvenMeasOffset * 32) / - iOddMeasOffset) & 0x3f; - qGainMismatch = - ((qOddMeasOffset * 32) / - qEvenMeasOffset) & 0x3f; - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d gain_mismatch_i = 0x%08x\n", i, - iGainMismatch); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d gain_mismatch_q = 0x%08x\n", i, - qGainMismatch); - - val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); - val &= 0xfffff000; - val |= (qGainMismatch) | (iGainMismatch << 6); - REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "ADC Gain Cal done for Chain %d\n", i); - } - } + if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) { + u16 micentry = entry + 64; - REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), - REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) | - AR_PHY_NEW_ADC_GAIN_CORR_ENABLE); -} + REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0); -static void -ath9k_hw_adc_dccal_calibrate(struct ath_hal *ah, u8 numChains) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - u32 iOddMeasOffset, iEvenMeasOffset, val, i; - int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch; - const struct hal_percal_data *calData = - ahp->ah_cal_list_curr->calData; - u32 numSamples = - (1 << (calData->calCountMax + 5)) * calData->calNumSamples; - - for (i = 0; i < numChains; i++) { - iOddMeasOffset = ahp->ah_totalAdcDcOffsetIOddPhase[i]; - iEvenMeasOffset = ahp->ah_totalAdcDcOffsetIEvenPhase[i]; - qOddMeasOffset = ahp->ah_totalAdcDcOffsetQOddPhase[i]; - qEvenMeasOffset = ahp->ah_totalAdcDcOffsetQEvenPhase[i]; - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Starting ADC DC Offset Cal for Chain %d\n", i); - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_odd_i = %d\n", i, - iOddMeasOffset); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_even_i = %d\n", i, - iEvenMeasOffset); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_odd_q = %d\n", i, - qOddMeasOffset); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_even_q = %d\n", i, - qEvenMeasOffset); - - iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) / - numSamples) & 0x1ff; - qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) / - numSamples) & 0x1ff; - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d dc_offset_mismatch_i = 0x%08x\n", i, - iDcMismatch); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d dc_offset_mismatch_q = 0x%08x\n", i, - qDcMismatch); - - val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); - val &= 0xc0000fff; - val |= (qDcMismatch << 12) | (iDcMismatch << 21); - REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "ADC DC Offset Cal done for Chain %d\n", i); } - REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), - REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) | - AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE); -} - -bool ath9k_hw_set_txpowerlimit(struct ath_hal *ah, u32 limit) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_channel *chan = ah->ah_curchan; - - ah->ah_powerLimit = min(limit, (u32) MAX_RATE_POWER); - - if (ath9k_hw_set_txpower(ah, &ahp->ah_eeprom, chan, - ath9k_regd_get_ctl(ah, chan), - ath9k_regd_get_antenna_allowed(ah, - chan), - chan->maxRegTxPower * 2, - min((u32) MAX_RATE_POWER, - (u32) ah->ah_powerLimit)) != 0) - return false; + if (ah->ah_curchan == NULL) + return true; return true; } -void -ath9k_hw_get_channel_centers(struct ath_hal *ah, - struct ath9k_channel *chan, - struct chan_centers *centers) +bool ath9k_hw_keysetmac(struct ath_hal *ah, u16 entry, const u8 *mac) { - int8_t extoff; - struct ath_hal_5416 *ahp = AH5416(ah); + u32 macHi, macLo; - if (!IS_CHAN_HT40(chan)) { - centers->ctl_center = centers->ext_center = - centers->synth_center = chan->channel; - return; + if (entry >= ah->ah_caps.keycache_size) { + DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, + "entry %u out of range\n", entry); + return false; } - if ((chan->chanmode == CHANNEL_A_HT40PLUS) || - (chan->chanmode == CHANNEL_G_HT40PLUS)) { - centers->synth_center = - chan->channel + HT40_CHANNEL_CENTER_SHIFT; - extoff = 1; + if (mac != NULL) { + macHi = (mac[5] << 8) | mac[4]; + macLo = (mac[3] << 24) | + (mac[2] << 16) | + (mac[1] << 8) | + mac[0]; + macLo >>= 1; + macLo |= (macHi & 1) << 31; + macHi >>= 1; } else { - centers->synth_center = - chan->channel - HT40_CHANNEL_CENTER_SHIFT; - extoff = -1; + macLo = macHi = 0; } + REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo); + REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | AR_KEYTABLE_VALID); - centers->ctl_center = centers->synth_center - (extoff * - HT40_CHANNEL_CENTER_SHIFT); - centers->ext_center = centers->synth_center + (extoff * - ((ahp-> - ah_extprotspacing - == - ATH9K_HT_EXTPROTSPACING_20) - ? - HT40_CHANNEL_CENTER_SHIFT - : 15)); - + return true; } -void -ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan, - bool *isCalDone) +bool ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry, + const struct ath9k_keyval *k, + const u8 *mac, int xorKey) { + const struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + u32 key0, key1, key2, key3, key4; + u32 keyType; + u32 xorMask = xorKey ? + (ATH9K_KEY_XOR << 24 | ATH9K_KEY_XOR << 16 | ATH9K_KEY_XOR << 8 + | ATH9K_KEY_XOR) : 0; struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_channel *ichan = - ath9k_regd_check_channel(ah, chan); - struct hal_cal_list *currCal = ahp->ah_cal_list_curr; - - *isCalDone = true; - - if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah)) - return; - if (currCal == NULL) - return; - - if (ichan == NULL) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: invalid channel %u/0x%x; no mapping\n", - __func__, chan->channel, chan->channelFlags); - return; + if (entry >= pCap->keycache_size) { + DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, + "entry %u out of range\n", entry); + return false; } - - if (currCal->calState != CAL_DONE) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: Calibration state incorrect, %d\n", - __func__, currCal->calState); - return; + switch (k->kv_type) { + case ATH9K_CIPHER_AES_OCB: + keyType = AR_KEYTABLE_TYPE_AES; + break; + case ATH9K_CIPHER_AES_CCM: + if (!(pCap->hw_caps & ATH9K_HW_CAP_CIPHER_AESCCM)) { + DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, + "AES-CCM not supported by mac rev 0x%x\n", + ah->ah_macRev); + return false; + } + keyType = AR_KEYTABLE_TYPE_CCM; + break; + case ATH9K_CIPHER_TKIP: + keyType = AR_KEYTABLE_TYPE_TKIP; + if (ATH9K_IS_MIC_ENABLED(ah) + && entry + 64 >= pCap->keycache_size) { + DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, + "entry %u inappropriate for TKIP\n", entry); + return false; + } + break; + case ATH9K_CIPHER_WEP: + if (k->kv_len < LEN_WEP40) { + DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, + "WEP key length %u too small\n", k->kv_len); + return false; + } + if (k->kv_len <= LEN_WEP40) + keyType = AR_KEYTABLE_TYPE_40; + else if (k->kv_len <= LEN_WEP104) + keyType = AR_KEYTABLE_TYPE_104; + else + keyType = AR_KEYTABLE_TYPE_128; + break; + case ATH9K_CIPHER_CLR: + keyType = AR_KEYTABLE_TYPE_CLR; + break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, + "cipher %u not supported\n", k->kv_type); + return false; } + key0 = get_unaligned_le32(k->kv_val + 0) ^ xorMask; + key1 = (get_unaligned_le16(k->kv_val + 4) ^ xorMask) & 0xffff; + key2 = get_unaligned_le32(k->kv_val + 6) ^ xorMask; + key3 = (get_unaligned_le16(k->kv_val + 10) ^ xorMask) & 0xffff; + key4 = get_unaligned_le32(k->kv_val + 12) ^ xorMask; + if (k->kv_len <= LEN_WEP104) + key4 &= 0xff; - if (!ath9k_hw_iscal_supported(ah, chan, currCal->calData->calType)) - return; - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: Resetting Cal %d state for channel %u/0x%x\n", - __func__, currCal->calData->calType, chan->channel, - chan->channelFlags); - - ichan->CalValid &= ~currCal->calData->calType; - currCal->calState = CAL_WAITING; - - *isCalDone = false; -} - -void ath9k_hw_getmac(struct ath_hal *ah, u8 *mac) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - - memcpy(mac, ahp->ah_macaddr, ETH_ALEN); -} + if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) { + u16 micentry = entry + 64; -bool ath9k_hw_setmac(struct ath_hal *ah, const u8 *mac) -{ - struct ath_hal_5416 *ahp = AH5416(ah); + REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0); + REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1); + REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2); + REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3); + REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); + REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); + (void) ath9k_hw_keysetmac(ah, entry, mac); - memcpy(ahp->ah_macaddr, mac, ETH_ALEN); - return true; -} + if (ahp->ah_miscMode & AR_PCU_MIC_NEW_LOC_ENA) { + u32 mic0, mic1, mic2, mic3, mic4; -void ath9k_hw_getbssidmask(struct ath_hal *ah, u8 *mask) -{ - struct ath_hal_5416 *ahp = AH5416(ah); + mic0 = get_unaligned_le32(k->kv_mic + 0); + mic2 = get_unaligned_le32(k->kv_mic + 4); + mic1 = get_unaligned_le16(k->kv_txmic + 2) & 0xffff; + mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff; + mic4 = get_unaligned_le32(k->kv_txmic + 4); + REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); + REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1); + REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2); + REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), mic3); + REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), mic4); + REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), + AR_KEYTABLE_TYPE_CLR); - memcpy(mask, ahp->ah_bssidmask, ETH_ALEN); -} + } else { + u32 mic0, mic2; -bool -ath9k_hw_setbssidmask(struct ath_hal *ah, const u8 *mask) -{ - struct ath_hal_5416 *ahp = AH5416(ah); + mic0 = get_unaligned_le32(k->kv_mic + 0); + mic2 = get_unaligned_le32(k->kv_mic + 4); + REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); + REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2); + REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0); + REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), + AR_KEYTABLE_TYPE_CLR); + } + REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0); + REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); + REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); + } else { + REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); + REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); + REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2); + REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3); + REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); + REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); - memcpy(ahp->ah_bssidmask, mask, ETH_ALEN); + (void) ath9k_hw_keysetmac(ah, entry, mac); + } - REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(ahp->ah_bssidmask)); - REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(ahp->ah_bssidmask + 4)); + if (ah->ah_curchan == NULL) + return true; return true; } -void -ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid, - u16 assocId) +bool ath9k_hw_keyisvalid(struct ath_hal *ah, u16 entry) { - struct ath_hal_5416 *ahp = AH5416(ah); - - memcpy(ahp->ah_bssid, bssid, ETH_ALEN); - ahp->ah_assocId = assocId; - - REG_WRITE(ah, AR_BSS_ID0, get_unaligned_le32(ahp->ah_bssid)); - REG_WRITE(ah, AR_BSS_ID1, get_unaligned_le16(ahp->ah_bssid + 4) | - ((assocId & 0x3fff) << AR_BSS_ID1_AID_S)); + if (entry < ah->ah_caps.keycache_size) { + u32 val = REG_READ(ah, AR_KEYTABLE_MAC1(entry)); + if (val & AR_KEYTABLE_VALID) + return true; + } + return false; } -u64 ath9k_hw_gettsf64(struct ath_hal *ah) +/******************************/ +/* Power Management (Chipset) */ +/******************************/ + +static void ath9k_set_power_sleep(struct ath_hal *ah, int setChip) { - u64 tsf; + REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); + if (setChip) { + REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, + AR_RTC_FORCE_WAKE_EN); + if (!AR_SREV_9100(ah)) + REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF); - tsf = REG_READ(ah, AR_TSF_U32); - tsf = (tsf << 32) | REG_READ(ah, AR_TSF_L32); - return tsf; + REG_CLR_BIT(ah, (u16) (AR_RTC_RESET), + AR_RTC_RESET_EN); + } } -void ath9k_hw_reset_tsf(struct ath_hal *ah) +static void ath9k_set_power_network_sleep(struct ath_hal *ah, int setChip) { - int count; + REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); + if (setChip) { + struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - count = 0; - while (REG_READ(ah, AR_SLP32_MODE) & AR_SLP32_TSF_WRITE_STATUS) { - count++; - if (count > 10) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s: AR_SLP32_TSF_WRITE_STATUS limit exceeded\n", - __func__); - break; + if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { + REG_WRITE(ah, AR_RTC_FORCE_WAKE, + AR_RTC_FORCE_WAKE_ON_INT); + } else { + REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, + AR_RTC_FORCE_WAKE_EN); } - udelay(10); } - REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE); -} - -u32 ath9k_hw_getdefantenna(struct ath_hal *ah) -{ - return REG_READ(ah, AR_DEF_ANTENNA) & 0x7; } -void ath9k_hw_setantenna(struct ath_hal *ah, u32 antenna) +static bool ath9k_hw_set_power_awake(struct ath_hal *ah, + int setChip) { - REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7)); -} + u32 val; + int i; -bool -ath9k_hw_setantennaswitch(struct ath_hal *ah, - enum ath9k_ant_setting settings, - struct ath9k_channel *chan, - u8 *tx_chainmask, - u8 *rx_chainmask, - u8 *antenna_cfgd) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - static u8 tx_chainmask_cfg, rx_chainmask_cfg; + if (setChip) { + if ((REG_READ(ah, AR_RTC_STATUS) & + AR_RTC_STATUS_M) == AR_RTC_STATUS_SHUTDOWN) { + if (ath9k_hw_set_reset_reg(ah, + ATH9K_RESET_POWER_ON) != true) { + return false; + } + } + if (AR_SREV_9100(ah)) + REG_SET_BIT(ah, AR_RTC_RESET, + AR_RTC_RESET_EN); - if (AR_SREV_9280(ah)) { - if (!tx_chainmask_cfg) { + REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, + AR_RTC_FORCE_WAKE_EN); + udelay(50); - tx_chainmask_cfg = *tx_chainmask; - rx_chainmask_cfg = *rx_chainmask; + for (i = POWER_UP_TIME / 50; i > 0; i--) { + val = REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M; + if (val == AR_RTC_STATUS_ON) + break; + udelay(50); + REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, + AR_RTC_FORCE_WAKE_EN); } - - switch (settings) { - case ATH9K_ANT_FIXED_A: - *tx_chainmask = ATH9K_ANTENNA0_CHAINMASK; - *rx_chainmask = ATH9K_ANTENNA0_CHAINMASK; - *antenna_cfgd = true; - break; - case ATH9K_ANT_FIXED_B: - if (ah->ah_caps.tx_chainmask > - ATH9K_ANTENNA1_CHAINMASK) { - *tx_chainmask = ATH9K_ANTENNA1_CHAINMASK; - } - *rx_chainmask = ATH9K_ANTENNA1_CHAINMASK; - *antenna_cfgd = true; - break; - case ATH9K_ANT_VARIABLE: - *tx_chainmask = tx_chainmask_cfg; - *rx_chainmask = rx_chainmask_cfg; - *antenna_cfgd = true; - break; - default: - break; + if (i == 0) { + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + "Failed to wakeup in %uus\n", POWER_UP_TIME / 20); + return false; } - } else { - ahp->ah_diversityControl = settings; } - return true; -} + REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); -void ath9k_hw_setopmode(struct ath_hal *ah) -{ - ath9k_hw_set_operating_mode(ah, ah->ah_opmode); + return true; } -bool -ath9k_hw_getcapability(struct ath_hal *ah, enum ath9k_capability_type type, - u32 capability, u32 *result) +bool ath9k_hw_setpower(struct ath_hal *ah, + enum ath9k_power_mode mode) { struct ath_hal_5416 *ahp = AH5416(ah); - const struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + static const char *modes[] = { + "AWAKE", + "FULL-SLEEP", + "NETWORK SLEEP", + "UNDEFINED" + }; + int status = true, setChip = true; - switch (type) { - case ATH9K_CAP_CIPHER: - switch (capability) { - case ATH9K_CIPHER_AES_CCM: - case ATH9K_CIPHER_AES_OCB: - case ATH9K_CIPHER_TKIP: - case ATH9K_CIPHER_WEP: - case ATH9K_CIPHER_MIC: - case ATH9K_CIPHER_CLR: - return true; - default: - return false; - } - case ATH9K_CAP_TKIP_MIC: - switch (capability) { - case 0: - return true; - case 1: - return (ahp->ah_staId1Defaults & - AR_STA_ID1_CRPT_MIC_ENABLE) ? true : - false; - } - case ATH9K_CAP_TKIP_SPLIT: - return (ahp->ah_miscMode & AR_PCU_MIC_NEW_LOC_ENA) ? - false : true; - case ATH9K_CAP_WME_TKIPMIC: - return 0; - case ATH9K_CAP_PHYCOUNTERS: - return ahp->ah_hasHwPhyCounters ? 0 : -ENXIO; - case ATH9K_CAP_DIVERSITY: - return (REG_READ(ah, AR_PHY_CCK_DETECT) & - AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV) ? - true : false; - case ATH9K_CAP_PHYDIAG: - return true; - case ATH9K_CAP_MCAST_KEYSRCH: - switch (capability) { - case 0: - return true; - case 1: - if (REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_ADHOC) { - return false; - } else { - return (ahp->ah_staId1Defaults & - AR_STA_ID1_MCAST_KSRCH) ? true : - false; - } - } - return false; - case ATH9K_CAP_TSF_ADJUST: - return (ahp->ah_miscMode & AR_PCU_TX_ADD_TSF) ? - true : false; - case ATH9K_CAP_RFSILENT: - if (capability == 3) - return false; - case ATH9K_CAP_ANT_CFG_2GHZ: - *result = pCap->num_antcfg_2ghz; - return true; - case ATH9K_CAP_ANT_CFG_5GHZ: - *result = pCap->num_antcfg_5ghz; - return true; - case ATH9K_CAP_TXPOW: - switch (capability) { - case 0: - return 0; - case 1: - *result = ah->ah_powerLimit; - return 0; - case 2: - *result = ah->ah_maxPowerLevel; - return 0; - case 3: - *result = ah->ah_tpScale; - return 0; - } - return false; + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, "%s -> %s (%s)\n", + modes[ahp->ah_powerMode], modes[mode], + setChip ? "set chip " : ""); + + switch (mode) { + case ATH9K_PM_AWAKE: + status = ath9k_hw_set_power_awake(ah, setChip); + break; + case ATH9K_PM_FULL_SLEEP: + ath9k_set_power_sleep(ah, setChip); + ahp->ah_chipFullSleep = true; + break; + case ATH9K_PM_NETWORK_SLEEP: + ath9k_set_power_network_sleep(ah, setChip); + break; default: + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + "Unknown power mode %u\n", mode); return false; } + ahp->ah_powerMode = mode; + + return status; } -int -ath9k_hw_select_antconfig(struct ath_hal *ah, u32 cfg) +void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore) { struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_channel *chan = ah->ah_curchan; - const struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - u16 ant_config; - u32 halNumAntConfig; + u8 i; + + if (ah->ah_isPciExpress != true) + return; + + if (ah->ah_config.pcie_powersave_enable == 2) + return; - halNumAntConfig = - IS_CHAN_2GHZ(chan) ? pCap->num_antcfg_2ghz : pCap-> - num_antcfg_5ghz; + if (restore) + return; - if (cfg < halNumAntConfig) { - if (!ath9k_hw_get_eeprom_antenna_cfg(ahp, chan, - cfg, &ant_config)) { - REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config); - return 0; + if (AR_SREV_9280_20_OR_LATER(ah)) { + for (i = 0; i < ahp->ah_iniPcieSerdes.ia_rows; i++) { + REG_WRITE(ah, INI_RA(&ahp->ah_iniPcieSerdes, i, 0), + INI_RA(&ahp->ah_iniPcieSerdes, i, 1)); } + udelay(1000); + } else if (AR_SREV_9280(ah) && + (ah->ah_macRev == AR_SREV_REVISION_9280_10)) { + REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fd00); + REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924); + + REG_WRITE(ah, AR_PCIE_SERDES, 0xa8000019); + REG_WRITE(ah, AR_PCIE_SERDES, 0x13160820); + REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980560); + + if (ah->ah_config.pcie_clock_req) + REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffc); + else + REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffd); + + REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40); + REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554); + REG_WRITE(ah, AR_PCIE_SERDES, 0x00043007); + + REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); + + udelay(1000); + } else { + REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00); + REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924); + REG_WRITE(ah, AR_PCIE_SERDES, 0x28000039); + REG_WRITE(ah, AR_PCIE_SERDES, 0x53160824); + REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980579); + REG_WRITE(ah, AR_PCIE_SERDES, 0x001defff); + REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40); + REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554); + REG_WRITE(ah, AR_PCIE_SERDES, 0x000e3007); + REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); + } + + REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA); + + if (ah->ah_config.pcie_waen) { + REG_WRITE(ah, AR_WA, ah->ah_config.pcie_waen); + } else { + if (AR_SREV_9285(ah)) + REG_WRITE(ah, AR_WA, AR9285_WA_DEFAULT); + else if (AR_SREV_9280(ah)) + REG_WRITE(ah, AR_WA, AR9280_WA_DEFAULT); + else + REG_WRITE(ah, AR_WA, AR_WA_DEFAULT); } - return -EINVAL; } +/**********************/ +/* Interrupt Handling */ +/**********************/ + bool ath9k_hw_intrpend(struct ath_hal *ah) { u32 host_isr; @@ -6791,6 +2857,7 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked) struct ath9k_hw_capabilities *pCap = &ah->ah_caps; u32 sync_cause = 0; bool fatal_int = false; + struct ath_hal_5416 *ahp = AH5416(ah); if (!AR_SREV_9100(ah)) { if (REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) { @@ -6800,9 +2867,8 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked) } } - sync_cause = - REG_READ(ah, - AR_INTR_SYNC_CAUSE) & AR_INTR_SYNC_DEFAULT; + sync_cause = REG_READ(ah, AR_INTR_SYNC_CAUSE) & + AR_INTR_SYNC_DEFAULT; *masked = 0; @@ -6814,8 +2880,6 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked) } if (isr) { - struct ath_hal_5416 *ahp = AH5416(ah); - if (isr & AR_ISR_BCNMISC) { u32 isr2; isr2 = REG_READ(ah, AR_ISR_S2); @@ -6842,7 +2906,6 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked) *masked = isr & ATH9K_INT_COMMON; if (ahp->ah_intrMitigation) { - if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM)) *masked |= ATH9K_INT_RX; } @@ -6867,8 +2930,7 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked) if (isr & AR_ISR_RXORN) { DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, - "%s: receive FIFO overrun interrupt\n", - __func__); + "receive FIFO overrun interrupt\n"); } if (!AR_SREV_9100(ah)) { @@ -6881,8 +2943,10 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked) *masked |= mask2; } + if (AR_SREV_9100(ah)) return true; + if (sync_cause) { fatal_int = (sync_cause & @@ -6892,32 +2956,29 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked) if (fatal_int) { if (sync_cause & AR_INTR_SYNC_HOST1_FATAL) { DPRINTF(ah->ah_sc, ATH_DBG_ANY, - "%s: received PCI FATAL interrupt\n", - __func__); + "received PCI FATAL interrupt\n"); } if (sync_cause & AR_INTR_SYNC_HOST1_PERR) { DPRINTF(ah->ah_sc, ATH_DBG_ANY, - "%s: received PCI PERR interrupt\n", - __func__); + "received PCI PERR interrupt\n"); } } if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) { DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, - "%s: AR_INTR_SYNC_RADM_CPL_TIMEOUT\n", - __func__); + "AR_INTR_SYNC_RADM_CPL_TIMEOUT\n"); REG_WRITE(ah, AR_RC, AR_RC_HOSTIF); REG_WRITE(ah, AR_RC, 0); *masked |= ATH9K_INT_FATAL; } if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT) { DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, - "%s: AR_INTR_SYNC_LOCAL_TIMEOUT\n", - __func__); + "AR_INTR_SYNC_LOCAL_TIMEOUT\n"); } REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause); (void) REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR); } + return true; } @@ -6933,12 +2994,10 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints) u32 mask, mask2; struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "%s: 0x%x => 0x%x\n", __func__, - omask, ints); + DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints); if (omask & ATH9K_INT_GLOBAL) { - DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "%s: disable IER\n", - __func__); + DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "disable IER\n"); REG_WRITE(ah, AR_IER, AR_IER_DISABLE); (void) REG_READ(ah, AR_IER); if (!AR_SREV_9100(ah)) { @@ -6993,8 +3052,7 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints) mask2 |= AR_IMR_S2_CST; } - DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "%s: new IMR 0x%x\n", __func__, - mask); + DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "new IMR 0x%x\n", mask); REG_WRITE(ah, AR_IMR, mask); mask = REG_READ(ah, AR_IMR_S2) & ~(AR_IMR_S2_TIM | AR_IMR_S2_DTIM | @@ -7014,8 +3072,7 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints) } if (ints & ATH9K_INT_GLOBAL) { - DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "%s: enable IER\n", - __func__); + DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "enable IER\n"); REG_WRITE(ah, AR_IER, AR_IER_ENABLE); if (!AR_SREV_9100(ah)) { REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, @@ -7035,9 +3092,11 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints) return omask; } -void -ath9k_hw_beaconinit(struct ath_hal *ah, - u32 next_beacon, u32 beacon_period) +/*******************/ +/* Beacon Handling */ +/*******************/ + +void ath9k_hw_beaconinit(struct ath_hal *ah, u32 next_beacon, u32 beacon_period) { struct ath_hal_5416 *ahp = AH5416(ah); int flags = 0; @@ -7045,14 +3104,14 @@ ath9k_hw_beaconinit(struct ath_hal *ah, ahp->ah_beaconInterval = beacon_period; switch (ah->ah_opmode) { - case ATH9K_M_STA: - case ATH9K_M_MONITOR: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_MONITOR: REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(next_beacon)); REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, 0xffff); REG_WRITE(ah, AR_NEXT_SWBA, 0x7ffff); flags |= AR_TBTT_TIMER_EN; break; - case ATH9K_M_IBSS: + case NL80211_IFTYPE_ADHOC: REG_SET_BIT(ah, AR_TXCFG, AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY); REG_WRITE(ah, AR_NEXT_NDP_TIMER, @@ -7060,7 +3119,7 @@ ath9k_hw_beaconinit(struct ath_hal *ah, (ahp->ah_atimWindow ? ahp-> ah_atimWindow : 1))); flags |= AR_NDP_TIMER_EN; - case ATH9K_M_HOSTAP: + case NL80211_IFTYPE_AP: REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(next_beacon)); REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, TU_TO_USEC(next_beacon - @@ -7073,6 +3132,12 @@ ath9k_hw_beaconinit(struct ath_hal *ah, flags |= AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN; break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_BEACON, + "%s: unsupported opmode: %d\n", + __func__, ah->ah_opmode); + return; + break; } REG_WRITE(ah, AR_BEACON_PERIOD, TU_TO_USEC(beacon_period)); @@ -7089,9 +3154,8 @@ ath9k_hw_beaconinit(struct ath_hal *ah, REG_SET_BIT(ah, AR_TIMER_MODE, flags); } -void -ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah, - const struct ath9k_beacon_state *bs) +void ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah, + const struct ath9k_beacon_state *bs) { u32 nextTbtt, beaconintval, dtimperiod, beacontimeout; struct ath9k_hw_capabilities *pCap = &ah->ah_caps; @@ -7120,14 +3184,10 @@ ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah, else nextTbtt = bs->bs_nexttbtt; - DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "%s: next DTIM %d\n", __func__, - bs->bs_nextdtim); - DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "%s: next beacon %d\n", __func__, - nextTbtt); - DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "%s: beacon period %d\n", __func__, - beaconintval); - DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "%s: DTIM period %d\n", __func__, - dtimperiod); + DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "next DTIM %d\n", bs->bs_nextdtim); + DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "next beacon %d\n", nextTbtt); + DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "beacon period %d\n", beaconintval); + DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "DTIM period %d\n", dtimperiod); REG_WRITE(ah, AR_NEXT_DTIM, TU_TO_USEC(bs->bs_nextdtim - SLEEP_SLOP)); @@ -7137,1327 +3197,661 @@ ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah, SM((CAB_TIMEOUT_VAL << 3), AR_SLEEP1_CAB_TIMEOUT) | AR_SLEEP1_ASSUME_DTIM); - if (pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP) - beacontimeout = (BEACON_TIMEOUT_VAL << 3); - else - beacontimeout = MIN_BEACON_TIMEOUT_VAL; - - REG_WRITE(ah, AR_SLEEP2, - SM(beacontimeout, AR_SLEEP2_BEACON_TIMEOUT)); - - REG_WRITE(ah, AR_TIM_PERIOD, TU_TO_USEC(beaconintval)); - REG_WRITE(ah, AR_DTIM_PERIOD, TU_TO_USEC(dtimperiod)); - - REG_SET_BIT(ah, AR_TIMER_MODE, - AR_TBTT_TIMER_EN | AR_TIM_TIMER_EN | - AR_DTIM_TIMER_EN); - -} - -bool ath9k_hw_keyisvalid(struct ath_hal *ah, u16 entry) -{ - if (entry < ah->ah_caps.keycache_size) { - u32 val = REG_READ(ah, AR_KEYTABLE_MAC1(entry)); - if (val & AR_KEYTABLE_VALID) - return true; - } - return false; -} - -bool ath9k_hw_keyreset(struct ath_hal *ah, u16 entry) -{ - u32 keyType; - - if (entry >= ah->ah_caps.keycache_size) { - DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, - "%s: entry %u out of range\n", __func__, entry); - return false; - } - keyType = REG_READ(ah, AR_KEYTABLE_TYPE(entry)); - - REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0); - REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0); - REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0); - REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), 0); - REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), 0); - REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), AR_KEYTABLE_TYPE_CLR); - REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), 0); - REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), 0); - - if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) { - u16 micentry = entry + 64; - - REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), 0); - REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0); - REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), 0); - REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0); - - } - - if (ah->ah_curchan == NULL) - return true; - - return true; -} - -bool -ath9k_hw_keysetmac(struct ath_hal *ah, u16 entry, - const u8 *mac) -{ - u32 macHi, macLo; - - if (entry >= ah->ah_caps.keycache_size) { - DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, - "%s: entry %u out of range\n", __func__, entry); - return false; - } - - if (mac != NULL) { - macHi = (mac[5] << 8) | mac[4]; - macLo = (mac[3] << 24) | (mac[2] << 16) - | (mac[1] << 8) | mac[0]; - macLo >>= 1; - macLo |= (macHi & 1) << 31; - macHi >>= 1; - } else { - macLo = macHi = 0; - } - REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo); - REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | AR_KEYTABLE_VALID); - - return true; -} - -bool -ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry, - const struct ath9k_keyval *k, - const u8 *mac, int xorKey) -{ - const struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - u32 key0, key1, key2, key3, key4; - u32 keyType; - u32 xorMask = xorKey ? - (ATH9K_KEY_XOR << 24 | ATH9K_KEY_XOR << 16 | ATH9K_KEY_XOR << 8 - | ATH9K_KEY_XOR) : 0; - struct ath_hal_5416 *ahp = AH5416(ah); - - if (entry >= pCap->keycache_size) { - DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, - "%s: entry %u out of range\n", __func__, entry); - return false; - } - switch (k->kv_type) { - case ATH9K_CIPHER_AES_OCB: - keyType = AR_KEYTABLE_TYPE_AES; - break; - case ATH9K_CIPHER_AES_CCM: - if (!(pCap->hw_caps & ATH9K_HW_CAP_CIPHER_AESCCM)) { - DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, - "%s: AES-CCM not supported by " - "mac rev 0x%x\n", __func__, - ah->ah_macRev); - return false; - } - keyType = AR_KEYTABLE_TYPE_CCM; - break; - case ATH9K_CIPHER_TKIP: - keyType = AR_KEYTABLE_TYPE_TKIP; - if (ATH9K_IS_MIC_ENABLED(ah) - && entry + 64 >= pCap->keycache_size) { - DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, - "%s: entry %u inappropriate for TKIP\n", - __func__, entry); - return false; - } - break; - case ATH9K_CIPHER_WEP: - if (k->kv_len < LEN_WEP40) { - DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, - "%s: WEP key length %u too small\n", - __func__, k->kv_len); - return false; - } - if (k->kv_len <= LEN_WEP40) - keyType = AR_KEYTABLE_TYPE_40; - else if (k->kv_len <= LEN_WEP104) - keyType = AR_KEYTABLE_TYPE_104; - else - keyType = AR_KEYTABLE_TYPE_128; - break; - case ATH9K_CIPHER_CLR: - keyType = AR_KEYTABLE_TYPE_CLR; - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, - "%s: cipher %u not supported\n", __func__, - k->kv_type); - return false; - } - - key0 = get_unaligned_le32(k->kv_val + 0) ^ xorMask; - key1 = (get_unaligned_le16(k->kv_val + 4) ^ xorMask) & 0xffff; - key2 = get_unaligned_le32(k->kv_val + 6) ^ xorMask; - key3 = (get_unaligned_le16(k->kv_val + 10) ^ xorMask) & 0xffff; - key4 = get_unaligned_le32(k->kv_val + 12) ^ xorMask; - if (k->kv_len <= LEN_WEP104) - key4 &= 0xff; - - if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) { - u16 micentry = entry + 64; - - REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0); - REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1); - REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2); - REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3); - REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); - REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); - (void) ath9k_hw_keysetmac(ah, entry, mac); - - if (ahp->ah_miscMode & AR_PCU_MIC_NEW_LOC_ENA) { - u32 mic0, mic1, mic2, mic3, mic4; - - mic0 = get_unaligned_le32(k->kv_mic + 0); - mic2 = get_unaligned_le32(k->kv_mic + 4); - mic1 = get_unaligned_le16(k->kv_txmic + 2) & 0xffff; - mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff; - mic4 = get_unaligned_le32(k->kv_txmic + 4); - REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); - REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1); - REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2); - REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), mic3); - REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), mic4); - REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), - AR_KEYTABLE_TYPE_CLR); - - } else { - u32 mic0, mic2; - - mic0 = get_unaligned_le32(k->kv_mic + 0); - mic2 = get_unaligned_le32(k->kv_mic + 4); - REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); - REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0); - REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2); - REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0); - REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0); - REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), - AR_KEYTABLE_TYPE_CLR); - } - REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0); - REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0); - REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); - REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); - } else { - REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); - REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); - REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2); - REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3); - REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); - REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); + if (pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP) + beacontimeout = (BEACON_TIMEOUT_VAL << 3); + else + beacontimeout = MIN_BEACON_TIMEOUT_VAL; - (void) ath9k_hw_keysetmac(ah, entry, mac); - } + REG_WRITE(ah, AR_SLEEP2, + SM(beacontimeout, AR_SLEEP2_BEACON_TIMEOUT)); - if (ah->ah_curchan == NULL) - return true; + REG_WRITE(ah, AR_TIM_PERIOD, TU_TO_USEC(beaconintval)); + REG_WRITE(ah, AR_DTIM_PERIOD, TU_TO_USEC(dtimperiod)); + + REG_SET_BIT(ah, AR_TIMER_MODE, + AR_TBTT_TIMER_EN | AR_TIM_TIMER_EN | + AR_DTIM_TIMER_EN); - return true; } -bool -ath9k_hw_updatetxtriglevel(struct ath_hal *ah, bool bIncTrigLevel) +/*******************/ +/* HW Capabilities */ +/*******************/ + +bool ath9k_hw_fill_cap_info(struct ath_hal *ah) { struct ath_hal_5416 *ahp = AH5416(ah); - u32 txcfg, curLevel, newLevel; - enum ath9k_int omask; + struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + u16 capField = 0, eeval; - if (ah->ah_txTrigLevel >= MAX_TX_FIFO_THRESHOLD) - return false; + eeval = ath9k_hw_get_eeprom(ah, EEP_REG_0); - omask = ath9k_hw_set_interrupts(ah, - ahp->ah_maskReg & ~ATH9K_INT_GLOBAL); + ah->ah_currentRD = eeval; - txcfg = REG_READ(ah, AR_TXCFG); - curLevel = MS(txcfg, AR_FTRIG); - newLevel = curLevel; - if (bIncTrigLevel) { - if (curLevel < MAX_TX_FIFO_THRESHOLD) - newLevel++; - } else if (curLevel > MIN_TX_FIFO_THRESHOLD) - newLevel--; - if (newLevel != curLevel) - REG_WRITE(ah, AR_TXCFG, - (txcfg & ~AR_FTRIG) | SM(newLevel, AR_FTRIG)); + eeval = ath9k_hw_get_eeprom(ah, EEP_REG_1); + ah->ah_currentRDExt = eeval; - ath9k_hw_set_interrupts(ah, omask); + capField = ath9k_hw_get_eeprom(ah, EEP_OP_CAP); - ah->ah_txTrigLevel = newLevel; + if (ah->ah_opmode != NL80211_IFTYPE_AP && + ah->ah_subvendorid == AR_SUBVENDOR_ID_NEW_A) { + if (ah->ah_currentRD == 0x64 || ah->ah_currentRD == 0x65) + ah->ah_currentRD += 5; + else if (ah->ah_currentRD == 0x41) + ah->ah_currentRD = 0x43; + DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, + "regdomain mapped to 0x%x\n", ah->ah_currentRD); + } - return newLevel != curLevel; -} + eeval = ath9k_hw_get_eeprom(ah, EEP_OP_MODE); + bitmap_zero(pCap->wireless_modes, ATH9K_MODE_MAX); -bool ath9k_hw_set_txq_props(struct ath_hal *ah, int q, - const struct ath9k_tx_queue_info *qinfo) -{ - u32 cw; - struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - struct ath9k_tx_queue_info *qi; + if (eeval & AR5416_OPFLAGS_11A) { + set_bit(ATH9K_MODE_11A, pCap->wireless_modes); + if (ah->ah_config.ht_enable) { + if (!(eeval & AR5416_OPFLAGS_N_5G_HT20)) + set_bit(ATH9K_MODE_11NA_HT20, + pCap->wireless_modes); + if (!(eeval & AR5416_OPFLAGS_N_5G_HT40)) { + set_bit(ATH9K_MODE_11NA_HT40PLUS, + pCap->wireless_modes); + set_bit(ATH9K_MODE_11NA_HT40MINUS, + pCap->wireless_modes); + } + } + } - if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n", - __func__, q); - return false; + if (eeval & AR5416_OPFLAGS_11G) { + set_bit(ATH9K_MODE_11B, pCap->wireless_modes); + set_bit(ATH9K_MODE_11G, pCap->wireless_modes); + if (ah->ah_config.ht_enable) { + if (!(eeval & AR5416_OPFLAGS_N_2G_HT20)) + set_bit(ATH9K_MODE_11NG_HT20, + pCap->wireless_modes); + if (!(eeval & AR5416_OPFLAGS_N_2G_HT40)) { + set_bit(ATH9K_MODE_11NG_HT40PLUS, + pCap->wireless_modes); + set_bit(ATH9K_MODE_11NG_HT40MINUS, + pCap->wireless_modes); + } + } } - qi = &ahp->ah_txq[q]; - if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue\n", - __func__); - return false; + pCap->tx_chainmask = ath9k_hw_get_eeprom(ah, EEP_TX_MASK); + if ((ah->ah_isPciExpress) + || (eeval & AR5416_OPFLAGS_11A)) { + pCap->rx_chainmask = + ath9k_hw_get_eeprom(ah, EEP_RX_MASK); + } else { + pCap->rx_chainmask = + (ath9k_hw_gpio_get(ah, 0)) ? 0x5 : 0x7; } - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: queue %p\n", __func__, qi); + if (!(AR_SREV_9280(ah) && (ah->ah_macRev == 0))) + ahp->ah_miscMode |= AR_PCU_MIC_NEW_LOC_ENA; + + pCap->low_2ghz_chan = 2312; + pCap->high_2ghz_chan = 2732; + + pCap->low_5ghz_chan = 4920; + pCap->high_5ghz_chan = 6100; + + pCap->hw_caps &= ~ATH9K_HW_CAP_CIPHER_CKIP; + pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_TKIP; + pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_AESCCM; + + pCap->hw_caps &= ~ATH9K_HW_CAP_MIC_CKIP; + pCap->hw_caps |= ATH9K_HW_CAP_MIC_TKIP; + pCap->hw_caps |= ATH9K_HW_CAP_MIC_AESCCM; + + pCap->hw_caps |= ATH9K_HW_CAP_CHAN_SPREAD; - qi->tqi_ver = qinfo->tqi_ver; - qi->tqi_subtype = qinfo->tqi_subtype; - qi->tqi_qflags = qinfo->tqi_qflags; - qi->tqi_priority = qinfo->tqi_priority; - if (qinfo->tqi_aifs != ATH9K_TXQ_USEDEFAULT) - qi->tqi_aifs = min(qinfo->tqi_aifs, 255U); + if (ah->ah_config.ht_enable) + pCap->hw_caps |= ATH9K_HW_CAP_HT; else - qi->tqi_aifs = INIT_AIFS; - if (qinfo->tqi_cwmin != ATH9K_TXQ_USEDEFAULT) { - cw = min(qinfo->tqi_cwmin, 1024U); - qi->tqi_cwmin = 1; - while (qi->tqi_cwmin < cw) - qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1; - } else - qi->tqi_cwmin = qinfo->tqi_cwmin; - if (qinfo->tqi_cwmax != ATH9K_TXQ_USEDEFAULT) { - cw = min(qinfo->tqi_cwmax, 1024U); - qi->tqi_cwmax = 1; - while (qi->tqi_cwmax < cw) - qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1; - } else - qi->tqi_cwmax = INIT_CWMAX; + pCap->hw_caps &= ~ATH9K_HW_CAP_HT; + + pCap->hw_caps |= ATH9K_HW_CAP_GTT; + pCap->hw_caps |= ATH9K_HW_CAP_VEOL; + pCap->hw_caps |= ATH9K_HW_CAP_BSSIDMASK; + pCap->hw_caps &= ~ATH9K_HW_CAP_MCAST_KEYSEARCH; - if (qinfo->tqi_shretry != 0) - qi->tqi_shretry = min((u32) qinfo->tqi_shretry, 15U); + if (capField & AR_EEPROM_EEPCAP_MAXQCU) + pCap->total_queues = + MS(capField, AR_EEPROM_EEPCAP_MAXQCU); else - qi->tqi_shretry = INIT_SH_RETRY; - if (qinfo->tqi_lgretry != 0) - qi->tqi_lgretry = min((u32) qinfo->tqi_lgretry, 15U); + pCap->total_queues = ATH9K_NUM_TX_QUEUES; + + if (capField & AR_EEPROM_EEPCAP_KC_ENTRIES) + pCap->keycache_size = + 1 << MS(capField, AR_EEPROM_EEPCAP_KC_ENTRIES); else - qi->tqi_lgretry = INIT_LG_RETRY; - qi->tqi_cbrPeriod = qinfo->tqi_cbrPeriod; - qi->tqi_cbrOverflowLimit = qinfo->tqi_cbrOverflowLimit; - qi->tqi_burstTime = qinfo->tqi_burstTime; - qi->tqi_readyTime = qinfo->tqi_readyTime; - - switch (qinfo->tqi_subtype) { - case ATH9K_WME_UPSD: - if (qi->tqi_type == ATH9K_TX_QUEUE_DATA) - qi->tqi_intFlags = ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS; - break; - default: - break; - } - return true; -} + pCap->keycache_size = AR_KEYTABLE_SIZE; -bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q, - struct ath9k_tx_queue_info *qinfo) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - struct ath9k_tx_queue_info *qi; + pCap->hw_caps |= ATH9K_HW_CAP_FASTCC; + pCap->num_mr_retries = 4; + pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD; - if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n", - __func__, q); - return false; - } + if (AR_SREV_9280_10_OR_LATER(ah)) + pCap->num_gpio_pins = AR928X_NUM_GPIO; + else + pCap->num_gpio_pins = AR_NUM_GPIO; - qi = &ahp->ah_txq[q]; - if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue\n", - __func__); - return false; + if (AR_SREV_9280_10_OR_LATER(ah)) { + pCap->hw_caps |= ATH9K_HW_CAP_WOW; + pCap->hw_caps |= ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT; + } else { + pCap->hw_caps &= ~ATH9K_HW_CAP_WOW; + pCap->hw_caps &= ~ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT; } - qinfo->tqi_qflags = qi->tqi_qflags; - qinfo->tqi_ver = qi->tqi_ver; - qinfo->tqi_subtype = qi->tqi_subtype; - qinfo->tqi_qflags = qi->tqi_qflags; - qinfo->tqi_priority = qi->tqi_priority; - qinfo->tqi_aifs = qi->tqi_aifs; - qinfo->tqi_cwmin = qi->tqi_cwmin; - qinfo->tqi_cwmax = qi->tqi_cwmax; - qinfo->tqi_shretry = qi->tqi_shretry; - qinfo->tqi_lgretry = qi->tqi_lgretry; - qinfo->tqi_cbrPeriod = qi->tqi_cbrPeriod; - qinfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit; - qinfo->tqi_burstTime = qi->tqi_burstTime; - qinfo->tqi_readyTime = qi->tqi_readyTime; + if (AR_SREV_9160_10_OR_LATER(ah) || AR_SREV_9100(ah)) { + pCap->hw_caps |= ATH9K_HW_CAP_CST; + pCap->rts_aggr_limit = ATH_AMPDU_LIMIT_MAX; + } else { + pCap->rts_aggr_limit = (8 * 1024); + } - return true; -} + pCap->hw_caps |= ATH9K_HW_CAP_ENHANCEDPM; -int -ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type, - const struct ath9k_tx_queue_info *qinfo) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_tx_queue_info *qi; - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - int q; +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) + ah->ah_rfsilent = ath9k_hw_get_eeprom(ah, EEP_RF_SILENT); + if (ah->ah_rfsilent & EEP_RFSILENT_ENABLED) { + ah->ah_rfkill_gpio = + MS(ah->ah_rfsilent, EEP_RFSILENT_GPIO_SEL); + ah->ah_rfkill_polarity = + MS(ah->ah_rfsilent, EEP_RFSILENT_POLARITY); - switch (type) { - case ATH9K_TX_QUEUE_BEACON: - q = pCap->total_queues - 1; - break; - case ATH9K_TX_QUEUE_CAB: - q = pCap->total_queues - 2; - break; - case ATH9K_TX_QUEUE_PSPOLL: - q = 1; - break; - case ATH9K_TX_QUEUE_UAPSD: - q = pCap->total_queues - 3; - break; - case ATH9K_TX_QUEUE_DATA: - for (q = 0; q < pCap->total_queues; q++) - if (ahp->ah_txq[q].tqi_type == - ATH9K_TX_QUEUE_INACTIVE) - break; - if (q == pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, - "%s: no available tx queue\n", __func__); - return -1; - } - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: bad tx queue type %u\n", - __func__, type); - return -1; + pCap->hw_caps |= ATH9K_HW_CAP_RFSILENT; } +#endif + + if ((ah->ah_macVersion == AR_SREV_VERSION_5416_PCI) || + (ah->ah_macVersion == AR_SREV_VERSION_5416_PCIE) || + (ah->ah_macVersion == AR_SREV_VERSION_9160) || + (ah->ah_macVersion == AR_SREV_VERSION_9100) || + (ah->ah_macVersion == AR_SREV_VERSION_9280)) + pCap->hw_caps &= ~ATH9K_HW_CAP_AUTOSLEEP; + else + pCap->hw_caps |= ATH9K_HW_CAP_AUTOSLEEP; - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: queue %u\n", __func__, q); + if (AR_SREV_9280(ah) || AR_SREV_9285(ah)) + pCap->hw_caps &= ~ATH9K_HW_CAP_4KB_SPLITTRANS; + else + pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS; - qi = &ahp->ah_txq[q]; - if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, - "%s: tx queue %u already active\n", __func__, q); - return -1; - } - memset(qi, 0, sizeof(struct ath9k_tx_queue_info)); - qi->tqi_type = type; - if (qinfo == NULL) { - qi->tqi_qflags = - TXQ_FLAG_TXOKINT_ENABLE - | TXQ_FLAG_TXERRINT_ENABLE - | TXQ_FLAG_TXDESCINT_ENABLE | TXQ_FLAG_TXURNINT_ENABLE; - qi->tqi_aifs = INIT_AIFS; - qi->tqi_cwmin = ATH9K_TXQ_USEDEFAULT; - qi->tqi_cwmax = INIT_CWMAX; - qi->tqi_shretry = INIT_SH_RETRY; - qi->tqi_lgretry = INIT_LG_RETRY; - qi->tqi_physCompBuf = 0; + if (ah->ah_currentRDExt & (1 << REG_EXT_JAPAN_MIDBAND)) { + pCap->reg_cap = + AR_EEPROM_EEREGCAP_EN_KK_NEW_11A | + AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN | + AR_EEPROM_EEREGCAP_EN_KK_U2 | + AR_EEPROM_EEREGCAP_EN_KK_MIDBAND; } else { - qi->tqi_physCompBuf = qinfo->tqi_physCompBuf; - (void) ath9k_hw_set_txq_props(ah, q, qinfo); + pCap->reg_cap = + AR_EEPROM_EEREGCAP_EN_KK_NEW_11A | + AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN; } - return q; -} + pCap->reg_cap |= AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND; -static void -ath9k_hw_set_txq_interrupts(struct ath_hal *ah, - struct ath9k_tx_queue_info *qi) -{ - struct ath_hal_5416 *ahp = AH5416(ah); + pCap->num_antcfg_5ghz = + ath9k_hw_get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_5GHZ); + pCap->num_antcfg_2ghz = + ath9k_hw_get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_2GHZ); - DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, - "%s: tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n", - __func__, ahp->ah_txOkInterruptMask, - ahp->ah_txErrInterruptMask, ahp->ah_txDescInterruptMask, - ahp->ah_txEolInterruptMask, ahp->ah_txUrnInterruptMask); - - REG_WRITE(ah, AR_IMR_S0, - SM(ahp->ah_txOkInterruptMask, AR_IMR_S0_QCU_TXOK) - | SM(ahp->ah_txDescInterruptMask, AR_IMR_S0_QCU_TXDESC)); - REG_WRITE(ah, AR_IMR_S1, - SM(ahp->ah_txErrInterruptMask, AR_IMR_S1_QCU_TXERR) - | SM(ahp->ah_txEolInterruptMask, AR_IMR_S1_QCU_TXEOL)); - REG_RMW_FIELD(ah, AR_IMR_S2, - AR_IMR_S2_QCU_TXURN, ahp->ah_txUrnInterruptMask); + return true; } -bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q) +bool ath9k_hw_getcapability(struct ath_hal *ah, enum ath9k_capability_type type, + u32 capability, u32 *result) { struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - struct ath9k_tx_queue_info *qi; + const struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n", - __func__, q); + switch (type) { + case ATH9K_CAP_CIPHER: + switch (capability) { + case ATH9K_CIPHER_AES_CCM: + case ATH9K_CIPHER_AES_OCB: + case ATH9K_CIPHER_TKIP: + case ATH9K_CIPHER_WEP: + case ATH9K_CIPHER_MIC: + case ATH9K_CIPHER_CLR: + return true; + default: + return false; + } + case ATH9K_CAP_TKIP_MIC: + switch (capability) { + case 0: + return true; + case 1: + return (ahp->ah_staId1Defaults & + AR_STA_ID1_CRPT_MIC_ENABLE) ? true : + false; + } + case ATH9K_CAP_TKIP_SPLIT: + return (ahp->ah_miscMode & AR_PCU_MIC_NEW_LOC_ENA) ? + false : true; + case ATH9K_CAP_WME_TKIPMIC: + return 0; + case ATH9K_CAP_PHYCOUNTERS: + return ahp->ah_hasHwPhyCounters ? 0 : -ENXIO; + case ATH9K_CAP_DIVERSITY: + return (REG_READ(ah, AR_PHY_CCK_DETECT) & + AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV) ? + true : false; + case ATH9K_CAP_PHYDIAG: + return true; + case ATH9K_CAP_MCAST_KEYSRCH: + switch (capability) { + case 0: + return true; + case 1: + if (REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_ADHOC) { + return false; + } else { + return (ahp->ah_staId1Defaults & + AR_STA_ID1_MCAST_KSRCH) ? true : + false; + } + } + return false; + case ATH9K_CAP_TSF_ADJUST: + return (ahp->ah_miscMode & AR_PCU_TX_ADD_TSF) ? + true : false; + case ATH9K_CAP_RFSILENT: + if (capability == 3) + return false; + case ATH9K_CAP_ANT_CFG_2GHZ: + *result = pCap->num_antcfg_2ghz; + return true; + case ATH9K_CAP_ANT_CFG_5GHZ: + *result = pCap->num_antcfg_5ghz; + return true; + case ATH9K_CAP_TXPOW: + switch (capability) { + case 0: + return 0; + case 1: + *result = ah->ah_powerLimit; + return 0; + case 2: + *result = ah->ah_maxPowerLevel; + return 0; + case 3: + *result = ah->ah_tpScale; + return 0; + } return false; - } - qi = &ahp->ah_txq[q]; - if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue %u\n", - __func__, q); + default: return false; } - - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: release queue %u\n", - __func__, q); - - qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE; - ahp->ah_txOkInterruptMask &= ~(1 << q); - ahp->ah_txErrInterruptMask &= ~(1 << q); - ahp->ah_txDescInterruptMask &= ~(1 << q); - ahp->ah_txEolInterruptMask &= ~(1 << q); - ahp->ah_txUrnInterruptMask &= ~(1 << q); - ath9k_hw_set_txq_interrupts(ah, qi); - - return true; } -bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q) +bool ath9k_hw_setcapability(struct ath_hal *ah, enum ath9k_capability_type type, + u32 capability, u32 setting, int *status) { struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - struct ath9k_channel *chan = ah->ah_curchan; - struct ath9k_tx_queue_info *qi; - u32 cwMin, chanCwMin, value; + u32 v; - if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n", - __func__, q); - return false; - } - qi = &ahp->ah_txq[q]; - if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue %u\n", - __func__, q); + switch (type) { + case ATH9K_CAP_TKIP_MIC: + if (setting) + ahp->ah_staId1Defaults |= + AR_STA_ID1_CRPT_MIC_ENABLE; + else + ahp->ah_staId1Defaults &= + ~AR_STA_ID1_CRPT_MIC_ENABLE; return true; - } - - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: reset queue %u\n", __func__, q); - - if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) { - if (chan && IS_CHAN_B(chan)) - chanCwMin = INIT_CWMIN_11B; + case ATH9K_CAP_DIVERSITY: + v = REG_READ(ah, AR_PHY_CCK_DETECT); + if (setting) + v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; else - chanCwMin = INIT_CWMIN; - - for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1); - } else - cwMin = qi->tqi_cwmin; - - REG_WRITE(ah, AR_DLCL_IFS(q), SM(cwMin, AR_D_LCL_IFS_CWMIN) - | SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX) - | SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS)); - - REG_WRITE(ah, AR_DRETRY_LIMIT(q), - SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH) - | SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG) - | SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH)); - - REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ); - REG_WRITE(ah, AR_DMISC(q), - AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2); - - if (qi->tqi_cbrPeriod) { - REG_WRITE(ah, AR_QCBRCFG(q), - SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) - | SM(qi->tqi_cbrOverflowLimit, - AR_Q_CBRCFG_OVF_THRESH)); - REG_WRITE(ah, AR_QMISC(q), - REG_READ(ah, - AR_QMISC(q)) | AR_Q_MISC_FSP_CBR | (qi-> - tqi_cbrOverflowLimit - ? - AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN - : - 0)); - } - if (qi->tqi_readyTime && (qi->tqi_type != ATH9K_TX_QUEUE_CAB)) { - REG_WRITE(ah, AR_QRDYTIMECFG(q), - SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_DURATION) | - AR_Q_RDYTIMECFG_EN); - } - - REG_WRITE(ah, AR_DCHNTIME(q), - SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) | - (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0)); - - if (qi->tqi_burstTime - && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)) { - REG_WRITE(ah, AR_QMISC(q), - REG_READ(ah, - AR_QMISC(q)) | - AR_Q_MISC_RDYTIME_EXP_POLICY); - - } - - if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE) { - REG_WRITE(ah, AR_DMISC(q), - REG_READ(ah, AR_DMISC(q)) | - AR_D_MISC_POST_FR_BKOFF_DIS); - } - if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) { - REG_WRITE(ah, AR_DMISC(q), - REG_READ(ah, AR_DMISC(q)) | - AR_D_MISC_FRAG_BKOFF_EN); - } - switch (qi->tqi_type) { - case ATH9K_TX_QUEUE_BEACON: - REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q)) - | AR_Q_MISC_FSP_DBA_GATED - | AR_Q_MISC_BEACON_USE - | AR_Q_MISC_CBR_INCR_DIS1); - - REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) - | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << - AR_D_MISC_ARB_LOCKOUT_CNTRL_S) - | AR_D_MISC_BEACON_USE - | AR_D_MISC_POST_FR_BKOFF_DIS); - break; - case ATH9K_TX_QUEUE_CAB: - REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q)) - | AR_Q_MISC_FSP_DBA_GATED - | AR_Q_MISC_CBR_INCR_DIS1 - | AR_Q_MISC_CBR_INCR_DIS0); - value = (qi->tqi_readyTime - - (ah->ah_config.sw_beacon_response_time - - ah->ah_config.dma_beacon_response_time) - - - ah->ah_config.additional_swba_backoff) * - 1024; - REG_WRITE(ah, AR_QRDYTIMECFG(q), - value | AR_Q_RDYTIMECFG_EN); - REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) - | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << - AR_D_MISC_ARB_LOCKOUT_CNTRL_S)); - break; - case ATH9K_TX_QUEUE_PSPOLL: - REG_WRITE(ah, AR_QMISC(q), - REG_READ(ah, - AR_QMISC(q)) | AR_Q_MISC_CBR_INCR_DIS1); - break; - case ATH9K_TX_QUEUE_UAPSD: - REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) - | AR_D_MISC_POST_FR_BKOFF_DIS); - break; + v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; + REG_WRITE(ah, AR_PHY_CCK_DETECT, v); + return true; + case ATH9K_CAP_MCAST_KEYSRCH: + if (setting) + ahp->ah_staId1Defaults |= AR_STA_ID1_MCAST_KSRCH; + else + ahp->ah_staId1Defaults &= ~AR_STA_ID1_MCAST_KSRCH; + return true; + case ATH9K_CAP_TSF_ADJUST: + if (setting) + ahp->ah_miscMode |= AR_PCU_TX_ADD_TSF; + else + ahp->ah_miscMode &= ~AR_PCU_TX_ADD_TSF; + return true; default: - break; + return false; } +} - if (qi->tqi_intFlags & ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS) { - REG_WRITE(ah, AR_DMISC(q), - REG_READ(ah, AR_DMISC(q)) | - SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL, - AR_D_MISC_ARB_LOCKOUT_CNTRL) | - AR_D_MISC_POST_FR_BKOFF_DIS); - } +/****************************/ +/* GPIO / RFKILL / Antennae */ +/****************************/ - if (qi->tqi_qflags & TXQ_FLAG_TXOKINT_ENABLE) - ahp->ah_txOkInterruptMask |= 1 << q; - else - ahp->ah_txOkInterruptMask &= ~(1 << q); - if (qi->tqi_qflags & TXQ_FLAG_TXERRINT_ENABLE) - ahp->ah_txErrInterruptMask |= 1 << q; - else - ahp->ah_txErrInterruptMask &= ~(1 << q); - if (qi->tqi_qflags & TXQ_FLAG_TXDESCINT_ENABLE) - ahp->ah_txDescInterruptMask |= 1 << q; - else - ahp->ah_txDescInterruptMask &= ~(1 << q); - if (qi->tqi_qflags & TXQ_FLAG_TXEOLINT_ENABLE) - ahp->ah_txEolInterruptMask |= 1 << q; - else - ahp->ah_txEolInterruptMask &= ~(1 << q); - if (qi->tqi_qflags & TXQ_FLAG_TXURNINT_ENABLE) - ahp->ah_txUrnInterruptMask |= 1 << q; - else - ahp->ah_txUrnInterruptMask &= ~(1 << q); - ath9k_hw_set_txq_interrupts(ah, qi); +static void ath9k_hw_gpio_cfg_output_mux(struct ath_hal *ah, + u32 gpio, u32 type) +{ + int addr; + u32 gpio_shift, tmp; - return true; -} + if (gpio > 11) + addr = AR_GPIO_OUTPUT_MUX3; + else if (gpio > 5) + addr = AR_GPIO_OUTPUT_MUX2; + else + addr = AR_GPIO_OUTPUT_MUX1; -void ath9k_hw_gettxintrtxqs(struct ath_hal *ah, u32 *txqs) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - *txqs &= ahp->ah_intrTxqs; - ahp->ah_intrTxqs &= ~(*txqs); -} + gpio_shift = (gpio % 6) * 5; -bool -ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds, - u32 segLen, bool firstSeg, - bool lastSeg, const struct ath_desc *ds0) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - - if (firstSeg) { - ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_TxMore); - } else if (lastSeg) { - ads->ds_ctl0 = 0; - ads->ds_ctl1 = segLen; - ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2; - ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3; + if (AR_SREV_9280_20_OR_LATER(ah) + || (addr != AR_GPIO_OUTPUT_MUX1)) { + REG_RMW(ah, addr, (type << gpio_shift), + (0x1f << gpio_shift)); } else { - ads->ds_ctl0 = 0; - ads->ds_ctl1 = segLen | AR_TxMore; - ads->ds_ctl2 = 0; - ads->ds_ctl3 = 0; + tmp = REG_READ(ah, addr); + tmp = ((tmp & 0x1F0) << 1) | (tmp & ~0x1F0); + tmp &= ~(0x1f << gpio_shift); + tmp |= (type << gpio_shift); + REG_WRITE(ah, addr, tmp); } - ads->ds_txstatus0 = ads->ds_txstatus1 = 0; - ads->ds_txstatus2 = ads->ds_txstatus3 = 0; - ads->ds_txstatus4 = ads->ds_txstatus5 = 0; - ads->ds_txstatus6 = ads->ds_txstatus7 = 0; - ads->ds_txstatus8 = ads->ds_txstatus9 = 0; - return true; -} - -void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - - ads->ds_txstatus0 = ads->ds_txstatus1 = 0; - ads->ds_txstatus2 = ads->ds_txstatus3 = 0; - ads->ds_txstatus4 = ads->ds_txstatus5 = 0; - ads->ds_txstatus6 = ads->ds_txstatus7 = 0; - ads->ds_txstatus8 = ads->ds_txstatus9 = 0; } -int -ath9k_hw_txprocdesc(struct ath_hal *ah, struct ath_desc *ds) +void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio) { - struct ar5416_desc *ads = AR5416DESC(ds); - - if ((ads->ds_txstatus9 & AR_TxDone) == 0) - return -EINPROGRESS; - - ds->ds_txstat.ts_seqnum = MS(ads->ds_txstatus9, AR_SeqNum); - ds->ds_txstat.ts_tstamp = ads->AR_SendTimestamp; - ds->ds_txstat.ts_status = 0; - ds->ds_txstat.ts_flags = 0; - - if (ads->ds_txstatus1 & AR_ExcessiveRetries) - ds->ds_txstat.ts_status |= ATH9K_TXERR_XRETRY; - if (ads->ds_txstatus1 & AR_Filtered) - ds->ds_txstat.ts_status |= ATH9K_TXERR_FILT; - if (ads->ds_txstatus1 & AR_FIFOUnderrun) - ds->ds_txstat.ts_status |= ATH9K_TXERR_FIFO; - if (ads->ds_txstatus9 & AR_TxOpExceeded) - ds->ds_txstat.ts_status |= ATH9K_TXERR_XTXOP; - if (ads->ds_txstatus1 & AR_TxTimerExpired) - ds->ds_txstat.ts_status |= ATH9K_TXERR_TIMER_EXPIRED; - - if (ads->ds_txstatus1 & AR_DescCfgErr) - ds->ds_txstat.ts_flags |= ATH9K_TX_DESC_CFG_ERR; - if (ads->ds_txstatus1 & AR_TxDataUnderrun) { - ds->ds_txstat.ts_flags |= ATH9K_TX_DATA_UNDERRUN; - ath9k_hw_updatetxtriglevel(ah, true); - } - if (ads->ds_txstatus1 & AR_TxDelimUnderrun) { - ds->ds_txstat.ts_flags |= ATH9K_TX_DELIM_UNDERRUN; - ath9k_hw_updatetxtriglevel(ah, true); - } - if (ads->ds_txstatus0 & AR_TxBaStatus) { - ds->ds_txstat.ts_flags |= ATH9K_TX_BA; - ds->ds_txstat.ba_low = ads->AR_BaBitmapLow; - ds->ds_txstat.ba_high = ads->AR_BaBitmapHigh; - } + u32 gpio_shift; - ds->ds_txstat.ts_rateindex = MS(ads->ds_txstatus9, AR_FinalTxIdx); - switch (ds->ds_txstat.ts_rateindex) { - case 0: - ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate0); - break; - case 1: - ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate1); - break; - case 2: - ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate2); - break; - case 3: - ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate3); - break; - } + ASSERT(gpio < ah->ah_caps.num_gpio_pins); - ds->ds_txstat.ts_rssi = MS(ads->ds_txstatus5, AR_TxRSSICombined); - ds->ds_txstat.ts_rssi_ctl0 = MS(ads->ds_txstatus0, AR_TxRSSIAnt00); - ds->ds_txstat.ts_rssi_ctl1 = MS(ads->ds_txstatus0, AR_TxRSSIAnt01); - ds->ds_txstat.ts_rssi_ctl2 = MS(ads->ds_txstatus0, AR_TxRSSIAnt02); - ds->ds_txstat.ts_rssi_ext0 = MS(ads->ds_txstatus5, AR_TxRSSIAnt10); - ds->ds_txstat.ts_rssi_ext1 = MS(ads->ds_txstatus5, AR_TxRSSIAnt11); - ds->ds_txstat.ts_rssi_ext2 = MS(ads->ds_txstatus5, AR_TxRSSIAnt12); - ds->ds_txstat.evm0 = ads->AR_TxEVM0; - ds->ds_txstat.evm1 = ads->AR_TxEVM1; - ds->ds_txstat.evm2 = ads->AR_TxEVM2; - ds->ds_txstat.ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt); - ds->ds_txstat.ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt); - ds->ds_txstat.ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt); - ds->ds_txstat.ts_antenna = 1; + gpio_shift = gpio << 1; - return 0; + REG_RMW(ah, + AR_GPIO_OE_OUT, + (AR_GPIO_OE_OUT_DRV_NO << gpio_shift), + (AR_GPIO_OE_OUT_DRV << gpio_shift)); } -void -ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds, - u32 pktLen, enum ath9k_pkt_type type, u32 txPower, - u32 keyIx, enum ath9k_key_type keyType, u32 flags) +u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio) { - struct ar5416_desc *ads = AR5416DESC(ds); - struct ath_hal_5416 *ahp = AH5416(ah); - - txPower += ahp->ah_txPowerIndexOffset; - if (txPower > 63) - txPower = 63; - - ads->ds_ctl0 = (pktLen & AR_FrameLen) - | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) - | SM(txPower, AR_XmitPower) - | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) - | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0) - | (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0) - | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0); - - ads->ds_ctl1 = - (keyIx != ATH9K_TXKEYIX_INVALID ? SM(keyIx, AR_DestIdx) : 0) - | SM(type, AR_FrameType) - | (flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0) - | (flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0) - | (flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0); - - ads->ds_ctl6 = SM(keyType, AR_EncrType); - - if (AR_SREV_9285(ah)) { + if (gpio >= ah->ah_caps.num_gpio_pins) + return 0xffffffff; - ads->ds_ctl8 = 0; - ads->ds_ctl9 = 0; - ads->ds_ctl10 = 0; - ads->ds_ctl11 = 0; + if (AR_SREV_9280_10_OR_LATER(ah)) { + return (MS + (REG_READ(ah, AR_GPIO_IN_OUT), + AR928X_GPIO_IN_VAL) & AR_GPIO_BIT(gpio)) != 0; + } else { + return (MS(REG_READ(ah, AR_GPIO_IN_OUT), AR_GPIO_IN_VAL) & + AR_GPIO_BIT(gpio)) != 0; } } -void -ath9k_hw_set11n_ratescenario(struct ath_hal *ah, struct ath_desc *ds, - struct ath_desc *lastds, - u32 durUpdateEn, u32 rtsctsRate, - u32 rtsctsDuration, - struct ath9k_11n_rate_series series[], - u32 nseries, u32 flags) +void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio, + u32 ah_signal_type) { - struct ar5416_desc *ads = AR5416DESC(ds); - struct ar5416_desc *last_ads = AR5416DESC(lastds); - u32 ds_ctl0; - - (void) nseries; - (void) rtsctsDuration; + u32 gpio_shift; - if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) { - ds_ctl0 = ads->ds_ctl0; + ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type); - if (flags & ATH9K_TXDESC_RTSENA) { - ds_ctl0 &= ~AR_CTSEnable; - ds_ctl0 |= AR_RTSEnable; - } else { - ds_ctl0 &= ~AR_RTSEnable; - ds_ctl0 |= AR_CTSEnable; - } + gpio_shift = 2 * gpio; - ads->ds_ctl0 = ds_ctl0; - } else { - ads->ds_ctl0 = - (ads->ds_ctl0 & ~(AR_RTSEnable | AR_CTSEnable)); - } + REG_RMW(ah, + AR_GPIO_OE_OUT, + (AR_GPIO_OE_OUT_DRV_ALL << gpio_shift), + (AR_GPIO_OE_OUT_DRV << gpio_shift)); +} - ads->ds_ctl2 = set11nTries(series, 0) - | set11nTries(series, 1) - | set11nTries(series, 2) - | set11nTries(series, 3) - | (durUpdateEn ? AR_DurUpdateEna : 0) - | SM(0, AR_BurstDur); - - ads->ds_ctl3 = set11nRate(series, 0) - | set11nRate(series, 1) - | set11nRate(series, 2) - | set11nRate(series, 3); - - ads->ds_ctl4 = set11nPktDurRTSCTS(series, 0) - | set11nPktDurRTSCTS(series, 1); - - ads->ds_ctl5 = set11nPktDurRTSCTS(series, 2) - | set11nPktDurRTSCTS(series, 3); - - ads->ds_ctl7 = set11nRateFlags(series, 0) - | set11nRateFlags(series, 1) - | set11nRateFlags(series, 2) - | set11nRateFlags(series, 3) - | SM(rtsctsRate, AR_RTSCTSRate); - last_ads->ds_ctl2 = ads->ds_ctl2; - last_ads->ds_ctl3 = ads->ds_ctl3; +void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val) +{ + REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio), + AR_GPIO_BIT(gpio)); } -void -ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds, - u32 aggrLen) +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) +void ath9k_enable_rfkill(struct ath_hal *ah) { - struct ar5416_desc *ads = AR5416DESC(ds); + REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, + AR_GPIO_INPUT_EN_VAL_RFSILENT_BB); - ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr); + REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2, + AR_GPIO_INPUT_MUX2_RFSILENT); - ads->ds_ctl6 &= ~AR_AggrLen; - ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen); + ath9k_hw_cfg_gpio_input(ah, ah->ah_rfkill_gpio); + REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB); } +#endif -void -ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds, - u32 numDelims) +int ath9k_hw_select_antconfig(struct ath_hal *ah, u32 cfg) { - struct ar5416_desc *ads = AR5416DESC(ds); - unsigned int ctl6; + struct ath9k_channel *chan = ah->ah_curchan; + const struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + u16 ant_config; + u32 halNumAntConfig; - ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr); + halNumAntConfig = IS_CHAN_2GHZ(chan) ? + pCap->num_antcfg_2ghz : pCap->num_antcfg_5ghz; + + if (cfg < halNumAntConfig) { + if (!ath9k_hw_get_eeprom_antenna_cfg(ah, chan, + cfg, &ant_config)) { + REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config); + return 0; + } + } - ctl6 = ads->ds_ctl6; - ctl6 &= ~AR_PadDelim; - ctl6 |= SM(numDelims, AR_PadDelim); - ads->ds_ctl6 = ctl6; + return -EINVAL; } -void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds) +u32 ath9k_hw_getdefantenna(struct ath_hal *ah) { - struct ar5416_desc *ads = AR5416DESC(ds); - - ads->ds_ctl1 |= AR_IsAggr; - ads->ds_ctl1 &= ~AR_MoreAggr; - ads->ds_ctl6 &= ~AR_PadDelim; + return REG_READ(ah, AR_DEF_ANTENNA) & 0x7; } -void ath9k_hw_clr11n_aggr(struct ath_hal *ah, struct ath_desc *ds) +void ath9k_hw_setantenna(struct ath_hal *ah, u32 antenna) { - struct ar5416_desc *ads = AR5416DESC(ds); - - ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr); + REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7)); } -void -ath9k_hw_set11n_burstduration(struct ath_hal *ah, struct ath_desc *ds, - u32 burstDuration) +bool ath9k_hw_setantennaswitch(struct ath_hal *ah, + enum ath9k_ant_setting settings, + struct ath9k_channel *chan, + u8 *tx_chainmask, + u8 *rx_chainmask, + u8 *antenna_cfgd) { - struct ar5416_desc *ads = AR5416DESC(ds); + struct ath_hal_5416 *ahp = AH5416(ah); + static u8 tx_chainmask_cfg, rx_chainmask_cfg; - ads->ds_ctl2 &= ~AR_BurstDur; - ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur); -} + if (AR_SREV_9280(ah)) { + if (!tx_chainmask_cfg) { -void -ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah, struct ath_desc *ds, - u32 vmf) -{ - struct ar5416_desc *ads = AR5416DESC(ds); + tx_chainmask_cfg = *tx_chainmask; + rx_chainmask_cfg = *rx_chainmask; + } - if (vmf) - ads->ds_ctl0 |= AR_VirtMoreFrag; - else - ads->ds_ctl0 &= ~AR_VirtMoreFrag; -} + switch (settings) { + case ATH9K_ANT_FIXED_A: + *tx_chainmask = ATH9K_ANTENNA0_CHAINMASK; + *rx_chainmask = ATH9K_ANTENNA0_CHAINMASK; + *antenna_cfgd = true; + break; + case ATH9K_ANT_FIXED_B: + if (ah->ah_caps.tx_chainmask > + ATH9K_ANTENNA1_CHAINMASK) { + *tx_chainmask = ATH9K_ANTENNA1_CHAINMASK; + } + *rx_chainmask = ATH9K_ANTENNA1_CHAINMASK; + *antenna_cfgd = true; + break; + case ATH9K_ANT_VARIABLE: + *tx_chainmask = tx_chainmask_cfg; + *rx_chainmask = rx_chainmask_cfg; + *antenna_cfgd = true; + break; + default: + break; + } + } else { + ahp->ah_diversityControl = settings; + } -void ath9k_hw_putrxbuf(struct ath_hal *ah, u32 rxdp) -{ - REG_WRITE(ah, AR_RXDP, rxdp); + return true; } -void ath9k_hw_rxena(struct ath_hal *ah) -{ - REG_WRITE(ah, AR_CR, AR_CR_RXE); -} +/*********************/ +/* General Operation */ +/*********************/ -bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set) +u32 ath9k_hw_getrxfilter(struct ath_hal *ah) { - if (set) { - - REG_SET_BIT(ah, AR_DIAG_SW, - (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); + u32 bits = REG_READ(ah, AR_RX_FILTER); + u32 phybits = REG_READ(ah, AR_PHY_ERR); - if (!ath9k_hw_wait - (ah, AR_OBS_BUS_1, AR_OBS_BUS_1_RX_STATE, 0)) { - u32 reg; + if (phybits & AR_PHY_ERR_RADAR) + bits |= ATH9K_RX_FILTER_PHYRADAR; + if (phybits & (AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING)) + bits |= ATH9K_RX_FILTER_PHYERR; - REG_CLR_BIT(ah, AR_DIAG_SW, - (AR_DIAG_RX_DIS | - AR_DIAG_RX_ABORT)); + return bits; +} - reg = REG_READ(ah, AR_OBS_BUS_1); - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "%s: rx failed to go idle in 10 ms RXSM=0x%x\n", - __func__, reg); +void ath9k_hw_setrxfilter(struct ath_hal *ah, u32 bits) +{ + u32 phybits; - return false; - } - } else { - REG_CLR_BIT(ah, AR_DIAG_SW, - (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); - } + REG_WRITE(ah, AR_RX_FILTER, (bits & 0xffff) | AR_RX_COMPR_BAR); + phybits = 0; + if (bits & ATH9K_RX_FILTER_PHYRADAR) + phybits |= AR_PHY_ERR_RADAR; + if (bits & ATH9K_RX_FILTER_PHYERR) + phybits |= AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING; + REG_WRITE(ah, AR_PHY_ERR, phybits); - return true; + if (phybits) + REG_WRITE(ah, AR_RXCFG, + REG_READ(ah, AR_RXCFG) | AR_RXCFG_ZLFDMA); + else + REG_WRITE(ah, AR_RXCFG, + REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA); } -void -ath9k_hw_setmcastfilter(struct ath_hal *ah, u32 filter0, - u32 filter1) +bool ath9k_hw_phy_disable(struct ath_hal *ah) { - REG_WRITE(ah, AR_MCAST_FIL0, filter0); - REG_WRITE(ah, AR_MCAST_FIL1, filter1); + return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM); } -bool -ath9k_hw_setuprxdesc(struct ath_hal *ah, struct ath_desc *ds, - u32 size, u32 flags) +bool ath9k_hw_disable(struct ath_hal *ah) { - struct ar5416_desc *ads = AR5416DESC(ds); - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - - ads->ds_ctl1 = size & AR_BufLen; - if (flags & ATH9K_RXDESC_INTREQ) - ads->ds_ctl1 |= AR_RxIntrReq; + if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) + return false; - ads->ds_rxstatus8 &= ~AR_RxDone; - if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) - memset(&(ads->u), 0, sizeof(ads->u)); - return true; + return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_COLD); } -int -ath9k_hw_rxprocdesc(struct ath_hal *ah, struct ath_desc *ds, - u32 pa, struct ath_desc *nds, u64 tsf) +bool ath9k_hw_set_txpowerlimit(struct ath_hal *ah, u32 limit) { - struct ar5416_desc ads; - struct ar5416_desc *adsp = AR5416DESC(ds); - - if ((adsp->ds_rxstatus8 & AR_RxDone) == 0) - return -EINPROGRESS; - - ads.u.rx = adsp->u.rx; - - ds->ds_rxstat.rs_status = 0; - ds->ds_rxstat.rs_flags = 0; + struct ath9k_channel *chan = ah->ah_curchan; - ds->ds_rxstat.rs_datalen = ads.ds_rxstatus1 & AR_DataLen; - ds->ds_rxstat.rs_tstamp = ads.AR_RcvTimestamp; + ah->ah_powerLimit = min(limit, (u32) MAX_RATE_POWER); - ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined); - ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt00); - ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt01); - ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt02); - ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt10); - ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt11); - ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt12); - if (ads.ds_rxstatus8 & AR_RxKeyIdxValid) - ds->ds_rxstat.rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx); - else - ds->ds_rxstat.rs_keyix = ATH9K_RXKEYIX_INVALID; - - ds->ds_rxstat.rs_rate = RXSTATUS_RATE(ah, (&ads)); - ds->ds_rxstat.rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0; - - ds->ds_rxstat.rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0; - ds->ds_rxstat.rs_moreaggr = - (ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0; - ds->ds_rxstat.rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna); - ds->ds_rxstat.rs_flags = - (ads.ds_rxstatus3 & AR_GI) ? ATH9K_RX_GI : 0; - ds->ds_rxstat.rs_flags |= - (ads.ds_rxstatus3 & AR_2040) ? ATH9K_RX_2040 : 0; - - if (ads.ds_rxstatus8 & AR_PreDelimCRCErr) - ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_PRE; - if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) - ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_POST; - if (ads.ds_rxstatus8 & AR_DecryptBusyErr) - ds->ds_rxstat.rs_flags |= ATH9K_RX_DECRYPT_BUSY; - - if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) { - - if (ads.ds_rxstatus8 & AR_CRCErr) - ds->ds_rxstat.rs_status |= ATH9K_RXERR_CRC; - else if (ads.ds_rxstatus8 & AR_PHYErr) { - u32 phyerr; - - ds->ds_rxstat.rs_status |= ATH9K_RXERR_PHY; - phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode); - ds->ds_rxstat.rs_phyerr = phyerr; - } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr) - ds->ds_rxstat.rs_status |= ATH9K_RXERR_DECRYPT; - else if (ads.ds_rxstatus8 & AR_MichaelErr) - ds->ds_rxstat.rs_status |= ATH9K_RXERR_MIC; - } + if (ath9k_hw_set_txpower(ah, chan, + ath9k_regd_get_ctl(ah, chan), + ath9k_regd_get_antenna_allowed(ah, chan), + chan->maxRegTxPower * 2, + min((u32) MAX_RATE_POWER, + (u32) ah->ah_powerLimit)) != 0) + return false; - return 0; + return true; } -static void ath9k_hw_setup_rate_table(struct ath_hal *ah, - struct ath9k_rate_table *rt) +void ath9k_hw_getmac(struct ath_hal *ah, u8 *mac) { - int i; + struct ath_hal_5416 *ahp = AH5416(ah); - if (rt->rateCodeToIndex[0] != 0) - return; - for (i = 0; i < 256; i++) - rt->rateCodeToIndex[i] = (u8) -1; - for (i = 0; i < rt->rateCount; i++) { - u8 code = rt->info[i].rateCode; - u8 cix = rt->info[i].controlRate; - - rt->rateCodeToIndex[code] = i; - rt->rateCodeToIndex[code | rt->info[i].shortPreamble] = i; - - rt->info[i].lpAckDuration = - ath9k_hw_computetxtime(ah, rt, - WLAN_CTRL_FRAME_SIZE, - cix, - false); - rt->info[i].spAckDuration = - ath9k_hw_computetxtime(ah, rt, - WLAN_CTRL_FRAME_SIZE, - cix, - true); - } + memcpy(mac, ahp->ah_macaddr, ETH_ALEN); } -const struct ath9k_rate_table *ath9k_hw_getratetable(struct ath_hal *ah, - u32 mode) +bool ath9k_hw_setmac(struct ath_hal *ah, const u8 *mac) { - struct ath9k_rate_table *rt; - switch (mode) { - case ATH9K_MODE_11A: - rt = &ar5416_11a_table; - break; - case ATH9K_MODE_11B: - rt = &ar5416_11b_table; - break; - case ATH9K_MODE_11G: - rt = &ar5416_11g_table; - break; - case ATH9K_MODE_11NG_HT20: - case ATH9K_MODE_11NG_HT40PLUS: - case ATH9K_MODE_11NG_HT40MINUS: - rt = &ar5416_11ng_table; - break; - case ATH9K_MODE_11NA_HT20: - case ATH9K_MODE_11NA_HT40PLUS: - case ATH9K_MODE_11NA_HT40MINUS: - rt = &ar5416_11na_table; - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, "%s: invalid mode 0x%x\n", - __func__, mode); - return NULL; - } - ath9k_hw_setup_rate_table(ah, rt); - return rt; + struct ath_hal_5416 *ahp = AH5416(ah); + + memcpy(ahp->ah_macaddr, mac, ETH_ALEN); + + return true; } -static const char *ath9k_hw_devname(u16 devid) +void ath9k_hw_setopmode(struct ath_hal *ah) { - switch (devid) { - case AR5416_DEVID_PCI: - case AR5416_DEVID_PCIE: - return "Atheros 5416"; - case AR9160_DEVID_PCI: - return "Atheros 9160"; - case AR9280_DEVID_PCI: - case AR9280_DEVID_PCIE: - return "Atheros 9280"; - } - return NULL; + ath9k_hw_set_operating_mode(ah, ah->ah_opmode); } -const char *ath9k_hw_probe(u16 vendorid, u16 devid) +void ath9k_hw_setmcastfilter(struct ath_hal *ah, u32 filter0, u32 filter1) { - return vendorid == ATHEROS_VENDOR_ID ? - ath9k_hw_devname(devid) : NULL; + REG_WRITE(ah, AR_MCAST_FIL0, filter0); + REG_WRITE(ah, AR_MCAST_FIL1, filter1); } -struct ath_hal *ath9k_hw_attach(u16 devid, - struct ath_softc *sc, - void __iomem *mem, - int *error) +void ath9k_hw_getbssidmask(struct ath_hal *ah, u8 *mask) { - struct ath_hal *ah = NULL; - - switch (devid) { - case AR5416_DEVID_PCI: - case AR5416_DEVID_PCIE: - case AR9160_DEVID_PCI: - case AR9280_DEVID_PCI: - case AR9280_DEVID_PCIE: - ah = ath9k_hw_do_attach(devid, sc, mem, error); - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_ANY, - "devid=0x%x not supported.\n", devid); - ah = NULL; - *error = -ENXIO; - break; - } + struct ath_hal_5416 *ahp = AH5416(ah); - return ah; + memcpy(mask, ahp->ah_bssidmask, ETH_ALEN); } -u16 -ath9k_hw_computetxtime(struct ath_hal *ah, - const struct ath9k_rate_table *rates, - u32 frameLen, u16 rateix, - bool shortPreamble) +bool ath9k_hw_setbssidmask(struct ath_hal *ah, const u8 *mask) { - u32 bitsPerSymbol, numBits, numSymbols, phyTime, txTime; - u32 kbps; - - kbps = rates->info[rateix].rateKbps; + struct ath_hal_5416 *ahp = AH5416(ah); - if (kbps == 0) - return 0; - switch (rates->info[rateix].phy) { + memcpy(ahp->ah_bssidmask, mask, ETH_ALEN); - case PHY_CCK: - phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS; - if (shortPreamble && rates->info[rateix].shortPreamble) - phyTime >>= 1; - numBits = frameLen << 3; - txTime = CCK_SIFS_TIME + phyTime - + ((numBits * 1000) / kbps); - break; - case PHY_OFDM: - if (ah->ah_curchan && IS_CHAN_QUARTER_RATE(ah->ah_curchan)) { - bitsPerSymbol = - (kbps * OFDM_SYMBOL_TIME_QUARTER) / 1000; + REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(ahp->ah_bssidmask)); + REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(ahp->ah_bssidmask + 4)); - numBits = OFDM_PLCP_BITS + (frameLen << 3); - numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol); - txTime = OFDM_SIFS_TIME_QUARTER - + OFDM_PREAMBLE_TIME_QUARTER - + (numSymbols * OFDM_SYMBOL_TIME_QUARTER); - } else if (ah->ah_curchan && - IS_CHAN_HALF_RATE(ah->ah_curchan)) { - bitsPerSymbol = - (kbps * OFDM_SYMBOL_TIME_HALF) / 1000; + return true; +} - numBits = OFDM_PLCP_BITS + (frameLen << 3); - numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol); - txTime = OFDM_SIFS_TIME_HALF + - OFDM_PREAMBLE_TIME_HALF - + (numSymbols * OFDM_SYMBOL_TIME_HALF); - } else { - bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME) / 1000; +void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid, u16 assocId) +{ + struct ath_hal_5416 *ahp = AH5416(ah); - numBits = OFDM_PLCP_BITS + (frameLen << 3); - numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol); - txTime = OFDM_SIFS_TIME + OFDM_PREAMBLE_TIME - + (numSymbols * OFDM_SYMBOL_TIME); - } - break; + memcpy(ahp->ah_bssid, bssid, ETH_ALEN); + ahp->ah_assocId = assocId; - default: - DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO, - "%s: unknown phy %u (rate ix %u)\n", __func__, - rates->info[rateix].phy, rateix); - txTime = 0; - break; - } - return txTime; + REG_WRITE(ah, AR_BSS_ID0, get_unaligned_le32(ahp->ah_bssid)); + REG_WRITE(ah, AR_BSS_ID1, get_unaligned_le16(ahp->ah_bssid + 4) | + ((assocId & 0x3fff) << AR_BSS_ID1_AID_S)); } -u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags) +u64 ath9k_hw_gettsf64(struct ath_hal *ah) { - if (flags & CHANNEL_2GHZ) { - if (freq == 2484) - return 14; - if (freq < 2484) - return (freq - 2407) / 5; - else - return 15 + ((freq - 2512) / 20); - } else if (flags & CHANNEL_5GHZ) { - if (ath9k_regd_is_public_safety_sku(ah) && - IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq)) { - return ((freq * 10) + - (((freq % 5) == 2) ? 5 : 0) - 49400) / 5; - } else if ((flags & CHANNEL_A) && (freq <= 5000)) { - return (freq - 4000) / 5; - } else { - return (freq - 5000) / 5; - } - } else { - if (freq == 2484) - return 14; - if (freq < 2484) - return (freq - 2407) / 5; - if (freq < 5000) { - if (ath9k_regd_is_public_safety_sku(ah) - && IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq)) { - return ((freq * 10) + - (((freq % 5) == - 2) ? 5 : 0) - 49400) / 5; - } else if (freq > 4900) { - return (freq - 4000) / 5; - } else { - return 15 + ((freq - 2512) / 20); - } - } - return (freq - 5000) / 5; - } -} + u64 tsf; -/* We can tune this as we go by monitoring really low values */ -#define ATH9K_NF_TOO_LOW -60 + tsf = REG_READ(ah, AR_TSF_U32); + tsf = (tsf << 32) | REG_READ(ah, AR_TSF_L32); -/* AR5416 may return very high value (like -31 dBm), in those cases the nf - * is incorrect and we should use the static NF value. Later we can try to - * find out why they are reporting these values */ -static bool ath9k_hw_nf_in_range(struct ath_hal *ah, s16 nf) -{ - if (nf > ATH9K_NF_TOO_LOW) { - DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL, - "%s: noise floor value detected (%d) is " - "lower than what we think is a " - "reasonable value (%d)\n", - __func__, nf, ATH9K_NF_TOO_LOW); - return false; - } - return true; + return tsf; } -s16 -ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan) +void ath9k_hw_reset_tsf(struct ath_hal *ah) { - struct ath9k_channel *ichan; - s16 nf; - - ichan = ath9k_regd_check_channel(ah, chan); - if (ichan == NULL) { - DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL, - "%s: invalid channel %u/0x%x; no mapping\n", - __func__, chan->channel, chan->channelFlags); - return ATH_DEFAULT_NOISE_FLOOR; - } - if (ichan->rawNoiseFloor == 0) { - enum wireless_mode mode = ath9k_hw_chan2wmode(ah, chan); - nf = NOISE_FLOOR[mode]; - } else - nf = ichan->rawNoiseFloor; - - if (!ath9k_hw_nf_in_range(ah, nf)) - nf = ATH_DEFAULT_NOISE_FLOOR; + int count; - return nf; + count = 0; + while (REG_READ(ah, AR_SLP32_MODE) & AR_SLP32_TSF_WRITE_STATUS) { + count++; + if (count > 10) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, + "AR_SLP32_TSF_WRITE_STATUS limit exceeded\n"); + break; + } + udelay(10); + } + REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE); } bool ath9k_hw_set_tsfadjust(struct ath_hal *ah, u32 setting) @@ -8468,110 +3862,34 @@ bool ath9k_hw_set_tsfadjust(struct ath_hal *ah, u32 setting) ahp->ah_miscMode |= AR_PCU_TX_ADD_TSF; else ahp->ah_miscMode &= ~AR_PCU_TX_ADD_TSF; - return true; -} - -bool ath9k_hw_phycounters(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - - return ahp->ah_hasHwPhyCounters ? true : false; -} - -u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q) -{ - return REG_READ(ah, AR_QTXDP(q)); -} - -bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q, - u32 txdp) -{ - REG_WRITE(ah, AR_QTXDP(q), txdp); - - return true; -} - -bool ath9k_hw_txstart(struct ath_hal *ah, u32 q) -{ - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: queue %u\n", __func__, q); - - REG_WRITE(ah, AR_Q_TXE, 1 << q); return true; } -u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q) +bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us) { - u32 npend; - - npend = REG_READ(ah, AR_QSTS(q)) & AR_Q_STS_PEND_FR_CNT; - if (npend == 0) { + struct ath_hal_5416 *ahp = AH5416(ah); - if (REG_READ(ah, AR_Q_TXE) & (1 << q)) - npend = 1; + if (us < ATH9K_SLOT_TIME_9 || us > ath9k_hw_mac_to_usec(ah, 0xffff)) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad slot time %u\n", us); + ahp->ah_slottime = (u32) -1; + return false; + } else { + REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath9k_hw_mac_to_clks(ah, us)); + ahp->ah_slottime = us; + return true; } - return npend; } -bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q) +void ath9k_hw_set11nmac2040(struct ath_hal *ah, enum ath9k_ht_macmode mode) { - u32 wait; - - REG_WRITE(ah, AR_Q_TXD, 1 << q); - - for (wait = 1000; wait != 0; wait--) { - if (ath9k_hw_numtxpending(ah, q) == 0) - break; - udelay(100); - } - - if (ath9k_hw_numtxpending(ah, q)) { - u32 tsfLow, j; - - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, - "%s: Num of pending TX Frames %d on Q %d\n", - __func__, ath9k_hw_numtxpending(ah, q), q); - - for (j = 0; j < 2; j++) { - tsfLow = REG_READ(ah, AR_TSF_L32); - REG_WRITE(ah, AR_QUIET2, - SM(10, AR_QUIET2_QUIET_DUR)); - REG_WRITE(ah, AR_QUIET_PERIOD, 100); - REG_WRITE(ah, AR_NEXT_QUIET_TIMER, tsfLow >> 10); - REG_SET_BIT(ah, AR_TIMER_MODE, - AR_QUIET_TIMER_EN); - - if ((REG_READ(ah, AR_TSF_L32) >> 10) == - (tsfLow >> 10)) { - break; - } - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, - "%s: TSF have moved while trying to set " - "quiet time TSF: 0x%08x\n", - __func__, tsfLow); - } - - REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH); - - udelay(200); - REG_CLR_BIT(ah, AR_TIMER_MODE, AR_QUIET_TIMER_EN); - - wait = 1000; - - while (ath9k_hw_numtxpending(ah, q)) { - if ((--wait) == 0) { - DPRINTF(ah->ah_sc, ATH_DBG_XMIT, - "%s: Failed to stop Tx DMA in 100 " - "msec after killing last frame\n", - __func__); - break; - } - udelay(100); - } + u32 macmode; - REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH); - } + if (mode == ATH9K_HT_MACMODE_2040 && + !ah->ah_config.cwm_ignore_extcca) + macmode = AR_2040_JOINED_RX_CLEAR; + else + macmode = 0; - REG_WRITE(ah, AR_Q_TXD, 0); - return wait != 0; + REG_WRITE(ah, AR_2040_MODE, macmode); } diff --git a/drivers/net/wireless/ath9k/hw.h b/drivers/net/wireless/ath9k/hw.h index 2113818ee9348dffdd4cc2334c85abac662d4683..91d8f594af813a9d1d5100ea117c4ffef0e841d7 100644 --- a/drivers/net/wireless/ath9k/hw.h +++ b/drivers/net/wireless/ath9k/hw.h @@ -415,6 +415,9 @@ struct ar5416Stats { #define AR5416_EEP_MINOR_VER_3 0x3 #define AR5416_EEP_MINOR_VER_7 0x7 #define AR5416_EEP_MINOR_VER_9 0x9 +#define AR5416_EEP_MINOR_VER_16 0x10 +#define AR5416_EEP_MINOR_VER_17 0x11 +#define AR5416_EEP_MINOR_VER_19 0x13 #define AR5416_NUM_5G_CAL_PIERS 8 #define AR5416_NUM_2G_CAL_PIERS 4 @@ -436,6 +439,27 @@ struct ar5416Stats { #define AR5416_MAX_CHAINS 3 #define AR5416_PWR_TABLE_OFFSET -5 +/* Rx gain type values */ +#define AR5416_EEP_RXGAIN_23DB_BACKOFF 0 +#define AR5416_EEP_RXGAIN_13DB_BACKOFF 1 +#define AR5416_EEP_RXGAIN_ORIG 2 + +/* Tx gain type values */ +#define AR5416_EEP_TXGAIN_ORIGINAL 0 +#define AR5416_EEP_TXGAIN_HIGH_POWER 1 + +#define AR5416_EEP4K_START_LOC 64 +#define AR5416_EEP4K_NUM_2G_CAL_PIERS 3 +#define AR5416_EEP4K_NUM_2G_CCK_TARGET_POWERS 3 +#define AR5416_EEP4K_NUM_2G_20_TARGET_POWERS 3 +#define AR5416_EEP4K_NUM_2G_40_TARGET_POWERS 3 +#define AR5416_EEP4K_NUM_CTLS 12 +#define AR5416_EEP4K_NUM_BAND_EDGES 4 +#define AR5416_EEP4K_NUM_PD_GAINS 2 +#define AR5416_EEP4K_PD_GAINS_IN_MASK 4 +#define AR5416_EEP4K_PD_GAIN_ICEPTS 5 +#define AR5416_EEP4K_MAX_CHAINS 1 + enum eeprom_param { EEP_NFTHRESH_5, EEP_NFTHRESH_2, @@ -454,6 +478,8 @@ enum eeprom_param { EEP_MINOR_REV, EEP_TX_MASK, EEP_RX_MASK, + EEP_RXGAIN_TYPE, + EEP_TXGAIN_TYPE, }; enum ar5416_rates { @@ -469,6 +495,11 @@ enum ar5416_rates { Ar5416RateSize }; +enum ath9k_hal_freq_band { + ATH9K_HAL_FREQ_BAND_5GHZ = 0, + ATH9K_HAL_FREQ_BAND_2GHZ = 1 +}; + struct base_eep_header { u16 length; u16 checksum; @@ -485,9 +516,32 @@ struct base_eep_header { u32 binBuildNumber; u8 deviceType; u8 pwdclkind; - u8 futureBase[32]; + u8 futureBase_1[2]; + u8 rxGainType; + u8 futureBase_2[3]; + u8 txGainType; + u8 futureBase_3[25]; +} __packed; + +struct base_eep_header_4k { + u16 length; + u16 checksum; + u16 version; + u8 opCapFlags; + u8 eepMisc; + u16 regDmn[2]; + u8 macAddr[6]; + u8 rxMask; + u8 txMask; + u16 rfSilent; + u16 blueToothOptions; + u16 deviceCap; + u32 binBuildNumber; + u8 deviceType; + u8 futureBase[1]; } __packed; + struct spur_chan { u16 spurChan; u8 spurRangeLow; @@ -540,11 +594,58 @@ struct modal_eep_header { struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS]; } __packed; +struct modal_eep_4k_header { + u32 antCtrlChain[AR5416_EEP4K_MAX_CHAINS]; + u32 antCtrlCommon; + u8 antennaGainCh[AR5416_EEP4K_MAX_CHAINS]; + u8 switchSettling; + u8 txRxAttenCh[AR5416_EEP4K_MAX_CHAINS]; + u8 rxTxMarginCh[AR5416_EEP4K_MAX_CHAINS]; + u8 adcDesiredSize; + u8 pgaDesiredSize; + u8 xlnaGainCh[AR5416_EEP4K_MAX_CHAINS]; + u8 txEndToXpaOff; + u8 txEndToRxOn; + u8 txFrameToXpaOn; + u8 thresh62; + u8 noiseFloorThreshCh[AR5416_EEP4K_MAX_CHAINS]; + u8 xpdGain; + u8 xpd; + u8 iqCalICh[AR5416_EEP4K_MAX_CHAINS]; + u8 iqCalQCh[AR5416_EEP4K_MAX_CHAINS]; + u8 pdGainOverlap; + u8 ob_01; + u8 db1_01; + u8 xpaBiasLvl; + u8 txFrameToDataStart; + u8 txFrameToPaOn; + u8 ht40PowerIncForPdadc; + u8 bswAtten[AR5416_EEP4K_MAX_CHAINS]; + u8 bswMargin[AR5416_EEP4K_MAX_CHAINS]; + u8 swSettleHt40; + u8 xatten2Db[AR5416_EEP4K_MAX_CHAINS]; + u8 xatten2Margin[AR5416_EEP4K_MAX_CHAINS]; + u8 db2_01; + u8 version; + u16 ob_234; + u16 db1_234; + u16 db2_234; + u8 futureModal[4]; + + struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS]; +} __packed; + + struct cal_data_per_freq { u8 pwrPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; u8 vpdPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; } __packed; +struct cal_data_per_freq_4k { + u8 pwrPdg[AR5416_EEP4K_NUM_PD_GAINS][AR5416_EEP4K_PD_GAIN_ICEPTS]; + u8 vpdPdg[AR5416_EEP4K_NUM_PD_GAINS][AR5416_EEP4K_PD_GAIN_ICEPTS]; +} __packed; + struct cal_target_power_leg { u8 bChannel; u8 tPow2x[4]; @@ -555,6 +656,7 @@ struct cal_target_power_ht { u8 tPow2x[8]; } __packed; + #ifdef __BIG_ENDIAN_BITFIELD struct cal_ctl_edges { u8 bChannel; @@ -569,10 +671,15 @@ struct cal_ctl_edges { struct cal_ctl_data { struct cal_ctl_edges - ctlEdges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES]; + ctlEdges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES]; } __packed; -struct ar5416_eeprom { +struct cal_ctl_data_4k { + struct cal_ctl_edges + ctlEdges[AR5416_EEP4K_MAX_CHAINS][AR5416_EEP4K_NUM_BAND_EDGES]; +} __packed; + +struct ar5416_eeprom_def { struct base_eep_header baseEepHeader; u8 custData[64]; struct modal_eep_header modalHeader[2]; @@ -601,6 +708,26 @@ struct ar5416_eeprom { u8 padding; } __packed; +struct ar5416_eeprom_4k { + struct base_eep_header_4k baseEepHeader; + u8 custData[20]; + struct modal_eep_4k_header modalHeader; + u8 calFreqPier2G[AR5416_EEP4K_NUM_2G_CAL_PIERS]; + struct cal_data_per_freq_4k + calPierData2G[AR5416_EEP4K_MAX_CHAINS][AR5416_EEP4K_NUM_2G_CAL_PIERS]; + struct cal_target_power_leg + calTargetPowerCck[AR5416_EEP4K_NUM_2G_CCK_TARGET_POWERS]; + struct cal_target_power_leg + calTargetPower2G[AR5416_EEP4K_NUM_2G_20_TARGET_POWERS]; + struct cal_target_power_ht + calTargetPower2GHT20[AR5416_EEP4K_NUM_2G_20_TARGET_POWERS]; + struct cal_target_power_ht + calTargetPower2GHT40[AR5416_EEP4K_NUM_2G_40_TARGET_POWERS]; + u8 ctlIndex[AR5416_EEP4K_NUM_CTLS]; + struct cal_ctl_data_4k ctlData[AR5416_EEP4K_NUM_CTLS]; + u8 padding; +} __packed; + struct ar5416IniArray { u32 *ia_array; u32 ia_rows; @@ -668,9 +795,22 @@ struct hal_cal_list { struct hal_cal_list *calNext; }; +/* + * Enum to indentify the eeprom mappings + */ +enum hal_eep_map { + EEP_MAP_DEFAULT = 0x0, + EEP_MAP_4KBITS, + EEP_MAP_MAX +}; + + struct ath_hal_5416 { struct ath_hal ah; - struct ar5416_eeprom ah_eeprom; + union { + struct ar5416_eeprom_def def; + struct ar5416_eeprom_4k map4k; + } ah_eeprom; struct ar5416Stats ah_stats; struct ath9k_tx_queue_info ah_txq[ATH9K_NUM_TX_QUEUES]; void __iomem *ah_cal_mem; @@ -792,6 +932,10 @@ struct ath_hal_5416 { struct ar5416IniArray ah_iniAddac; struct ar5416IniArray ah_iniPcieSerdes; struct ar5416IniArray ah_iniModesAdditional; + struct ar5416IniArray ah_iniModesRxGain; + struct ar5416IniArray ah_iniModesTxGain; + /* To indicate EEPROM mapping used */ + enum hal_eep_map ah_eep_map; }; #define AH5416(_ah) ((struct ath_hal_5416 *)(_ah)) @@ -833,13 +977,20 @@ struct ath_hal_5416 { (AR_SREV_9100(ah)) ? 0x1fff1000 : 0x503f1200 #define AR5416_EEPROM_MAX 0xae0 #define ar5416_get_eep_ver(_ahp) \ - (((_ahp)->ah_eeprom.baseEepHeader.version >> 12) & 0xF) + (((_ahp)->ah_eeprom.def.baseEepHeader.version >> 12) & 0xF) #define ar5416_get_eep_rev(_ahp) \ - (((_ahp)->ah_eeprom.baseEepHeader.version) & 0xFFF) + (((_ahp)->ah_eeprom.def.baseEepHeader.version) & 0xFFF) #define ar5416_get_ntxchains(_txchainmask) \ (((_txchainmask >> 2) & 1) + \ ((_txchainmask >> 1) & 1) + (_txchainmask & 1)) +/* EEPROM 4K bit map definations */ +#define ar5416_get_eep4k_ver(_ahp) \ + (((_ahp)->ah_eeprom.map4k.baseEepHeader.version >> 12) & 0xF) +#define ar5416_get_eep4k_rev(_ahp) \ + (((_ahp)->ah_eeprom.map4k.baseEepHeader.version) & 0xFFF) + + #ifdef __BIG_ENDIAN #define AR5416_EEPROM_MAGIC 0x5aa5 #else @@ -923,7 +1074,7 @@ struct ath_hal_5416 { #define OFDM_PLCP_BITS_QUARTER 22 #define OFDM_SYMBOL_TIME_QUARTER 16 -u32 ath9k_hw_get_eeprom(struct ath_hal_5416 *ahp, +u32 ath9k_hw_get_eeprom(struct ath_hal *ah, enum eeprom_param param); #endif diff --git a/drivers/net/wireless/ath9k/initvals.h b/drivers/net/wireless/ath9k/initvals.h index 3dd3815940a4efa7a72ba083718d787086166706..f3cfa16525e42d029c98be3d8d681a4bd39a2096 100644 --- a/drivers/net/wireless/ath9k/initvals.h +++ b/drivers/net/wireless/ath9k/initvals.h @@ -14,6 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +/* AR5416 to Fowl ar5146.ini */ static const u32 ar5416Modes_9100[][6] = { { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, @@ -31,17 +32,17 @@ static const u32 ar5416Modes_9100[][6] = { { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, - { 0x00009850, 0x6de8b4e0, 0x6de8b4e0, 0x6de8b0de, 0x6de8b0de, 0x6de8b0de }, + { 0x00009850, 0x6c48b4e0, 0x6c48b4e0, 0x6c48b0de, 0x6c48b0de, 0x6c48b0de }, { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e }, - { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e }, + { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e }, { 0x00009860, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18 }, { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, { 0x00009868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 }, { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 }, - { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 }, + { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 }, { 0x00009918, 0x000001b8, 0x00000370, 0x00000268, 0x00000134, 0x00000134 }, { 0x00009924, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b }, - { 0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020 }, + { 0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020 }, { 0x00009960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 }, { 0x0000a960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 }, { 0x0000b960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 }, @@ -207,7 +208,7 @@ static const u32 ar5416Common_9100[][2] = { { 0x00008134, 0x00000000 }, { 0x00008138, 0x00000000 }, { 0x0000813c, 0x00000000 }, - { 0x00008144, 0x00000000 }, + { 0x00008144, 0xffffffff }, { 0x00008168, 0x00000000 }, { 0x0000816c, 0x00000000 }, { 0x00008170, 0x32143320 }, @@ -266,7 +267,7 @@ static const u32 ar5416Common_9100[][2] = { { 0x0000832c, 0x00000007 }, { 0x00008330, 0x00000302 }, { 0x00008334, 0x00000e00 }, - { 0x00008338, 0x00000000 }, + { 0x00008338, 0x00070000 }, { 0x0000833c, 0x00000000 }, { 0x00008340, 0x000107ff }, { 0x00009808, 0x00000000 }, @@ -661,6 +662,7 @@ static const u32 ar5416Addac_9100[][2] = { {0x000098c4, 0x00000000 }, }; +/* ar5416 - howl ar5416_howl.ini */ static const u32 ar5416Modes[][6] = { { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, @@ -952,7 +954,7 @@ static const u32 ar5416Common[][2] = { { 0x0000994c, 0x00020028 }, { 0x0000c95c, 0x004b6a8e }, { 0x0000c968, 0x000003ce }, - { 0x00009970, 0x190fb514 }, + { 0x00009970, 0x190fb515 }, { 0x00009974, 0x00000000 }, { 0x00009978, 0x00000001 }, { 0x0000997c, 0x00000000 }, @@ -1311,7 +1313,7 @@ static const u32 ar5416Addac[][2] = { {0x000098cc, 0x00000000 }, }; - +/* AR5416 9160 Sowl ar5416_sowl.ini */ static const u32 ar5416Modes_9160[][6] = { { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, @@ -1329,21 +1331,22 @@ static const u32 ar5416Modes_9160[][6] = { { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, - { 0x00009850, 0x6d48b4e2, 0x6d48b4e2, 0x6d48b0e2, 0x6d48b0e2, 0x6d48b0e2 }, + { 0x00009850, 0x6c48b4e2, 0x6c48b4e2, 0x6c48b0e2, 0x6c48b0e2, 0x6c48b0e2 }, { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e }, - { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e }, + { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e }, { 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 }, { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, { 0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0 }, { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 }, - { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 }, + { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 }, { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 }, { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d }, - { 0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020 }, + { 0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020 }, { 0x00009960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 }, { 0x0000a960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 }, { 0x0000b960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 }, { 0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0x00001120 }, + { 0x0000c968, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce, 0x000003ce }, { 0x0000c9bc, 0x001a0600, 0x001a0600, 0x001a0c00, 0x001a0c00, 0x001a0c00 }, { 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be }, { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, @@ -1505,7 +1508,7 @@ static const u32 ar5416Common_9160[][2] = { { 0x00008134, 0x00000000 }, { 0x00008138, 0x00000000 }, { 0x0000813c, 0x00000000 }, - { 0x00008144, 0x00000000 }, + { 0x00008144, 0xffffffff }, { 0x00008168, 0x00000000 }, { 0x0000816c, 0x00000000 }, { 0x00008170, 0x32143320 }, @@ -1564,7 +1567,7 @@ static const u32 ar5416Common_9160[][2] = { { 0x0000832c, 0x00000007 }, { 0x00008330, 0x00000302 }, { 0x00008334, 0x00000e00 }, - { 0x00008338, 0x00000000 }, + { 0x00008338, 0x00ff0000 }, { 0x0000833c, 0x00000000 }, { 0x00008340, 0x000107ff }, { 0x00009808, 0x00000000 }, @@ -1597,7 +1600,6 @@ static const u32 ar5416Common_9160[][2] = { { 0x00009958, 0x2108ecff }, { 0x00009940, 0x00750604 }, { 0x0000c95c, 0x004b6a8e }, - { 0x0000c968, 0x000003ce }, { 0x00009970, 0x190fb515 }, { 0x00009974, 0x00000000 }, { 0x00009978, 0x00000001 }, @@ -1699,7 +1701,7 @@ static const u32 ar5416Common_9160[][2] = { { 0x0000a244, 0x00007bb6 }, { 0x0000a248, 0x0fff3ffc }, { 0x0000a24c, 0x00000001 }, - { 0x0000a250, 0x0000a000 }, + { 0x0000a250, 0x0000e000 }, { 0x0000a254, 0x00000000 }, { 0x0000a258, 0x0cc75380 }, { 0x0000a25c, 0x0f0f0f01 }, @@ -1719,7 +1721,7 @@ static const u32 ar5416Common_9160[][2] = { { 0x0000a34c, 0x3fffffff }, { 0x0000a350, 0x3fffffff }, { 0x0000a354, 0x0003ffff }, - { 0x0000a358, 0x79a8aa33 }, + { 0x0000a358, 0x79bfaa03 }, { 0x0000d35c, 0x07ffffef }, { 0x0000d360, 0x0fffffe7 }, { 0x0000d364, 0x17ffffe5 }, @@ -1842,7 +1844,6 @@ static const u32 ar5416Bank3_9160[][3] = { }; static const u32 ar5416Bank6_9160[][3] = { - { 0x0000989c, 0x00000000, 0x00000000 }, { 0x0000989c, 0x00000000, 0x00000000 }, { 0x0000989c, 0x00000000, 0x00000000 }, @@ -1920,7 +1921,6 @@ static const u32 ar5416Bank7_9160[][2] = { { 0x000098cc, 0x0000000e }, }; - static u32 ar5416Addac_9160[][2] = { {0x0000989c, 0x00000000 }, {0x0000989c, 0x00000000 }, @@ -1956,7 +1956,6 @@ static u32 ar5416Addac_9160[][2] = { {0x000098cc, 0x00000000 }, }; - static u32 ar5416Addac_91601_1[][2] = { {0x0000989c, 0x00000000 }, {0x0000989c, 0x00000000 }, @@ -1992,8 +1991,7 @@ static u32 ar5416Addac_91601_1[][2] = { {0x000098cc, 0x00000000 }, }; - - +/* XXX 9280 1 */ static const u32 ar9280Modes_9280[][6] = { { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, @@ -2543,9 +2541,7 @@ static const u32 ar9280Common_9280[][2] = { { 0x00007898, 0x2a850160 }, }; - - - +/* XXX 9280 2 */ static const u32 ar9280Modes_9280_2[][6] = { { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, @@ -2560,26 +2556,24 @@ static const u32 ar9280Modes_9280_2[][6] = { { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, - { 0x00009840, 0x206a012e, 0x206a012e, 0x206a022e, 0x206a022e, 0x206a022e }, + { 0x00009840, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e, 0x206a012e }, { 0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0 }, - { 0x00009848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 }, - { 0x0000a848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 }, - { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 }, - { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec88d2e, 0x7ec88d2e, 0x7ec88d2e }, - { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e }, + { 0x00009850, 0x6c4000e2, 0x6c4000e2, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2 }, + { 0x00009858, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e }, + { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x3139605e, 0x31395d5e, 0x31395d5e }, { 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 }, - { 0x0000c864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, + { 0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 }, { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 }, - { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 }, + { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 }, { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 }, - { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d }, - { 0x00009944, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010 }, + { 0x00009924, 0xd00a8a0b, 0xd00a8a0b, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d }, + { 0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010 }, { 0x00009960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 }, { 0x0000a960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 }, { 0x00009964, 0x00000210, 0x00000210, 0x00000210, 0x00000210, 0x00000210 }, - { 0x0000c9b8, 0x0000000f, 0x0000000f, 0x0000001c, 0x0000001c, 0x0000001c }, - { 0x0000c9bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 }, + { 0x000099b8, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c }, + { 0x000099bc, 0x00000a00, 0x00000a00, 0x00000c00, 0x00000c00, 0x00000c00 }, { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 }, { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 }, @@ -2587,164 +2581,13 @@ static const u32 ar9280Modes_9280_2[][6] = { { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290 }, - { 0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300 }, - { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304 }, - { 0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308 }, - { 0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c }, - { 0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000 }, - { 0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004 }, - { 0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008 }, - { 0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c }, - { 0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080 }, - { 0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084 }, - { 0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088 }, - { 0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c }, - { 0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100 }, - { 0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104 }, - { 0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108 }, - { 0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c }, - { 0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110 }, - { 0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114 }, - { 0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180 }, - { 0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184 }, - { 0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188 }, - { 0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c }, - { 0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190 }, - { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 }, - { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 }, - { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c }, - { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 }, - { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 }, - { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 }, - { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 }, - { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 }, - { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 }, - { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 }, - { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 }, - { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c }, - { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 }, - { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 }, - { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 }, - { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 }, - { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 }, - { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c }, - { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 }, - { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 }, - { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 }, - { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 }, - { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 }, - { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c }, - { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80 }, - { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84 }, - { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88 }, - { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c }, - { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90 }, - { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80 }, - { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84 }, - { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88 }, - { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c }, - { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90 }, - { 0x00009ae8, 0x0000b780, 0x0000b780, 0x0000930c, 0x0000930c, 0x0000930c }, - { 0x00009aec, 0x0000b784, 0x0000b784, 0x00009310, 0x00009310, 0x00009310 }, - { 0x00009af0, 0x0000b788, 0x0000b788, 0x00009384, 0x00009384, 0x00009384 }, - { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009388, 0x00009388, 0x00009388 }, - { 0x00009af8, 0x0000b790, 0x0000b790, 0x00009324, 0x00009324, 0x00009324 }, - { 0x00009afc, 0x0000b794, 0x0000b794, 0x00009704, 0x00009704, 0x00009704 }, - { 0x00009b00, 0x0000b798, 0x0000b798, 0x000096a4, 0x000096a4, 0x000096a4 }, - { 0x00009b04, 0x0000d784, 0x0000d784, 0x000096a8, 0x000096a8, 0x000096a8 }, - { 0x00009b08, 0x0000d788, 0x0000d788, 0x00009710, 0x00009710, 0x00009710 }, - { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009714, 0x00009714, 0x00009714 }, - { 0x00009b10, 0x0000d790, 0x0000d790, 0x00009720, 0x00009720, 0x00009720 }, - { 0x00009b14, 0x0000f780, 0x0000f780, 0x00009724, 0x00009724, 0x00009724 }, - { 0x00009b18, 0x0000f784, 0x0000f784, 0x00009728, 0x00009728, 0x00009728 }, - { 0x00009b1c, 0x0000f788, 0x0000f788, 0x0000972c, 0x0000972c, 0x0000972c }, - { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x000097a0, 0x000097a0, 0x000097a0 }, - { 0x00009b24, 0x0000f790, 0x0000f790, 0x000097a4, 0x000097a4, 0x000097a4 }, - { 0x00009b28, 0x0000f794, 0x0000f794, 0x000097a8, 0x000097a8, 0x000097a8 }, - { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x000097b0, 0x000097b0, 0x000097b0 }, - { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x000097b4, 0x000097b4, 0x000097b4 }, - { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x000097b8, 0x000097b8, 0x000097b8 }, - { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x000097a5, 0x000097a5, 0x000097a5 }, - { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x000097a9, 0x000097a9, 0x000097a9 }, - { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x000097ad, 0x000097ad, 0x000097ad }, - { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x000097b1, 0x000097b1, 0x000097b1 }, - { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x000097b5, 0x000097b5, 0x000097b5 }, - { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x000097b9, 0x000097b9, 0x000097b9 }, - { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x000097c5, 0x000097c5, 0x000097c5 }, - { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x000097c9, 0x000097c9, 0x000097c9 }, - { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x000097d1, 0x000097d1, 0x000097d1 }, - { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x000097d5, 0x000097d5, 0x000097d5 }, - { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x000097d9, 0x000097d9, 0x000097d9 }, - { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x000097c6, 0x000097c6, 0x000097c6 }, - { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x000097ca, 0x000097ca, 0x000097ca }, - { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x000097ce, 0x000097ce, 0x000097ce }, - { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x000097d2, 0x000097d2, 0x000097d2 }, - { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x000097d6, 0x000097d6, 0x000097d6 }, - { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x000097c3, 0x000097c3, 0x000097c3 }, - { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x000097c7, 0x000097c7, 0x000097c7 }, - { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x000097cb, 0x000097cb, 0x000097cb }, - { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x000097cf, 0x000097cf, 0x000097cf }, - { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x000097d7, 0x000097d7, 0x000097d7 }, - { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, { 0x0000a204, 0x00000444, 0x00000444, 0x00000444, 0x00000444, 0x00000444 }, - { 0x0000a208, 0x803e4788, 0x803e4788, 0x803e4788, 0x803e4788, 0x803e4788 }, { 0x0000a20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019 }, { 0x0000b20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019 }, - { 0x0000a21c, 0x1463800a, 0x1463800a, 0x1463800a, 0x1463800a, 0x1463800a }, + { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, - { 0x0000a250, 0x001ff000, 0x001ff000, 0x001da000, 0x001da000, 0x001da000 }, + { 0x0000a250, 0x001ff000, 0x001ff000, 0x0004a000, 0x0004a000, 0x0004a000 }, { 0x0000a274, 0x0a19c652, 0x0a19c652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 }, - { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a304, 0x00003002, 0x00003002, 0x00003002, 0x00003002, 0x00003002 }, - { 0x0000a308, 0x00006004, 0x00006004, 0x00008009, 0x00008009, 0x00008009 }, - { 0x0000a30c, 0x0000a006, 0x0000a006, 0x0000b00b, 0x0000b00b, 0x0000b00b }, - { 0x0000a310, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012 }, - { 0x0000a314, 0x00011014, 0x00011014, 0x00012048, 0x00012048, 0x00012048 }, - { 0x0000a318, 0x0001504a, 0x0001504a, 0x0001604a, 0x0001604a, 0x0001604a }, - { 0x0000a31c, 0x0001904c, 0x0001904c, 0x0001a211, 0x0001a211, 0x0001a211 }, - { 0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213 }, - { 0x0000a324, 0x00020092, 0x00020092, 0x0002121b, 0x0002121b, 0x0002121b }, - { 0x0000a328, 0x0002410a, 0x0002410a, 0x00024412, 0x00024412, 0x00024412 }, - { 0x0000a32c, 0x0002710c, 0x0002710c, 0x00028414, 0x00028414, 0x00028414 }, - { 0x0000a330, 0x0002b18b, 0x0002b18b, 0x0002b44a, 0x0002b44a, 0x0002b44a }, - { 0x0000a334, 0x0002e1cc, 0x0002e1cc, 0x00030649, 0x00030649, 0x00030649 }, - { 0x0000a338, 0x000321ec, 0x000321ec, 0x0003364b, 0x0003364b, 0x0003364b }, - { 0x0000a33c, 0x000321ec, 0x000321ec, 0x00038a49, 0x00038a49, 0x00038a49 }, - { 0x0000a340, 0x000321ec, 0x000321ec, 0x0003be48, 0x0003be48, 0x0003be48 }, - { 0x0000a344, 0x000321ec, 0x000321ec, 0x0003ee4a, 0x0003ee4a, 0x0003ee4a }, - { 0x0000a348, 0x000321ec, 0x000321ec, 0x00042e88, 0x00042e88, 0x00042e88 }, - { 0x0000a34c, 0x000321ec, 0x000321ec, 0x00046e8a, 0x00046e8a, 0x00046e8a }, - { 0x0000a350, 0x000321ec, 0x000321ec, 0x00049ec9, 0x00049ec9, 0x00049ec9 }, - { 0x0000a354, 0x000321ec, 0x000321ec, 0x0004bf42, 0x0004bf42, 0x0004bf42 }, { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e }, { 0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, { 0x00007894, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000 }, @@ -2884,7 +2727,7 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x00008134, 0x00000000 }, { 0x00008138, 0x00000000 }, { 0x0000813c, 0x00000000 }, - { 0x00008144, 0x00000000 }, + { 0x00008144, 0xffffffff }, { 0x00008168, 0x00000000 }, { 0x0000816c, 0x00000000 }, { 0x00008170, 0x32143320 }, @@ -2923,6 +2766,7 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x00008258, 0x00000000 }, { 0x0000825c, 0x400000ff }, { 0x00008260, 0x00080922 }, + { 0x00008264, 0xa8a00010 }, { 0x00008270, 0x00000000 }, { 0x00008274, 0x40000000 }, { 0x00008278, 0x003e4180 }, @@ -2939,7 +2783,7 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x0000832c, 0x00000007 }, { 0x00008330, 0x00000302 }, { 0x00008334, 0x00000e00 }, - { 0x00008338, 0x00000000 }, + { 0x00008338, 0x00ff0000 }, { 0x0000833c, 0x00000000 }, { 0x00008340, 0x000107ff }, { 0x00008344, 0x00581043 }, @@ -2973,7 +2817,7 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x00009958, 0x2108ecff }, { 0x00009940, 0x14750604 }, { 0x0000c95c, 0x004b6a8e }, - { 0x0000c968, 0x000003ce }, + { 0x00009968, 0x000003ce }, { 0x00009970, 0x190fb515 }, { 0x00009974, 0x00000000 }, { 0x00009978, 0x00000001 }, @@ -2999,13 +2843,14 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x000099ec, 0x0cc80caa }, { 0x000099f0, 0x00000000 }, { 0x000099fc, 0x00001042 }, + { 0x0000a208, 0x803e4788 }, { 0x0000a210, 0x4080a333 }, { 0x0000a214, 0x40206c10 }, { 0x0000a218, 0x009c4060 }, { 0x0000a220, 0x01834061 }, { 0x0000a224, 0x00000400 }, { 0x0000a228, 0x000003b5 }, - { 0x0000a22c, 0x233f71c0 }, + { 0x0000a22c, 0x233f7180 }, { 0x0000a234, 0x20202020 }, { 0x0000a238, 0x20202020 }, { 0x0000a23c, 0x13c88000 }, @@ -3022,7 +2867,6 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x0000b26c, 0x0ebae9c6 }, { 0x0000d270, 0x00820820 }, { 0x0000a278, 0x1ce739ce }, - { 0x0000a27c, 0x050701ce }, { 0x0000d35c, 0x07ffffef }, { 0x0000d360, 0x0fffffe7 }, { 0x0000d364, 0x17ffffe5 }, @@ -3064,7 +2908,6 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x00007808, 0x04924914 }, { 0x0000780c, 0x21084210 }, { 0x00007810, 0x6d801300 }, - { 0x00007814, 0x0019beff }, { 0x00007818, 0x07e41000 }, { 0x0000781c, 0x00392000 }, { 0x00007820, 0x92592480 }, @@ -3073,7 +2916,6 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x0000782c, 0x04924914 }, { 0x00007830, 0x21084210 }, { 0x00007834, 0x6d801300 }, - { 0x00007838, 0x0019beff }, { 0x0000783c, 0x07e40000 }, { 0x00007840, 0x00392000 }, { 0x00007844, 0x92592480 }, @@ -3110,36 +2952,1850 @@ static const u32 ar9280Modes_fast_clock_9280_2[][3] = { { 0x00009828, 0x0b020001, 0x0b020001 }, { 0x00009834, 0x00000f0f, 0x00000f0f }, { 0x00009844, 0x03721821, 0x03721821 }, - { 0x00009914, 0x00000898, 0x00000898 }, + { 0x00009914, 0x00000898, 0x00001130 }, { 0x00009918, 0x0000000b, 0x00000016 }, { 0x00009944, 0xdfbc1210, 0xdfbc1210 }, }; - - -static const u32 ar9280PciePhy_clkreq_off_L1_9280[][2] = { - {0x00004040, 0x9248fd00 }, - {0x00004040, 0x24924924 }, - {0x00004040, 0xa8000019 }, - {0x00004040, 0x13160820 }, - {0x00004040, 0xe5980560 }, - {0x00004040, 0x401dcffc }, - {0x00004040, 0x1aaabe40 }, - {0x00004040, 0xbe105554 }, - {0x00004040, 0x00043007 }, - {0x00004044, 0x00000000 }, +static const u32 ar9280Modes_backoff_23db_rxgain_9280_2[][6] = { + { 0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290 }, + { 0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300 }, + { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304 }, + { 0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308 }, + { 0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c }, + { 0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000 }, + { 0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004 }, + { 0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008 }, + { 0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c }, + { 0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080 }, + { 0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084 }, + { 0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088 }, + { 0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c }, + { 0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100 }, + { 0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104 }, + { 0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108 }, + { 0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c }, + { 0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110 }, + { 0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114 }, + { 0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180 }, + { 0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184 }, + { 0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188 }, + { 0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c }, + { 0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190 }, + { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 }, + { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 }, + { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c }, + { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 }, + { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 }, + { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 }, + { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 }, + { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 }, + { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 }, + { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 }, + { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 }, + { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c }, + { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 }, + { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 }, + { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 }, + { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 }, + { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 }, + { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c }, + { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 }, + { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 }, + { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 }, + { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 }, + { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 }, + { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c }, + { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b10, 0x00008b10, 0x00008b10 }, + { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b14, 0x00008b14, 0x00008b14 }, + { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b01, 0x00008b01, 0x00008b01 }, + { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b05, 0x00008b05, 0x00008b05 }, + { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b09, 0x00008b09, 0x00008b09 }, + { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008b0d, 0x00008b0d, 0x00008b0d }, + { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008b11, 0x00008b11, 0x00008b11 }, + { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008b15, 0x00008b15, 0x00008b15 }, + { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008b02, 0x00008b02, 0x00008b02 }, + { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008b06, 0x00008b06, 0x00008b06 }, + { 0x00009ae8, 0x0000b780, 0x0000b780, 0x00008b0a, 0x00008b0a, 0x00008b0a }, + { 0x00009aec, 0x0000b784, 0x0000b784, 0x00008b0e, 0x00008b0e, 0x00008b0e }, + { 0x00009af0, 0x0000b788, 0x0000b788, 0x00008b12, 0x00008b12, 0x00008b12 }, + { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00008b16, 0x00008b16, 0x00008b16 }, + { 0x00009af8, 0x0000b790, 0x0000b790, 0x00008b03, 0x00008b03, 0x00008b03 }, + { 0x00009afc, 0x0000b794, 0x0000b794, 0x00008b07, 0x00008b07, 0x00008b07 }, + { 0x00009b00, 0x0000b798, 0x0000b798, 0x00008b0b, 0x00008b0b, 0x00008b0b }, + { 0x00009b04, 0x0000d784, 0x0000d784, 0x00008b0f, 0x00008b0f, 0x00008b0f }, + { 0x00009b08, 0x0000d788, 0x0000d788, 0x00008b13, 0x00008b13, 0x00008b13 }, + { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00008b17, 0x00008b17, 0x00008b17 }, + { 0x00009b10, 0x0000d790, 0x0000d790, 0x00008b23, 0x00008b23, 0x00008b23 }, + { 0x00009b14, 0x0000f780, 0x0000f780, 0x00008b27, 0x00008b27, 0x00008b27 }, + { 0x00009b18, 0x0000f784, 0x0000f784, 0x00008b2b, 0x00008b2b, 0x00008b2b }, + { 0x00009b1c, 0x0000f788, 0x0000f788, 0x00008b2f, 0x00008b2f, 0x00008b2f }, + { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x00008b33, 0x00008b33, 0x00008b33 }, + { 0x00009b24, 0x0000f790, 0x0000f790, 0x00008b37, 0x00008b37, 0x00008b37 }, + { 0x00009b28, 0x0000f794, 0x0000f794, 0x00008b43, 0x00008b43, 0x00008b43 }, + { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x00008b47, 0x00008b47, 0x00008b47 }, + { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x00008b4b, 0x00008b4b, 0x00008b4b }, + { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x00008b4f, 0x00008b4f, 0x00008b4f }, + { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x00008b53, 0x00008b53, 0x00008b53 }, + { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x00008b57, 0x00008b57, 0x00008b57 }, + { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009848, 0x00001066, 0x00001066, 0x00001050, 0x00001050, 0x00001050 }, + { 0x0000a848, 0x00001066, 0x00001066, 0x00001050, 0x00001050, 0x00001050 }, }; - - -static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = { +static const u32 ar9280Modes_original_rxgain_9280_2[][6] = { + { 0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290 }, + { 0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300 }, + { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304 }, + { 0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308 }, + { 0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c }, + { 0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000 }, + { 0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004 }, + { 0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008 }, + { 0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c }, + { 0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080 }, + { 0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084 }, + { 0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088 }, + { 0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c }, + { 0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100 }, + { 0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104 }, + { 0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108 }, + { 0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c }, + { 0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110 }, + { 0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114 }, + { 0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180 }, + { 0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184 }, + { 0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188 }, + { 0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c }, + { 0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190 }, + { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 }, + { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 }, + { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c }, + { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 }, + { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 }, + { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 }, + { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 }, + { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 }, + { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 }, + { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 }, + { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 }, + { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c }, + { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 }, + { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 }, + { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 }, + { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 }, + { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 }, + { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c }, + { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 }, + { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 }, + { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 }, + { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 }, + { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 }, + { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c }, + { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80 }, + { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84 }, + { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88 }, + { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c }, + { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90 }, + { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80 }, + { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84 }, + { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88 }, + { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c }, + { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90 }, + { 0x00009ae8, 0x0000b780, 0x0000b780, 0x0000930c, 0x0000930c, 0x0000930c }, + { 0x00009aec, 0x0000b784, 0x0000b784, 0x00009310, 0x00009310, 0x00009310 }, + { 0x00009af0, 0x0000b788, 0x0000b788, 0x00009384, 0x00009384, 0x00009384 }, + { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009388, 0x00009388, 0x00009388 }, + { 0x00009af8, 0x0000b790, 0x0000b790, 0x00009324, 0x00009324, 0x00009324 }, + { 0x00009afc, 0x0000b794, 0x0000b794, 0x00009704, 0x00009704, 0x00009704 }, + { 0x00009b00, 0x0000b798, 0x0000b798, 0x000096a4, 0x000096a4, 0x000096a4 }, + { 0x00009b04, 0x0000d784, 0x0000d784, 0x000096a8, 0x000096a8, 0x000096a8 }, + { 0x00009b08, 0x0000d788, 0x0000d788, 0x00009710, 0x00009710, 0x00009710 }, + { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009714, 0x00009714, 0x00009714 }, + { 0x00009b10, 0x0000d790, 0x0000d790, 0x00009720, 0x00009720, 0x00009720 }, + { 0x00009b14, 0x0000f780, 0x0000f780, 0x00009724, 0x00009724, 0x00009724 }, + { 0x00009b18, 0x0000f784, 0x0000f784, 0x00009728, 0x00009728, 0x00009728 }, + { 0x00009b1c, 0x0000f788, 0x0000f788, 0x0000972c, 0x0000972c, 0x0000972c }, + { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x000097a0, 0x000097a0, 0x000097a0 }, + { 0x00009b24, 0x0000f790, 0x0000f790, 0x000097a4, 0x000097a4, 0x000097a4 }, + { 0x00009b28, 0x0000f794, 0x0000f794, 0x000097a8, 0x000097a8, 0x000097a8 }, + { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x000097b0, 0x000097b0, 0x000097b0 }, + { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x000097b4, 0x000097b4, 0x000097b4 }, + { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x000097b8, 0x000097b8, 0x000097b8 }, + { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x000097a5, 0x000097a5, 0x000097a5 }, + { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x000097a9, 0x000097a9, 0x000097a9 }, + { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x000097ad, 0x000097ad, 0x000097ad }, + { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x000097b1, 0x000097b1, 0x000097b1 }, + { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x000097b5, 0x000097b5, 0x000097b5 }, + { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x000097b9, 0x000097b9, 0x000097b9 }, + { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x000097c5, 0x000097c5, 0x000097c5 }, + { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x000097c9, 0x000097c9, 0x000097c9 }, + { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x000097d1, 0x000097d1, 0x000097d1 }, + { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x000097d5, 0x000097d5, 0x000097d5 }, + { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x000097d9, 0x000097d9, 0x000097d9 }, + { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x000097c6, 0x000097c6, 0x000097c6 }, + { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x000097ca, 0x000097ca, 0x000097ca }, + { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x000097ce, 0x000097ce, 0x000097ce }, + { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x000097d2, 0x000097d2, 0x000097d2 }, + { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x000097d6, 0x000097d6, 0x000097d6 }, + { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x000097c3, 0x000097c3, 0x000097c3 }, + { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x000097c7, 0x000097c7, 0x000097c7 }, + { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x000097cb, 0x000097cb, 0x000097cb }, + { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x000097cf, 0x000097cf, 0x000097cf }, + { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x000097d7, 0x000097d7, 0x000097d7 }, + { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 }, + { 0x0000a848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 }, +}; + +static const u32 ar9280Modes_backoff_13db_rxgain_9280_2[][6] = { + { 0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290 }, + { 0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300 }, + { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304 }, + { 0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308 }, + { 0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c }, + { 0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000 }, + { 0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004 }, + { 0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008 }, + { 0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c }, + { 0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080 }, + { 0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084 }, + { 0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088 }, + { 0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c }, + { 0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100 }, + { 0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104 }, + { 0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108 }, + { 0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c }, + { 0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110 }, + { 0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114 }, + { 0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180 }, + { 0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184 }, + { 0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188 }, + { 0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c }, + { 0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190 }, + { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 }, + { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 }, + { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c }, + { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 }, + { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 }, + { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 }, + { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 }, + { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 }, + { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 }, + { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 }, + { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 }, + { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c }, + { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 }, + { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 }, + { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 }, + { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 }, + { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 }, + { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c }, + { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 }, + { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 }, + { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 }, + { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 }, + { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 }, + { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c }, + { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80 }, + { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84 }, + { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88 }, + { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c }, + { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90 }, + { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80 }, + { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84 }, + { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88 }, + { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c }, + { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90 }, + { 0x00009ae8, 0x0000b780, 0x0000b780, 0x00009310, 0x00009310, 0x00009310 }, + { 0x00009aec, 0x0000b784, 0x0000b784, 0x00009314, 0x00009314, 0x00009314 }, + { 0x00009af0, 0x0000b788, 0x0000b788, 0x00009320, 0x00009320, 0x00009320 }, + { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009324, 0x00009324, 0x00009324 }, + { 0x00009af8, 0x0000b790, 0x0000b790, 0x00009328, 0x00009328, 0x00009328 }, + { 0x00009afc, 0x0000b794, 0x0000b794, 0x0000932c, 0x0000932c, 0x0000932c }, + { 0x00009b00, 0x0000b798, 0x0000b798, 0x00009330, 0x00009330, 0x00009330 }, + { 0x00009b04, 0x0000d784, 0x0000d784, 0x00009334, 0x00009334, 0x00009334 }, + { 0x00009b08, 0x0000d788, 0x0000d788, 0x00009321, 0x00009321, 0x00009321 }, + { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009325, 0x00009325, 0x00009325 }, + { 0x00009b10, 0x0000d790, 0x0000d790, 0x00009329, 0x00009329, 0x00009329 }, + { 0x00009b14, 0x0000f780, 0x0000f780, 0x0000932d, 0x0000932d, 0x0000932d }, + { 0x00009b18, 0x0000f784, 0x0000f784, 0x00009331, 0x00009331, 0x00009331 }, + { 0x00009b1c, 0x0000f788, 0x0000f788, 0x00009335, 0x00009335, 0x00009335 }, + { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x00009322, 0x00009322, 0x00009322 }, + { 0x00009b24, 0x0000f790, 0x0000f790, 0x00009326, 0x00009326, 0x00009326 }, + { 0x00009b28, 0x0000f794, 0x0000f794, 0x0000932a, 0x0000932a, 0x0000932a }, + { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x0000932e, 0x0000932e, 0x0000932e }, + { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x00009332, 0x00009332, 0x00009332 }, + { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x00009336, 0x00009336, 0x00009336 }, + { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x00009323, 0x00009323, 0x00009323 }, + { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x00009327, 0x00009327, 0x00009327 }, + { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x0000932b, 0x0000932b, 0x0000932b }, + { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x0000932f, 0x0000932f, 0x0000932f }, + { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x00009333, 0x00009333, 0x00009333 }, + { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x00009337, 0x00009337, 0x00009337 }, + { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x00009343, 0x00009343, 0x00009343 }, + { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x00009347, 0x00009347, 0x00009347 }, + { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x0000934b, 0x0000934b, 0x0000934b }, + { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x0000934f, 0x0000934f, 0x0000934f }, + { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x00009353, 0x00009353, 0x00009353 }, + { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x00009357, 0x00009357, 0x00009357 }, + { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009848, 0x00001066, 0x00001066, 0x0000105a, 0x0000105a, 0x0000105a }, + { 0x0000a848, 0x00001066, 0x00001066, 0x0000105a, 0x0000105a, 0x0000105a }, +}; + +static const u32 ar9280Modes_high_power_tx_gain_9280_2[][6] = { + { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a304, 0x00003002, 0x00003002, 0x00004002, 0x00004002, 0x00004002 }, + { 0x0000a308, 0x00006004, 0x00006004, 0x00007008, 0x00007008, 0x00007008 }, + { 0x0000a30c, 0x0000a006, 0x0000a006, 0x0000c010, 0x0000c010, 0x0000c010 }, + { 0x0000a310, 0x0000e012, 0x0000e012, 0x00010012, 0x00010012, 0x00010012 }, + { 0x0000a314, 0x00011014, 0x00011014, 0x00013014, 0x00013014, 0x00013014 }, + { 0x0000a318, 0x0001504a, 0x0001504a, 0x0001820a, 0x0001820a, 0x0001820a }, + { 0x0000a31c, 0x0001904c, 0x0001904c, 0x0001b211, 0x0001b211, 0x0001b211 }, + { 0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213 }, + { 0x0000a324, 0x00020092, 0x00020092, 0x00022411, 0x00022411, 0x00022411 }, + { 0x0000a328, 0x0002410a, 0x0002410a, 0x00025413, 0x00025413, 0x00025413 }, + { 0x0000a32c, 0x0002710c, 0x0002710c, 0x00029811, 0x00029811, 0x00029811 }, + { 0x0000a330, 0x0002b18b, 0x0002b18b, 0x0002c813, 0x0002c813, 0x0002c813 }, + { 0x0000a334, 0x0002e1cc, 0x0002e1cc, 0x00030a14, 0x00030a14, 0x00030a14 }, + { 0x0000a338, 0x000321ec, 0x000321ec, 0x00035a50, 0x00035a50, 0x00035a50 }, + { 0x0000a33c, 0x000321ec, 0x000321ec, 0x00039c4c, 0x00039c4c, 0x00039c4c }, + { 0x0000a340, 0x000321ec, 0x000321ec, 0x0003de8a, 0x0003de8a, 0x0003de8a }, + { 0x0000a344, 0x000321ec, 0x000321ec, 0x00042e92, 0x00042e92, 0x00042e92 }, + { 0x0000a348, 0x000321ec, 0x000321ec, 0x00046ed2, 0x00046ed2, 0x00046ed2 }, + { 0x0000a34c, 0x000321ec, 0x000321ec, 0x0004bed5, 0x0004bed5, 0x0004bed5 }, + { 0x0000a350, 0x000321ec, 0x000321ec, 0x0004ff54, 0x0004ff54, 0x0004ff54 }, + { 0x0000a354, 0x000321ec, 0x000321ec, 0x00053fd5, 0x00053fd5, 0x00053fd5 }, + { 0x00007814, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff }, + { 0x00007838, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff }, + { 0x0000a27c, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce }, +}; + +static const u32 ar9280Modes_original_tx_gain_9280_2[][6] = { + { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a304, 0x00003002, 0x00003002, 0x00003002, 0x00003002, 0x00003002 }, + { 0x0000a308, 0x00006004, 0x00006004, 0x00008009, 0x00008009, 0x00008009 }, + { 0x0000a30c, 0x0000a006, 0x0000a006, 0x0000b00b, 0x0000b00b, 0x0000b00b }, + { 0x0000a310, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012 }, + { 0x0000a314, 0x00011014, 0x00011014, 0x00012048, 0x00012048, 0x00012048 }, + { 0x0000a318, 0x0001504a, 0x0001504a, 0x0001604a, 0x0001604a, 0x0001604a }, + { 0x0000a31c, 0x0001904c, 0x0001904c, 0x0001a211, 0x0001a211, 0x0001a211 }, + { 0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213 }, + { 0x0000a324, 0x00020092, 0x00020092, 0x0002121b, 0x0002121b, 0x0002121b }, + { 0x0000a328, 0x0002410a, 0x0002410a, 0x00024412, 0x00024412, 0x00024412 }, + { 0x0000a32c, 0x0002710c, 0x0002710c, 0x00028414, 0x00028414, 0x00028414 }, + { 0x0000a330, 0x0002b18b, 0x0002b18b, 0x0002b44a, 0x0002b44a, 0x0002b44a }, + { 0x0000a334, 0x0002e1cc, 0x0002e1cc, 0x00030649, 0x00030649, 0x00030649 }, + { 0x0000a338, 0x000321ec, 0x000321ec, 0x0003364b, 0x0003364b, 0x0003364b }, + { 0x0000a33c, 0x000321ec, 0x000321ec, 0x00038a49, 0x00038a49, 0x00038a49 }, + { 0x0000a340, 0x000321ec, 0x000321ec, 0x0003be48, 0x0003be48, 0x0003be48 }, + { 0x0000a344, 0x000321ec, 0x000321ec, 0x0003ee4a, 0x0003ee4a, 0x0003ee4a }, + { 0x0000a348, 0x000321ec, 0x000321ec, 0x00042e88, 0x00042e88, 0x00042e88 }, + { 0x0000a34c, 0x000321ec, 0x000321ec, 0x00046e8a, 0x00046e8a, 0x00046e8a }, + { 0x0000a350, 0x000321ec, 0x000321ec, 0x00049ec9, 0x00049ec9, 0x00049ec9 }, + { 0x0000a354, 0x000321ec, 0x000321ec, 0x0004bf42, 0x0004bf42, 0x0004bf42 }, + { 0x00007814, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff }, + { 0x00007838, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff }, + { 0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce }, +}; + +static const u32 ar9280PciePhy_clkreq_off_L1_9280[][2] = { + {0x00004040, 0x9248fd00 }, + {0x00004040, 0x24924924 }, + {0x00004040, 0xa8000019 }, + {0x00004040, 0x13160820 }, + {0x00004040, 0xe5980560 }, + {0x00004040, 0xc01dcffc }, + {0x00004040, 0x1aaabe41 }, + {0x00004040, 0xbe105554 }, + {0x00004040, 0x00043007 }, + {0x00004044, 0x00000000 }, +}; + +static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = { + {0x00004040, 0x9248fd00 }, + {0x00004040, 0x24924924 }, + {0x00004040, 0xa8000019 }, + {0x00004040, 0x13160820 }, + {0x00004040, 0xe5980560 }, + {0x00004040, 0xc01dcffd }, + {0x00004040, 0x1aaabe41 }, + {0x00004040, 0xbe105554 }, + {0x00004040, 0x00043007 }, + {0x00004044, 0x00000000 }, +}; + +/* AR9285 */ +static const u_int32_t ar9285Modes_9285[][6] = { + { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, + { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, + { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, + { 0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 }, + { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 }, + { 0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f }, + { 0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880 }, + { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, + { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, + { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, + { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, + { 0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e }, + { 0x00009844, 0x0372161e, 0x0372161e, 0x03720020, 0x03720020, 0x037216a0 }, + { 0x00009848, 0x00001066, 0x00001066, 0x0000004e, 0x0000004e, 0x00001059 }, + { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 }, + { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e }, + { 0x0000985c, 0x3139605e, 0x3139605e, 0x3136605e, 0x3136605e, 0x3139605e }, + { 0x00009860, 0x00058d18, 0x00058d18, 0x00058d20, 0x00058d20, 0x00058d18 }, + { 0x00009864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, + { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 }, + { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 }, + { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 }, + { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 }, + { 0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d }, + { 0x00009944, 0xdfbc1010, 0xdfbc1010, 0xdfbc1020, 0xdfbc1020, 0xdfbc1010 }, + { 0x00009960, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x00009964, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x000099b8, 0x00cf4d1c, 0x00cf4d1c, 0x00cf4d1c, 0x00cf4d1c, 0x00cf4d1c }, + { 0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 }, + { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 }, + { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, + { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 }, + { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 }, + { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, + { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x00009a00, 0x00000000, 0x00000000, 0x00068084, 0x00068084, 0x00000000 }, + { 0x00009a04, 0x00000000, 0x00000000, 0x00068088, 0x00068088, 0x00000000 }, + { 0x00009a08, 0x00000000, 0x00000000, 0x0006808c, 0x0006808c, 0x00000000 }, + { 0x00009a0c, 0x00000000, 0x00000000, 0x00068100, 0x00068100, 0x00000000 }, + { 0x00009a10, 0x00000000, 0x00000000, 0x00068104, 0x00068104, 0x00000000 }, + { 0x00009a14, 0x00000000, 0x00000000, 0x00068108, 0x00068108, 0x00000000 }, + { 0x00009a18, 0x00000000, 0x00000000, 0x0006810c, 0x0006810c, 0x00000000 }, + { 0x00009a1c, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 }, + { 0x00009a20, 0x00000000, 0x00000000, 0x00068114, 0x00068114, 0x00000000 }, + { 0x00009a24, 0x00000000, 0x00000000, 0x00068180, 0x00068180, 0x00000000 }, + { 0x00009a28, 0x00000000, 0x00000000, 0x00068184, 0x00068184, 0x00000000 }, + { 0x00009a2c, 0x00000000, 0x00000000, 0x00068188, 0x00068188, 0x00000000 }, + { 0x00009a30, 0x00000000, 0x00000000, 0x0006818c, 0x0006818c, 0x00000000 }, + { 0x00009a34, 0x00000000, 0x00000000, 0x00068190, 0x00068190, 0x00000000 }, + { 0x00009a38, 0x00000000, 0x00000000, 0x00068194, 0x00068194, 0x00000000 }, + { 0x00009a3c, 0x00000000, 0x00000000, 0x000681a0, 0x000681a0, 0x00000000 }, + { 0x00009a40, 0x00000000, 0x00000000, 0x0006820c, 0x0006820c, 0x00000000 }, + { 0x00009a44, 0x00000000, 0x00000000, 0x000681a8, 0x000681a8, 0x00000000 }, + { 0x00009a48, 0x00000000, 0x00000000, 0x00068284, 0x00068284, 0x00000000 }, + { 0x00009a4c, 0x00000000, 0x00000000, 0x00068288, 0x00068288, 0x00000000 }, + { 0x00009a50, 0x00000000, 0x00000000, 0x00068220, 0x00068220, 0x00000000 }, + { 0x00009a54, 0x00000000, 0x00000000, 0x00068290, 0x00068290, 0x00000000 }, + { 0x00009a58, 0x00000000, 0x00000000, 0x00068300, 0x00068300, 0x00000000 }, + { 0x00009a5c, 0x00000000, 0x00000000, 0x00068304, 0x00068304, 0x00000000 }, + { 0x00009a60, 0x00000000, 0x00000000, 0x00068308, 0x00068308, 0x00000000 }, + { 0x00009a64, 0x00000000, 0x00000000, 0x0006830c, 0x0006830c, 0x00000000 }, + { 0x00009a68, 0x00000000, 0x00000000, 0x00068380, 0x00068380, 0x00000000 }, + { 0x00009a6c, 0x00000000, 0x00000000, 0x00068384, 0x00068384, 0x00000000 }, + { 0x00009a70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000 }, + { 0x00009a74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000 }, + { 0x00009a78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000 }, + { 0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 }, + { 0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 }, + { 0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 }, + { 0x00009a88, 0x00000000, 0x00000000, 0x00068b04, 0x00068b04, 0x00000000 }, + { 0x00009a8c, 0x00000000, 0x00000000, 0x00068b08, 0x00068b08, 0x00000000 }, + { 0x00009a90, 0x00000000, 0x00000000, 0x00068b08, 0x00068b08, 0x00000000 }, + { 0x00009a94, 0x00000000, 0x00000000, 0x00068b0c, 0x00068b0c, 0x00000000 }, + { 0x00009a98, 0x00000000, 0x00000000, 0x00068b80, 0x00068b80, 0x00000000 }, + { 0x00009a9c, 0x00000000, 0x00000000, 0x00068b84, 0x00068b84, 0x00000000 }, + { 0x00009aa0, 0x00000000, 0x00000000, 0x00068b88, 0x00068b88, 0x00000000 }, + { 0x00009aa4, 0x00000000, 0x00000000, 0x00068b8c, 0x00068b8c, 0x00000000 }, + { 0x00009aa8, 0x00000000, 0x00000000, 0x000b8b90, 0x000b8b90, 0x00000000 }, + { 0x00009aac, 0x00000000, 0x00000000, 0x000b8f80, 0x000b8f80, 0x00000000 }, + { 0x00009ab0, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 }, + { 0x00009ab4, 0x00000000, 0x00000000, 0x000b8f88, 0x000b8f88, 0x00000000 }, + { 0x00009ab8, 0x00000000, 0x00000000, 0x000b8f8c, 0x000b8f8c, 0x00000000 }, + { 0x00009abc, 0x00000000, 0x00000000, 0x000b8f90, 0x000b8f90, 0x00000000 }, + { 0x00009ac0, 0x00000000, 0x00000000, 0x000bb30c, 0x000bb30c, 0x00000000 }, + { 0x00009ac4, 0x00000000, 0x00000000, 0x000bb310, 0x000bb310, 0x00000000 }, + { 0x00009ac8, 0x00000000, 0x00000000, 0x000bb384, 0x000bb384, 0x00000000 }, + { 0x00009acc, 0x00000000, 0x00000000, 0x000bb388, 0x000bb388, 0x00000000 }, + { 0x00009ad0, 0x00000000, 0x00000000, 0x000bb324, 0x000bb324, 0x00000000 }, + { 0x00009ad4, 0x00000000, 0x00000000, 0x000bb704, 0x000bb704, 0x00000000 }, + { 0x00009ad8, 0x00000000, 0x00000000, 0x000f96a4, 0x000f96a4, 0x00000000 }, + { 0x00009adc, 0x00000000, 0x00000000, 0x000f96a8, 0x000f96a8, 0x00000000 }, + { 0x00009ae0, 0x00000000, 0x00000000, 0x000f9710, 0x000f9710, 0x00000000 }, + { 0x00009ae4, 0x00000000, 0x00000000, 0x000f9714, 0x000f9714, 0x00000000 }, + { 0x00009ae8, 0x00000000, 0x00000000, 0x000f9720, 0x000f9720, 0x00000000 }, + { 0x00009aec, 0x00000000, 0x00000000, 0x000f9724, 0x000f9724, 0x00000000 }, + { 0x00009af0, 0x00000000, 0x00000000, 0x000f9728, 0x000f9728, 0x00000000 }, + { 0x00009af4, 0x00000000, 0x00000000, 0x000f972c, 0x000f972c, 0x00000000 }, + { 0x00009af8, 0x00000000, 0x00000000, 0x000f97a0, 0x000f97a0, 0x00000000 }, + { 0x00009afc, 0x00000000, 0x00000000, 0x000f97a4, 0x000f97a4, 0x00000000 }, + { 0x00009b00, 0x00000000, 0x00000000, 0x000fb7a8, 0x000fb7a8, 0x00000000 }, + { 0x00009b04, 0x00000000, 0x00000000, 0x000fb7b0, 0x000fb7b0, 0x00000000 }, + { 0x00009b08, 0x00000000, 0x00000000, 0x000fb7b4, 0x000fb7b4, 0x00000000 }, + { 0x00009b0c, 0x00000000, 0x00000000, 0x000fb7b8, 0x000fb7b8, 0x00000000 }, + { 0x00009b10, 0x00000000, 0x00000000, 0x000fb7a5, 0x000fb7a5, 0x00000000 }, + { 0x00009b14, 0x00000000, 0x00000000, 0x000fb7a9, 0x000fb7a9, 0x00000000 }, + { 0x00009b18, 0x00000000, 0x00000000, 0x000fb7ad, 0x000fb7ad, 0x00000000 }, + { 0x00009b1c, 0x00000000, 0x00000000, 0x000fb7b1, 0x000fb7b1, 0x00000000 }, + { 0x00009b20, 0x00000000, 0x00000000, 0x000fb7b5, 0x000fb7b5, 0x00000000 }, + { 0x00009b24, 0x00000000, 0x00000000, 0x000fb7b9, 0x000fb7b9, 0x00000000 }, + { 0x00009b28, 0x00000000, 0x00000000, 0x000fb7c5, 0x000fb7c5, 0x00000000 }, + { 0x00009b2c, 0x00000000, 0x00000000, 0x000fb7c9, 0x000fb7c9, 0x00000000 }, + { 0x00009b30, 0x00000000, 0x00000000, 0x000fb7d1, 0x000fb7d1, 0x00000000 }, + { 0x00009b34, 0x00000000, 0x00000000, 0x000fb7d5, 0x000fb7d5, 0x00000000 }, + { 0x00009b38, 0x00000000, 0x00000000, 0x000fb7d9, 0x000fb7d9, 0x00000000 }, + { 0x00009b3c, 0x00000000, 0x00000000, 0x000fb7c6, 0x000fb7c6, 0x00000000 }, + { 0x00009b40, 0x00000000, 0x00000000, 0x000fb7ca, 0x000fb7ca, 0x00000000 }, + { 0x00009b44, 0x00000000, 0x00000000, 0x000fb7ce, 0x000fb7ce, 0x00000000 }, + { 0x00009b48, 0x00000000, 0x00000000, 0x000fb7d2, 0x000fb7d2, 0x00000000 }, + { 0x00009b4c, 0x00000000, 0x00000000, 0x000fb7d6, 0x000fb7d6, 0x00000000 }, + { 0x00009b50, 0x00000000, 0x00000000, 0x000fb7c3, 0x000fb7c3, 0x00000000 }, + { 0x00009b54, 0x00000000, 0x00000000, 0x000fb7c7, 0x000fb7c7, 0x00000000 }, + { 0x00009b58, 0x00000000, 0x00000000, 0x000fb7cb, 0x000fb7cb, 0x00000000 }, + { 0x00009b5c, 0x00000000, 0x00000000, 0x000fb7cf, 0x000fb7cf, 0x00000000 }, + { 0x00009b60, 0x00000000, 0x00000000, 0x000fb7d7, 0x000fb7d7, 0x00000000 }, + { 0x00009b64, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b68, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b6c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b70, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b74, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b78, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b7c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b80, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b84, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b88, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b8c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b90, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b94, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b98, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b9c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009ba0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009ba4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009ba8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bac, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bb0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bb4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bb8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bbc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bc0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bc4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bc8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bcc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bd0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bd4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bd8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bdc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009be0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009be4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009be8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bec, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bf0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bf4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bf8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bfc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x0000aa00, 0x00000000, 0x00000000, 0x0006801c, 0x0006801c, 0x00000000 }, + { 0x0000aa04, 0x00000000, 0x00000000, 0x00068080, 0x00068080, 0x00000000 }, + { 0x0000aa08, 0x00000000, 0x00000000, 0x00068084, 0x00068084, 0x00000000 }, + { 0x0000aa0c, 0x00000000, 0x00000000, 0x00068088, 0x00068088, 0x00000000 }, + { 0x0000aa10, 0x00000000, 0x00000000, 0x0006808c, 0x0006808c, 0x00000000 }, + { 0x0000aa14, 0x00000000, 0x00000000, 0x00068100, 0x00068100, 0x00000000 }, + { 0x0000aa18, 0x00000000, 0x00000000, 0x00068104, 0x00068104, 0x00000000 }, + { 0x0000aa1c, 0x00000000, 0x00000000, 0x00068108, 0x00068108, 0x00000000 }, + { 0x0000aa20, 0x00000000, 0x00000000, 0x0006810c, 0x0006810c, 0x00000000 }, + { 0x0000aa24, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 }, + { 0x0000aa28, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 }, + { 0x0000aa2c, 0x00000000, 0x00000000, 0x00068180, 0x00068180, 0x00000000 }, + { 0x0000aa30, 0x00000000, 0x00000000, 0x00068184, 0x00068184, 0x00000000 }, + { 0x0000aa34, 0x00000000, 0x00000000, 0x00068188, 0x00068188, 0x00000000 }, + { 0x0000aa38, 0x00000000, 0x00000000, 0x0006818c, 0x0006818c, 0x00000000 }, + { 0x0000aa3c, 0x00000000, 0x00000000, 0x00068190, 0x00068190, 0x00000000 }, + { 0x0000aa40, 0x00000000, 0x00000000, 0x00068194, 0x00068194, 0x00000000 }, + { 0x0000aa44, 0x00000000, 0x00000000, 0x000681a0, 0x000681a0, 0x00000000 }, + { 0x0000aa48, 0x00000000, 0x00000000, 0x0006820c, 0x0006820c, 0x00000000 }, + { 0x0000aa4c, 0x00000000, 0x00000000, 0x000681a8, 0x000681a8, 0x00000000 }, + { 0x0000aa50, 0x00000000, 0x00000000, 0x000681ac, 0x000681ac, 0x00000000 }, + { 0x0000aa54, 0x00000000, 0x00000000, 0x0006821c, 0x0006821c, 0x00000000 }, + { 0x0000aa58, 0x00000000, 0x00000000, 0x00068224, 0x00068224, 0x00000000 }, + { 0x0000aa5c, 0x00000000, 0x00000000, 0x00068290, 0x00068290, 0x00000000 }, + { 0x0000aa60, 0x00000000, 0x00000000, 0x00068300, 0x00068300, 0x00000000 }, + { 0x0000aa64, 0x00000000, 0x00000000, 0x00068308, 0x00068308, 0x00000000 }, + { 0x0000aa68, 0x00000000, 0x00000000, 0x0006830c, 0x0006830c, 0x00000000 }, + { 0x0000aa6c, 0x00000000, 0x00000000, 0x00068310, 0x00068310, 0x00000000 }, + { 0x0000aa70, 0x00000000, 0x00000000, 0x00068788, 0x00068788, 0x00000000 }, + { 0x0000aa74, 0x00000000, 0x00000000, 0x0006878c, 0x0006878c, 0x00000000 }, + { 0x0000aa78, 0x00000000, 0x00000000, 0x00068790, 0x00068790, 0x00000000 }, + { 0x0000aa7c, 0x00000000, 0x00000000, 0x00068794, 0x00068794, 0x00000000 }, + { 0x0000aa80, 0x00000000, 0x00000000, 0x00068798, 0x00068798, 0x00000000 }, + { 0x0000aa84, 0x00000000, 0x00000000, 0x0006879c, 0x0006879c, 0x00000000 }, + { 0x0000aa88, 0x00000000, 0x00000000, 0x00068b89, 0x00068b89, 0x00000000 }, + { 0x0000aa8c, 0x00000000, 0x00000000, 0x00068b8d, 0x00068b8d, 0x00000000 }, + { 0x0000aa90, 0x00000000, 0x00000000, 0x00068b91, 0x00068b91, 0x00000000 }, + { 0x0000aa94, 0x00000000, 0x00000000, 0x00068b95, 0x00068b95, 0x00000000 }, + { 0x0000aa98, 0x00000000, 0x00000000, 0x00068b99, 0x00068b99, 0x00000000 }, + { 0x0000aa9c, 0x00000000, 0x00000000, 0x00068ba5, 0x00068ba5, 0x00000000 }, + { 0x0000aaa0, 0x00000000, 0x00000000, 0x00068ba9, 0x00068ba9, 0x00000000 }, + { 0x0000aaa4, 0x00000000, 0x00000000, 0x00068bad, 0x00068bad, 0x00000000 }, + { 0x0000aaa8, 0x00000000, 0x00000000, 0x000b8b0c, 0x000b8b0c, 0x00000000 }, + { 0x0000aaac, 0x00000000, 0x00000000, 0x000b8f10, 0x000b8f10, 0x00000000 }, + { 0x0000aab0, 0x00000000, 0x00000000, 0x000b8f14, 0x000b8f14, 0x00000000 }, + { 0x0000aab4, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 }, + { 0x0000aab8, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 }, + { 0x0000aabc, 0x00000000, 0x00000000, 0x000b8f88, 0x000b8f88, 0x00000000 }, + { 0x0000aac0, 0x00000000, 0x00000000, 0x000bb380, 0x000bb380, 0x00000000 }, + { 0x0000aac4, 0x00000000, 0x00000000, 0x000bb384, 0x000bb384, 0x00000000 }, + { 0x0000aac8, 0x00000000, 0x00000000, 0x000bb388, 0x000bb388, 0x00000000 }, + { 0x0000aacc, 0x00000000, 0x00000000, 0x000bb38c, 0x000bb38c, 0x00000000 }, + { 0x0000aad0, 0x00000000, 0x00000000, 0x000bb394, 0x000bb394, 0x00000000 }, + { 0x0000aad4, 0x00000000, 0x00000000, 0x000bb798, 0x000bb798, 0x00000000 }, + { 0x0000aad8, 0x00000000, 0x00000000, 0x000f970c, 0x000f970c, 0x00000000 }, + { 0x0000aadc, 0x00000000, 0x00000000, 0x000f9710, 0x000f9710, 0x00000000 }, + { 0x0000aae0, 0x00000000, 0x00000000, 0x000f9714, 0x000f9714, 0x00000000 }, + { 0x0000aae4, 0x00000000, 0x00000000, 0x000f9718, 0x000f9718, 0x00000000 }, + { 0x0000aae8, 0x00000000, 0x00000000, 0x000f9705, 0x000f9705, 0x00000000 }, + { 0x0000aaec, 0x00000000, 0x00000000, 0x000f9709, 0x000f9709, 0x00000000 }, + { 0x0000aaf0, 0x00000000, 0x00000000, 0x000f970d, 0x000f970d, 0x00000000 }, + { 0x0000aaf4, 0x00000000, 0x00000000, 0x000f9711, 0x000f9711, 0x00000000 }, + { 0x0000aaf8, 0x00000000, 0x00000000, 0x000f9715, 0x000f9715, 0x00000000 }, + { 0x0000aafc, 0x00000000, 0x00000000, 0x000f9719, 0x000f9719, 0x00000000 }, + { 0x0000ab00, 0x00000000, 0x00000000, 0x000fb7a4, 0x000fb7a4, 0x00000000 }, + { 0x0000ab04, 0x00000000, 0x00000000, 0x000fb7a8, 0x000fb7a8, 0x00000000 }, + { 0x0000ab08, 0x00000000, 0x00000000, 0x000fb7ac, 0x000fb7ac, 0x00000000 }, + { 0x0000ab0c, 0x00000000, 0x00000000, 0x000fb7ac, 0x000fb7ac, 0x00000000 }, + { 0x0000ab10, 0x00000000, 0x00000000, 0x000fb7b0, 0x000fb7b0, 0x00000000 }, + { 0x0000ab14, 0x00000000, 0x00000000, 0x000fb7b8, 0x000fb7b8, 0x00000000 }, + { 0x0000ab18, 0x00000000, 0x00000000, 0x000fb7bc, 0x000fb7bc, 0x00000000 }, + { 0x0000ab1c, 0x00000000, 0x00000000, 0x000fb7a1, 0x000fb7a1, 0x00000000 }, + { 0x0000ab20, 0x00000000, 0x00000000, 0x000fb7a5, 0x000fb7a5, 0x00000000 }, + { 0x0000ab24, 0x00000000, 0x00000000, 0x000fb7a9, 0x000fb7a9, 0x00000000 }, + { 0x0000ab28, 0x00000000, 0x00000000, 0x000fb7b1, 0x000fb7b1, 0x00000000 }, + { 0x0000ab2c, 0x00000000, 0x00000000, 0x000fb7b5, 0x000fb7b5, 0x00000000 }, + { 0x0000ab30, 0x00000000, 0x00000000, 0x000fb7bd, 0x000fb7bd, 0x00000000 }, + { 0x0000ab34, 0x00000000, 0x00000000, 0x000fb7c9, 0x000fb7c9, 0x00000000 }, + { 0x0000ab38, 0x00000000, 0x00000000, 0x000fb7cd, 0x000fb7cd, 0x00000000 }, + { 0x0000ab3c, 0x00000000, 0x00000000, 0x000fb7d1, 0x000fb7d1, 0x00000000 }, + { 0x0000ab40, 0x00000000, 0x00000000, 0x000fb7d9, 0x000fb7d9, 0x00000000 }, + { 0x0000ab44, 0x00000000, 0x00000000, 0x000fb7c2, 0x000fb7c2, 0x00000000 }, + { 0x0000ab48, 0x00000000, 0x00000000, 0x000fb7c6, 0x000fb7c6, 0x00000000 }, + { 0x0000ab4c, 0x00000000, 0x00000000, 0x000fb7ca, 0x000fb7ca, 0x00000000 }, + { 0x0000ab50, 0x00000000, 0x00000000, 0x000fb7ce, 0x000fb7ce, 0x00000000 }, + { 0x0000ab54, 0x00000000, 0x00000000, 0x000fb7d2, 0x000fb7d2, 0x00000000 }, + { 0x0000ab58, 0x00000000, 0x00000000, 0x000fb7d6, 0x000fb7d6, 0x00000000 }, + { 0x0000ab5c, 0x00000000, 0x00000000, 0x000fb7c3, 0x000fb7c3, 0x00000000 }, + { 0x0000ab60, 0x00000000, 0x00000000, 0x000fb7cb, 0x000fb7cb, 0x00000000 }, + { 0x0000ab64, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab68, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab6c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab70, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab74, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab78, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab7c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab80, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab84, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab88, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab8c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab90, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab94, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab98, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab9c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000aba0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000aba4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000aba8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abac, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abb0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abb4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abb8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abbc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abc0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abc4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abc8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abcc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abd0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abd4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abd8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abdc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abe0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abe4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abe8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abec, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abf0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abf4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abf8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abfc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 }, + { 0x0000a20c, 0x00000014, 0x00000014, 0x00000000, 0x00000000, 0x0001f000 }, + { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, + { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, + { 0x0000a250, 0x001ff000, 0x001ff000, 0x001ca000, 0x001ca000, 0x001da000 }, + { 0x0000a274, 0x0a81c652, 0x0a81c652, 0x0a820652, 0x0a820652, 0x0a82a652 }, + { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a304, 0x00000000, 0x00000000, 0x00007201, 0x00007201, 0x00000000 }, + { 0x0000a308, 0x00000000, 0x00000000, 0x00010408, 0x00010408, 0x00000000 }, + { 0x0000a30c, 0x00000000, 0x00000000, 0x0001860a, 0x0001860a, 0x00000000 }, + { 0x0000a310, 0x00000000, 0x00000000, 0x00020818, 0x00020818, 0x00000000 }, + { 0x0000a314, 0x00000000, 0x00000000, 0x00024858, 0x00024858, 0x00000000 }, + { 0x0000a318, 0x00000000, 0x00000000, 0x00026859, 0x00026859, 0x00000000 }, + { 0x0000a31c, 0x00000000, 0x00000000, 0x0002985b, 0x0002985b, 0x00000000 }, + { 0x0000a320, 0x00000000, 0x00000000, 0x0002c89a, 0x0002c89a, 0x00000000 }, + { 0x0000a324, 0x00000000, 0x00000000, 0x0002e89b, 0x0002e89b, 0x00000000 }, + { 0x0000a328, 0x00000000, 0x00000000, 0x0003089c, 0x0003089c, 0x00000000 }, + { 0x0000a32c, 0x00000000, 0x00000000, 0x0003289d, 0x0003289d, 0x00000000 }, + { 0x0000a330, 0x00000000, 0x00000000, 0x0003489e, 0x0003489e, 0x00000000 }, + { 0x0000a334, 0x00000000, 0x00000000, 0x000388de, 0x000388de, 0x00000000 }, + { 0x0000a338, 0x00000000, 0x00000000, 0x0003b91e, 0x0003b91e, 0x00000000 }, + { 0x0000a33c, 0x00000000, 0x00000000, 0x0003d95e, 0x0003d95e, 0x00000000 }, + { 0x0000a340, 0x00000000, 0x00000000, 0x000419df, 0x000419df, 0x00000000 }, + { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e }, +}; + +static const u_int32_t ar9285Common_9285[][2] = { + { 0x0000000c, 0x00000000 }, + { 0x00000030, 0x00020045 }, + { 0x00000034, 0x00000005 }, + { 0x00000040, 0x00000000 }, + { 0x00000044, 0x00000008 }, + { 0x00000048, 0x00000008 }, + { 0x0000004c, 0x00000010 }, + { 0x00000050, 0x00000000 }, + { 0x00000054, 0x0000001f }, + { 0x00000800, 0x00000000 }, + { 0x00000804, 0x00000000 }, + { 0x00000808, 0x00000000 }, + { 0x0000080c, 0x00000000 }, + { 0x00000810, 0x00000000 }, + { 0x00000814, 0x00000000 }, + { 0x00000818, 0x00000000 }, + { 0x0000081c, 0x00000000 }, + { 0x00000820, 0x00000000 }, + { 0x00000824, 0x00000000 }, + { 0x00001040, 0x002ffc0f }, + { 0x00001044, 0x002ffc0f }, + { 0x00001048, 0x002ffc0f }, + { 0x0000104c, 0x002ffc0f }, + { 0x00001050, 0x002ffc0f }, + { 0x00001054, 0x002ffc0f }, + { 0x00001058, 0x002ffc0f }, + { 0x0000105c, 0x002ffc0f }, + { 0x00001060, 0x002ffc0f }, + { 0x00001064, 0x002ffc0f }, + { 0x00001230, 0x00000000 }, + { 0x00001270, 0x00000000 }, + { 0x00001038, 0x00000000 }, + { 0x00001078, 0x00000000 }, + { 0x000010b8, 0x00000000 }, + { 0x000010f8, 0x00000000 }, + { 0x00001138, 0x00000000 }, + { 0x00001178, 0x00000000 }, + { 0x000011b8, 0x00000000 }, + { 0x000011f8, 0x00000000 }, + { 0x00001238, 0x00000000 }, + { 0x00001278, 0x00000000 }, + { 0x000012b8, 0x00000000 }, + { 0x000012f8, 0x00000000 }, + { 0x00001338, 0x00000000 }, + { 0x00001378, 0x00000000 }, + { 0x000013b8, 0x00000000 }, + { 0x000013f8, 0x00000000 }, + { 0x00001438, 0x00000000 }, + { 0x00001478, 0x00000000 }, + { 0x000014b8, 0x00000000 }, + { 0x000014f8, 0x00000000 }, + { 0x00001538, 0x00000000 }, + { 0x00001578, 0x00000000 }, + { 0x000015b8, 0x00000000 }, + { 0x000015f8, 0x00000000 }, + { 0x00001638, 0x00000000 }, + { 0x00001678, 0x00000000 }, + { 0x000016b8, 0x00000000 }, + { 0x000016f8, 0x00000000 }, + { 0x00001738, 0x00000000 }, + { 0x00001778, 0x00000000 }, + { 0x000017b8, 0x00000000 }, + { 0x000017f8, 0x00000000 }, + { 0x0000103c, 0x00000000 }, + { 0x0000107c, 0x00000000 }, + { 0x000010bc, 0x00000000 }, + { 0x000010fc, 0x00000000 }, + { 0x0000113c, 0x00000000 }, + { 0x0000117c, 0x00000000 }, + { 0x000011bc, 0x00000000 }, + { 0x000011fc, 0x00000000 }, + { 0x0000123c, 0x00000000 }, + { 0x0000127c, 0x00000000 }, + { 0x000012bc, 0x00000000 }, + { 0x000012fc, 0x00000000 }, + { 0x0000133c, 0x00000000 }, + { 0x0000137c, 0x00000000 }, + { 0x000013bc, 0x00000000 }, + { 0x000013fc, 0x00000000 }, + { 0x0000143c, 0x00000000 }, + { 0x0000147c, 0x00000000 }, + { 0x00004030, 0x00000002 }, + { 0x0000403c, 0x00000002 }, + { 0x00004024, 0x0000001f }, + { 0x00004060, 0x00000000 }, + { 0x00004064, 0x00000000 }, + { 0x00007010, 0x00000031 }, + { 0x00007034, 0x00000002 }, + { 0x00007038, 0x000004c2 }, + { 0x00008004, 0x00000000 }, + { 0x00008008, 0x00000000 }, + { 0x0000800c, 0x00000000 }, + { 0x00008018, 0x00000700 }, + { 0x00008020, 0x00000000 }, + { 0x00008038, 0x00000000 }, + { 0x0000803c, 0x00000000 }, + { 0x00008048, 0x00000000 }, + { 0x00008054, 0x00000000 }, + { 0x00008058, 0x00000000 }, + { 0x0000805c, 0x000fc78f }, + { 0x00008060, 0x0000000f }, + { 0x00008064, 0x00000000 }, + { 0x00008070, 0x00000000 }, + { 0x000080c0, 0x2a80001a }, + { 0x000080c4, 0x05dc01e0 }, + { 0x000080c8, 0x1f402710 }, + { 0x000080cc, 0x01f40000 }, + { 0x000080d0, 0x00001e00 }, + { 0x000080d4, 0x00000000 }, + { 0x000080d8, 0x00400000 }, + { 0x000080e0, 0xffffffff }, + { 0x000080e4, 0x0000ffff }, + { 0x000080e8, 0x003f3f3f }, + { 0x000080ec, 0x00000000 }, + { 0x000080f0, 0x00000000 }, + { 0x000080f4, 0x00000000 }, + { 0x000080f8, 0x00000000 }, + { 0x000080fc, 0x00020000 }, + { 0x00008100, 0x00020000 }, + { 0x00008104, 0x00000001 }, + { 0x00008108, 0x00000052 }, + { 0x0000810c, 0x00000000 }, + { 0x00008110, 0x00000168 }, + { 0x00008118, 0x000100aa }, + { 0x0000811c, 0x00003210 }, + { 0x00008120, 0x08f04800 }, + { 0x00008124, 0x00000000 }, + { 0x00008128, 0x00000000 }, + { 0x0000812c, 0x00000000 }, + { 0x00008130, 0x00000000 }, + { 0x00008134, 0x00000000 }, + { 0x00008138, 0x00000000 }, + { 0x0000813c, 0x00000000 }, + { 0x00008144, 0x00000000 }, + { 0x00008168, 0x00000000 }, + { 0x0000816c, 0x00000000 }, + { 0x00008170, 0x32143320 }, + { 0x00008174, 0xfaa4fa50 }, + { 0x00008178, 0x00000100 }, + { 0x0000817c, 0x00000000 }, + { 0x000081c0, 0x00000000 }, + { 0x000081d0, 0x00003210 }, + { 0x000081ec, 0x00000000 }, + { 0x000081f0, 0x00000000 }, + { 0x000081f4, 0x00000000 }, + { 0x000081f8, 0x00000000 }, + { 0x000081fc, 0x00000000 }, + { 0x00008200, 0x00000000 }, + { 0x00008204, 0x00000000 }, + { 0x00008208, 0x00000000 }, + { 0x0000820c, 0x00000000 }, + { 0x00008210, 0x00000000 }, + { 0x00008214, 0x00000000 }, + { 0x00008218, 0x00000000 }, + { 0x0000821c, 0x00000000 }, + { 0x00008220, 0x00000000 }, + { 0x00008224, 0x00000000 }, + { 0x00008228, 0x00000000 }, + { 0x0000822c, 0x00000000 }, + { 0x00008230, 0x00000000 }, + { 0x00008234, 0x00000000 }, + { 0x00008238, 0x00000000 }, + { 0x0000823c, 0x00000000 }, + { 0x00008240, 0x00100000 }, + { 0x00008244, 0x0010f400 }, + { 0x00008248, 0x00000100 }, + { 0x0000824c, 0x0001e800 }, + { 0x00008250, 0x00000000 }, + { 0x00008254, 0x00000000 }, + { 0x00008258, 0x00000000 }, + { 0x0000825c, 0x400000ff }, + { 0x00008260, 0x00080922 }, + { 0x00008264, 0xa8a00010 }, + { 0x00008270, 0x00000000 }, + { 0x00008274, 0x40000000 }, + { 0x00008278, 0x003e4180 }, + { 0x0000827c, 0x00000000 }, + { 0x00008284, 0x0000002c }, + { 0x00008288, 0x0000002c }, + { 0x0000828c, 0x00000000 }, + { 0x00008294, 0x00000000 }, + { 0x00008298, 0x00000000 }, + { 0x0000829c, 0x00000000 }, + { 0x00008300, 0x00000040 }, + { 0x00008314, 0x00000000 }, + { 0x00008328, 0x00000000 }, + { 0x0000832c, 0x00000001 }, + { 0x00008330, 0x00000302 }, + { 0x00008334, 0x00000e00 }, + { 0x00008338, 0x00000000 }, + { 0x0000833c, 0x00000000 }, + { 0x00008340, 0x00010380 }, + { 0x00008344, 0x00581043 }, + { 0x00009808, 0x00000000 }, + { 0x0000980c, 0xafe68e30 }, + { 0x00009810, 0xfd14e000 }, + { 0x00009814, 0x9c0a9f6b }, + { 0x0000981c, 0x00000000 }, + { 0x0000982c, 0x0000a000 }, + { 0x00009830, 0x00000000 }, + { 0x0000983c, 0x00200400 }, + { 0x0000984c, 0x0040233c }, + { 0x00009854, 0x00000044 }, + { 0x00009900, 0x00000000 }, + { 0x00009904, 0x00000000 }, + { 0x00009908, 0x00000000 }, + { 0x0000990c, 0x00000000 }, + { 0x00009910, 0x01002310 }, + { 0x0000991c, 0x10000fff }, + { 0x00009920, 0x04900000 }, + { 0x00009928, 0x00000001 }, + { 0x0000992c, 0x00000004 }, + { 0x00009934, 0x1e1f2022 }, + { 0x00009938, 0x0a0b0c0d }, + { 0x0000993c, 0x00000000 }, + { 0x00009940, 0x14750604 }, + { 0x00009948, 0x9280c00a }, + { 0x0000994c, 0x00020028 }, + { 0x00009954, 0x5f3ca3de }, + { 0x00009958, 0x2108ecff }, + { 0x00009968, 0x000003ce }, + { 0x00009970, 0x1927b515 }, + { 0x00009974, 0x00000000 }, + { 0x00009978, 0x00000001 }, + { 0x0000997c, 0x00000000 }, + { 0x00009980, 0x00000000 }, + { 0x00009984, 0x00000000 }, + { 0x00009988, 0x00000000 }, + { 0x0000998c, 0x00000000 }, + { 0x00009990, 0x00000000 }, + { 0x00009994, 0x00000000 }, + { 0x00009998, 0x00000000 }, + { 0x0000999c, 0x00000000 }, + { 0x000099a0, 0x00000000 }, + { 0x000099a4, 0x00000001 }, + { 0x000099a8, 0x201fff00 }, + { 0x000099ac, 0x2def0a00 }, + { 0x000099b0, 0x03051000 }, + { 0x000099b4, 0x00000820 }, + { 0x000099dc, 0x00000000 }, + { 0x000099e0, 0x00000000 }, + { 0x000099e4, 0xaaaaaaaa }, + { 0x000099e8, 0x3c466478 }, + { 0x000099ec, 0x0cc80caa }, + { 0x000099f0, 0x00000000 }, + { 0x0000a208, 0x803e6788 }, + { 0x0000a210, 0x4080a333 }, + { 0x0000a214, 0x00206c10 }, + { 0x0000a218, 0x009c4060 }, + { 0x0000a220, 0x01834061 }, + { 0x0000a224, 0x00000400 }, + { 0x0000a228, 0x000003b5 }, + { 0x0000a22c, 0x00000000 }, + { 0x0000a234, 0x20202020 }, + { 0x0000a238, 0x20202020 }, + { 0x0000a244, 0x00000000 }, + { 0x0000a248, 0xfffffffc }, + { 0x0000a24c, 0x00000000 }, + { 0x0000a254, 0x00000000 }, + { 0x0000a258, 0x0ccb5380 }, + { 0x0000a25c, 0x15151501 }, + { 0x0000a260, 0xdfa90f01 }, + { 0x0000a268, 0x00000000 }, + { 0x0000a26c, 0x0ebae9e6 }, + { 0x0000d270, 0x0d820820 }, + { 0x0000a278, 0x39ce739c }, + { 0x0000a27c, 0x050e039c }, + { 0x0000d35c, 0x07ffffef }, + { 0x0000d360, 0x0fffffe7 }, + { 0x0000d364, 0x17ffffe5 }, + { 0x0000d368, 0x1fffffe4 }, + { 0x0000d36c, 0x37ffffe3 }, + { 0x0000d370, 0x3fffffe3 }, + { 0x0000d374, 0x57ffffe3 }, + { 0x0000d378, 0x5fffffe2 }, + { 0x0000d37c, 0x7fffffe2 }, + { 0x0000d380, 0x7f3c7bba }, + { 0x0000d384, 0xf3307ff0 }, + { 0x0000a388, 0x0c000000 }, + { 0x0000a38c, 0x20202020 }, + { 0x0000a390, 0x20202020 }, + { 0x0000a394, 0x39ce739c }, + { 0x0000a398, 0x0000039c }, + { 0x0000a39c, 0x00000001 }, + { 0x0000a3a0, 0x00000000 }, + { 0x0000a3a4, 0x00000000 }, + { 0x0000a3a8, 0x00000000 }, + { 0x0000a3ac, 0x00000000 }, + { 0x0000a3b0, 0x00000000 }, + { 0x0000a3b4, 0x00000000 }, + { 0x0000a3b8, 0x00000000 }, + { 0x0000a3bc, 0x00000000 }, + { 0x0000a3c0, 0x00000000 }, + { 0x0000a3c4, 0x00000000 }, + { 0x0000a3cc, 0x20202020 }, + { 0x0000a3d0, 0x20202020 }, + { 0x0000a3d4, 0x20202020 }, + { 0x0000a3dc, 0x39ce739c }, + { 0x0000a3e0, 0x0000039c }, + { 0x0000a3e4, 0x00000000 }, + { 0x0000a3e8, 0x18c43433 }, + { 0x0000a3ec, 0x00f70081 }, + { 0x00007800, 0x00140000 }, + { 0x00007804, 0x0e4548d8 }, + { 0x00007808, 0x54214514 }, + { 0x0000780c, 0x02025820 }, + { 0x00007810, 0x71c0d388 }, + { 0x00007814, 0x924934a8 }, + { 0x0000781c, 0x00000000 }, + { 0x00007820, 0x00000c04 }, + { 0x00007824, 0x00d86fff }, + { 0x00007828, 0x26d2491b }, + { 0x0000782c, 0x6e36d97b }, + { 0x00007830, 0xedb6d96c }, + { 0x00007834, 0x71400086 }, + { 0x00007838, 0xfac68800 }, + { 0x0000783c, 0x0001fffe }, + { 0x00007840, 0xffeb1a20 }, + { 0x00007844, 0x000c0db6 }, + { 0x00007848, 0x6db61b6f }, + { 0x0000784c, 0x6d9b66db }, + { 0x00007850, 0x6d8c6dba }, + { 0x00007854, 0x00040000 }, + { 0x00007858, 0xdb003012 }, + { 0x0000785c, 0x04924914 }, + { 0x00007860, 0x21084210 }, + { 0x00007864, 0xf7d7ffde }, + { 0x00007868, 0xc2034080 }, + { 0x0000786c, 0x48609eb4 }, + { 0x00007870, 0x10142c00 }, +}; + +static const u_int32_t ar9285PciePhy_clkreq_always_on_L1_9285[][2] = { + {0x00004040, 0x9248fd00 }, + {0x00004040, 0x24924924 }, + {0x00004040, 0xa8000019 }, + {0x00004040, 0x13160820 }, + {0x00004040, 0xe5980560 }, + {0x00004040, 0xc01dcffd }, + {0x00004040, 0x1aaabe41 }, + {0x00004040, 0xbe105554 }, + {0x00004040, 0x00043007 }, + {0x00004044, 0x00000000 }, +}; + +static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285[][2] = { + {0x00004040, 0x9248fd00 }, + {0x00004040, 0x24924924 }, + {0x00004040, 0xa8000019 }, + {0x00004040, 0x13160820 }, + {0x00004040, 0xe5980560 }, + {0x00004040, 0xc01dcffc }, + {0x00004040, 0x1aaabe41 }, + {0x00004040, 0xbe105554 }, + {0x00004040, 0x00043007 }, + {0x00004044, 0x00000000 }, +}; + +static const u_int32_t ar9285Modes_9285_1_2[][6] = { + { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, + { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, + { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, + { 0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 }, + { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 }, + { 0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f }, + { 0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880 }, + { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, + { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, + { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, + { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, + { 0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e }, + { 0x00009844, 0x0372161e, 0x0372161e, 0x03720020, 0x03720020, 0x037216a0 }, + { 0x00009848, 0x00001066, 0x00001066, 0x00000057, 0x00000057, 0x00001059 }, + { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 }, + { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e }, + { 0x0000985c, 0x3139605e, 0x3139605e, 0x3136605e, 0x3136605e, 0x3139605e }, + { 0x00009860, 0x00058d18, 0x00058d18, 0x00058d20, 0x00058d20, 0x00058d18 }, + { 0x00009864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, + { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 }, + { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 }, + { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 }, + { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 }, + { 0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d }, + { 0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1020, 0xffbc1020, 0xffbc1010 }, + { 0x00009960, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x00009964, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x000099b8, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c }, + { 0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 }, + { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 }, + { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, + { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 }, + { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 }, + { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, + { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x00009a00, 0x00000000, 0x00000000, 0x00068084, 0x00068084, 0x00000000 }, + { 0x00009a04, 0x00000000, 0x00000000, 0x00068088, 0x00068088, 0x00000000 }, + { 0x00009a08, 0x00000000, 0x00000000, 0x0006808c, 0x0006808c, 0x00000000 }, + { 0x00009a0c, 0x00000000, 0x00000000, 0x00068100, 0x00068100, 0x00000000 }, + { 0x00009a10, 0x00000000, 0x00000000, 0x00068104, 0x00068104, 0x00000000 }, + { 0x00009a14, 0x00000000, 0x00000000, 0x00068108, 0x00068108, 0x00000000 }, + { 0x00009a18, 0x00000000, 0x00000000, 0x0006810c, 0x0006810c, 0x00000000 }, + { 0x00009a1c, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 }, + { 0x00009a20, 0x00000000, 0x00000000, 0x00068114, 0x00068114, 0x00000000 }, + { 0x00009a24, 0x00000000, 0x00000000, 0x00068180, 0x00068180, 0x00000000 }, + { 0x00009a28, 0x00000000, 0x00000000, 0x00068184, 0x00068184, 0x00000000 }, + { 0x00009a2c, 0x00000000, 0x00000000, 0x00068188, 0x00068188, 0x00000000 }, + { 0x00009a30, 0x00000000, 0x00000000, 0x0006818c, 0x0006818c, 0x00000000 }, + { 0x00009a34, 0x00000000, 0x00000000, 0x00068190, 0x00068190, 0x00000000 }, + { 0x00009a38, 0x00000000, 0x00000000, 0x00068194, 0x00068194, 0x00000000 }, + { 0x00009a3c, 0x00000000, 0x00000000, 0x000681a0, 0x000681a0, 0x00000000 }, + { 0x00009a40, 0x00000000, 0x00000000, 0x0006820c, 0x0006820c, 0x00000000 }, + { 0x00009a44, 0x00000000, 0x00000000, 0x000681a8, 0x000681a8, 0x00000000 }, + { 0x00009a48, 0x00000000, 0x00000000, 0x00068284, 0x00068284, 0x00000000 }, + { 0x00009a4c, 0x00000000, 0x00000000, 0x00068288, 0x00068288, 0x00000000 }, + { 0x00009a50, 0x00000000, 0x00000000, 0x00068220, 0x00068220, 0x00000000 }, + { 0x00009a54, 0x00000000, 0x00000000, 0x00068290, 0x00068290, 0x00000000 }, + { 0x00009a58, 0x00000000, 0x00000000, 0x00068300, 0x00068300, 0x00000000 }, + { 0x00009a5c, 0x00000000, 0x00000000, 0x00068304, 0x00068304, 0x00000000 }, + { 0x00009a60, 0x00000000, 0x00000000, 0x00068308, 0x00068308, 0x00000000 }, + { 0x00009a64, 0x00000000, 0x00000000, 0x0006830c, 0x0006830c, 0x00000000 }, + { 0x00009a68, 0x00000000, 0x00000000, 0x00068380, 0x00068380, 0x00000000 }, + { 0x00009a6c, 0x00000000, 0x00000000, 0x00068384, 0x00068384, 0x00000000 }, + { 0x00009a70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000 }, + { 0x00009a74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000 }, + { 0x00009a78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000 }, + { 0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 }, + { 0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 }, + { 0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 }, + { 0x00009a88, 0x00000000, 0x00000000, 0x00068b04, 0x00068b04, 0x00000000 }, + { 0x00009a8c, 0x00000000, 0x00000000, 0x00068b08, 0x00068b08, 0x00000000 }, + { 0x00009a90, 0x00000000, 0x00000000, 0x00068b08, 0x00068b08, 0x00000000 }, + { 0x00009a94, 0x00000000, 0x00000000, 0x00068b0c, 0x00068b0c, 0x00000000 }, + { 0x00009a98, 0x00000000, 0x00000000, 0x00068b80, 0x00068b80, 0x00000000 }, + { 0x00009a9c, 0x00000000, 0x00000000, 0x00068b84, 0x00068b84, 0x00000000 }, + { 0x00009aa0, 0x00000000, 0x00000000, 0x00068b88, 0x00068b88, 0x00000000 }, + { 0x00009aa4, 0x00000000, 0x00000000, 0x00068b8c, 0x00068b8c, 0x00000000 }, + { 0x00009aa8, 0x00000000, 0x00000000, 0x000b8b90, 0x000b8b90, 0x00000000 }, + { 0x00009aac, 0x00000000, 0x00000000, 0x000b8f80, 0x000b8f80, 0x00000000 }, + { 0x00009ab0, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 }, + { 0x00009ab4, 0x00000000, 0x00000000, 0x000b8f88, 0x000b8f88, 0x00000000 }, + { 0x00009ab8, 0x00000000, 0x00000000, 0x000b8f8c, 0x000b8f8c, 0x00000000 }, + { 0x00009abc, 0x00000000, 0x00000000, 0x000b8f90, 0x000b8f90, 0x00000000 }, + { 0x00009ac0, 0x00000000, 0x00000000, 0x000bb30c, 0x000bb30c, 0x00000000 }, + { 0x00009ac4, 0x00000000, 0x00000000, 0x000bb310, 0x000bb310, 0x00000000 }, + { 0x00009ac8, 0x00000000, 0x00000000, 0x000bb384, 0x000bb384, 0x00000000 }, + { 0x00009acc, 0x00000000, 0x00000000, 0x000bb388, 0x000bb388, 0x00000000 }, + { 0x00009ad0, 0x00000000, 0x00000000, 0x000bb324, 0x000bb324, 0x00000000 }, + { 0x00009ad4, 0x00000000, 0x00000000, 0x000bb704, 0x000bb704, 0x00000000 }, + { 0x00009ad8, 0x00000000, 0x00000000, 0x000f96a4, 0x000f96a4, 0x00000000 }, + { 0x00009adc, 0x00000000, 0x00000000, 0x000f96a8, 0x000f96a8, 0x00000000 }, + { 0x00009ae0, 0x00000000, 0x00000000, 0x000f9710, 0x000f9710, 0x00000000 }, + { 0x00009ae4, 0x00000000, 0x00000000, 0x000f9714, 0x000f9714, 0x00000000 }, + { 0x00009ae8, 0x00000000, 0x00000000, 0x000f9720, 0x000f9720, 0x00000000 }, + { 0x00009aec, 0x00000000, 0x00000000, 0x000f9724, 0x000f9724, 0x00000000 }, + { 0x00009af0, 0x00000000, 0x00000000, 0x000f9728, 0x000f9728, 0x00000000 }, + { 0x00009af4, 0x00000000, 0x00000000, 0x000f972c, 0x000f972c, 0x00000000 }, + { 0x00009af8, 0x00000000, 0x00000000, 0x000f97a0, 0x000f97a0, 0x00000000 }, + { 0x00009afc, 0x00000000, 0x00000000, 0x000f97a4, 0x000f97a4, 0x00000000 }, + { 0x00009b00, 0x00000000, 0x00000000, 0x000fb7a8, 0x000fb7a8, 0x00000000 }, + { 0x00009b04, 0x00000000, 0x00000000, 0x000fb7b0, 0x000fb7b0, 0x00000000 }, + { 0x00009b08, 0x00000000, 0x00000000, 0x000fb7b4, 0x000fb7b4, 0x00000000 }, + { 0x00009b0c, 0x00000000, 0x00000000, 0x000fb7b8, 0x000fb7b8, 0x00000000 }, + { 0x00009b10, 0x00000000, 0x00000000, 0x000fb7a5, 0x000fb7a5, 0x00000000 }, + { 0x00009b14, 0x00000000, 0x00000000, 0x000fb7a9, 0x000fb7a9, 0x00000000 }, + { 0x00009b18, 0x00000000, 0x00000000, 0x000fb7ad, 0x000fb7ad, 0x00000000 }, + { 0x00009b1c, 0x00000000, 0x00000000, 0x000fb7b1, 0x000fb7b1, 0x00000000 }, + { 0x00009b20, 0x00000000, 0x00000000, 0x000fb7b5, 0x000fb7b5, 0x00000000 }, + { 0x00009b24, 0x00000000, 0x00000000, 0x000fb7b9, 0x000fb7b9, 0x00000000 }, + { 0x00009b28, 0x00000000, 0x00000000, 0x000fb7c5, 0x000fb7c5, 0x00000000 }, + { 0x00009b2c, 0x00000000, 0x00000000, 0x000fb7c9, 0x000fb7c9, 0x00000000 }, + { 0x00009b30, 0x00000000, 0x00000000, 0x000fb7d1, 0x000fb7d1, 0x00000000 }, + { 0x00009b34, 0x00000000, 0x00000000, 0x000fb7d5, 0x000fb7d5, 0x00000000 }, + { 0x00009b38, 0x00000000, 0x00000000, 0x000fb7d9, 0x000fb7d9, 0x00000000 }, + { 0x00009b3c, 0x00000000, 0x00000000, 0x000fb7c6, 0x000fb7c6, 0x00000000 }, + { 0x00009b40, 0x00000000, 0x00000000, 0x000fb7ca, 0x000fb7ca, 0x00000000 }, + { 0x00009b44, 0x00000000, 0x00000000, 0x000fb7ce, 0x000fb7ce, 0x00000000 }, + { 0x00009b48, 0x00000000, 0x00000000, 0x000fb7d2, 0x000fb7d2, 0x00000000 }, + { 0x00009b4c, 0x00000000, 0x00000000, 0x000fb7d6, 0x000fb7d6, 0x00000000 }, + { 0x00009b50, 0x00000000, 0x00000000, 0x000fb7c3, 0x000fb7c3, 0x00000000 }, + { 0x00009b54, 0x00000000, 0x00000000, 0x000fb7c7, 0x000fb7c7, 0x00000000 }, + { 0x00009b58, 0x00000000, 0x00000000, 0x000fb7cb, 0x000fb7cb, 0x00000000 }, + { 0x00009b5c, 0x00000000, 0x00000000, 0x000fb7cf, 0x000fb7cf, 0x00000000 }, + { 0x00009b60, 0x00000000, 0x00000000, 0x000fb7d7, 0x000fb7d7, 0x00000000 }, + { 0x00009b64, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b68, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b6c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b70, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b74, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b78, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b7c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b80, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b84, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b88, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b8c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b90, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b94, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b98, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b9c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009ba0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009ba4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009ba8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bac, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bb0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bb4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bb8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bbc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bc0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bc4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bc8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bcc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bd0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bd4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bd8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bdc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009be0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009be4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009be8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bec, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bf0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bf4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bf8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bfc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x0000aa00, 0x00000000, 0x00000000, 0x0006801c, 0x0006801c, 0x00000000 }, + { 0x0000aa04, 0x00000000, 0x00000000, 0x0006801c, 0x0006801c, 0x00000000 }, + { 0x0000aa08, 0x00000000, 0x00000000, 0x0006801c, 0x0006801c, 0x00000000 }, + { 0x0000aa0c, 0x00000000, 0x00000000, 0x00068080, 0x00068080, 0x00000000 }, + { 0x0000aa10, 0x00000000, 0x00000000, 0x00068084, 0x00068084, 0x00000000 }, + { 0x0000aa14, 0x00000000, 0x00000000, 0x00068088, 0x00068088, 0x00000000 }, + { 0x0000aa18, 0x00000000, 0x00000000, 0x0006808c, 0x0006808c, 0x00000000 }, + { 0x0000aa1c, 0x00000000, 0x00000000, 0x00068100, 0x00068100, 0x00000000 }, + { 0x0000aa20, 0x00000000, 0x00000000, 0x00068104, 0x00068104, 0x00000000 }, + { 0x0000aa24, 0x00000000, 0x00000000, 0x00068108, 0x00068108, 0x00000000 }, + { 0x0000aa28, 0x00000000, 0x00000000, 0x0006810c, 0x0006810c, 0x00000000 }, + { 0x0000aa2c, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 }, + { 0x0000aa30, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 }, + { 0x0000aa34, 0x00000000, 0x00000000, 0x00068180, 0x00068180, 0x00000000 }, + { 0x0000aa38, 0x00000000, 0x00000000, 0x00068184, 0x00068184, 0x00000000 }, + { 0x0000aa3c, 0x00000000, 0x00000000, 0x00068188, 0x00068188, 0x00000000 }, + { 0x0000aa40, 0x00000000, 0x00000000, 0x0006818c, 0x0006818c, 0x00000000 }, + { 0x0000aa44, 0x00000000, 0x00000000, 0x00068190, 0x00068190, 0x00000000 }, + { 0x0000aa48, 0x00000000, 0x00000000, 0x00068194, 0x00068194, 0x00000000 }, + { 0x0000aa4c, 0x00000000, 0x00000000, 0x000681a0, 0x000681a0, 0x00000000 }, + { 0x0000aa50, 0x00000000, 0x00000000, 0x0006820c, 0x0006820c, 0x00000000 }, + { 0x0000aa54, 0x00000000, 0x00000000, 0x000681a8, 0x000681a8, 0x00000000 }, + { 0x0000aa58, 0x00000000, 0x00000000, 0x000681ac, 0x000681ac, 0x00000000 }, + { 0x0000aa5c, 0x00000000, 0x00000000, 0x0006821c, 0x0006821c, 0x00000000 }, + { 0x0000aa60, 0x00000000, 0x00000000, 0x00068224, 0x00068224, 0x00000000 }, + { 0x0000aa64, 0x00000000, 0x00000000, 0x00068290, 0x00068290, 0x00000000 }, + { 0x0000aa68, 0x00000000, 0x00000000, 0x00068300, 0x00068300, 0x00000000 }, + { 0x0000aa6c, 0x00000000, 0x00000000, 0x00068308, 0x00068308, 0x00000000 }, + { 0x0000aa70, 0x00000000, 0x00000000, 0x0006830c, 0x0006830c, 0x00000000 }, + { 0x0000aa74, 0x00000000, 0x00000000, 0x00068310, 0x00068310, 0x00000000 }, + { 0x0000aa78, 0x00000000, 0x00000000, 0x00068788, 0x00068788, 0x00000000 }, + { 0x0000aa7c, 0x00000000, 0x00000000, 0x0006878c, 0x0006878c, 0x00000000 }, + { 0x0000aa80, 0x00000000, 0x00000000, 0x00068790, 0x00068790, 0x00000000 }, + { 0x0000aa84, 0x00000000, 0x00000000, 0x00068794, 0x00068794, 0x00000000 }, + { 0x0000aa88, 0x00000000, 0x00000000, 0x00068798, 0x00068798, 0x00000000 }, + { 0x0000aa8c, 0x00000000, 0x00000000, 0x0006879c, 0x0006879c, 0x00000000 }, + { 0x0000aa90, 0x00000000, 0x00000000, 0x00068b89, 0x00068b89, 0x00000000 }, + { 0x0000aa94, 0x00000000, 0x00000000, 0x00068b8d, 0x00068b8d, 0x00000000 }, + { 0x0000aa98, 0x00000000, 0x00000000, 0x00068b91, 0x00068b91, 0x00000000 }, + { 0x0000aa9c, 0x00000000, 0x00000000, 0x00068b95, 0x00068b95, 0x00000000 }, + { 0x0000aaa0, 0x00000000, 0x00000000, 0x00068b99, 0x00068b99, 0x00000000 }, + { 0x0000aaa4, 0x00000000, 0x00000000, 0x00068ba5, 0x00068ba5, 0x00000000 }, + { 0x0000aaa8, 0x00000000, 0x00000000, 0x00068ba9, 0x00068ba9, 0x00000000 }, + { 0x0000aaac, 0x00000000, 0x00000000, 0x00068bad, 0x00068bad, 0x00000000 }, + { 0x0000aab0, 0x00000000, 0x00000000, 0x000b8b0c, 0x000b8b0c, 0x00000000 }, + { 0x0000aab4, 0x00000000, 0x00000000, 0x000b8f10, 0x000b8f10, 0x00000000 }, + { 0x0000aab8, 0x00000000, 0x00000000, 0x000b8f14, 0x000b8f14, 0x00000000 }, + { 0x0000aabc, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 }, + { 0x0000aac0, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 }, + { 0x0000aac4, 0x00000000, 0x00000000, 0x000b8f88, 0x000b8f88, 0x00000000 }, + { 0x0000aac8, 0x00000000, 0x00000000, 0x000bb380, 0x000bb380, 0x00000000 }, + { 0x0000aacc, 0x00000000, 0x00000000, 0x000bb384, 0x000bb384, 0x00000000 }, + { 0x0000aad0, 0x00000000, 0x00000000, 0x000bb388, 0x000bb388, 0x00000000 }, + { 0x0000aad4, 0x00000000, 0x00000000, 0x000bb38c, 0x000bb38c, 0x00000000 }, + { 0x0000aad8, 0x00000000, 0x00000000, 0x000bb394, 0x000bb394, 0x00000000 }, + { 0x0000aadc, 0x00000000, 0x00000000, 0x000bb798, 0x000bb798, 0x00000000 }, + { 0x0000aae0, 0x00000000, 0x00000000, 0x000f970c, 0x000f970c, 0x00000000 }, + { 0x0000aae4, 0x00000000, 0x00000000, 0x000f9710, 0x000f9710, 0x00000000 }, + { 0x0000aae8, 0x00000000, 0x00000000, 0x000f9714, 0x000f9714, 0x00000000 }, + { 0x0000aaec, 0x00000000, 0x00000000, 0x000f9718, 0x000f9718, 0x00000000 }, + { 0x0000aaf0, 0x00000000, 0x00000000, 0x000f9705, 0x000f9705, 0x00000000 }, + { 0x0000aaf4, 0x00000000, 0x00000000, 0x000f9709, 0x000f9709, 0x00000000 }, + { 0x0000aaf8, 0x00000000, 0x00000000, 0x000f970d, 0x000f970d, 0x00000000 }, + { 0x0000aafc, 0x00000000, 0x00000000, 0x000f9711, 0x000f9711, 0x00000000 }, + { 0x0000ab00, 0x00000000, 0x00000000, 0x000f9715, 0x000f9715, 0x00000000 }, + { 0x0000ab04, 0x00000000, 0x00000000, 0x000f9719, 0x000f9719, 0x00000000 }, + { 0x0000ab08, 0x00000000, 0x00000000, 0x000fb7a4, 0x000fb7a4, 0x00000000 }, + { 0x0000ab0c, 0x00000000, 0x00000000, 0x000fb7a8, 0x000fb7a8, 0x00000000 }, + { 0x0000ab10, 0x00000000, 0x00000000, 0x000fb7ac, 0x000fb7ac, 0x00000000 }, + { 0x0000ab14, 0x00000000, 0x00000000, 0x000fb7ac, 0x000fb7ac, 0x00000000 }, + { 0x0000ab18, 0x00000000, 0x00000000, 0x000fb7b0, 0x000fb7b0, 0x00000000 }, + { 0x0000ab1c, 0x00000000, 0x00000000, 0x000fb7b8, 0x000fb7b8, 0x00000000 }, + { 0x0000ab20, 0x00000000, 0x00000000, 0x000fb7bc, 0x000fb7bc, 0x00000000 }, + { 0x0000ab24, 0x00000000, 0x00000000, 0x000fb7a1, 0x000fb7a1, 0x00000000 }, + { 0x0000ab28, 0x00000000, 0x00000000, 0x000fb7a5, 0x000fb7a5, 0x00000000 }, + { 0x0000ab2c, 0x00000000, 0x00000000, 0x000fb7a9, 0x000fb7a9, 0x00000000 }, + { 0x0000ab30, 0x00000000, 0x00000000, 0x000fb7b1, 0x000fb7b1, 0x00000000 }, + { 0x0000ab34, 0x00000000, 0x00000000, 0x000fb7b5, 0x000fb7b5, 0x00000000 }, + { 0x0000ab38, 0x00000000, 0x00000000, 0x000fb7bd, 0x000fb7bd, 0x00000000 }, + { 0x0000ab3c, 0x00000000, 0x00000000, 0x000fb7c9, 0x000fb7c9, 0x00000000 }, + { 0x0000ab40, 0x00000000, 0x00000000, 0x000fb7cd, 0x000fb7cd, 0x00000000 }, + { 0x0000ab44, 0x00000000, 0x00000000, 0x000fb7d1, 0x000fb7d1, 0x00000000 }, + { 0x0000ab48, 0x00000000, 0x00000000, 0x000fb7d9, 0x000fb7d9, 0x00000000 }, + { 0x0000ab4c, 0x00000000, 0x00000000, 0x000fb7c2, 0x000fb7c2, 0x00000000 }, + { 0x0000ab50, 0x00000000, 0x00000000, 0x000fb7c6, 0x000fb7c6, 0x00000000 }, + { 0x0000ab54, 0x00000000, 0x00000000, 0x000fb7ca, 0x000fb7ca, 0x00000000 }, + { 0x0000ab58, 0x00000000, 0x00000000, 0x000fb7ce, 0x000fb7ce, 0x00000000 }, + { 0x0000ab5c, 0x00000000, 0x00000000, 0x000fb7d2, 0x000fb7d2, 0x00000000 }, + { 0x0000ab60, 0x00000000, 0x00000000, 0x000fb7d6, 0x000fb7d6, 0x00000000 }, + { 0x0000ab64, 0x00000000, 0x00000000, 0x000fb7c3, 0x000fb7c3, 0x00000000 }, + { 0x0000ab68, 0x00000000, 0x00000000, 0x000fb7cb, 0x000fb7cb, 0x00000000 }, + { 0x0000ab6c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab70, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab74, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab78, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab7c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab80, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab84, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab88, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab8c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab90, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab94, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab98, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab9c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000aba0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000aba4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000aba8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abac, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abb0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abb4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abb8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abbc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abc0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abc4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abc8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abcc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abd0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abd4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abd8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abdc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abe0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abe4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abe8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abec, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abf0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abf4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abf8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abfc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 }, + { 0x0000a20c, 0x00000014, 0x00000014, 0x00000000, 0x00000000, 0x0001f000 }, + { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, + { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, + { 0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000 }, + { 0x0000a274, 0x0a81c652, 0x0a81c652, 0x0a820652, 0x0a820652, 0x0a82a652 }, + { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a304, 0x00000000, 0x00000000, 0x00007201, 0x00007201, 0x00000000 }, + { 0x0000a308, 0x00000000, 0x00000000, 0x00010408, 0x00010408, 0x00000000 }, + { 0x0000a30c, 0x00000000, 0x00000000, 0x0001860a, 0x0001860a, 0x00000000 }, + { 0x0000a310, 0x00000000, 0x00000000, 0x00020818, 0x00020818, 0x00000000 }, + { 0x0000a314, 0x00000000, 0x00000000, 0x00024858, 0x00024858, 0x00000000 }, + { 0x0000a318, 0x00000000, 0x00000000, 0x00026859, 0x00026859, 0x00000000 }, + { 0x0000a31c, 0x00000000, 0x00000000, 0x0002985b, 0x0002985b, 0x00000000 }, + { 0x0000a320, 0x00000000, 0x00000000, 0x0002b89a, 0x0002b89a, 0x00000000 }, + { 0x0000a324, 0x00000000, 0x00000000, 0x0002d89b, 0x0002d89b, 0x00000000 }, + { 0x0000a328, 0x00000000, 0x00000000, 0x0002f89c, 0x0002f89c, 0x00000000 }, + { 0x0000a32c, 0x00000000, 0x00000000, 0x0003189d, 0x0003189d, 0x00000000 }, + { 0x0000a330, 0x00000000, 0x00000000, 0x0003389e, 0x0003389e, 0x00000000 }, + { 0x0000a334, 0x00000000, 0x00000000, 0x000368de, 0x000368de, 0x00000000 }, + { 0x0000a338, 0x00000000, 0x00000000, 0x0003891e, 0x0003891e, 0x00000000 }, + { 0x0000a33c, 0x00000000, 0x00000000, 0x0003a95e, 0x0003a95e, 0x00000000 }, + { 0x0000a340, 0x00000000, 0x00000000, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e }, +}; + +static const u_int32_t ar9285Common_9285_1_2[][2] = { + { 0x0000000c, 0x00000000 }, + { 0x00000030, 0x00020045 }, + { 0x00000034, 0x00000005 }, + { 0x00000040, 0x00000000 }, + { 0x00000044, 0x00000008 }, + { 0x00000048, 0x00000008 }, + { 0x0000004c, 0x00000010 }, + { 0x00000050, 0x00000000 }, + { 0x00000054, 0x0000001f }, + { 0x00000800, 0x00000000 }, + { 0x00000804, 0x00000000 }, + { 0x00000808, 0x00000000 }, + { 0x0000080c, 0x00000000 }, + { 0x00000810, 0x00000000 }, + { 0x00000814, 0x00000000 }, + { 0x00000818, 0x00000000 }, + { 0x0000081c, 0x00000000 }, + { 0x00000820, 0x00000000 }, + { 0x00000824, 0x00000000 }, + { 0x00001040, 0x002ffc0f }, + { 0x00001044, 0x002ffc0f }, + { 0x00001048, 0x002ffc0f }, + { 0x0000104c, 0x002ffc0f }, + { 0x00001050, 0x002ffc0f }, + { 0x00001054, 0x002ffc0f }, + { 0x00001058, 0x002ffc0f }, + { 0x0000105c, 0x002ffc0f }, + { 0x00001060, 0x002ffc0f }, + { 0x00001064, 0x002ffc0f }, + { 0x00001230, 0x00000000 }, + { 0x00001270, 0x00000000 }, + { 0x00001038, 0x00000000 }, + { 0x00001078, 0x00000000 }, + { 0x000010b8, 0x00000000 }, + { 0x000010f8, 0x00000000 }, + { 0x00001138, 0x00000000 }, + { 0x00001178, 0x00000000 }, + { 0x000011b8, 0x00000000 }, + { 0x000011f8, 0x00000000 }, + { 0x00001238, 0x00000000 }, + { 0x00001278, 0x00000000 }, + { 0x000012b8, 0x00000000 }, + { 0x000012f8, 0x00000000 }, + { 0x00001338, 0x00000000 }, + { 0x00001378, 0x00000000 }, + { 0x000013b8, 0x00000000 }, + { 0x000013f8, 0x00000000 }, + { 0x00001438, 0x00000000 }, + { 0x00001478, 0x00000000 }, + { 0x000014b8, 0x00000000 }, + { 0x000014f8, 0x00000000 }, + { 0x00001538, 0x00000000 }, + { 0x00001578, 0x00000000 }, + { 0x000015b8, 0x00000000 }, + { 0x000015f8, 0x00000000 }, + { 0x00001638, 0x00000000 }, + { 0x00001678, 0x00000000 }, + { 0x000016b8, 0x00000000 }, + { 0x000016f8, 0x00000000 }, + { 0x00001738, 0x00000000 }, + { 0x00001778, 0x00000000 }, + { 0x000017b8, 0x00000000 }, + { 0x000017f8, 0x00000000 }, + { 0x0000103c, 0x00000000 }, + { 0x0000107c, 0x00000000 }, + { 0x000010bc, 0x00000000 }, + { 0x000010fc, 0x00000000 }, + { 0x0000113c, 0x00000000 }, + { 0x0000117c, 0x00000000 }, + { 0x000011bc, 0x00000000 }, + { 0x000011fc, 0x00000000 }, + { 0x0000123c, 0x00000000 }, + { 0x0000127c, 0x00000000 }, + { 0x000012bc, 0x00000000 }, + { 0x000012fc, 0x00000000 }, + { 0x0000133c, 0x00000000 }, + { 0x0000137c, 0x00000000 }, + { 0x000013bc, 0x00000000 }, + { 0x000013fc, 0x00000000 }, + { 0x0000143c, 0x00000000 }, + { 0x0000147c, 0x00000000 }, + { 0x00004030, 0x00000002 }, + { 0x0000403c, 0x00000002 }, + { 0x00004024, 0x0000001f }, + { 0x00004060, 0x00000000 }, + { 0x00004064, 0x00000000 }, + { 0x00007010, 0x00000031 }, + { 0x00007034, 0x00000002 }, + { 0x00007038, 0x000004c2 }, + { 0x00008004, 0x00000000 }, + { 0x00008008, 0x00000000 }, + { 0x0000800c, 0x00000000 }, + { 0x00008018, 0x00000700 }, + { 0x00008020, 0x00000000 }, + { 0x00008038, 0x00000000 }, + { 0x0000803c, 0x00000000 }, + { 0x00008048, 0x00000000 }, + { 0x00008054, 0x00000000 }, + { 0x00008058, 0x00000000 }, + { 0x0000805c, 0x000fc78f }, + { 0x00008060, 0x0000000f }, + { 0x00008064, 0x00000000 }, + { 0x00008070, 0x00000000 }, + { 0x000080c0, 0x2a80001a }, + { 0x000080c4, 0x05dc01e0 }, + { 0x000080c8, 0x1f402710 }, + { 0x000080cc, 0x01f40000 }, + { 0x000080d0, 0x00001e00 }, + { 0x000080d4, 0x00000000 }, + { 0x000080d8, 0x00400000 }, + { 0x000080e0, 0xffffffff }, + { 0x000080e4, 0x0000ffff }, + { 0x000080e8, 0x003f3f3f }, + { 0x000080ec, 0x00000000 }, + { 0x000080f0, 0x00000000 }, + { 0x000080f4, 0x00000000 }, + { 0x000080f8, 0x00000000 }, + { 0x000080fc, 0x00020000 }, + { 0x00008100, 0x00020000 }, + { 0x00008104, 0x00000001 }, + { 0x00008108, 0x00000052 }, + { 0x0000810c, 0x00000000 }, + { 0x00008110, 0x00000168 }, + { 0x00008118, 0x000100aa }, + { 0x0000811c, 0x00003210 }, + { 0x00008120, 0x08f04800 }, + { 0x00008124, 0x00000000 }, + { 0x00008128, 0x00000000 }, + { 0x0000812c, 0x00000000 }, + { 0x00008130, 0x00000000 }, + { 0x00008134, 0x00000000 }, + { 0x00008138, 0x00000000 }, + { 0x0000813c, 0x00000000 }, + { 0x00008144, 0xffffffff }, + { 0x00008168, 0x00000000 }, + { 0x0000816c, 0x00000000 }, + { 0x00008170, 0x32143320 }, + { 0x00008174, 0xfaa4fa50 }, + { 0x00008178, 0x00000100 }, + { 0x0000817c, 0x00000000 }, + { 0x000081c0, 0x00000000 }, + { 0x000081d0, 0x00003210 }, + { 0x000081ec, 0x00000000 }, + { 0x000081f0, 0x00000000 }, + { 0x000081f4, 0x00000000 }, + { 0x000081f8, 0x00000000 }, + { 0x000081fc, 0x00000000 }, + { 0x00008200, 0x00000000 }, + { 0x00008204, 0x00000000 }, + { 0x00008208, 0x00000000 }, + { 0x0000820c, 0x00000000 }, + { 0x00008210, 0x00000000 }, + { 0x00008214, 0x00000000 }, + { 0x00008218, 0x00000000 }, + { 0x0000821c, 0x00000000 }, + { 0x00008220, 0x00000000 }, + { 0x00008224, 0x00000000 }, + { 0x00008228, 0x00000000 }, + { 0x0000822c, 0x00000000 }, + { 0x00008230, 0x00000000 }, + { 0x00008234, 0x00000000 }, + { 0x00008238, 0x00000000 }, + { 0x0000823c, 0x00000000 }, + { 0x00008240, 0x00100000 }, + { 0x00008244, 0x0010f400 }, + { 0x00008248, 0x00000100 }, + { 0x0000824c, 0x0001e800 }, + { 0x00008250, 0x00000000 }, + { 0x00008254, 0x00000000 }, + { 0x00008258, 0x00000000 }, + { 0x0000825c, 0x400000ff }, + { 0x00008260, 0x00080922 }, + { 0x00008264, 0xa8a00010 }, + { 0x00008270, 0x00000000 }, + { 0x00008274, 0x40000000 }, + { 0x00008278, 0x003e4180 }, + { 0x0000827c, 0x00000000 }, + { 0x00008284, 0x0000002c }, + { 0x00008288, 0x0000002c }, + { 0x0000828c, 0x00000000 }, + { 0x00008294, 0x00000000 }, + { 0x00008298, 0x00000000 }, + { 0x0000829c, 0x00000000 }, + { 0x00008300, 0x00000040 }, + { 0x00008314, 0x00000000 }, + { 0x00008328, 0x00000000 }, + { 0x0000832c, 0x00000001 }, + { 0x00008330, 0x00000302 }, + { 0x00008334, 0x00000e00 }, + { 0x00008338, 0x00ff0000 }, + { 0x0000833c, 0x00000000 }, + { 0x00008340, 0x00010380 }, + { 0x00008344, 0x00581043 }, + { 0x00009808, 0x00000000 }, + { 0x0000980c, 0xafe68e30 }, + { 0x00009810, 0xfd14e000 }, + { 0x00009814, 0x9c0a9f6b }, + { 0x0000981c, 0x00000000 }, + { 0x0000982c, 0x0000a000 }, + { 0x00009830, 0x00000000 }, + { 0x0000983c, 0x00200400 }, + { 0x0000984c, 0x0040233c }, + { 0x00009854, 0x00000044 }, + { 0x00009900, 0x00000000 }, + { 0x00009904, 0x00000000 }, + { 0x00009908, 0x00000000 }, + { 0x0000990c, 0x00000000 }, + { 0x00009910, 0x01002310 }, + { 0x0000991c, 0x10000fff }, + { 0x00009920, 0x04900000 }, + { 0x00009928, 0x00000001 }, + { 0x0000992c, 0x00000004 }, + { 0x00009934, 0x1e1f2022 }, + { 0x00009938, 0x0a0b0c0d }, + { 0x0000993c, 0x00000000 }, + { 0x00009940, 0x14750604 }, + { 0x00009948, 0x9280c00a }, + { 0x0000994c, 0x00020028 }, + { 0x00009954, 0x5f3ca3de }, + { 0x00009958, 0x2108ecff }, + { 0x00009968, 0x000003ce }, + { 0x00009970, 0x192bb515 }, + { 0x00009974, 0x00000000 }, + { 0x00009978, 0x00000001 }, + { 0x0000997c, 0x00000000 }, + { 0x00009980, 0x00000000 }, + { 0x00009984, 0x00000000 }, + { 0x00009988, 0x00000000 }, + { 0x0000998c, 0x00000000 }, + { 0x00009990, 0x00000000 }, + { 0x00009994, 0x00000000 }, + { 0x00009998, 0x00000000 }, + { 0x0000999c, 0x00000000 }, + { 0x000099a0, 0x00000000 }, + { 0x000099a4, 0x00000001 }, + { 0x000099a8, 0x201fff00 }, + { 0x000099ac, 0x2def1000 }, + { 0x000099b0, 0x03051000 }, + { 0x000099b4, 0x00000820 }, + { 0x000099dc, 0x00000000 }, + { 0x000099e0, 0x00000000 }, + { 0x000099e4, 0xaaaaaaaa }, + { 0x000099e8, 0x3c466478 }, + { 0x000099ec, 0x0cc80caa }, + { 0x000099f0, 0x00000000 }, + { 0x0000a208, 0x803e6788 }, + { 0x0000a210, 0x4080a333 }, + { 0x0000a214, 0x00206c10 }, + { 0x0000a218, 0x009c4060 }, + { 0x0000a220, 0x01834061 }, + { 0x0000a224, 0x00000400 }, + { 0x0000a228, 0x000003b5 }, + { 0x0000a22c, 0x00000000 }, + { 0x0000a234, 0x20202020 }, + { 0x0000a238, 0x20202020 }, + { 0x0000a244, 0x00000000 }, + { 0x0000a248, 0xfffffffc }, + { 0x0000a24c, 0x00000000 }, + { 0x0000a254, 0x00000000 }, + { 0x0000a258, 0x0ccb5380 }, + { 0x0000a25c, 0x15151501 }, + { 0x0000a260, 0xdfa90f01 }, + { 0x0000a268, 0x00000000 }, + { 0x0000a26c, 0x0ebae9e6 }, + { 0x0000d270, 0x0d820820 }, + { 0x0000a278, 0x318c6318 }, + { 0x0000a27c, 0x050c0318 }, + { 0x0000d35c, 0x07ffffef }, + { 0x0000d360, 0x0fffffe7 }, + { 0x0000d364, 0x17ffffe5 }, + { 0x0000d368, 0x1fffffe4 }, + { 0x0000d36c, 0x37ffffe3 }, + { 0x0000d370, 0x3fffffe3 }, + { 0x0000d374, 0x57ffffe3 }, + { 0x0000d378, 0x5fffffe2 }, + { 0x0000d37c, 0x7fffffe2 }, + { 0x0000d380, 0x7f3c7bba }, + { 0x0000d384, 0xf3307ff0 }, + { 0x0000a388, 0x0c000000 }, + { 0x0000a38c, 0x20202020 }, + { 0x0000a390, 0x20202020 }, + { 0x0000a394, 0x318c6318 }, + { 0x0000a398, 0x00000318 }, + { 0x0000a39c, 0x00000001 }, + { 0x0000a3a0, 0x00000000 }, + { 0x0000a3a4, 0x00000000 }, + { 0x0000a3a8, 0x00000000 }, + { 0x0000a3ac, 0x00000000 }, + { 0x0000a3b0, 0x00000000 }, + { 0x0000a3b4, 0x00000000 }, + { 0x0000a3b8, 0x00000000 }, + { 0x0000a3bc, 0x00000000 }, + { 0x0000a3c0, 0x00000000 }, + { 0x0000a3c4, 0x00000000 }, + { 0x0000a3cc, 0x20202020 }, + { 0x0000a3d0, 0x20202020 }, + { 0x0000a3d4, 0x20202020 }, + { 0x0000a3dc, 0x318c6318 }, + { 0x0000a3e0, 0x00000318 }, + { 0x0000a3e4, 0x00000000 }, + { 0x0000a3e8, 0x18c43433 }, + { 0x0000a3ec, 0x00f70081 }, + { 0x00007800, 0x00140000 }, + { 0x00007804, 0x0e4548d8 }, + { 0x00007808, 0x54214514 }, + { 0x0000780c, 0x02025820 }, + { 0x00007810, 0x71c0d388 }, + { 0x00007814, 0x924934a8 }, + { 0x0000781c, 0x00000000 }, + { 0x00007820, 0x00000c04 }, + { 0x00007824, 0x00d86fff }, + { 0x00007828, 0x26d2491b }, + { 0x0000782c, 0x6e36d97b }, + { 0x00007830, 0xedb6d96e }, + { 0x00007834, 0x71400087 }, + { 0x00007838, 0xfac68801 }, + { 0x0000783c, 0x0001fffe }, + { 0x00007840, 0xffeb1a20 }, + { 0x00007844, 0x000c0db6 }, + { 0x00007848, 0x6db61b6f }, + { 0x0000784c, 0x6d9b66db }, + { 0x00007850, 0x6d8c6dba }, + { 0x00007854, 0x00040000 }, + { 0x00007858, 0xdb003012 }, + { 0x0000785c, 0x04924914 }, + { 0x00007860, 0x21084210 }, + { 0x00007864, 0xf7d7ffde }, + { 0x00007868, 0xc2034080 }, + { 0x0000786c, 0x48609eb4 }, + { 0x00007870, 0x10142c00 }, +}; + +static const u_int32_t ar9285PciePhy_clkreq_always_on_L1_9285_1_2[][2] = { + {0x00004040, 0x9248fd00 }, + {0x00004040, 0x24924924 }, + {0x00004040, 0xa8000019 }, + {0x00004040, 0x13160820 }, + {0x00004040, 0xe5980560 }, + {0x00004040, 0xc01dcffd }, + {0x00004040, 0x1aaabe41 }, + {0x00004040, 0xbe105554 }, + {0x00004040, 0x00043007 }, + {0x00004044, 0x00000000 }, +}; + +static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285_1_2[][2] = { {0x00004040, 0x9248fd00 }, {0x00004040, 0x24924924 }, {0x00004040, 0xa8000019 }, {0x00004040, 0x13160820 }, {0x00004040, 0xe5980560 }, - {0x00004040, 0x401dcffd }, - {0x00004040, 0x1aaabe40 }, + {0x00004040, 0xc01dcffc }, + {0x00004040, 0x1aaabe41 }, {0x00004040, 0xbe105554 }, {0x00004040, 0x00043007 }, {0x00004044, 0x00000000 }, diff --git a/drivers/net/wireless/ath9k/mac.c b/drivers/net/wireless/ath9k/mac.c new file mode 100644 index 0000000000000000000000000000000000000000..af32d091dc38231b4d77ba321d56711e93297c7e --- /dev/null +++ b/drivers/net/wireless/ath9k/mac.c @@ -0,0 +1,946 @@ +/* + * Copyright (c) 2008 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "core.h" +#include "hw.h" +#include "reg.h" +#include "phy.h" + +static void ath9k_hw_set_txq_interrupts(struct ath_hal *ah, + struct ath9k_tx_queue_info *qi) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, + "tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n", + ahp->ah_txOkInterruptMask, ahp->ah_txErrInterruptMask, + ahp->ah_txDescInterruptMask, ahp->ah_txEolInterruptMask, + ahp->ah_txUrnInterruptMask); + + REG_WRITE(ah, AR_IMR_S0, + SM(ahp->ah_txOkInterruptMask, AR_IMR_S0_QCU_TXOK) + | SM(ahp->ah_txDescInterruptMask, AR_IMR_S0_QCU_TXDESC)); + REG_WRITE(ah, AR_IMR_S1, + SM(ahp->ah_txErrInterruptMask, AR_IMR_S1_QCU_TXERR) + | SM(ahp->ah_txEolInterruptMask, AR_IMR_S1_QCU_TXEOL)); + REG_RMW_FIELD(ah, AR_IMR_S2, + AR_IMR_S2_QCU_TXURN, ahp->ah_txUrnInterruptMask); +} + +u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q) +{ + return REG_READ(ah, AR_QTXDP(q)); +} + +bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q, u32 txdp) +{ + REG_WRITE(ah, AR_QTXDP(q), txdp); + + return true; +} + +bool ath9k_hw_txstart(struct ath_hal *ah, u32 q) +{ + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %u\n", q); + + REG_WRITE(ah, AR_Q_TXE, 1 << q); + + return true; +} + +u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q) +{ + u32 npend; + + npend = REG_READ(ah, AR_QSTS(q)) & AR_Q_STS_PEND_FR_CNT; + if (npend == 0) { + + if (REG_READ(ah, AR_Q_TXE) & (1 << q)) + npend = 1; + } + + return npend; +} + +bool ath9k_hw_updatetxtriglevel(struct ath_hal *ah, bool bIncTrigLevel) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + u32 txcfg, curLevel, newLevel; + enum ath9k_int omask; + + if (ah->ah_txTrigLevel >= MAX_TX_FIFO_THRESHOLD) + return false; + + omask = ath9k_hw_set_interrupts(ah, ahp->ah_maskReg & ~ATH9K_INT_GLOBAL); + + txcfg = REG_READ(ah, AR_TXCFG); + curLevel = MS(txcfg, AR_FTRIG); + newLevel = curLevel; + if (bIncTrigLevel) { + if (curLevel < MAX_TX_FIFO_THRESHOLD) + newLevel++; + } else if (curLevel > MIN_TX_FIFO_THRESHOLD) + newLevel--; + if (newLevel != curLevel) + REG_WRITE(ah, AR_TXCFG, + (txcfg & ~AR_FTRIG) | SM(newLevel, AR_FTRIG)); + + ath9k_hw_set_interrupts(ah, omask); + + ah->ah_txTrigLevel = newLevel; + + return newLevel != curLevel; +} + +bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q) +{ + u32 tsfLow, j, wait; + + REG_WRITE(ah, AR_Q_TXD, 1 << q); + + for (wait = 1000; wait != 0; wait--) { + if (ath9k_hw_numtxpending(ah, q) == 0) + break; + udelay(100); + } + + if (ath9k_hw_numtxpending(ah, q)) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, + "%s: Num of pending TX Frames %d on Q %d\n", + __func__, ath9k_hw_numtxpending(ah, q), q); + + for (j = 0; j < 2; j++) { + tsfLow = REG_READ(ah, AR_TSF_L32); + REG_WRITE(ah, AR_QUIET2, + SM(10, AR_QUIET2_QUIET_DUR)); + REG_WRITE(ah, AR_QUIET_PERIOD, 100); + REG_WRITE(ah, AR_NEXT_QUIET_TIMER, tsfLow >> 10); + REG_SET_BIT(ah, AR_TIMER_MODE, + AR_QUIET_TIMER_EN); + + if ((REG_READ(ah, AR_TSF_L32) >> 10) == (tsfLow >> 10)) + break; + + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, + "TSF have moved while trying to set " + "quiet time TSF: 0x%08x\n", tsfLow); + } + + REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH); + + udelay(200); + REG_CLR_BIT(ah, AR_TIMER_MODE, AR_QUIET_TIMER_EN); + + wait = 1000; + + while (ath9k_hw_numtxpending(ah, q)) { + if ((--wait) == 0) { + DPRINTF(ah->ah_sc, ATH_DBG_XMIT, + "Failed to stop Tx DMA in 100 " + "msec after killing last frame\n"); + break; + } + udelay(100); + } + + REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH); + } + + REG_WRITE(ah, AR_Q_TXD, 0); + + return wait != 0; +} + +bool ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds, + u32 segLen, bool firstSeg, + bool lastSeg, const struct ath_desc *ds0) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + if (firstSeg) { + ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_TxMore); + } else if (lastSeg) { + ads->ds_ctl0 = 0; + ads->ds_ctl1 = segLen; + ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2; + ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3; + } else { + ads->ds_ctl0 = 0; + ads->ds_ctl1 = segLen | AR_TxMore; + ads->ds_ctl2 = 0; + ads->ds_ctl3 = 0; + } + ads->ds_txstatus0 = ads->ds_txstatus1 = 0; + ads->ds_txstatus2 = ads->ds_txstatus3 = 0; + ads->ds_txstatus4 = ads->ds_txstatus5 = 0; + ads->ds_txstatus6 = ads->ds_txstatus7 = 0; + ads->ds_txstatus8 = ads->ds_txstatus9 = 0; + + return true; +} + +void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + ads->ds_txstatus0 = ads->ds_txstatus1 = 0; + ads->ds_txstatus2 = ads->ds_txstatus3 = 0; + ads->ds_txstatus4 = ads->ds_txstatus5 = 0; + ads->ds_txstatus6 = ads->ds_txstatus7 = 0; + ads->ds_txstatus8 = ads->ds_txstatus9 = 0; +} + +int ath9k_hw_txprocdesc(struct ath_hal *ah, struct ath_desc *ds) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + if ((ads->ds_txstatus9 & AR_TxDone) == 0) + return -EINPROGRESS; + + ds->ds_txstat.ts_seqnum = MS(ads->ds_txstatus9, AR_SeqNum); + ds->ds_txstat.ts_tstamp = ads->AR_SendTimestamp; + ds->ds_txstat.ts_status = 0; + ds->ds_txstat.ts_flags = 0; + + if (ads->ds_txstatus1 & AR_ExcessiveRetries) + ds->ds_txstat.ts_status |= ATH9K_TXERR_XRETRY; + if (ads->ds_txstatus1 & AR_Filtered) + ds->ds_txstat.ts_status |= ATH9K_TXERR_FILT; + if (ads->ds_txstatus1 & AR_FIFOUnderrun) { + ds->ds_txstat.ts_status |= ATH9K_TXERR_FIFO; + ath9k_hw_updatetxtriglevel(ah, true); + } + if (ads->ds_txstatus9 & AR_TxOpExceeded) + ds->ds_txstat.ts_status |= ATH9K_TXERR_XTXOP; + if (ads->ds_txstatus1 & AR_TxTimerExpired) + ds->ds_txstat.ts_status |= ATH9K_TXERR_TIMER_EXPIRED; + + if (ads->ds_txstatus1 & AR_DescCfgErr) + ds->ds_txstat.ts_flags |= ATH9K_TX_DESC_CFG_ERR; + if (ads->ds_txstatus1 & AR_TxDataUnderrun) { + ds->ds_txstat.ts_flags |= ATH9K_TX_DATA_UNDERRUN; + ath9k_hw_updatetxtriglevel(ah, true); + } + if (ads->ds_txstatus1 & AR_TxDelimUnderrun) { + ds->ds_txstat.ts_flags |= ATH9K_TX_DELIM_UNDERRUN; + ath9k_hw_updatetxtriglevel(ah, true); + } + if (ads->ds_txstatus0 & AR_TxBaStatus) { + ds->ds_txstat.ts_flags |= ATH9K_TX_BA; + ds->ds_txstat.ba_low = ads->AR_BaBitmapLow; + ds->ds_txstat.ba_high = ads->AR_BaBitmapHigh; + } + + ds->ds_txstat.ts_rateindex = MS(ads->ds_txstatus9, AR_FinalTxIdx); + switch (ds->ds_txstat.ts_rateindex) { + case 0: + ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate0); + break; + case 1: + ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate1); + break; + case 2: + ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate2); + break; + case 3: + ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate3); + break; + } + + ds->ds_txstat.ts_rssi = MS(ads->ds_txstatus5, AR_TxRSSICombined); + ds->ds_txstat.ts_rssi_ctl0 = MS(ads->ds_txstatus0, AR_TxRSSIAnt00); + ds->ds_txstat.ts_rssi_ctl1 = MS(ads->ds_txstatus0, AR_TxRSSIAnt01); + ds->ds_txstat.ts_rssi_ctl2 = MS(ads->ds_txstatus0, AR_TxRSSIAnt02); + ds->ds_txstat.ts_rssi_ext0 = MS(ads->ds_txstatus5, AR_TxRSSIAnt10); + ds->ds_txstat.ts_rssi_ext1 = MS(ads->ds_txstatus5, AR_TxRSSIAnt11); + ds->ds_txstat.ts_rssi_ext2 = MS(ads->ds_txstatus5, AR_TxRSSIAnt12); + ds->ds_txstat.evm0 = ads->AR_TxEVM0; + ds->ds_txstat.evm1 = ads->AR_TxEVM1; + ds->ds_txstat.evm2 = ads->AR_TxEVM2; + ds->ds_txstat.ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt); + ds->ds_txstat.ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt); + ds->ds_txstat.ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt); + ds->ds_txstat.ts_antenna = 1; + + return 0; +} + +void ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds, + u32 pktLen, enum ath9k_pkt_type type, u32 txPower, + u32 keyIx, enum ath9k_key_type keyType, u32 flags) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + struct ath_hal_5416 *ahp = AH5416(ah); + + txPower += ahp->ah_txPowerIndexOffset; + if (txPower > 63) + txPower = 63; + + ads->ds_ctl0 = (pktLen & AR_FrameLen) + | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) + | SM(txPower, AR_XmitPower) + | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) + | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0) + | (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0) + | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0); + + ads->ds_ctl1 = + (keyIx != ATH9K_TXKEYIX_INVALID ? SM(keyIx, AR_DestIdx) : 0) + | SM(type, AR_FrameType) + | (flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0) + | (flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0) + | (flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0); + + ads->ds_ctl6 = SM(keyType, AR_EncrType); + + if (AR_SREV_9285(ah)) { + ads->ds_ctl8 = 0; + ads->ds_ctl9 = 0; + ads->ds_ctl10 = 0; + ads->ds_ctl11 = 0; + } +} + +void ath9k_hw_set11n_ratescenario(struct ath_hal *ah, struct ath_desc *ds, + struct ath_desc *lastds, + u32 durUpdateEn, u32 rtsctsRate, + u32 rtsctsDuration, + struct ath9k_11n_rate_series series[], + u32 nseries, u32 flags) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + struct ar5416_desc *last_ads = AR5416DESC(lastds); + u32 ds_ctl0; + + (void) nseries; + (void) rtsctsDuration; + + if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) { + ds_ctl0 = ads->ds_ctl0; + + if (flags & ATH9K_TXDESC_RTSENA) { + ds_ctl0 &= ~AR_CTSEnable; + ds_ctl0 |= AR_RTSEnable; + } else { + ds_ctl0 &= ~AR_RTSEnable; + ds_ctl0 |= AR_CTSEnable; + } + + ads->ds_ctl0 = ds_ctl0; + } else { + ads->ds_ctl0 = + (ads->ds_ctl0 & ~(AR_RTSEnable | AR_CTSEnable)); + } + + ads->ds_ctl2 = set11nTries(series, 0) + | set11nTries(series, 1) + | set11nTries(series, 2) + | set11nTries(series, 3) + | (durUpdateEn ? AR_DurUpdateEna : 0) + | SM(0, AR_BurstDur); + + ads->ds_ctl3 = set11nRate(series, 0) + | set11nRate(series, 1) + | set11nRate(series, 2) + | set11nRate(series, 3); + + ads->ds_ctl4 = set11nPktDurRTSCTS(series, 0) + | set11nPktDurRTSCTS(series, 1); + + ads->ds_ctl5 = set11nPktDurRTSCTS(series, 2) + | set11nPktDurRTSCTS(series, 3); + + ads->ds_ctl7 = set11nRateFlags(series, 0) + | set11nRateFlags(series, 1) + | set11nRateFlags(series, 2) + | set11nRateFlags(series, 3) + | SM(rtsctsRate, AR_RTSCTSRate); + last_ads->ds_ctl2 = ads->ds_ctl2; + last_ads->ds_ctl3 = ads->ds_ctl3; +} + +void ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds, + u32 aggrLen) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr); + ads->ds_ctl6 &= ~AR_AggrLen; + ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen); +} + +void ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds, + u32 numDelims) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + unsigned int ctl6; + + ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr); + + ctl6 = ads->ds_ctl6; + ctl6 &= ~AR_PadDelim; + ctl6 |= SM(numDelims, AR_PadDelim); + ads->ds_ctl6 = ctl6; +} + +void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + ads->ds_ctl1 |= AR_IsAggr; + ads->ds_ctl1 &= ~AR_MoreAggr; + ads->ds_ctl6 &= ~AR_PadDelim; +} + +void ath9k_hw_clr11n_aggr(struct ath_hal *ah, struct ath_desc *ds) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr); +} + +void ath9k_hw_set11n_burstduration(struct ath_hal *ah, struct ath_desc *ds, + u32 burstDuration) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + ads->ds_ctl2 &= ~AR_BurstDur; + ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur); +} + +void ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah, struct ath_desc *ds, + u32 vmf) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + if (vmf) + ads->ds_ctl0 |= AR_VirtMoreFrag; + else + ads->ds_ctl0 &= ~AR_VirtMoreFrag; +} + +void ath9k_hw_gettxintrtxqs(struct ath_hal *ah, u32 *txqs) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + *txqs &= ahp->ah_intrTxqs; + ahp->ah_intrTxqs &= ~(*txqs); +} + +bool ath9k_hw_set_txq_props(struct ath_hal *ah, int q, + const struct ath9k_tx_queue_info *qinfo) +{ + u32 cw; + struct ath_hal_5416 *ahp = AH5416(ah); + struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + struct ath9k_tx_queue_info *qi; + + if (q >= pCap->total_queues) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q); + return false; + } + + qi = &ahp->ah_txq[q]; + if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue\n"); + return false; + } + + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %p\n", qi); + + qi->tqi_ver = qinfo->tqi_ver; + qi->tqi_subtype = qinfo->tqi_subtype; + qi->tqi_qflags = qinfo->tqi_qflags; + qi->tqi_priority = qinfo->tqi_priority; + if (qinfo->tqi_aifs != ATH9K_TXQ_USEDEFAULT) + qi->tqi_aifs = min(qinfo->tqi_aifs, 255U); + else + qi->tqi_aifs = INIT_AIFS; + if (qinfo->tqi_cwmin != ATH9K_TXQ_USEDEFAULT) { + cw = min(qinfo->tqi_cwmin, 1024U); + qi->tqi_cwmin = 1; + while (qi->tqi_cwmin < cw) + qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1; + } else + qi->tqi_cwmin = qinfo->tqi_cwmin; + if (qinfo->tqi_cwmax != ATH9K_TXQ_USEDEFAULT) { + cw = min(qinfo->tqi_cwmax, 1024U); + qi->tqi_cwmax = 1; + while (qi->tqi_cwmax < cw) + qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1; + } else + qi->tqi_cwmax = INIT_CWMAX; + + if (qinfo->tqi_shretry != 0) + qi->tqi_shretry = min((u32) qinfo->tqi_shretry, 15U); + else + qi->tqi_shretry = INIT_SH_RETRY; + if (qinfo->tqi_lgretry != 0) + qi->tqi_lgretry = min((u32) qinfo->tqi_lgretry, 15U); + else + qi->tqi_lgretry = INIT_LG_RETRY; + qi->tqi_cbrPeriod = qinfo->tqi_cbrPeriod; + qi->tqi_cbrOverflowLimit = qinfo->tqi_cbrOverflowLimit; + qi->tqi_burstTime = qinfo->tqi_burstTime; + qi->tqi_readyTime = qinfo->tqi_readyTime; + + switch (qinfo->tqi_subtype) { + case ATH9K_WME_UPSD: + if (qi->tqi_type == ATH9K_TX_QUEUE_DATA) + qi->tqi_intFlags = ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS; + break; + default: + break; + } + + return true; +} + +bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q, + struct ath9k_tx_queue_info *qinfo) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + struct ath9k_tx_queue_info *qi; + + if (q >= pCap->total_queues) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q); + return false; + } + + qi = &ahp->ah_txq[q]; + if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue\n"); + return false; + } + + qinfo->tqi_qflags = qi->tqi_qflags; + qinfo->tqi_ver = qi->tqi_ver; + qinfo->tqi_subtype = qi->tqi_subtype; + qinfo->tqi_qflags = qi->tqi_qflags; + qinfo->tqi_priority = qi->tqi_priority; + qinfo->tqi_aifs = qi->tqi_aifs; + qinfo->tqi_cwmin = qi->tqi_cwmin; + qinfo->tqi_cwmax = qi->tqi_cwmax; + qinfo->tqi_shretry = qi->tqi_shretry; + qinfo->tqi_lgretry = qi->tqi_lgretry; + qinfo->tqi_cbrPeriod = qi->tqi_cbrPeriod; + qinfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit; + qinfo->tqi_burstTime = qi->tqi_burstTime; + qinfo->tqi_readyTime = qi->tqi_readyTime; + + return true; +} + +int ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type, + const struct ath9k_tx_queue_info *qinfo) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ath9k_tx_queue_info *qi; + struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + int q; + + switch (type) { + case ATH9K_TX_QUEUE_BEACON: + q = pCap->total_queues - 1; + break; + case ATH9K_TX_QUEUE_CAB: + q = pCap->total_queues - 2; + break; + case ATH9K_TX_QUEUE_PSPOLL: + q = 1; + break; + case ATH9K_TX_QUEUE_UAPSD: + q = pCap->total_queues - 3; + break; + case ATH9K_TX_QUEUE_DATA: + for (q = 0; q < pCap->total_queues; q++) + if (ahp->ah_txq[q].tqi_type == + ATH9K_TX_QUEUE_INACTIVE) + break; + if (q == pCap->total_queues) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, + "no available tx queue\n"); + return -1; + } + break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "bad tx queue type %u\n", type); + return -1; + } + + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %u\n", q); + + qi = &ahp->ah_txq[q]; + if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, + "tx queue %u already active\n", q); + return -1; + } + memset(qi, 0, sizeof(struct ath9k_tx_queue_info)); + qi->tqi_type = type; + if (qinfo == NULL) { + qi->tqi_qflags = + TXQ_FLAG_TXOKINT_ENABLE + | TXQ_FLAG_TXERRINT_ENABLE + | TXQ_FLAG_TXDESCINT_ENABLE | TXQ_FLAG_TXURNINT_ENABLE; + qi->tqi_aifs = INIT_AIFS; + qi->tqi_cwmin = ATH9K_TXQ_USEDEFAULT; + qi->tqi_cwmax = INIT_CWMAX; + qi->tqi_shretry = INIT_SH_RETRY; + qi->tqi_lgretry = INIT_LG_RETRY; + qi->tqi_physCompBuf = 0; + } else { + qi->tqi_physCompBuf = qinfo->tqi_physCompBuf; + (void) ath9k_hw_set_txq_props(ah, q, qinfo); + } + + return q; +} + +bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + struct ath9k_tx_queue_info *qi; + + if (q >= pCap->total_queues) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q); + return false; + } + qi = &ahp->ah_txq[q]; + if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue %u\n", q); + return false; + } + + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "release queue %u\n", q); + + qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE; + ahp->ah_txOkInterruptMask &= ~(1 << q); + ahp->ah_txErrInterruptMask &= ~(1 << q); + ahp->ah_txDescInterruptMask &= ~(1 << q); + ahp->ah_txEolInterruptMask &= ~(1 << q); + ahp->ah_txUrnInterruptMask &= ~(1 << q); + ath9k_hw_set_txq_interrupts(ah, qi); + + return true; +} + +bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + struct ath9k_channel *chan = ah->ah_curchan; + struct ath9k_tx_queue_info *qi; + u32 cwMin, chanCwMin, value; + + if (q >= pCap->total_queues) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q); + return false; + } + + qi = &ahp->ah_txq[q]; + if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue %u\n", q); + return true; + } + + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "reset queue %u\n", q); + + if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) { + if (chan && IS_CHAN_B(chan)) + chanCwMin = INIT_CWMIN_11B; + else + chanCwMin = INIT_CWMIN; + + for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1); + } else + cwMin = qi->tqi_cwmin; + + REG_WRITE(ah, AR_DLCL_IFS(q), + SM(cwMin, AR_D_LCL_IFS_CWMIN) | + SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX) | + SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS)); + + REG_WRITE(ah, AR_DRETRY_LIMIT(q), + SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH) | + SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG) | + SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH)); + + REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ); + REG_WRITE(ah, AR_DMISC(q), + AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2); + + if (qi->tqi_cbrPeriod) { + REG_WRITE(ah, AR_QCBRCFG(q), + SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) | + SM(qi->tqi_cbrOverflowLimit, AR_Q_CBRCFG_OVF_THRESH)); + REG_WRITE(ah, AR_QMISC(q), + REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_FSP_CBR | + (qi->tqi_cbrOverflowLimit ? + AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN : 0)); + } + if (qi->tqi_readyTime && (qi->tqi_type != ATH9K_TX_QUEUE_CAB)) { + REG_WRITE(ah, AR_QRDYTIMECFG(q), + SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_DURATION) | + AR_Q_RDYTIMECFG_EN); + } + + REG_WRITE(ah, AR_DCHNTIME(q), + SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) | + (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0)); + + if (qi->tqi_burstTime + && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)) { + REG_WRITE(ah, AR_QMISC(q), + REG_READ(ah, AR_QMISC(q)) | + AR_Q_MISC_RDYTIME_EXP_POLICY); + + } + + if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE) { + REG_WRITE(ah, AR_DMISC(q), + REG_READ(ah, AR_DMISC(q)) | + AR_D_MISC_POST_FR_BKOFF_DIS); + } + if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) { + REG_WRITE(ah, AR_DMISC(q), + REG_READ(ah, AR_DMISC(q)) | + AR_D_MISC_FRAG_BKOFF_EN); + } + switch (qi->tqi_type) { + case ATH9K_TX_QUEUE_BEACON: + REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q)) + | AR_Q_MISC_FSP_DBA_GATED + | AR_Q_MISC_BEACON_USE + | AR_Q_MISC_CBR_INCR_DIS1); + + REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) + | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << + AR_D_MISC_ARB_LOCKOUT_CNTRL_S) + | AR_D_MISC_BEACON_USE + | AR_D_MISC_POST_FR_BKOFF_DIS); + break; + case ATH9K_TX_QUEUE_CAB: + REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q)) + | AR_Q_MISC_FSP_DBA_GATED + | AR_Q_MISC_CBR_INCR_DIS1 + | AR_Q_MISC_CBR_INCR_DIS0); + value = (qi->tqi_readyTime - + (ah->ah_config.sw_beacon_response_time - + ah->ah_config.dma_beacon_response_time) - + ah->ah_config.additional_swba_backoff) * 1024; + REG_WRITE(ah, AR_QRDYTIMECFG(q), + value | AR_Q_RDYTIMECFG_EN); + REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) + | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << + AR_D_MISC_ARB_LOCKOUT_CNTRL_S)); + break; + case ATH9K_TX_QUEUE_PSPOLL: + REG_WRITE(ah, AR_QMISC(q), + REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_CBR_INCR_DIS1); + break; + case ATH9K_TX_QUEUE_UAPSD: + REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) | + AR_D_MISC_POST_FR_BKOFF_DIS); + break; + default: + break; + } + + if (qi->tqi_intFlags & ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS) { + REG_WRITE(ah, AR_DMISC(q), + REG_READ(ah, AR_DMISC(q)) | + SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL, + AR_D_MISC_ARB_LOCKOUT_CNTRL) | + AR_D_MISC_POST_FR_BKOFF_DIS); + } + + if (qi->tqi_qflags & TXQ_FLAG_TXOKINT_ENABLE) + ahp->ah_txOkInterruptMask |= 1 << q; + else + ahp->ah_txOkInterruptMask &= ~(1 << q); + if (qi->tqi_qflags & TXQ_FLAG_TXERRINT_ENABLE) + ahp->ah_txErrInterruptMask |= 1 << q; + else + ahp->ah_txErrInterruptMask &= ~(1 << q); + if (qi->tqi_qflags & TXQ_FLAG_TXDESCINT_ENABLE) + ahp->ah_txDescInterruptMask |= 1 << q; + else + ahp->ah_txDescInterruptMask &= ~(1 << q); + if (qi->tqi_qflags & TXQ_FLAG_TXEOLINT_ENABLE) + ahp->ah_txEolInterruptMask |= 1 << q; + else + ahp->ah_txEolInterruptMask &= ~(1 << q); + if (qi->tqi_qflags & TXQ_FLAG_TXURNINT_ENABLE) + ahp->ah_txUrnInterruptMask |= 1 << q; + else + ahp->ah_txUrnInterruptMask &= ~(1 << q); + ath9k_hw_set_txq_interrupts(ah, qi); + + return true; +} + +int ath9k_hw_rxprocdesc(struct ath_hal *ah, struct ath_desc *ds, + u32 pa, struct ath_desc *nds, u64 tsf) +{ + struct ar5416_desc ads; + struct ar5416_desc *adsp = AR5416DESC(ds); + u32 phyerr; + + if ((adsp->ds_rxstatus8 & AR_RxDone) == 0) + return -EINPROGRESS; + + ads.u.rx = adsp->u.rx; + + ds->ds_rxstat.rs_status = 0; + ds->ds_rxstat.rs_flags = 0; + + ds->ds_rxstat.rs_datalen = ads.ds_rxstatus1 & AR_DataLen; + ds->ds_rxstat.rs_tstamp = ads.AR_RcvTimestamp; + + ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined); + ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt00); + ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt01); + ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt02); + ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt10); + ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt11); + ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt12); + if (ads.ds_rxstatus8 & AR_RxKeyIdxValid) + ds->ds_rxstat.rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx); + else + ds->ds_rxstat.rs_keyix = ATH9K_RXKEYIX_INVALID; + + ds->ds_rxstat.rs_rate = RXSTATUS_RATE(ah, (&ads)); + ds->ds_rxstat.rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0; + + ds->ds_rxstat.rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0; + ds->ds_rxstat.rs_moreaggr = + (ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0; + ds->ds_rxstat.rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna); + ds->ds_rxstat.rs_flags = + (ads.ds_rxstatus3 & AR_GI) ? ATH9K_RX_GI : 0; + ds->ds_rxstat.rs_flags |= + (ads.ds_rxstatus3 & AR_2040) ? ATH9K_RX_2040 : 0; + + if (ads.ds_rxstatus8 & AR_PreDelimCRCErr) + ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_PRE; + if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) + ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_POST; + if (ads.ds_rxstatus8 & AR_DecryptBusyErr) + ds->ds_rxstat.rs_flags |= ATH9K_RX_DECRYPT_BUSY; + + if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) { + if (ads.ds_rxstatus8 & AR_CRCErr) + ds->ds_rxstat.rs_status |= ATH9K_RXERR_CRC; + else if (ads.ds_rxstatus8 & AR_PHYErr) { + ds->ds_rxstat.rs_status |= ATH9K_RXERR_PHY; + phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode); + ds->ds_rxstat.rs_phyerr = phyerr; + } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr) + ds->ds_rxstat.rs_status |= ATH9K_RXERR_DECRYPT; + else if (ads.ds_rxstatus8 & AR_MichaelErr) + ds->ds_rxstat.rs_status |= ATH9K_RXERR_MIC; + } + + return 0; +} + +bool ath9k_hw_setuprxdesc(struct ath_hal *ah, struct ath_desc *ds, + u32 size, u32 flags) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + + ads->ds_ctl1 = size & AR_BufLen; + if (flags & ATH9K_RXDESC_INTREQ) + ads->ds_ctl1 |= AR_RxIntrReq; + + ads->ds_rxstatus8 &= ~AR_RxDone; + if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) + memset(&(ads->u), 0, sizeof(ads->u)); + + return true; +} + +bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set) +{ + u32 reg; + + if (set) { + REG_SET_BIT(ah, AR_DIAG_SW, + (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); + + if (!ath9k_hw_wait(ah, AR_OBS_BUS_1, AR_OBS_BUS_1_RX_STATE, 0)) { + REG_CLR_BIT(ah, AR_DIAG_SW, + (AR_DIAG_RX_DIS | + AR_DIAG_RX_ABORT)); + + reg = REG_READ(ah, AR_OBS_BUS_1); + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "rx failed to go idle in 10 ms RXSM=0x%x\n", reg); + + return false; + } + } else { + REG_CLR_BIT(ah, AR_DIAG_SW, + (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); + } + + return true; +} + +void ath9k_hw_putrxbuf(struct ath_hal *ah, u32 rxdp) +{ + REG_WRITE(ah, AR_RXDP, rxdp); +} + +void ath9k_hw_rxena(struct ath_hal *ah) +{ + REG_WRITE(ah, AR_CR, AR_CR_RXE); +} + +void ath9k_hw_startpcureceive(struct ath_hal *ah) +{ + ath9k_enable_mib_counters(ah); + + ath9k_ani_reset(ah); + + REG_CLR_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); +} + +void ath9k_hw_stoppcurecv(struct ath_hal *ah) +{ + REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS); + + ath9k_hw_disable_mib_counters(ah); +} + +bool ath9k_hw_stopdmarecv(struct ath_hal *ah) +{ + REG_WRITE(ah, AR_CR, AR_CR_RXD); + + if (!ath9k_hw_wait(ah, AR_CR, AR_CR_RXE, 0)) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, + "dma failed to stop in 10ms\n" + "AR_CR=0x%08x\nAR_DIAG_SW=0x%08x\n", + REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW)); + return false; + } else { + return true; + } +} diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index f05f584ab7bc960f9e8ba5ea29207ec63582bd2c..191eec50dc751c1fff9142f76d7960a5eb4c23db 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -14,15 +14,13 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* mac80211 and PCI callbacks */ - #include #include "core.h" +#include "reg.h" +#include "hw.h" #define ATH_PCI_VERSION "0.1" -#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13 - static char *dev_info = "ath9k"; MODULE_AUTHOR("Atheros Communications"); @@ -36,258 +34,79 @@ static struct pci_device_id ath_pci_id_table[] __devinitdata = { { PCI_VDEVICE(ATHEROS, 0x0027) }, /* PCI */ { PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */ { PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */ + { PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */ { 0 } }; -static int ath_get_channel(struct ath_softc *sc, - struct ieee80211_channel *chan) -{ - int i; +static void ath_detach(struct ath_softc *sc); - for (i = 0; i < sc->sc_ah->ah_nchan; i++) { - if (sc->sc_ah->ah_channels[i].channel == chan->center_freq) - return i; - } - - return -1; -} +/* return bus cachesize in 4B word units */ -static u32 ath_get_extchanmode(struct ath_softc *sc, - struct ieee80211_channel *chan) +static void bus_read_cachesize(struct ath_softc *sc, int *csz) { - u32 chanmode = 0; - u8 ext_chan_offset = sc->sc_ht_info.ext_chan_offset; - enum ath9k_ht_macmode tx_chan_width = sc->sc_ht_info.tx_chan_width; - - switch (chan->band) { - case IEEE80211_BAND_2GHZ: - if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_NONE) && - (tx_chan_width == ATH9K_HT_MACMODE_20)) - chanmode = CHANNEL_G_HT20; - if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_ABOVE) && - (tx_chan_width == ATH9K_HT_MACMODE_2040)) - chanmode = CHANNEL_G_HT40PLUS; - if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_BELOW) && - (tx_chan_width == ATH9K_HT_MACMODE_2040)) - chanmode = CHANNEL_G_HT40MINUS; - break; - case IEEE80211_BAND_5GHZ: - if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_NONE) && - (tx_chan_width == ATH9K_HT_MACMODE_20)) - chanmode = CHANNEL_A_HT20; - if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_ABOVE) && - (tx_chan_width == ATH9K_HT_MACMODE_2040)) - chanmode = CHANNEL_A_HT40PLUS; - if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_BELOW) && - (tx_chan_width == ATH9K_HT_MACMODE_2040)) - chanmode = CHANNEL_A_HT40MINUS; - break; - default: - break; - } - - return chanmode; -} + u8 u8tmp; + pci_read_config_byte(sc->pdev, PCI_CACHE_LINE_SIZE, (u8 *)&u8tmp); + *csz = (int)u8tmp; -static int ath_setkey_tkip(struct ath_softc *sc, - struct ieee80211_key_conf *key, - struct ath9k_keyval *hk, - const u8 *addr) -{ - u8 *key_rxmic = NULL; - u8 *key_txmic = NULL; - - key_txmic = key->key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY; - key_rxmic = key->key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY; - - if (addr == NULL) { - /* Group key installation */ - memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); - return ath_keyset(sc, key->keyidx, hk, addr); - } - if (!sc->sc_splitmic) { - /* - * data key goes at first index, - * the hal handles the MIC keys at index+64. - */ - memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); - memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic)); - return ath_keyset(sc, key->keyidx, hk, addr); - } /* - * TX key goes at first index, RX key at +32. - * The hal handles the MIC keys at index+64. + * This check was put in to avoid "unplesant" consequences if + * the bootrom has not fully initialized all PCI devices. + * Sometimes the cache line size register is not set */ - memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); - if (!ath_keyset(sc, key->keyidx, hk, NULL)) { - /* Txmic entry failed. No need to proceed further */ - DPRINTF(sc, ATH_DBG_KEYCACHE, - "%s Setting TX MIC Key Failed\n", __func__); - return 0; - } - memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); - /* XXX delete tx key on failure? */ - return ath_keyset(sc, key->keyidx+32, hk, addr); + if (*csz == 0) + *csz = DEFAULT_CACHELINE >> 2; /* Use the default size */ } -static int ath_key_config(struct ath_softc *sc, - const u8 *addr, - struct ieee80211_key_conf *key) +static void ath_setcurmode(struct ath_softc *sc, enum wireless_mode mode) { - struct ieee80211_vif *vif; - struct ath9k_keyval hk; - const u8 *mac = NULL; - int ret = 0; - enum nl80211_iftype opmode; - - memset(&hk, 0, sizeof(hk)); - - switch (key->alg) { - case ALG_WEP: - hk.kv_type = ATH9K_CIPHER_WEP; - break; - case ALG_TKIP: - hk.kv_type = ATH9K_CIPHER_TKIP; - break; - case ALG_CCMP: - hk.kv_type = ATH9K_CIPHER_AES_CCM; - break; - default: - return -EINVAL; - } - - hk.kv_len = key->keylen; - memcpy(hk.kv_val, key->key, key->keylen); - - if (!sc->sc_vaps[0]) - return -EIO; - - vif = sc->sc_vaps[0]->av_if_data; - opmode = vif->type; - + sc->cur_rate_table = sc->hw_rate_table[mode]; /* - * Strategy: - * For _M_STA mc tx, we will not setup a key at all since we never - * tx mc. - * _M_STA mc rx, we will use the keyID. - * for _M_IBSS mc tx, we will use the keyID, and no macaddr. - * for _M_IBSS mc rx, we will alloc a slot and plumb the mac of the - * peer node. BUT we will plumb a cleartext key so that we can do - * perSta default key table lookup in software. + * All protection frames are transmited at 2Mb/s for + * 11g, otherwise at 1Mb/s. + * XXX select protection rate index from rate table. */ - if (is_broadcast_ether_addr(addr)) { - switch (opmode) { - case NL80211_IFTYPE_STATION: - /* default key: could be group WPA key - * or could be static WEP key */ - mac = NULL; - break; - case NL80211_IFTYPE_ADHOC: - break; - case NL80211_IFTYPE_AP: - break; - default: - ASSERT(0); - break; - } - } else { - mac = addr; - } - - if (key->alg == ALG_TKIP) - ret = ath_setkey_tkip(sc, key, &hk, mac); - else - ret = ath_keyset(sc, key->keyidx, &hk, mac); - - if (!ret) - return -EIO; - - return 0; + sc->sc_protrix = (mode == ATH9K_MODE_11G ? 1 : 0); } -static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key) +static enum wireless_mode ath_chan2mode(struct ath9k_channel *chan) { - int freeslot; - - freeslot = (key->keyidx >= 4) ? 1 : 0; - ath_key_reset(sc, key->keyidx, freeslot); + if (chan->chanmode == CHANNEL_A) + return ATH9K_MODE_11A; + else if (chan->chanmode == CHANNEL_G) + return ATH9K_MODE_11G; + else if (chan->chanmode == CHANNEL_B) + return ATH9K_MODE_11B; + else if (chan->chanmode == CHANNEL_A_HT20) + return ATH9K_MODE_11NA_HT20; + else if (chan->chanmode == CHANNEL_G_HT20) + return ATH9K_MODE_11NG_HT20; + else if (chan->chanmode == CHANNEL_A_HT40PLUS) + return ATH9K_MODE_11NA_HT40PLUS; + else if (chan->chanmode == CHANNEL_A_HT40MINUS) + return ATH9K_MODE_11NA_HT40MINUS; + else if (chan->chanmode == CHANNEL_G_HT40PLUS) + return ATH9K_MODE_11NG_HT40PLUS; + else if (chan->chanmode == CHANNEL_G_HT40MINUS) + return ATH9K_MODE_11NG_HT40MINUS; + + WARN_ON(1); /* should not get here */ + + return ATH9K_MODE_11B; } -static void setup_ht_cap(struct ieee80211_ht_info *ht_info) +static void ath_update_txpow(struct ath_softc *sc) { -#define ATH9K_HT_CAP_MAXRXAMPDU_65536 0x3 /* 2 ^ 16 */ -#define ATH9K_HT_CAP_MPDUDENSITY_8 0x6 /* 8 usec */ - - ht_info->ht_supported = 1; - ht_info->cap = (u16)IEEE80211_HT_CAP_SUP_WIDTH - |(u16)IEEE80211_HT_CAP_SM_PS - |(u16)IEEE80211_HT_CAP_SGI_40 - |(u16)IEEE80211_HT_CAP_DSSSCCK40; - - ht_info->ampdu_factor = ATH9K_HT_CAP_MAXRXAMPDU_65536; - ht_info->ampdu_density = ATH9K_HT_CAP_MPDUDENSITY_8; - /* setup supported mcs set */ - memset(ht_info->supp_mcs_set, 0, 16); - ht_info->supp_mcs_set[0] = 0xff; - ht_info->supp_mcs_set[1] = 0xff; - ht_info->supp_mcs_set[12] = IEEE80211_HT_CAP_MCS_TX_DEFINED; -} - -static int ath_rate2idx(struct ath_softc *sc, int rate) -{ - int i = 0, cur_band, n_rates; - struct ieee80211_hw *hw = sc->hw; - - cur_band = hw->conf.channel->band; - n_rates = sc->sbands[cur_band].n_bitrates; + struct ath_hal *ah = sc->sc_ah; + u32 txpow; - for (i = 0; i < n_rates; i++) { - if (sc->sbands[cur_band].bitrates[i].bitrate == rate) - break; + if (sc->sc_curtxpow != sc->sc_config.txpowlimit) { + ath9k_hw_set_txpowerlimit(ah, sc->sc_config.txpowlimit); + /* read back in case value is clamped */ + ath9k_hw_getcapability(ah, ATH9K_CAP_TXPOW, 1, &txpow); + sc->sc_curtxpow = txpow; } - - /* - * NB:mac80211 validates rx rate index against the supported legacy rate - * index only (should be done against ht rates also), return the highest - * legacy rate index for rx rate which does not match any one of the - * supported basic and extended rates to make mac80211 happy. - * The following hack will be cleaned up once the issue with - * the rx rate index validation in mac80211 is fixed. - */ - if (i == n_rates) - return n_rates - 1; - return i; -} - -static void ath9k_rx_prepare(struct ath_softc *sc, - struct sk_buff *skb, - struct ath_recv_status *status, - struct ieee80211_rx_status *rx_status) -{ - struct ieee80211_hw *hw = sc->hw; - struct ieee80211_channel *curchan = hw->conf.channel; - - memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); - - rx_status->mactime = status->tsf; - rx_status->band = curchan->band; - rx_status->freq = curchan->center_freq; - rx_status->noise = sc->sc_ani.sc_noise_floor; - rx_status->signal = rx_status->noise + status->rssi; - rx_status->rate_idx = ath_rate2idx(sc, (status->rateKbps / 100)); - rx_status->antenna = status->antenna; - - /* XXX Fix me, 64 cannot be the max rssi value, rigure it out */ - rx_status->qual = status->rssi * 100 / 64; - - if (status->flags & ATH_RX_MIC_ERROR) - rx_status->flag |= RX_FLAG_MMIC_ERROR; - if (status->flags & ATH_RX_FCS_ERROR) - rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; - - rx_status->flag |= RX_FLAG_TSFT; } static u8 parse_mpdudensity(u8 mpdudensity) @@ -325,241 +144,803 @@ static u8 parse_mpdudensity(u8 mpdudensity) } } -static void ath9k_ht_conf(struct ath_softc *sc, - struct ieee80211_bss_conf *bss_conf) +static void ath_setup_rates(struct ath_softc *sc, enum ieee80211_band band) { -#define IEEE80211_HT_CAP_40MHZ_INTOLERANT BIT(14) - struct ath_ht_info *ht_info = &sc->sc_ht_info; + struct ath_rate_table *rate_table = NULL; + struct ieee80211_supported_band *sband; + struct ieee80211_rate *rate; + int i, maxrates; - if (bss_conf->assoc_ht) { - ht_info->ext_chan_offset = - bss_conf->ht_bss_conf->bss_cap & - IEEE80211_HT_IE_CHA_SEC_OFFSET; + switch (band) { + case IEEE80211_BAND_2GHZ: + rate_table = sc->hw_rate_table[ATH9K_MODE_11G]; + break; + case IEEE80211_BAND_5GHZ: + rate_table = sc->hw_rate_table[ATH9K_MODE_11A]; + break; + default: + break; + } - if (!(bss_conf->ht_conf->cap & - IEEE80211_HT_CAP_40MHZ_INTOLERANT) && - (bss_conf->ht_bss_conf->bss_cap & - IEEE80211_HT_IE_CHA_WIDTH)) - ht_info->tx_chan_width = ATH9K_HT_MACMODE_2040; - else - ht_info->tx_chan_width = ATH9K_HT_MACMODE_20; + if (rate_table == NULL) + return; - ath9k_hw_set11nmac2040(sc->sc_ah, ht_info->tx_chan_width); - ht_info->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + - bss_conf->ht_conf->ampdu_factor); - ht_info->mpdudensity = - parse_mpdudensity(bss_conf->ht_conf->ampdu_density); + sband = &sc->sbands[band]; + rate = sc->rates[band]; + if (rate_table->rate_cnt > ATH_RATE_MAX) + maxrates = ATH_RATE_MAX; + else + maxrates = rate_table->rate_cnt; + + for (i = 0; i < maxrates; i++) { + rate[i].bitrate = rate_table->info[i].ratekbps / 100; + rate[i].hw_value = rate_table->info[i].ratecode; + sband->n_bitrates++; + DPRINTF(sc, ATH_DBG_CONFIG, "Rate: %2dMbps, ratecode: %2d\n", + rate[i].bitrate / 10, rate[i].hw_value); } - -#undef IEEE80211_HT_CAP_40MHZ_INTOLERANT } -static void ath9k_bss_assoc_info(struct ath_softc *sc, - struct ieee80211_bss_conf *bss_conf) +static int ath_setup_channels(struct ath_softc *sc) { - struct ieee80211_hw *hw = sc->hw; - struct ieee80211_channel *curchan = hw->conf.channel; - struct ath_vap *avp; - int pos; - DECLARE_MAC_BUF(mac); + struct ath_hal *ah = sc->sc_ah; + int nchan, i, a = 0, b = 0; + u8 regclassids[ATH_REGCLASSIDS_MAX]; + u32 nregclass = 0; + struct ieee80211_supported_band *band_2ghz; + struct ieee80211_supported_band *band_5ghz; + struct ieee80211_channel *chan_2ghz; + struct ieee80211_channel *chan_5ghz; + struct ath9k_channel *c; + + /* Fill in ah->ah_channels */ + if (!ath9k_regd_init_channels(ah, ATH_CHAN_MAX, (u32 *)&nchan, + regclassids, ATH_REGCLASSIDS_MAX, + &nregclass, CTRY_DEFAULT, false, 1)) { + u32 rd = ah->ah_currentRD; + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to collect channel list; " + "regdomain likely %u country code %u\n", + rd, CTRY_DEFAULT); + return -EINVAL; + } - if (bss_conf->assoc) { - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Bss Info ASSOC %d\n", - __func__, - bss_conf->aid); - - avp = sc->sc_vaps[0]; - if (avp == NULL) { - DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n", - __func__); - return; + band_2ghz = &sc->sbands[IEEE80211_BAND_2GHZ]; + band_5ghz = &sc->sbands[IEEE80211_BAND_5GHZ]; + chan_2ghz = sc->channels[IEEE80211_BAND_2GHZ]; + chan_5ghz = sc->channels[IEEE80211_BAND_5GHZ]; + + for (i = 0; i < nchan; i++) { + c = &ah->ah_channels[i]; + if (IS_CHAN_2GHZ(c)) { + chan_2ghz[a].band = IEEE80211_BAND_2GHZ; + chan_2ghz[a].center_freq = c->channel; + chan_2ghz[a].max_power = c->maxTxPower; + + if (c->privFlags & CHANNEL_DISALLOW_ADHOC) + chan_2ghz[a].flags |= IEEE80211_CHAN_NO_IBSS; + if (c->channelFlags & CHANNEL_PASSIVE) + chan_2ghz[a].flags |= IEEE80211_CHAN_PASSIVE_SCAN; + + band_2ghz->n_channels = ++a; + + DPRINTF(sc, ATH_DBG_CONFIG, "2MHz channel: %d, " + "channelFlags: 0x%x\n", + c->channel, c->channelFlags); + } else if (IS_CHAN_5GHZ(c)) { + chan_5ghz[b].band = IEEE80211_BAND_5GHZ; + chan_5ghz[b].center_freq = c->channel; + chan_5ghz[b].max_power = c->maxTxPower; + + if (c->privFlags & CHANNEL_DISALLOW_ADHOC) + chan_5ghz[b].flags |= IEEE80211_CHAN_NO_IBSS; + if (c->channelFlags & CHANNEL_PASSIVE) + chan_5ghz[b].flags |= IEEE80211_CHAN_PASSIVE_SCAN; + + band_5ghz->n_channels = ++b; + + DPRINTF(sc, ATH_DBG_CONFIG, "5MHz channel: %d, " + "channelFlags: 0x%x\n", + c->channel, c->channelFlags); } + } - /* New association, store aid */ - if (avp->av_opmode == ATH9K_M_STA) { - sc->sc_curaid = bss_conf->aid; - ath9k_hw_write_associd(sc->sc_ah, sc->sc_curbssid, - sc->sc_curaid); - } + return 0; +} - /* Configure the beacon */ - ath_beacon_config(sc, 0); - sc->sc_flags |= SC_OP_BEACONS; +/* + * Set/change channels. If the channel is really being changed, it's done + * by reseting the chip. To accomplish this we must first cleanup any pending + * DMA, then restart stuff. +*/ +static int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) +{ + struct ath_hal *ah = sc->sc_ah; + bool fastcc = true, stopped; - /* Reset rssi stats */ - sc->sc_halstats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER; - sc->sc_halstats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER; - sc->sc_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER; - sc->sc_halstats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER; + if (sc->sc_flags & SC_OP_INVALID) + return -EIO; + + if (hchan->channel != sc->sc_ah->ah_curchan->channel || + hchan->channelFlags != sc->sc_ah->ah_curchan->channelFlags || + (sc->sc_flags & SC_OP_CHAINMASK_UPDATE) || + (sc->sc_flags & SC_OP_FULL_RESET)) { + int status; + /* + * This is only performed if the channel settings have + * actually changed. + * + * To switch channels clear any pending DMA operations; + * wait long enough for the RX fifo to drain, reset the + * hardware at the new frequency, and then re-enable + * the relevant bits of the h/w. + */ + ath9k_hw_set_interrupts(ah, 0); + ath_draintxq(sc, false); + stopped = ath_stoprecv(sc); - /* Update chainmask */ - ath_update_chainmask(sc, bss_conf->assoc_ht); + /* XXX: do not flush receive queue here. We don't want + * to flush data frames already in queue because of + * changing channel. */ + + if (!stopped || (sc->sc_flags & SC_OP_FULL_RESET)) + fastcc = false; DPRINTF(sc, ATH_DBG_CONFIG, - "%s: bssid %s aid 0x%x\n", - __func__, - print_mac(mac, sc->sc_curbssid), sc->sc_curaid); + "(%u MHz) -> (%u MHz), cflags:%x, chanwidth: %d\n", + sc->sc_ah->ah_curchan->channel, + hchan->channel, hchan->channelFlags, sc->tx_chan_width); + + spin_lock_bh(&sc->sc_resetlock); + if (!ath9k_hw_reset(ah, hchan, sc->tx_chan_width, + sc->sc_tx_chainmask, sc->sc_rx_chainmask, + sc->sc_ht_extprotspacing, fastcc, &status)) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to reset channel %u (%uMhz) " + "flags 0x%x hal status %u\n", + ath9k_hw_mhz2ieee(ah, hchan->channel, + hchan->channelFlags), + hchan->channel, hchan->channelFlags, status); + spin_unlock_bh(&sc->sc_resetlock); + return -EIO; + } + spin_unlock_bh(&sc->sc_resetlock); - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n", - __func__, - curchan->center_freq); + sc->sc_flags &= ~SC_OP_CHAINMASK_UPDATE; + sc->sc_flags &= ~SC_OP_FULL_RESET; - pos = ath_get_channel(sc, curchan); - if (pos == -1) { + if (ath_startrecv(sc) != 0) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: Invalid channel\n", __func__); - return; + "Unable to restart recv logic\n"); + return -EIO; } - if (hw->conf.ht_conf.ht_supported) - sc->sc_ah->ah_channels[pos].chanmode = - ath_get_extchanmode(sc, curchan); - else - sc->sc_ah->ah_channels[pos].chanmode = - (curchan->band == IEEE80211_BAND_2GHZ) ? - CHANNEL_G : CHANNEL_A; + ath_setcurmode(sc, ath_chan2mode(hchan)); + ath_update_txpow(sc); + ath9k_hw_set_interrupts(ah, sc->sc_imask); + } + return 0; +} - /* set h/w channel */ - if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to set channel\n", - __func__); +/* + * This routine performs the periodic noise floor calibration function + * that is used to adjust and optimize the chip performance. This + * takes environmental changes (location, temperature) into account. + * When the task is complete, it reschedules itself depending on the + * appropriate interval that was calculated. + */ +static void ath_ani_calibrate(unsigned long data) +{ + struct ath_softc *sc; + struct ath_hal *ah; + bool longcal = false; + bool shortcal = false; + bool aniflag = false; + unsigned int timestamp = jiffies_to_msecs(jiffies); + u32 cal_interval; - ath_rate_newstate(sc, avp); - /* Update ratectrl about the new state */ - ath_rc_node_update(hw, avp->rc_node); + sc = (struct ath_softc *)data; + ah = sc->sc_ah; - /* Start ANI */ - mod_timer(&sc->sc_ani.timer, - jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); + /* + * don't calibrate when we're scanning. + * we are most likely not on our home channel. + */ + if (sc->rx.rxfilter & FIF_BCN_PRBRESP_PROMISC) + return; + + /* Long calibration runs independently of short calibration. */ + if ((timestamp - sc->sc_ani.sc_longcal_timer) >= ATH_LONG_CALINTERVAL) { + longcal = true; + DPRINTF(sc, ATH_DBG_ANI, "longcal @%lu\n", jiffies); + sc->sc_ani.sc_longcal_timer = timestamp; + } + /* Short calibration applies only while sc_caldone is false */ + if (!sc->sc_ani.sc_caldone) { + if ((timestamp - sc->sc_ani.sc_shortcal_timer) >= + ATH_SHORT_CALINTERVAL) { + shortcal = true; + DPRINTF(sc, ATH_DBG_ANI, "shortcal @%lu\n", jiffies); + sc->sc_ani.sc_shortcal_timer = timestamp; + sc->sc_ani.sc_resetcal_timer = timestamp; + } } else { - DPRINTF(sc, ATH_DBG_CONFIG, - "%s: Bss Info DISSOC\n", __func__); - sc->sc_curaid = 0; + if ((timestamp - sc->sc_ani.sc_resetcal_timer) >= + ATH_RESTART_CALINTERVAL) { + ath9k_hw_reset_calvalid(ah, ah->ah_curchan, + &sc->sc_ani.sc_caldone); + if (sc->sc_ani.sc_caldone) + sc->sc_ani.sc_resetcal_timer = timestamp; + } + } + + /* Verify whether we must check ANI */ + if ((timestamp - sc->sc_ani.sc_checkani_timer) >= + ATH_ANI_POLLINTERVAL) { + aniflag = true; + sc->sc_ani.sc_checkani_timer = timestamp; + } + + /* Skip all processing if there's nothing to do. */ + if (longcal || shortcal || aniflag) { + /* Call ANI routine if necessary */ + if (aniflag) + ath9k_hw_ani_monitor(ah, &sc->sc_halstats, + ah->ah_curchan); + + /* Perform calibration if necessary */ + if (longcal || shortcal) { + bool iscaldone = false; + + if (ath9k_hw_calibrate(ah, ah->ah_curchan, + sc->sc_rx_chainmask, longcal, + &iscaldone)) { + if (longcal) + sc->sc_ani.sc_noise_floor = + ath9k_hw_getchan_noise(ah, + ah->ah_curchan); + + DPRINTF(sc, ATH_DBG_ANI, + "calibrate chan %u/%x nf: %d\n", + ah->ah_curchan->channel, + ah->ah_curchan->channelFlags, + sc->sc_ani.sc_noise_floor); + } else { + DPRINTF(sc, ATH_DBG_ANY, + "calibrate chan %u/%x failed\n", + ah->ah_curchan->channel, + ah->ah_curchan->channelFlags); + } + sc->sc_ani.sc_caldone = iscaldone; + } } + + /* + * Set timer interval based on previous results. + * The interval must be the shortest necessary to satisfy ANI, + * short calibration and long calibration. + */ + cal_interval = ATH_LONG_CALINTERVAL; + if (sc->sc_ah->ah_config.enable_ani) + cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL); + if (!sc->sc_ani.sc_caldone) + cal_interval = min(cal_interval, (u32)ATH_SHORT_CALINTERVAL); + + mod_timer(&sc->sc_ani.timer, jiffies + msecs_to_jiffies(cal_interval)); } -void ath_get_beaconconfig(struct ath_softc *sc, - int if_id, - struct ath_beacon_config *conf) +/* + * Update tx/rx chainmask. For legacy association, + * hard code chainmask to 1x1, for 11n association, use + * the chainmask configuration. + */ +static void ath_update_chainmask(struct ath_softc *sc, int is_ht) { - struct ieee80211_hw *hw = sc->hw; + sc->sc_flags |= SC_OP_CHAINMASK_UPDATE; + if (is_ht) { + sc->sc_tx_chainmask = sc->sc_ah->ah_caps.tx_chainmask; + sc->sc_rx_chainmask = sc->sc_ah->ah_caps.rx_chainmask; + } else { + sc->sc_tx_chainmask = 1; + sc->sc_rx_chainmask = 1; + } + + DPRINTF(sc, ATH_DBG_CONFIG, "tx chmask: %d, rx chmask: %d\n", + sc->sc_tx_chainmask, sc->sc_rx_chainmask); +} + +static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta) +{ + struct ath_node *an; + + an = (struct ath_node *)sta->drv_priv; - /* fill in beacon config data */ + if (sc->sc_flags & SC_OP_TXAGGR) + ath_tx_node_init(sc, an); - conf->beacon_interval = hw->conf.beacon_int; - conf->listen_interval = 100; - conf->dtim_count = 1; - conf->bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf->listen_interval; + an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + + sta->ht_cap.ampdu_factor); + an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density); } -void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, - struct ath_xmit_status *tx_status, struct ath_node *an) +static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) { - struct ieee80211_hw *hw = sc->hw; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ath_node *an = (struct ath_node *)sta->drv_priv; + + if (sc->sc_flags & SC_OP_TXAGGR) + ath_tx_node_cleanup(sc, an); +} - DPRINTF(sc, ATH_DBG_XMIT, - "%s: TX complete: skb: %p\n", __func__, skb); +static void ath9k_tasklet(unsigned long data) +{ + struct ath_softc *sc = (struct ath_softc *)data; + u32 status = sc->sc_intrstatus; + + if (status & ATH9K_INT_FATAL) { + /* need a chip reset */ + ath_reset(sc, false); + return; + } else { - if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK || - tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) { - /* free driver's private data area of tx_info */ - if (tx_info->driver_data[0] != NULL) - kfree(tx_info->driver_data[0]); - tx_info->driver_data[0] = NULL; + if (status & + (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN)) { + spin_lock_bh(&sc->rx.rxflushlock); + ath_rx_tasklet(sc, 0); + spin_unlock_bh(&sc->rx.rxflushlock); + } + /* XXX: optimize this */ + if (status & ATH9K_INT_TX) + ath_tx_tasklet(sc); } - if (tx_status->flags & ATH_TX_BAR) { - tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; - tx_status->flags &= ~ATH_TX_BAR; + /* re-enable hardware interrupt */ + ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask); +} + +static irqreturn_t ath_isr(int irq, void *dev) +{ + struct ath_softc *sc = dev; + struct ath_hal *ah = sc->sc_ah; + enum ath9k_int status; + bool sched = false; + + do { + if (sc->sc_flags & SC_OP_INVALID) { + /* + * The hardware is not ready/present, don't + * touch anything. Note this can happen early + * on if the IRQ is shared. + */ + return IRQ_NONE; + } + if (!ath9k_hw_intrpend(ah)) { /* shared irq, not for us */ + return IRQ_NONE; + } + + /* + * Figure out the reason(s) for the interrupt. Note + * that the hal returns a pseudo-ISR that may include + * bits we haven't explicitly enabled so we mask the + * value to insure we only process bits we requested. + */ + ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */ + + status &= sc->sc_imask; /* discard unasked-for bits */ + + /* + * If there are no status bits set, then this interrupt was not + * for me (should have been caught above). + */ + if (!status) + return IRQ_NONE; + + sc->sc_intrstatus = status; + + if (status & ATH9K_INT_FATAL) { + /* need a chip reset */ + sched = true; + } else if (status & ATH9K_INT_RXORN) { + /* need a chip reset */ + sched = true; + } else { + if (status & ATH9K_INT_SWBA) { + /* schedule a tasklet for beacon handling */ + tasklet_schedule(&sc->bcon_tasklet); + } + if (status & ATH9K_INT_RXEOL) { + /* + * NB: the hardware should re-read the link when + * RXE bit is written, but it doesn't work + * at least on older hardware revs. + */ + sched = true; + } + + if (status & ATH9K_INT_TXURN) + /* bump tx trigger level */ + ath9k_hw_updatetxtriglevel(ah, true); + /* XXX: optimize this */ + if (status & ATH9K_INT_RX) + sched = true; + if (status & ATH9K_INT_TX) + sched = true; + if (status & ATH9K_INT_BMISS) + sched = true; + /* carrier sense timeout */ + if (status & ATH9K_INT_CST) + sched = true; + if (status & ATH9K_INT_MIB) { + /* + * Disable interrupts until we service the MIB + * interrupt; otherwise it will continue to + * fire. + */ + ath9k_hw_set_interrupts(ah, 0); + /* + * Let the hal handle the event. We assume + * it will clear whatever condition caused + * the interrupt. + */ + ath9k_hw_procmibevent(ah, &sc->sc_halstats); + ath9k_hw_set_interrupts(ah, sc->sc_imask); + } + if (status & ATH9K_INT_TIM_TIMER) { + if (!(ah->ah_caps.hw_caps & + ATH9K_HW_CAP_AUTOSLEEP)) { + /* Clear RxAbort bit so that we can + * receive frames */ + ath9k_hw_setrxabort(ah, 0); + sched = true; + } + } + } + } while (0); + + ath_debug_stat_interrupt(sc, status); + + if (sched) { + /* turn off every interrupt except SWBA */ + ath9k_hw_set_interrupts(ah, (sc->sc_imask & ATH9K_INT_SWBA)); + tasklet_schedule(&sc->intr_tq); } - if (tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY)) { - if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) { - /* Frame was not ACKed, but an ACK was expected */ - tx_info->status.excessive_retries = 1; + return IRQ_HANDLED; +} + +static int ath_get_channel(struct ath_softc *sc, + struct ieee80211_channel *chan) +{ + int i; + + for (i = 0; i < sc->sc_ah->ah_nchan; i++) { + if (sc->sc_ah->ah_channels[i].channel == chan->center_freq) + return i; + } + + return -1; +} + +static u32 ath_get_extchanmode(struct ath_softc *sc, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type) +{ + u32 chanmode = 0; + + switch (chan->band) { + case IEEE80211_BAND_2GHZ: + switch(channel_type) { + case NL80211_CHAN_NO_HT: + case NL80211_CHAN_HT20: + chanmode = CHANNEL_G_HT20; + break; + case NL80211_CHAN_HT40PLUS: + chanmode = CHANNEL_G_HT40PLUS; + break; + case NL80211_CHAN_HT40MINUS: + chanmode = CHANNEL_G_HT40MINUS; + break; + } + break; + case IEEE80211_BAND_5GHZ: + switch(channel_type) { + case NL80211_CHAN_NO_HT: + case NL80211_CHAN_HT20: + chanmode = CHANNEL_A_HT20; + break; + case NL80211_CHAN_HT40PLUS: + chanmode = CHANNEL_A_HT40PLUS; + break; + case NL80211_CHAN_HT40MINUS: + chanmode = CHANNEL_A_HT40MINUS; + break; + } + break; + default: + break; + } + + return chanmode; +} + +static int ath_keyset(struct ath_softc *sc, u16 keyix, + struct ath9k_keyval *hk, const u8 mac[ETH_ALEN]) +{ + bool status; + + status = ath9k_hw_set_keycache_entry(sc->sc_ah, + keyix, hk, mac, false); + + return status != false; +} + +static int ath_setkey_tkip(struct ath_softc *sc, u16 keyix, const u8 *key, + struct ath9k_keyval *hk, + const u8 *addr) +{ + const u8 *key_rxmic; + const u8 *key_txmic; + + key_txmic = key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY; + key_rxmic = key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY; + + if (addr == NULL) { + /* Group key installation */ + memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); + return ath_keyset(sc, keyix, hk, addr); + } + if (!sc->sc_splitmic) { + /* + * data key goes at first index, + * the hal handles the MIC keys at index+64. + */ + memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); + memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic)); + return ath_keyset(sc, keyix, hk, addr); + } + /* + * TX key goes at first index, RX key at +32. + * The hal handles the MIC keys at index+64. + */ + memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); + if (!ath_keyset(sc, keyix, hk, NULL)) { + /* Txmic entry failed. No need to proceed further */ + DPRINTF(sc, ATH_DBG_KEYCACHE, + "Setting TX MIC Key Failed\n"); + return 0; + } + + memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); + /* XXX delete tx key on failure? */ + return ath_keyset(sc, keyix + 32, hk, addr); +} + +static int ath_reserve_key_cache_slot_tkip(struct ath_softc *sc) +{ + int i; + + for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax / 2; i++) { + if (test_bit(i, sc->sc_keymap) || + test_bit(i + 64, sc->sc_keymap)) + continue; /* At least one part of TKIP key allocated */ + if (sc->sc_splitmic && + (test_bit(i + 32, sc->sc_keymap) || + test_bit(i + 64 + 32, sc->sc_keymap))) + continue; /* At least one part of TKIP key allocated */ + + /* Found a free slot for a TKIP key */ + return i; + } + return -1; +} + +static int ath_reserve_key_cache_slot(struct ath_softc *sc) +{ + int i; + + /* First, try to find slots that would not be available for TKIP. */ + if (sc->sc_splitmic) { + for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax / 4; i++) { + if (!test_bit(i, sc->sc_keymap) && + (test_bit(i + 32, sc->sc_keymap) || + test_bit(i + 64, sc->sc_keymap) || + test_bit(i + 64 + 32, sc->sc_keymap))) + return i; + if (!test_bit(i + 32, sc->sc_keymap) && + (test_bit(i, sc->sc_keymap) || + test_bit(i + 64, sc->sc_keymap) || + test_bit(i + 64 + 32, sc->sc_keymap))) + return i + 32; + if (!test_bit(i + 64, sc->sc_keymap) && + (test_bit(i , sc->sc_keymap) || + test_bit(i + 32, sc->sc_keymap) || + test_bit(i + 64 + 32, sc->sc_keymap))) + return i + 64; + if (!test_bit(i + 64 + 32, sc->sc_keymap) && + (test_bit(i, sc->sc_keymap) || + test_bit(i + 32, sc->sc_keymap) || + test_bit(i + 64, sc->sc_keymap))) + return i + 64 + 32; } } else { - /* Frame was ACKed */ - tx_info->flags |= IEEE80211_TX_STAT_ACK; + for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax / 2; i++) { + if (!test_bit(i, sc->sc_keymap) && + test_bit(i + 64, sc->sc_keymap)) + return i; + if (test_bit(i, sc->sc_keymap) && + !test_bit(i + 64, sc->sc_keymap)) + return i + 64; + } } - tx_info->status.retry_count = tx_status->retries; + /* No partially used TKIP slots, pick any available slot */ + for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax; i++) { + /* Do not allow slots that could be needed for TKIP group keys + * to be used. This limitation could be removed if we know that + * TKIP will not be used. */ + if (i >= 64 && i < 64 + IEEE80211_WEP_NKID) + continue; + if (sc->sc_splitmic) { + if (i >= 32 && i < 32 + IEEE80211_WEP_NKID) + continue; + if (i >= 64 + 32 && i < 64 + 32 + IEEE80211_WEP_NKID) + continue; + } - ieee80211_tx_status(hw, skb); - if (an) - ath_node_put(sc, an, ATH9K_BH_STATUS_CHANGE); + if (!test_bit(i, sc->sc_keymap)) + return i; /* Found a free slot for a key */ + } + + /* No free slot found */ + return -1; } -int _ath_rx_indicate(struct ath_softc *sc, - struct sk_buff *skb, - struct ath_recv_status *status, - u16 keyix) +static int ath_key_config(struct ath_softc *sc, + const u8 *addr, + struct ieee80211_key_conf *key) { - struct ieee80211_hw *hw = sc->hw; - struct ath_node *an = NULL; - struct ieee80211_rx_status rx_status; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - int hdrlen = ieee80211_get_hdrlen_from_skb(skb); - int padsize; - enum ATH_RX_TYPE st; - - /* see if any padding is done by the hw and remove it */ - if (hdrlen & 3) { - padsize = hdrlen % 4; - memmove(skb->data + padsize, skb->data, hdrlen); - skb_pull(skb, padsize); + struct ath9k_keyval hk; + const u8 *mac = NULL; + int ret = 0; + int idx; + + memset(&hk, 0, sizeof(hk)); + + switch (key->alg) { + case ALG_WEP: + hk.kv_type = ATH9K_CIPHER_WEP; + break; + case ALG_TKIP: + hk.kv_type = ATH9K_CIPHER_TKIP; + break; + case ALG_CCMP: + hk.kv_type = ATH9K_CIPHER_AES_CCM; + break; + default: + return -EINVAL; + } + + hk.kv_len = key->keylen; + memcpy(hk.kv_val, key->key, key->keylen); + + if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { + /* For now, use the default keys for broadcast keys. This may + * need to change with virtual interfaces. */ + idx = key->keyidx; + } else if (key->keyidx) { + struct ieee80211_vif *vif; + + mac = addr; + vif = sc->sc_vaps[0]; + if (vif->type != NL80211_IFTYPE_AP) { + /* Only keyidx 0 should be used with unicast key, but + * allow this for client mode for now. */ + idx = key->keyidx; + } else + return -EIO; + } else { + mac = addr; + if (key->alg == ALG_TKIP) + idx = ath_reserve_key_cache_slot_tkip(sc); + else + idx = ath_reserve_key_cache_slot(sc); + if (idx < 0) + return -EIO; /* no free key cache entries */ + } + + if (key->alg == ALG_TKIP) + ret = ath_setkey_tkip(sc, idx, key->key, &hk, mac); + else + ret = ath_keyset(sc, idx, &hk, mac); + + if (!ret) + return -EIO; + + set_bit(idx, sc->sc_keymap); + if (key->alg == ALG_TKIP) { + set_bit(idx + 64, sc->sc_keymap); + if (sc->sc_splitmic) { + set_bit(idx + 32, sc->sc_keymap); + set_bit(idx + 64 + 32, sc->sc_keymap); + } } - /* Prepare rx status */ - ath9k_rx_prepare(sc, skb, status, &rx_status); + return idx; +} + +static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key) +{ + ath9k_hw_keyreset(sc->sc_ah, key->hw_key_idx); + if (key->hw_key_idx < IEEE80211_WEP_NKID) + return; - if (!(keyix == ATH9K_RXKEYIX_INVALID) && - !(status->flags & ATH_RX_DECRYPT_ERROR)) { - rx_status.flag |= RX_FLAG_DECRYPTED; - } else if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED) - && !(status->flags & ATH_RX_DECRYPT_ERROR) - && skb->len >= hdrlen + 4) { - keyix = skb->data[hdrlen + 3] >> 6; + clear_bit(key->hw_key_idx, sc->sc_keymap); + if (key->alg != ALG_TKIP) + return; - if (test_bit(keyix, sc->sc_keymap)) - rx_status.flag |= RX_FLAG_DECRYPTED; + clear_bit(key->hw_key_idx + 64, sc->sc_keymap); + if (sc->sc_splitmic) { + clear_bit(key->hw_key_idx + 32, sc->sc_keymap); + clear_bit(key->hw_key_idx + 64 + 32, sc->sc_keymap); } +} - spin_lock_bh(&sc->node_lock); - an = ath_node_find(sc, hdr->addr2); - spin_unlock_bh(&sc->node_lock); +static void setup_ht_cap(struct ieee80211_sta_ht_cap *ht_info) +{ +#define ATH9K_HT_CAP_MAXRXAMPDU_65536 0x3 /* 2 ^ 16 */ +#define ATH9K_HT_CAP_MPDUDENSITY_8 0x6 /* 8 usec */ - if (an) { - ath_rx_input(sc, an, - hw->conf.ht_conf.ht_supported, - skb, status, &st); - } - if (!an || (st != ATH_RX_CONSUMED)) - __ieee80211_rx(hw, skb, &rx_status); + ht_info->ht_supported = true; + ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | + IEEE80211_HT_CAP_SM_PS | + IEEE80211_HT_CAP_SGI_40 | + IEEE80211_HT_CAP_DSSSCCK40; - return 0; + ht_info->ampdu_factor = ATH9K_HT_CAP_MAXRXAMPDU_65536; + ht_info->ampdu_density = ATH9K_HT_CAP_MPDUDENSITY_8; + /* set up supported mcs set */ + memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); + ht_info->mcs.rx_mask[0] = 0xff; + ht_info->mcs.rx_mask[1] = 0xff; + ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; } -int ath_rx_subframe(struct ath_node *an, - struct sk_buff *skb, - struct ath_recv_status *status) +static void ath9k_bss_assoc_info(struct ath_softc *sc, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf) { - struct ath_softc *sc = an->an_sc; - struct ieee80211_hw *hw = sc->hw; - struct ieee80211_rx_status rx_status; + struct ath_vap *avp = (void *)vif->drv_priv; - /* Prepare rx status */ - ath9k_rx_prepare(sc, skb, status, &rx_status); - if (!(status->flags & ATH_RX_DECRYPT_ERROR)) - rx_status.flag |= RX_FLAG_DECRYPTED; + if (bss_conf->assoc) { + DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info ASSOC %d, bssid: %pM\n", + bss_conf->aid, sc->sc_curbssid); - __ieee80211_rx(hw, skb, &rx_status); + /* New association, store aid */ + if (avp->av_opmode == NL80211_IFTYPE_STATION) { + sc->sc_curaid = bss_conf->aid; + ath9k_hw_write_associd(sc->sc_ah, sc->sc_curbssid, + sc->sc_curaid); + } - return 0; + /* Configure the beacon */ + ath_beacon_config(sc, 0); + sc->sc_flags |= SC_OP_BEACONS; + + /* Reset rssi stats */ + sc->sc_halstats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER; + sc->sc_halstats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER; + sc->sc_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER; + sc->sc_halstats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER; + + /* Start ANI */ + mod_timer(&sc->sc_ani.timer, + jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); + + } else { + DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info DISSOC\n"); + sc->sc_curaid = 0; + } } /********************************/ @@ -677,7 +1058,8 @@ static void ath_init_leds(struct ath_softc *sc) ath_deinit_leds(sc); } -#ifdef CONFIG_RFKILL +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) + /*******************/ /* Rfkill */ /*******************/ @@ -689,14 +1071,14 @@ static void ath_radio_enable(struct ath_softc *sc) spin_lock_bh(&sc->sc_resetlock); if (!ath9k_hw_reset(ah, ah->ah_curchan, - sc->sc_ht_info.tx_chan_width, + sc->tx_chan_width, sc->sc_tx_chainmask, sc->sc_rx_chainmask, sc->sc_ht_extprotspacing, false, &status)) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to reset channel %u (%uMhz) " - "flags 0x%x hal status %u\n", __func__, + "Unable to reset channel %u (%uMhz) " + "flags 0x%x hal status %u\n", ath9k_hw_mhz2ieee(ah, ah->ah_curchan->channel, ah->ah_curchan->channelFlags), @@ -708,7 +1090,7 @@ static void ath_radio_enable(struct ath_softc *sc) ath_update_txpow(sc); if (ath_startrecv(sc) != 0) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to restart recv logic\n", __func__); + "Unable to restart recv logic\n"); return; } @@ -747,14 +1129,14 @@ static void ath_radio_disable(struct ath_softc *sc) spin_lock_bh(&sc->sc_resetlock); if (!ath9k_hw_reset(ah, ah->ah_curchan, - sc->sc_ht_info.tx_chan_width, + sc->tx_chan_width, sc->sc_tx_chainmask, sc->sc_rx_chainmask, sc->sc_ht_extprotspacing, false, &status)) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to reset channel %u (%uMhz) " - "flags 0x%x hal status %u\n", __func__, + "Unable to reset channel %u (%uMhz) " + "flags 0x%x hal status %u\n", ath9k_hw_mhz2ieee(ah, ah->ah_curchan->channel, ah->ah_curchan->channelFlags), @@ -834,7 +1216,7 @@ static int ath_sw_toggle_radio(void *data, enum rfkill_state state) sc->sc_flags &= ~SC_OP_RFKILL_SW_BLOCKED; if (sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED) { DPRINTF(sc, ATH_DBG_FATAL, "Can't turn on the" - "radio as it is disabled by h/w \n"); + "radio as it is disabled by h/w\n"); return -EPERM; } ath_radio_enable(sc); @@ -878,61 +1260,258 @@ static void ath_deinit_rfkill(struct ath_softc *sc) sc->rf_kill.rfkill = NULL; } } + +static int ath_start_rfkill_poll(struct ath_softc *sc) +{ + if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + queue_delayed_work(sc->hw->workqueue, + &sc->rf_kill.rfkill_poll, 0); + + if (!(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) { + if (rfkill_register(sc->rf_kill.rfkill)) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to register rfkill\n"); + rfkill_free(sc->rf_kill.rfkill); + + /* Deinitialize the device */ + ath_detach(sc); + if (sc->pdev->irq) + free_irq(sc->pdev->irq, sc); + pci_iounmap(sc->pdev, sc->mem); + pci_release_region(sc->pdev, 0); + pci_disable_device(sc->pdev); + ieee80211_free_hw(sc->hw); + return -EIO; + } else { + sc->sc_flags |= SC_OP_RFKILL_REGISTERED; + } + } + + return 0; +} #endif /* CONFIG_RFKILL */ -static int ath_detach(struct ath_softc *sc) +static void ath_detach(struct ath_softc *sc) { struct ieee80211_hw *hw = sc->hw; + int i = 0; - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach ATH hw\n", __func__); + DPRINTF(sc, ATH_DBG_CONFIG, "Detach ATH hw\n"); - /* Deinit LED control */ - ath_deinit_leds(sc); - -#ifdef CONFIG_RFKILL - /* deinit rfkill */ +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) ath_deinit_rfkill(sc); #endif - - /* Unregister hw */ + ath_deinit_leds(sc); ieee80211_unregister_hw(hw); - - /* unregister Rate control */ - ath_rate_control_unregister(); - - /* tx/rx cleanup */ - ath_rx_cleanup(sc); ath_tx_cleanup(sc); - /* Deinit */ + tasklet_kill(&sc->intr_tq); + tasklet_kill(&sc->bcon_tasklet); - ath_deinit(sc); + if (!(sc->sc_flags & SC_OP_INVALID)) + ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); - return 0; + /* cleanup tx queues */ + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) + if (ATH_TXQ_SETUP(sc, i)) + ath_tx_cleanupq(sc, &sc->tx.txq[i]); + + ath9k_hw_detach(sc->sc_ah); + ath9k_exit_debug(sc); } -static int ath_attach(u16 devid, - struct ath_softc *sc) +static int ath_init(u16 devid, struct ath_softc *sc) { - struct ieee80211_hw *hw = sc->hw; - int error = 0; + struct ath_hal *ah = NULL; + int status; + int error = 0, i; + int csz = 0; - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach ATH hw\n", __func__); + /* XXX: hardware will not be ready until ath_open() being called */ + sc->sc_flags |= SC_OP_INVALID; - error = ath_init(devid, sc); - if (error != 0) - return error; + if (ath9k_init_debug(sc) < 0) + printk(KERN_ERR "Unable to create debugfs files\n"); - /* Init nodes */ + spin_lock_init(&sc->sc_resetlock); + mutex_init(&sc->mutex); + tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); + tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet, + (unsigned long)sc); + + /* + * Cache line size is used to size and align various + * structures used to communicate with the hardware. + */ + bus_read_cachesize(sc, &csz); + /* XXX assert csz is non-zero */ + sc->sc_cachelsz = csz << 2; /* convert to bytes */ - INIT_LIST_HEAD(&sc->node_list); - spin_lock_init(&sc->node_lock); + ah = ath9k_hw_attach(devid, sc, sc->mem, &status); + if (ah == NULL) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to attach hardware; HAL status %u\n", status); + error = -ENXIO; + goto bad; + } + sc->sc_ah = ah; - /* get mac address from hardware and set in mac80211 */ + /* Get the hardware key cache size. */ + sc->sc_keymax = ah->ah_caps.keycache_size; + if (sc->sc_keymax > ATH_KEYMAX) { + DPRINTF(sc, ATH_DBG_KEYCACHE, + "Warning, using only %u entries in %u key cache\n", + ATH_KEYMAX, sc->sc_keymax); + sc->sc_keymax = ATH_KEYMAX; + } - SET_IEEE80211_PERM_ADDR(hw, sc->sc_myaddr); + /* + * Reset the key cache since some parts do not + * reset the contents on initial power up. + */ + for (i = 0; i < sc->sc_keymax; i++) + ath9k_hw_keyreset(ah, (u16) i); + + /* Collect the channel list using the default country code */ + + error = ath_setup_channels(sc); + if (error) + goto bad; + + /* default to MONITOR mode */ + sc->sc_ah->ah_opmode = NL80211_IFTYPE_MONITOR; + + + /* Setup rate tables */ + + ath_rate_attach(sc); + ath_setup_rates(sc, IEEE80211_BAND_2GHZ); + ath_setup_rates(sc, IEEE80211_BAND_5GHZ); + + /* + * Allocate hardware transmit queues: one queue for + * beacon frames and one data queue for each QoS + * priority. Note that the hal handles reseting + * these queues at the needed time. + */ + sc->beacon.beaconq = ath_beaconq_setup(ah); + if (sc->beacon.beaconq == -1) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to setup a beacon xmit queue\n"); + error = -EIO; + goto bad2; + } + sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0); + if (sc->beacon.cabq == NULL) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to setup CAB xmit queue\n"); + error = -EIO; + goto bad2; + } + + sc->sc_config.cabqReadytime = ATH_CABQ_READY_TIME; + ath_cabq_update(sc); + + for (i = 0; i < ARRAY_SIZE(sc->tx.hwq_map); i++) + sc->tx.hwq_map[i] = -1; + + /* Setup data queues */ + /* NB: ensure BK queue is the lowest priority h/w queue */ + if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to setup xmit queue for BK traffic\n"); + error = -EIO; + goto bad2; + } + + if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to setup xmit queue for BE traffic\n"); + error = -EIO; + goto bad2; + } + if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to setup xmit queue for VI traffic\n"); + error = -EIO; + goto bad2; + } + if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to setup xmit queue for VO traffic\n"); + error = -EIO; + goto bad2; + } + + /* Initializes the noise floor to a reasonable default value. + * Later on this will be updated during ANI processing. */ + + sc->sc_ani.sc_noise_floor = ATH_DEFAULT_NOISE_FLOOR; + setup_timer(&sc->sc_ani.timer, ath_ani_calibrate, (unsigned long)sc); + + if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, + ATH9K_CIPHER_TKIP, NULL)) { + /* + * Whether we should enable h/w TKIP MIC. + * XXX: if we don't support WME TKIP MIC, then we wouldn't + * report WMM capable, so it's always safe to turn on + * TKIP MIC in this case. + */ + ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_TKIP_MIC, + 0, 1, NULL); + } + + /* + * Check whether the separate key cache entries + * are required to handle both tx+rx MIC keys. + * With split mic keys the number of stations is limited + * to 27 otherwise 59. + */ + if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, + ATH9K_CIPHER_TKIP, NULL) + && ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, + ATH9K_CIPHER_MIC, NULL) + && ath9k_hw_getcapability(ah, ATH9K_CAP_TKIP_SPLIT, + 0, NULL)) + sc->sc_splitmic = 1; + + /* turn on mcast key search if possible */ + if (!ath9k_hw_getcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL)) + (void)ath9k_hw_setcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 1, + 1, NULL); + + sc->sc_config.txpowlimit = ATH_TXPOWER_MAX; + sc->sc_config.txpowlimit_override = 0; + + /* 11n Capabilities */ + if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) { + sc->sc_flags |= SC_OP_TXAGGR; + sc->sc_flags |= SC_OP_RXAGGR; + } + + sc->sc_tx_chainmask = ah->ah_caps.tx_chainmask; + sc->sc_rx_chainmask = ah->ah_caps.rx_chainmask; + + ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL); + sc->rx.defant = ath9k_hw_getdefantenna(ah); + + ath9k_hw_getmac(ah, sc->sc_myaddr); + if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) { + ath9k_hw_getbssidmask(ah, sc->sc_bssidmask); + ATH_SET_VAP_BSSID_MASK(sc->sc_bssidmask); + ath9k_hw_setbssidmask(ah, sc->sc_bssidmask); + } + + sc->beacon.slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */ + + /* initialize beacon slots */ + for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) + sc->beacon.bslot[i] = ATH_IF_ID_ANY; + + /* save MISC configurations */ + sc->sc_config.swBeaconProcess = 1; /* setup channels and rates */ @@ -942,146 +1521,455 @@ static int ath_attach(u16 devid, sc->rates[IEEE80211_BAND_2GHZ]; sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; - if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) - /* Setup HT capabilities for 2.4Ghz*/ - setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_info); - - hw->wiphy->bands[IEEE80211_BAND_2GHZ] = - &sc->sbands[IEEE80211_BAND_2GHZ]; - if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) { sc->sbands[IEEE80211_BAND_5GHZ].channels = sc->channels[IEEE80211_BAND_5GHZ]; sc->sbands[IEEE80211_BAND_5GHZ].bitrates = sc->rates[IEEE80211_BAND_5GHZ]; - sc->sbands[IEEE80211_BAND_5GHZ].band = - IEEE80211_BAND_5GHZ; + sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; + } + + return 0; +bad2: + /* cleanup tx queues */ + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) + if (ATH_TXQ_SETUP(sc, i)) + ath_tx_cleanupq(sc, &sc->tx.txq[i]); +bad: + if (ah) + ath9k_hw_detach(ah); + + return error; +} + +static int ath_attach(u16 devid, struct ath_softc *sc) +{ + struct ieee80211_hw *hw = sc->hw; + int error = 0; + + DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n"); + + error = ath_init(devid, sc); + if (error != 0) + return error; + + /* get mac address from hardware and set in mac80211 */ + + SET_IEEE80211_PERM_ADDR(hw, sc->sc_myaddr); + + hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_AMPDU_AGGREGATION; + + hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC); + + hw->queues = 4; + hw->max_rates = 4; + hw->max_rate_tries = ATH_11N_TXMAXTRY; + hw->sta_data_size = sizeof(struct ath_node); + hw->vif_data_size = sizeof(struct ath_vap); + + hw->rate_control_algorithm = "ath9k_rate_control"; + + if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) { + setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); + if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) + setup_ht_cap(&sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); + } + + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &sc->sbands[IEEE80211_BAND_2GHZ]; + if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) + hw->wiphy->bands[IEEE80211_BAND_5GHZ] = + &sc->sbands[IEEE80211_BAND_5GHZ]; + + /* initialize tx/rx engine */ + error = ath_tx_init(sc, ATH_TXBUF); + if (error != 0) + goto detach; + + error = ath_rx_init(sc, ATH_RXBUF); + if (error != 0) + goto detach; + +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) + /* Initialze h/w Rfkill */ + if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + INIT_DELAYED_WORK(&sc->rf_kill.rfkill_poll, ath_rfkill_poll); + + /* Initialize s/w rfkill */ + if (ath_init_sw_rfkill(sc)) + goto detach; +#endif + + error = ieee80211_register_hw(hw); + + /* Initialize LED control */ + ath_init_leds(sc); + + return 0; +detach: + ath_detach(sc); + return error; +} + +int ath_reset(struct ath_softc *sc, bool retry_tx) +{ + struct ath_hal *ah = sc->sc_ah; + int status; + int error = 0; + + ath9k_hw_set_interrupts(ah, 0); + ath_draintxq(sc, retry_tx); + ath_stoprecv(sc); + ath_flushrecv(sc); + + spin_lock_bh(&sc->sc_resetlock); + if (!ath9k_hw_reset(ah, sc->sc_ah->ah_curchan, + sc->tx_chan_width, + sc->sc_tx_chainmask, sc->sc_rx_chainmask, + sc->sc_ht_extprotspacing, false, &status)) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to reset hardware; hal status %u\n", status); + error = -EIO; + } + spin_unlock_bh(&sc->sc_resetlock); + + if (ath_startrecv(sc) != 0) + DPRINTF(sc, ATH_DBG_FATAL, "Unable to start recv logic\n"); + + /* + * We may be doing a reset in response to a request + * that changes the channel so update any state that + * might change as a result. + */ + ath_setcurmode(sc, ath_chan2mode(sc->sc_ah->ah_curchan)); + + ath_update_txpow(sc); + + if (sc->sc_flags & SC_OP_BEACONS) + ath_beacon_config(sc, ATH_IF_ID_ANY); /* restart beacons */ + + ath9k_hw_set_interrupts(ah, sc->sc_imask); + + if (retry_tx) { + int i; + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { + if (ATH_TXQ_SETUP(sc, i)) { + spin_lock_bh(&sc->tx.txq[i].axq_lock); + ath_txq_schedule(sc, &sc->tx.txq[i]); + spin_unlock_bh(&sc->tx.txq[i].axq_lock); + } + } + } + + return error; +} + +/* + * This function will allocate both the DMA descriptor structure, and the + * buffers it contains. These are used to contain the descriptors used + * by the system. +*/ +int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, + struct list_head *head, const char *name, + int nbuf, int ndesc) +{ +#define DS2PHYS(_dd, _ds) \ + ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc)) +#define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0) +#define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096) + + struct ath_desc *ds; + struct ath_buf *bf; + int i, bsize, error; + + DPRINTF(sc, ATH_DBG_CONFIG, "%s DMA: %u buffers %u desc/buf\n", + name, nbuf, ndesc); + + /* ath_desc must be a multiple of DWORDs */ + if ((sizeof(struct ath_desc) % 4) != 0) { + DPRINTF(sc, ATH_DBG_FATAL, "ath_desc not DWORD aligned\n"); + ASSERT((sizeof(struct ath_desc) % 4) == 0); + error = -ENOMEM; + goto fail; + } + + dd->dd_name = name; + dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc; + + /* + * Need additional DMA memory because we can't use + * descriptors that cross the 4K page boundary. Assume + * one skipped descriptor per 4K page. + */ + if (!(sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) { + u32 ndesc_skipped = + ATH_DESC_4KB_BOUND_NUM_SKIPPED(dd->dd_desc_len); + u32 dma_len; - if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) - /* Setup HT capabilities for 5Ghz*/ - setup_ht_cap(&sc->sbands[IEEE80211_BAND_5GHZ].ht_info); + while (ndesc_skipped) { + dma_len = ndesc_skipped * sizeof(struct ath_desc); + dd->dd_desc_len += dma_len; - hw->wiphy->bands[IEEE80211_BAND_5GHZ] = - &sc->sbands[IEEE80211_BAND_5GHZ]; + ndesc_skipped = ATH_DESC_4KB_BOUND_NUM_SKIPPED(dma_len); + }; } - /* FIXME: Have to figure out proper hw init values later */ + /* allocate descriptors */ + dd->dd_desc = pci_alloc_consistent(sc->pdev, + dd->dd_desc_len, + &dd->dd_desc_paddr); + if (dd->dd_desc == NULL) { + error = -ENOMEM; + goto fail; + } + ds = dd->dd_desc; + DPRINTF(sc, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n", + dd->dd_name, ds, (u32) dd->dd_desc_len, + ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len); + + /* allocate buffers */ + bsize = sizeof(struct ath_buf) * nbuf; + bf = kmalloc(bsize, GFP_KERNEL); + if (bf == NULL) { + error = -ENOMEM; + goto fail2; + } + memset(bf, 0, bsize); + dd->dd_bufptr = bf; - hw->queues = 4; - hw->ampdu_queues = 1; + INIT_LIST_HEAD(head); + for (i = 0; i < nbuf; i++, bf++, ds += ndesc) { + bf->bf_desc = ds; + bf->bf_daddr = DS2PHYS(dd, ds); - /* Register rate control */ - hw->rate_control_algorithm = "ath9k_rate_control"; - error = ath_rate_control_register(); - if (error != 0) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to register rate control " - "algorithm:%d\n", __func__, error); - ath_rate_control_unregister(); - goto bad; + if (!(sc->sc_ah->ah_caps.hw_caps & + ATH9K_HW_CAP_4KB_SPLITTRANS)) { + /* + * Skip descriptor addresses which can cause 4KB + * boundary crossing (addr + length) with a 32 dword + * descriptor fetch. + */ + while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) { + ASSERT((caddr_t) bf->bf_desc < + ((caddr_t) dd->dd_desc + + dd->dd_desc_len)); + + ds += ndesc; + bf->bf_desc = ds; + bf->bf_daddr = DS2PHYS(dd, ds); + } + } + list_add_tail(&bf->list, head); } + return 0; +fail2: + pci_free_consistent(sc->pdev, + dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr); +fail: + memset(dd, 0, sizeof(*dd)); + return error; +#undef ATH_DESC_4KB_BOUND_CHECK +#undef ATH_DESC_4KB_BOUND_NUM_SKIPPED +#undef DS2PHYS +} - error = ieee80211_register_hw(hw); - if (error != 0) { - ath_rate_control_unregister(); - goto bad; - } +void ath_descdma_cleanup(struct ath_softc *sc, + struct ath_descdma *dd, + struct list_head *head) +{ + pci_free_consistent(sc->pdev, + dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr); - /* Initialize LED control */ - ath_init_leds(sc); + INIT_LIST_HEAD(head); + kfree(dd->dd_bufptr); + memset(dd, 0, sizeof(*dd)); +} -#ifdef CONFIG_RFKILL - /* Initialze h/w Rfkill */ - if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) - INIT_DELAYED_WORK(&sc->rf_kill.rfkill_poll, ath_rfkill_poll); +int ath_get_hal_qnum(u16 queue, struct ath_softc *sc) +{ + int qnum; - /* Initialize s/w rfkill */ - if (ath_init_sw_rfkill(sc)) - goto detach; -#endif + switch (queue) { + case 0: + qnum = sc->tx.hwq_map[ATH9K_WME_AC_VO]; + break; + case 1: + qnum = sc->tx.hwq_map[ATH9K_WME_AC_VI]; + break; + case 2: + qnum = sc->tx.hwq_map[ATH9K_WME_AC_BE]; + break; + case 3: + qnum = sc->tx.hwq_map[ATH9K_WME_AC_BK]; + break; + default: + qnum = sc->tx.hwq_map[ATH9K_WME_AC_BE]; + break; + } - /* initialize tx/rx engine */ + return qnum; +} - error = ath_tx_init(sc, ATH_TXBUF); - if (error != 0) - goto detach; +int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc) +{ + int qnum; - error = ath_rx_init(sc, ATH_RXBUF); - if (error != 0) - goto detach; + switch (queue) { + case ATH9K_WME_AC_VO: + qnum = 0; + break; + case ATH9K_WME_AC_VI: + qnum = 1; + break; + case ATH9K_WME_AC_BE: + qnum = 2; + break; + case ATH9K_WME_AC_BK: + qnum = 3; + break; + default: + qnum = -1; + break; + } - return 0; -detach: - ath_detach(sc); -bad: - return error; + return qnum; } +/**********************/ +/* mac80211 callbacks */ +/**********************/ + static int ath9k_start(struct ieee80211_hw *hw) { struct ath_softc *sc = hw->priv; struct ieee80211_channel *curchan = hw->conf.channel; - int error = 0, pos; + struct ath9k_channel *init_channel; + int error = 0, pos, status; - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Starting driver with " - "initial channel: %d MHz\n", __func__, curchan->center_freq); + DPRINTF(sc, ATH_DBG_CONFIG, "Starting driver with " + "initial channel: %d MHz\n", curchan->center_freq); /* setup initial channel */ pos = ath_get_channel(sc, curchan); if (pos == -1) { - DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__); - return -EINVAL; + DPRINTF(sc, ATH_DBG_FATAL, "Invalid channel: %d\n", curchan->center_freq); + error = -EINVAL; + goto error; } + sc->tx_chan_width = ATH9K_HT_MACMODE_20; sc->sc_ah->ah_channels[pos].chanmode = (curchan->band == IEEE80211_BAND_2GHZ) ? CHANNEL_G : CHANNEL_A; + init_channel = &sc->sc_ah->ah_channels[pos]; + + /* Reset SERDES registers */ + ath9k_hw_configpcipowersave(sc->sc_ah, 0); - /* open ath_dev */ - error = ath_open(sc, &sc->sc_ah->ah_channels[pos]); - if (error) { + /* + * The basic interface to setting the hardware in a good + * state is ``reset''. On return the hardware is known to + * be powered up and with interrupts disabled. This must + * be followed by initialization of the appropriate bits + * and then setup of the interrupt mask. + */ + spin_lock_bh(&sc->sc_resetlock); + if (!ath9k_hw_reset(sc->sc_ah, init_channel, + sc->tx_chan_width, + sc->sc_tx_chainmask, sc->sc_rx_chainmask, + sc->sc_ht_extprotspacing, false, &status)) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to complete ath_open\n", __func__); - return error; + "Unable to reset hardware; hal status %u " + "(freq %u flags 0x%x)\n", status, + init_channel->channel, init_channel->channelFlags); + error = -EIO; + spin_unlock_bh(&sc->sc_resetlock); + goto error; } + spin_unlock_bh(&sc->sc_resetlock); -#ifdef CONFIG_RFKILL - /* Start rfkill polling */ - if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) - queue_delayed_work(sc->hw->workqueue, - &sc->rf_kill.rfkill_poll, 0); - - if (!(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) { - if (rfkill_register(sc->rf_kill.rfkill)) { - DPRINTF(sc, ATH_DBG_FATAL, - "Unable to register rfkill\n"); - rfkill_free(sc->rf_kill.rfkill); + /* + * This is needed only to setup initial state + * but it's best done after a reset. + */ + ath_update_txpow(sc); - /* Deinitialize the device */ - if (sc->pdev->irq) - free_irq(sc->pdev->irq, sc); - ath_detach(sc); - pci_iounmap(sc->pdev, sc->mem); - pci_release_region(sc->pdev, 0); - pci_disable_device(sc->pdev); - ieee80211_free_hw(hw); - return -EIO; - } else { - sc->sc_flags |= SC_OP_RFKILL_REGISTERED; - } + /* + * Setup the hardware after reset: + * The receive engine is set going. + * Frame transmit is handled entirely + * in the frame output path; there's nothing to do + * here except setup the interrupt mask. + */ + if (ath_startrecv(sc) != 0) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to start recv logic\n"); + error = -EIO; + goto error; } + + /* Setup our intr mask. */ + sc->sc_imask = ATH9K_INT_RX | ATH9K_INT_TX + | ATH9K_INT_RXEOL | ATH9K_INT_RXORN + | ATH9K_INT_FATAL | ATH9K_INT_GLOBAL; + + if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_GTT) + sc->sc_imask |= ATH9K_INT_GTT; + + if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) + sc->sc_imask |= ATH9K_INT_CST; + + /* + * Enable MIB interrupts when there are hardware phy counters. + * Note we only do this (at the moment) for station mode. + */ + if (ath9k_hw_phycounters(sc->sc_ah) && + ((sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION) || + (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC))) + sc->sc_imask |= ATH9K_INT_MIB; + /* + * Some hardware processes the TIM IE and fires an + * interrupt when the TIM bit is set. For hardware + * that does, if not overridden by configuration, + * enable the TIM interrupt when operating as station. + */ + if ((sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_ENHANCEDPM) && + (sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION) && + !sc->sc_config.swBeaconProcess) + sc->sc_imask |= ATH9K_INT_TIM; + + ath_setcurmode(sc, ath_chan2mode(init_channel)); + + sc->sc_flags &= ~SC_OP_INVALID; + + /* Disable BMISS interrupt when we're not associated */ + sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); + ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask); + + ieee80211_wake_queues(sc->hw); + +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) + error = ath_start_rfkill_poll(sc); #endif - ieee80211_wake_queues(hw); - return 0; +error: + return error; } static int ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ath_softc *sc = hw->priv; + struct ath_tx_control txctl; int hdrlen, padsize; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + memset(&txctl, 0, sizeof(struct ath_tx_control)); /* * As a temporary workaround, assign seq# here; this will likely need @@ -1091,9 +1979,9 @@ static int ath9k_tx(struct ieee80211_hw *hw, if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) - sc->seq_no += 0x10; + sc->tx.seq_no += 0x10; hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); - hdr->seq_ctrl |= cpu_to_le16(sc->seq_no); + hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no); } /* Add the padding after the header if this is not already done */ @@ -1106,45 +1994,68 @@ static int ath9k_tx(struct ieee80211_hw *hw, memmove(skb->data, skb->data + padsize, hdrlen); } - DPRINTF(sc, ATH_DBG_XMIT, "%s: transmitting packet, skb: %p\n", - __func__, - skb); + /* Check if a tx queue is available */ - if (ath_tx_start(sc, skb) != 0) { - DPRINTF(sc, ATH_DBG_XMIT, "%s: TX failed\n", __func__); - dev_kfree_skb_any(skb); - /* FIXME: Check for proper return value from ATH_DEV */ - return 0; + txctl.txq = ath_test_get_txq(sc, skb); + if (!txctl.txq) + goto exit; + + DPRINTF(sc, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb); + + if (ath_tx_start(sc, skb, &txctl) != 0) { + DPRINTF(sc, ATH_DBG_XMIT, "TX failed\n"); + goto exit; } + return 0; +exit: + dev_kfree_skb_any(skb); return 0; } static void ath9k_stop(struct ieee80211_hw *hw) { struct ath_softc *sc = hw->priv; - int error; - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Driver halt\n", __func__); + if (sc->sc_flags & SC_OP_INVALID) { + DPRINTF(sc, ATH_DBG_ANY, "Device not present\n"); + return; + } + + DPRINTF(sc, ATH_DBG_CONFIG, "Cleaning up\n"); - error = ath_suspend(sc); - if (error) - DPRINTF(sc, ATH_DBG_CONFIG, - "%s: Device is no longer present\n", __func__); + ieee80211_stop_queues(sc->hw); + + /* make sure h/w will not generate any interrupt + * before setting the invalid flag. */ + ath9k_hw_set_interrupts(sc->sc_ah, 0); - ieee80211_stop_queues(hw); + if (!(sc->sc_flags & SC_OP_INVALID)) { + ath_draintxq(sc, false); + ath_stoprecv(sc); + ath9k_hw_phy_disable(sc->sc_ah); + } else + sc->rx.rxlink = NULL; -#ifdef CONFIG_RFKILL +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); #endif + /* disable HAL and put h/w to sleep */ + ath9k_hw_disable(sc->sc_ah); + ath9k_hw_configpcipowersave(sc->sc_ah, 1); + + sc->sc_flags |= SC_OP_INVALID; + + DPRINTF(sc, ATH_DBG_CONFIG, "Driver halt\n"); } static int ath9k_add_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { struct ath_softc *sc = hw->priv; - int error, ic_opmode = 0; + struct ath_vap *avp = (void *)conf->vif->drv_priv; + enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED; /* Support only vap for now */ @@ -1153,32 +2064,34 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, switch (conf->type) { case NL80211_IFTYPE_STATION: - ic_opmode = ATH9K_M_STA; + ic_opmode = NL80211_IFTYPE_STATION; break; case NL80211_IFTYPE_ADHOC: - ic_opmode = ATH9K_M_IBSS; + ic_opmode = NL80211_IFTYPE_ADHOC; break; case NL80211_IFTYPE_AP: - ic_opmode = ATH9K_M_HOSTAP; + ic_opmode = NL80211_IFTYPE_AP; break; default: DPRINTF(sc, ATH_DBG_FATAL, - "%s: Interface type %d not yet supported\n", - __func__, conf->type); + "Interface type %d not yet supported\n", conf->type); return -EOPNOTSUPP; } - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach a VAP of type: %d\n", - __func__, - ic_opmode); + DPRINTF(sc, ATH_DBG_CONFIG, "Attach a VAP of type: %d\n", ic_opmode); - error = ath_vap_attach(sc, 0, conf->vif, ic_opmode); - if (error) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to attach vap, error: %d\n", - __func__, error); - return error; - } + /* Set the VAP opmode */ + avp->av_opmode = ic_opmode; + avp->av_bslot = -1; + + if (ic_opmode == NL80211_IFTYPE_AP) + ath9k_hw_set_tsfadjust(sc->sc_ah, 1); + + sc->sc_vaps[0] = conf->vif; + sc->sc_nvaps++; + + /* Set the device opmode */ + sc->sc_ah->ah_opmode = ic_opmode; if (conf->type == NL80211_IFTYPE_AP) { /* TODO: is this a suitable place to start ANI for AP mode? */ @@ -1194,78 +2107,76 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { struct ath_softc *sc = hw->priv; - struct ath_vap *avp; - int error; - - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach VAP\n", __func__); + struct ath_vap *avp = (void *)conf->vif->drv_priv; - avp = sc->sc_vaps[0]; - if (avp == NULL) { - DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n", - __func__); - return; - } + DPRINTF(sc, ATH_DBG_CONFIG, "Detach Interface\n"); -#ifdef CONFIG_SLOW_ANT_DIV - ath_slow_ant_div_stop(&sc->sc_antdiv); -#endif /* Stop ANI */ del_timer_sync(&sc->sc_ani.timer); - /* Update ratectrl */ - ath_rate_newstate(sc, avp); - /* Reclaim beacon resources */ - if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP || - sc->sc_ah->ah_opmode == ATH9K_M_IBSS) { - ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq); + if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP || + sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC) { + ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); ath_beacon_return(sc, avp); } - /* Set interrupt mask */ - sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); - ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask & ~ATH9K_INT_GLOBAL); sc->sc_flags &= ~SC_OP_BEACONS; - error = ath_vap_detach(sc, 0); - if (error) - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to detach vap, error: %d\n", - __func__, error); + sc->sc_vaps[0] = NULL; + sc->sc_nvaps--; } -static int ath9k_config(struct ieee80211_hw *hw, - struct ieee80211_conf *conf) +static int ath9k_config(struct ieee80211_hw *hw, u32 changed) { struct ath_softc *sc = hw->priv; - struct ieee80211_channel *curchan = hw->conf.channel; - int pos; + struct ieee80211_conf *conf = &hw->conf; - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n", - __func__, - curchan->center_freq); + mutex_lock(&sc->mutex); + if (changed & (IEEE80211_CONF_CHANGE_CHANNEL | + IEEE80211_CONF_CHANGE_HT)) { + struct ieee80211_channel *curchan = hw->conf.channel; + int pos; - pos = ath_get_channel(sc, curchan); - if (pos == -1) { - DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__); - return -EINVAL; - } + DPRINTF(sc, ATH_DBG_CONFIG, "Set channel: %d MHz\n", + curchan->center_freq); - sc->sc_ah->ah_channels[pos].chanmode = - (curchan->band == IEEE80211_BAND_2GHZ) ? - CHANNEL_G : CHANNEL_A; + pos = ath_get_channel(sc, curchan); + if (pos == -1) { + DPRINTF(sc, ATH_DBG_FATAL, "Invalid channel: %d\n", + curchan->center_freq); + mutex_unlock(&sc->mutex); + return -EINVAL; + } - if (sc->sc_curaid && hw->conf.ht_conf.ht_supported) + sc->tx_chan_width = ATH9K_HT_MACMODE_20; sc->sc_ah->ah_channels[pos].chanmode = - ath_get_extchanmode(sc, curchan); + (curchan->band == IEEE80211_BAND_2GHZ) ? + CHANNEL_G : CHANNEL_A; + + if (conf->ht.enabled) { + if (conf->ht.channel_type == NL80211_CHAN_HT40PLUS || + conf->ht.channel_type == NL80211_CHAN_HT40MINUS) + sc->tx_chan_width = ATH9K_HT_MACMODE_2040; + + sc->sc_ah->ah_channels[pos].chanmode = + ath_get_extchanmode(sc, curchan, + conf->ht.channel_type); + } + + if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) { + DPRINTF(sc, ATH_DBG_FATAL, "Unable to set channel\n"); + mutex_unlock(&sc->mutex); + return -EINVAL; + } - sc->sc_config.txpowlimit = 2 * conf->power_level; + ath_update_chainmask(sc, conf->ht.enabled); + } - /* set h/w channel */ - if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) - DPRINTF(sc, ATH_DBG_FATAL, "%s: Unable to set channel\n", - __func__); + if (changed & IEEE80211_CONF_CHANGE_POWER) + sc->sc_config.txpowlimit = 2 * conf->power_level; + mutex_unlock(&sc->mutex); return 0; } @@ -1275,23 +2186,15 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, { struct ath_softc *sc = hw->priv; struct ath_hal *ah = sc->sc_ah; - struct ath_vap *avp; + struct ath_vap *avp = (void *)vif->drv_priv; u32 rfilt = 0; int error, i; - DECLARE_MAC_BUF(mac); - - avp = sc->sc_vaps[0]; - if (avp == NULL) { - DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n", - __func__); - return -EINVAL; - } /* TODO: Need to decide which hw opmode to use for multi-interface * cases */ if (vif->type == NL80211_IFTYPE_AP && - ah->ah_opmode != ATH9K_M_HOSTAP) { - ah->ah_opmode = ATH9K_M_HOSTAP; + ah->ah_opmode != NL80211_IFTYPE_AP) { + ah->ah_opmode = NL80211_IFTYPE_STATION; ath9k_hw_setopmode(ah); ath9k_hw_write_associd(ah, sc->sc_myaddr, 0); /* Request full reset to get hw opmode changed properly */ @@ -1303,9 +2206,6 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, switch (vif->type) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_ADHOC: - /* Update ratectrl about the new state */ - ath_rate_newstate(sc, avp); - /* Set BSSID */ memcpy(sc->sc_curbssid, conf->bssid, ETH_ALEN); sc->sc_curaid = 0; @@ -1315,27 +2215,9 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, /* Set aggregation protection mode parameters */ sc->sc_config.ath_aggr_prot = 0; - /* - * Reset our TSF so that its value is lower than the - * beacon that we are trying to catch. - * Only then hw will update its TSF register with the - * new beacon. Reset the TSF before setting the BSSID - * to avoid allowing in any frames that would update - * our TSF only to have us clear it - * immediately thereafter. - */ - ath9k_hw_reset_tsf(sc->sc_ah); - - /* Disable BMISS interrupt when we're not associated */ - ath9k_hw_set_interrupts(sc->sc_ah, - sc->sc_imask & - ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS)); - sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); - DPRINTF(sc, ATH_DBG_CONFIG, - "%s: RX filter 0x%x bssid %s aid 0x%x\n", - __func__, rfilt, - print_mac(mac, sc->sc_curbssid), sc->sc_curaid); + "RX filter 0x%x bssid %pM aid 0x%x\n", + rfilt, sc->sc_curbssid, sc->sc_curaid); /* need to reconfigure the beacon */ sc->sc_flags &= ~SC_OP_BEACONS ; @@ -1357,7 +2239,7 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, * causes reconfiguration; we may be called * with beacon transmission active. */ - ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq); + ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); error = ath_beacon_alloc(sc, 0); if (error != 0) @@ -1403,7 +2285,7 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw, changed_flags &= SUPPORTED_FILTERS; *total_flags &= SUPPORTED_FILTERS; - sc->rx_filter = *total_flags; + sc->rx.rxfilter = *total_flags; rfilt = ath_calcrxfilter(sc); ath9k_hw_setrxfilter(sc->sc_ah, rfilt); @@ -1412,8 +2294,7 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw, ath9k_hw_write_associd(sc->sc_ah, ath_bcast_mac, 0); } - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set HW RX filter: 0x%x\n", - __func__, sc->rx_filter); + DPRINTF(sc, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", sc->rx.rxfilter); } static void ath9k_sta_notify(struct ieee80211_hw *hw, @@ -1422,37 +2303,13 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, struct ieee80211_sta *sta) { struct ath_softc *sc = hw->priv; - struct ath_node *an; - unsigned long flags; - DECLARE_MAC_BUF(mac); - - spin_lock_irqsave(&sc->node_lock, flags); - an = ath_node_find(sc, sta->addr); - spin_unlock_irqrestore(&sc->node_lock, flags); switch (cmd) { case STA_NOTIFY_ADD: - spin_lock_irqsave(&sc->node_lock, flags); - if (!an) { - ath_node_attach(sc, sta->addr, 0); - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach a node: %s\n", - __func__, print_mac(mac, sta->addr)); - } else { - ath_node_get(sc, sta->addr); - } - spin_unlock_irqrestore(&sc->node_lock, flags); + ath_node_attach(sc, sta); break; case STA_NOTIFY_REMOVE: - if (!an) - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Removal of a non-existent node\n", - __func__); - else { - ath_node_put(sc, an, ATH9K_BH_STATUS_INTACT); - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Put a node: %s\n", - __func__, - print_mac(mac, sta->addr)); - } + ath_node_detach(sc, sta); break; default: break; @@ -1477,20 +2334,14 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw, qnum = ath_get_hal_qnum(queue, sc); DPRINTF(sc, ATH_DBG_CONFIG, - "%s: Configure tx [queue/halq] [%d/%d], " + "Configure tx [queue/halq] [%d/%d], " "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n", - __func__, - queue, - qnum, - params->aifs, - params->cw_min, - params->cw_max, - params->txop); + queue, qnum, params->aifs, params->cw_min, + params->cw_max, params->txop); ret = ath_txq_update(sc, qnum, &qi); if (ret) - DPRINTF(sc, ATH_DBG_FATAL, - "%s: TXQ Update failed\n", __func__); + DPRINTF(sc, ATH_DBG_FATAL, "TXQ Update failed\n"); return ret; } @@ -1504,23 +2355,22 @@ static int ath9k_set_key(struct ieee80211_hw *hw, struct ath_softc *sc = hw->priv; int ret = 0; - DPRINTF(sc, ATH_DBG_KEYCACHE, " %s: Set HW Key\n", __func__); + DPRINTF(sc, ATH_DBG_KEYCACHE, "Set HW Key\n"); switch (cmd) { case SET_KEY: ret = ath_key_config(sc, addr, key); - if (!ret) { - set_bit(key->keyidx, sc->sc_keymap); - key->hw_key_idx = key->keyidx; + if (ret >= 0) { + key->hw_key_idx = ret; /* push IV and Michael MIC generation to stack */ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; if (key->alg == ALG_TKIP) key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; + ret = 0; } break; case DISABLE_KEY: ath_key_delete(sc, key); - clear_bit(key->keyidx, sc->sc_keymap); break; default: ret = -EINVAL; @@ -1537,8 +2387,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, struct ath_softc *sc = hw->priv; if (changed & BSS_CHANGED_ERP_PREAMBLE) { - DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed PREAMBLE %d\n", - __func__, + DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n", bss_conf->use_short_preamble); if (bss_conf->use_short_preamble) sc->sc_flags |= SC_OP_PREAMBLE_SHORT; @@ -1547,8 +2396,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_ERP_CTS_PROT) { - DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed CTS PROT %d\n", - __func__, + DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n", bss_conf->use_cts_prot); if (bss_conf->use_cts_prot && hw->conf.channel->band != IEEE80211_BAND_5GHZ) @@ -1557,18 +2405,10 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, sc->sc_flags &= ~SC_OP_PROTECT_ENABLE; } - if (changed & BSS_CHANGED_HT) { - DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed HT %d\n", - __func__, - bss_conf->assoc_ht); - ath9k_ht_conf(sc, bss_conf); - } - if (changed & BSS_CHANGED_ASSOC) { - DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed ASSOC %d\n", - __func__, + DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n", bss_conf->assoc); - ath9k_bss_assoc_info(sc, bss_conf); + ath9k_bss_assoc_info(sc, vif, bss_conf); } } @@ -1601,50 +2441,37 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, switch (action) { case IEEE80211_AMPDU_RX_START: - ret = ath_rx_aggr_start(sc, sta->addr, tid, ssn); - if (ret < 0) - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to start RX aggregation\n", - __func__); + if (!(sc->sc_flags & SC_OP_RXAGGR)) + ret = -ENOTSUPP; break; case IEEE80211_AMPDU_RX_STOP: - ret = ath_rx_aggr_stop(sc, sta->addr, tid); - if (ret < 0) - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to stop RX aggregation\n", - __func__); break; case IEEE80211_AMPDU_TX_START: - ret = ath_tx_aggr_start(sc, sta->addr, tid, ssn); + ret = ath_tx_aggr_start(sc, sta, tid, ssn); if (ret < 0) DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to start TX aggregation\n", - __func__); + "Unable to start TX aggregation\n"); else ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid); break; case IEEE80211_AMPDU_TX_STOP: - ret = ath_tx_aggr_stop(sc, sta->addr, tid); + ret = ath_tx_aggr_stop(sc, sta, tid); if (ret < 0) DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to stop TX aggregation\n", - __func__); + "Unable to stop TX aggregation\n"); ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid); break; + case IEEE80211_AMPDU_TX_RESUME: + ath_tx_aggr_resume(sc, sta, tid); + break; default: - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unknown AMPDU action\n", __func__); + DPRINTF(sc, ATH_DBG_FATAL, "Unknown AMPDU action\n"); } return ret; } -static int ath9k_no_fragmentation(struct ieee80211_hw *hw, u32 value) -{ - return -EOPNOTSUPP; -} - static struct ieee80211_ops ath9k_ops = { .tx = ath9k_tx, .start = ath9k_start, @@ -1654,42 +2481,97 @@ static struct ieee80211_ops ath9k_ops = { .config = ath9k_config, .config_interface = ath9k_config_interface, .configure_filter = ath9k_configure_filter, - .get_stats = NULL, .sta_notify = ath9k_sta_notify, .conf_tx = ath9k_conf_tx, - .get_tx_stats = NULL, .bss_info_changed = ath9k_bss_info_changed, - .set_tim = NULL, .set_key = ath9k_set_key, - .hw_scan = NULL, - .get_tkip_seq = NULL, - .set_rts_threshold = NULL, - .set_frag_threshold = NULL, - .set_retry_limit = NULL, .get_tsf = ath9k_get_tsf, .reset_tsf = ath9k_reset_tsf, - .tx_last_beacon = NULL, .ampdu_action = ath9k_ampdu_action, - .set_frag_threshold = ath9k_no_fragmentation, }; +static struct { + u32 version; + const char * name; +} ath_mac_bb_names[] = { + { AR_SREV_VERSION_5416_PCI, "5416" }, + { AR_SREV_VERSION_5416_PCIE, "5418" }, + { AR_SREV_VERSION_9100, "9100" }, + { AR_SREV_VERSION_9160, "9160" }, + { AR_SREV_VERSION_9280, "9280" }, + { AR_SREV_VERSION_9285, "9285" } +}; + +static struct { + u16 version; + const char * name; +} ath_rf_names[] = { + { 0, "5133" }, + { AR_RAD5133_SREV_MAJOR, "5133" }, + { AR_RAD5122_SREV_MAJOR, "5122" }, + { AR_RAD2133_SREV_MAJOR, "2133" }, + { AR_RAD2122_SREV_MAJOR, "2122" } +}; + +/* + * Return the MAC/BB name. "????" is returned if the MAC/BB is unknown. + */ +static const char * +ath_mac_bb_name(u32 mac_bb_version) +{ + int i; + + for (i=0; iflags = IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_NOISE_DBM; - - hw->wiphy->interface_modes = - BIT(NL80211_IFTYPE_AP) | - BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC); - SET_IEEE80211_DEV(hw, &pdev->dev); pci_set_drvdata(pdev, hw); @@ -1778,11 +2650,15 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto bad4; } - athname = ath9k_hw_probe(id->vendor, id->device); - - printk(KERN_INFO "%s: %s: mem=0x%lx, irq=%d\n", + ah = sc->sc_ah; + printk(KERN_INFO + "%s: Atheros AR%s MAC/BB Rev:%x " + "AR%s RF Rev:%x: mem=0x%lx, irq=%d\n", wiphy_name(hw->wiphy), - athname ? athname : "Atheros ???", + ath_mac_bb_name(ah->ah_macVersion), + ah->ah_macRev, + ath_rf_name((ah->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR)), + ah->ah_phyRev, (unsigned long)mem, pdev->irq); return 0; @@ -1803,17 +2679,10 @@ static void ath_pci_remove(struct pci_dev *pdev) { struct ieee80211_hw *hw = pci_get_drvdata(pdev); struct ath_softc *sc = hw->priv; - enum ath9k_int status; - if (pdev->irq) { - ath9k_hw_set_interrupts(sc->sc_ah, 0); - /* clear the ISR */ - ath9k_hw_getisr(sc->sc_ah, &status); - sc->sc_flags |= SC_OP_INVALID; - free_irq(pdev->irq, sc); - } ath_detach(sc); - + if (pdev->irq) + free_irq(pdev->irq, sc); pci_iounmap(pdev, sc->mem); pci_release_region(pdev, 0); pci_disable_device(pdev); @@ -1829,7 +2698,7 @@ static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); -#ifdef CONFIG_RFKILL +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); #endif @@ -1866,7 +2735,7 @@ static int ath_pci_resume(struct pci_dev *pdev) AR_GPIO_OUTPUT_MUX_AS_OUTPUT); ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); -#ifdef CONFIG_RFKILL +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) /* * check the h/w rfkill state on resume * and start the rfkill poll timer @@ -1896,11 +2765,24 @@ static struct pci_driver ath_pci_driver = { static int __init init_ath_pci(void) { + int error; + printk(KERN_INFO "%s: %s\n", dev_info, ATH_PCI_VERSION); + /* Register rate control algorithm */ + error = ath_rate_control_register(); + if (error != 0) { + printk(KERN_ERR + "Unable to register rate control algorithm: %d\n", + error); + ath_rate_control_unregister(); + return error; + } + if (pci_register_driver(&ath_pci_driver) < 0) { printk(KERN_ERR "ath_pci: No devices found, driver not installed.\n"); + ath_rate_control_unregister(); pci_unregister_driver(&ath_pci_driver); return -ENODEV; } @@ -1911,7 +2793,8 @@ module_init(init_ath_pci); static void __exit exit_ath_pci(void) { + ath_rate_control_unregister(); pci_unregister_driver(&ath_pci_driver); - printk(KERN_INFO "%s: driver unloaded\n", dev_info); + printk(KERN_INFO "%s: Driver unloaded\n", dev_info); } module_exit(exit_ath_pci); diff --git a/drivers/net/wireless/ath9k/phy.c b/drivers/net/wireless/ath9k/phy.c index eb9121fdfd385389087807526edcc28924e12942..766982a8196e38b154348f14944e816519abea4e 100644 --- a/drivers/net/wireless/ath9k/phy.c +++ b/drivers/net/wireless/ath9k/phy.c @@ -52,8 +52,7 @@ ath9k_hw_set_channel(struct ath_hal *ah, struct ath9k_channel *chan) bModeSynth = 1; } else { DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: invalid channel %u MHz\n", __func__, - freq); + "Invalid channel %u MHz\n", freq); return false; } @@ -86,7 +85,7 @@ ath9k_hw_set_channel(struct ath_hal *ah, struct ath9k_channel *chan) aModeRefSel = ath9k_hw_reverse_bits(1, 2); } else { DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: invalid channel %u MHz\n", __func__, freq); + "Invalid channel %u MHz\n", freq); return false; } @@ -215,7 +214,7 @@ ath9k_hw_set_rf_regs(struct ath_hal *ah, struct ath9k_channel *chan, if (AR_SREV_9280_10_OR_LATER(ah)) return true; - eepMinorRev = ath9k_hw_get_eeprom(ahp, EEP_MINOR_REV); + eepMinorRev = ath9k_hw_get_eeprom(ah, EEP_MINOR_REV); RF_BANK_SETUP(ahp->ah_analogBank0Data, &ahp->ah_iniBank0, 1); @@ -235,15 +234,15 @@ ath9k_hw_set_rf_regs(struct ath_hal *ah, struct ath9k_channel *chan, if (eepMinorRev >= 2) { if (IS_CHAN_2GHZ(chan)) { - ob2GHz = ath9k_hw_get_eeprom(ahp, EEP_OB_2); - db2GHz = ath9k_hw_get_eeprom(ahp, EEP_DB_2); + ob2GHz = ath9k_hw_get_eeprom(ah, EEP_OB_2); + db2GHz = ath9k_hw_get_eeprom(ah, EEP_DB_2); ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data, ob2GHz, 3, 197, 0); ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data, db2GHz, 3, 194, 0); } else { - ob5GHz = ath9k_hw_get_eeprom(ahp, EEP_OB_5); - db5GHz = ath9k_hw_get_eeprom(ahp, EEP_DB_5); + ob5GHz = ath9k_hw_get_eeprom(ah, EEP_OB_5); + db5GHz = ath9k_hw_get_eeprom(ah, EEP_DB_5); ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data, ob5GHz, 3, 203, 0); ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data, @@ -348,8 +347,7 @@ bool ath9k_hw_init_rf(struct ath_hal *ah, int *status) || ahp->ah_analogBank6TPCData == NULL || ahp->ah_analogBank7Data == NULL) { DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "%s: cannot allocate RF banks\n", - __func__); + "Cannot allocate RF banks\n"); *status = -ENOMEM; return false; } @@ -360,8 +358,7 @@ bool ath9k_hw_init_rf(struct ath_hal *ah, int *status) ahp->ah_iniAddac.ia_columns), GFP_KERNEL); if (ahp->ah_addac5416_21 == NULL) { DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "%s: cannot allocate ah_addac5416_21\n", - __func__); + "Cannot allocate ah_addac5416_21\n"); *status = -ENOMEM; return false; } @@ -371,8 +368,7 @@ bool ath9k_hw_init_rf(struct ath_hal *ah, int *status) ahp->ah_iniBank6.ia_rows), GFP_KERNEL); if (ahp->ah_bank6Temp == NULL) { DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "%s: cannot allocate ah_bank6Temp\n", - __func__); + "Cannot allocate ah_bank6Temp\n"); *status = -ENOMEM; return false; } diff --git a/drivers/net/wireless/ath9k/phy.h b/drivers/net/wireless/ath9k/phy.h index 14702344448be9ee15d38836550806a80c193b44..3a406a5c0593c624d0f4a5d3842778fdb342874e 100644 --- a/drivers/net/wireless/ath9k/phy.h +++ b/drivers/net/wireless/ath9k/phy.h @@ -50,6 +50,9 @@ bool ath9k_hw_init_rf(struct ath_hal *ah, #define AR_PHY_FC_SHORT_GI_40 0x00000080 #define AR_PHY_FC_WALSH 0x00000100 #define AR_PHY_FC_SINGLE_HT_LTF1 0x00000200 +#define AR_PHY_FC_ENABLE_DAC_FIFO 0x00000800 + +#define AR_PHY_TEST2 0x9808 #define AR_PHY_TIMING2 0x9810 #define AR_PHY_TIMING3 0x9814 @@ -100,6 +103,8 @@ bool ath9k_hw_init_rf(struct ath_hal *ah, #define AR_PHY_RF_CTL4_FRAME_XPAA_ON 0x000000FF #define AR_PHY_RF_CTL4_FRAME_XPAA_ON_S 0 +#define AR_PHY_TSTDAC_CONST 0x983c + #define AR_PHY_SETTLING 0x9844 #define AR_PHY_SETTLING_SWITCH 0x00003F80 #define AR_PHY_SETTLING_SWITCH_S 7 diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index cca2fc5b07654b3e17107b4acaf2b7893e328d53..04ab457a8faa3f3bce73692b583a61866c72e6e2 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -15,143 +15,136 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* - * Atheros rate control algorithm - */ - #include "core.h" -/* FIXME: remove this include! */ -#include "../net/mac80211/rate.h" - -static u32 tx_triglevel_max; static struct ath_rate_table ar5416_11na_ratetable = { 42, + {0}, { - { TRUE, TRUE, WLAN_PHY_OFDM, 6000, /* 6 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ 5400, 0x0b, 0x00, 12, 0, 2, 1, 0, 0, 0, 0, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 9000, /* 9 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ 7800, 0x0f, 0x00, 18, 0, 3, 1, 1, 1, 1, 1, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 12 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ 10000, 0x0a, 0x00, 24, 2, 4, 2, 2, 2, 2, 2, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 18000, /* 18 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ 13900, 0x0e, 0x00, 36, 2, 6, 2, 3, 3, 3, 3, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 24000, /* 24 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ 17300, 0x09, 0x00, 48, 4, 10, 3, 4, 4, 4, 4, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 36000, /* 36 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ 23000, 0x0d, 0x00, 72, 4, 14, 3, 5, 5, 5, 5, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 48000, /* 48 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ 27400, 0x08, 0x00, 96, 4, 20, 3, 6, 6, 6, 6, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 54000, /* 54 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ 29300, 0x0c, 0x00, 108, 4, 23, 3, 7, 7, 7, 7, 0 }, - { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 6500, /* 6.5 Mb */ + { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */ 6400, 0x80, 0x00, 0, 0, 2, 3, 8, 24, 8, 24, 3216 }, - { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 13000, /* 13 Mb */ + { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */ 12700, 0x81, 0x00, 1, 2, 4, 3, 9, 25, 9, 25, 6434 }, - { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 19500, /* 19.5 Mb */ + { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */ 18800, 0x82, 0x00, 2, 2, 6, 3, 10, 26, 10, 26, 9650 }, - { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 26000, /* 26 Mb */ + { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */ 25000, 0x83, 0x00, 3, 4, 10, 3, 11, 27, 11, 27, 12868 }, - { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 39000, /* 39 Mb */ + { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */ 36700, 0x84, 0x00, 4, 4, 14, 3, 12, 28, 12, 28, 19304 }, - { FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 52000, /* 52 Mb */ + { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */ 48100, 0x85, 0x00, 5, 4, 20, 3, 13, 29, 13, 29, 25740 }, - { FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 58500, /* 58.5 Mb */ + { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */ 53500, 0x86, 0x00, 6, 4, 23, 3, 14, 30, 14, 30, 28956 }, - { FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 65000, /* 65 Mb */ + { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */ 59000, 0x87, 0x00, 7, 4, 25, 3, 15, 31, 15, 32, 32180 }, - { FALSE, FALSE, WLAN_PHY_HT_20_DS, 13000, /* 13 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */ 12700, 0x88, 0x00, 8, 0, 2, 3, 16, 33, 16, 33, 6430 }, - { FALSE, FALSE, WLAN_PHY_HT_20_DS, 26000, /* 26 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */ 24800, 0x89, 0x00, 9, 2, 4, 3, 17, 34, 17, 34, 12860 }, - { FALSE, FALSE, WLAN_PHY_HT_20_DS, 39000, /* 39 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */ 36600, 0x8a, 0x00, 10, 2, 6, 3, 18, 35, 18, 35, 19300 }, - { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 52000, /* 52 Mb */ + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */ 48100, 0x8b, 0x00, 11, 4, 10, 3, 19, 36, 19, 36, 25736 }, - { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 78000, /* 78 Mb */ + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */ 69500, 0x8c, 0x00, 12, 4, 14, 3, 20, 37, 20, 37, 38600 }, - { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 104000, /* 104 Mb */ + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */ 89500, 0x8d, 0x00, 13, 4, 20, 3, 21, 38, 21, 38, 51472 }, - { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 117000, /* 117 Mb */ + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */ 98900, 0x8e, 0x00, 14, 4, 23, 3, 22, 39, 22, 39, 57890 }, - { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 130000, /* 130 Mb */ + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */ 108300, 0x8f, 0x00, 15, 4, 25, 3, 23, 40, 23, 41, 64320 }, - { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 13500, /* 13.5 Mb */ + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */ 13200, 0x80, 0x00, 0, 0, 2, 3, 8, 24, 24, 24, 6684 }, - { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 27500, /* 27.0 Mb */ + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */ 25900, 0x81, 0x00, 1, 2, 4, 3, 9, 25, 25, 25, 13368 }, - { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 40500, /* 40.5 Mb */ + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */ 38600, 0x82, 0x00, 2, 2, 6, 3, 10, 26, 26, 26, 20052 }, - { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 54000, /* 54 Mb */ + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */ 49800, 0x83, 0x00, 3, 4, 10, 3, 11, 27, 27, 27, 26738 }, - { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 81500, /* 81 Mb */ + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */ 72200, 0x84, 0x00, 4, 4, 14, 3, 12, 28, 28, 28, 40104 }, - { FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 108000, /* 108 Mb */ + { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */ 92900, 0x85, 0x00, 5, 4, 20, 3, 13, 29, 29, 29, 53476 }, - { FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 121500, /* 121.5 Mb */ + { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */ 102700, 0x86, 0x00, 6, 4, 23, 3, 14, 30, 30, 30, 60156 }, - { FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 135000, /* 135 Mb */ + { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */ 112000, 0x87, 0x00, 7, 4, 25, 3, 15, 31, 32, 32, 66840 }, - { FALSE, TRUE_40, WLAN_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */ + { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */ 122000, 0x87, 0x00, 7, 4, 25, 3, 15, 31, 32, 32, 74200 }, - { FALSE, FALSE, WLAN_PHY_HT_40_DS, 27000, /* 27 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */ 25800, 0x88, 0x00, 8, 0, 2, 3, 16, 33, 33, 33, 13360 }, - { FALSE, FALSE, WLAN_PHY_HT_40_DS, 54000, /* 54 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */ 49800, 0x89, 0x00, 9, 2, 4, 3, 17, 34, 34, 34, 26720 }, - { FALSE, FALSE, WLAN_PHY_HT_40_DS, 81000, /* 81 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */ 71900, 0x8a, 0x00, 10, 2, 6, 3, 18, 35, 35, 35, 40080 }, - { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 108000, /* 108 Mb */ + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */ 92500, 0x8b, 0x00, 11, 4, 10, 3, 19, 36, 36, 36, 53440 }, - { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 162000, /* 162 Mb */ + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */ 130300, 0x8c, 0x00, 12, 4, 14, 3, 20, 37, 37, 37, 80160 }, - { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 216000, /* 216 Mb */ + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */ 162800, 0x8d, 0x00, 13, 4, 20, 3, 21, 38, 38, 38, 106880 }, - { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 243000, /* 243 Mb */ + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */ 178200, 0x8e, 0x00, 14, 4, 23, 3, 22, 39, 39, 39, 120240 }, - { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 270000, /* 270 Mb */ + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */ 192100, 0x8f, 0x00, 15, 4, 25, 3, 23, 40, 41, 41, 133600 }, - { TRUE_40, FALSE, WLAN_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */ + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */ 207000, 0x8f, 0x00, 15, 4, 25, 3, 23, 40, 41, 41, 148400 }, }, @@ -160,153 +153,149 @@ static struct ath_rate_table ar5416_11na_ratetable = { WLAN_RC_HT_FLAG, /* Phy rates allowed initially */ }; -/* TRUE_ALL - valid for 20/40/Legacy, - * TRUE - Legacy only, - * TRUE_20 - HT 20 only, - * TRUE_40 - HT 40 only */ - /* 4ms frame limit not used for NG mode. The values filled * for HT are the 64K max aggregate limit */ static struct ath_rate_table ar5416_11ng_ratetable = { 46, + {0}, { - { TRUE_ALL, TRUE_ALL, WLAN_PHY_CCK, 1000, /* 1 Mb */ + { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ 900, 0x1b, 0x00, 2, 0, 0, 1, 0, 0, 0, 0, 0 }, - { TRUE_ALL, TRUE_ALL, WLAN_PHY_CCK, 2000, /* 2 Mb */ + { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */ 1900, 0x1a, 0x04, 4, 1, 1, 1, 1, 1, 1, 1, 0 }, - { TRUE_ALL, TRUE_ALL, WLAN_PHY_CCK, 5500, /* 5.5 Mb */ + { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */ 4900, 0x19, 0x04, 11, 2, 2, 2, 2, 2, 2, 2, 0 }, - { TRUE_ALL, TRUE_ALL, WLAN_PHY_CCK, 11000, /* 11 Mb */ + { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */ 8100, 0x18, 0x04, 22, 3, 3, 2, 3, 3, 3, 3, 0 }, - { FALSE, FALSE, WLAN_PHY_OFDM, 6000, /* 6 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ 5400, 0x0b, 0x00, 12, 4, 2, 1, 4, 4, 4, 4, 0 }, - { FALSE, FALSE, WLAN_PHY_OFDM, 9000, /* 9 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ 7800, 0x0f, 0x00, 18, 4, 3, 1, 5, 5, 5, 5, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 12 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ 10100, 0x0a, 0x00, 24, 6, 4, 1, 6, 6, 6, 6, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 18000, /* 18 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ 14100, 0x0e, 0x00, 36, 6, 6, 2, 7, 7, 7, 7, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 24000, /* 24 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ 17700, 0x09, 0x00, 48, 8, 10, 3, 8, 8, 8, 8, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 36000, /* 36 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ 23700, 0x0d, 0x00, 72, 8, 14, 3, 9, 9, 9, 9, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 48000, /* 48 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ 27400, 0x08, 0x00, 96, 8, 20, 3, 10, 10, 10, 10, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 54000, /* 54 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ 30900, 0x0c, 0x00, 108, 8, 23, 3, 11, 11, 11, 11, 0 }, - { FALSE, FALSE, WLAN_PHY_HT_20_SS, 6500, /* 6.5 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */ 6400, 0x80, 0x00, 0, 4, 2, 3, 12, 28, 12, 28, 3216 }, - { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 13000, /* 13 Mb */ + { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */ 12700, 0x81, 0x00, 1, 6, 4, 3, 13, 29, 13, 29, 6434 }, - { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 19500, /* 19.5 Mb */ + { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */ 18800, 0x82, 0x00, 2, 6, 6, 3, 14, 30, 14, 30, 9650 }, - { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 26000, /* 26 Mb */ + { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */ 25000, 0x83, 0x00, 3, 8, 10, 3, 15, 31, 15, 31, 12868 }, - { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 39000, /* 39 Mb */ + { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */ 36700, 0x84, 0x00, 4, 8, 14, 3, 16, 32, 16, 32, 19304 }, - { FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 52000, /* 52 Mb */ + { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */ 48100, 0x85, 0x00, 5, 8, 20, 3, 17, 33, 17, 33, 25740 }, - { FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 58500, /* 58.5 Mb */ + { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */ 53500, 0x86, 0x00, 6, 8, 23, 3, 18, 34, 18, 34, 28956 }, - { FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 65000, /* 65 Mb */ + { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */ 59000, 0x87, 0x00, 7, 8, 25, 3, 19, 35, 19, 36, 32180 }, - { FALSE, FALSE, WLAN_PHY_HT_20_DS, 13000, /* 13 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */ 12700, 0x88, 0x00, 8, 4, 2, 3, 20, 37, 20, 37, 6430 }, - { FALSE, FALSE, WLAN_PHY_HT_20_DS, 26000, /* 26 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */ 24800, 0x89, 0x00, 9, 6, 4, 3, 21, 38, 21, 38, 12860 }, - { FALSE, FALSE, WLAN_PHY_HT_20_DS, 39000, /* 39 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */ 36600, 0x8a, 0x00, 10, 6, 6, 3, 22, 39, 22, 39, 19300 }, - { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 52000, /* 52 Mb */ + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */ 48100, 0x8b, 0x00, 11, 8, 10, 3, 23, 40, 23, 40, 25736 }, - { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 78000, /* 78 Mb */ + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */ 69500, 0x8c, 0x00, 12, 8, 14, 3, 24, 41, 24, 41, 38600 }, - { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 104000, /* 104 Mb */ + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */ 89500, 0x8d, 0x00, 13, 8, 20, 3, 25, 42, 25, 42, 51472 }, - { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 117000, /* 117 Mb */ + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */ 98900, 0x8e, 0x00, 14, 8, 23, 3, 26, 43, 26, 44, 57890 }, - { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 130000, /* 130 Mb */ + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */ 108300, 0x8f, 0x00, 15, 8, 25, 3, 27, 44, 27, 45, 64320 }, - { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 13500, /* 13.5 Mb */ + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */ 13200, 0x80, 0x00, 0, 8, 2, 3, 12, 28, 28, 28, 6684 }, - { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 27500, /* 27.0 Mb */ + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */ 25900, 0x81, 0x00, 1, 8, 4, 3, 13, 29, 29, 29, 13368 }, - { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 40500, /* 40.5 Mb */ + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */ 38600, 0x82, 0x00, 2, 8, 6, 3, 14, 30, 30, 30, 20052 }, - { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 54000, /* 54 Mb */ + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */ 49800, 0x83, 0x00, 3, 8, 10, 3, 15, 31, 31, 31, 26738 }, - { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 81500, /* 81 Mb */ + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */ 72200, 0x84, 0x00, 4, 8, 14, 3, 16, 32, 32, 32, 40104 }, - { FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 108000, /* 108 Mb */ + { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */ 92900, 0x85, 0x00, 5, 8, 20, 3, 17, 33, 33, 33, 53476 }, - { FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 121500, /* 121.5 Mb */ + { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */ 102700, 0x86, 0x00, 6, 8, 23, 3, 18, 34, 34, 34, 60156 }, - { FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 135000, /* 135 Mb */ + { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */ 112000, 0x87, 0x00, 7, 8, 23, 3, 19, 35, 36, 36, 66840 }, - { FALSE, TRUE_40, WLAN_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */ + { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */ 122000, 0x87, 0x00, 7, 8, 25, 3, 19, 35, 36, 36, 74200 }, - { FALSE, FALSE, WLAN_PHY_HT_40_DS, 27000, /* 27 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */ 25800, 0x88, 0x00, 8, 8, 2, 3, 20, 37, 37, 37, 13360 }, - { FALSE, FALSE, WLAN_PHY_HT_40_DS, 54000, /* 54 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */ 49800, 0x89, 0x00, 9, 8, 4, 3, 21, 38, 38, 38, 26720 }, - { FALSE, FALSE, WLAN_PHY_HT_40_DS, 81000, /* 81 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */ 71900, 0x8a, 0x00, 10, 8, 6, 3, 22, 39, 39, 39, 40080 }, - { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 108000, /* 108 Mb */ + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */ 92500, 0x8b, 0x00, 11, 8, 10, 3, 23, 40, 40, 40, 53440 }, - { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 162000, /* 162 Mb */ + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */ 130300, 0x8c, 0x00, 12, 8, 14, 3, 24, 41, 41, 41, 80160 }, - { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 216000, /* 216 Mb */ + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */ 162800, 0x8d, 0x00, 13, 8, 20, 3, 25, 42, 42, 42, 106880 }, - { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 243000, /* 243 Mb */ + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */ 178200, 0x8e, 0x00, 14, 8, 23, 3, 26, 43, 43, 43, 120240 }, - { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 270000, /* 270 Mb */ + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */ 192100, 0x8f, 0x00, 15, 8, 23, 3, 27, 44, 45, 45, 133600 }, - { TRUE_40, FALSE, WLAN_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */ + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */ 207000, 0x8f, 0x00, 15, 8, 25, 3, 27, 44, 45, 45, 148400 }, }, @@ -317,29 +306,30 @@ static struct ath_rate_table ar5416_11ng_ratetable = { static struct ath_rate_table ar5416_11a_ratetable = { 8, + {0}, { - { TRUE, TRUE, WLAN_PHY_OFDM, 6000, /* 6 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ 5400, 0x0b, 0x00, (0x80|12), 0, 2, 1, 0, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 9000, /* 9 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ 7800, 0x0f, 0x00, 18, 0, 3, 1, 1, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 12 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ 10000, 0x0a, 0x00, (0x80|24), 2, 4, 2, 2, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 18000, /* 18 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ 13900, 0x0e, 0x00, 36, 2, 6, 2, 3, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 24000, /* 24 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ 17300, 0x09, 0x00, (0x80|48), 4, 10, 3, 4, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 36000, /* 36 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ 23000, 0x0d, 0x00, 72, 4, 14, 3, 5, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 48000, /* 48 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ 27400, 0x08, 0x00, 96, 4, 19, 3, 6, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 54000, /* 54 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ 29300, 0x0c, 0x00, 108, 4, 23, 3, 7, 0 }, }, @@ -348,109 +338,44 @@ static struct ath_rate_table ar5416_11a_ratetable = { 0, /* Phy rates allowed initially */ }; -static struct ath_rate_table ar5416_11a_ratetable_Half = { - 8, - { - { TRUE, TRUE, WLAN_PHY_OFDM, 3000, /* 6 Mb */ - 2700, 0x0b, 0x00, (0x80|6), - 0, 2, 1, 0, 0}, - { TRUE, TRUE, WLAN_PHY_OFDM, 4500, /* 9 Mb */ - 3900, 0x0f, 0x00, 9, - 0, 3, 1, 1, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 6000, /* 12 Mb */ - 5000, 0x0a, 0x00, (0x80|12), - 2, 4, 2, 2, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 9000, /* 18 Mb */ - 6950, 0x0e, 0x00, 18, - 2, 6, 2, 3, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 24 Mb */ - 8650, 0x09, 0x00, (0x80|24), - 4, 10, 3, 4, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 18000, /* 36 Mb */ - 11500, 0x0d, 0x00, 36, - 4, 14, 3, 5, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 24000, /* 48 Mb */ - 13700, 0x08, 0x00, 48, - 4, 19, 3, 6, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 27000, /* 54 Mb */ - 14650, 0x0c, 0x00, 54, - 4, 23, 3, 7, 0 }, - }, - 50, /* probe interval */ - 50, /* rssi reduce interval */ - 0, /* Phy rates allowed initially */ -}; - -static struct ath_rate_table ar5416_11a_ratetable_Quarter = { - 8, - { - { TRUE, TRUE, WLAN_PHY_OFDM, 1500, /* 6 Mb */ - 1350, 0x0b, 0x00, (0x80|3), - 0, 2, 1, 0, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 2250, /* 9 Mb */ - 1950, 0x0f, 0x00, 4, - 0, 3, 1, 1, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 3000, /* 12 Mb */ - 2500, 0x0a, 0x00, (0x80|6), - 2, 4, 2, 2, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 4500, /* 18 Mb */ - 3475, 0x0e, 0x00, 9, - 2, 6, 2, 3, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 6000, /* 25 Mb */ - 4325, 0x09, 0x00, (0x80|12), - 4, 10, 3, 4, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 9000, /* 36 Mb */ - 5750, 0x0d, 0x00, 18, - 4, 14, 3, 5, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 48 Mb */ - 6850, 0x08, 0x00, 24, - 4, 19, 3, 6, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 13500, /* 54 Mb */ - 7325, 0x0c, 0x00, 27, - 4, 23, 3, 7, 0 }, - }, - 50, /* probe interval */ - 50, /* rssi reduce interval */ - 0, /* Phy rates allowed initially */ -}; - static struct ath_rate_table ar5416_11g_ratetable = { 12, + {0}, { - { TRUE, TRUE, WLAN_PHY_CCK, 1000, /* 1 Mb */ + { VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ 900, 0x1b, 0x00, 2, 0, 0, 1, 0, 0 }, - { TRUE, TRUE, WLAN_PHY_CCK, 2000, /* 2 Mb */ + { VALID, VALID, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */ 1900, 0x1a, 0x04, 4, 1, 1, 1, 1, 0 }, - { TRUE, TRUE, WLAN_PHY_CCK, 5500, /* 5.5 Mb */ + { VALID, VALID, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */ 4900, 0x19, 0x04, 11, 2, 2, 2, 2, 0 }, - { TRUE, TRUE, WLAN_PHY_CCK, 11000, /* 11 Mb */ + { VALID, VALID, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */ 8100, 0x18, 0x04, 22, 3, 3, 2, 3, 0 }, - { FALSE, FALSE, WLAN_PHY_OFDM, 6000, /* 6 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ 5400, 0x0b, 0x00, 12, 4, 2, 1, 4, 0 }, - { FALSE, FALSE, WLAN_PHY_OFDM, 9000, /* 9 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ 7800, 0x0f, 0x00, 18, 4, 3, 1, 5, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 12 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ 10000, 0x0a, 0x00, 24, 6, 4, 1, 6, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 18000, /* 18 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ 13900, 0x0e, 0x00, 36, 6, 6, 2, 7, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 24000, /* 24 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ 17300, 0x09, 0x00, 48, 8, 10, 3, 8, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 36000, /* 36 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ 23000, 0x0d, 0x00, 72, 8, 14, 3, 9, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 48000, /* 48 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ 27400, 0x08, 0x00, 96, 8, 19, 3, 10, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 54000, /* 54 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ 29300, 0x0c, 0x00, 108, 8, 23, 3, 11, 0 }, }, @@ -461,17 +386,18 @@ static struct ath_rate_table ar5416_11g_ratetable = { static struct ath_rate_table ar5416_11b_ratetable = { 4, + {0}, { - { TRUE, TRUE, WLAN_PHY_CCK, 1000, /* 1 Mb */ + { VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ 900, 0x1b, 0x00, (0x80|2), 0, 0, 1, 0, 0 }, - { TRUE, TRUE, WLAN_PHY_CCK, 2000, /* 2 Mb */ + { VALID, VALID, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */ 1800, 0x1a, 0x04, (0x80|4), 1, 1, 1, 1, 0 }, - { TRUE, TRUE, WLAN_PHY_CCK, 5500, /* 5.5 Mb */ + { VALID, VALID, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */ 4300, 0x19, 0x04, (0x80|11), 1, 2, 2, 2, 0 }, - { TRUE, TRUE, WLAN_PHY_CCK, 11000, /* 11 Mb */ + { VALID, VALID, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */ 7100, 0x18, 0x04, (0x80|22), 1, 4, 100, 3, 0 }, }, @@ -480,48 +406,6 @@ static struct ath_rate_table ar5416_11b_ratetable = { 0, /* Phy rates allowed initially */ }; -static void ar5416_attach_ratetables(struct ath_rate_softc *sc) -{ - /* - * Attach rate tables. - */ - sc->hw_rate_table[ATH9K_MODE_11B] = &ar5416_11b_ratetable; - sc->hw_rate_table[ATH9K_MODE_11A] = &ar5416_11a_ratetable; - sc->hw_rate_table[ATH9K_MODE_11G] = &ar5416_11g_ratetable; - - sc->hw_rate_table[ATH9K_MODE_11NA_HT20] = &ar5416_11na_ratetable; - sc->hw_rate_table[ATH9K_MODE_11NG_HT20] = &ar5416_11ng_ratetable; - sc->hw_rate_table[ATH9K_MODE_11NA_HT40PLUS] = - &ar5416_11na_ratetable; - sc->hw_rate_table[ATH9K_MODE_11NA_HT40MINUS] = - &ar5416_11na_ratetable; - sc->hw_rate_table[ATH9K_MODE_11NG_HT40PLUS] = - &ar5416_11ng_ratetable; - sc->hw_rate_table[ATH9K_MODE_11NG_HT40MINUS] = - &ar5416_11ng_ratetable; -} - -static void ar5416_setquarter_ratetable(struct ath_rate_softc *sc) -{ - sc->hw_rate_table[ATH9K_MODE_11A] = &ar5416_11a_ratetable_Quarter; - return; -} - -static void ar5416_sethalf_ratetable(struct ath_rate_softc *sc) -{ - sc->hw_rate_table[ATH9K_MODE_11A] = &ar5416_11a_ratetable_Half; - return; -} - -static void ar5416_setfull_ratetable(struct ath_rate_softc *sc) -{ - sc->hw_rate_table[ATH9K_MODE_11A] = &ar5416_11a_ratetable; - return; -} - -/* - * Return the median of three numbers - */ static inline int8_t median(int8_t a, int8_t b, int8_t c) { if (a >= b) { @@ -541,68 +425,65 @@ static inline int8_t median(int8_t a, int8_t b, int8_t c) } } -static void ath_rc_sort_validrates(const struct ath_rate_table *rate_table, - struct ath_tx_ratectrl *rate_ctrl) +static void ath_rc_sort_validrates(struct ath_rate_table *rate_table, + struct ath_rate_priv *ath_rc_priv) { u8 i, j, idx, idx_next; - for (i = rate_ctrl->max_valid_rate - 1; i > 0; i--) { + for (i = ath_rc_priv->max_valid_rate - 1; i > 0; i--) { for (j = 0; j <= i-1; j++) { - idx = rate_ctrl->valid_rate_index[j]; - idx_next = rate_ctrl->valid_rate_index[j+1]; + idx = ath_rc_priv->valid_rate_index[j]; + idx_next = ath_rc_priv->valid_rate_index[j+1]; if (rate_table->info[idx].ratekbps > rate_table->info[idx_next].ratekbps) { - rate_ctrl->valid_rate_index[j] = idx_next; - rate_ctrl->valid_rate_index[j+1] = idx; + ath_rc_priv->valid_rate_index[j] = idx_next; + ath_rc_priv->valid_rate_index[j+1] = idx; } } } } -/* Access functions for valid_txrate_mask */ - -static void ath_rc_init_valid_txmask(struct ath_tx_ratectrl *rate_ctrl) +static void ath_rc_init_valid_txmask(struct ath_rate_priv *ath_rc_priv) { u8 i; - for (i = 0; i < rate_ctrl->rate_table_size; i++) - rate_ctrl->valid_rate_index[i] = FALSE; + for (i = 0; i < ath_rc_priv->rate_table_size; i++) + ath_rc_priv->valid_rate_index[i] = 0; } -static inline void ath_rc_set_valid_txmask(struct ath_tx_ratectrl *rate_ctrl, +static inline void ath_rc_set_valid_txmask(struct ath_rate_priv *ath_rc_priv, u8 index, int valid_tx_rate) { - ASSERT(index <= rate_ctrl->rate_table_size); - rate_ctrl->valid_rate_index[index] = valid_tx_rate ? TRUE : FALSE; + ASSERT(index <= ath_rc_priv->rate_table_size); + ath_rc_priv->valid_rate_index[index] = valid_tx_rate ? 1 : 0; } -static inline int ath_rc_isvalid_txmask(struct ath_tx_ratectrl *rate_ctrl, +static inline int ath_rc_isvalid_txmask(struct ath_rate_priv *ath_rc_priv, u8 index) { - ASSERT(index <= rate_ctrl->rate_table_size); - return rate_ctrl->valid_rate_index[index]; + ASSERT(index <= ath_rc_priv->rate_table_size); + return ath_rc_priv->valid_rate_index[index]; } -/* Iterators for valid_txrate_mask */ -static inline int -ath_rc_get_nextvalid_txrate(const struct ath_rate_table *rate_table, - struct ath_tx_ratectrl *rate_ctrl, - u8 cur_valid_txrate, - u8 *next_idx) +static inline int ath_rc_get_nextvalid_txrate(struct ath_rate_table *rate_table, + struct ath_rate_priv *ath_rc_priv, + u8 cur_valid_txrate, + u8 *next_idx) { u8 i; - for (i = 0; i < rate_ctrl->max_valid_rate - 1; i++) { - if (rate_ctrl->valid_rate_index[i] == cur_valid_txrate) { - *next_idx = rate_ctrl->valid_rate_index[i+1]; - return TRUE; + for (i = 0; i < ath_rc_priv->max_valid_rate - 1; i++) { + if (ath_rc_priv->valid_rate_index[i] == cur_valid_txrate) { + *next_idx = ath_rc_priv->valid_rate_index[i+1]; + return 1; } } /* No more valid rates */ *next_idx = 0; - return FALSE; + + return 0; } /* Return true only for single stream */ @@ -610,83 +491,72 @@ ath_rc_get_nextvalid_txrate(const struct ath_rate_table *rate_table, static int ath_rc_valid_phyrate(u32 phy, u32 capflag, int ignore_cw) { if (WLAN_RC_PHY_HT(phy) & !(capflag & WLAN_RC_HT_FLAG)) - return FALSE; + return 0; if (WLAN_RC_PHY_DS(phy) && !(capflag & WLAN_RC_DS_FLAG)) - return FALSE; + return 0; if (WLAN_RC_PHY_SGI(phy) && !(capflag & WLAN_RC_SGI_FLAG)) - return FALSE; + return 0; if (!ignore_cw && WLAN_RC_PHY_HT(phy)) if (WLAN_RC_PHY_40(phy) && !(capflag & WLAN_RC_40_FLAG)) - return FALSE; + return 0; if (!WLAN_RC_PHY_40(phy) && (capflag & WLAN_RC_40_FLAG)) - return FALSE; - return TRUE; + return 0; + return 1; } static inline int -ath_rc_get_nextlowervalid_txrate(const struct ath_rate_table *rate_table, - struct ath_tx_ratectrl *rate_ctrl, +ath_rc_get_nextlowervalid_txrate(struct ath_rate_table *rate_table, + struct ath_rate_priv *ath_rc_priv, u8 cur_valid_txrate, u8 *next_idx) { int8_t i; - for (i = 1; i < rate_ctrl->max_valid_rate ; i++) { - if (rate_ctrl->valid_rate_index[i] == cur_valid_txrate) { - *next_idx = rate_ctrl->valid_rate_index[i-1]; - return TRUE; + for (i = 1; i < ath_rc_priv->max_valid_rate ; i++) { + if (ath_rc_priv->valid_rate_index[i] == cur_valid_txrate) { + *next_idx = ath_rc_priv->valid_rate_index[i-1]; + return 1; } } - return FALSE; + + return 0; } -/* - * Initialize the Valid Rate Index from valid entries in Rate Table - */ -static u8 -ath_rc_sib_init_validrates(struct ath_rate_node *ath_rc_priv, - const struct ath_rate_table *rate_table, - u32 capflag) +static u8 ath_rc_init_validrates(struct ath_rate_priv *ath_rc_priv, + struct ath_rate_table *rate_table, + u32 capflag) { - struct ath_tx_ratectrl *rate_ctrl; u8 i, hi = 0; u32 valid; - rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv); for (i = 0; i < rate_table->rate_cnt; i++) { valid = (ath_rc_priv->single_stream ? rate_table->info[i].valid_single_stream : rate_table->info[i].valid); - if (valid == TRUE) { + if (valid == 1) { u32 phy = rate_table->info[i].phy; u8 valid_rate_count = 0; - if (!ath_rc_valid_phyrate(phy, capflag, FALSE)) + if (!ath_rc_valid_phyrate(phy, capflag, 0)) continue; - valid_rate_count = rate_ctrl->valid_phy_ratecnt[phy]; + valid_rate_count = ath_rc_priv->valid_phy_ratecnt[phy]; - rate_ctrl->valid_phy_rateidx[phy][valid_rate_count] = i; - rate_ctrl->valid_phy_ratecnt[phy] += 1; - ath_rc_set_valid_txmask(rate_ctrl, i, TRUE); + ath_rc_priv->valid_phy_rateidx[phy][valid_rate_count] = i; + ath_rc_priv->valid_phy_ratecnt[phy] += 1; + ath_rc_set_valid_txmask(ath_rc_priv, i, 1); hi = A_MAX(hi, i); } } + return hi; } -/* - * Initialize the Valid Rate Index from Rate Set - */ -static u8 -ath_rc_sib_setvalid_rates(struct ath_rate_node *ath_rc_priv, - const struct ath_rate_table *rate_table, - struct ath_rateset *rateset, - u32 capflag) +static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv, + struct ath_rate_table *rate_table, + struct ath_rateset *rateset, + u32 capflag) { - /* XXX: Clean me up and make identation friendly */ u8 i, j, hi = 0; - struct ath_tx_ratectrl *rate_ctrl = - (struct ath_tx_ratectrl *)(ath_rc_priv); /* Use intersection of working rates and valid rates */ for (i = 0; i < rateset->rs_nrates; i++) { @@ -695,196 +565,89 @@ ath_rc_sib_setvalid_rates(struct ath_rate_node *ath_rc_priv, u32 valid = (ath_rc_priv->single_stream ? rate_table->info[j].valid_single_stream : rate_table->info[j].valid); + u8 rate = rateset->rs_rates[i]; + u8 dot11rate = rate_table->info[j].dot11rate; /* We allow a rate only if its valid and the * capflag matches one of the validity - * (TRUE/TRUE_20/TRUE_40) flags */ - - /* XXX: catch the negative of this branch - * first and then continue */ - if (((rateset->rs_rates[i] & 0x7F) == - (rate_table->info[j].dot11rate & 0x7F)) && - ((valid & WLAN_RC_CAP_MODE(capflag)) == - WLAN_RC_CAP_MODE(capflag)) && - !WLAN_RC_PHY_HT(phy)) { + * (VALID/VALID_20/VALID_40) flags */ + if (((rate & 0x7F) == (dot11rate & 0x7F)) && + ((valid & WLAN_RC_CAP_MODE(capflag)) == + WLAN_RC_CAP_MODE(capflag)) && + !WLAN_RC_PHY_HT(phy)) { u8 valid_rate_count = 0; - if (!ath_rc_valid_phyrate(phy, capflag, FALSE)) + if (!ath_rc_valid_phyrate(phy, capflag, 0)) continue; valid_rate_count = - rate_ctrl->valid_phy_ratecnt[phy]; + ath_rc_priv->valid_phy_ratecnt[phy]; - rate_ctrl->valid_phy_rateidx[phy] + ath_rc_priv->valid_phy_rateidx[phy] [valid_rate_count] = j; - rate_ctrl->valid_phy_ratecnt[phy] += 1; - ath_rc_set_valid_txmask(rate_ctrl, j, TRUE); + ath_rc_priv->valid_phy_ratecnt[phy] += 1; + ath_rc_set_valid_txmask(ath_rc_priv, j, 1); hi = A_MAX(hi, j); } } } + return hi; } -static u8 -ath_rc_sib_setvalid_htrates(struct ath_rate_node *ath_rc_priv, - const struct ath_rate_table *rate_table, - u8 *mcs_set, u32 capflag) +static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv, + struct ath_rate_table *rate_table, + u8 *mcs_set, u32 capflag) { + struct ath_rateset *rateset = (struct ath_rateset *)mcs_set; + u8 i, j, hi = 0; - struct ath_tx_ratectrl *rate_ctrl = - (struct ath_tx_ratectrl *)(ath_rc_priv); /* Use intersection of working rates and valid rates */ - for (i = 0; i < ((struct ath_rateset *)mcs_set)->rs_nrates; i++) { + for (i = 0; i < rateset->rs_nrates; i++) { for (j = 0; j < rate_table->rate_cnt; j++) { u32 phy = rate_table->info[j].phy; u32 valid = (ath_rc_priv->single_stream ? rate_table->info[j].valid_single_stream : rate_table->info[j].valid); + u8 rate = rateset->rs_rates[i]; + u8 dot11rate = rate_table->info[j].dot11rate; - if (((((struct ath_rateset *) - mcs_set)->rs_rates[i] & 0x7F) != - (rate_table->info[j].dot11rate & 0x7F)) || + if (((rate & 0x7F) != (dot11rate & 0x7F)) || !WLAN_RC_PHY_HT(phy) || !WLAN_RC_PHY_HT_VALID(valid, capflag)) continue; - if (!ath_rc_valid_phyrate(phy, capflag, FALSE)) + if (!ath_rc_valid_phyrate(phy, capflag, 0)) continue; - rate_ctrl->valid_phy_rateidx[phy] - [rate_ctrl->valid_phy_ratecnt[phy]] = j; - rate_ctrl->valid_phy_ratecnt[phy] += 1; - ath_rc_set_valid_txmask(rate_ctrl, j, TRUE); + ath_rc_priv->valid_phy_rateidx[phy] + [ath_rc_priv->valid_phy_ratecnt[phy]] = j; + ath_rc_priv->valid_phy_ratecnt[phy] += 1; + ath_rc_set_valid_txmask(ath_rc_priv, j, 1); hi = A_MAX(hi, j); } } - return hi; -} - -/* - * Attach to a device instance. Setup the public definition - * of how much per-node space we need and setup the private - * phy tables that have rate control parameters. - */ -struct ath_rate_softc *ath_rate_attach(struct ath_hal *ah) -{ - struct ath_rate_softc *asc; - - /* we are only in user context so we can sleep for memory */ - asc = kzalloc(sizeof(struct ath_rate_softc), GFP_KERNEL); - if (asc == NULL) - return NULL; - - ar5416_attach_ratetables(asc); - - /* Save Maximum TX Trigger Level (used for 11n) */ - tx_triglevel_max = ah->ah_caps.tx_triglevel_max; - /* return alias for ath_rate_softc * */ - return asc; -} - -static struct ath_rate_node *ath_rate_node_alloc(struct ath_vap *avp, - struct ath_rate_softc *rsc, - gfp_t gfp) -{ - struct ath_rate_node *anode; - - anode = kzalloc(sizeof(struct ath_rate_node), gfp); - if (anode == NULL) - return NULL; - - anode->avp = avp; - anode->asc = rsc; - avp->rc_node = anode; - - return anode; -} - -static void ath_rate_node_free(struct ath_rate_node *anode) -{ - if (anode != NULL) - kfree(anode); -} - -void ath_rate_detach(struct ath_rate_softc *asc) -{ - if (asc != NULL) - kfree(asc); -} - -u8 ath_rate_findrateix(struct ath_softc *sc, - u8 dot11rate) -{ - const struct ath_rate_table *ratetable; - struct ath_rate_softc *rsc = sc->sc_rc; - int i; - - ratetable = rsc->hw_rate_table[sc->sc_curmode]; - - if (WARN_ON(!ratetable)) - return 0; - - for (i = 0; i < ratetable->rate_cnt; i++) { - if ((ratetable->info[i].dot11rate & 0x7f) == (dot11rate & 0x7f)) - return i; - } - return 0; -} - -/* - * Update rate-control state on a device state change. When - * operating as a station this includes associate/reassociate - * with an AP. Otherwise this gets called, for example, when - * the we transition to run state when operating as an AP. - */ -void ath_rate_newstate(struct ath_softc *sc, struct ath_vap *avp) -{ - struct ath_rate_softc *asc = sc->sc_rc; - - /* For half and quarter rate channles use different - * rate tables - */ - if (sc->sc_ah->ah_curchan->channelFlags & CHANNEL_HALF) - ar5416_sethalf_ratetable(asc); - else if (sc->sc_ah->ah_curchan->channelFlags & CHANNEL_QUARTER) - ar5416_setquarter_ratetable(asc); - else /* full rate */ - ar5416_setfull_ratetable(asc); - - if (avp->av_config.av_fixed_rateset != IEEE80211_FIXED_RATE_NONE) { - asc->fixedrix = - sc->sc_rixmap[avp->av_config.av_fixed_rateset & 0xff]; - /* NB: check the fixed rate exists */ - if (asc->fixedrix == 0xff) - asc->fixedrix = IEEE80211_FIXED_RATE_NONE; - } else { - asc->fixedrix = IEEE80211_FIXED_RATE_NONE; - } + return hi; } static u8 ath_rc_ratefind_ht(struct ath_softc *sc, - struct ath_rate_node *ath_rc_priv, - const struct ath_rate_table *rate_table, + struct ath_rate_priv *ath_rc_priv, + struct ath_rate_table *rate_table, int probe_allowed, int *is_probing, int is_retry) { u32 dt, best_thruput, this_thruput, now_msec; u8 rate, next_rate, best_rate, maxindex, minindex; int8_t rssi_last, rssi_reduce = 0, index = 0; - struct ath_tx_ratectrl *rate_ctrl = NULL; - - rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv ? - (ath_rc_priv) : NULL); - *is_probing = FALSE; + *is_probing = 0; - rssi_last = median(rate_ctrl->rssi_last, - rate_ctrl->rssi_last_prev, - rate_ctrl->rssi_last_prev2); + rssi_last = median(ath_rc_priv->rssi_last, + ath_rc_priv->rssi_last_prev, + ath_rc_priv->rssi_last_prev2); /* * Age (reduce) last ack rssi based on how old it is. @@ -896,7 +659,7 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc, */ now_msec = jiffies_to_msecs(jiffies); - dt = now_msec - rate_ctrl->rssi_time; + dt = now_msec - ath_rc_priv->rssi_time; if (dt >= 185) rssi_reduce = 10; @@ -915,7 +678,7 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc, */ best_thruput = 0; - maxindex = rate_ctrl->max_valid_rate-1; + maxindex = ath_rc_priv->max_valid_rate-1; minindex = 0; best_rate = minindex; @@ -927,8 +690,8 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc, for (index = maxindex; index >= minindex ; index--) { u8 per_thres; - rate = rate_ctrl->valid_rate_index[index]; - if (rate > rate_ctrl->rate_max_phy) + rate = ath_rc_priv->valid_rate_index[index]; + if (rate > ath_rc_priv->rate_max_phy) continue; /* @@ -942,7 +705,7 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc, * 10-15 and we would be worse off then staying * at the current rate. */ - per_thres = rate_ctrl->state[rate].per; + per_thres = ath_rc_priv->state[rate].per; if (per_thres < 12) per_thres = 12; @@ -961,41 +724,35 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc, * of max retries, use the min rate for the next retry */ if (is_retry) - rate = rate_ctrl->valid_rate_index[minindex]; + rate = ath_rc_priv->valid_rate_index[minindex]; - rate_ctrl->rssi_last_lookup = rssi_last; + ath_rc_priv->rssi_last_lookup = rssi_last; /* * Must check the actual rate (ratekbps) to account for * non-monoticity of 11g's rate table */ - if (rate >= rate_ctrl->rate_max_phy && probe_allowed) { - rate = rate_ctrl->rate_max_phy; + if (rate >= ath_rc_priv->rate_max_phy && probe_allowed) { + rate = ath_rc_priv->rate_max_phy; /* Probe the next allowed phy state */ /* FIXME:XXXX Check to make sure ratMax is checked properly */ if (ath_rc_get_nextvalid_txrate(rate_table, - rate_ctrl, rate, &next_rate) && - (now_msec - rate_ctrl->probe_time > + ath_rc_priv, rate, &next_rate) && + (now_msec - ath_rc_priv->probe_time > rate_table->probe_interval) && - (rate_ctrl->hw_maxretry_pktcnt >= 1)) { + (ath_rc_priv->hw_maxretry_pktcnt >= 1)) { rate = next_rate; - rate_ctrl->probe_rate = rate; - rate_ctrl->probe_time = now_msec; - rate_ctrl->hw_maxretry_pktcnt = 0; - *is_probing = TRUE; + ath_rc_priv->probe_rate = rate; + ath_rc_priv->probe_time = now_msec; + ath_rc_priv->hw_maxretry_pktcnt = 0; + *is_probing = 1; } } - /* - * Make sure rate is not higher than the allowed maximum. - * We should also enforce the min, but I suspect the min is - * normally 1 rather than 0 because of the rate 9 vs 6 issue - * in the old code. - */ - if (rate > (rate_ctrl->rate_table_size - 1)) - rate = rate_ctrl->rate_table_size - 1; + if (rate > (ath_rc_priv->rate_table_size - 1)) + rate = ath_rc_priv->rate_table_size - 1; ASSERT((rate_table->info[rate].valid && !ath_rc_priv->single_stream) || (rate_table->info[rate].valid_single_stream && @@ -1004,40 +761,36 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc, return rate; } -static void ath_rc_rate_set_series(const struct ath_rate_table *rate_table , - struct ath_rc_series *series, - u8 tries, - u8 rix, - int rtsctsenable) +static void ath_rc_rate_set_series(struct ath_rate_table *rate_table , + struct ieee80211_tx_rate *rate, + u8 tries, u8 rix, int rtsctsenable) { - series->tries = tries; - series->flags = (rtsctsenable ? ATH_RC_RTSCTS_FLAG : 0) | - (WLAN_RC_PHY_DS(rate_table->info[rix].phy) ? - ATH_RC_DS_FLAG : 0) | - (WLAN_RC_PHY_40(rate_table->info[rix].phy) ? - ATH_RC_CW40_FLAG : 0) | - (WLAN_RC_PHY_SGI(rate_table->info[rix].phy) ? - ATH_RC_SGI_FLAG : 0); - - series->rix = rate_table->info[rix].base_index; - series->max_4ms_framelen = rate_table->info[rix].max_4ms_framelen; + rate->count = tries; + rate->idx = rix; + + if (rtsctsenable) + rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS; + if (WLAN_RC_PHY_40(rate_table->info[rix].phy)) + rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; + if (WLAN_RC_PHY_SGI(rate_table->info[rix].phy)) + rate->flags |= IEEE80211_TX_RC_SHORT_GI; + if (WLAN_RC_PHY_HT(rate_table->info[rix].phy)) + rate->flags |= IEEE80211_TX_RC_MCS; } static u8 ath_rc_rate_getidx(struct ath_softc *sc, - struct ath_rate_node *ath_rc_priv, - const struct ath_rate_table *rate_table, + struct ath_rate_priv *ath_rc_priv, + struct ath_rate_table *rate_table, u8 rix, u16 stepdown, u16 min_rate) { u32 j; u8 nextindex; - struct ath_tx_ratectrl *rate_ctrl = - (struct ath_tx_ratectrl *)(ath_rc_priv); if (min_rate) { for (j = RATE_TABLE_SIZE; j > 0; j--) { if (ath_rc_get_nextlowervalid_txrate(rate_table, - rate_ctrl, rix, &nextindex)) + ath_rc_priv, rix, &nextindex)) rix = nextindex; else break; @@ -1045,7 +798,7 @@ static u8 ath_rc_rate_getidx(struct ath_softc *sc, } else { for (j = stepdown; j > 0; j--) { if (ath_rc_get_nextlowervalid_txrate(rate_table, - rate_ctrl, rix, &nextindex)) + ath_rc_priv, rix, &nextindex)) rix = nextindex; else break; @@ -1055,41 +808,39 @@ static u8 ath_rc_rate_getidx(struct ath_softc *sc, } static void ath_rc_ratefind(struct ath_softc *sc, - struct ath_rate_node *ath_rc_priv, - int num_tries, int num_rates, unsigned int rcflag, - struct ath_rc_series series[], int *is_probe, + struct ath_rate_priv *ath_rc_priv, + int num_tries, int num_rates, + struct ieee80211_tx_info *tx_info, int *is_probe, int is_retry) { u8 try_per_rate = 0, i = 0, rix, nrix; - struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc; struct ath_rate_table *rate_table; + struct ieee80211_tx_rate *rates = tx_info->control.rates; - rate_table = - (struct ath_rate_table *)asc->hw_rate_table[sc->sc_curmode]; - rix = ath_rc_ratefind_ht(sc, ath_rc_priv, rate_table, - (rcflag & ATH_RC_PROBE_ALLOWED) ? 1 : 0, + rate_table = sc->cur_rate_table; + rix = ath_rc_ratefind_ht(sc, ath_rc_priv, rate_table, 1, is_probe, is_retry); nrix = rix; - if ((rcflag & ATH_RC_PROBE_ALLOWED) && (*is_probe)) { + if (*is_probe) { /* set one try for probe rates. For the * probes don't enable rts */ ath_rc_rate_set_series(rate_table, - &series[i++], 1, nrix, FALSE); + &rates[i++], 1, nrix, 0); try_per_rate = (num_tries/num_rates); /* Get the next tried/allowed rate. No RTS for the next series * after the probe rate */ nrix = ath_rc_rate_getidx(sc, - ath_rc_priv, rate_table, nrix, 1, FALSE); + ath_rc_priv, rate_table, nrix, 1, 0); ath_rc_rate_set_series(rate_table, - &series[i++], try_per_rate, nrix, 0); + &rates[i++], try_per_rate, nrix, 0); } else { try_per_rate = (num_tries/num_rates); /* Set the choosen rate. No RTS for first series entry. */ ath_rc_rate_set_series(rate_table, - &series[i++], try_per_rate, nrix, FALSE); + &rates[i++], try_per_rate, nrix, 0); } /* Fill in the other rates for multirate retry */ @@ -1099,14 +850,13 @@ static void ath_rc_ratefind(struct ath_softc *sc, try_num = ((i + 1) == num_rates) ? num_tries - (try_per_rate * i) : try_per_rate ; - min_rate = (((i + 1) == num_rates) && - (rcflag & ATH_RC_MINRATE_LASTRATE)) ? 1 : 0; + min_rate = (((i + 1) == num_rates) && 0); nrix = ath_rc_rate_getidx(sc, ath_rc_priv, rate_table, nrix, 1, min_rate); /* All other rates in the series have RTS enabled */ ath_rc_rate_set_series(rate_table, - &series[i], try_num, nrix, TRUE); + &rates[i], try_num, nrix, 1); } /* @@ -1124,115 +874,29 @@ static void ath_rc_ratefind(struct ath_softc *sc, * So, set fourth rate in series to be same as third one for * above conditions. */ - if ((sc->sc_curmode == ATH9K_MODE_11NG_HT20) || - (sc->sc_curmode == ATH9K_MODE_11NG_HT40PLUS) || - (sc->sc_curmode == ATH9K_MODE_11NG_HT40MINUS)) { - u8 dot11rate = rate_table->info[rix].dot11rate; + if ((sc->hw->conf.channel->band == IEEE80211_BAND_2GHZ) && + (sc->hw->conf.ht.enabled)) { + u8 dot11rate = rate_table->info[rix].dot11rate; u8 phy = rate_table->info[rix].phy; if (i == 4 && ((dot11rate == 2 && phy == WLAN_RC_PHY_HT_40_SS) || (dot11rate == 3 && phy == WLAN_RC_PHY_HT_20_SS))) { - series[3].rix = series[2].rix; - series[3].flags = series[2].flags; - series[3].max_4ms_framelen = series[2].max_4ms_framelen; - } - } -} - -/* - * Return the Tx rate series. - */ -static void ath_rate_findrate(struct ath_softc *sc, - struct ath_rate_node *ath_rc_priv, - int num_tries, - int num_rates, - unsigned int rcflag, - struct ath_rc_series series[], - int *is_probe, - int is_retry) -{ - struct ath_vap *avp = ath_rc_priv->avp; - - DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); - - if (!num_rates || !num_tries) - return; - - if (avp->av_config.av_fixed_rateset == IEEE80211_FIXED_RATE_NONE) { - ath_rc_ratefind(sc, ath_rc_priv, num_tries, num_rates, - rcflag, series, is_probe, is_retry); - } else { - /* Fixed rate */ - int idx; - u8 flags; - u32 rix; - struct ath_rate_softc *asc = ath_rc_priv->asc; - struct ath_rate_table *rate_table; - - rate_table = (struct ath_rate_table *) - asc->hw_rate_table[sc->sc_curmode]; - - for (idx = 0; idx < 4; idx++) { - unsigned int mcs; - u8 series_rix = 0; - - series[idx].tries = IEEE80211_RATE_IDX_ENTRY( - avp->av_config.av_fixed_retryset, idx); - - mcs = IEEE80211_RATE_IDX_ENTRY( - avp->av_config.av_fixed_rateset, idx); - - if (idx == 3 && (mcs & 0xf0) == 0x70) - mcs = (mcs & ~0xf0)|0x80; - - if (!(mcs & 0x80)) - flags = 0; - else - flags = ((ath_rc_priv->ht_cap & - WLAN_RC_DS_FLAG) ? - ATH_RC_DS_FLAG : 0) | - ((ath_rc_priv->ht_cap & - WLAN_RC_40_FLAG) ? - ATH_RC_CW40_FLAG : 0) | - ((ath_rc_priv->ht_cap & - WLAN_RC_SGI_FLAG) ? - ((ath_rc_priv->ht_cap & - WLAN_RC_40_FLAG) ? - ATH_RC_SGI_FLAG : 0) : 0); - - series[idx].rix = sc->sc_rixmap[mcs]; - series_rix = series[idx].rix; - - /* XXX: Give me some cleanup love */ - if ((flags & ATH_RC_CW40_FLAG) && - (flags & ATH_RC_SGI_FLAG)) - rix = rate_table->info[series_rix].ht_index; - else if (flags & ATH_RC_SGI_FLAG) - rix = rate_table->info[series_rix].sgi_index; - else if (flags & ATH_RC_CW40_FLAG) - rix = rate_table->info[series_rix].cw40index; - else - rix = rate_table->info[series_rix].base_index; - series[idx].max_4ms_framelen = - rate_table->info[rix].max_4ms_framelen; - series[idx].flags = flags; + rates[3].idx = rates[2].idx; + rates[3].flags = rates[2].flags; } } } -static void ath_rc_update_ht(struct ath_softc *sc, - struct ath_rate_node *ath_rc_priv, - struct ath_tx_info_priv *info_priv, - int tx_rate, int xretries, int retries) +static bool ath_rc_update_per(struct ath_softc *sc, + struct ath_rate_table *rate_table, + struct ath_rate_priv *ath_rc_priv, + struct ath_tx_info_priv *tx_info_priv, + int tx_rate, int xretries, int retries, + u32 now_msec) { - struct ath_tx_ratectrl *rate_ctrl; - u32 now_msec = jiffies_to_msecs(jiffies); - int state_change = FALSE, rate, count; + bool state_change = false; + int count; u8 last_per; - struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc; - struct ath_rate_table *rate_table = - (struct ath_rate_table *)asc->hw_rate_table[sc->sc_curmode]; - static u32 nretry_to_per_lookup[10] = { 100 * 0 / 1, 100 * 1 / 4, @@ -1246,56 +910,35 @@ static void ath_rc_update_ht(struct ath_softc *sc, 100 * 9 / 10 }; - if (!ath_rc_priv) - return; - - rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv); - - ASSERT(tx_rate >= 0); - if (tx_rate < 0) - return; - - /* To compensate for some imbalance between ctrl and ext. channel */ - - if (WLAN_RC_PHY_40(rate_table->info[tx_rate].phy)) - info_priv->tx.ts_rssi = - info_priv->tx.ts_rssi < 3 ? 0 : - info_priv->tx.ts_rssi - 3; - - last_per = rate_ctrl->state[tx_rate].per; + last_per = ath_rc_priv->state[tx_rate].per; if (xretries) { - /* Update the PER. */ if (xretries == 1) { - rate_ctrl->state[tx_rate].per += 30; - if (rate_ctrl->state[tx_rate].per > 100) - rate_ctrl->state[tx_rate].per = 100; + ath_rc_priv->state[tx_rate].per += 30; + if (ath_rc_priv->state[tx_rate].per > 100) + ath_rc_priv->state[tx_rate].per = 100; } else { /* xretries == 2 */ - count = sizeof(nretry_to_per_lookup) / - sizeof(nretry_to_per_lookup[0]); + count = ARRAY_SIZE(nretry_to_per_lookup); if (retries >= count) retries = count - 1; + /* new_PER = 7/8*old_PER + 1/8*(currentPER) */ - rate_ctrl->state[tx_rate].per = - (u8)(rate_ctrl->state[tx_rate].per - - (rate_ctrl->state[tx_rate].per >> 3) + - ((100) >> 3)); + ath_rc_priv->state[tx_rate].per = + (u8)(last_per - (last_per >> 3) + (100 >> 3)); } /* xretries == 1 or 2 */ - if (rate_ctrl->probe_rate == tx_rate) - rate_ctrl->probe_rate = 0; + if (ath_rc_priv->probe_rate == tx_rate) + ath_rc_priv->probe_rate = 0; - } else { /* xretries == 0 */ - /* Update the PER. */ - /* Make sure it doesn't index out of array's bounds. */ - count = sizeof(nretry_to_per_lookup) / - sizeof(nretry_to_per_lookup[0]); + } else { /* xretries == 0 */ + count = ARRAY_SIZE(nretry_to_per_lookup); if (retries >= count) retries = count - 1; - if (info_priv->n_bad_frames) { + + if (tx_info_priv->n_bad_frames) { /* new_PER = 7/8*old_PER + 1/8*(currentPER) * Assuming that n_frames is not 0. The current PER * from the retries is 100 * retries / (retries+1), @@ -1308,37 +951,35 @@ static void ath_rc_update_ht(struct ath_softc *sc, * the above PER. The expression below is a * simplified version of the sum of these two terms. */ - if (info_priv->n_frames > 0) - rate_ctrl->state[tx_rate].per - = (u8) - (rate_ctrl->state[tx_rate].per - - (rate_ctrl->state[tx_rate].per >> 3) + - ((100*(retries*info_priv->n_frames + - info_priv->n_bad_frames) / - (info_priv->n_frames * - (retries+1))) >> 3)); + if (tx_info_priv->n_frames > 0) { + int n_frames, n_bad_frames; + u8 cur_per, new_per; + + n_bad_frames = retries * tx_info_priv->n_frames + + tx_info_priv->n_bad_frames; + n_frames = tx_info_priv->n_frames * (retries + 1); + cur_per = (100 * n_bad_frames / n_frames) >> 3; + new_per = (u8)(last_per - (last_per >> 3) + cur_per); + ath_rc_priv->state[tx_rate].per = new_per; + } } else { - /* new_PER = 7/8*old_PER + 1/8*(currentPER) */ - - rate_ctrl->state[tx_rate].per = (u8) - (rate_ctrl->state[tx_rate].per - - (rate_ctrl->state[tx_rate].per >> 3) + - (nretry_to_per_lookup[retries] >> 3)); + ath_rc_priv->state[tx_rate].per = + (u8)(last_per - (last_per >> 3) + + (nretry_to_per_lookup[retries] >> 3)); } - rate_ctrl->rssi_last_prev2 = rate_ctrl->rssi_last_prev; - rate_ctrl->rssi_last_prev = rate_ctrl->rssi_last; - rate_ctrl->rssi_last = info_priv->tx.ts_rssi; - rate_ctrl->rssi_time = now_msec; + ath_rc_priv->rssi_last_prev2 = ath_rc_priv->rssi_last_prev; + ath_rc_priv->rssi_last_prev = ath_rc_priv->rssi_last; + ath_rc_priv->rssi_last = tx_info_priv->tx.ts_rssi; + ath_rc_priv->rssi_time = now_msec; /* * If we got at most one retry then increase the max rate if * this was a probe. Otherwise, ignore the probe. */ - - if (rate_ctrl->probe_rate && rate_ctrl->probe_rate == tx_rate) { - if (retries > 0 || 2 * info_priv->n_bad_frames > - info_priv->n_frames) { + if (ath_rc_priv->probe_rate && ath_rc_priv->probe_rate == tx_rate) { + if (retries > 0 || 2 * tx_info_priv->n_bad_frames > + tx_info_priv->n_frames) { /* * Since we probed with just a single attempt, * any retries means the probe failed. Also, @@ -1346,17 +987,18 @@ static void ath_rc_update_ht(struct ath_softc *sc, * the subframes were bad then also consider * the probe a failure. */ - rate_ctrl->probe_rate = 0; + ath_rc_priv->probe_rate = 0; } else { u8 probe_rate = 0; - rate_ctrl->rate_max_phy = rate_ctrl->probe_rate; - probe_rate = rate_ctrl->probe_rate; + ath_rc_priv->rate_max_phy = + ath_rc_priv->probe_rate; + probe_rate = ath_rc_priv->probe_rate; - if (rate_ctrl->state[probe_rate].per > 30) - rate_ctrl->state[probe_rate].per = 20; + if (ath_rc_priv->state[probe_rate].per > 30) + ath_rc_priv->state[probe_rate].per = 20; - rate_ctrl->probe_rate = 0; + ath_rc_priv->probe_rate = 0; /* * Since this probe succeeded, we allow the next @@ -1364,8 +1006,8 @@ static void ath_rc_update_ht(struct ath_softc *sc, * to move up faster if the probes are * succesful. */ - rate_ctrl->probe_time = now_msec - - rate_table->probe_interval / 2; + ath_rc_priv->probe_time = + now_msec - rate_table->probe_interval / 2; } } @@ -1375,74 +1017,114 @@ static void ath_rc_update_ht(struct ath_softc *sc, * this was because of collisions or poor signal. * * Later: if rssi_ack is close to - * rate_ctrl->state[txRate].rssi_thres and we see lots + * ath_rc_priv->state[txRate].rssi_thres and we see lots * of retries, then we could increase - * rate_ctrl->state[txRate].rssi_thres. + * ath_rc_priv->state[txRate].rssi_thres. */ - rate_ctrl->hw_maxretry_pktcnt = 0; + ath_rc_priv->hw_maxretry_pktcnt = 0; } else { + int32_t rssi_ackAvg; + int8_t rssi_thres; + int8_t rssi_ack_vmin; + /* * It worked with no retries. First ignore bogus (small) * rssi_ack values. */ - if (tx_rate == rate_ctrl->rate_max_phy && - rate_ctrl->hw_maxretry_pktcnt < 255) { - rate_ctrl->hw_maxretry_pktcnt++; + if (tx_rate == ath_rc_priv->rate_max_phy && + ath_rc_priv->hw_maxretry_pktcnt < 255) { + ath_rc_priv->hw_maxretry_pktcnt++; } - if (info_priv->tx.ts_rssi >= - rate_table->info[tx_rate].rssi_ack_validmin) { - /* Average the rssi */ - if (tx_rate != rate_ctrl->rssi_sum_rate) { - rate_ctrl->rssi_sum_rate = tx_rate; - rate_ctrl->rssi_sum = - rate_ctrl->rssi_sum_cnt = 0; - } + if (tx_info_priv->tx.ts_rssi < + rate_table->info[tx_rate].rssi_ack_validmin) + goto exit; - rate_ctrl->rssi_sum += info_priv->tx.ts_rssi; - rate_ctrl->rssi_sum_cnt++; - - if (rate_ctrl->rssi_sum_cnt > 4) { - int32_t rssi_ackAvg = - (rate_ctrl->rssi_sum + 2) / 4; - int8_t rssi_thres = - rate_ctrl->state[tx_rate]. - rssi_thres; - int8_t rssi_ack_vmin = - rate_table->info[tx_rate]. - rssi_ack_validmin; - - rate_ctrl->rssi_sum = - rate_ctrl->rssi_sum_cnt = 0; - - /* Now reduce the current - * rssi threshold. */ - if ((rssi_ackAvg < rssi_thres + 2) && - (rssi_thres > rssi_ack_vmin)) { - rate_ctrl->state[tx_rate]. - rssi_thres--; - } - - state_change = TRUE; - } + /* Average the rssi */ + if (tx_rate != ath_rc_priv->rssi_sum_rate) { + ath_rc_priv->rssi_sum_rate = tx_rate; + ath_rc_priv->rssi_sum = + ath_rc_priv->rssi_sum_cnt = 0; } + + ath_rc_priv->rssi_sum += tx_info_priv->tx.ts_rssi; + ath_rc_priv->rssi_sum_cnt++; + + if (ath_rc_priv->rssi_sum_cnt < 4) + goto exit; + + rssi_ackAvg = + (ath_rc_priv->rssi_sum + 2) / 4; + rssi_thres = + ath_rc_priv->state[tx_rate].rssi_thres; + rssi_ack_vmin = + rate_table->info[tx_rate].rssi_ack_validmin; + + ath_rc_priv->rssi_sum = + ath_rc_priv->rssi_sum_cnt = 0; + + /* Now reduce the current rssi threshold */ + if ((rssi_ackAvg < rssi_thres + 2) && + (rssi_thres > rssi_ack_vmin)) { + ath_rc_priv->state[tx_rate].rssi_thres--; + } + + state_change = true; } } +exit: + return state_change; +} + +/* Update PER, RSSI and whatever else that the code thinks it is doing. + If you can make sense of all this, you really need to go out more. */ + +static void ath_rc_update_ht(struct ath_softc *sc, + struct ath_rate_priv *ath_rc_priv, + struct ath_tx_info_priv *tx_info_priv, + int tx_rate, int xretries, int retries) +{ +#define CHK_RSSI(rate) \ + ((ath_rc_priv->state[(rate)].rssi_thres + \ + rate_table->info[(rate)].rssi_ack_deltamin) > \ + ath_rc_priv->state[(rate)+1].rssi_thres) - /* For all cases */ + u32 now_msec = jiffies_to_msecs(jiffies); + int rate; + u8 last_per; + bool state_change = false; + struct ath_rate_table *rate_table = sc->cur_rate_table; + int size = ath_rc_priv->rate_table_size; + + if ((tx_rate < 0) || (tx_rate > rate_table->rate_cnt)) + return; + + /* To compensate for some imbalance between ctrl and ext. channel */ + + if (WLAN_RC_PHY_40(rate_table->info[tx_rate].phy)) + tx_info_priv->tx.ts_rssi = + tx_info_priv->tx.ts_rssi < 3 ? 0 : + tx_info_priv->tx.ts_rssi - 3; + + last_per = ath_rc_priv->state[tx_rate].per; + + /* Update PER first */ + state_change = ath_rc_update_per(sc, rate_table, ath_rc_priv, + tx_info_priv, tx_rate, xretries, + retries, now_msec); /* * If this rate looks bad (high PER) then stop using it for * a while (except if we are probing). */ - if (rate_ctrl->state[tx_rate].per >= 55 && tx_rate > 0 && + if (ath_rc_priv->state[tx_rate].per >= 55 && tx_rate > 0 && rate_table->info[tx_rate].ratekbps <= - rate_table->info[rate_ctrl->rate_max_phy].ratekbps) { - ath_rc_get_nextlowervalid_txrate(rate_table, rate_ctrl, - (u8) tx_rate, &rate_ctrl->rate_max_phy); + rate_table->info[ath_rc_priv->rate_max_phy].ratekbps) { + ath_rc_get_nextlowervalid_txrate(rate_table, ath_rc_priv, + (u8)tx_rate, &ath_rc_priv->rate_max_phy); /* Don't probe for a little while. */ - rate_ctrl->probe_time = now_msec; + ath_rc_priv->probe_time = now_msec; } if (state_change) { @@ -1453,20 +1135,15 @@ static void ath_rc_update_ht(struct ath_softc *sc, * made to keep the rssi thresholds monotonically * increasing between the CCK and OFDM rates.) */ - for (rate = tx_rate; rate < - rate_ctrl->rate_table_size - 1; rate++) { + for (rate = tx_rate; rate < size - 1; rate++) { if (rate_table->info[rate+1].phy != - rate_table->info[tx_rate].phy) + rate_table->info[tx_rate].phy) break; - if (rate_ctrl->state[rate].rssi_thres + - rate_table->info[rate].rssi_ack_deltamin > - rate_ctrl->state[rate+1].rssi_thres) { - rate_ctrl->state[rate+1].rssi_thres = - rate_ctrl->state[rate]. - rssi_thres + - rate_table->info[rate]. - rssi_ack_deltamin; + if (CHK_RSSI(rate)) { + ath_rc_priv->state[rate+1].rssi_thres = + ath_rc_priv->state[rate].rssi_thres + + rate_table->info[rate].rssi_ack_deltamin; } } @@ -1476,27 +1153,20 @@ static void ath_rc_update_ht(struct ath_softc *sc, rate_table->info[tx_rate].phy) break; - if (rate_ctrl->state[rate].rssi_thres + - rate_table->info[rate].rssi_ack_deltamin > - rate_ctrl->state[rate+1].rssi_thres) { - if (rate_ctrl->state[rate+1].rssi_thres < - rate_table->info[rate]. - rssi_ack_deltamin) - rate_ctrl->state[rate].rssi_thres = 0; + if (CHK_RSSI(rate)) { + if (ath_rc_priv->state[rate+1].rssi_thres < + rate_table->info[rate].rssi_ack_deltamin) + ath_rc_priv->state[rate].rssi_thres = 0; else { - rate_ctrl->state[rate].rssi_thres = - rate_ctrl->state[rate+1]. - rssi_thres - - rate_table->info[rate]. - rssi_ack_deltamin; + ath_rc_priv->state[rate].rssi_thres = + ath_rc_priv->state[rate+1].rssi_thres - + rate_table->info[rate].rssi_ack_deltamin; } - if (rate_ctrl->state[rate].rssi_thres < - rate_table->info[rate]. - rssi_ack_validmin) { - rate_ctrl->state[rate].rssi_thres = - rate_table->info[rate]. - rssi_ack_validmin; + if (ath_rc_priv->state[rate].rssi_thres < + rate_table->info[rate].rssi_ack_validmin) { + ath_rc_priv->state[rate].rssi_thres = + rate_table->info[rate].rssi_ack_validmin; } } } @@ -1504,74 +1174,86 @@ static void ath_rc_update_ht(struct ath_softc *sc, /* Make sure the rates below this have lower PER */ /* Monotonicity is kept only for rates below the current rate. */ - if (rate_ctrl->state[tx_rate].per < last_per) { + if (ath_rc_priv->state[tx_rate].per < last_per) { for (rate = tx_rate - 1; rate >= 0; rate--) { if (rate_table->info[rate].phy != rate_table->info[tx_rate].phy) break; - if (rate_ctrl->state[rate].per > - rate_ctrl->state[rate+1].per) { - rate_ctrl->state[rate].per = - rate_ctrl->state[rate+1].per; + if (ath_rc_priv->state[rate].per > + ath_rc_priv->state[rate+1].per) { + ath_rc_priv->state[rate].per = + ath_rc_priv->state[rate+1].per; } } } /* Maintain monotonicity for rates above the current rate */ - for (rate = tx_rate; rate < rate_ctrl->rate_table_size - 1; rate++) { - if (rate_ctrl->state[rate+1].per < rate_ctrl->state[rate].per) - rate_ctrl->state[rate+1].per = - rate_ctrl->state[rate].per; + for (rate = tx_rate; rate < size - 1; rate++) { + if (ath_rc_priv->state[rate+1].per < + ath_rc_priv->state[rate].per) + ath_rc_priv->state[rate+1].per = + ath_rc_priv->state[rate].per; } /* Every so often, we reduce the thresholds and * PER (different for CCK and OFDM). */ - if (now_msec - rate_ctrl->rssi_down_time >= + if (now_msec - ath_rc_priv->rssi_down_time >= rate_table->rssi_reduce_interval) { - for (rate = 0; rate < rate_ctrl->rate_table_size; rate++) { - if (rate_ctrl->state[rate].rssi_thres > + for (rate = 0; rate < size; rate++) { + if (ath_rc_priv->state[rate].rssi_thres > rate_table->info[rate].rssi_ack_validmin) - rate_ctrl->state[rate].rssi_thres -= 1; + ath_rc_priv->state[rate].rssi_thres -= 1; } - rate_ctrl->rssi_down_time = now_msec; + ath_rc_priv->rssi_down_time = now_msec; } /* Every so often, we reduce the thresholds * and PER (different for CCK and OFDM). */ - if (now_msec - rate_ctrl->per_down_time >= + if (now_msec - ath_rc_priv->per_down_time >= rate_table->rssi_reduce_interval) { - for (rate = 0; rate < rate_ctrl->rate_table_size; rate++) { - rate_ctrl->state[rate].per = - 7 * rate_ctrl->state[rate].per / 8; + for (rate = 0; rate < size; rate++) { + ath_rc_priv->state[rate].per = + 7 * ath_rc_priv->state[rate].per / 8; } - rate_ctrl->per_down_time = now_msec; + ath_rc_priv->per_down_time = now_msec; } + +#undef CHK_RSSI } -/* - * This routine is called in rate control callback tx_status() to give - * the status of previous frames. - */ -static void ath_rc_update(struct ath_softc *sc, - struct ath_rate_node *ath_rc_priv, - struct ath_tx_info_priv *info_priv, int final_ts_idx, - int xretries, int long_retry) +static int ath_rc_get_rateindex(struct ath_rate_table *rate_table, + struct ieee80211_tx_rate *rate) { - struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc; + int rix; + + if ((rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && + (rate->flags & IEEE80211_TX_RC_SHORT_GI)) + rix = rate_table->info[rate->idx].ht_index; + else if (rate->flags & IEEE80211_TX_RC_SHORT_GI) + rix = rate_table->info[rate->idx].sgi_index; + else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + rix = rate_table->info[rate->idx].cw40index; + else + rix = rate_table->info[rate->idx].base_index; + + return rix; +} + +static void ath_rc_tx_status(struct ath_softc *sc, + struct ath_rate_priv *ath_rc_priv, + struct ieee80211_tx_info *tx_info, + int final_ts_idx, int xretries, int long_retry) +{ + struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); struct ath_rate_table *rate_table; - struct ath_tx_ratectrl *rate_ctrl; - struct ath_rc_series rcs[4]; + struct ieee80211_tx_rate *rates = tx_info->status.rates; u8 flags; - u32 series = 0, rix; + u32 i = 0, rix; - memcpy(rcs, info_priv->rcs, 4 * sizeof(rcs[0])); - rate_table = (struct ath_rate_table *) - asc->hw_rate_table[sc->sc_curmode]; - rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv); - ASSERT(rcs[0].tries != 0); + rate_table = sc->cur_rate_table; /* * If the first rate is not the final index, there @@ -1579,32 +1261,22 @@ static void ath_rc_update(struct ath_softc *sc, */ if (final_ts_idx != 0) { /* Process intermediate rates that failed.*/ - for (series = 0; series < final_ts_idx ; series++) { - if (rcs[series].tries != 0) { - flags = rcs[series].flags; + for (i = 0; i < final_ts_idx ; i++) { + if (rates[i].count != 0 && (rates[i].idx >= 0)) { + flags = rates[i].flags; + /* If HT40 and we have switched mode from * 40 to 20 => don't update */ - if ((flags & ATH_RC_CW40_FLAG) && - (rate_ctrl->rc_phy_mode != - (flags & ATH_RC_CW40_FLAG))) + + if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && + (ath_rc_priv->rc_phy_mode != WLAN_RC_40_FLAG)) return; - if ((flags & ATH_RC_CW40_FLAG) && - (flags & ATH_RC_SGI_FLAG)) - rix = rate_table->info[ - rcs[series].rix].ht_index; - else if (flags & ATH_RC_SGI_FLAG) - rix = rate_table->info[ - rcs[series].rix].sgi_index; - else if (flags & ATH_RC_CW40_FLAG) - rix = rate_table->info[ - rcs[series].rix].cw40index; - else - rix = rate_table->info[ - rcs[series].rix].base_index; + + rix = ath_rc_get_rateindex(rate_table, &rates[i]); ath_rc_update_ht(sc, ath_rc_priv, - info_priv, rix, + tx_info_priv, rix, xretries ? 1 : 2, - rcs[series].tries); + rates[i].count); } } } else { @@ -1614,240 +1286,152 @@ static void ath_rc_update(struct ath_softc *sc, * Treating it as an excessive retry penalizes the rate * inordinately. */ - if (rcs[0].tries == 1 && xretries == 1) + if (rates[0].count == 1 && xretries == 1) xretries = 2; } - flags = rcs[series].flags; + flags = rates[i].flags; + /* If HT40 and we have switched mode from 40 to 20 => don't update */ - if ((flags & ATH_RC_CW40_FLAG) && - (rate_ctrl->rc_phy_mode != (flags & ATH_RC_CW40_FLAG))) + if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && + (ath_rc_priv->rc_phy_mode != WLAN_RC_40_FLAG)) { return; + } - if ((flags & ATH_RC_CW40_FLAG) && (flags & ATH_RC_SGI_FLAG)) - rix = rate_table->info[rcs[series].rix].ht_index; - else if (flags & ATH_RC_SGI_FLAG) - rix = rate_table->info[rcs[series].rix].sgi_index; - else if (flags & ATH_RC_CW40_FLAG) - rix = rate_table->info[rcs[series].rix].cw40index; - else - rix = rate_table->info[rcs[series].rix].base_index; - - ath_rc_update_ht(sc, ath_rc_priv, info_priv, rix, - xretries, long_retry); + rix = ath_rc_get_rateindex(rate_table, &rates[i]); + ath_rc_update_ht(sc, ath_rc_priv, tx_info_priv, rix, + xretries, long_retry); } -/* - * Process a tx descriptor for a completed transmit (success or failure). - */ -static void ath_rate_tx_complete(struct ath_softc *sc, - struct ath_node *an, - struct ath_rate_node *rc_priv, - struct ath_tx_info_priv *info_priv) +static struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc, + enum ieee80211_band band, + bool is_ht, bool is_cw_40) { - int final_ts_idx = info_priv->tx.ts_rateindex; - int tx_status = 0, is_underrun = 0; - struct ath_vap *avp; - - avp = rc_priv->avp; - if ((avp->av_config.av_fixed_rateset != IEEE80211_FIXED_RATE_NONE) || - (info_priv->tx.ts_status & ATH9K_TXERR_FILT)) - return; - - if (info_priv->tx.ts_rssi > 0) { - ATH_RSSI_LPF(an->an_chainmask_sel.tx_avgrssi, - info_priv->tx.ts_rssi); - } - - /* - * If underrun error is seen assume it as an excessive retry only - * if prefetch trigger level have reached the max (0x3f for 5416) - * Adjust the long retry as if the frame was tried ATH_11N_TXMAXTRY - * times. This affects how ratectrl updates PER for the failed rate. - */ - if (info_priv->tx.ts_flags & - (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN) && - ((sc->sc_ah->ah_txTrigLevel) >= tx_triglevel_max)) { - tx_status = 1; - is_underrun = 1; + int mode = 0; + + switch(band) { + case IEEE80211_BAND_2GHZ: + mode = ATH9K_MODE_11G; + if (is_ht) + mode = ATH9K_MODE_11NG_HT20; + if (is_cw_40) + mode = ATH9K_MODE_11NG_HT40PLUS; + break; + case IEEE80211_BAND_5GHZ: + mode = ATH9K_MODE_11A; + if (is_ht) + mode = ATH9K_MODE_11NA_HT20; + if (is_cw_40) + mode = ATH9K_MODE_11NA_HT40PLUS; + break; + default: + DPRINTF(sc, ATH_DBG_CONFIG, "Invalid band\n"); + return NULL; } - if ((info_priv->tx.ts_status & ATH9K_TXERR_XRETRY) || - (info_priv->tx.ts_status & ATH9K_TXERR_FIFO)) - tx_status = 1; + BUG_ON(mode >= ATH9K_MODE_MAX); - ath_rc_update(sc, rc_priv, info_priv, final_ts_idx, tx_status, - (is_underrun) ? ATH_11N_TXMAXTRY : - info_priv->tx.ts_longretry); + DPRINTF(sc, ATH_DBG_CONFIG, "Choosing rate table for mode: %d\n", mode); + return sc->hw_rate_table[mode]; } -/* - * Update the SIB's rate control information - * - * This should be called when the supported rates change - * (e.g. SME operation, wireless mode change) - * - * It will determine which rates are valid for use. - */ -static void ath_rc_sib_update(struct ath_softc *sc, - struct ath_rate_node *ath_rc_priv, - u32 capflag, int keep_state, - struct ath_rateset *negotiated_rates, - struct ath_rateset *negotiated_htrates) +static void ath_rc_init(struct ath_softc *sc, + struct ath_rate_priv *ath_rc_priv, + struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta) { struct ath_rate_table *rate_table = NULL; - struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc; - struct ath_rateset *rateset = negotiated_rates; - u8 *ht_mcs = (u8 *)negotiated_htrates; - struct ath_tx_ratectrl *rate_ctrl = - (struct ath_tx_ratectrl *)ath_rc_priv; + struct ath_rateset *rateset = &ath_rc_priv->neg_rates; + u8 *ht_mcs = (u8 *)&ath_rc_priv->neg_ht_rates; u8 i, j, k, hi = 0, hthi = 0; - rate_table = (struct ath_rate_table *) - asc->hw_rate_table[sc->sc_curmode]; + /* FIXME: Adhoc */ + if ((sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION) || + (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC)) { + bool is_cw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; + rate_table = ath_choose_rate_table(sc, sband->band, + sta->ht_cap.ht_supported, + is_cw_40); + } else if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) { + /* cur_rate_table would be set on init through config() */ + rate_table = sc->cur_rate_table; + } + + if (!rate_table) { + DPRINTF(sc, ATH_DBG_FATAL, "Rate table not initialized\n"); + return; + } + + if (sta->ht_cap.ht_supported) { + ath_rc_priv->ht_cap = (WLAN_RC_HT_FLAG | WLAN_RC_DS_FLAG); + if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) + ath_rc_priv->ht_cap |= WLAN_RC_40_FLAG; + } /* Initial rate table size. Will change depending * on the working rate set */ - rate_ctrl->rate_table_size = MAX_TX_RATE_TBL; + ath_rc_priv->rate_table_size = RATE_TABLE_SIZE; /* Initialize thresholds according to the global rate table */ - for (i = 0 ; (i < rate_ctrl->rate_table_size) && (!keep_state); i++) { - rate_ctrl->state[i].rssi_thres = + for (i = 0 ; i < ath_rc_priv->rate_table_size; i++) { + ath_rc_priv->state[i].rssi_thres = rate_table->info[i].rssi_ack_validmin; - rate_ctrl->state[i].per = 0; + ath_rc_priv->state[i].per = 0; } /* Determine the valid rates */ - ath_rc_init_valid_txmask(rate_ctrl); + ath_rc_init_valid_txmask(ath_rc_priv); for (i = 0; i < WLAN_RC_PHY_MAX; i++) { for (j = 0; j < MAX_TX_RATE_PHY; j++) - rate_ctrl->valid_phy_rateidx[i][j] = 0; - rate_ctrl->valid_phy_ratecnt[i] = 0; + ath_rc_priv->valid_phy_rateidx[i][j] = 0; + ath_rc_priv->valid_phy_ratecnt[i] = 0; } - rate_ctrl->rc_phy_mode = (capflag & WLAN_RC_40_FLAG); + ath_rc_priv->rc_phy_mode = (ath_rc_priv->ht_cap & WLAN_RC_40_FLAG); /* Set stream capability */ - ath_rc_priv->single_stream = (capflag & WLAN_RC_DS_FLAG) ? 0 : 1; + ath_rc_priv->single_stream = (ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG) ? 0 : 1; if (!rateset->rs_nrates) { /* No working rate, just initialize valid rates */ - hi = ath_rc_sib_init_validrates(ath_rc_priv, rate_table, - capflag); + hi = ath_rc_init_validrates(ath_rc_priv, rate_table, + ath_rc_priv->ht_cap); } else { /* Use intersection of working rates and valid rates */ - hi = ath_rc_sib_setvalid_rates(ath_rc_priv, rate_table, - rateset, capflag); - if (capflag & WLAN_RC_HT_FLAG) { - hthi = ath_rc_sib_setvalid_htrates(ath_rc_priv, + hi = ath_rc_setvalid_rates(ath_rc_priv, rate_table, + rateset, ath_rc_priv->ht_cap); + if (ath_rc_priv->ht_cap & WLAN_RC_HT_FLAG) { + hthi = ath_rc_setvalid_htrates(ath_rc_priv, rate_table, ht_mcs, - capflag); + ath_rc_priv->ht_cap); } hi = A_MAX(hi, hthi); } - rate_ctrl->rate_table_size = hi + 1; - rate_ctrl->rate_max_phy = 0; - ASSERT(rate_ctrl->rate_table_size <= MAX_TX_RATE_TBL); + ath_rc_priv->rate_table_size = hi + 1; + ath_rc_priv->rate_max_phy = 0; + ASSERT(ath_rc_priv->rate_table_size <= RATE_TABLE_SIZE); for (i = 0, k = 0; i < WLAN_RC_PHY_MAX; i++) { - for (j = 0; j < rate_ctrl->valid_phy_ratecnt[i]; j++) { - rate_ctrl->valid_rate_index[k++] = - rate_ctrl->valid_phy_rateidx[i][j]; + for (j = 0; j < ath_rc_priv->valid_phy_ratecnt[i]; j++) { + ath_rc_priv->valid_rate_index[k++] = + ath_rc_priv->valid_phy_rateidx[i][j]; } - if (!ath_rc_valid_phyrate(i, rate_table->initial_ratemax, TRUE) - || !rate_ctrl->valid_phy_ratecnt[i]) + if (!ath_rc_valid_phyrate(i, rate_table->initial_ratemax, 1) + || !ath_rc_priv->valid_phy_ratecnt[i]) continue; - rate_ctrl->rate_max_phy = rate_ctrl->valid_phy_rateidx[i][j-1]; + ath_rc_priv->rate_max_phy = ath_rc_priv->valid_phy_rateidx[i][j-1]; } - ASSERT(rate_ctrl->rate_table_size <= MAX_TX_RATE_TBL); - ASSERT(k <= MAX_TX_RATE_TBL); - - rate_ctrl->max_valid_rate = k; - /* - * Some third party vendors don't send the supported rate series in - * order. So sorting to make sure its in order, otherwise our RateFind - * Algo will select wrong rates - */ - ath_rc_sort_validrates(rate_table, rate_ctrl); - rate_ctrl->rate_max_phy = rate_ctrl->valid_rate_index[k-4]; -} - -/* - * Update rate-control state on station associate/reassociate. - */ -static int ath_rate_newassoc(struct ath_softc *sc, - struct ath_rate_node *ath_rc_priv, - unsigned int capflag, - struct ath_rateset *negotiated_rates, - struct ath_rateset *negotiated_htrates) -{ - - - ath_rc_priv->ht_cap = - ((capflag & ATH_RC_DS_FLAG) ? WLAN_RC_DS_FLAG : 0) | - ((capflag & ATH_RC_SGI_FLAG) ? WLAN_RC_SGI_FLAG : 0) | - ((capflag & ATH_RC_HT_FLAG) ? WLAN_RC_HT_FLAG : 0) | - ((capflag & ATH_RC_CW40_FLAG) ? WLAN_RC_40_FLAG : 0); - - ath_rc_sib_update(sc, ath_rc_priv, ath_rc_priv->ht_cap, 0, - negotiated_rates, negotiated_htrates); - - return 0; -} - -/* - * This routine is called to initialize the rate control parameters - * in the SIB. It is called initially during system initialization - * or when a station is associated with the AP. - */ -static void ath_rc_sib_init(struct ath_rate_node *ath_rc_priv) -{ - struct ath_tx_ratectrl *rate_ctrl; - - rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv); - rate_ctrl->rssi_down_time = jiffies_to_msecs(jiffies); -} - - -static void ath_setup_rates(struct ath_softc *sc, - struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, - struct ath_rate_node *rc_priv) - -{ - int i, j = 0; - - DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); - - for (i = 0; i < sband->n_bitrates; i++) { - if (sta->supp_rates[sband->band] & BIT(i)) { - rc_priv->neg_rates.rs_rates[j] - = (sband->bitrates[i].bitrate * 2) / 10; - j++; - } - } - rc_priv->neg_rates.rs_nrates = j; -} - -void ath_rc_node_update(struct ieee80211_hw *hw, struct ath_rate_node *rc_priv) -{ - struct ath_softc *sc = hw->priv; - u32 capflag = 0; - - if (hw->conf.ht_conf.ht_supported) { - capflag |= ATH_RC_HT_FLAG | ATH_RC_DS_FLAG; - if (sc->sc_ht_info.tx_chan_width == ATH9K_HT_MACMODE_2040) - capflag |= ATH_RC_CW40_FLAG; - } - - ath_rate_newassoc(sc, rc_priv, capflag, - &rc_priv->neg_rates, - &rc_priv->neg_ht_rates); + ASSERT(ath_rc_priv->rate_table_size <= RATE_TABLE_SIZE); + ASSERT(k <= RATE_TABLE_SIZE); + ath_rc_priv->max_valid_rate = k; + ath_rc_sort_validrates(rate_table, ath_rc_priv); + ath_rc_priv->rate_max_phy = ath_rc_priv->valid_rate_index[k-4]; + sc->cur_rate_table = rate_table; } /* Rate Control callbacks */ @@ -1856,163 +1440,88 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, struct sk_buff *skb) { struct ath_softc *sc = priv; - struct ath_tx_info_priv *tx_info_priv; - struct ath_node *an; + struct ath_rate_priv *ath_rc_priv = priv_sta; + struct ath_tx_info_priv *tx_info_priv = NULL; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr; + int final_ts_idx, tx_status = 0, is_underrun = 0; __le16 fc; hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; - tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; + tx_info_priv = ATH_TX_INFO_PRIV(tx_info); + final_ts_idx = tx_info_priv->tx.ts_rateindex; - spin_lock_bh(&sc->node_lock); - an = ath_node_find(sc, hdr->addr1); - spin_unlock_bh(&sc->node_lock); + if (!priv_sta || !ieee80211_is_data(fc) || + !tx_info_priv->update_rc) + goto exit; - if (!an || !priv_sta || !ieee80211_is_data(fc)) { - if (tx_info->driver_data[0] != NULL) { - kfree(tx_info->driver_data[0]); - tx_info->driver_data[0] = NULL; - } - return; - } - if (tx_info->driver_data[0] != NULL) { - ath_rate_tx_complete(sc, an, priv_sta, tx_info_priv); - kfree(tx_info->driver_data[0]); - tx_info->driver_data[0] = NULL; - } -} - -static void ath_tx_aggr_resp(struct ath_softc *sc, - struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, - struct ath_node *an, - u8 tidno) -{ - struct ath_atx_tid *txtid; - u16 buffersize = 0; - int state; - struct sta_info *si; - - if (!(sc->sc_flags & SC_OP_TXAGGR)) - return; - - txtid = ATH_AN_2_TID(an, tidno); - if (!txtid->paused) - return; + if (tx_info_priv->tx.ts_status & ATH9K_TXERR_FILT) + goto exit; /* - * XXX: This is entirely busted, we aren't supposed to - * access the sta from here because it's internal - * to mac80211, and looking at the state without - * locking is wrong too. + * If underrun error is seen assume it as an excessive retry only + * if prefetch trigger level have reached the max (0x3f for 5416) + * Adjust the long retry as if the frame was tried ATH_11N_TXMAXTRY + * times. This affects how ratectrl updates PER for the failed rate. */ - si = container_of(sta, struct sta_info, sta); - buffersize = IEEE80211_MIN_AMPDU_BUF << - sband->ht_info.ampdu_factor; /* FIXME */ - state = si->ampdu_mlme.tid_state_tx[tidno]; - - if (state & HT_ADDBA_RECEIVED_MSK) { - txtid->addba_exchangecomplete = 1; - txtid->addba_exchangeinprogress = 0; - txtid->baw_size = buffersize; - - DPRINTF(sc, ATH_DBG_AGGR, - "%s: Resuming tid, buffersize: %d\n", - __func__, - buffersize); - - ath_tx_resume_tid(sc, txtid); + if (tx_info_priv->tx.ts_flags & + (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN) && + ((sc->sc_ah->ah_txTrigLevel) >= ath_rc_priv->tx_triglevel_max)) { + tx_status = 1; + is_underrun = 1; } + + if ((tx_info_priv->tx.ts_status & ATH9K_TXERR_XRETRY) || + (tx_info_priv->tx.ts_status & ATH9K_TXERR_FIFO)) + tx_status = 1; + + ath_rc_tx_status(sc, ath_rc_priv, tx_info, final_ts_idx, tx_status, + (is_underrun) ? ATH_11N_TXMAXTRY : + tx_info_priv->tx.ts_longretry); + +exit: + kfree(tx_info_priv); } -static void ath_get_rate(void *priv, struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, void *priv_sta, - struct sk_buff *skb, struct rate_selection *sel) +static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, + struct ieee80211_tx_rate_control *txrc) { + struct ieee80211_supported_band *sband = txrc->sband; + struct sk_buff *skb = txrc->skb; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ath_softc *sc = priv; struct ieee80211_hw *hw = sc->hw; - struct ath_tx_info_priv *tx_info_priv; - struct ath_rate_node *ath_rc_priv = priv_sta; - struct ath_node *an; + struct ath_rate_priv *ath_rc_priv = priv_sta; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - int is_probe = FALSE, chk, ret; - s8 lowest_idx; + int is_probe = 0; __le16 fc = hdr->frame_control; - u8 *qc, tid; - DECLARE_MAC_BUF(mac); - - DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); - - /* allocate driver private area of tx_info */ - tx_info->driver_data[0] = kzalloc(sizeof(*tx_info_priv), GFP_ATOMIC); - ASSERT(tx_info->driver_data[0] != NULL); - tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; - lowest_idx = rate_lowest_index(sband, sta); - tx_info_priv->min_rate = (sband->bitrates[lowest_idx].bitrate * 2) / 10; /* lowest rate for management and multicast/broadcast frames */ - if (!ieee80211_is_data(fc) || - is_multicast_ether_addr(hdr->addr1) || !sta) { - sel->rate_idx = lowest_idx; + if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) || + !sta) { + tx_info->control.rates[0].idx = rate_lowest_index(sband, sta); + tx_info->control.rates[0].count = + is_multicast_ether_addr(hdr->addr1) ? 1 : ATH_MGT_TXMAXTRY; return; } /* Find tx rate for unicast frames */ - ath_rate_findrate(sc, ath_rc_priv, - ATH_11N_TXMAXTRY, 4, - ATH_RC_PROBE_ALLOWED, - tx_info_priv->rcs, - &is_probe, - false); - if (is_probe) - sel->probe_idx = ath_rc_priv->tx_ratectrl.probe_rate; - - /* Ratecontrol sometimes returns invalid rate index */ - if (tx_info_priv->rcs[0].rix != 0xff) - ath_rc_priv->prev_data_rix = tx_info_priv->rcs[0].rix; - else - tx_info_priv->rcs[0].rix = ath_rc_priv->prev_data_rix; - - sel->rate_idx = tx_info_priv->rcs[0].rix; + ath_rc_ratefind(sc, ath_rc_priv, ATH_11N_TXMAXTRY, 4, + tx_info, &is_probe, false); /* Check if aggregation has to be enabled for this tid */ - - if (hw->conf.ht_conf.ht_supported) { + if (hw->conf.ht.enabled) { if (ieee80211_is_data_qos(fc)) { + u8 *qc, tid; + struct ath_node *an; + qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & 0xf; + an = (struct ath_node *)sta->drv_priv; - spin_lock_bh(&sc->node_lock); - an = ath_node_find(sc, hdr->addr1); - spin_unlock_bh(&sc->node_lock); - - if (!an) { - DPRINTF(sc, ATH_DBG_AGGR, - "%s: Node not found to " - "init/chk TX aggr\n", __func__); - return; - } - - chk = ath_tx_aggr_check(sc, an, tid); - if (chk == AGGR_REQUIRED) { - ret = ieee80211_start_tx_ba_session(hw, - hdr->addr1, tid); - if (ret) - DPRINTF(sc, ATH_DBG_AGGR, - "%s: Unable to start tx " - "aggr for: %s\n", - __func__, - print_mac(mac, hdr->addr1)); - else - DPRINTF(sc, ATH_DBG_AGGR, - "%s: Started tx aggr for: %s\n", - __func__, - print_mac(mac, hdr->addr1)); - } else if (chk == AGGR_EXCHANGE_PROGRESS) - ath_tx_aggr_resp(sc, sband, sta, an, tid); + if(ath_tx_aggr_check(sc, an, tid)) + ieee80211_start_tx_ba_session(hw, hdr->addr1, tid); } } } @@ -2021,34 +1530,33 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, struct ieee80211_sta *sta, void *priv_sta) { struct ath_softc *sc = priv; - struct ath_rate_node *ath_rc_priv = priv_sta; + struct ath_rate_priv *ath_rc_priv = priv_sta; int i, j = 0; - DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); + for (i = 0; i < sband->n_bitrates; i++) { + if (sta->supp_rates[sband->band] & BIT(i)) { + ath_rc_priv->neg_rates.rs_rates[j] + = (sband->bitrates[i].bitrate * 2) / 10; + j++; + } + } + ath_rc_priv->neg_rates.rs_nrates = j; - ath_setup_rates(sc, sband, sta, ath_rc_priv); - if (sc->hw->conf.flags & IEEE80211_CONF_SUPPORT_HT_MODE) { - for (i = 0; i < MCS_SET_SIZE; i++) { - if (sc->hw->conf.ht_conf.supp_mcs_set[i/8] & (1<<(i%8))) + if (sta->ht_cap.ht_supported) { + for (i = 0, j = 0; i < 77; i++) { + if (sta->ht_cap.mcs.rx_mask[i/8] & (1<<(i%8))) ath_rc_priv->neg_ht_rates.rs_rates[j++] = i; if (j == ATH_RATE_MAX) break; } ath_rc_priv->neg_ht_rates.rs_nrates = j; } - ath_rc_node_update(sc->hw, priv_sta); -} -static void ath_rate_clear(void *priv) -{ - return; + ath_rc_init(sc, priv_sta, sband, sta); } static void *ath_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) { - struct ath_softc *sc = hw->priv; - - DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); return hw->priv; } @@ -2060,19 +1568,17 @@ static void ath_rate_free(void *priv) static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp) { struct ath_softc *sc = priv; - struct ath_vap *avp = sc->sc_vaps[0]; - struct ath_rate_node *rate_priv; - - DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); + struct ath_rate_priv *rate_priv; - rate_priv = ath_rate_node_alloc(avp, sc->sc_rc, gfp); + rate_priv = kzalloc(sizeof(struct ath_rate_priv), gfp); if (!rate_priv) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to allocate private rc structure\n", - __func__); + "Unable to allocate private rc structure\n"); return NULL; } - ath_rc_sib_init(rate_priv); + + rate_priv->rssi_down_time = jiffies_to_msecs(jiffies); + rate_priv->tx_triglevel_max = sc->sc_ah->ah_caps.tx_triglevel_max; return rate_priv; } @@ -2080,11 +1586,8 @@ static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp static void ath_rate_free_sta(void *priv, struct ieee80211_sta *sta, void *priv_sta) { - struct ath_rate_node *rate_priv = priv_sta; - struct ath_softc *sc = priv; - - DPRINTF(sc, ATH_DBG_RATE, "%s", __func__); - ath_rate_node_free(rate_priv); + struct ath_rate_priv *rate_priv = priv_sta; + kfree(rate_priv); } static struct rate_control_ops ath_rate_ops = { @@ -2093,13 +1596,69 @@ static struct rate_control_ops ath_rate_ops = { .tx_status = ath_tx_status, .get_rate = ath_get_rate, .rate_init = ath_rate_init, - .clear = ath_rate_clear, .alloc = ath_rate_alloc, .free = ath_rate_free, .alloc_sta = ath_rate_alloc_sta, .free_sta = ath_rate_free_sta, }; +static void ath_setup_rate_table(struct ath_softc *sc, + struct ath_rate_table *rate_table) +{ + int i; + + for (i = 0; i < 256; i++) + rate_table->rateCodeToIndex[i] = (u8)-1; + + for (i = 0; i < rate_table->rate_cnt; i++) { + u8 code = rate_table->info[i].ratecode; + u8 cix = rate_table->info[i].ctrl_rate; + u8 sh = rate_table->info[i].short_preamble; + + rate_table->rateCodeToIndex[code] = i; + rate_table->rateCodeToIndex[code | sh] = i; + + rate_table->info[i].lpAckDuration = + ath9k_hw_computetxtime(sc->sc_ah, rate_table, + WLAN_CTRL_FRAME_SIZE, + cix, + false); + rate_table->info[i].spAckDuration = + ath9k_hw_computetxtime(sc->sc_ah, rate_table, + WLAN_CTRL_FRAME_SIZE, + cix, + true); + } +} + +void ath_rate_attach(struct ath_softc *sc) +{ + sc->hw_rate_table[ATH9K_MODE_11B] = + &ar5416_11b_ratetable; + sc->hw_rate_table[ATH9K_MODE_11A] = + &ar5416_11a_ratetable; + sc->hw_rate_table[ATH9K_MODE_11G] = + &ar5416_11g_ratetable; + sc->hw_rate_table[ATH9K_MODE_11NA_HT20] = + &ar5416_11na_ratetable; + sc->hw_rate_table[ATH9K_MODE_11NG_HT20] = + &ar5416_11ng_ratetable; + sc->hw_rate_table[ATH9K_MODE_11NA_HT40PLUS] = + &ar5416_11na_ratetable; + sc->hw_rate_table[ATH9K_MODE_11NA_HT40MINUS] = + &ar5416_11na_ratetable; + sc->hw_rate_table[ATH9K_MODE_11NG_HT40PLUS] = + &ar5416_11ng_ratetable; + sc->hw_rate_table[ATH9K_MODE_11NG_HT40MINUS] = + &ar5416_11ng_ratetable; + + ath_setup_rate_table(sc, &ar5416_11b_ratetable); + ath_setup_rate_table(sc, &ar5416_11a_ratetable); + ath_setup_rate_table(sc, &ar5416_11g_ratetable); + ath_setup_rate_table(sc, &ar5416_11na_ratetable); + ath_setup_rate_table(sc, &ar5416_11ng_ratetable); +} + int ath_rate_control_register(void) { return ieee80211_rate_control_register(&ath_rate_ops); @@ -2109,4 +1668,3 @@ void ath_rate_control_unregister(void) { ieee80211_rate_control_unregister(&ath_rate_ops); } - diff --git a/drivers/net/wireless/ath9k/rc.h b/drivers/net/wireless/ath9k/rc.h index b95b41508b986000174519cc451458962f4962c3..97c60d12e8aa51cbfc7e34cff14869a556888908 100644 --- a/drivers/net/wireless/ath9k/rc.h +++ b/drivers/net/wireless/ath9k/rc.h @@ -20,84 +20,24 @@ #define RC_H #include "ath9k.h" -/* - * Interface definitions for transmit rate control modules for the - * Atheros driver. - * - * A rate control module is responsible for choosing the transmit rate - * for each data frame. Management+control frames are always sent at - * a fixed rate. - * - * Only one module may be present at a time; the driver references - * rate control interfaces by symbol name. If multiple modules are - * to be supported we'll need to switch to a registration-based scheme - * as is currently done, for example, for authentication modules. - * - * An instance of the rate control module is attached to each device - * at attach time and detached when the device is destroyed. The module - * may associate data with each device and each node (station). Both - * sets of storage are opaque except for the size of the per-node storage - * which must be provided when the module is attached. - * - * The rate control module is notified for each state transition and - * station association/reassociation. Otherwise it is queried for a - * rate for each outgoing frame and provided status from each transmitted - * frame. Any ancillary processing is the responsibility of the module - * (e.g. if periodic processing is required then the module should setup - * it's own timer). - * - * In addition to the transmit rate for each frame the module must also - * indicate the number of attempts to make at the specified rate. If this - * number is != ATH_TXMAXTRY then an additional callback is made to setup - * additional transmit state. The rate control code is assumed to write - * this additional data directly to the transmit descriptor. - */ struct ath_softc; -#define TRUE 1 -#define FALSE 0 +#define ATH_RATE_MAX 30 +#define RATE_TABLE_SIZE 64 +#define MAX_TX_RATE_PHY 48 -#define ATH_RATE_MAX 30 -#define MCS_SET_SIZE 128 +/* VALID_ALL - valid for 20/40/Legacy, + * VALID - Legacy only, + * VALID_20 - HT 20 only, + * VALID_40 - HT 40 only */ -enum ieee80211_fixed_rate_mode { - IEEE80211_FIXED_RATE_NONE = 0, - IEEE80211_FIXED_RATE_MCS = 1 /* HT rates */ -}; - -/* - * Use the hal os glue code to get ms time - */ -#define IEEE80211_RATE_IDX_ENTRY(val, idx) (((val&(0xff<<(idx*8)))>>(idx*8))) - -#define WLAN_PHY_HT_20_SS WLAN_RC_PHY_HT_20_SS -#define WLAN_PHY_HT_20_DS WLAN_RC_PHY_HT_20_DS -#define WLAN_PHY_HT_20_DS_HGI WLAN_RC_PHY_HT_20_DS_HGI -#define WLAN_PHY_HT_40_SS WLAN_RC_PHY_HT_40_SS -#define WLAN_PHY_HT_40_SS_HGI WLAN_RC_PHY_HT_40_SS_HGI -#define WLAN_PHY_HT_40_DS WLAN_RC_PHY_HT_40_DS -#define WLAN_PHY_HT_40_DS_HGI WLAN_RC_PHY_HT_40_DS_HGI - -#define WLAN_PHY_OFDM PHY_OFDM -#define WLAN_PHY_CCK PHY_CCK - -#define TRUE_20 0x2 -#define TRUE_40 0x4 -#define TRUE_2040 (TRUE_20|TRUE_40) -#define TRUE_ALL (TRUE_2040|TRUE) - -enum { - WLAN_RC_PHY_HT_20_SS = 4, - WLAN_RC_PHY_HT_20_DS, - WLAN_RC_PHY_HT_40_SS, - WLAN_RC_PHY_HT_40_DS, - WLAN_RC_PHY_HT_20_SS_HGI, - WLAN_RC_PHY_HT_20_DS_HGI, - WLAN_RC_PHY_HT_40_SS_HGI, - WLAN_RC_PHY_HT_40_DS_HGI, - WLAN_RC_PHY_MAX -}; +#define INVALID 0x0 +#define VALID 0x1 +#define VALID_20 0x2 +#define VALID_40 0x4 +#define VALID_2040 (VALID_20|VALID_40) +#define VALID_ALL (VALID_2040|VALID) #define WLAN_RC_PHY_DS(_phy) ((_phy == WLAN_RC_PHY_HT_20_DS) \ || (_phy == WLAN_RC_PHY_HT_40_DS) \ @@ -114,26 +54,22 @@ enum { #define WLAN_RC_PHY_HT(_phy) (_phy >= WLAN_RC_PHY_HT_20_SS) -/* Returns the capflag mode */ #define WLAN_RC_CAP_MODE(capflag) (((capflag & WLAN_RC_HT_FLAG) ? \ - (capflag & WLAN_RC_40_FLAG) ? TRUE_40 : TRUE_20 : TRUE)) + (capflag & WLAN_RC_40_FLAG) ? VALID_40 : VALID_20 : VALID)) /* Return TRUE if flag supports HT20 && client supports HT20 or * return TRUE if flag supports HT40 && client supports HT40. * This is used becos some rates overlap between HT20/HT40. */ - -#define WLAN_RC_PHY_HT_VALID(flag, capflag) (((flag & TRUE_20) && !(capflag \ - & WLAN_RC_40_FLAG)) || ((flag & TRUE_40) && \ - (capflag & WLAN_RC_40_FLAG))) +#define WLAN_RC_PHY_HT_VALID(flag, capflag) \ + (((flag & VALID_20) && !(capflag & WLAN_RC_40_FLAG)) || \ + ((flag & VALID_40) && (capflag & WLAN_RC_40_FLAG))) #define WLAN_RC_DS_FLAG (0x01) #define WLAN_RC_40_FLAG (0x02) #define WLAN_RC_SGI_FLAG (0x04) #define WLAN_RC_HT_FLAG (0x08) -#define RATE_TABLE_SIZE 64 - /** * struct ath_rate_table - Rate Control table * @valid: valid for use in rate control @@ -150,10 +86,11 @@ enum { * @max_4ms_framelen: maximum frame length(bytes) for tx duration * @probe_interval: interval for rate control to probe for other rates * @rssi_reduce_interval: interval for rate control to reduce rssi - * @initial_ratemax: initial ratemax value used in ath_rc_sib_update() + * @initial_ratemax: initial ratemax value */ struct ath_rate_table { int rate_cnt; + u8 rateCodeToIndex[256]; struct { int valid; int valid_single_stream; @@ -171,42 +108,26 @@ struct ath_rate_table { u8 sgi_index; u8 ht_index; u32 max_4ms_framelen; + u16 lpAckDuration; + u16 spAckDuration; } info[RATE_TABLE_SIZE]; u32 probe_interval; u32 rssi_reduce_interval; u8 initial_ratemax; }; -#define ATH_RC_PROBE_ALLOWED 0x00000001 -#define ATH_RC_MINRATE_LASTRATE 0x00000002 - -struct ath_rc_series { - u8 rix; - u8 tries; - u8 flags; - u32 max_4ms_framelen; -}; - -/* rcs_flags definition */ -#define ATH_RC_DS_FLAG 0x01 -#define ATH_RC_CW40_FLAG 0x02 /* CW 40 */ -#define ATH_RC_SGI_FLAG 0x04 /* Short Guard Interval */ -#define ATH_RC_HT_FLAG 0x08 /* HT */ -#define ATH_RC_RTSCTS_FLAG 0x10 /* RTS-CTS */ - -/* - * State structures for new rate adaptation code - */ -#define MAX_TX_RATE_TBL 64 -#define MAX_TX_RATE_PHY 48 - struct ath_tx_ratectrl_state { int8_t rssi_thres; /* required rssi for this rate (dB) */ u8 per; /* recent estimate of packet error rate (%) */ }; +struct ath_rateset { + u8 rs_nrates; + u8 rs_rates[ATH_RATE_MAX]; +}; + /** - * struct ath_tx_ratectrl - TX Rate control Information + * struct ath_rate_priv - Rate Control priv data * @state: RC state * @rssi_last: last ACK rssi * @rssi_last_lookup: last ACK rssi used for lookup @@ -225,9 +146,13 @@ struct ath_tx_ratectrl_state { * @valid_phy_ratecnt: valid rate count * @rate_max_phy: phy index for the max rate * @probe_interval: interval for ratectrl to probe for other rates + * @prev_data_rix: rate idx of last data frame + * @ht_cap: HT capabilities + * @single_stream: When TRUE, only single TX stream possible + * @neg_rates: Negotatied rates + * @neg_ht_rates: Negotiated HT rates */ -struct ath_tx_ratectrl { - struct ath_tx_ratectrl_state state[MAX_TX_RATE_TBL]; +struct ath_rate_priv { int8_t rssi_last; int8_t rssi_last_lookup; int8_t rssi_last_prev; @@ -237,89 +162,40 @@ struct ath_tx_ratectrl { int32_t rssi_sum; u8 rate_table_size; u8 probe_rate; - u32 rssi_time; - u32 rssi_down_time; - u32 probe_time; u8 hw_maxretry_pktcnt; u8 max_valid_rate; - u8 valid_rate_index[MAX_TX_RATE_TBL]; - u32 per_down_time; - - /* 11n state */ + u8 valid_rate_index[RATE_TABLE_SIZE]; + u8 ht_cap; + u8 single_stream; u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX]; - u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][MAX_TX_RATE_TBL]; + u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][RATE_TABLE_SIZE]; u8 rc_phy_mode; u8 rate_max_phy; + u32 rssi_time; + u32 rssi_down_time; + u32 probe_time; + u32 per_down_time; u32 probe_interval; -}; - -struct ath_rateset { - u8 rs_nrates; - u8 rs_rates[ATH_RATE_MAX]; -}; - -/* per-device state */ -struct ath_rate_softc { - /* phy tables that contain rate control data */ - const void *hw_rate_table[ATH9K_MODE_MAX]; - - /* -1 or index of fixed rate */ - int fixedrix; -}; - -/* per-node state */ -struct ath_rate_node { - struct ath_tx_ratectrl tx_ratectrl; - - /* rate idx of last data frame */ u32 prev_data_rix; - - /* ht capabilities */ - u8 ht_cap; - - /* When TRUE, only single stream Tx possible */ - u8 single_stream; - - /* Negotiated rates */ + u32 tx_triglevel_max; + struct ath_tx_ratectrl_state state[RATE_TABLE_SIZE]; struct ath_rateset neg_rates; - - /* Negotiated HT rates */ struct ath_rateset neg_ht_rates; - struct ath_rate_softc *asc; - struct ath_vap *avp; }; -/* Driver data of ieee80211_tx_info */ struct ath_tx_info_priv { - struct ath_rc_series rcs[4]; struct ath_tx_status tx; int n_frames; int n_bad_frames; - u8 min_rate; + bool update_rc; }; -/* - * Attach/detach a rate control module. - */ -struct ath_rate_softc *ath_rate_attach(struct ath_hal *ah); -void ath_rate_detach(struct ath_rate_softc *asc); - -/* - * Update/reset rate control state for 802.11 state transitions. - * Important mostly as the analog to ath_rate_newassoc when operating - * in station mode. - */ -void ath_rc_node_update(struct ieee80211_hw *hw, struct ath_rate_node *rc_priv); -void ath_rate_newstate(struct ath_softc *sc, struct ath_vap *avp); - -/* - * Return rate index for given Dot11 Rate. - */ -u8 ath_rate_findrateix(struct ath_softc *sc, - u8 dot11_rate); +#define ATH_TX_INFO_PRIV(tx_info) \ + ((struct ath_tx_info_priv *)((tx_info)->rate_driver_data[0])) -/* Routines to register/unregister rate control algorithm */ +void ath_rate_attach(struct ath_softc *sc); +u8 ath_rate_findrateix(struct ath_softc *sc, u8 dot11_rate); int ath_rate_control_register(void); void ath_rate_control_unregister(void); diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index 504a0444d89f853672a4abd71886cc17e3068ff9..462e08c3d09dc4cf18693f4e39c383a7dc34c580 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -14,10 +14,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* - * Implementation of receive path. - */ - #include "core.h" /* @@ -27,10 +23,7 @@ * MAC acknowledges BA status as long as it copies frames to host * buffer (or rx fifo). This can incorrectly acknowledge packets * to a sender if last desc is self-linked. - * - * NOTE: Caller should hold the rxbuf lock. */ - static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf) { struct ath_hal *ah = sc->sc_ah; @@ -40,356 +33,53 @@ static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf) ATH_RXBUF_RESET(bf); ds = bf->bf_desc; - ds->ds_link = 0; /* link to null */ + ds->ds_link = 0; /* link to null */ ds->ds_data = bf->bf_buf_addr; - /* XXX For RADAR? - * virtual addr of the beginning of the buffer. */ + /* virtual addr of the beginning of the buffer. */ skb = bf->bf_mpdu; ASSERT(skb != NULL); ds->ds_vdata = skb->data; - /* setup rx descriptors. The sc_rxbufsize here tells the harware + /* setup rx descriptors. The rx.bufsize here tells the harware * how much data it can DMA to us and that we are prepared * to process */ - ath9k_hw_setuprxdesc(ah, - ds, - sc->sc_rxbufsize, + ath9k_hw_setuprxdesc(ah, ds, + sc->rx.bufsize, 0); - if (sc->sc_rxlink == NULL) + if (sc->rx.rxlink == NULL) ath9k_hw_putrxbuf(ah, bf->bf_daddr); else - *sc->sc_rxlink = bf->bf_daddr; + *sc->rx.rxlink = bf->bf_daddr; - sc->sc_rxlink = &ds->ds_link; + sc->rx.rxlink = &ds->ds_link; ath9k_hw_rxena(ah); } -/* Process received BAR frame */ - -static int ath_bar_rx(struct ath_softc *sc, - struct ath_node *an, - struct sk_buff *skb) -{ - struct ieee80211_bar *bar; - struct ath_arx_tid *rxtid; - struct sk_buff *tskb; - struct ath_recv_status *rx_status; - int tidno, index, cindex; - u16 seqno; - - /* look at BAR contents */ - - bar = (struct ieee80211_bar *)skb->data; - tidno = (le16_to_cpu(bar->control) & IEEE80211_BAR_CTL_TID_M) - >> IEEE80211_BAR_CTL_TID_S; - seqno = le16_to_cpu(bar->start_seq_num) >> IEEE80211_SEQ_SEQ_SHIFT; - - /* process BAR - indicate all pending RX frames till the BAR seqno */ - - rxtid = &an->an_aggr.rx.tid[tidno]; - - spin_lock_bh(&rxtid->tidlock); - - /* get relative index */ - - index = ATH_BA_INDEX(rxtid->seq_next, seqno); - - /* drop BAR if old sequence (index is too large) */ - - if ((index > rxtid->baw_size) && - (index > (IEEE80211_SEQ_MAX - (rxtid->baw_size << 2)))) - /* discard frame, ieee layer may not treat frame as a dup */ - goto unlock_and_free; - - /* complete receive processing for all pending frames upto BAR seqno */ - - cindex = (rxtid->baw_head + index) & (ATH_TID_MAX_BUFS - 1); - while ((rxtid->baw_head != rxtid->baw_tail) && - (rxtid->baw_head != cindex)) { - tskb = rxtid->rxbuf[rxtid->baw_head].rx_wbuf; - rx_status = &rxtid->rxbuf[rxtid->baw_head].rx_status; - rxtid->rxbuf[rxtid->baw_head].rx_wbuf = NULL; - - if (tskb != NULL) - ath_rx_subframe(an, tskb, rx_status); - - INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); - INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); - } - - /* ... and indicate rest of the frames in-order */ - - while (rxtid->baw_head != rxtid->baw_tail && - rxtid->rxbuf[rxtid->baw_head].rx_wbuf != NULL) { - tskb = rxtid->rxbuf[rxtid->baw_head].rx_wbuf; - rx_status = &rxtid->rxbuf[rxtid->baw_head].rx_status; - rxtid->rxbuf[rxtid->baw_head].rx_wbuf = NULL; - - ath_rx_subframe(an, tskb, rx_status); - - INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); - INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); - } - -unlock_and_free: - spin_unlock_bh(&rxtid->tidlock); - /* free bar itself */ - dev_kfree_skb(skb); - return IEEE80211_FTYPE_CTL; -} - -/* Function to handle a subframe of aggregation when HT is enabled */ - -static int ath_ampdu_input(struct ath_softc *sc, - struct ath_node *an, - struct sk_buff *skb, - struct ath_recv_status *rx_status) -{ - struct ieee80211_hdr *hdr; - struct ath_arx_tid *rxtid; - struct ath_rxbuf *rxbuf; - u8 type, subtype; - u16 rxseq; - int tid = 0, index, cindex, rxdiff; - __le16 fc; - u8 *qc; - - hdr = (struct ieee80211_hdr *)skb->data; - fc = hdr->frame_control; - - /* collect stats of frames with non-zero version */ - - if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_VERS) != 0) { - dev_kfree_skb(skb); - return -1; - } - - type = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_FTYPE; - subtype = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_STYPE; - - if (ieee80211_is_back_req(fc)) - return ath_bar_rx(sc, an, skb); - - /* special aggregate processing only for qos unicast data frames */ - - if (!ieee80211_is_data(fc) || - !ieee80211_is_data_qos(fc) || - is_multicast_ether_addr(hdr->addr1)) - return ath_rx_subframe(an, skb, rx_status); - - /* lookup rx tid state */ - - if (ieee80211_is_data_qos(fc)) { - qc = ieee80211_get_qos_ctl(hdr); - tid = qc[0] & 0xf; - } - - if (sc->sc_ah->ah_opmode == ATH9K_M_STA) { - /* Drop the frame not belonging to me. */ - if (memcmp(hdr->addr1, sc->sc_myaddr, ETH_ALEN)) { - dev_kfree_skb(skb); - return -1; - } - } - - rxtid = &an->an_aggr.rx.tid[tid]; - - spin_lock(&rxtid->tidlock); - - rxdiff = (rxtid->baw_tail - rxtid->baw_head) & - (ATH_TID_MAX_BUFS - 1); - - /* - * If the ADDBA exchange has not been completed by the source, - * process via legacy path (i.e. no reordering buffer is needed) - */ - if (!rxtid->addba_exchangecomplete) { - spin_unlock(&rxtid->tidlock); - return ath_rx_subframe(an, skb, rx_status); - } - - /* extract sequence number from recvd frame */ - - rxseq = le16_to_cpu(hdr->seq_ctrl) >> IEEE80211_SEQ_SEQ_SHIFT; - - if (rxtid->seq_reset) { - rxtid->seq_reset = 0; - rxtid->seq_next = rxseq; - } - - index = ATH_BA_INDEX(rxtid->seq_next, rxseq); - - /* drop frame if old sequence (index is too large) */ - - if (index > (IEEE80211_SEQ_MAX - (rxtid->baw_size << 2))) { - /* discard frame, ieee layer may not treat frame as a dup */ - spin_unlock(&rxtid->tidlock); - dev_kfree_skb(skb); - return IEEE80211_FTYPE_DATA; - } - - /* sequence number is beyond block-ack window */ - - if (index >= rxtid->baw_size) { - - /* complete receive processing for all pending frames */ - - while (index >= rxtid->baw_size) { - - rxbuf = rxtid->rxbuf + rxtid->baw_head; - - if (rxbuf->rx_wbuf != NULL) { - ath_rx_subframe(an, rxbuf->rx_wbuf, - &rxbuf->rx_status); - rxbuf->rx_wbuf = NULL; - } - - INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); - INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); - - index--; - } - } - - /* add buffer to the recv ba window */ - - cindex = (rxtid->baw_head + index) & (ATH_TID_MAX_BUFS - 1); - rxbuf = rxtid->rxbuf + cindex; - - if (rxbuf->rx_wbuf != NULL) { - spin_unlock(&rxtid->tidlock); - /* duplicate frame */ - dev_kfree_skb(skb); - return IEEE80211_FTYPE_DATA; - } - - rxbuf->rx_wbuf = skb; - rxbuf->rx_time = get_timestamp(); - rxbuf->rx_status = *rx_status; - - /* advance tail if sequence received is newer - * than any received so far */ - - if (index >= rxdiff) { - rxtid->baw_tail = cindex; - INCR(rxtid->baw_tail, ATH_TID_MAX_BUFS); - } - - /* indicate all in-order received frames */ - - while (rxtid->baw_head != rxtid->baw_tail) { - rxbuf = rxtid->rxbuf + rxtid->baw_head; - if (!rxbuf->rx_wbuf) - break; - - ath_rx_subframe(an, rxbuf->rx_wbuf, &rxbuf->rx_status); - rxbuf->rx_wbuf = NULL; - - INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); - INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); - } - - /* - * start a timer to flush all received frames if there are pending - * receive frames - */ - if (rxtid->baw_head != rxtid->baw_tail) - mod_timer(&rxtid->timer, ATH_RX_TIMEOUT); - else - del_timer_sync(&rxtid->timer); - - spin_unlock(&rxtid->tidlock); - return IEEE80211_FTYPE_DATA; -} - -/* Timer to flush all received sub-frames */ - -static void ath_rx_timer(unsigned long data) +static void ath_setdefantenna(struct ath_softc *sc, u32 antenna) { - struct ath_arx_tid *rxtid = (struct ath_arx_tid *)data; - struct ath_node *an = rxtid->an; - struct ath_rxbuf *rxbuf; - int nosched; - - spin_lock_bh(&rxtid->tidlock); - while (rxtid->baw_head != rxtid->baw_tail) { - rxbuf = rxtid->rxbuf + rxtid->baw_head; - if (!rxbuf->rx_wbuf) { - INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); - INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); - continue; - } - - /* - * Stop if the next one is a very recent frame. - * - * Call get_timestamp in every iteration to protect against the - * case in which a new frame is received while we are executing - * this function. Using a timestamp obtained before entering - * the loop could lead to a very large time interval - * (a negative value typecast to unsigned), breaking the - * function's logic. - */ - if ((get_timestamp() - rxbuf->rx_time) < - (ATH_RX_TIMEOUT * HZ / 1000)) - break; - - ath_rx_subframe(an, rxbuf->rx_wbuf, - &rxbuf->rx_status); - rxbuf->rx_wbuf = NULL; - - INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); - INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); - } - - /* - * start a timer to flush all received frames if there are pending - * receive frames - */ - if (rxtid->baw_head != rxtid->baw_tail) - nosched = 0; - else - nosched = 1; /* no need to re-arm the timer again */ - - spin_unlock_bh(&rxtid->tidlock); + /* XXX block beacon interrupts */ + ath9k_hw_setantenna(sc->sc_ah, antenna); + sc->rx.defant = antenna; + sc->rx.rxotherant = 0; } -/* Free all pending sub-frames in the re-ordering buffer */ - -static void ath_rx_flush_tid(struct ath_softc *sc, - struct ath_arx_tid *rxtid, int drop) +/* + * Extend 15-bit time stamp from rx descriptor to + * a full 64-bit TSF using the current h/w TSF. +*/ +static u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp) { - struct ath_rxbuf *rxbuf; - unsigned long flag; - - spin_lock_irqsave(&rxtid->tidlock, flag); - while (rxtid->baw_head != rxtid->baw_tail) { - rxbuf = rxtid->rxbuf + rxtid->baw_head; - if (!rxbuf->rx_wbuf) { - INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); - INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); - continue; - } - - if (drop) - dev_kfree_skb(rxbuf->rx_wbuf); - else - ath_rx_subframe(rxtid->an, - rxbuf->rx_wbuf, - &rxbuf->rx_status); - - rxbuf->rx_wbuf = NULL; + u64 tsf; - INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); - INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); - } - spin_unlock_irqrestore(&rxtid->tidlock, flag); + tsf = ath9k_hw_gettsf64(sc->sc_ah); + if ((tsf & 0x7fff) < rstamp) + tsf -= 0x8000; + return (tsf & ~0x7fff) | rstamp; } -static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, - u32 len) +static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, u32 len) { struct sk_buff *skb; u32 off; @@ -414,67 +104,131 @@ static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, skb_reserve(skb, sc->sc_cachelsz - off); } else { DPRINTF(sc, ATH_DBG_FATAL, - "%s: skbuff alloc of size %u failed\n", - __func__, len); + "skbuff alloc of size %u failed\n", len); return NULL; } return skb; } -static void ath_rx_requeue(struct ath_softc *sc, struct sk_buff *skb) +/* + * For Decrypt or Demic errors, we only mark packet status here and always push + * up the frame up to let mac80211 handle the actual error case, be it no + * decryption key or real decryption error. This let us keep statistics there. + */ +static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds, + struct ieee80211_rx_status *rx_status, bool *decrypt_error, + struct ath_softc *sc) { - struct ath_buf *bf = ATH_RX_CONTEXT(skb)->ctx_rxbuf; + struct ieee80211_hdr *hdr; + u8 ratecode; + __le16 fc; - ASSERT(bf != NULL); + hdr = (struct ieee80211_hdr *)skb->data; + fc = hdr->frame_control; + memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); - spin_lock_bh(&sc->sc_rxbuflock); - if (bf->bf_status & ATH_BUFSTATUS_STALE) { + if (ds->ds_rxstat.rs_more) { /* - * This buffer is still held for hw acess. - * Mark it as free to be re-queued it later. + * Frame spans multiple descriptors; this cannot happen yet + * as we don't support jumbograms. If not in monitor mode, + * discard the frame. Enable this if you want to see + * error frames in Monitor mode. */ - bf->bf_status |= ATH_BUFSTATUS_FREE; - } else { - /* XXX: we probably never enter here, remove after - * verification */ - list_add_tail(&bf->list, &sc->sc_rxbuf); - ath_rx_buf_link(sc, bf); + if (sc->sc_ah->ah_opmode != NL80211_IFTYPE_MONITOR) + goto rx_next; + } else if (ds->ds_rxstat.rs_status != 0) { + if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC) + rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; + if (ds->ds_rxstat.rs_status & ATH9K_RXERR_PHY) + goto rx_next; + + if (ds->ds_rxstat.rs_status & ATH9K_RXERR_DECRYPT) { + *decrypt_error = true; + } else if (ds->ds_rxstat.rs_status & ATH9K_RXERR_MIC) { + if (ieee80211_is_ctl(fc)) + /* + * Sometimes, we get invalid + * MIC failures on valid control frames. + * Remove these mic errors. + */ + ds->ds_rxstat.rs_status &= ~ATH9K_RXERR_MIC; + else + rx_status->flag |= RX_FLAG_MMIC_ERROR; + } + /* + * Reject error frames with the exception of + * decryption and MIC failures. For monitor mode, + * we also ignore the CRC error. + */ + if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_MONITOR) { + if (ds->ds_rxstat.rs_status & + ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | + ATH9K_RXERR_CRC)) + goto rx_next; + } else { + if (ds->ds_rxstat.rs_status & + ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) { + goto rx_next; + } + } } - spin_unlock_bh(&sc->sc_rxbuflock); -} -/* - * The skb indicated to upper stack won't be returned to us. - * So we have to allocate a new one and queue it by ourselves. - */ -static int ath_rx_indicate(struct ath_softc *sc, - struct sk_buff *skb, - struct ath_recv_status *status, - u16 keyix) -{ - struct ath_buf *bf = ATH_RX_CONTEXT(skb)->ctx_rxbuf; - struct sk_buff *nskb; - int type; - - /* indicate frame to the stack, which will free the old skb. */ - type = _ath_rx_indicate(sc, skb, status, keyix); - - /* allocate a new skb and queue it to for H/W processing */ - nskb = ath_rxbuf_alloc(sc, sc->sc_rxbufsize); - if (nskb != NULL) { - bf->bf_mpdu = nskb; - bf->bf_buf_addr = pci_map_single(sc->pdev, nskb->data, - sc->sc_rxbufsize, - PCI_DMA_FROMDEVICE); - bf->bf_dmacontext = bf->bf_buf_addr; - ATH_RX_CONTEXT(nskb)->ctx_rxbuf = bf; + ratecode = ds->ds_rxstat.rs_rate; + + if (ratecode & 0x80) { + /* HT rate */ + rx_status->flag |= RX_FLAG_HT; + if (ds->ds_rxstat.rs_flags & ATH9K_RX_2040) + rx_status->flag |= RX_FLAG_40MHZ; + if (ds->ds_rxstat.rs_flags & ATH9K_RX_GI) + rx_status->flag |= RX_FLAG_SHORT_GI; + rx_status->rate_idx = ratecode & 0x7f; + } else { + int i = 0, cur_band, n_rates; + struct ieee80211_hw *hw = sc->hw; - /* queue the new wbuf to H/W */ - ath_rx_requeue(sc, nskb); + cur_band = hw->conf.channel->band; + n_rates = sc->sbands[cur_band].n_bitrates; + + for (i = 0; i < n_rates; i++) { + if (sc->sbands[cur_band].bitrates[i].hw_value == + ratecode) { + rx_status->rate_idx = i; + break; + } + + if (sc->sbands[cur_band].bitrates[i].hw_value_short == + ratecode) { + rx_status->rate_idx = i; + rx_status->flag |= RX_FLAG_SHORTPRE; + break; + } + } } - return type; + rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp); + rx_status->band = sc->hw->conf.channel->band; + rx_status->freq = sc->hw->conf.channel->center_freq; + rx_status->noise = sc->sc_ani.sc_noise_floor; + rx_status->signal = rx_status->noise + ds->ds_rxstat.rs_rssi; + rx_status->antenna = ds->ds_rxstat.rs_antenna; + + /* at 45 you will be able to use MCS 15 reliably. A more elaborate + * scheme can be used here but it requires tables of SNR/throughput for + * each possible mode used. */ + rx_status->qual = ds->ds_rxstat.rs_rssi * 100 / 45; + + /* rssi can be more than 45 though, anything above that + * should be considered at 100% */ + if (rx_status->qual > 100) + rx_status->qual = 100; + + rx_status->flag |= RX_FLAG_TSFT; + + return 1; +rx_next: + return 0; } static void ath_opmode_init(struct ath_softc *sc) @@ -498,11 +252,7 @@ static void ath_opmode_init(struct ath_softc *sc) /* calculate and install multicast filter */ mfilt[0] = mfilt[1] = ~0; - ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]); - DPRINTF(sc, ATH_DBG_CONFIG , - "%s: RX filter 0x%x, MC filter %08x:%08x\n", - __func__, rfilt, mfilt[0], mfilt[1]); } int ath_rx_init(struct ath_softc *sc, int nbufs) @@ -512,38 +262,29 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) int error = 0; do { - spin_lock_init(&sc->sc_rxflushlock); + spin_lock_init(&sc->rx.rxflushlock); sc->sc_flags &= ~SC_OP_RXFLUSH; - spin_lock_init(&sc->sc_rxbuflock); + spin_lock_init(&sc->rx.rxbuflock); - /* - * Cisco's VPN software requires that drivers be able to - * receive encapsulated frames that are larger than the MTU. - * Since we can't be sure how large a frame we'll get, setup - * to handle the larges on possible. - */ - sc->sc_rxbufsize = roundup(IEEE80211_MAX_MPDU_LEN, + sc->rx.bufsize = roundup(IEEE80211_MAX_MPDU_LEN, min(sc->sc_cachelsz, (u16)64)); - DPRINTF(sc, ATH_DBG_CONFIG, "%s: cachelsz %u rxbufsize %u\n", - __func__, sc->sc_cachelsz, sc->sc_rxbufsize); + DPRINTF(sc, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n", + sc->sc_cachelsz, sc->rx.bufsize); /* Initialize rx descriptors */ - error = ath_descdma_setup(sc, &sc->sc_rxdma, &sc->sc_rxbuf, + error = ath_descdma_setup(sc, &sc->rx.rxdma, &sc->rx.rxbuf, "rx", nbufs, 1); if (error != 0) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: failed to allocate rx descriptors: %d\n", - __func__, error); + "failed to allocate rx descriptors: %d\n", error); break; } - /* Pre-allocate a wbuf for each rx buffer */ - - list_for_each_entry(bf, &sc->sc_rxbuf, list) { - skb = ath_rxbuf_alloc(sc, sc->sc_rxbufsize); + list_for_each_entry(bf, &sc->rx.rxbuf, list) { + skb = ath_rxbuf_alloc(sc, sc->rx.bufsize); if (skb == NULL) { error = -ENOMEM; break; @@ -551,12 +292,20 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) bf->bf_mpdu = skb; bf->bf_buf_addr = pci_map_single(sc->pdev, skb->data, - sc->sc_rxbufsize, - PCI_DMA_FROMDEVICE); + sc->rx.bufsize, + PCI_DMA_FROMDEVICE); + if (unlikely(pci_dma_mapping_error(sc->pdev, + bf->bf_buf_addr))) { + dev_kfree_skb_any(skb); + bf->bf_mpdu = NULL; + DPRINTF(sc, ATH_DBG_CONFIG, + "pci_dma_mapping_error() on RX init\n"); + error = -ENOMEM; + break; + } bf->bf_dmacontext = bf->bf_buf_addr; - ATH_RX_CONTEXT(skb)->ctx_rxbuf = bf; } - sc->sc_rxlink = NULL; + sc->rx.rxlink = NULL; } while (0); @@ -566,23 +315,19 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) return error; } -/* Reclaim all rx queue resources */ - void ath_rx_cleanup(struct ath_softc *sc) { struct sk_buff *skb; struct ath_buf *bf; - list_for_each_entry(bf, &sc->sc_rxbuf, list) { + list_for_each_entry(bf, &sc->rx.rxbuf, list) { skb = bf->bf_mpdu; if (skb) dev_kfree_skb(skb); } - /* cleanup rx descriptors */ - - if (sc->sc_rxdma.dd_desc_len != 0) - ath_descdma_cleanup(sc, &sc->sc_rxdma, &sc->sc_rxbuf); + if (sc->rx.rxdma.dd_desc_len != 0) + ath_descdma_cleanup(sc, &sc->rx.rxdma, &sc->rx.rxbuf); } /* @@ -615,201 +360,115 @@ u32 ath_calcrxfilter(struct ath_softc *sc) | ATH9K_RX_FILTER_MCAST; /* If not a STA, enable processing of Probe Requests */ - if (sc->sc_ah->ah_opmode != ATH9K_M_STA) + if (sc->sc_ah->ah_opmode != NL80211_IFTYPE_STATION) rfilt |= ATH9K_RX_FILTER_PROBEREQ; /* Can't set HOSTAP into promiscous mode */ - if (((sc->sc_ah->ah_opmode != ATH9K_M_HOSTAP) && - (sc->rx_filter & FIF_PROMISC_IN_BSS)) || - (sc->sc_ah->ah_opmode == ATH9K_M_MONITOR)) { + if (((sc->sc_ah->ah_opmode != NL80211_IFTYPE_AP) && + (sc->rx.rxfilter & FIF_PROMISC_IN_BSS)) || + (sc->sc_ah->ah_opmode == NL80211_IFTYPE_MONITOR)) { rfilt |= ATH9K_RX_FILTER_PROM; /* ??? To prevent from sending ACK */ rfilt &= ~ATH9K_RX_FILTER_UCAST; } - if (((sc->sc_ah->ah_opmode == ATH9K_M_STA) && - (sc->rx_filter & FIF_BCN_PRBRESP_PROMISC)) || - (sc->sc_ah->ah_opmode == ATH9K_M_IBSS)) + if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION || + sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC) rfilt |= ATH9K_RX_FILTER_BEACON; /* If in HOSTAP mode, want to enable reception of PSPOLL frames & beacon frames */ - if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) + if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) rfilt |= (ATH9K_RX_FILTER_BEACON | ATH9K_RX_FILTER_PSPOLL); + return rfilt; #undef RX_FILTER_PRESERVE } -/* Enable the receive h/w following a reset. */ - int ath_startrecv(struct ath_softc *sc) { struct ath_hal *ah = sc->sc_ah; struct ath_buf *bf, *tbf; - spin_lock_bh(&sc->sc_rxbuflock); - if (list_empty(&sc->sc_rxbuf)) + spin_lock_bh(&sc->rx.rxbuflock); + if (list_empty(&sc->rx.rxbuf)) goto start_recv; - sc->sc_rxlink = NULL; - list_for_each_entry_safe(bf, tbf, &sc->sc_rxbuf, list) { - if (bf->bf_status & ATH_BUFSTATUS_STALE) { - /* restarting h/w, no need for holding descriptors */ - bf->bf_status &= ~ATH_BUFSTATUS_STALE; - /* - * Upper layer may not be done with the frame yet so - * we can't just re-queue it to hardware. Remove it - * from h/w queue. It'll be re-queued when upper layer - * returns the frame and ath_rx_requeue_mpdu is called. - */ - if (!(bf->bf_status & ATH_BUFSTATUS_FREE)) { - list_del(&bf->list); - continue; - } - } - /* chain descriptors */ + sc->rx.rxlink = NULL; + list_for_each_entry_safe(bf, tbf, &sc->rx.rxbuf, list) { ath_rx_buf_link(sc, bf); } /* We could have deleted elements so the list may be empty now */ - if (list_empty(&sc->sc_rxbuf)) + if (list_empty(&sc->rx.rxbuf)) goto start_recv; - bf = list_first_entry(&sc->sc_rxbuf, struct ath_buf, list); + bf = list_first_entry(&sc->rx.rxbuf, struct ath_buf, list); ath9k_hw_putrxbuf(ah, bf->bf_daddr); - ath9k_hw_rxena(ah); /* enable recv descriptors */ + ath9k_hw_rxena(ah); start_recv: - spin_unlock_bh(&sc->sc_rxbuflock); - ath_opmode_init(sc); /* set filters, etc. */ - ath9k_hw_startpcureceive(ah); /* re-enable PCU/DMA engine */ + spin_unlock_bh(&sc->rx.rxbuflock); + ath_opmode_init(sc); + ath9k_hw_startpcureceive(ah); + return 0; } -/* Disable the receive h/w in preparation for a reset. */ - bool ath_stoprecv(struct ath_softc *sc) { struct ath_hal *ah = sc->sc_ah; - u64 tsf; bool stopped; - ath9k_hw_stoppcurecv(ah); /* disable PCU */ - ath9k_hw_setrxfilter(ah, 0); /* clear recv filter */ - stopped = ath9k_hw_stopdmarecv(ah); /* disable DMA engine */ - mdelay(3); /* 3ms is long enough for 1 frame */ - tsf = ath9k_hw_gettsf64(ah); - sc->sc_rxlink = NULL; /* just in case */ + ath9k_hw_stoppcurecv(ah); + ath9k_hw_setrxfilter(ah, 0); + stopped = ath9k_hw_stopdmarecv(ah); + mdelay(3); /* 3ms is long enough for 1 frame */ + sc->rx.rxlink = NULL; + return stopped; } -/* Flush receive queue */ - void ath_flushrecv(struct ath_softc *sc) { - /* - * ath_rx_tasklet may be used to handle rx interrupt and flush receive - * queue at the same time. Use a lock to serialize the access of rx - * queue. - * ath_rx_tasklet cannot hold the spinlock while indicating packets. - * Instead, do not claim the spinlock but check for a flush in - * progress (see references to sc_rxflush) - */ - spin_lock_bh(&sc->sc_rxflushlock); + spin_lock_bh(&sc->rx.rxflushlock); sc->sc_flags |= SC_OP_RXFLUSH; - ath_rx_tasklet(sc, 1); - sc->sc_flags &= ~SC_OP_RXFLUSH; - spin_unlock_bh(&sc->sc_rxflushlock); + spin_unlock_bh(&sc->rx.rxflushlock); } -/* Process an individual frame */ - -int ath_rx_input(struct ath_softc *sc, - struct ath_node *an, - int is_ampdu, - struct sk_buff *skb, - struct ath_recv_status *rx_status, - enum ATH_RX_TYPE *status) -{ - if (is_ampdu && (sc->sc_flags & SC_OP_RXAGGR)) { - *status = ATH_RX_CONSUMED; - return ath_ampdu_input(sc, an, skb, rx_status); - } else { - *status = ATH_RX_NON_CONSUMED; - return -1; - } -} - -/* Process receive queue, as well as LED, etc. */ - int ath_rx_tasklet(struct ath_softc *sc, int flush) { #define PA2DESC(_sc, _pa) \ - ((struct ath_desc *)((caddr_t)(_sc)->sc_rxdma.dd_desc + \ - ((_pa) - (_sc)->sc_rxdma.dd_desc_paddr))) + ((struct ath_desc *)((caddr_t)(_sc)->rx.rxdma.dd_desc + \ + ((_pa) - (_sc)->rx.rxdma.dd_desc_paddr))) - struct ath_buf *bf, *bf_held = NULL; + struct ath_buf *bf; struct ath_desc *ds; - struct ieee80211_hdr *hdr; - struct sk_buff *skb = NULL; - struct ath_recv_status rx_status; + struct sk_buff *skb = NULL, *requeue_skb; + struct ieee80211_rx_status rx_status; struct ath_hal *ah = sc->sc_ah; - int type, rx_processed = 0; - u32 phyerr; - u8 chainreset = 0; - int retval; - __le16 fc; + struct ieee80211_hdr *hdr; + int hdrlen, padsize, retval; + bool decrypt_error = false; + u8 keyix; + + spin_lock_bh(&sc->rx.rxbuflock); do { /* If handling rx interrupt and flush is in progress => exit */ if ((sc->sc_flags & SC_OP_RXFLUSH) && (flush == 0)) break; - spin_lock_bh(&sc->sc_rxbuflock); - if (list_empty(&sc->sc_rxbuf)) { - sc->sc_rxlink = NULL; - spin_unlock_bh(&sc->sc_rxbuflock); + if (list_empty(&sc->rx.rxbuf)) { + sc->rx.rxlink = NULL; break; } - bf = list_first_entry(&sc->sc_rxbuf, struct ath_buf, list); - - /* - * There is a race condition that BH gets scheduled after sw - * writes RxE and before hw re-load the last descriptor to get - * the newly chained one. Software must keep the last DONE - * descriptor as a holding descriptor - software does so by - * marking it with the STALE flag. - */ - if (bf->bf_status & ATH_BUFSTATUS_STALE) { - bf_held = bf; - if (list_is_last(&bf_held->list, &sc->sc_rxbuf)) { - /* - * The holding descriptor is the last - * descriptor in queue. It's safe to - * remove the last holding descriptor - * in BH context. - */ - list_del(&bf_held->list); - bf_held->bf_status &= ~ATH_BUFSTATUS_STALE; - sc->sc_rxlink = NULL; - - if (bf_held->bf_status & ATH_BUFSTATUS_FREE) { - list_add_tail(&bf_held->list, - &sc->sc_rxbuf); - ath_rx_buf_link(sc, bf_held); - } - spin_unlock_bh(&sc->sc_rxbuflock); - break; - } - bf = list_entry(bf->list.next, struct ath_buf, list); - } - + bf = list_first_entry(&sc->rx.rxbuf, struct ath_buf, list); ds = bf->bf_desc; - ++rx_processed; /* * Must provide the virtual address of the current @@ -822,8 +481,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) * on. All this is necessary because of our use of * a self-linked list to avoid rx overruns. */ - retval = ath9k_hw_rxprocdesc(ah, - ds, + retval = ath9k_hw_rxprocdesc(ah, ds, bf->bf_daddr, PA2DESC(sc, ds->ds_link), 0); @@ -831,8 +489,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) struct ath_buf *tbf; struct ath_desc *tds; - if (list_is_last(&bf->list, &sc->sc_rxbuf)) { - spin_unlock_bh(&sc->sc_rxbuflock); + if (list_is_last(&bf->list, &sc->rx.rxbuf)) { + sc->rx.rxlink = NULL; break; } @@ -850,451 +508,127 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) */ tds = tbf->bf_desc; - retval = ath9k_hw_rxprocdesc(ah, - tds, tbf->bf_daddr, - PA2DESC(sc, tds->ds_link), 0); + retval = ath9k_hw_rxprocdesc(ah, tds, tbf->bf_daddr, + PA2DESC(sc, tds->ds_link), 0); if (retval == -EINPROGRESS) { - spin_unlock_bh(&sc->sc_rxbuflock); break; } } - /* XXX: we do not support frames spanning - * multiple descriptors */ - bf->bf_status |= ATH_BUFSTATUS_DONE; - skb = bf->bf_mpdu; - if (skb == NULL) { /* XXX ??? can this happen */ - spin_unlock_bh(&sc->sc_rxbuflock); + if (!skb) continue; - } + /* - * Now we know it's a completed frame, we can indicate the - * frame. Remove the previous holding descriptor and leave - * this one in the queue as the new holding descriptor. + * Synchronize the DMA transfer with CPU before + * 1. accessing the frame + * 2. requeueing the same buffer to h/w */ - if (bf_held) { - list_del(&bf_held->list); - bf_held->bf_status &= ~ATH_BUFSTATUS_STALE; - if (bf_held->bf_status & ATH_BUFSTATUS_FREE) { - list_add_tail(&bf_held->list, &sc->sc_rxbuf); - /* try to requeue this descriptor */ - ath_rx_buf_link(sc, bf_held); - } - } + pci_dma_sync_single_for_cpu(sc->pdev, bf->bf_buf_addr, + sc->rx.bufsize, + PCI_DMA_FROMDEVICE); - bf->bf_status |= ATH_BUFSTATUS_STALE; - bf_held = bf; /* - * Release the lock here in case ieee80211_input() return - * the frame immediately by calling ath_rx_mpdu_requeue(). + * If we're asked to flush receive queue, directly + * chain it back at the queue without processing it. */ - spin_unlock_bh(&sc->sc_rxbuflock); + if (flush) + goto requeue; - if (flush) { - /* - * If we're asked to flush receive queue, directly - * chain it back at the queue without processing it. - */ - goto rx_next; - } + if (!ds->ds_rxstat.rs_datalen) + goto requeue; - hdr = (struct ieee80211_hdr *)skb->data; - fc = hdr->frame_control; - memset(&rx_status, 0, sizeof(struct ath_recv_status)); + /* The status portion of the descriptor could get corrupted. */ + if (sc->rx.bufsize < ds->ds_rxstat.rs_datalen) + goto requeue; - if (ds->ds_rxstat.rs_more) { - /* - * Frame spans multiple descriptors; this - * cannot happen yet as we don't support - * jumbograms. If not in monitor mode, - * discard the frame. - */ -#ifndef ERROR_FRAMES - /* - * Enable this if you want to see - * error frames in Monitor mode. - */ - if (sc->sc_ah->ah_opmode != ATH9K_M_MONITOR) - goto rx_next; -#endif - /* fall thru for monitor mode handling... */ - } else if (ds->ds_rxstat.rs_status != 0) { - if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC) - rx_status.flags |= ATH_RX_FCS_ERROR; - if (ds->ds_rxstat.rs_status & ATH9K_RXERR_PHY) { - phyerr = ds->ds_rxstat.rs_phyerr & 0x1f; - goto rx_next; - } + if (!ath_rx_prepare(skb, ds, &rx_status, &decrypt_error, sc)) + goto requeue; + + /* Ensure we always have an skb to requeue once we are done + * processing the current buffer's skb */ + requeue_skb = ath_rxbuf_alloc(sc, sc->rx.bufsize); + + /* If there is no memory we ignore the current RX'd frame, + * tell hardware it can give us a new frame using the old + * skb and put it at the tail of the sc->rx.rxbuf list for + * processing. */ + if (!requeue_skb) + goto requeue; + + /* Unmap the frame */ + pci_unmap_single(sc->pdev, bf->bf_buf_addr, + sc->rx.bufsize, + PCI_DMA_FROMDEVICE); - if (ds->ds_rxstat.rs_status & ATH9K_RXERR_DECRYPT) { - /* - * Decrypt error. We only mark packet status - * here and always push up the frame up to let - * mac80211 handle the actual error case, be - * it no decryption key or real decryption - * error. This let us keep statistics there. - */ - rx_status.flags |= ATH_RX_DECRYPT_ERROR; - } else if (ds->ds_rxstat.rs_status & ATH9K_RXERR_MIC) { - /* - * Demic error. We only mark frame status here - * and always push up the frame up to let - * mac80211 handle the actual error case. This - * let us keep statistics there. Hardware may - * post a false-positive MIC error. - */ - if (ieee80211_is_ctl(fc)) - /* - * Sometimes, we get invalid - * MIC failures on valid control frames. - * Remove these mic errors. - */ - ds->ds_rxstat.rs_status &= - ~ATH9K_RXERR_MIC; - else - rx_status.flags |= ATH_RX_MIC_ERROR; - } - /* - * Reject error frames with the exception of - * decryption and MIC failures. For monitor mode, - * we also ignore the CRC error. - */ - if (sc->sc_ah->ah_opmode == ATH9K_M_MONITOR) { - if (ds->ds_rxstat.rs_status & - ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | - ATH9K_RXERR_CRC)) - goto rx_next; - } else { - if (ds->ds_rxstat.rs_status & - ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) { - goto rx_next; - } - } - } - /* - * The status portion of the descriptor could get corrupted. - */ - if (sc->sc_rxbufsize < ds->ds_rxstat.rs_datalen) - goto rx_next; - /* - * Sync and unmap the frame. At this point we're - * committed to passing the sk_buff somewhere so - * clear buf_skb; this means a new sk_buff must be - * allocated when the rx descriptor is setup again - * to receive another frame. - */ skb_put(skb, ds->ds_rxstat.rs_datalen); skb->protocol = cpu_to_be16(ETH_P_CONTROL); - rx_status.tsf = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp); - rx_status.rateieee = - sc->sc_hwmap[ds->ds_rxstat.rs_rate].ieeerate; - rx_status.rateKbps = - sc->sc_hwmap[ds->ds_rxstat.rs_rate].rateKbps; - rx_status.ratecode = ds->ds_rxstat.rs_rate; - /* HT rate */ - if (rx_status.ratecode & 0x80) { - /* TODO - add table to avoid division */ - if (ds->ds_rxstat.rs_flags & ATH9K_RX_2040) { - rx_status.flags |= ATH_RX_40MHZ; - rx_status.rateKbps = - (rx_status.rateKbps * 27) / 13; - } - if (ds->ds_rxstat.rs_flags & ATH9K_RX_GI) - rx_status.rateKbps = - (rx_status.rateKbps * 10) / 9; - else - rx_status.flags |= ATH_RX_SHORT_GI; + /* see if any padding is done by the hw and remove it */ + hdr = (struct ieee80211_hdr *)skb->data; + hdrlen = ieee80211_get_hdrlen_from_skb(skb); + + /* The MAC header is padded to have 32-bit boundary if the + * packet payload is non-zero. The general calculation for + * padsize would take into account odd header lengths: + * padsize = (4 - hdrlen % 4) % 4; However, since only + * even-length headers are used, padding can only be 0 or 2 + * bytes and we can optimize this a bit. In addition, we must + * not try to remove padding from short control frames that do + * not have payload. */ + padsize = hdrlen & 3; + if (padsize && hdrlen >= 24) { + memmove(skb->data + padsize, skb->data, hdrlen); + skb_pull(skb, padsize); } - /* sc_noise_floor is only available when the station - attaches to an AP, so we use a default value - if we are not yet attached. */ - rx_status.abs_rssi = - ds->ds_rxstat.rs_rssi + sc->sc_ani.sc_noise_floor; - - pci_dma_sync_single_for_cpu(sc->pdev, - bf->bf_buf_addr, - sc->sc_rxbufsize, - PCI_DMA_FROMDEVICE); - pci_unmap_single(sc->pdev, - bf->bf_buf_addr, - sc->sc_rxbufsize, - PCI_DMA_FROMDEVICE); + keyix = ds->ds_rxstat.rs_keyix; - /* XXX: Ah! make me more readable, use a helper */ - if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) { - if (ds->ds_rxstat.rs_moreaggr == 0) { - rx_status.rssictl[0] = - ds->ds_rxstat.rs_rssi_ctl0; - rx_status.rssictl[1] = - ds->ds_rxstat.rs_rssi_ctl1; - rx_status.rssictl[2] = - ds->ds_rxstat.rs_rssi_ctl2; - rx_status.rssi = ds->ds_rxstat.rs_rssi; - if (ds->ds_rxstat.rs_flags & ATH9K_RX_2040) { - rx_status.rssiextn[0] = - ds->ds_rxstat.rs_rssi_ext0; - rx_status.rssiextn[1] = - ds->ds_rxstat.rs_rssi_ext1; - rx_status.rssiextn[2] = - ds->ds_rxstat.rs_rssi_ext2; - rx_status.flags |= - ATH_RX_RSSI_EXTN_VALID; - } - rx_status.flags |= ATH_RX_RSSI_VALID | - ATH_RX_CHAIN_RSSI_VALID; - } - } else { - /* - * Need to insert the "combined" rssi into the - * status structure for upper layer processing - */ - rx_status.rssi = ds->ds_rxstat.rs_rssi; - rx_status.flags |= ATH_RX_RSSI_VALID; + if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) { + rx_status.flag |= RX_FLAG_DECRYPTED; + } else if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED) + && !decrypt_error && skb->len >= hdrlen + 4) { + keyix = skb->data[hdrlen + 3] >> 6; + + if (test_bit(keyix, sc->sc_keymap)) + rx_status.flag |= RX_FLAG_DECRYPTED; } - /* Pass frames up to the stack. */ + /* Send the frame to mac80211 */ + __ieee80211_rx(sc->hw, skb, &rx_status); - type = ath_rx_indicate(sc, skb, - &rx_status, ds->ds_rxstat.rs_keyix); + /* We will now give hardware our shiny new allocated skb */ + bf->bf_mpdu = requeue_skb; + bf->bf_buf_addr = pci_map_single(sc->pdev, requeue_skb->data, + sc->rx.bufsize, + PCI_DMA_FROMDEVICE); + if (unlikely(pci_dma_mapping_error(sc->pdev, + bf->bf_buf_addr))) { + dev_kfree_skb_any(requeue_skb); + bf->bf_mpdu = NULL; + DPRINTF(sc, ATH_DBG_CONFIG, + "pci_dma_mapping_error() on RX\n"); + break; + } + bf->bf_dmacontext = bf->bf_buf_addr; /* * change the default rx antenna if rx diversity chooses the * other antenna 3 times in a row. */ - if (sc->sc_defant != ds->ds_rxstat.rs_antenna) { - if (++sc->sc_rxotherant >= 3) - ath_setdefantenna(sc, - ds->ds_rxstat.rs_antenna); + if (sc->rx.defant != ds->ds_rxstat.rs_antenna) { + if (++sc->rx.rxotherant >= 3) + ath_setdefantenna(sc, ds->ds_rxstat.rs_antenna); } else { - sc->sc_rxotherant = 0; + sc->rx.rxotherant = 0; } +requeue: + list_move_tail(&bf->list, &sc->rx.rxbuf); + ath_rx_buf_link(sc, bf); + } while (1); -#ifdef CONFIG_SLOW_ANT_DIV - if ((rx_status.flags & ATH_RX_RSSI_VALID) && - ieee80211_is_beacon(fc)) { - ath_slow_ant_div(&sc->sc_antdiv, hdr, &ds->ds_rxstat); - } -#endif - /* - * For frames successfully indicated, the buffer will be - * returned to us by upper layers by calling - * ath_rx_mpdu_requeue, either synchronusly or asynchronously. - * So we don't want to do it here in this loop. - */ - continue; - -rx_next: - bf->bf_status |= ATH_BUFSTATUS_FREE; - } while (TRUE); - - if (chainreset) { - DPRINTF(sc, ATH_DBG_CONFIG, - "%s: Reset rx chain mask. " - "Do internal reset\n", __func__); - ASSERT(flush == 0); - ath_reset(sc, false); - } + spin_unlock_bh(&sc->rx.rxbuflock); return 0; #undef PA2DESC } - -/* Process ADDBA request in per-TID data structure */ - -int ath_rx_aggr_start(struct ath_softc *sc, - const u8 *addr, - u16 tid, - u16 *ssn) -{ - struct ath_arx_tid *rxtid; - struct ath_node *an; - struct ieee80211_hw *hw = sc->hw; - struct ieee80211_supported_band *sband; - u16 buffersize = 0; - - spin_lock_bh(&sc->node_lock); - an = ath_node_find(sc, (u8 *) addr); - spin_unlock_bh(&sc->node_lock); - - if (!an) { - DPRINTF(sc, ATH_DBG_AGGR, - "%s: Node not found to initialize RX aggregation\n", - __func__); - return -1; - } - - sband = hw->wiphy->bands[hw->conf.channel->band]; - buffersize = IEEE80211_MIN_AMPDU_BUF << - sband->ht_info.ampdu_factor; /* FIXME */ - - rxtid = &an->an_aggr.rx.tid[tid]; - - spin_lock_bh(&rxtid->tidlock); - if (sc->sc_flags & SC_OP_RXAGGR) { - /* Allow aggregation reception - * Adjust rx BA window size. Peer might indicate a - * zero buffer size for a _dont_care_ condition. - */ - if (buffersize) - rxtid->baw_size = min(buffersize, rxtid->baw_size); - - /* set rx sequence number */ - rxtid->seq_next = *ssn; - - /* Allocate the receive buffers for this TID */ - DPRINTF(sc, ATH_DBG_AGGR, - "%s: Allcating rxbuffer for TID %d\n", __func__, tid); - - if (rxtid->rxbuf == NULL) { - /* - * If the rxbuff is not NULL at this point, we *probably* - * already allocated the buffer on a previous ADDBA, - * and this is a subsequent ADDBA that got through. - * Don't allocate, but use the value in the pointer, - * we zero it out when we de-allocate. - */ - rxtid->rxbuf = kmalloc(ATH_TID_MAX_BUFS * - sizeof(struct ath_rxbuf), GFP_ATOMIC); - } - if (rxtid->rxbuf == NULL) { - DPRINTF(sc, ATH_DBG_AGGR, - "%s: Unable to allocate RX buffer, " - "refusing ADDBA\n", __func__); - } else { - /* Ensure the memory is zeroed out (all internal - * pointers are null) */ - memset(rxtid->rxbuf, 0, ATH_TID_MAX_BUFS * - sizeof(struct ath_rxbuf)); - DPRINTF(sc, ATH_DBG_AGGR, - "%s: Allocated @%p\n", __func__, rxtid->rxbuf); - - /* Allow aggregation reception */ - rxtid->addba_exchangecomplete = 1; - } - } - spin_unlock_bh(&rxtid->tidlock); - - return 0; -} - -/* Process DELBA */ - -int ath_rx_aggr_stop(struct ath_softc *sc, - const u8 *addr, - u16 tid) -{ - struct ath_node *an; - - spin_lock_bh(&sc->node_lock); - an = ath_node_find(sc, (u8 *) addr); - spin_unlock_bh(&sc->node_lock); - - if (!an) { - DPRINTF(sc, ATH_DBG_AGGR, - "%s: RX aggr stop for non-existent node\n", __func__); - return -1; - } - - ath_rx_aggr_teardown(sc, an, tid); - return 0; -} - -/* Rx aggregation tear down */ - -void ath_rx_aggr_teardown(struct ath_softc *sc, - struct ath_node *an, u8 tid) -{ - struct ath_arx_tid *rxtid = &an->an_aggr.rx.tid[tid]; - - if (!rxtid->addba_exchangecomplete) - return; - - del_timer_sync(&rxtid->timer); - ath_rx_flush_tid(sc, rxtid, 0); - rxtid->addba_exchangecomplete = 0; - - /* De-allocate the receive buffer array allocated when addba started */ - - if (rxtid->rxbuf) { - DPRINTF(sc, ATH_DBG_AGGR, - "%s: Deallocating TID %d rxbuff @%p\n", - __func__, tid, rxtid->rxbuf); - kfree(rxtid->rxbuf); - - /* Set pointer to null to avoid reuse*/ - rxtid->rxbuf = NULL; - } -} - -/* Initialize per-node receive state */ - -void ath_rx_node_init(struct ath_softc *sc, struct ath_node *an) -{ - if (sc->sc_flags & SC_OP_RXAGGR) { - struct ath_arx_tid *rxtid; - int tidno; - - /* Init per tid rx state */ - for (tidno = 0, rxtid = &an->an_aggr.rx.tid[tidno]; - tidno < WME_NUM_TID; - tidno++, rxtid++) { - rxtid->an = an; - rxtid->seq_reset = 1; - rxtid->seq_next = 0; - rxtid->baw_size = WME_MAX_BA; - rxtid->baw_head = rxtid->baw_tail = 0; - - /* - * Ensure the buffer pointer is null at this point - * (needs to be allocated when addba is received) - */ - - rxtid->rxbuf = NULL; - setup_timer(&rxtid->timer, ath_rx_timer, - (unsigned long)rxtid); - spin_lock_init(&rxtid->tidlock); - - /* ADDBA state */ - rxtid->addba_exchangecomplete = 0; - } - } -} - -void ath_rx_node_cleanup(struct ath_softc *sc, struct ath_node *an) -{ - if (sc->sc_flags & SC_OP_RXAGGR) { - struct ath_arx_tid *rxtid; - int tidno, i; - - /* Init per tid rx state */ - for (tidno = 0, rxtid = &an->an_aggr.rx.tid[tidno]; - tidno < WME_NUM_TID; - tidno++, rxtid++) { - - if (!rxtid->addba_exchangecomplete) - continue; - - /* must cancel timer first */ - del_timer_sync(&rxtid->timer); - - /* drop any pending sub-frames */ - ath_rx_flush_tid(sc, rxtid, 1); - - for (i = 0; i < ATH_TID_MAX_BUFS; i++) - ASSERT(rxtid->rxbuf[i].rx_wbuf == NULL); - - rxtid->addba_exchangecomplete = 0; - } - } - -} - -/* Cleanup per-node receive state */ - -void ath_rx_node_free(struct ath_softc *sc, struct ath_node *an) -{ - ath_rx_node_cleanup(sc, an); -} diff --git a/drivers/net/wireless/ath9k/reg.h b/drivers/net/wireless/ath9k/reg.h index 60617ae66209964890623a63b6c021d1fe3c3bcb..9fedb4911bc30b859ca87d907bdb8357c7a80178 100644 --- a/drivers/net/wireless/ath9k/reg.h +++ b/drivers/net/wireless/ath9k/reg.h @@ -671,7 +671,11 @@ #define AR_RC_APB 0x00000002 #define AR_RC_HOSTIF 0x00000100 -#define AR_WA 0x4004 +#define AR_WA 0x4004 +#define AR9285_WA_DEFAULT 0x004a05cb +#define AR9280_WA_DEFAULT 0x0040073f +#define AR_WA_DEFAULT 0x0000073f + #define AR_PM_STATE 0x4008 #define AR_PM_STATE_PME_D3COLD_VAUX 0x00100000 @@ -738,6 +742,8 @@ #define AR_SREV_REVISION_9280_21 2 #define AR_SREV_VERSION_9285 0xC0 #define AR_SREV_REVISION_9285_10 0 +#define AR_SREV_REVISION_9285_11 1 +#define AR_SREV_REVISION_9285_12 2 #define AR_SREV_9100_OR_LATER(_ah) \ (((_ah)->ah_macVersion >= AR_SREV_VERSION_5416_PCIE)) @@ -768,6 +774,16 @@ #define AR_SREV_9285(_ah) (((_ah)->ah_macVersion == AR_SREV_VERSION_9285)) #define AR_SREV_9285_10_OR_LATER(_ah) \ (((_ah)->ah_macVersion >= AR_SREV_VERSION_9285)) +#define AR_SREV_9285_11(_ah) \ + (AR_SREV_9280(ah) && ((_ah)->ah_macRev == AR_SREV_REVISION_9285_11)) +#define AR_SREV_9285_11_OR_LATER(_ah) \ + (((_ah)->ah_macVersion > AR_SREV_VERSION_9285) || \ + (AR_SREV_9285(ah) && ((_ah)->ah_macRev >= AR_SREV_REVISION_9285_11))) +#define AR_SREV_9285_12(_ah) \ + (AR_SREV_9280(ah) && ((_ah)->ah_macRev == AR_SREV_REVISION_9285_12)) +#define AR_SREV_9285_12_OR_LATER(_ah) \ + (((_ah)->ah_macVersion > AR_SREV_VERSION_9285) || \ + (AR_SREV_9285(ah) && ((_ah)->ah_macRev >= AR_SREV_REVISION_9285_12))) #define AR_RADIO_SREV_MAJOR 0xf0 #define AR_RAD5133_SREV_MAJOR 0xc0 @@ -1017,6 +1033,97 @@ enum { #define AR_AN_SYNTH9_REFDIVA 0xf8000000 #define AR_AN_SYNTH9_REFDIVA_S 27 +#define AR9285_AN_RF2G1 0x7820 +#define AR9285_AN_RF2G1_ENPACAL 0x00000800 +#define AR9285_AN_RF2G1_ENPACAL_S 11 +#define AR9285_AN_RF2G1_PDPADRV1 0x02000000 +#define AR9285_AN_RF2G1_PDPADRV1_S 25 +#define AR9285_AN_RF2G1_PDPADRV2 0x01000000 +#define AR9285_AN_RF2G1_PDPADRV2_S 24 +#define AR9285_AN_RF2G1_PDPAOUT 0x00800000 +#define AR9285_AN_RF2G1_PDPAOUT_S 23 + + +#define AR9285_AN_RF2G2 0x7824 +#define AR9285_AN_RF2G2_OFFCAL 0x00001000 +#define AR9285_AN_RF2G2_OFFCAL_S 12 + +#define AR9285_AN_RF2G3 0x7828 +#define AR9285_AN_RF2G3_PDVCCOMP 0x02000000 +#define AR9285_AN_RF2G3_PDVCCOMP_S 25 +#define AR9285_AN_RF2G3_OB_0 0x00E00000 +#define AR9285_AN_RF2G3_OB_0_S 21 +#define AR9285_AN_RF2G3_OB_1 0x001C0000 +#define AR9285_AN_RF2G3_OB_1_S 18 +#define AR9285_AN_RF2G3_OB_2 0x00038000 +#define AR9285_AN_RF2G3_OB_2_S 15 +#define AR9285_AN_RF2G3_OB_3 0x00007000 +#define AR9285_AN_RF2G3_OB_3_S 12 +#define AR9285_AN_RF2G3_OB_4 0x00000E00 +#define AR9285_AN_RF2G3_OB_4_S 9 + +#define AR9285_AN_RF2G3_DB1_0 0x000001C0 +#define AR9285_AN_RF2G3_DB1_0_S 6 +#define AR9285_AN_RF2G3_DB1_1 0x00000038 +#define AR9285_AN_RF2G3_DB1_1_S 3 +#define AR9285_AN_RF2G3_DB1_2 0x00000007 +#define AR9285_AN_RF2G3_DB1_2_S 0 +#define AR9285_AN_RF2G4 0x782C +#define AR9285_AN_RF2G4_DB1_3 0xE0000000 +#define AR9285_AN_RF2G4_DB1_3_S 29 +#define AR9285_AN_RF2G4_DB1_4 0x1C000000 +#define AR9285_AN_RF2G4_DB1_4_S 26 + +#define AR9285_AN_RF2G4_DB2_0 0x03800000 +#define AR9285_AN_RF2G4_DB2_0_S 23 +#define AR9285_AN_RF2G4_DB2_1 0x00700000 +#define AR9285_AN_RF2G4_DB2_1_S 20 +#define AR9285_AN_RF2G4_DB2_2 0x000E0000 +#define AR9285_AN_RF2G4_DB2_2_S 17 +#define AR9285_AN_RF2G4_DB2_3 0x0001C000 +#define AR9285_AN_RF2G4_DB2_3_S 14 +#define AR9285_AN_RF2G4_DB2_4 0x00003800 +#define AR9285_AN_RF2G4_DB2_4_S 11 + +#define AR9285_AN_RF2G6 0x7834 +#define AR9285_AN_RF2G6_CCOMP 0x00007800 +#define AR9285_AN_RF2G6_CCOMP_S 11 +#define AR9285_AN_RF2G6_OFFS 0x03f00000 +#define AR9285_AN_RF2G6_OFFS_S 20 + +#define AR9285_AN_RF2G7 0x7838 +#define AR9285_AN_RF2G7_PWDDB 0x00000002 +#define AR9285_AN_RF2G7_PWDDB_S 1 +#define AR9285_AN_RF2G7_PADRVGN2TAB0 0xE0000000 +#define AR9285_AN_RF2G7_PADRVGN2TAB0_S 29 + +#define AR9285_AN_RF2G8 0x783C +#define AR9285_AN_RF2G8_PADRVGN2TAB0 0x0001C000 +#define AR9285_AN_RF2G8_PADRVGN2TAB0_S 14 + + +#define AR9285_AN_RF2G9 0x7840 +#define AR9285_AN_RXTXBB1 0x7854 +#define AR9285_AN_RXTXBB1_PDRXTXBB1 0x00000020 +#define AR9285_AN_RXTXBB1_PDRXTXBB1_S 5 +#define AR9285_AN_RXTXBB1_PDV2I 0x00000080 +#define AR9285_AN_RXTXBB1_PDV2I_S 7 +#define AR9285_AN_RXTXBB1_PDDACIF 0x00000100 +#define AR9285_AN_RXTXBB1_PDDACIF_S 8 +#define AR9285_AN_RXTXBB1_SPARE9 0x00000001 +#define AR9285_AN_RXTXBB1_SPARE9_S 0 + +#define AR9285_AN_TOP2 0x7868 + +#define AR9285_AN_TOP3 0x786c +#define AR9285_AN_TOP3_XPABIAS_LVL 0x0000000C +#define AR9285_AN_TOP3_XPABIAS_LVL_S 2 +#define AR9285_AN_TOP3_PWDDAC 0x00800000 +#define AR9285_AN_TOP3_PWDDAC_S 23 + +#define AR9285_AN_TOP4 0x7870 +#define AR9285_AN_TOP4_DEFAULT 0x10142c00 + #define AR_STA_ID0 0x8000 #define AR_STA_ID1 0x8004 #define AR_STA_ID1_SADH_MASK 0x0000FFFF diff --git a/drivers/net/wireless/ath9k/regd.c b/drivers/net/wireless/ath9k/regd.c index 62e28887ccd3661dcffe155d57c54d8c9e27aaaa..64043e99facff0faef1838b01ca214c2d2f7c9b8 100644 --- a/drivers/net/wireless/ath9k/regd.c +++ b/drivers/net/wireless/ath9k/regd.c @@ -42,7 +42,7 @@ ath9k_regd_sort(void *a, u32 n, u32 size, ath_hal_cmp_t *cmp) u8 *u = t - size; if (cmp(u, t) <= 0) break; - swap(u, t, size); + swap_array(u, t, size); } } @@ -78,8 +78,7 @@ static bool ath9k_regd_is_eeprom_valid(struct ath_hal *ah) return true; } DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: invalid regulatory domain/country code 0x%x\n", - __func__, rd); + "invalid regulatory domain/country code 0x%x\n", rd); return false; } @@ -107,13 +106,12 @@ static bool ath9k_regd_is_ccode_valid(struct ath_hal *ah, return true; rd = ath9k_regd_get_eepromRD(ah); - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "%s: EEPROM regdomain 0x%x\n", - __func__, rd); + DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "EEPROM regdomain 0x%x\n", rd); if (rd & COUNTRY_ERD_FLAG) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: EEPROM setting is country code %u\n", - __func__, rd & ~COUNTRY_ERD_FLAG); + "EEPROM setting is country code %u\n", + rd & ~COUNTRY_ERD_FLAG); return cc == (rd & ~COUNTRY_ERD_FLAG); } @@ -290,8 +288,7 @@ ath9k_regd_get_wmode_regdomain(struct ath_hal *ah, int regDmn, } if (!found) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: Failed to find reg domain pair %u\n", - __func__, regDmn); + "Failed to find reg domain pair %u\n", regDmn); return false; } if (!(channelFlag & CHANNEL_2GHZ)) { @@ -307,8 +304,7 @@ ath9k_regd_get_wmode_regdomain(struct ath_hal *ah, int regDmn, found = ath9k_regd_is_valid_reg_domain(regDmn, rd); if (!found) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: Failed to find unitary reg domain %u\n", - __func__, regDmn); + "Failed to find unitary reg domain %u\n", regDmn); return false; } else { rd->pscan &= regPair->pscanMask; @@ -430,30 +426,27 @@ ath9k_regd_add_channel(struct ath_hal *ah, if (!(c_lo <= c && c <= c_hi)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: c %u out of range [%u..%u]\n", - __func__, c, c_lo, c_hi); + "c %u out of range [%u..%u]\n", + c, c_lo, c_hi); return false; } if ((fband->channelBW == CHANNEL_HALF_BW) && !(ah->ah_caps.hw_caps & ATH9K_HW_CAP_CHAN_HALFRATE)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: Skipping %u half rate channel\n", - __func__, c); + "Skipping %u half rate channel\n", c); return false; } if ((fband->channelBW == CHANNEL_QUARTER_BW) && !(ah->ah_caps.hw_caps & ATH9K_HW_CAP_CHAN_QUARTERRATE)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: Skipping %u quarter rate channel\n", - __func__, c); + "Skipping %u quarter rate channel\n", c); return false; } if (((c + fband->channelSep) / 2) > (maxChan + HALF_MAXCHANBW)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: c %u > maxChan %u\n", - __func__, c, maxChan); + "c %u > maxChan %u\n", c, maxChan); return false; } @@ -463,7 +456,7 @@ ath9k_regd_add_channel(struct ath_hal *ah, return false; } - if ((rd->flags & NO_HOSTAP) && (ah->ah_opmode == ATH9K_M_HOSTAP)) { + if ((rd->flags & NO_HOSTAP) && (ah->ah_opmode == NL80211_IFTYPE_AP)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "Skipping HOSTAP channel\n"); return false; @@ -606,8 +599,7 @@ static bool ath9k_regd_japan_check(struct ath_hal *ah, } DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: Skipping %d freq band\n", - __func__, j_bandcheck[i].freqbandbit); + "Skipping %d freq band\n", j_bandcheck[i].freqbandbit); return skipband; } @@ -632,20 +624,19 @@ ath9k_regd_init_channels(struct ath_hal *ah, unsigned long *modes_avail; DECLARE_BITMAP(modes_allowed, ATH9K_MODE_MAX); - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "%s: cc %u %s %s\n", - __func__, cc, + DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "cc %u %s %s\n", cc, enableOutdoor ? "Enable outdoor" : "", enableExtendedChannels ? "Enable ecm" : ""); if (!ath9k_regd_is_ccode_valid(ah, cc)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: invalid country code %d\n", __func__, cc); + "Invalid country code %d\n", cc); return false; } if (!ath9k_regd_is_eeprom_valid(ah)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: invalid EEPROM contents\n", __func__); + "Invalid EEPROM contents\n"); return false; } @@ -693,9 +684,9 @@ ath9k_regd_init_channels(struct ath_hal *ah, ~CHANNEL_2GHZ, &rd5GHz)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: couldn't find unitary " + "Couldn't find unitary " "5GHz reg domain for country %u\n", - __func__, ah->ah_countryCode); + ah->ah_countryCode); return false; } if (!ath9k_regd_get_wmode_regdomain(ah, @@ -703,9 +694,9 @@ ath9k_regd_init_channels(struct ath_hal *ah, CHANNEL_2GHZ, &rd2GHz)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: couldn't find unitary 2GHz " + "Couldn't find unitary 2GHz " "reg domain for country %u\n", - __func__, ah->ah_countryCode); + ah->ah_countryCode); return false; } @@ -717,9 +708,9 @@ ath9k_regd_init_channels(struct ath_hal *ah, ~CHANNEL_2GHZ, &rd5GHz)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: couldn't find unitary 5GHz " + "Couldn't find unitary 5GHz " "reg domain for country %u\n", - __func__, ah->ah_countryCode); + ah->ah_countryCode); return false; } } @@ -749,15 +740,14 @@ ath9k_regd_init_channels(struct ath_hal *ah, if (!test_bit(cm->mode, modes_avail)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: !avail mode %d flags 0x%x\n", - __func__, cm->mode, cm->flags); + "!avail mode %d flags 0x%x\n", + cm->mode, cm->flags); continue; } if (!ath9k_get_channel_edges(ah, cm->flags, &c_lo, &c_hi)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: channels 0x%x not supported " - "by hardware\n", - __func__, cm->flags); + "channels 0x%x not supported " + "by hardware\n", cm->flags); continue; } @@ -788,8 +778,7 @@ ath9k_regd_init_channels(struct ath_hal *ah, break; default: DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: Unknown HAL mode 0x%x\n", __func__, - cm->mode); + "Unknown HAL mode 0x%x\n", cm->mode); continue; } @@ -841,9 +830,8 @@ ath9k_regd_init_channels(struct ath_hal *ah, if (next >= maxchans) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: too many channels " - "for channel table\n", - __func__); + "too many channels " + "for channel table\n"); goto done; } if (ath9k_regd_add_channel(ah, @@ -869,9 +857,8 @@ ath9k_regd_init_channels(struct ath_hal *ah, if (next > ARRAY_SIZE(ah->ah_channels)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: too many channels %u; truncating to %u\n", - __func__, next, - (int) ARRAY_SIZE(ah->ah_channels)); + "too many channels %u; truncating to %u\n", + next, (int) ARRAY_SIZE(ah->ah_channels)); next = ARRAY_SIZE(ah->ah_channels); } #ifdef ATH_NF_PER_CHAN @@ -919,7 +906,7 @@ ath9k_regd_check_channel(struct ath_hal *ah, int n, lim; DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: channel %u/0x%x (0x%x) requested\n", __func__, + "channel %u/0x%x (0x%x) requested\n", c->channel, c->channelFlags, flags); cc = ah->ah_curchan; @@ -950,15 +937,15 @@ ath9k_regd_check_channel(struct ath_hal *ah, d = flags - (cc->channelFlags & CHAN_FLAGS); } DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: channel %u/0x%x d %d\n", __func__, + "channel %u/0x%x d %d\n", cc->channel, cc->channelFlags, d); if (d > 0) { base = cc + 1; lim--; } } - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "%s: no match for %u/0x%x\n", - __func__, c->channel, c->channelFlags); + DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "no match for %u/0x%x\n", + c->channel, c->channelFlags); return NULL; } diff --git a/drivers/net/wireless/ath9k/regd.h b/drivers/net/wireless/ath9k/regd.h index 0ecd344fbd988e3592624b90bb86ced5a32e30ae..512d990aa7ea352e44452158cb04742689add545 100644 --- a/drivers/net/wireless/ath9k/regd.h +++ b/drivers/net/wireless/ath9k/regd.h @@ -125,7 +125,7 @@ #define CHAN_FLAGS (CHANNEL_ALL|CHANNEL_HALF|CHANNEL_QUARTER) -#define swap(_a, _b, _size) { \ +#define swap_array(_a, _b, _size) { \ u8 *s = _b; \ int i = _size; \ do { \ diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 3a4757942b3fa80f5454bebffd468b4dc0103e76..3bfc3b90f2569013092e82959a03bfebdf39b979 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -14,10 +14,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* - * Implementation of transmit path. - */ - #include "core.h" #define BITS_PER_BYTE 8 @@ -65,11 +61,12 @@ static u32 bits_per_symbol[][2] = { * NB: must be called with txq lock held */ -static void ath_tx_txqaddbuf(struct ath_softc *sc, - struct ath_txq *txq, struct list_head *head) +static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, + struct list_head *head) { struct ath_hal *ah = sc->sc_ah; struct ath_buf *bf; + /* * Insert the frame on the outbound list and * pass it on to the hardware. @@ -86,18 +83,16 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, txq->axq_linkbuf = list_entry(txq->axq_q.prev, struct ath_buf, list); DPRINTF(sc, ATH_DBG_QUEUE, - "%s: txq depth = %d\n", __func__, txq->axq_depth); + "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth); if (txq->axq_link == NULL) { ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr); DPRINTF(sc, ATH_DBG_XMIT, - "%s: TXDP[%u] = %llx (%p)\n", - __func__, txq->axq_qnum, - ito64(bf->bf_daddr), bf->bf_desc); + "TXDP[%u] = %llx (%p)\n", + txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc); } else { *txq->axq_link = bf->bf_daddr; - DPRINTF(sc, ATH_DBG_XMIT, "%s: link[%u] (%p)=%llx (%p)\n", - __func__, + DPRINTF(sc, ATH_DBG_XMIT, "link[%u] (%p)=%llx (%p)\n", txq->axq_qnum, txq->axq_link, ito64(bf->bf_daddr), bf->bf_desc); } @@ -105,46 +100,94 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, ath9k_hw_txstart(ah, txq->axq_qnum); } -/* Get transmit rate index using rate in Kbps */ - -static int ath_tx_findindex(const struct ath9k_rate_table *rt, int rate) +static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, + struct ath_xmit_status *tx_status) { - int i; - int ndx = 0; + struct ieee80211_hw *hw = sc->hw; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); + int hdrlen, padsize; - for (i = 0; i < rt->rateCount; i++) { - if (rt->info[i].rateKbps == rate) { - ndx = i; - break; - } + DPRINTF(sc, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb); + + if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK || + tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) { + kfree(tx_info_priv); + tx_info->rate_driver_data[0] = NULL; + } + + if (tx_status->flags & ATH_TX_BAR) { + tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; + tx_status->flags &= ~ATH_TX_BAR; + } + + if (!(tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) { + /* Frame was ACKed */ + tx_info->flags |= IEEE80211_TX_STAT_ACK; + } + + tx_info->status.rates[0].count = tx_status->retries; + if (tx_info->status.rates[0].flags & IEEE80211_TX_RC_MCS) { + /* Change idx from internal table index to MCS index */ + int idx = tx_info->status.rates[0].idx; + struct ath_rate_table *rate_table = sc->cur_rate_table; + if (idx >= 0 && idx < rate_table->rate_cnt) + tx_info->status.rates[0].idx = + rate_table->info[idx].ratecode & 0x7f; + } + + hdrlen = ieee80211_get_hdrlen_from_skb(skb); + padsize = hdrlen & 3; + if (padsize && hdrlen >= 24) { + /* + * Remove MAC header padding before giving the frame back to + * mac80211. + */ + memmove(skb->data + padsize, skb->data, hdrlen); + skb_pull(skb, padsize); } - return ndx; + ieee80211_tx_status(hw, skb); } /* Check if it's okay to send out aggregates */ -static int ath_aggr_query(struct ath_softc *sc, - struct ath_node *an, u8 tidno) +static int ath_aggr_query(struct ath_softc *sc, struct ath_node *an, u8 tidno) { struct ath_atx_tid *tid; tid = ATH_AN_2_TID(an, tidno); - if (tid->addba_exchangecomplete || tid->addba_exchangeinprogress) + if (tid->state & AGGR_ADDBA_COMPLETE || + tid->state & AGGR_ADDBA_PROGRESS) return 1; else return 0; } -static enum ath9k_pkt_type get_hal_packet_type(struct ieee80211_hdr *hdr) +static void ath_get_beaconconfig(struct ath_softc *sc, int if_id, + struct ath_beacon_config *conf) +{ + struct ieee80211_hw *hw = sc->hw; + + /* fill in beacon config data */ + + conf->beacon_interval = hw->conf.beacon_int; + conf->listen_interval = 100; + conf->dtim_count = 1; + conf->bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf->listen_interval; +} + +/* Calculate Atheros packet type from IEEE80211 packet header */ + +static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb) { + struct ieee80211_hdr *hdr; enum ath9k_pkt_type htype; __le16 fc; + hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; - /* Calculate Atheros packet type from IEEE80211 packet header */ - if (ieee80211_is_beacon(fc)) htype = ATH9K_PKT_TYPE_BEACON; else if (ieee80211_is_probe_resp(fc)) @@ -159,232 +202,123 @@ static enum ath9k_pkt_type get_hal_packet_type(struct ieee80211_hdr *hdr) return htype; } -static void fill_min_rates(struct sk_buff *skb, struct ath_tx_control *txctl) +static bool is_pae(struct sk_buff *skb) { struct ieee80211_hdr *hdr; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ath_tx_info_priv *tx_info_priv; __le16 fc; hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; - tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; - if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)) { - txctl->use_minrate = 1; - txctl->min_rate = tx_info_priv->min_rate; - } else if (ieee80211_is_data(fc)) { + if (ieee80211_is_data(fc)) { if (ieee80211_is_nullfunc(fc) || - /* Port Access Entity (IEEE 802.1X) */ - (skb->protocol == cpu_to_be16(0x888E))) { - txctl->use_minrate = 1; - txctl->min_rate = tx_info_priv->min_rate; + /* Port Access Entity (IEEE 802.1X) */ + (skb->protocol == cpu_to_be16(ETH_P_PAE))) { + return true; } - if (is_multicast_ether_addr(hdr->addr1)) - txctl->mcast_rate = tx_info_priv->min_rate; } + return false; } -/* This function will setup additional txctl information, mostly rate stuff */ -/* FIXME: seqno, ps */ -static int ath_tx_prepare(struct ath_softc *sc, - struct sk_buff *skb, - struct ath_tx_control *txctl) +static int get_hw_crypto_keytype(struct sk_buff *skb) { - struct ieee80211_hw *hw = sc->hw; - struct ieee80211_hdr *hdr; - struct ath_rc_series *rcs; - struct ath_txq *txq = NULL; - const struct ath9k_rate_table *rt; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ath_tx_info_priv *tx_info_priv; - int hdrlen; - u8 rix, antenna; - __le16 fc; - u8 *qc; - - txctl->dev = sc; - hdr = (struct ieee80211_hdr *)skb->data; - hdrlen = ieee80211_get_hdrlen_from_skb(skb); - fc = hdr->frame_control; - - rt = sc->sc_currates; - BUG_ON(!rt); - - /* Fill misc fields */ - - spin_lock_bh(&sc->node_lock); - txctl->an = ath_node_get(sc, hdr->addr1); - /* create a temp node, if the node is not there already */ - if (!txctl->an) - txctl->an = ath_node_attach(sc, hdr->addr1, 0); - spin_unlock_bh(&sc->node_lock); - - if (ieee80211_is_data_qos(fc)) { - qc = ieee80211_get_qos_ctl(hdr); - txctl->tidno = qc[0] & 0xf; - } - - txctl->if_id = 0; - txctl->frmlen = skb->len + FCS_LEN - (hdrlen & 3); - txctl->txpower = MAX_RATE_POWER; /* FIXME */ - - /* Fill Key related fields */ - - txctl->keytype = ATH9K_KEY_TYPE_CLEAR; - txctl->keyix = ATH9K_TXKEYIX_INVALID; if (tx_info->control.hw_key) { - txctl->keyix = tx_info->control.hw_key->hw_key_idx; - txctl->frmlen += tx_info->control.hw_key->icv_len; - if (tx_info->control.hw_key->alg == ALG_WEP) - txctl->keytype = ATH9K_KEY_TYPE_WEP; + return ATH9K_KEY_TYPE_WEP; else if (tx_info->control.hw_key->alg == ALG_TKIP) - txctl->keytype = ATH9K_KEY_TYPE_TKIP; + return ATH9K_KEY_TYPE_TKIP; else if (tx_info->control.hw_key->alg == ALG_CCMP) - txctl->keytype = ATH9K_KEY_TYPE_AES; - } - - /* Fill packet type */ - - txctl->atype = get_hal_packet_type(hdr); - - /* Fill qnum */ - - if (unlikely(txctl->flags & ATH9K_TXDESC_CAB)) { - txctl->qnum = 0; - txq = sc->sc_cabq; - } else { - txctl->qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc); - txq = &sc->sc_txq[txctl->qnum]; - } - spin_lock_bh(&txq->axq_lock); - - /* Try to avoid running out of descriptors */ - if (txq->axq_depth >= (ATH_TXBUF - 20) && - !(txctl->flags & ATH9K_TXDESC_CAB)) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: TX queue: %d is full, depth: %d\n", - __func__, - txctl->qnum, - txq->axq_depth); - ieee80211_stop_queue(hw, skb_get_queue_mapping(skb)); - txq->stopped = 1; - spin_unlock_bh(&txq->axq_lock); - return -1; + return ATH9K_KEY_TYPE_AES; } - spin_unlock_bh(&txq->axq_lock); - - /* Fill rate */ - - fill_min_rates(skb, txctl); + return ATH9K_KEY_TYPE_CLEAR; +} - /* Fill flags */ +/* Called only when tx aggregation is enabled and HT is supported */ - txctl->flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */ +static void assign_aggr_tid_seqno(struct sk_buff *skb, + struct ath_buf *bf) +{ + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr; + struct ath_node *an; + struct ath_atx_tid *tid; + __le16 fc; + u8 *qc; - if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) - txctl->flags |= ATH9K_TXDESC_NOACK; - if (tx_info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) - txctl->flags |= ATH9K_TXDESC_RTSENA; + if (!tx_info->control.sta) + return; - /* - * Setup for rate calculations. - */ - tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; - rcs = tx_info_priv->rcs; + an = (struct ath_node *)tx_info->control.sta->drv_priv; + hdr = (struct ieee80211_hdr *)skb->data; + fc = hdr->frame_control; - if (ieee80211_is_data(fc) && !txctl->use_minrate) { + /* Get tidno */ - /* Enable HT only for DATA frames and not for EAPOL */ - txctl->ht = (hw->conf.ht_conf.ht_supported && - (tx_info->flags & IEEE80211_TX_CTL_AMPDU)); + if (ieee80211_is_data_qos(fc)) { + qc = ieee80211_get_qos_ctl(hdr); + bf->bf_tidno = qc[0] & 0xf; + } - if (is_multicast_ether_addr(hdr->addr1)) { - rcs[0].rix = (u8) - ath_tx_findindex(rt, txctl->mcast_rate); + /* Get seqno */ - /* - * mcast packets are not re-tried. - */ - rcs[0].tries = 1; - } + if (ieee80211_is_data(fc) && !is_pae(skb)) { /* For HT capable stations, we save tidno for later use. * We also override seqno set by upper layer with the one * in tx aggregation state. * - * First, the fragmentation stat is determined. * If fragmentation is on, the sequence number is * not overridden, since it has been * incremented by the fragmentation routine. + * + * FIXME: check if the fragmentation threshold exceeds + * IEEE80211 max. */ - if (likely(!(txctl->flags & ATH9K_TXDESC_FRAG_IS_ON)) && - txctl->ht && (sc->sc_flags & SC_OP_TXAGGR)) { - struct ath_atx_tid *tid; + tid = ATH_AN_2_TID(an, bf->bf_tidno); + hdr->seq_ctrl = cpu_to_le16(tid->seq_next << + IEEE80211_SEQ_SEQ_SHIFT); + bf->bf_seqno = tid->seq_next; + INCR(tid->seq_next, IEEE80211_SEQ_MAX); + } +} - tid = ATH_AN_2_TID(txctl->an, txctl->tidno); +static int setup_tx_flags(struct ath_softc *sc, struct sk_buff *skb, + struct ath_txq *txq) +{ + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + int flags = 0; - hdr->seq_ctrl = cpu_to_le16(tid->seq_next << - IEEE80211_SEQ_SEQ_SHIFT); - txctl->seqno = tid->seq_next; - INCR(tid->seq_next, IEEE80211_SEQ_MAX); - } - } else { - /* for management and control frames, - * or for NULL and EAPOL frames */ - if (txctl->min_rate) - rcs[0].rix = ath_rate_findrateix(sc, txctl->min_rate); - else - rcs[0].rix = 0; - rcs[0].tries = ATH_MGT_TXMAXTRY; - } - rix = rcs[0].rix; + flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */ + flags |= ATH9K_TXDESC_INTREQ; - if (ieee80211_has_morefrags(fc) || - (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) { - /* - ** Force hardware to use computed duration for next - ** fragment by disabling multi-rate retry, which - ** updates duration based on the multi-rate - ** duration table. - */ - rcs[1].tries = rcs[2].tries = rcs[3].tries = 0; - rcs[1].rix = rcs[2].rix = rcs[3].rix = 0; - /* reset tries but keep rate index */ - rcs[0].tries = ATH_TXMAXTRY; - } + if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) + flags |= ATH9K_TXDESC_NOACK; + if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) + flags |= ATH9K_TXDESC_RTSENA; - /* - * Determine if a tx interrupt should be generated for - * this descriptor. We take a tx interrupt to reap - * descriptors when the h/w hits an EOL condition or - * when the descriptor is specifically marked to generate - * an interrupt. We periodically mark descriptors in this - * way to insure timely replenishing of the supply needed - * for sending frames. Defering interrupts reduces system - * load and potentially allows more concurrent work to be - * done but if done to aggressively can cause senders to - * backup. - * - * NB: use >= to deal with sc_txintrperiod changing - * dynamically through sysctl. - */ - spin_lock_bh(&txq->axq_lock); - if ((++txq->axq_intrcnt >= sc->sc_txintrperiod)) { - txctl->flags |= ATH9K_TXDESC_INTREQ; - txq->axq_intrcnt = 0; - } - spin_unlock_bh(&txq->axq_lock); + return flags; +} + +static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc) +{ + struct ath_buf *bf = NULL; - if (is_multicast_ether_addr(hdr->addr1)) { - antenna = sc->sc_mcastantenna + 1; - sc->sc_mcastantenna = (sc->sc_mcastantenna + 1) & 0x1; + spin_lock_bh(&sc->tx.txbuflock); + + if (unlikely(list_empty(&sc->tx.txbuf))) { + spin_unlock_bh(&sc->tx.txbuflock); + return NULL; } - return 0; + bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list); + list_del(&bf->list); + + spin_unlock_bh(&sc->tx.txbuflock); + + return bf; } /* To complete a chain of buffers associated a frame */ @@ -396,6 +330,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc, { struct sk_buff *skb = bf->bf_mpdu; struct ath_xmit_status tx_status; + unsigned long flags; /* * Set retry information. @@ -414,20 +349,21 @@ static void ath_tx_complete_buf(struct ath_softc *sc, if (bf_isxretried(bf)) tx_status.flags |= ATH_TX_XRETRY; } + /* Unmap this frame */ pci_unmap_single(sc->pdev, bf->bf_dmacontext, skb->len, PCI_DMA_TODEVICE); /* complete this frame */ - ath_tx_complete(sc, skb, &tx_status, bf->bf_node); + ath_tx_complete(sc, skb, &tx_status); /* * Return the list of ath_buf of this mpdu to free queue */ - spin_lock_bh(&sc->sc_txbuflock); - list_splice_tail_init(bf_q, &sc->sc_txbuf); - spin_unlock_bh(&sc->sc_txbuflock); + spin_lock_irqsave(&sc->tx.txbuflock, flags); + list_splice_tail_init(bf_q, &sc->tx.txbuf); + spin_unlock_irqrestore(&sc->tx.txbuflock, flags); } /* @@ -468,7 +404,7 @@ static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid) static void ath_tx_pause_tid(struct ath_softc *sc, struct ath_atx_tid *tid) { - struct ath_txq *txq = &sc->sc_txq[tid->ac->qnum]; + struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum]; spin_lock_bh(&txq->axq_lock); @@ -481,7 +417,7 @@ static void ath_tx_pause_tid(struct ath_softc *sc, struct ath_atx_tid *tid) void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid) { - struct ath_txq *txq = &sc->sc_txq[tid->ac->qnum]; + struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum]; ASSERT(tid->paused > 0); spin_lock_bh(&txq->axq_lock); @@ -505,11 +441,9 @@ void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid) /* Compute the number of bad frames */ -static int ath_tx_num_badfrms(struct ath_softc *sc, - struct ath_buf *bf, int txok) +static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf, + int txok) { - struct ath_node *an = bf->bf_node; - int isnodegone = (an->an_flags & ATH_NODE_CLEAN); struct ath_buf *bf_last = bf->bf_lastbf; struct ath_desc *ds = bf_last->bf_desc; u16 seq_st = 0; @@ -518,7 +452,7 @@ static int ath_tx_num_badfrms(struct ath_softc *sc, int nbad = 0; int isaggr = 0; - if (isnodegone || ds->ds_txstat.ts_flags == ATH9K_TX_SW_ABORTED) + if (ds->ds_txstat.ts_flags == ATH9K_TX_SW_ABORTED) return 0; isaggr = bf_isaggr(bf); @@ -553,8 +487,8 @@ static void ath_tx_set_retry(struct ath_softc *sc, struct ath_buf *bf) /* Update block ack window */ -static void ath_tx_update_baw(struct ath_softc *sc, - struct ath_atx_tid *tid, int seqno) +static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, + int seqno) { int index, cindex; @@ -577,34 +511,23 @@ static void ath_tx_update_baw(struct ath_softc *sc, * width - 0 for 20 MHz, 1 for 40 MHz * half_gi - to use 4us v/s 3.6 us for symbol time */ - -static u32 ath_pkt_duration(struct ath_softc *sc, - u8 rix, - struct ath_buf *bf, - int width, - int half_gi, - bool shortPreamble) +static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf, + int width, int half_gi, bool shortPreamble) { - const struct ath9k_rate_table *rt = sc->sc_currates; + struct ath_rate_table *rate_table = sc->cur_rate_table; u32 nbits, nsymbits, duration, nsymbols; u8 rc; int streams, pktlen; pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen; - rc = rt->info[rix].rateCode; + rc = rate_table->info[rix].ratecode; - /* - * for legacy rates, use old function to compute packet duration - */ + /* for legacy rates, use old function to compute packet duration */ if (!IS_HT_RATE(rc)) - return ath9k_hw_computetxtime(sc->sc_ah, - rt, - pktlen, - rix, - shortPreamble); - /* - * find number of symbols: PLCP + data - */ + return ath9k_hw_computetxtime(sc->sc_ah, rate_table, pktlen, + rix, shortPreamble); + + /* find number of symbols: PLCP + data */ nbits = (pktlen << 3) + OFDM_PLCP_BITS; nsymbits = bits_per_symbol[HT_RC_2_MCS(rc)][width]; nsymbols = (nbits + nsymbits - 1) / nsymbits; @@ -614,11 +537,10 @@ static u32 ath_pkt_duration(struct ath_softc *sc, else duration = SYMBOL_TIME_HALFGI(nsymbols); - /* - * addup duration for legacy/ht training and signal fields - */ + /* addup duration for legacy/ht training and signal fields */ streams = HT_RC_2_STREAMS(rc); duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams); + return duration; } @@ -627,207 +549,127 @@ static u32 ath_pkt_duration(struct ath_softc *sc, static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) { struct ath_hal *ah = sc->sc_ah; - const struct ath9k_rate_table *rt; + struct ath_rate_table *rt; struct ath_desc *ds = bf->bf_desc; struct ath_desc *lastds = bf->bf_lastbf->bf_desc; struct ath9k_11n_rate_series series[4]; - int i, flags, rtsctsena = 0, dynamic_mimops = 0; + struct sk_buff *skb; + struct ieee80211_tx_info *tx_info; + struct ieee80211_tx_rate *rates; + struct ieee80211_hdr *hdr; + int i, flags, rtsctsena = 0; u32 ctsduration = 0; u8 rix = 0, cix, ctsrate = 0; - u32 aggr_limit_with_rts = ah->ah_caps.rts_aggr_limit; - struct ath_node *an = (struct ath_node *) bf->bf_node; + __le16 fc; - /* - * get the cix for the lowest valid rix. - */ - rt = sc->sc_currates; - for (i = 4; i--;) { - if (bf->bf_rcs[i].tries) { - rix = bf->bf_rcs[i].rix; + memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4); + + skb = (struct sk_buff *)bf->bf_mpdu; + hdr = (struct ieee80211_hdr *)skb->data; + fc = hdr->frame_control; + tx_info = IEEE80211_SKB_CB(skb); + rates = tx_info->control.rates; + + if (ieee80211_has_morefrags(fc) || + (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) { + rates[1].count = rates[2].count = rates[3].count = 0; + rates[1].idx = rates[2].idx = rates[3].idx = 0; + rates[0].count = ATH_TXMAXTRY; + } + + /* get the cix for the lowest valid rix */ + rt = sc->cur_rate_table; + for (i = 3; i >= 0; i--) { + if (rates[i].count && (rates[i].idx >= 0)) { + rix = rates[i].idx; break; } } + flags = (bf->bf_flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)); - cix = rt->info[rix].controlRate; + cix = rt->info[rix].ctrl_rate; /* - * If 802.11g protection is enabled, determine whether - * to use RTS/CTS or just CTS. Note that this is only - * done for OFDM/HT unicast frames. + * If 802.11g protection is enabled, determine whether to use RTS/CTS or + * just CTS. Note that this is only done for OFDM/HT unicast frames. */ - if (sc->sc_protmode != PROT_M_NONE && - (rt->info[rix].phy == PHY_OFDM || - rt->info[rix].phy == PHY_HT) && - (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) { + if (sc->sc_protmode != PROT_M_NONE && !(bf->bf_flags & ATH9K_TXDESC_NOACK) + && (rt->info[rix].phy == WLAN_RC_PHY_OFDM || + WLAN_RC_PHY_HT(rt->info[rix].phy))) { if (sc->sc_protmode == PROT_M_RTSCTS) flags = ATH9K_TXDESC_RTSENA; else if (sc->sc_protmode == PROT_M_CTSONLY) flags = ATH9K_TXDESC_CTSENA; - cix = rt->info[sc->sc_protrix].controlRate; + cix = rt->info[sc->sc_protrix].ctrl_rate; rtsctsena = 1; } - /* For 11n, the default behavior is to enable RTS for - * hw retried frames. We enable the global flag here and - * let rate series flags determine which rates will actually - * use RTS. + /* For 11n, the default behavior is to enable RTS for hw retried frames. + * We enable the global flag here and let rate series flags determine + * which rates will actually use RTS. */ if ((ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) && bf_isdata(bf)) { - BUG_ON(!an); - /* - * 802.11g protection not needed, use our default behavior - */ + /* 802.11g protection not needed, use our default behavior */ if (!rtsctsena) flags = ATH9K_TXDESC_RTSENA; - /* - * For dynamic MIMO PS, RTS needs to precede the first aggregate - * and the second aggregate should have any protection at all. - */ - if (an->an_smmode == ATH_SM_PWRSAV_DYNAMIC) { - if (!bf_isaggrburst(bf)) { - flags = ATH9K_TXDESC_RTSENA; - dynamic_mimops = 1; - } else { - flags = 0; - } - } } - /* - * Set protection if aggregate protection on - */ + /* Set protection if aggregate protection on */ if (sc->sc_config.ath_aggr_prot && (!bf_isaggr(bf) || (bf_isaggr(bf) && bf->bf_al < 8192))) { flags = ATH9K_TXDESC_RTSENA; - cix = rt->info[sc->sc_protrix].controlRate; + cix = rt->info[sc->sc_protrix].ctrl_rate; rtsctsena = 1; } - /* - * For AR5416 - RTS cannot be followed by a frame larger than 8K. - */ - if (bf_isaggr(bf) && (bf->bf_al > aggr_limit_with_rts)) { - /* - * Ensure that in the case of SM Dynamic power save - * while we are bursting the second aggregate the - * RTS is cleared. - */ + /* For AR5416 - RTS cannot be followed by a frame larger than 8K */ + if (bf_isaggr(bf) && (bf->bf_al > ah->ah_caps.rts_aggr_limit)) flags &= ~(ATH9K_TXDESC_RTSENA); - } /* - * CTS transmit rate is derived from the transmit rate - * by looking in the h/w rate table. We must also factor - * in whether or not a short preamble is to be used. + * CTS transmit rate is derived from the transmit rate by looking in the + * h/w rate table. We must also factor in whether or not a short + * preamble is to be used. NB: cix is set above where RTS/CTS is enabled */ - /* NB: cix is set above where RTS/CTS is enabled */ - BUG_ON(cix == 0xff); - ctsrate = rt->info[cix].rateCode | - (bf_isshpreamble(bf) ? rt->info[cix].shortPreamble : 0); - - /* - * Setup HAL rate series - */ - memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4); + ctsrate = rt->info[cix].ratecode | + (bf_isshpreamble(bf) ? rt->info[cix].short_preamble : 0); for (i = 0; i < 4; i++) { - if (!bf->bf_rcs[i].tries) + if (!rates[i].count || (rates[i].idx < 0)) continue; - rix = bf->bf_rcs[i].rix; + rix = rates[i].idx; - series[i].Rate = rt->info[rix].rateCode | - (bf_isshpreamble(bf) ? rt->info[rix].shortPreamble : 0); + series[i].Rate = rt->info[rix].ratecode | + (bf_isshpreamble(bf) ? rt->info[rix].short_preamble : 0); - series[i].Tries = bf->bf_rcs[i].tries; + series[i].Tries = rates[i].count; series[i].RateFlags = ( - (bf->bf_rcs[i].flags & ATH_RC_RTSCTS_FLAG) ? + (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) ? ATH9K_RATESERIES_RTS_CTS : 0) | - ((bf->bf_rcs[i].flags & ATH_RC_CW40_FLAG) ? + ((rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? ATH9K_RATESERIES_2040 : 0) | - ((bf->bf_rcs[i].flags & ATH_RC_SGI_FLAG) ? + ((rates[i].flags & IEEE80211_TX_RC_SHORT_GI) ? ATH9K_RATESERIES_HALFGI : 0); - series[i].PktDuration = ath_pkt_duration( - sc, rix, bf, - (bf->bf_rcs[i].flags & ATH_RC_CW40_FLAG) != 0, - (bf->bf_rcs[i].flags & ATH_RC_SGI_FLAG), - bf_isshpreamble(bf)); + series[i].PktDuration = ath_pkt_duration(sc, rix, bf, + (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) != 0, + (rates[i].flags & IEEE80211_TX_RC_SHORT_GI), + bf_isshpreamble(bf)); - if ((an->an_smmode == ATH_SM_PWRSAV_STATIC) && - (bf->bf_rcs[i].flags & ATH_RC_DS_FLAG) == 0) { - /* - * When sending to an HT node that has enabled static - * SM/MIMO power save, send at single stream rates but - * use maximum allowed transmit chains per user, - * hardware, regulatory, or country limits for - * better range. - */ - series[i].ChSel = sc->sc_tx_chainmask; - } else { - if (bf_isht(bf)) - series[i].ChSel = - ath_chainmask_sel_logic(sc, an); - else - series[i].ChSel = sc->sc_tx_chainmask; - } + series[i].ChSel = sc->sc_tx_chainmask; if (rtsctsena) series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS; - - /* - * Set RTS for all rates if node is in dynamic powersave - * mode and we are using dual stream rates. - */ - if (dynamic_mimops && (bf->bf_rcs[i].flags & ATH_RC_DS_FLAG)) - series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS; - } - - /* - * For non-HT devices, calculate RTS/CTS duration in software - * and disable multi-rate retry. - */ - if (flags && !(ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT)) { - /* - * Compute the transmit duration based on the frame - * size and the size of an ACK frame. We call into the - * HAL to do the computation since it depends on the - * characteristics of the actual PHY being used. - * - * NB: CTS is assumed the same size as an ACK so we can - * use the precalculated ACK durations. - */ - if (flags & ATH9K_TXDESC_RTSENA) { /* SIFS + CTS */ - ctsduration += bf_isshpreamble(bf) ? - rt->info[cix].spAckDuration : - rt->info[cix].lpAckDuration; - } - - ctsduration += series[0].PktDuration; - - if ((bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) { /* SIFS + ACK */ - ctsduration += bf_isshpreamble(bf) ? - rt->info[rix].spAckDuration : - rt->info[rix].lpAckDuration; - } - - /* - * Disable multi-rate retry when using RTS/CTS by clearing - * series 1, 2 and 3. - */ - memset(&series[1], 0, sizeof(struct ath9k_11n_rate_series) * 3); } - /* - * set dur_update_en for l-sig computation except for PS-Poll frames - */ - ath9k_hw_set11n_ratescenario(ah, ds, lastds, - !bf_ispspoll(bf), - ctsrate, - ctsduration, + /* set dur_update_en for l-sig computation except for PS-Poll frames */ + ath9k_hw_set11n_ratescenario(ah, ds, lastds, !bf_ispspoll(bf), + ctsrate, ctsduration, series, 4, flags); + if (sc->sc_config.ath_aggr_prot && flags) ath9k_hw_set11n_burstduration(ah, ds, 8192); } @@ -836,27 +678,18 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) * Function to send a normal HT (non-AMPDU) frame * NB: must be called with txq lock held */ - static int ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid, struct list_head *bf_head) { struct ath_buf *bf; - struct sk_buff *skb; - struct ieee80211_tx_info *tx_info; - struct ath_tx_info_priv *tx_info_priv; BUG_ON(list_empty(bf_head)); bf = list_first_entry(bf_head, struct ath_buf, list); bf->bf_state.bf_type &= ~BUF_AMPDU; /* regular HT frame */ - skb = (struct sk_buff *)bf->bf_mpdu; - tx_info = IEEE80211_SKB_CB(skb); - tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; - memcpy(bf->bf_rcs, tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0])); - /* update starting sequence number for subsequent ADDBA request */ INCR(tid->seq_start, IEEE80211_SEQ_MAX); @@ -873,7 +706,7 @@ static int ath_tx_send_normal(struct ath_softc *sc, static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) { - struct ath_txq *txq = &sc->sc_txq[tid->ac->qnum]; + struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum]; struct ath_buf *bf; struct list_head bf_head; INIT_LIST_HEAD(&bf_head); @@ -906,8 +739,10 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, struct list_head *bf_q, int txok) { - struct ath_node *an = bf->bf_node; - struct ath_atx_tid *tid = ATH_AN_2_TID(an, bf->bf_tidno); + struct ath_node *an = NULL; + struct sk_buff *skb; + struct ieee80211_tx_info *tx_info; + struct ath_atx_tid *tid = NULL; struct ath_buf *bf_last = bf->bf_lastbf; struct ath_desc *ds = bf_last->bf_desc; struct ath_buf *bf_next, *bf_lastq = NULL; @@ -915,7 +750,14 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, u16 seq_st = 0; u32 ba[WME_BA_BMP_SIZE >> 5]; int isaggr, txfail, txpending, sendbar = 0, needreset = 0; - int isnodegone = (an->an_flags & ATH_NODE_CLEAN); + + skb = (struct sk_buff *)bf->bf_mpdu; + tx_info = IEEE80211_SKB_CB(skb); + + if (tx_info->control.sta) { + an = (struct ath_node *)tx_info->control.sta->drv_priv; + tid = ATH_AN_2_TID(an, bf->bf_tidno); + } isaggr = bf_isaggr(bf); if (isaggr) { @@ -939,7 +781,8 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, * when perform internal reset in this routine. * Only enable reset in STA mode for now. */ - if (sc->sc_ah->ah_opmode == ATH9K_M_STA) + if (sc->sc_ah->ah_opmode == + NL80211_IFTYPE_STATION) needreset = 1; } } else { @@ -961,7 +804,7 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, /* transmit completion */ } else { - if (!tid->cleanup_inprogress && !isnodegone && + if (!(tid->state & AGGR_CLEANUP) && ds->ds_txstat.ts_flags != ATH9K_TX_SW_ABORTED) { if (bf->bf_retries < ATH_MAX_SW_RETRIES) { ath_tx_set_retry(sc, bf); @@ -1038,18 +881,17 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, struct ath_buf *tbf; /* allocate new descriptor */ - spin_lock_bh(&sc->sc_txbuflock); - ASSERT(!list_empty((&sc->sc_txbuf))); - tbf = list_first_entry(&sc->sc_txbuf, + spin_lock_bh(&sc->tx.txbuflock); + ASSERT(!list_empty((&sc->tx.txbuf))); + tbf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list); list_del(&tbf->list); - spin_unlock_bh(&sc->sc_txbuflock); + spin_unlock_bh(&sc->tx.txbuflock); ATH_TXBUF_RESET(tbf); /* copy descriptor content */ tbf->bf_mpdu = bf_last->bf_mpdu; - tbf->bf_node = bf_last->bf_node; tbf->bf_buf_addr = bf_last->bf_buf_addr; *(tbf->bf_desc) = *(bf_last->bf_desc); @@ -1090,25 +932,16 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, bf = bf_next; } - /* - * node is already gone. no more assocication - * with the node. the node might have been freed - * any node acces can result in panic.note tid - * is part of the node. - */ - if (isnodegone) - return; - - if (tid->cleanup_inprogress) { + if (tid->state & AGGR_CLEANUP) { /* check to see if we're done with cleaning the h/w queue */ spin_lock_bh(&txq->axq_lock); if (tid->baw_head == tid->baw_tail) { - tid->addba_exchangecomplete = 0; + tid->state &= ~AGGR_ADDBA_COMPLETE; tid->addba_exchangeattempts = 0; spin_unlock_bh(&txq->axq_lock); - tid->cleanup_inprogress = false; + tid->state &= ~AGGR_CLEANUP; /* send buffered frames as singles */ ath_tx_flush_tid(sc, tid); @@ -1136,29 +969,45 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, return; } +static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds, int nbad) +{ + struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); + + tx_info_priv->update_rc = false; + if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) + tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; + + if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 && + (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) { + if (bf_isdata(bf)) { + memcpy(&tx_info_priv->tx, &ds->ds_txstat, + sizeof(tx_info_priv->tx)); + tx_info_priv->n_frames = bf->bf_nframes; + tx_info_priv->n_bad_frames = nbad; + tx_info_priv->update_rc = true; + } + } +} + /* Process completed xmit descriptors from the specified queue */ -static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) +static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) { struct ath_hal *ah = sc->sc_ah; struct ath_buf *bf, *lastbf, *bf_held = NULL; struct list_head bf_head; - struct ath_desc *ds, *tmp_ds; - struct sk_buff *skb; - struct ieee80211_tx_info *tx_info; - struct ath_tx_info_priv *tx_info_priv; - int nacked, txok, nbad = 0, isrifs = 0; + struct ath_desc *ds; + int txok, nbad = 0; int status; - DPRINTF(sc, ATH_DBG_QUEUE, - "%s: tx queue %d (%x), link %p\n", __func__, + DPRINTF(sc, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n", txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum), txq->axq_link); - nacked = 0; for (;;) { spin_lock_bh(&txq->axq_lock); - txq->axq_intrcnt = 0; /* reset periodic desc intr count */ if (list_empty(&txq->axq_q)) { txq->axq_link = NULL; txq->axq_linkbuf = NULL; @@ -1229,9 +1078,9 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) if (bf_held) { list_del(&bf_held->list); - spin_lock_bh(&sc->sc_txbuflock); - list_add_tail(&bf_held->list, &sc->sc_txbuf); - spin_unlock_bh(&sc->sc_txbuflock); + spin_lock_bh(&sc->tx.txbuflock); + list_add_tail(&bf_held->list, &sc->tx.txbuf); + spin_unlock_bh(&sc->tx.txbuflock); } if (!bf_isampdu(bf)) { @@ -1246,29 +1095,8 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) } else { nbad = ath_tx_num_badfrms(sc, bf, txok); } - skb = bf->bf_mpdu; - tx_info = IEEE80211_SKB_CB(skb); - tx_info_priv = (struct ath_tx_info_priv *) - tx_info->driver_data[0]; - if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) - tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; - if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 && - (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) { - if (ds->ds_txstat.ts_status == 0) - nacked++; - - if (bf_isdata(bf)) { - if (isrifs) - tmp_ds = bf->bf_rifslast->bf_desc; - else - tmp_ds = ds; - memcpy(&tx_info_priv->tx, - &tmp_ds->ds_txstat, - sizeof(tx_info_priv->tx)); - tx_info_priv->n_frames = bf->bf_nframes; - tx_info_priv->n_bad_frames = nbad; - } - } + + ath_tx_rc_status(bf, ds, nbad); /* * Complete this transmit unit @@ -1299,7 +1127,6 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) ath_txq_schedule(sc, txq); spin_unlock_bh(&txq->axq_lock); } - return nacked; } static void ath_tx_stopdma(struct ath_softc *sc, struct ath_txq *txq) @@ -1307,9 +1134,9 @@ static void ath_tx_stopdma(struct ath_softc *sc, struct ath_txq *txq) struct ath_hal *ah = sc->sc_ah; (void) ath9k_hw_stoptxdma(ah, txq->axq_qnum); - DPRINTF(sc, ATH_DBG_XMIT, "%s: tx queue [%u] %x, link %p\n", - __func__, txq->axq_qnum, - ath9k_hw_gettxbuf(ah, txq->axq_qnum), txq->axq_link); + DPRINTF(sc, ATH_DBG_XMIT, "tx queue [%u] %x, link %p\n", + txq->axq_qnum, ath9k_hw_gettxbuf(ah, txq->axq_qnum), + txq->axq_link); } /* Drain only the data queues */ @@ -1317,40 +1144,33 @@ static void ath_tx_stopdma(struct ath_softc *sc, struct ath_txq *txq) static void ath_drain_txdataq(struct ath_softc *sc, bool retry_tx) { struct ath_hal *ah = sc->sc_ah; - int i; - int npend = 0; + int i, status, npend = 0; - /* XXX return value */ if (!(sc->sc_flags & SC_OP_INVALID)) { for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { if (ATH_TXQ_SETUP(sc, i)) { - ath_tx_stopdma(sc, &sc->sc_txq[i]); - + ath_tx_stopdma(sc, &sc->tx.txq[i]); /* The TxDMA may not really be stopped. * Double check the hal tx pending count */ npend += ath9k_hw_numtxpending(ah, - sc->sc_txq[i].axq_qnum); + sc->tx.txq[i].axq_qnum); } } } if (npend) { - int status; - /* TxDMA not stopped, reset the hal */ - DPRINTF(sc, ATH_DBG_XMIT, - "%s: Unable to stop TxDMA. Reset HAL!\n", __func__); + DPRINTF(sc, ATH_DBG_XMIT, "Unable to stop TxDMA. Reset HAL!\n"); spin_lock_bh(&sc->sc_resetlock); if (!ath9k_hw_reset(ah, sc->sc_ah->ah_curchan, - sc->sc_ht_info.tx_chan_width, + sc->tx_chan_width, sc->sc_tx_chainmask, sc->sc_rx_chainmask, sc->sc_ht_extprotspacing, true, &status)) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to reset hardware; hal status %u\n", - __func__, + "Unable to reset hardware; hal status %u\n", status); } spin_unlock_bh(&sc->sc_resetlock); @@ -1358,7 +1178,7 @@ static void ath_drain_txdataq(struct ath_softc *sc, bool retry_tx) for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { if (ATH_TXQ_SETUP(sc, i)) - ath_tx_draintxq(sc, &sc->sc_txq[i], retry_tx); + ath_tx_draintxq(sc, &sc->tx.txq[i], retry_tx); } } @@ -1390,24 +1210,17 @@ static void ath_tx_addto_baw(struct ath_softc *sc, * Function to send an A-MPDU * NB: must be called with txq lock held */ - static int ath_tx_send_ampdu(struct ath_softc *sc, - struct ath_txq *txq, struct ath_atx_tid *tid, struct list_head *bf_head, struct ath_tx_control *txctl) { struct ath_buf *bf; - struct sk_buff *skb; - struct ieee80211_tx_info *tx_info; - struct ath_tx_info_priv *tx_info_priv; BUG_ON(list_empty(bf_head)); bf = list_first_entry(bf_head, struct ath_buf, list); bf->bf_state.bf_type |= BUF_AMPDU; - bf->bf_seqno = txctl->seqno; /* save seqno and tidno in buffer */ - bf->bf_tidno = txctl->tidno; /* * Do not queue to h/w when any of the following conditions is true: @@ -1418,21 +1231,16 @@ static int ath_tx_send_ampdu(struct ath_softc *sc, */ if (!list_empty(&tid->buf_q) || tid->paused || !BAW_WITHIN(tid->seq_start, tid->baw_size, bf->bf_seqno) || - txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) { + txctl->txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) { /* * Add this frame to software queue for scheduling later * for aggregation. */ list_splice_tail_init(bf_head, &tid->buf_q); - ath_tx_queue_tid(txq, tid); + ath_tx_queue_tid(txctl->txq, tid); return 0; } - skb = (struct sk_buff *)bf->bf_mpdu; - tx_info = IEEE80211_SKB_CB(skb); - tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; - memcpy(bf->bf_rcs, tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0])); - /* Add sub-frame to BAW */ ath_tx_addto_baw(sc, tid, bf); @@ -1440,7 +1248,8 @@ static int ath_tx_send_ampdu(struct ath_softc *sc, bf->bf_nframes = 1; bf->bf_lastbf = bf->bf_lastfrm; /* one single frame */ ath_buf_set_rate(sc, bf); - ath_tx_txqaddbuf(sc, txq, bf_head); + ath_tx_txqaddbuf(sc, txctl->txq, bf_head); + return 0; } @@ -1448,25 +1257,24 @@ static int ath_tx_send_ampdu(struct ath_softc *sc, * looks up the rate * returns aggr limit based on lowest of the rates */ - static u32 ath_lookup_rate(struct ath_softc *sc, - struct ath_buf *bf) + struct ath_buf *bf, + struct ath_atx_tid *tid) { - const struct ath9k_rate_table *rt = sc->sc_currates; + struct ath_rate_table *rate_table = sc->cur_rate_table; struct sk_buff *skb; struct ieee80211_tx_info *tx_info; + struct ieee80211_tx_rate *rates; struct ath_tx_info_priv *tx_info_priv; u32 max_4ms_framelen, frame_length; u16 aggr_limit, legacy = 0, maxampdu; int i; - skb = (struct sk_buff *)bf->bf_mpdu; tx_info = IEEE80211_SKB_CB(skb); - tx_info_priv = (struct ath_tx_info_priv *) - tx_info->driver_data[0]; - memcpy(bf->bf_rcs, - tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0])); + rates = tx_info->control.rates; + tx_info_priv = + (struct ath_tx_info_priv *)tx_info->rate_driver_data[0]; /* * Find the lowest frame length among the rate series that will have a @@ -1476,14 +1284,14 @@ static u32 ath_lookup_rate(struct ath_softc *sc, max_4ms_framelen = ATH_AMPDU_LIMIT_MAX; for (i = 0; i < 4; i++) { - if (bf->bf_rcs[i].tries) { - frame_length = bf->bf_rcs[i].max_4ms_framelen; - - if (rt->info[bf->bf_rcs[i].rix].phy != PHY_HT) { + if (rates[i].count) { + if (!WLAN_RC_PHY_HT(rate_table->info[rates[i].idx].phy)) { legacy = 1; break; } + frame_length = + rate_table->info[rates[i].idx].max_4ms_framelen; max_4ms_framelen = min(max_4ms_framelen, frame_length); } } @@ -1504,7 +1312,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, * The IE, however can hold upto 65536, which shows up here * as zero. Ignore 65536 since we are constrained by hw. */ - maxampdu = sc->sc_ht_info.maxampdu; + maxampdu = tid->an->maxampdu; if (maxampdu) aggr_limit = min(aggr_limit, maxampdu); @@ -1516,12 +1324,14 @@ static u32 ath_lookup_rate(struct ath_softc *sc, * meet the minimum required mpdudensity. * caller should make sure that the rate is HT rate . */ - static int ath_compute_num_delims(struct ath_softc *sc, + struct ath_atx_tid *tid, struct ath_buf *bf, u16 frmlen) { - const struct ath9k_rate_table *rt = sc->sc_currates; + struct ath_rate_table *rt = sc->cur_rate_table; + struct sk_buff *skb = bf->bf_mpdu; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); u32 nsymbits, nsymbols, mpdudensity; u16 minlen; u8 rc, flags, rix; @@ -1545,7 +1355,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, * required minimum length for subframe. Take into account * whether high rate is 20 or 40Mhz and half or full GI. */ - mpdudensity = sc->sc_ht_info.mpdudensity; + mpdudensity = tid->an->mpdudensity; /* * If there is no mpdu density restriction, no further calculation @@ -1554,11 +1364,11 @@ static int ath_compute_num_delims(struct ath_softc *sc, if (mpdudensity == 0) return ndelim; - rix = bf->bf_rcs[0].rix; - flags = bf->bf_rcs[0].flags; - rc = rt->info[rix].rateCode; - width = (flags & ATH_RC_CW40_FLAG) ? 1 : 0; - half_gi = (flags & ATH_RC_SGI_FLAG) ? 1 : 0; + rix = tx_info->control.rates[0].idx; + flags = tx_info->control.rates[0].flags; + rc = rt->info[rix].ratecode; + width = (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? 1 : 0; + half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0; if (half_gi) nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(mpdudensity); @@ -1585,7 +1395,6 @@ static int ath_compute_num_delims(struct ath_softc *sc, * For aggregation from software buffer queue. * NB: must be called with txq lock held */ - static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, struct ath_atx_tid *tid, struct list_head *bf_q, @@ -1600,7 +1409,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, u16 aggr_limit = 0, al = 0, bpad = 0, al_delta, h_baw = tid->baw_size / 2; enum ATH_AGGR_STATUS status = ATH_AGGR_DONE; - int prev_al = 0, is_ds_rate = 0; + int prev_al = 0; INIT_LIST_HEAD(&bf_head); BUG_ON(list_empty(&tid->buf_q)); @@ -1619,13 +1428,8 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, } if (!rl) { - aggr_limit = ath_lookup_rate(sc, bf); + aggr_limit = ath_lookup_rate(sc, bf, tid); rl = 1; - /* - * Is rate dual stream - */ - is_ds_rate = - (bf->bf_rcs[0].flags & ATH_RC_DS_FLAG) ? 1 : 0; } /* @@ -1657,7 +1461,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, * Get the delimiters needed to meet the MPDU * density for this node. */ - ndelim = ath_compute_num_delims(sc, bf_first, bf->bf_frmlen); + ndelim = ath_compute_num_delims(sc, tid, bf_first, bf->bf_frmlen); bpad = PADBYTES(al_delta) + (ndelim << 2); @@ -1713,7 +1517,6 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, * process pending frames possibly doing a-mpdu aggregation * NB: must be called with txq lock held */ - static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid) { @@ -1799,8 +1602,8 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, - struct ath_atx_tid *tid, - bool bh_flag) + struct ath_atx_tid *tid) + { struct ath_buf *bf; struct list_head bf_head; @@ -1821,18 +1624,12 @@ static void ath_tid_drain(struct ath_softc *sc, * do not indicate packets while holding txq spinlock. * unlock is intentional here */ - if (likely(bh_flag)) - spin_unlock_bh(&txq->axq_lock); - else - spin_unlock(&txq->axq_lock); + spin_unlock(&txq->axq_lock); /* complete this sub-frame */ ath_tx_complete_buf(sc, bf, &bf_head, 0, 0); - if (likely(bh_flag)) - spin_lock_bh(&txq->axq_lock); - else - spin_lock(&txq->axq_lock); + spin_lock(&txq->axq_lock); } /* @@ -1849,10 +1646,8 @@ static void ath_tid_drain(struct ath_softc *sc, * Drain all pending buffers * NB: must be called with txq lock held */ - static void ath_txq_drain_pending_buffers(struct ath_softc *sc, - struct ath_txq *txq, - bool bh_flag) + struct ath_txq *txq) { struct ath_atx_ac *ac, *ac_tmp; struct ath_atx_tid *tid, *tid_tmp; @@ -1863,51 +1658,33 @@ static void ath_txq_drain_pending_buffers(struct ath_softc *sc, list_for_each_entry_safe(tid, tid_tmp, &ac->tid_q, list) { list_del(&tid->list); tid->sched = false; - ath_tid_drain(sc, txq, tid, bh_flag); + ath_tid_drain(sc, txq, tid); } } } -static int ath_tx_start_dma(struct ath_softc *sc, - struct sk_buff *skb, - struct scatterlist *sg, - u32 n_sg, - struct ath_tx_control *txctl) +static int ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf, + struct sk_buff *skb, + struct ath_tx_control *txctl) { - struct ath_node *an = txctl->an; - struct ath_buf *bf = NULL; - struct list_head bf_head; - struct ath_desc *ds; - struct ath_hal *ah = sc->sc_ah; - struct ath_txq *txq; - struct ath_tx_info_priv *tx_info_priv; - struct ath_rc_series *rcs; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - __le16 fc = hdr->frame_control; - - if (unlikely(txctl->flags & ATH9K_TXDESC_CAB)) - txq = sc->sc_cabq; - else - txq = &sc->sc_txq[txctl->qnum]; + struct ath_tx_info_priv *tx_info_priv; + int hdrlen; + __le16 fc; - /* For each sglist entry, allocate an ath_buf for DMA */ - INIT_LIST_HEAD(&bf_head); - spin_lock_bh(&sc->sc_txbuflock); - if (unlikely(list_empty(&sc->sc_txbuf))) { - spin_unlock_bh(&sc->sc_txbuflock); + tx_info_priv = kzalloc(sizeof(*tx_info_priv), GFP_ATOMIC); + if (unlikely(!tx_info_priv)) return -ENOMEM; - } + tx_info->rate_driver_data[0] = tx_info_priv; + hdrlen = ieee80211_get_hdrlen_from_skb(skb); + fc = hdr->frame_control; - bf = list_first_entry(&sc->sc_txbuf, struct ath_buf, list); - list_del(&bf->list); - spin_unlock_bh(&sc->sc_txbuflock); + ATH_TXBUF_RESET(bf); - list_add_tail(&bf->list, &bf_head); + /* Frame type */ - /* set up this buffer */ - ATH_TXBUF_RESET(bf); - bf->bf_frmlen = txctl->frmlen; + bf->bf_frmlen = skb->len + FCS_LEN - (hdrlen & 3); ieee80211_is_data(fc) ? (bf->bf_state.bf_type |= BUF_DATA) : @@ -1921,120 +1698,158 @@ static int ath_tx_start_dma(struct ath_softc *sc, (sc->sc_flags & SC_OP_PREAMBLE_SHORT) ? (bf->bf_state.bf_type |= BUF_SHORT_PREAMBLE) : (bf->bf_state.bf_type &= ~BUF_SHORT_PREAMBLE); + (sc->hw->conf.ht.enabled && !is_pae(skb) && + (tx_info->flags & IEEE80211_TX_CTL_AMPDU)) ? + (bf->bf_state.bf_type |= BUF_HT) : + (bf->bf_state.bf_type &= ~BUF_HT); + + bf->bf_flags = setup_tx_flags(sc, skb, txctl->txq); + + /* Crypto */ + + bf->bf_keytype = get_hw_crypto_keytype(skb); + + if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR) { + bf->bf_frmlen += tx_info->control.hw_key->icv_len; + bf->bf_keyix = tx_info->control.hw_key->hw_key_idx; + } else { + bf->bf_keyix = ATH9K_TXKEYIX_INVALID; + } + + /* Assign seqno, tidno */ + + if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR)) + assign_aggr_tid_seqno(skb, bf); + + /* DMA setup */ - bf->bf_flags = txctl->flags; - bf->bf_keytype = txctl->keytype; - tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; - rcs = tx_info_priv->rcs; - bf->bf_rcs[0] = rcs[0]; - bf->bf_rcs[1] = rcs[1]; - bf->bf_rcs[2] = rcs[2]; - bf->bf_rcs[3] = rcs[3]; - bf->bf_node = an; bf->bf_mpdu = skb; - bf->bf_buf_addr = sg_dma_address(sg); + + bf->bf_dmacontext = pci_map_single(sc->pdev, skb->data, + skb->len, PCI_DMA_TODEVICE); + if (unlikely(pci_dma_mapping_error(sc->pdev, bf->bf_dmacontext))) { + bf->bf_mpdu = NULL; + DPRINTF(sc, ATH_DBG_CONFIG, + "pci_dma_mapping_error() on TX\n"); + return -ENOMEM; + } + + bf->bf_buf_addr = bf->bf_dmacontext; + return 0; +} + +/* FIXME: tx power */ +static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, + struct ath_tx_control *txctl) +{ + struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ath_node *an = NULL; + struct list_head bf_head; + struct ath_desc *ds; + struct ath_atx_tid *tid; + struct ath_hal *ah = sc->sc_ah; + int frm_type; + + frm_type = get_hw_packet_type(skb); + + INIT_LIST_HEAD(&bf_head); + list_add_tail(&bf->list, &bf_head); /* setup descriptor */ + ds = bf->bf_desc; ds->ds_link = 0; ds->ds_data = bf->bf_buf_addr; - /* - * Save the DMA context in the first ath_buf - */ - bf->bf_dmacontext = txctl->dmacontext; + /* Formulate first tx descriptor with tx controls */ - /* - * Formulate first tx descriptor with tx controls. - */ - ath9k_hw_set11n_txdesc(ah, - ds, - bf->bf_frmlen, /* frame length */ - txctl->atype, /* Atheros packet type */ - min(txctl->txpower, (u16)60), /* txpower */ - txctl->keyix, /* key cache index */ - txctl->keytype, /* key type */ - txctl->flags); /* flags */ - ath9k_hw_filltxdesc(ah, - ds, - sg_dma_len(sg), /* segment length */ - true, /* first segment */ - (n_sg == 1) ? true : false, /* last segment */ - ds); /* first descriptor */ + ath9k_hw_set11n_txdesc(ah, ds, bf->bf_frmlen, frm_type, MAX_RATE_POWER, + bf->bf_keyix, bf->bf_keytype, bf->bf_flags); + + ath9k_hw_filltxdesc(ah, ds, + skb->len, /* segment length */ + true, /* first segment */ + true, /* last segment */ + ds); /* first descriptor */ bf->bf_lastfrm = bf; - (txctl->ht) ? - (bf->bf_state.bf_type |= BUF_HT) : - (bf->bf_state.bf_type &= ~BUF_HT); - spin_lock_bh(&txq->axq_lock); + spin_lock_bh(&txctl->txq->axq_lock); - if (txctl->ht && (sc->sc_flags & SC_OP_TXAGGR)) { - struct ath_atx_tid *tid = ATH_AN_2_TID(an, txctl->tidno); - if (ath_aggr_query(sc, an, txctl->tidno)) { + if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR) && + tx_info->control.sta) { + an = (struct ath_node *)tx_info->control.sta->drv_priv; + tid = ATH_AN_2_TID(an, bf->bf_tidno); + + if (ath_aggr_query(sc, an, bf->bf_tidno)) { /* * Try aggregation if it's a unicast data frame * and the destination is HT capable. */ - ath_tx_send_ampdu(sc, txq, tid, &bf_head, txctl); + ath_tx_send_ampdu(sc, tid, &bf_head, txctl); } else { /* - * Send this frame as regular when ADDBA exchange - * is neither complete nor pending. + * Send this frame as regular when ADDBA + * exchange is neither complete nor pending. */ - ath_tx_send_normal(sc, txq, tid, &bf_head); + ath_tx_send_normal(sc, txctl->txq, + tid, &bf_head); } } else { bf->bf_lastbf = bf; bf->bf_nframes = 1; - ath_buf_set_rate(sc, bf); - - if (ieee80211_is_back_req(fc)) { - /* This is required for resuming tid - * during BAR completion */ - bf->bf_tidno = txctl->tidno; - } - ath_tx_txqaddbuf(sc, txq, &bf_head); + ath_buf_set_rate(sc, bf); + ath_tx_txqaddbuf(sc, txctl->txq, &bf_head); } - spin_unlock_bh(&txq->axq_lock); - return 0; + + spin_unlock_bh(&txctl->txq->axq_lock); } -static void xmit_map_sg(struct ath_softc *sc, - struct sk_buff *skb, - struct ath_tx_control *txctl) +/* Upon failure caller should free skb */ +int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb, + struct ath_tx_control *txctl) { - struct ath_xmit_status tx_status; - struct ath_atx_tid *tid; - struct scatterlist sg; + struct ath_buf *bf; + int r; - txctl->dmacontext = pci_map_single(sc->pdev, skb->data, - skb->len, PCI_DMA_TODEVICE); + /* Check if a tx buffer is available */ - /* setup S/G list */ - memset(&sg, 0, sizeof(struct scatterlist)); - sg_dma_address(&sg) = txctl->dmacontext; - sg_dma_len(&sg) = skb->len; + bf = ath_tx_get_buffer(sc); + if (!bf) { + DPRINTF(sc, ATH_DBG_XMIT, "TX buffers are full\n"); + return -1; + } - if (ath_tx_start_dma(sc, skb, &sg, 1, txctl) != 0) { - /* - * We have to do drop frame here. - */ - pci_unmap_single(sc->pdev, txctl->dmacontext, - skb->len, PCI_DMA_TODEVICE); + r = ath_tx_setup_buffer(sc, bf, skb, txctl); + if (unlikely(r)) { + struct ath_txq *txq = txctl->txq; - tx_status.retries = 0; - tx_status.flags = ATH_TX_ERROR; + DPRINTF(sc, ATH_DBG_FATAL, "TX mem alloc failure\n"); - if (txctl->ht && (sc->sc_flags & SC_OP_TXAGGR)) { - /* Reclaim the seqno. */ - tid = ATH_AN_2_TID((struct ath_node *) - txctl->an, txctl->tidno); - DECR(tid->seq_next, IEEE80211_SEQ_MAX); + /* upon ath_tx_processq() this TX queue will be resumed, we + * guarantee this will happen by knowing beforehand that + * we will at least have to run TX completionon one buffer + * on the queue */ + spin_lock_bh(&txq->axq_lock); + if (ath_txq_depth(sc, txq->axq_qnum) > 1) { + ieee80211_stop_queue(sc->hw, + skb_get_queue_mapping(skb)); + txq->stopped = 1; } - ath_tx_complete(sc, skb, &tx_status, txctl->an); + spin_unlock_bh(&txq->axq_lock); + + spin_lock_bh(&sc->tx.txbuflock); + list_add_tail(&bf->list, &sc->tx.txbuf); + spin_unlock_bh(&sc->tx.txbuflock); + + return r; } + + ath_tx_start_dma(sc, bf, txctl); + + return 0; } /* Initialize TX queue and h/w */ @@ -2044,26 +1859,25 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) int error = 0; do { - spin_lock_init(&sc->sc_txbuflock); + spin_lock_init(&sc->tx.txbuflock); /* Setup tx descriptors */ - error = ath_descdma_setup(sc, &sc->sc_txdma, &sc->sc_txbuf, + error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf, "tx", nbufs, 1); if (error != 0) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: failed to allocate tx descriptors: %d\n", - __func__, error); + "Failed to allocate tx descriptors: %d\n", + error); break; } /* XXX allocate beacon state together with vap */ - error = ath_descdma_setup(sc, &sc->sc_bdma, &sc->sc_bbuf, + error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf, "beacon", ATH_BCBUF, 1); if (error != 0) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: failed to allocate " - "beacon descripotrs: %d\n", - __func__, error); + "Failed to allocate beacon descriptors: %d\n", + error); break; } @@ -2080,12 +1894,12 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) int ath_tx_cleanup(struct ath_softc *sc) { /* cleanup beacon descriptors */ - if (sc->sc_bdma.dd_desc_len != 0) - ath_descdma_cleanup(sc, &sc->sc_bdma, &sc->sc_bbuf); + if (sc->beacon.bdma.dd_desc_len != 0) + ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf); /* cleanup tx descriptors */ - if (sc->sc_txdma.dd_desc_len != 0) - ath_descdma_cleanup(sc, &sc->sc_txdma, &sc->sc_txbuf); + if (sc->tx.txdma.dd_desc_len != 0) + ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf); return 0; } @@ -2133,15 +1947,15 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) */ return NULL; } - if (qnum >= ARRAY_SIZE(sc->sc_txq)) { + if (qnum >= ARRAY_SIZE(sc->tx.txq)) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: hal qnum %u out of range, max %u!\n", - __func__, qnum, (unsigned int)ARRAY_SIZE(sc->sc_txq)); + "qnum %u out of range, max %u!\n", + qnum, (unsigned int)ARRAY_SIZE(sc->tx.txq)); ath9k_hw_releasetxqueue(ah, qnum); return NULL; } if (!ATH_TXQ_SETUP(sc, qnum)) { - struct ath_txq *txq = &sc->sc_txq[qnum]; + struct ath_txq *txq = &sc->tx.txq[qnum]; txq->axq_qnum = qnum; txq->axq_link = NULL; @@ -2151,11 +1965,10 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) txq->axq_depth = 0; txq->axq_aggr_depth = 0; txq->axq_totalqueued = 0; - txq->axq_intrcnt = 0; txq->axq_linkbuf = NULL; - sc->sc_txqsetup |= 1<tx.txqsetup |= 1<sc_txq[qnum]; + return &sc->tx.txq[qnum]; } /* Reclaim resources for a setup queue */ @@ -2163,7 +1976,7 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq) { ath9k_hw_releasetxqueue(sc->sc_ah, txq->axq_qnum); - sc->sc_txqsetup &= ~(1<axq_qnum); + sc->tx.txqsetup &= ~(1<axq_qnum); } /* @@ -2180,15 +1993,15 @@ int ath_tx_setup(struct ath_softc *sc, int haltype) { struct ath_txq *txq; - if (haltype >= ARRAY_SIZE(sc->sc_haltype2q)) { + if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: HAL AC %u out of range, max %zu!\n", - __func__, haltype, ARRAY_SIZE(sc->sc_haltype2q)); + "HAL AC %u out of range, max %zu!\n", + haltype, ARRAY_SIZE(sc->tx.hwq_map)); return 0; } txq = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, haltype); if (txq != NULL) { - sc->sc_haltype2q[haltype] = txq->axq_qnum; + sc->tx.hwq_map[haltype] = txq->axq_qnum; return 1; } else return 0; @@ -2200,20 +2013,19 @@ int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype) switch (qtype) { case ATH9K_TX_QUEUE_DATA: - if (haltype >= ARRAY_SIZE(sc->sc_haltype2q)) { + if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: HAL AC %u out of range, max %zu!\n", - __func__, - haltype, ARRAY_SIZE(sc->sc_haltype2q)); + "HAL AC %u out of range, max %zu!\n", + haltype, ARRAY_SIZE(sc->tx.hwq_map)); return -1; } - qnum = sc->sc_haltype2q[haltype]; + qnum = sc->tx.hwq_map[haltype]; break; case ATH9K_TX_QUEUE_BEACON: - qnum = sc->sc_bhalq; + qnum = sc->beacon.beaconq; break; case ATH9K_TX_QUEUE_CAB: - qnum = sc->sc_cabq->axq_qnum; + qnum = sc->beacon.cabq->axq_qnum; break; default: qnum = -1; @@ -2221,6 +2033,34 @@ int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype) return qnum; } +/* Get a transmit queue, if available */ + +struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb) +{ + struct ath_txq *txq = NULL; + int qnum; + + qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc); + txq = &sc->tx.txq[qnum]; + + spin_lock_bh(&txq->axq_lock); + + /* Try to avoid running out of descriptors */ + if (txq->axq_depth >= (ATH_TXBUF - 20)) { + DPRINTF(sc, ATH_DBG_FATAL, + "TX queue: %d is full, depth: %d\n", + qnum, txq->axq_depth); + ieee80211_stop_queue(sc->hw, skb_get_queue_mapping(skb)); + txq->stopped = 1; + spin_unlock_bh(&txq->axq_lock); + return NULL; + } + + spin_unlock_bh(&txq->axq_lock); + + return txq; +} + /* Update parameters for a transmit queue */ int ath_txq_update(struct ath_softc *sc, int qnum, @@ -2230,17 +2070,17 @@ int ath_txq_update(struct ath_softc *sc, int qnum, int error = 0; struct ath9k_tx_queue_info qi; - if (qnum == sc->sc_bhalq) { + if (qnum == sc->beacon.beaconq) { /* * XXX: for beacon queue, we just save the parameter. * It will be picked up by ath_beaconq_config when * it's necessary. */ - sc->sc_beacon_qi = *qinfo; + sc->beacon.beacon_qi = *qinfo; return 0; } - ASSERT(sc->sc_txq[qnum].axq_qnum == qnum); + ASSERT(sc->tx.txq[qnum].axq_qnum == qnum); ath9k_hw_get_txq_props(ah, qnum, &qi); qi.tqi_aifs = qinfo->tqi_aifs; @@ -2251,8 +2091,7 @@ int ath_txq_update(struct ath_softc *sc, int qnum, if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to update hardware queue %u!\n", - __func__, qnum); + "Unable to update hardware queue %u!\n", qnum); error = -EIO; } else { ath9k_hw_resettxqueue(ah, qnum); /* push to h/w */ @@ -2264,7 +2103,7 @@ int ath_txq_update(struct ath_softc *sc, int qnum, int ath_cabq_update(struct ath_softc *sc) { struct ath9k_tx_queue_info qi; - int qnum = sc->sc_cabq->axq_qnum; + int qnum = sc->beacon.cabq->axq_qnum; struct ath_beacon_config conf; ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi); @@ -2284,27 +2123,6 @@ int ath_cabq_update(struct ath_softc *sc) return 0; } -int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb) -{ - struct ath_tx_control txctl; - int error = 0; - - memset(&txctl, 0, sizeof(struct ath_tx_control)); - error = ath_tx_prepare(sc, skb, &txctl); - if (error == 0) - /* - * Start DMA mapping. - * ath_tx_start_dma() will be called either synchronously - * or asynchrounsly once DMA is complete. - */ - xmit_map_sg(sc, skb, &txctl); - else - ath_node_put(sc, txctl.an, ATH9K_BH_STATUS_CHANGE); - - /* failed packets will be dropped by the caller */ - return error; -} - /* Deferred processing of transmit interrupt */ void ath_tx_tasklet(struct ath_softc *sc) @@ -2319,7 +2137,7 @@ void ath_tx_tasklet(struct ath_softc *sc) */ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i))) - ath_tx_processq(sc, &sc->sc_txq[i]); + ath_tx_processq(sc, &sc->tx.txq[i]); } } @@ -2351,9 +2169,9 @@ void ath_tx_draintxq(struct ath_softc *sc, list_del(&bf->list); spin_unlock_bh(&txq->axq_lock); - spin_lock_bh(&sc->sc_txbuflock); - list_add_tail(&bf->list, &sc->sc_txbuf); - spin_unlock_bh(&sc->sc_txbuflock); + spin_lock_bh(&sc->tx.txbuflock); + list_add_tail(&bf->list, &sc->tx.txbuf); + spin_unlock_bh(&sc->tx.txbuflock); continue; } @@ -2378,8 +2196,7 @@ void ath_tx_draintxq(struct ath_softc *sc, if (sc->sc_flags & SC_OP_TXAGGR) { if (!retry_tx) { spin_lock_bh(&txq->axq_lock); - ath_txq_drain_pending_buffers(sc, txq, - ATH9K_BH_STATUS_CHANGE); + ath_txq_drain_pending_buffers(sc, txq); spin_unlock_bh(&txq->axq_lock); } } @@ -2392,9 +2209,9 @@ void ath_draintxq(struct ath_softc *sc, bool retry_tx) /* stop beacon queue. The beacon will be freed when * we go to INIT state */ if (!(sc->sc_flags & SC_OP_INVALID)) { - (void) ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq); - DPRINTF(sc, ATH_DBG_XMIT, "%s: beacon queue %x\n", __func__, - ath9k_hw_gettxbuf(sc->sc_ah, sc->sc_bhalq)); + (void) ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); + DPRINTF(sc, ATH_DBG_XMIT, "beacon queue %x\n", + ath9k_hw_gettxbuf(sc->sc_ah, sc->beacon.beaconq)); } ath_drain_txdataq(sc, retry_tx); @@ -2402,72 +2219,47 @@ void ath_draintxq(struct ath_softc *sc, bool retry_tx) u32 ath_txq_depth(struct ath_softc *sc, int qnum) { - return sc->sc_txq[qnum].axq_depth; + return sc->tx.txq[qnum].axq_depth; } u32 ath_txq_aggr_depth(struct ath_softc *sc, int qnum) { - return sc->sc_txq[qnum].axq_aggr_depth; + return sc->tx.txq[qnum].axq_aggr_depth; } -/* Check if an ADDBA is required. A valid node must be passed. */ -enum ATH_AGGR_CHECK ath_tx_aggr_check(struct ath_softc *sc, - struct ath_node *an, - u8 tidno) +bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno) { struct ath_atx_tid *txtid; - DECLARE_MAC_BUF(mac); if (!(sc->sc_flags & SC_OP_TXAGGR)) - return AGGR_NOT_REQUIRED; + return false; - /* ADDBA exchange must be completed before sending aggregates */ txtid = ATH_AN_2_TID(an, tidno); - if (txtid->addba_exchangecomplete) - return AGGR_EXCHANGE_DONE; - - if (txtid->cleanup_inprogress) - return AGGR_CLEANUP_PROGRESS; - - if (txtid->addba_exchangeinprogress) - return AGGR_EXCHANGE_PROGRESS; - - if (!txtid->addba_exchangecomplete) { - if (!txtid->addba_exchangeinprogress && + if (!(txtid->state & AGGR_ADDBA_COMPLETE)) { + if (!(txtid->state & AGGR_ADDBA_PROGRESS) && (txtid->addba_exchangeattempts < ADDBA_EXCHANGE_ATTEMPTS)) { txtid->addba_exchangeattempts++; - return AGGR_REQUIRED; + return true; } } - return AGGR_NOT_REQUIRED; + return false; } /* Start TX aggregation */ -int ath_tx_aggr_start(struct ath_softc *sc, - const u8 *addr, - u16 tid, - u16 *ssn) +int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, + u16 tid, u16 *ssn) { struct ath_atx_tid *txtid; struct ath_node *an; - spin_lock_bh(&sc->node_lock); - an = ath_node_find(sc, (u8 *) addr); - spin_unlock_bh(&sc->node_lock); - - if (!an) { - DPRINTF(sc, ATH_DBG_AGGR, - "%s: Node not found to initialize " - "TX aggregation\n", __func__); - return -1; - } + an = (struct ath_node *)sta->drv_priv; if (sc->sc_flags & SC_OP_TXAGGR) { txtid = ATH_AN_2_TID(an, tid); - txtid->addba_exchangeinprogress = 1; + txtid->state |= AGGR_ADDBA_PROGRESS; ath_tx_pause_tid(sc, txtid); } @@ -2476,24 +2268,31 @@ int ath_tx_aggr_start(struct ath_softc *sc, /* Stop tx aggregation */ -int ath_tx_aggr_stop(struct ath_softc *sc, - const u8 *addr, - u16 tid) +int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) { + struct ath_node *an = (struct ath_node *)sta->drv_priv; + + ath_tx_aggr_teardown(sc, an, tid); + return 0; +} + +/* Resume tx aggregation */ + +void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) +{ + struct ath_atx_tid *txtid; struct ath_node *an; - spin_lock_bh(&sc->node_lock); - an = ath_node_find(sc, (u8 *) addr); - spin_unlock_bh(&sc->node_lock); + an = (struct ath_node *)sta->drv_priv; - if (!an) { - DPRINTF(sc, ATH_DBG_AGGR, - "%s: TX aggr stop for non-existent node\n", __func__); - return -1; + if (sc->sc_flags & SC_OP_TXAGGR) { + txtid = ATH_AN_2_TID(an, tid); + txtid->baw_size = + IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor; + txtid->state |= AGGR_ADDBA_COMPLETE; + txtid->state &= ~AGGR_ADDBA_PROGRESS; + ath_tx_resume_tid(sc, txtid); } - - ath_tx_aggr_teardown(sc, an, tid); - return 0; } /* @@ -2503,21 +2302,18 @@ int ath_tx_aggr_stop(struct ath_softc *sc, * - Discard all retry frames from the s/w queue. */ -void ath_tx_aggr_teardown(struct ath_softc *sc, - struct ath_node *an, u8 tid) +void ath_tx_aggr_teardown(struct ath_softc *sc, struct ath_node *an, u8 tid) { struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid); - struct ath_txq *txq = &sc->sc_txq[txtid->ac->qnum]; + struct ath_txq *txq = &sc->tx.txq[txtid->ac->qnum]; struct ath_buf *bf; struct list_head bf_head; INIT_LIST_HEAD(&bf_head); - DPRINTF(sc, ATH_DBG_AGGR, "%s: teardown TX aggregation\n", __func__); - - if (txtid->cleanup_inprogress) /* cleanup is in progress */ + if (txtid->state & AGGR_CLEANUP) /* cleanup is in progress */ return; - if (!txtid->addba_exchangecomplete) { + if (!(txtid->state & AGGR_ADDBA_COMPLETE)) { txtid->addba_exchangeattempts = 0; return; } @@ -2547,9 +2343,9 @@ void ath_tx_aggr_teardown(struct ath_softc *sc, if (txtid->baw_head != txtid->baw_tail) { spin_unlock_bh(&txq->axq_lock); - txtid->cleanup_inprogress = true; + txtid->state |= AGGR_CLEANUP; } else { - txtid->addba_exchangecomplete = 0; + txtid->state &= ~AGGR_ADDBA_COMPLETE; txtid->addba_exchangeattempts = 0; spin_unlock_bh(&txq->axq_lock); ath_tx_flush_tid(sc, txtid); @@ -2591,10 +2387,8 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) if (tid->paused) /* check next tid to keep h/w busy */ continue; - if (!(tid->an->an_smmode == ATH_SM_PWRSAV_DYNAMIC) || - ((txq->axq_depth % 2) == 0)) { + if ((txq->axq_depth % 2) == 0) ath_tx_sched_aggr(sc, txq, tid); - } /* * add tid to round-robin queue if more frames @@ -2625,72 +2419,67 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) { - if (sc->sc_flags & SC_OP_TXAGGR) { - struct ath_atx_tid *tid; - struct ath_atx_ac *ac; - int tidno, acno; - - sc->sc_ht_info.maxampdu = ATH_AMPDU_LIMIT_DEFAULT; + struct ath_atx_tid *tid; + struct ath_atx_ac *ac; + int tidno, acno; - /* - * Init per tid tx state - */ - for (tidno = 0, tid = &an->an_aggr.tx.tid[tidno]; - tidno < WME_NUM_TID; - tidno++, tid++) { - tid->an = an; - tid->tidno = tidno; - tid->seq_start = tid->seq_next = 0; - tid->baw_size = WME_MAX_BA; - tid->baw_head = tid->baw_tail = 0; - tid->sched = false; - tid->paused = false; - tid->cleanup_inprogress = false; - INIT_LIST_HEAD(&tid->buf_q); - - acno = TID_TO_WME_AC(tidno); - tid->ac = &an->an_aggr.tx.ac[acno]; - - /* ADDBA state */ - tid->addba_exchangecomplete = 0; - tid->addba_exchangeinprogress = 0; - tid->addba_exchangeattempts = 0; - } + /* + * Init per tid tx state + */ + for (tidno = 0, tid = &an->tid[tidno]; + tidno < WME_NUM_TID; + tidno++, tid++) { + tid->an = an; + tid->tidno = tidno; + tid->seq_start = tid->seq_next = 0; + tid->baw_size = WME_MAX_BA; + tid->baw_head = tid->baw_tail = 0; + tid->sched = false; + tid->paused = false; + tid->state &= ~AGGR_CLEANUP; + INIT_LIST_HEAD(&tid->buf_q); + + acno = TID_TO_WME_AC(tidno); + tid->ac = &an->ac[acno]; + + /* ADDBA state */ + tid->state &= ~AGGR_ADDBA_COMPLETE; + tid->state &= ~AGGR_ADDBA_PROGRESS; + tid->addba_exchangeattempts = 0; + } - /* - * Init per ac tx state - */ - for (acno = 0, ac = &an->an_aggr.tx.ac[acno]; - acno < WME_NUM_AC; acno++, ac++) { - ac->sched = false; - INIT_LIST_HEAD(&ac->tid_q); - - switch (acno) { - case WME_AC_BE: - ac->qnum = ath_tx_get_qnum(sc, - ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE); - break; - case WME_AC_BK: - ac->qnum = ath_tx_get_qnum(sc, - ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BK); - break; - case WME_AC_VI: - ac->qnum = ath_tx_get_qnum(sc, - ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VI); - break; - case WME_AC_VO: - ac->qnum = ath_tx_get_qnum(sc, - ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VO); - break; - } + /* + * Init per ac tx state + */ + for (acno = 0, ac = &an->ac[acno]; + acno < WME_NUM_AC; acno++, ac++) { + ac->sched = false; + INIT_LIST_HEAD(&ac->tid_q); + + switch (acno) { + case WME_AC_BE: + ac->qnum = ath_tx_get_qnum(sc, + ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE); + break; + case WME_AC_BK: + ac->qnum = ath_tx_get_qnum(sc, + ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BK); + break; + case WME_AC_VI: + ac->qnum = ath_tx_get_qnum(sc, + ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VI); + break; + case WME_AC_VO: + ac->qnum = ath_tx_get_qnum(sc, + ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VO); + break; } } } /* Cleanupthe pending buffers for the node. */ -void ath_tx_node_cleanup(struct ath_softc *sc, - struct ath_node *an, bool bh_flag) +void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) { int i; struct ath_atx_ac *ac, *ac_tmp; @@ -2698,12 +2487,9 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_txq *txq; for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { if (ATH_TXQ_SETUP(sc, i)) { - txq = &sc->sc_txq[i]; + txq = &sc->tx.txq[i]; - if (likely(bh_flag)) - spin_lock_bh(&txq->axq_lock); - else - spin_lock(&txq->axq_lock); + spin_lock(&txq->axq_lock); list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) { @@ -2718,36 +2504,14 @@ void ath_tx_node_cleanup(struct ath_softc *sc, tid_tmp, &ac->tid_q, list) { list_del(&tid->list); tid->sched = false; - ath_tid_drain(sc, txq, tid, bh_flag); - tid->addba_exchangecomplete = 0; + ath_tid_drain(sc, txq, tid); + tid->state &= ~AGGR_ADDBA_COMPLETE; tid->addba_exchangeattempts = 0; - tid->cleanup_inprogress = false; + tid->state &= ~AGGR_CLEANUP; } } - if (likely(bh_flag)) - spin_unlock_bh(&txq->axq_lock); - else - spin_unlock(&txq->axq_lock); - } - } -} - -/* Cleanup per node transmit state */ - -void ath_tx_node_free(struct ath_softc *sc, struct ath_node *an) -{ - if (sc->sc_flags & SC_OP_TXAGGR) { - struct ath_atx_tid *tid; - int tidno, i; - - /* Init per tid rx state */ - for (tidno = 0, tid = &an->an_aggr.tx.tid[tidno]; - tidno < WME_NUM_TID; - tidno++, tid++) { - - for (i = 0; i < ATH_TID_MAX_BUFS; i++) - ASSERT(tid->tx_buf[i] == NULL); + spin_unlock(&txq->axq_lock); } } } @@ -2758,6 +2522,8 @@ void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb) struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ath_tx_control txctl; + memset(&txctl, 0, sizeof(struct ath_tx_control)); + /* * As a temporary workaround, assign seq# here; this will likely need * to be cleaned up to work better with Beacon transmission and virtual @@ -2766,9 +2532,9 @@ void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb) if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) - sc->seq_no += 0x10; + sc->tx.seq_no += 0x10; hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); - hdr->seq_ctrl |= cpu_to_le16(sc->seq_no); + hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no); } /* Add the padding after the header if this is not already done */ @@ -2776,8 +2542,7 @@ void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb) if (hdrlen & 3) { padsize = hdrlen % 4; if (skb_headroom(skb) < padsize) { - DPRINTF(sc, ATH_DBG_XMIT, "%s: TX CABQ padding " - "failed\n", __func__); + DPRINTF(sc, ATH_DBG_XMIT, "TX CABQ padding failed\n"); dev_kfree_skb_any(skb); return; } @@ -2785,23 +2550,16 @@ void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb) memmove(skb->data, skb->data + padsize, hdrlen); } - DPRINTF(sc, ATH_DBG_XMIT, "%s: transmitting CABQ packet, skb: %p\n", - __func__, - skb); + txctl.txq = sc->beacon.cabq; - memset(&txctl, 0, sizeof(struct ath_tx_control)); - txctl.flags = ATH9K_TXDESC_CAB; - if (ath_tx_prepare(sc, skb, &txctl) == 0) { - /* - * Start DMA mapping. - * ath_tx_start_dma() will be called either synchronously - * or asynchrounsly once DMA is complete. - */ - xmit_map_sg(sc, skb, &txctl); - } else { - ath_node_put(sc, txctl.an, ATH9K_BH_STATUS_CHANGE); - DPRINTF(sc, ATH_DBG_XMIT, "%s: TX CABQ failed\n", __func__); - dev_kfree_skb_any(skb); + DPRINTF(sc, ATH_DBG_XMIT, "transmitting CABQ packet, skb: %p\n", skb); + + if (ath_tx_start(sc, skb, &txctl) != 0) { + DPRINTF(sc, ATH_DBG_XMIT, "CABQ TX failed\n"); + goto exit; } -} + return; +exit: + dev_kfree_skb_any(skb); +} diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index ecb02bdaab5be183821287d1d540a1eaad872d22..350157fcd080ae0bec9cc9734d7e65b05897caa0 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -67,7 +67,7 @@ #include #include #include -#include +#include #include "atmel.h" #define DRIVER_MAJOR 0 @@ -569,7 +569,7 @@ static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data); static void atmel_command_irq(struct atmel_private *priv); static int atmel_validate_channel(struct atmel_private *priv, int channel); static void atmel_management_frame(struct atmel_private *priv, - struct ieee80211_hdr_4addr *header, + struct ieee80211_hdr *header, u16 frame_len, u8 rssi); static void atmel_management_timer(u_long a); static void atmel_send_command(struct atmel_private *priv, int command, @@ -577,7 +577,7 @@ static void atmel_send_command(struct atmel_private *priv, int command, static int atmel_send_command_wait(struct atmel_private *priv, int command, void *cmd, int cmd_size); static void atmel_transmit_management_frame(struct atmel_private *priv, - struct ieee80211_hdr_4addr *header, + struct ieee80211_hdr *header, u8 *body, int body_len); static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index); @@ -785,7 +785,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) { static const u8 SNAP_RFC1024[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; struct atmel_private *priv = netdev_priv(dev); - struct ieee80211_hdr_4addr header; + struct ieee80211_hdr header; unsigned long flags; u16 buff, frame_ctl, len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; @@ -823,7 +823,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) frame_ctl = IEEE80211_FTYPE_DATA; header.duration_id = 0; - header.seq_ctl = 0; + header.seq_ctrl = 0; if (priv->wep_is_on) frame_ctl |= IEEE80211_FCTL_PROTECTED; if (priv->operating_mode == IW_MODE_ADHOC) { @@ -840,7 +840,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) if (priv->use_wpa) memcpy(&header.addr4, SNAP_RFC1024, 6); - header.frame_ctl = cpu_to_le16(frame_ctl); + header.frame_control = cpu_to_le16(frame_ctl); /* Copy the wireless header into the card */ atmel_copy_to_card(dev, buff, (unsigned char *)&header, DATA_FRAME_WS_HEADER_SIZE); /* Copy the packet sans its 802.3 header addresses which have been replaced */ @@ -860,7 +860,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) } static void atmel_transmit_management_frame(struct atmel_private *priv, - struct ieee80211_hdr_4addr *header, + struct ieee80211_hdr *header, u8 *body, int body_len) { u16 buff; @@ -876,7 +876,7 @@ static void atmel_transmit_management_frame(struct atmel_private *priv, } static void fast_rx_path(struct atmel_private *priv, - struct ieee80211_hdr_4addr *header, + struct ieee80211_hdr *header, u16 msdu_size, u16 rx_packet_loc, u32 crc) { /* fast path: unfragmented packet copy directly into skbuf */ @@ -914,12 +914,11 @@ static void fast_rx_path(struct atmel_private *priv, } memcpy(skbp, header->addr1, 6); /* destination address */ - if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS) + if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS) memcpy(&skbp[6], header->addr3, 6); else memcpy(&skbp[6], header->addr2, 6); /* source address */ - priv->dev->last_rx = jiffies; skb->protocol = eth_type_trans(skb, priv->dev); skb->ip_summed = CHECKSUM_NONE; netif_rx(skb); @@ -950,7 +949,7 @@ static int probe_crc(struct atmel_private *priv, u16 packet_loc, u16 msdu_size) } static void frag_rx_path(struct atmel_private *priv, - struct ieee80211_hdr_4addr *header, + struct ieee80211_hdr *header, u16 msdu_size, u16 rx_packet_loc, u32 crc, u16 seq_no, u8 frag_no, int more_frags) { @@ -958,7 +957,7 @@ static void frag_rx_path(struct atmel_private *priv, u8 source[6]; struct sk_buff *skb; - if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS) + if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS) memcpy(source, header->addr3, 6); else memcpy(source, header->addr2, 6); @@ -1026,7 +1025,6 @@ static void frag_rx_path(struct atmel_private *priv, memcpy(skb_put(skb, priv->frag_len + 12), priv->rx_buf, priv->frag_len + 12); - priv->dev->last_rx = jiffies; skb->protocol = eth_type_trans(skb, priv->dev); skb->ip_summed = CHECKSUM_NONE; netif_rx(skb); @@ -1041,7 +1039,7 @@ static void frag_rx_path(struct atmel_private *priv, static void rx_done_irq(struct atmel_private *priv) { int i; - struct ieee80211_hdr_4addr header; + struct ieee80211_hdr header; for (i = 0; atmel_rmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head)) == RX_DESC_FLAG_VALID && @@ -1068,10 +1066,10 @@ static void rx_done_irq(struct atmel_private *priv) goto next; } - /* Get header as far as end of seq_ctl */ + /* Get header as far as end of seq_ctrl */ atmel_copy_to_host(priv->dev, (char *)&header, rx_packet_loc, 24); - frame_ctl = le16_to_cpu(header.frame_ctl); - seq_control = le16_to_cpu(header.seq_ctl); + frame_ctl = le16_to_cpu(header.frame_control); + seq_control = le16_to_cpu(header.seq_ctrl); /* probe for CRC use here if needed once five packets have arrived with the same crc status, we assume we know what's @@ -1479,7 +1477,6 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port, struct net_device *dev; struct atmel_private *priv; int rc; - DECLARE_MAC_BUF(mac); /* Create the network device object. */ dev = alloc_etherdev(sizeof(*priv)); @@ -1591,8 +1588,8 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port, if (!ent) printk(KERN_WARNING "atmel: unable to create /proc entry.\n"); - printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %s\n", - dev->name, DRIVER_MAJOR, DRIVER_MINOR, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %pM\n", + dev->name, DRIVER_MAJOR, DRIVER_MINOR, dev->dev_addr); return dev; @@ -1822,7 +1819,7 @@ static int atmel_set_encodeext(struct net_device *dev, /* Determine and validate the key index */ idx = encoding->flags & IW_ENCODE_INDEX; if (idx) { - if (idx < 1 || idx > WEP_KEYS) + if (idx < 1 || idx > 4) return -EINVAL; idx--; } else @@ -1885,7 +1882,7 @@ static int atmel_get_encodeext(struct net_device *dev, idx = encoding->flags & IW_ENCODE_INDEX; if (idx) { - if (idx < 1 || idx > WEP_KEYS) + if (idx < 1 || idx > 4) return -EINVAL; idx--; } else @@ -2800,7 +2797,7 @@ static void handle_beacon_probe(struct atmel_private *priv, u16 capability, u8 channel) { int rejoin = 0; - int new = capability & MFIE_TYPE_POWER_CONSTRAINT ? + int new = capability & WLAN_CAPABILITY_SHORT_PREAMBLE ? SHORT_PREAMBLE : LONG_PREAMBLE; if (priv->preamble != new) { @@ -2829,19 +2826,19 @@ static void handle_beacon_probe(struct atmel_private *priv, u16 capability, static void send_authentication_request(struct atmel_private *priv, u16 system, u8 *challenge, int challenge_len) { - struct ieee80211_hdr_4addr header; + struct ieee80211_hdr header; struct auth_body auth; - header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH); + header.frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH); header.duration_id = cpu_to_le16(0x8000); - header.seq_ctl = 0; + header.seq_ctrl = 0; memcpy(header.addr1, priv->CurrentBSSID, 6); memcpy(header.addr2, priv->dev->dev_addr, 6); memcpy(header.addr3, priv->CurrentBSSID, 6); if (priv->wep_is_on && priv->CurrentAuthentTransactionSeqNum != 1) /* no WEP for authentication frames with TrSeqNo 1 */ - header.frame_ctl |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); + header.frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); auth.alg = cpu_to_le16(system); @@ -2864,7 +2861,7 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc) { u8 *ssid_el_p; int bodysize; - struct ieee80211_hdr_4addr header; + struct ieee80211_hdr header; struct ass_req_format { __le16 capability; __le16 listen_interval; @@ -2877,10 +2874,10 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc) u8 rates[4]; } body; - header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | + header.frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | (is_reassoc ? IEEE80211_STYPE_REASSOC_REQ : IEEE80211_STYPE_ASSOC_REQ)); header.duration_id = cpu_to_le16(0x8000); - header.seq_ctl = 0; + header.seq_ctrl = 0; memcpy(header.addr1, priv->CurrentBSSID, 6); memcpy(header.addr2, priv->dev->dev_addr, 6); @@ -2890,7 +2887,7 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc) if (priv->wep_is_on) body.capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); if (priv->preamble == SHORT_PREAMBLE) - body.capability |= cpu_to_le16(MFIE_TYPE_POWER_CONSTRAINT); + body.capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE); body.listen_interval = cpu_to_le16(priv->listen_interval * priv->beacon_period); @@ -2904,10 +2901,10 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc) bodysize = 12 + priv->SSID_size; } - ssid_el_p[0] = MFIE_TYPE_SSID; + ssid_el_p[0] = WLAN_EID_SSID; ssid_el_p[1] = priv->SSID_size; memcpy(ssid_el_p + 2, priv->SSID, priv->SSID_size); - ssid_el_p[2 + priv->SSID_size] = MFIE_TYPE_RATES; + ssid_el_p[2 + priv->SSID_size] = WLAN_EID_SUPP_RATES; ssid_el_p[3 + priv->SSID_size] = 4; /* len of suported rates */ memcpy(ssid_el_p + 4 + priv->SSID_size, atmel_basic_rates, 4); @@ -2915,9 +2912,9 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc) } static int is_frame_from_current_bss(struct atmel_private *priv, - struct ieee80211_hdr_4addr *header) + struct ieee80211_hdr *header) { - if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS) + if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS) return memcmp(header->addr3, priv->CurrentBSSID, 6) == 0; else return memcmp(header->addr2, priv->CurrentBSSID, 6) == 0; @@ -2965,7 +2962,7 @@ static int retrieve_bss(struct atmel_private *priv) } static void store_bss_info(struct atmel_private *priv, - struct ieee80211_hdr_4addr *header, u16 capability, + struct ieee80211_hdr *header, u16 capability, u16 beacon_period, u8 channel, u8 rssi, u8 ssid_len, u8 *ssid, int is_beacon) { @@ -3004,7 +3001,7 @@ static void store_bss_info(struct atmel_private *priv, else if (capability & WLAN_CAPABILITY_ESS) priv->BSSinfo[index].BSStype =IW_MODE_INFRA; - priv->BSSinfo[index].preamble = capability & MFIE_TYPE_POWER_CONSTRAINT ? + priv->BSSinfo[index].preamble = capability & WLAN_CAPABILITY_SHORT_PREAMBLE ? SHORT_PREAMBLE : LONG_PREAMBLE; } @@ -3040,7 +3037,7 @@ static void authenticate(struct atmel_private *priv, u16 frame_len) } } else if (system == WLAN_AUTH_SHARED_KEY) { if (trans_seq_no == 0x0002 && - auth->el_id == MFIE_TYPE_CHALLENGE) { + auth->el_id == WLAN_EID_CHALLENGE) { send_authentication_request(priv, system, auth->chall_text, auth->chall_text_len); return; } else if (trans_seq_no == 0x0004) { @@ -3183,7 +3180,7 @@ static void associate(struct atmel_private *priv, u16 frame_len, u16 subtype) } } -void atmel_join_bss(struct atmel_private *priv, int bss_index) +static void atmel_join_bss(struct atmel_private *priv, int bss_index) { struct bss_info *bss = &priv->BSSinfo[bss_index]; @@ -3291,12 +3288,12 @@ static void atmel_smooth_qual(struct atmel_private *priv) /* deals with incoming managment frames. */ static void atmel_management_frame(struct atmel_private *priv, - struct ieee80211_hdr_4addr *header, + struct ieee80211_hdr *header, u16 frame_len, u8 rssi) { u16 subtype; - subtype = le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_STYPE; + subtype = le16_to_cpu(header->frame_control) & IEEE80211_FCTL_STYPE; switch (subtype) { case IEEE80211_STYPE_BEACON: case IEEE80211_STYPE_PROBE_RESP: diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 427b8203e3f96af2d8367d5ef1e8b2fa0386ab4a..a53c378e74844ebdca86dd83fb3b5c9104511b27 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -718,7 +718,6 @@ struct b43_wldev { bool bad_frames_preempt; /* Use "Bad Frames Preemption" (default off) */ bool dfq_valid; /* Directed frame queue valid (IBSS PS mode, ATIM) */ - bool short_slot; /* TRUE, if short slot timing is enabled. */ bool radio_hw_enable; /* saved state of radio hardware enabled state */ bool suspend_in_progress; /* TRUE, if we are in a suspend/resume cycle */ diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c index 06a01da801604c91dcf92408871f622e2ccd947d..e04fc91f569ea573f3c9d3dfad8551b710d98c32 100644 --- a/drivers/net/wireless/b43/debugfs.c +++ b/drivers/net/wireless/b43/debugfs.c @@ -731,6 +731,7 @@ static void b43_add_dynamic_debug(struct b43_wldev *dev) add_dyn_dbg("debug_pwork_stop", B43_DBG_PWORK_STOP, 0); add_dyn_dbg("debug_lo", B43_DBG_LO, 0); add_dyn_dbg("debug_firmware", B43_DBG_FIRMWARE, 0); + add_dyn_dbg("debug_keys", B43_DBG_KEYS, 0); #undef add_dyn_dbg } diff --git a/drivers/net/wireless/b43/debugfs.h b/drivers/net/wireless/b43/debugfs.h index 22ffd02ba554806a8625319b5c2fd2aeae1cdcba..7886cbe2d1d19276f22e3a974dd4d7e44a55347b 100644 --- a/drivers/net/wireless/b43/debugfs.h +++ b/drivers/net/wireless/b43/debugfs.h @@ -12,6 +12,7 @@ enum b43_dyndbg { /* Dynamic debugging features */ B43_DBG_PWORK_STOP, B43_DBG_LO, B43_DBG_FIRMWARE, + B43_DBG_KEYS, __B43_NR_DYNDBG, }; diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 098f886976f658fe636c39aa8a9f3810d227e25f..6d65a02b7052cdfa0d754a029038dcb66d96c788 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -1387,13 +1387,11 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, info = IEEE80211_SKB_CB(meta->skb); - memset(&info->status, 0, sizeof(info->status)); - /* * Call back to inform the ieee80211 subsystem about * the status of the transmission. */ - frame_succeed = b43_fill_txstatus_report(info, status); + frame_succeed = b43_fill_txstatus_report(dev, info, status); #ifdef CONFIG_B43_DEBUG if (frame_succeed) ring->nr_succeed_tx_packets++; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 14c44df584d0973a383729955d8c4089a48f5e8d..7b31a327b24a33e643be1021360af7fdcb8273da 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -703,13 +703,11 @@ static void b43_set_slot_time(struct b43_wldev *dev, u16 slot_time) static void b43_short_slot_timing_enable(struct b43_wldev *dev) { b43_set_slot_time(dev, 9); - dev->short_slot = 1; } static void b43_short_slot_timing_disable(struct b43_wldev *dev) { b43_set_slot_time(dev, 20); - dev->short_slot = 0; } /* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable. @@ -994,6 +992,52 @@ static void b43_clear_keys(struct b43_wldev *dev) b43_key_clear(dev, i); } +static void b43_dump_keymemory(struct b43_wldev *dev) +{ + unsigned int i, index, offset; + DECLARE_MAC_BUF(macbuf); + u8 mac[ETH_ALEN]; + u16 algo; + u32 rcmta0; + u16 rcmta1; + u64 hf; + struct b43_key *key; + + if (!b43_debug(dev, B43_DBG_KEYS)) + return; + + hf = b43_hf_read(dev); + b43dbg(dev->wl, "Hardware key memory dump: USEDEFKEYS=%u\n", + !!(hf & B43_HF_USEDEFKEYS)); + for (index = 0; index < dev->max_nr_keys; index++) { + key = &(dev->key[index]); + printk(KERN_DEBUG "Key slot %02u: %s", + index, (key->keyconf == NULL) ? " " : "*"); + offset = dev->ktp + (index * B43_SEC_KEYSIZE); + for (i = 0; i < B43_SEC_KEYSIZE; i += 2) { + u16 tmp = b43_shm_read16(dev, B43_SHM_SHARED, offset + i); + printk("%02X%02X", (tmp & 0xFF), ((tmp >> 8) & 0xFF)); + } + + algo = b43_shm_read16(dev, B43_SHM_SHARED, + B43_SHM_SH_KEYIDXBLOCK + (index * 2)); + printk(" Algo: %04X/%02X", algo, key->algorithm); + + if (index >= 4) { + rcmta0 = b43_shm_read32(dev, B43_SHM_RCMTA, + ((index - 4) * 2) + 0); + rcmta1 = b43_shm_read16(dev, B43_SHM_RCMTA, + ((index - 4) * 2) + 1); + *((__le32 *)(&mac[0])) = cpu_to_le32(rcmta0); + *((__le16 *)(&mac[4])) = cpu_to_le16(rcmta1); + printk(" MAC: %s", + print_mac(macbuf, mac)); + } else + printk(" DEFAULT KEY"); + printk("\n"); + } +} + void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags) { u32 macctl; @@ -1339,25 +1383,6 @@ u8 b43_ieee80211_antenna_sanitize(struct b43_wldev *dev, return antenna_nr; } -static int b43_antenna_from_ieee80211(struct b43_wldev *dev, u8 antenna) -{ - antenna = b43_ieee80211_antenna_sanitize(dev, antenna); - switch (antenna) { - case 0: /* default/diversity */ - return B43_ANTENNA_DEFAULT; - case 1: /* Antenna 0 */ - return B43_ANTENNA0; - case 2: /* Antenna 1 */ - return B43_ANTENNA1; - case 3: /* Antenna 2 */ - return B43_ANTENNA2; - case 4: /* Antenna 3 */ - return B43_ANTENNA3; - default: - return B43_ANTENNA_DEFAULT; - } -} - /* Convert a b43 antenna number value to the PHY TX control value. */ static u16 b43_antenna_to_phyctl(int antenna) { @@ -1399,7 +1424,7 @@ static void b43_write_beacon_template(struct b43_wldev *dev, len, ram_offset, shm_size_offset, rate); /* Write the PHY TX control parameters. */ - antenna = b43_antenna_from_ieee80211(dev, info->antenna_sel_tx); + antenna = B43_ANTENNA_DEFAULT; antenna = b43_antenna_to_phyctl(antenna); ctl = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL); /* We can't send beacons with short preamble. Would get PHY errors. */ @@ -1693,25 +1718,6 @@ static void b43_update_templates(struct b43_wl *wl) queue_work(wl->hw->workqueue, &wl->beacon_update_trigger); } -static void b43_set_ssid(struct b43_wldev *dev, const u8 * ssid, u8 ssid_len) -{ - u32 tmp; - u16 i, len; - - len = min((u16) ssid_len, (u16) 0x100); - for (i = 0; i < len; i += sizeof(u32)) { - tmp = (u32) (ssid[i + 0]); - if (i + 1 < len) - tmp |= (u32) (ssid[i + 1]) << 8; - if (i + 2 < len) - tmp |= (u32) (ssid[i + 2]) << 16; - if (i + 3 < len) - tmp |= (u32) (ssid[i + 3]) << 24; - b43_shm_write32(dev, B43_SHM_SHARED, 0x380 + i, tmp); - } - b43_shm_write16(dev, B43_SHM_SHARED, 0x48, len); -} - static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int) { b43_time_lock(dev); @@ -3339,15 +3345,31 @@ static int b43_switch_band(struct b43_wl *wl, struct ieee80211_channel *chan) return err; } -static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +/* Write the short and long frame retry limit values. */ +static void b43_set_retry_limits(struct b43_wldev *dev, + unsigned int short_retry, + unsigned int long_retry) +{ + /* The retry limit is a 4-bit counter. Enforce this to avoid overflowing + * the chip-internal counter. */ + short_retry = min(short_retry, (unsigned int)0xF); + long_retry = min(long_retry, (unsigned int)0xF); + + b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_SRLIMIT, + short_retry); + b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_LRLIMIT, + long_retry); +} + +static int b43_op_config(struct ieee80211_hw *hw, u32 changed) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev; struct b43_phy *phy; + struct ieee80211_conf *conf = &hw->conf; unsigned long flags; int antenna; int err = 0; - u32 savedirqs; mutex_lock(&wl->mutex); @@ -3358,33 +3380,20 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) dev = wl->current_dev; phy = &dev->phy; - /* Disable IRQs while reconfiguring the device. - * This makes it possible to drop the spinlock throughout - * the reconfiguration process. */ - spin_lock_irqsave(&wl->irq_lock, flags); - if (b43_status(dev) < B43_STAT_STARTED) { - spin_unlock_irqrestore(&wl->irq_lock, flags); - goto out_unlock_mutex; - } - savedirqs = b43_interrupt_disable(dev, B43_IRQ_ALL); - spin_unlock_irqrestore(&wl->irq_lock, flags); - b43_synchronize_irq(dev); + b43_mac_suspend(dev); + + if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) + b43_set_retry_limits(dev, conf->short_frame_max_tx_count, + conf->long_frame_max_tx_count); + changed &= ~IEEE80211_CONF_CHANGE_RETRY_LIMITS; + if (!changed) + goto out_mac_enable; /* Switch to the requested channel. * The firmware takes care of races with the TX handler. */ if (conf->channel->hw_value != phy->channel) b43_switch_channel(dev, conf->channel->hw_value); - /* Enable/Disable ShortSlot timing. */ - if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)) != - dev->short_slot) { - B43_WARN_ON(phy->type != B43_PHYTYPE_G); - if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) - b43_short_slot_timing_enable(dev); - else - b43_short_slot_timing_disable(dev); - } - dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_RADIOTAP); /* Adjust the desired TX power level. */ @@ -3399,9 +3408,9 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) } /* Antennas for RX and management frame TX. */ - antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_tx); + antenna = B43_ANTENNA_DEFAULT; b43_mgmtframe_txantenna(dev, antenna); - antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_rx); + antenna = B43_ANTENNA_DEFAULT; if (phy->ops->set_rx_antenna) phy->ops->set_rx_antenna(dev, antenna); @@ -3425,16 +3434,91 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) } } - spin_lock_irqsave(&wl->irq_lock, flags); - b43_interrupt_enable(dev, savedirqs); - mmiowb(); - spin_unlock_irqrestore(&wl->irq_lock, flags); - out_unlock_mutex: +out_mac_enable: + b43_mac_enable(dev); +out_unlock_mutex: mutex_unlock(&wl->mutex); return err; } +static void b43_update_basic_rates(struct b43_wldev *dev, u64 brates) +{ + struct ieee80211_supported_band *sband = + dev->wl->hw->wiphy->bands[b43_current_band(dev->wl)]; + struct ieee80211_rate *rate; + int i; + u16 basic, direct, offset, basic_offset, rateptr; + + for (i = 0; i < sband->n_bitrates; i++) { + rate = &sband->bitrates[i]; + + if (b43_is_cck_rate(rate->hw_value)) { + direct = B43_SHM_SH_CCKDIRECT; + basic = B43_SHM_SH_CCKBASIC; + offset = b43_plcp_get_ratecode_cck(rate->hw_value); + offset &= 0xF; + } else { + direct = B43_SHM_SH_OFDMDIRECT; + basic = B43_SHM_SH_OFDMBASIC; + offset = b43_plcp_get_ratecode_ofdm(rate->hw_value); + offset &= 0xF; + } + + rate = ieee80211_get_response_rate(sband, brates, rate->bitrate); + + if (b43_is_cck_rate(rate->hw_value)) { + basic_offset = b43_plcp_get_ratecode_cck(rate->hw_value); + basic_offset &= 0xF; + } else { + basic_offset = b43_plcp_get_ratecode_ofdm(rate->hw_value); + basic_offset &= 0xF; + } + + /* + * Get the pointer that we need to point to + * from the direct map + */ + rateptr = b43_shm_read16(dev, B43_SHM_SHARED, + direct + 2 * basic_offset); + /* and write it to the basic map */ + b43_shm_write16(dev, B43_SHM_SHARED, basic + 2 * offset, + rateptr); + } +} + +static void b43_op_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *conf, + u32 changed) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + struct b43_wldev *dev; + + mutex_lock(&wl->mutex); + + dev = wl->current_dev; + if (!dev || b43_status(dev) < B43_STAT_STARTED) + goto out_unlock_mutex; + b43_mac_suspend(dev); + + if (changed & BSS_CHANGED_BASIC_RATES) + b43_update_basic_rates(dev, conf->basic_rates); + + if (changed & BSS_CHANGED_ERP_SLOT) { + if (conf->use_short_slot) + b43_short_slot_timing_enable(dev); + else + b43_short_slot_timing_disable(dev); + } + + b43_mac_enable(dev); +out_unlock_mutex: + mutex_unlock(&wl->mutex); + + return; +} + static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, const u8 *local_addr, const u8 *addr, struct ieee80211_key_conf *key) @@ -3445,7 +3529,6 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, u8 algorithm; u8 index; int err; - DECLARE_MAC_BUF(mac); if (modparam_nohwcrypt) return -ENOSPC; /* User disabled HW-crypto */ @@ -3528,15 +3611,18 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, default: B43_WARN_ON(1); } + out_unlock: - spin_unlock_irqrestore(&wl->irq_lock, flags); - mutex_unlock(&wl->mutex); if (!err) { b43dbg(wl, "%s hardware based encryption for keyidx: %d, " - "mac: %s\n", + "mac: %pM\n", cmd == SET_KEY ? "Using" : "Disabling", key->keyidx, - print_mac(mac, addr)); + addr); + b43_dump_keymemory(dev); } + spin_unlock_irqrestore(&wl->irq_lock, flags); + mutex_unlock(&wl->mutex); + return err; } @@ -3598,8 +3684,6 @@ static int b43_op_config_interface(struct ieee80211_hw *hw, if (b43_is_mode(wl, NL80211_IFTYPE_AP) || b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT)) { B43_WARN_ON(vif->type != wl->if_type); - if (conf->changed & IEEE80211_IFCC_SSID) - b43_set_ssid(dev, conf->ssid, conf->ssid_len); if (conf->changed & IEEE80211_IFCC_BEACON) b43_update_templates(wl); } else if (b43_is_mode(wl, NL80211_IFTYPE_ADHOC)) { @@ -3878,22 +3962,6 @@ static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev) #endif /* CONFIG_SSB_DRIVER_PCICORE */ } -/* Write the short and long frame retry limit values. */ -static void b43_set_retry_limits(struct b43_wldev *dev, - unsigned int short_retry, - unsigned int long_retry) -{ - /* The retry limit is a 4-bit counter. Enforce this to avoid overflowing - * the chip-internal counter. */ - short_retry = min(short_retry, (unsigned int)0xF); - long_retry = min(long_retry, (unsigned int)0xF); - - b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_SRLIMIT, - short_retry); - b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_LRLIMIT, - long_retry); -} - static void b43_set_synth_pu_delay(struct b43_wldev *dev, bool idle) { u16 pu_delay; @@ -4214,26 +4282,6 @@ static void b43_op_stop(struct ieee80211_hw *hw) cancel_work_sync(&(wl->txpower_adjust_work)); } -static int b43_op_set_retry_limit(struct ieee80211_hw *hw, - u32 short_retry_limit, u32 long_retry_limit) -{ - struct b43_wl *wl = hw_to_b43_wl(hw); - struct b43_wldev *dev; - int err = 0; - - mutex_lock(&wl->mutex); - dev = wl->current_dev; - if (unlikely(!dev || (b43_status(dev) < B43_STAT_INITIALIZED))) { - err = -ENODEV; - goto out_unlock; - } - b43_set_retry_limits(dev, short_retry_limit, long_retry_limit); -out_unlock: - mutex_unlock(&wl->mutex); - - return err; -} - static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) { @@ -4263,6 +4311,7 @@ static const struct ieee80211_ops b43_hw_ops = { .add_interface = b43_op_add_interface, .remove_interface = b43_op_remove_interface, .config = b43_op_config, + .bss_info_changed = b43_op_bss_info_changed, .config_interface = b43_op_config_interface, .configure_filter = b43_op_configure_filter, .set_key = b43_op_set_key, @@ -4270,7 +4319,6 @@ static const struct ieee80211_ops b43_hw_ops = { .get_tx_stats = b43_op_get_tx_stats, .start = b43_op_start, .stop = b43_op_stop, - .set_retry_limit = b43_op_set_retry_limit, .set_tim = b43_op_beacon_set_tim, .sta_notify = b43_op_sta_notify, }; @@ -4588,7 +4636,7 @@ static int b43_wireless_init(struct ssb_device *dev) BIT(NL80211_IFTYPE_ADHOC); hw->queues = b43_modparam_qos ? 4 : 1; - hw->max_altrates = 1; + hw->max_rates = 2; SET_IEEE80211_DEV(hw, dev->dev); if (is_valid_ether_addr(sprom->et1mac)) SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac); diff --git a/drivers/net/wireless/b43/phy_a.c b/drivers/net/wireless/b43/phy_a.c index 0f1a84c9de6162c41a83c823cc0c0f59492e9594..7fe9d1701624b01051518199ca5574c6663f9c24 100644 --- a/drivers/net/wireless/b43/phy_a.c +++ b/drivers/net/wireless/b43/phy_a.c @@ -77,7 +77,7 @@ static s8 b43_aphy_estimate_power_out(struct b43_wldev *dev, s8 tssi) } #endif -void b43_radio_set_tx_iq(struct b43_wldev *dev) +static void b43_radio_set_tx_iq(struct b43_wldev *dev) { static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 }; static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A }; @@ -147,7 +147,7 @@ static void aphy_channel_switch(struct b43_wldev *dev, unsigned int channel) //FIXME b43_phy_xmitpower(dev); } -void b43_radio_init2060(struct b43_wldev *dev) +static void b43_radio_init2060(struct b43_wldev *dev) { b43_radio_write16(dev, 0x0004, 0x00C0); b43_radio_write16(dev, 0x0005, 0x0008); diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index af37abccccb39e4f3ca7f7c1bcd465ef5fc10ac1..026b61c03fb9fb4432492bc8ddad32a617d72b6a 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -178,13 +178,27 @@ void b43_phy_unlock(struct b43_wldev *dev) b43_power_saving_ctl_bits(dev, 0); } +static inline void assert_mac_suspended(struct b43_wldev *dev) +{ + if (!B43_DEBUG) + return; + if ((b43_status(dev) >= B43_STAT_INITIALIZED) && + (dev->mac_suspended <= 0)) { + b43dbg(dev->wl, "PHY/RADIO register access with " + "enabled MAC.\n"); + dump_stack(); + } +} + u16 b43_radio_read(struct b43_wldev *dev, u16 reg) { + assert_mac_suspended(dev); return dev->phy.ops->radio_read(dev, reg); } void b43_radio_write(struct b43_wldev *dev, u16 reg, u16 value) { + assert_mac_suspended(dev); dev->phy.ops->radio_write(dev, reg, value); } @@ -208,11 +222,13 @@ void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set) u16 b43_phy_read(struct b43_wldev *dev, u16 reg) { + assert_mac_suspended(dev); return dev->phy.ops->phy_read(dev, reg); } void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value) { + assert_mac_suspended(dev); dev->phy.ops->phy_write(dev, reg, value); } @@ -280,8 +296,10 @@ void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state) state = RFKILL_STATE_SOFT_BLOCKED; } + b43_mac_suspend(dev); phy->ops->software_rfkill(dev, state); phy->radio_on = (state == RFKILL_STATE_UNBLOCKED); + b43_mac_enable(dev); } /** diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index 232181f6333c453eb6d0f030c07d60da1d0f2c73..caac4a45f0bf799bcf576c4ec0ede550008bc6ad 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c @@ -54,7 +54,7 @@ static const s8 b43_tssi2dbm_g_table[] = { -20, -20, -20, -20, }; -const u8 b43_radio_channel_codes_bg[] = { +static const u8 b43_radio_channel_codes_bg[] = { 12, 17, 22, 27, 32, 37, 42, 47, 52, 57, 62, 67, @@ -215,9 +215,9 @@ void b43_gphy_set_baseband_attenuation(struct b43_wldev *dev, } /* Adjust the transmission power output (G-PHY) */ -void b43_set_txpower_g(struct b43_wldev *dev, - const struct b43_bbatt *bbatt, - const struct b43_rfatt *rfatt, u8 tx_control) +static void b43_set_txpower_g(struct b43_wldev *dev, + const struct b43_bbatt *bbatt, + const struct b43_rfatt *rfatt, u8 tx_control) { struct b43_phy *phy = &dev->phy; struct b43_phy_g *gphy = phy->g; @@ -383,14 +383,14 @@ static void b43_set_original_gains(struct b43_wldev *dev) } /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ -void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val) +static void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val) { b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset); b43_phy_write(dev, B43_PHY_NRSSILT_DATA, (u16) val); } /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ -s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset) +static s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset) { u16 val; @@ -401,7 +401,7 @@ s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset) } /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ -void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val) +static void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val) { u16 i; s16 tmp; @@ -415,7 +415,7 @@ void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val) } /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ -void b43_nrssi_mem_update(struct b43_wldev *dev) +static void b43_nrssi_mem_update(struct b43_wldev *dev) { struct b43_phy_g *gphy = dev->phy.g; s16 i, delta; @@ -589,7 +589,7 @@ static void b43_calc_nrssi_offset(struct b43_wldev *dev) b43_phy_write(dev, 0x0811, backup[1]); } -void b43_calc_nrssi_slope(struct b43_wldev *dev) +static void b43_calc_nrssi_slope(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; struct b43_phy_g *gphy = phy->g; @@ -1354,7 +1354,7 @@ struct init2050_saved_values { u16 phy_syncctl; }; -u16 b43_radio_init2050(struct b43_wldev *dev) +static u16 b43_radio_init2050(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; struct init2050_saved_values sav; @@ -3047,6 +3047,8 @@ static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev) int rfatt, bbatt; u8 tx_control; + b43_mac_suspend(dev); + spin_lock_irq(&dev->wl->irq_lock); /* Calculate the new attenuation values. */ @@ -3103,6 +3105,8 @@ static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev) gphy->tx_control); b43_radio_unlock(dev); b43_phy_unlock(dev); + + b43_mac_enable(dev); } static enum b43_txpwr_result b43_gphy_op_recalc_txpower(struct b43_wldev *dev, @@ -3215,9 +3219,9 @@ static void b43_gphy_op_pwork_15sec(struct b43_wldev *dev) struct b43_phy *phy = &dev->phy; struct b43_phy_g *gphy = phy->g; + b43_mac_suspend(dev); //TODO: update_aci_moving_average if (gphy->aci_enable && gphy->aci_wlan_automatic) { - b43_mac_suspend(dev); if (!gphy->aci_enable && 1 /*TODO: not scanning? */ ) { if (0 /*TODO: bunch of conditions */ ) { phy->ops->interf_mitigation(dev, @@ -3227,12 +3231,12 @@ static void b43_gphy_op_pwork_15sec(struct b43_wldev *dev) if (/*(aci_average > 1000) &&*/ !b43_gphy_aci_scan(dev)) phy->ops->interf_mitigation(dev, B43_INTERFMODE_NONE); } - b43_mac_enable(dev); } else if (gphy->interfmode == B43_INTERFMODE_NONWLAN && phy->rev == 1) { //TODO: implement rev1 workaround } b43_lo_g_maintanance_work(dev); + b43_mac_enable(dev); } static void b43_gphy_op_pwork_60sec(struct b43_wldev *dev) diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index 4015912675922f4a5e9f8e6249885f70d364c8b1..1036bef8c4cc398e0fe72c16e09c4b43f67c45a3 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -587,9 +587,8 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev, spin_lock(&q->lock); /* IRQs are already disabled. */ info = IEEE80211_SKB_CB(pack->skb); - memset(&info->status, 0, sizeof(info->status)); - b43_fill_txstatus_report(info, status); + b43_fill_txstatus_report(dev, info, status); total_len = pack->skb->len + b43_txhdr_size(dev); total_len = roundup(total_len, 4); diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 2fabcf8f0474253bba1dca6fb46fa7b7afd4584c..eae9b8052658c3c28de328df9016a0bb82917ff8 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -46,7 +46,6 @@ static int b43_plcp_get_bitrate_idx_cck(struct b43_plcp_hdr6 *plcp) case 0x6E: return 3; } - B43_WARN_ON(1); return -1; } @@ -73,7 +72,6 @@ static u8 b43_plcp_get_bitrate_idx_ofdm(struct b43_plcp_hdr6 *plcp, bool aphy) case 0xC: return base + 7; } - B43_WARN_ON(1); return -1; } @@ -185,7 +183,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, u8 *_txhdr, const unsigned char *fragment_data, unsigned int fragment_len, - const struct ieee80211_tx_info *info, + struct ieee80211_tx_info *info, u16 cookie) { struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr; @@ -202,6 +200,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, u16 phy_ctl = 0; u8 extra_ft = 0; struct ieee80211_rate *txrate; + struct ieee80211_tx_rate *rates; memset(txhdr, 0, sizeof(*txhdr)); @@ -291,7 +290,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, phy_ctl |= B43_TXH_PHY_ENC_OFDM; else phy_ctl |= B43_TXH_PHY_ENC_CCK; - if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE) + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) phy_ctl |= B43_TXH_PHY_SHORTPRMBL; switch (b43_ieee80211_antenna_sanitize(dev, info->antenna_sel_tx)) { @@ -314,6 +313,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, B43_WARN_ON(1); } + rates = info->control.rates; /* MAC control */ if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) mac_ctl |= B43_TXH_MAC_ACK; @@ -324,12 +324,22 @@ int b43_generate_txhdr(struct b43_wldev *dev, mac_ctl |= B43_TXH_MAC_STMSDU; if (phy->type == B43_PHYTYPE_A) mac_ctl |= B43_TXH_MAC_5GHZ; - if (info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT) + + /* Overwrite rates[0].count to make the retry calculation + * in the tx status easier. need the actual retry limit to + * detect whether the fallback rate was used. + */ + if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || + (rates[0].count <= dev->wl->hw->conf.long_frame_max_tx_count)) { + rates[0].count = dev->wl->hw->conf.long_frame_max_tx_count; mac_ctl |= B43_TXH_MAC_LONGFRAME; + } else { + rates[0].count = dev->wl->hw->conf.short_frame_max_tx_count; + } /* Generate the RTS or CTS-to-self frame */ - if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) || - (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) { + if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || + (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) { unsigned int len; struct ieee80211_hdr *hdr; int rts_rate, rts_rate_fb; @@ -344,7 +354,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, rts_rate_fb = b43_calc_fallback_rate(rts_rate); rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb); - if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { + if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { struct ieee80211_cts *cts; if (b43_is_old_txhdr_format(dev)) { @@ -596,6 +606,8 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) phytype == B43_PHYTYPE_A); else status.rate_idx = b43_plcp_get_bitrate_idx_cck(plcp); + if (unlikely(status.rate_idx == -1)) + goto drop; status.antenna = !!(phystat0 & B43_RX_PHYST0_ANT); /* @@ -687,10 +699,18 @@ void b43_handle_txstatus(struct b43_wldev *dev, /* Fill out the mac80211 TXstatus report based on the b43-specific * txstatus report data. This returns a boolean whether the frame was * successfully transmitted. */ -bool b43_fill_txstatus_report(struct ieee80211_tx_info *report, +bool b43_fill_txstatus_report(struct b43_wldev *dev, + struct ieee80211_tx_info *report, const struct b43_txstatus *status) { bool frame_success = 1; + int retry_limit; + + /* preserve the confiured retry limit before clearing the status + * The xmit function has overwritten the rc's value with the actual + * retry limit done by the hardware */ + retry_limit = report->status.rates[0].count; + ieee80211_tx_info_clear_status(report); if (status->acked) { /* The frame was ACKed. */ @@ -700,14 +720,32 @@ bool b43_fill_txstatus_report(struct ieee80211_tx_info *report, if (!(report->flags & IEEE80211_TX_CTL_NO_ACK)) { /* ...but we expected an ACK. */ frame_success = 0; - report->status.excessive_retries = 1; } } if (status->frame_count == 0) { /* The frame was not transmitted at all. */ - report->status.retry_count = 0; - } else - report->status.retry_count = status->frame_count - 1; + report->status.rates[0].count = 0; + } else if (status->rts_count > dev->wl->hw->conf.short_frame_max_tx_count) { + /* + * If the short retries (RTS, not data frame) have exceeded + * the limit, the hw will not have tried the selected rate, + * but will have used the fallback rate instead. + * Don't let the rate control count attempts for the selected + * rate in this case, otherwise the statistics will be off. + */ + report->status.rates[0].count = 0; + report->status.rates[1].count = status->frame_count; + } else { + if (status->frame_count > retry_limit) { + report->status.rates[0].count = retry_limit; + report->status.rates[1].count = status->frame_count - + retry_limit; + + } else { + report->status.rates[0].count = status->frame_count; + report->status.rates[1].idx = -1; + } + } return frame_success; } diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h index 0215faf4754181cb6069b4878349d3d4c48e88d6..4fb2a190f7a74fc8f1a8cd9b44a27beff263281f 100644 --- a/drivers/net/wireless/b43/xmit.h +++ b/drivers/net/wireless/b43/xmit.h @@ -178,7 +178,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, u8 * txhdr, const unsigned char *fragment_data, unsigned int fragment_len, - const struct ieee80211_tx_info *txctl, u16 cookie); + struct ieee80211_tx_info *txctl, u16 cookie); /* Transmit Status */ struct b43_txstatus { @@ -294,7 +294,8 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr); void b43_handle_txstatus(struct b43_wldev *dev, const struct b43_txstatus *status); -bool b43_fill_txstatus_report(struct ieee80211_tx_info *report, +bool b43_fill_txstatus_report(struct b43_wldev *dev, + struct ieee80211_tx_info *report, const struct b43_txstatus *status); void b43_tx_suspend(struct b43_wldev *dev); diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h index c40078e1fff9f3efabfa92f787dcb7217018669d..97b0e06dfe219bf6a4614bcabed70efaa67521b4 100644 --- a/drivers/net/wireless/b43legacy/b43legacy.h +++ b/drivers/net/wireless/b43legacy/b43legacy.h @@ -145,6 +145,10 @@ #define B43legacy_SHM_SH_PRMAXTIME 0x0074 /* Probe Response max time */ #define B43legacy_SHM_SH_PRPHYCTL 0x0188 /* Probe Resp PHY TX control */ /* SHM_SHARED rate tables */ +#define B43legacy_SHM_SH_OFDMDIRECT 0x0480 /* Pointer to OFDM direct map */ +#define B43legacy_SHM_SH_OFDMBASIC 0x04A0 /* Pointer to OFDM basic rate map */ +#define B43legacy_SHM_SH_CCKDIRECT 0x04C0 /* Pointer to CCK direct map */ +#define B43legacy_SHM_SH_CCKBASIC 0x04E0 /* Pointer to CCK basic rate map */ /* SHM_SHARED microcode soft registers */ #define B43legacy_SHM_SH_UCODEREV 0x0000 /* Microcode revision */ #define B43legacy_SHM_SH_UCODEPATCH 0x0002 /* Microcode patchlevel */ @@ -663,7 +667,6 @@ struct b43legacy_wldev { bool bad_frames_preempt;/* Use "Bad Frames Preemption". */ bool dfq_valid; /* Directed frame queue valid (IBSS PS mode, ATIM). */ bool short_preamble; /* TRUE if using short preamble. */ - bool short_slot; /* TRUE if using short slot timing. */ bool radio_hw_enable; /* State of radio hardware enable bit. */ /* PHY/Radio device. */ diff --git a/drivers/net/wireless/b43legacy/debugfs.c b/drivers/net/wireless/b43legacy/debugfs.c index 03ce0821a60eb86e9f327675c9069bc1b64ecb1b..1f85ac569fec0065868fb4341971dfec9c83480f 100644 --- a/drivers/net/wireless/b43legacy/debugfs.c +++ b/drivers/net/wireless/b43legacy/debugfs.c @@ -211,7 +211,7 @@ static ssize_t b43legacy_debugfs_read(struct file *file, char __user *userbuf, struct b43legacy_dfs_file *dfile; ssize_t uninitialized_var(ret); char *buf; - const size_t bufsize = 1024 * 128; + const size_t bufsize = 1024 * 16; /* 16 KiB buffer */ const size_t buforder = get_order(bufsize); int err = 0; diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c index fb6819e40f383442a7c73ceb254f866e1dc6eb9b..3649fc3670988219cd99185fc3acfbec6e162b3e 100644 --- a/drivers/net/wireless/b43legacy/dma.c +++ b/drivers/net/wireless/b43legacy/dma.c @@ -919,7 +919,7 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev, if (!ring->txhdr_cache) goto err_kfree_meta; - dma_test = ssb_dma_map_single(dev->dev, + dma_test = ssb_dma_map_single(dev->dev, ring->txhdr_cache, sizeof(struct b43legacy_txhdr_fw3), DMA_TO_DEVICE); @@ -1411,6 +1411,7 @@ void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, struct b43legacy_dmaring *ring; struct b43legacy_dmadesc_generic *desc; struct b43legacy_dmadesc_meta *meta; + int retry_limit; int slot; ring = parse_cookie(dev, status->cookie, &slot); @@ -1437,25 +1438,42 @@ void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, struct ieee80211_tx_info *info; BUG_ON(!meta->skb); info = IEEE80211_SKB_CB(meta->skb); - /* Call back to inform the ieee80211 subsystem about the - * status of the transmission. - * Some fields of txstat are already filled in dma_tx(). - */ - memset(&info->status, 0, sizeof(info->status)); + /* preserve the confiured retry limit before clearing the status + * The xmit function has overwritten the rc's value with the actual + * retry limit done by the hardware */ + retry_limit = info->status.rates[0].count; + ieee80211_tx_info_clear_status(info); - if (status->acked) { + if (status->acked) info->flags |= IEEE80211_TX_STAT_ACK; + + if (status->rts_count > dev->wl->hw->conf.short_frame_max_tx_count) { + /* + * If the short retries (RTS, not data frame) have exceeded + * the limit, the hw will not have tried the selected rate, + * but will have used the fallback rate instead. + * Don't let the rate control count attempts for the selected + * rate in this case, otherwise the statistics will be off. + */ + info->status.rates[0].count = 0; + info->status.rates[1].count = status->frame_count; } else { - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) - info->status.excessive_retries = 1; + if (status->frame_count > retry_limit) { + info->status.rates[0].count = retry_limit; + info->status.rates[1].count = status->frame_count - + retry_limit; + + } else { + info->status.rates[0].count = status->frame_count; + info->status.rates[1].idx = -1; + } } - if (status->frame_count == 0) { - /* The frame was not transmitted at all. */ - info->status.retry_count = 0; - } else - info->status.retry_count = status->frame_count - - 1; + + /* Call back to inform the ieee80211 subsystem about the + * status of the transmission. + * Some fields of txstat are already filled in dma_tx(). + */ ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb); /* skb is freed by ieee80211_tx_status_irqsafe() */ meta->skb = NULL; diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index c66d57560e7ceb97af514a8c4bc05e07f03e9971..c1324e31d2f6465e0260e4df84e6e85c49c35e28 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -576,13 +576,11 @@ static void b43legacy_set_slot_time(struct b43legacy_wldev *dev, static void b43legacy_short_slot_timing_enable(struct b43legacy_wldev *dev) { b43legacy_set_slot_time(dev, 9); - dev->short_slot = 1; } static void b43legacy_short_slot_timing_disable(struct b43legacy_wldev *dev) { b43legacy_set_slot_time(dev, 20); - dev->short_slot = 0; } /* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable. @@ -1160,29 +1158,6 @@ static void b43legacy_update_templates(struct b43legacy_wl *wl) wl->beacon1_uploaded = 0; } -static void b43legacy_set_ssid(struct b43legacy_wldev *dev, - const u8 *ssid, u8 ssid_len) -{ - u32 tmp; - u16 i; - u16 len; - - len = min((u16)ssid_len, (u16)0x100); - for (i = 0; i < len; i += sizeof(u32)) { - tmp = (u32)(ssid[i + 0]); - if (i + 1 < len) - tmp |= (u32)(ssid[i + 1]) << 8; - if (i + 2 < len) - tmp |= (u32)(ssid[i + 2]) << 16; - if (i + 3 < len) - tmp |= (u32)(ssid[i + 3]) << 24; - b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, - 0x380 + i, tmp); - } - b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, - 0x48, len); -} - static void b43legacy_set_beacon_int(struct b43legacy_wldev *dev, u16 beacon_int) { @@ -2556,26 +2531,27 @@ static int b43legacy_switch_phymode(struct b43legacy_wl *wl, return err; } -static int b43legacy_antenna_from_ieee80211(u8 antenna) +/* Write the short and long frame retry limit values. */ +static void b43legacy_set_retry_limits(struct b43legacy_wldev *dev, + unsigned int short_retry, + unsigned int long_retry) { - switch (antenna) { - case 0: /* default/diversity */ - return B43legacy_ANTENNA_DEFAULT; - case 1: /* Antenna 0 */ - return B43legacy_ANTENNA0; - case 2: /* Antenna 1 */ - return B43legacy_ANTENNA1; - default: - return B43legacy_ANTENNA_DEFAULT; - } + /* The retry limit is a 4-bit counter. Enforce this to avoid overflowing + * the chip-internal counter. */ + short_retry = min(short_retry, (unsigned int)0xF); + long_retry = min(long_retry, (unsigned int)0xF); + + b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, 0x0006, short_retry); + b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, 0x0007, long_retry); } static int b43legacy_op_dev_config(struct ieee80211_hw *hw, - struct ieee80211_conf *conf) + u32 changed) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev; struct b43legacy_phy *phy; + struct ieee80211_conf *conf = &hw->conf; unsigned long flags; unsigned int new_phymode = 0xFFFF; int antenna_tx; @@ -2583,13 +2559,21 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw, int err = 0; u32 savedirqs; - antenna_tx = b43legacy_antenna_from_ieee80211(conf->antenna_sel_tx); - antenna_rx = b43legacy_antenna_from_ieee80211(conf->antenna_sel_rx); + antenna_tx = B43legacy_ANTENNA_DEFAULT; + antenna_rx = B43legacy_ANTENNA_DEFAULT; mutex_lock(&wl->mutex); dev = wl->current_dev; phy = &dev->phy; + if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) + b43legacy_set_retry_limits(dev, + conf->short_frame_max_tx_count, + conf->long_frame_max_tx_count); + changed &= ~IEEE80211_CONF_CHANGE_RETRY_LIMITS; + if (!changed) + goto out_unlock_mutex; + /* Switch the PHY mode (if necessary). */ switch (conf->channel->band) { case IEEE80211_BAND_2GHZ: @@ -2622,16 +2606,6 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw, if (conf->channel->hw_value != phy->channel) b43legacy_radio_selectchannel(dev, conf->channel->hw_value, 0); - /* Enable/Disable ShortSlot timing. */ - if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)) - != dev->short_slot) { - B43legacy_WARN_ON(phy->type != B43legacy_PHYTYPE_G); - if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) - b43legacy_short_slot_timing_enable(dev); - else - b43legacy_short_slot_timing_disable(dev); - } - dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_RADIOTAP); /* Adjust the desired TX power level. */ @@ -2676,6 +2650,104 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw, return err; } +static void b43legacy_update_basic_rates(struct b43legacy_wldev *dev, u64 brates) +{ + struct ieee80211_supported_band *sband = + dev->wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ]; + struct ieee80211_rate *rate; + int i; + u16 basic, direct, offset, basic_offset, rateptr; + + for (i = 0; i < sband->n_bitrates; i++) { + rate = &sband->bitrates[i]; + + if (b43legacy_is_cck_rate(rate->hw_value)) { + direct = B43legacy_SHM_SH_CCKDIRECT; + basic = B43legacy_SHM_SH_CCKBASIC; + offset = b43legacy_plcp_get_ratecode_cck(rate->hw_value); + offset &= 0xF; + } else { + direct = B43legacy_SHM_SH_OFDMDIRECT; + basic = B43legacy_SHM_SH_OFDMBASIC; + offset = b43legacy_plcp_get_ratecode_ofdm(rate->hw_value); + offset &= 0xF; + } + + rate = ieee80211_get_response_rate(sband, brates, rate->bitrate); + + if (b43legacy_is_cck_rate(rate->hw_value)) { + basic_offset = b43legacy_plcp_get_ratecode_cck(rate->hw_value); + basic_offset &= 0xF; + } else { + basic_offset = b43legacy_plcp_get_ratecode_ofdm(rate->hw_value); + basic_offset &= 0xF; + } + + /* + * Get the pointer that we need to point to + * from the direct map + */ + rateptr = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, + direct + 2 * basic_offset); + /* and write it to the basic map */ + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, + basic + 2 * offset, rateptr); + } +} + +static void b43legacy_op_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *conf, + u32 changed) +{ + struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); + struct b43legacy_wldev *dev; + struct b43legacy_phy *phy; + unsigned long flags; + u32 savedirqs; + + mutex_lock(&wl->mutex); + + dev = wl->current_dev; + phy = &dev->phy; + + /* Disable IRQs while reconfiguring the device. + * This makes it possible to drop the spinlock throughout + * the reconfiguration process. */ + spin_lock_irqsave(&wl->irq_lock, flags); + if (b43legacy_status(dev) < B43legacy_STAT_STARTED) { + spin_unlock_irqrestore(&wl->irq_lock, flags); + goto out_unlock_mutex; + } + savedirqs = b43legacy_interrupt_disable(dev, B43legacy_IRQ_ALL); + spin_unlock_irqrestore(&wl->irq_lock, flags); + b43legacy_synchronize_irq(dev); + + b43legacy_mac_suspend(dev); + + if (changed & BSS_CHANGED_BASIC_RATES) + b43legacy_update_basic_rates(dev, conf->basic_rates); + + if (changed & BSS_CHANGED_ERP_SLOT) { + if (conf->use_short_slot) + b43legacy_short_slot_timing_enable(dev); + else + b43legacy_short_slot_timing_disable(dev); + } + + b43legacy_mac_enable(dev); + + spin_lock_irqsave(&wl->irq_lock, flags); + b43legacy_interrupt_enable(dev, savedirqs); + /* XXX: why? */ + mmiowb(); + spin_unlock_irqrestore(&wl->irq_lock, flags); + out_unlock_mutex: + mutex_unlock(&wl->mutex); + + return; +} + static void b43legacy_op_configure_filter(struct ieee80211_hw *hw, unsigned int changed, unsigned int *fflags, @@ -2735,7 +2807,6 @@ static int b43legacy_op_config_interface(struct ieee80211_hw *hw, if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) { if (b43legacy_is_mode(wl, NL80211_IFTYPE_AP)) { B43legacy_WARN_ON(vif->type != NL80211_IFTYPE_AP); - b43legacy_set_ssid(dev, conf->ssid, conf->ssid_len); if (conf->changed & IEEE80211_IFCC_BEACON) b43legacy_update_templates(wl); } else if (b43legacy_is_mode(wl, NL80211_IFTYPE_ADHOC)) { @@ -3002,20 +3073,6 @@ static void b43legacy_imcfglo_timeouts_workaround(struct b43legacy_wldev *dev) #endif /* CONFIG_SSB_DRIVER_PCICORE */ } -/* Write the short and long frame retry limit values. */ -static void b43legacy_set_retry_limits(struct b43legacy_wldev *dev, - unsigned int short_retry, - unsigned int long_retry) -{ - /* The retry limit is a 4-bit counter. Enforce this to avoid overflowing - * the chip-internal counter. */ - short_retry = min(short_retry, (unsigned int)0xF); - long_retry = min(long_retry, (unsigned int)0xF); - - b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, 0x0006, short_retry); - b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, 0x0007, long_retry); -} - static void b43legacy_set_synth_pu_delay(struct b43legacy_wldev *dev, bool idle) { u16 pu_delay = 1050; @@ -3380,28 +3437,6 @@ static void b43legacy_op_stop(struct ieee80211_hw *hw) mutex_unlock(&wl->mutex); } -static int b43legacy_op_set_retry_limit(struct ieee80211_hw *hw, - u32 short_retry_limit, - u32 long_retry_limit) -{ - struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); - struct b43legacy_wldev *dev; - int err = 0; - - mutex_lock(&wl->mutex); - dev = wl->current_dev; - if (unlikely(!dev || - (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED))) { - err = -ENODEV; - goto out_unlock; - } - b43legacy_set_retry_limits(dev, short_retry_limit, long_retry_limit); -out_unlock: - mutex_unlock(&wl->mutex); - - return err; -} - static int b43legacy_op_beacon_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) { @@ -3421,13 +3456,13 @@ static const struct ieee80211_ops b43legacy_hw_ops = { .add_interface = b43legacy_op_add_interface, .remove_interface = b43legacy_op_remove_interface, .config = b43legacy_op_dev_config, + .bss_info_changed = b43legacy_op_bss_info_changed, .config_interface = b43legacy_op_config_interface, .configure_filter = b43legacy_op_configure_filter, .get_stats = b43legacy_op_get_stats, .get_tx_stats = b43legacy_op_get_tx_stats, .start = b43legacy_op_start, .stop = b43legacy_op_stop, - .set_retry_limit = b43legacy_op_set_retry_limit, .set_tim = b43legacy_op_beacon_set_tim, }; @@ -3710,7 +3745,7 @@ static int b43legacy_wireless_init(struct ssb_device *dev) BIT(NL80211_IFTYPE_WDS) | BIT(NL80211_IFTYPE_ADHOC); hw->queues = 1; /* FIXME: hardware has more queues */ - hw->max_altrates = 1; + hw->max_rates = 2; SET_IEEE80211_DEV(hw, dev->dev); if (is_valid_ether_addr(sprom->et1mac)) SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac); diff --git a/drivers/net/wireless/b43legacy/phy.c b/drivers/net/wireless/b43legacy/phy.c index 4c9442b16f3fb51ce9505ac5ac013d2d453d6f49..11319ec2d64a75d0788a3e6ea97357973b766da5 100644 --- a/drivers/net/wireless/b43legacy/phy.c +++ b/drivers/net/wireless/b43legacy/phy.c @@ -1296,12 +1296,10 @@ void b43legacy_lo_write(struct b43legacy_wldev *dev, /* Sanity check. */ if (pair->low < -8 || pair->low > 8 || pair->high < -8 || pair->high > 8) { - struct b43legacy_phy *phy = &dev->phy; b43legacydbg(dev->wl, "WARNING: Writing invalid LOpair " - "(low: %d, high: %d, index: %lu)\n", - pair->low, pair->high, - (unsigned long)(pair - phy->_lo_pairs)); + "(low: %d, high: %d)\n", + pair->low, pair->high); dump_stack(); } #endif diff --git a/drivers/net/wireless/b43legacy/pio.c b/drivers/net/wireless/b43legacy/pio.c index a86c7647fa2d62caec9027d316f3ddd648f156a6..746d5361bba017b56838c6cf5b5c54add2cd0317 100644 --- a/drivers/net/wireless/b43legacy/pio.c +++ b/drivers/net/wireless/b43legacy/pio.c @@ -491,6 +491,7 @@ void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev, struct b43legacy_pioqueue *queue; struct b43legacy_pio_txpacket *packet; struct ieee80211_tx_info *info; + int retry_limit; queue = parse_cookie(dev, status->cookie, &packet); B43legacy_WARN_ON(!queue); @@ -503,11 +504,37 @@ void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev, sizeof(struct b43legacy_txhdr_fw3)); info = IEEE80211_SKB_CB(packet->skb); - memset(&info->status, 0, sizeof(info->status)); + + /* preserve the confiured retry limit before clearing the status + * The xmit function has overwritten the rc's value with the actual + * retry limit done by the hardware */ + retry_limit = info->status.rates[0].count; + ieee80211_tx_info_clear_status(info); if (status->acked) info->flags |= IEEE80211_TX_STAT_ACK; - info->status.retry_count = status->frame_count - 1; + + if (status->rts_count > dev->wl->hw->conf.short_frame_max_tx_count) { + /* + * If the short retries (RTS, not data frame) have exceeded + * the limit, the hw will not have tried the selected rate, + * but will have used the fallback rate instead. + * Don't let the rate control count attempts for the selected + * rate in this case, otherwise the statistics will be off. + */ + info->status.rates[0].count = 0; + info->status.rates[1].count = status->frame_count; + } else { + if (status->frame_count > retry_limit) { + info->status.rates[0].count = retry_limit; + info->status.rates[1].count = status->frame_count - + retry_limit; + + } else { + info->status.rates[0].count = status->frame_count; + info->status.rates[1].idx = -1; + } + } ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb); packet->skb = NULL; diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c index 65e833781608ecda0629e85dd6755dcf9104847c..12fca99f7578d28744eb8a815fac0b7a2adcddcd 100644 --- a/drivers/net/wireless/b43legacy/xmit.c +++ b/drivers/net/wireless/b43legacy/xmit.c @@ -188,7 +188,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, struct b43legacy_txhdr_fw3 *txhdr, const unsigned char *fragment_data, unsigned int fragment_len, - const struct ieee80211_tx_info *info, + struct ieee80211_tx_info *info, u16 cookie) { const struct ieee80211_hdr *wlhdr; @@ -201,6 +201,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, u32 mac_ctl = 0; u16 phy_ctl = 0; struct ieee80211_rate *tx_rate; + struct ieee80211_tx_rate *rates; wlhdr = (const struct ieee80211_hdr *)fragment_data; @@ -274,7 +275,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, /* PHY TX Control word */ if (rate_ofdm) phy_ctl |= B43legacy_TX4_PHY_OFDM; - if (dev->short_preamble) + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) phy_ctl |= B43legacy_TX4_PHY_SHORTPRMBL; switch (info->antenna_sel_tx) { case 0: @@ -291,6 +292,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, } /* MAC control */ + rates = info->control.rates; if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) mac_ctl |= B43legacy_TX4_MAC_ACK; if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) @@ -299,12 +301,22 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, mac_ctl |= B43legacy_TX4_MAC_STMSDU; if (rate_fb_ofdm) mac_ctl |= B43legacy_TX4_MAC_FALLBACKOFDM; - if (info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT) + + /* Overwrite rates[0].count to make the retry calculation + * in the tx status easier. need the actual retry limit to + * detect whether the fallback rate was used. + */ + if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || + (rates[0].count <= dev->wl->hw->conf.long_frame_max_tx_count)) { + rates[0].count = dev->wl->hw->conf.long_frame_max_tx_count; mac_ctl |= B43legacy_TX4_MAC_LONGFRAME; + } else { + rates[0].count = dev->wl->hw->conf.short_frame_max_tx_count; + } /* Generate the RTS or CTS-to-self frame */ - if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) || - (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) { + if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || + (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) { unsigned int len; struct ieee80211_hdr *hdr; int rts_rate; @@ -319,7 +331,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, if (rts_rate_fb_ofdm) mac_ctl |= B43legacy_TX4_MAC_CTSFALLBACKOFDM; - if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { + if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { ieee80211_ctstoself_get(dev->wl->hw, info->control.vif, fragment_data, @@ -362,7 +374,7 @@ int b43legacy_generate_txhdr(struct b43legacy_wldev *dev, u8 *txhdr, const unsigned char *fragment_data, unsigned int fragment_len, - const struct ieee80211_tx_info *info, + struct ieee80211_tx_info *info, u16 cookie) { return generate_txhdr_fw3(dev, (struct b43legacy_txhdr_fw3 *)txhdr, diff --git a/drivers/net/wireless/b43legacy/xmit.h b/drivers/net/wireless/b43legacy/xmit.h index e56777e0feabf7f0e4552449e29daf91c8b11577..62e09d02788fb74648b13bfe324c35588ee50d87 100644 --- a/drivers/net/wireless/b43legacy/xmit.h +++ b/drivers/net/wireless/b43legacy/xmit.h @@ -80,7 +80,7 @@ int b43legacy_generate_txhdr(struct b43legacy_wldev *dev, u8 *txhdr, const unsigned char *fragment_data, unsigned int fragment_len, - const struct ieee80211_tx_info *info, + struct ieee80211_tx_info *info, u16 cookie); diff --git a/drivers/net/wireless/hostap/Kconfig b/drivers/net/wireless/hostap/Kconfig index 1fef33169fdd0c133c995bb2d173851674c3848c..932d207bce231955548e6e68adbc1585bb1e4b59 100644 --- a/drivers/net/wireless/hostap/Kconfig +++ b/drivers/net/wireless/hostap/Kconfig @@ -2,8 +2,17 @@ config HOSTAP tristate "IEEE 802.11 for Host AP (Prism2/2.5/3 and WEP/TKIP/CCMP)" depends on WLAN_80211 select WIRELESS_EXT - select IEEE80211 - select IEEE80211_CRYPT_WEP + select CRYPTO + select CRYPTO_ARC4 + select CRYPTO_ECB + select CRYPTO_AES + select CRYPTO_MICHAEL_MIC + select CRYPTO_ECB + select CRC32 + select LIB80211 + select LIB80211_CRYPT_WEP + select LIB80211_CRYPT_TKIP + select LIB80211_CRYPT_CCMP ---help--- Shared driver code for IEEE 802.11b wireless cards based on Intersil Prism2/2.5/3 chipset. This driver supports so called diff --git a/drivers/net/wireless/hostap/hostap.h b/drivers/net/wireless/hostap/hostap.h index 3a386a636cca4a0f2aad3f24cf259908fa1729ef..2453deaa3e009e03faab3f92850d012f6f808bbf 100644 --- a/drivers/net/wireless/hostap/hostap.h +++ b/drivers/net/wireless/hostap/hostap.h @@ -63,7 +63,7 @@ void ap_control_flush_macs(struct mac_restrictions *mac_restrictions); int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev, u8 *mac); void ap_control_kickall(struct ap_data *ap); void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent, - struct ieee80211_crypt_data ***crypt); + struct lib80211_crypt_data ***crypt); int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[], struct iw_quality qual[], int buf_size, int aplist); diff --git a/drivers/net/wireless/hostap/hostap_80211.h b/drivers/net/wireless/hostap/hostap_80211.h index 3694b1eba521cbca531bb56574abb643da79f9a8..3a9474d9a90780b7bbde1b83e2c91f14cd3b27bd 100644 --- a/drivers/net/wireless/hostap/hostap_80211.h +++ b/drivers/net/wireless/hostap/hostap_80211.h @@ -2,7 +2,7 @@ #define HOSTAP_80211_H #include -#include +#include struct hostap_ieee80211_mgmt { __le16 frame_control; diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c index f106bc1585a45bbeacb1c1a6f2716e2ac8dfc1b0..19b1bf0478bd62ae4e34c23a44f6cfb9a7c947f8 100644 --- a/drivers/net/wireless/hostap/hostap_80211_rx.c +++ b/drivers/net/wireless/hostap/hostap_80211_rx.c @@ -1,5 +1,5 @@ #include -#include +#include #include "hostap_80211.h" #include "hostap.h" @@ -19,7 +19,6 @@ void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, { struct ieee80211_hdr_4addr *hdr; u16 fc; - DECLARE_MAC_BUF(mac); hdr = (struct ieee80211_hdr_4addr *) skb->data; @@ -45,11 +44,11 @@ void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id), le16_to_cpu(hdr->seq_ctl)); - printk(KERN_DEBUG " A1=%s", print_mac(mac, hdr->addr1)); - printk(" A2=%s", print_mac(mac, hdr->addr2)); - printk(" A3=%s", print_mac(mac, hdr->addr3)); + printk(KERN_DEBUG " A1=%pM", hdr->addr1); + printk(" A2=%pM", hdr->addr2); + printk(" A3=%pM", hdr->addr3); if (skb->len >= 30) - printk(" A4=%s", print_mac(mac, hdr->addr4)); + printk(" A4=%pM", hdr->addr4); printk("\n"); } @@ -68,7 +67,6 @@ int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb, iface = netdev_priv(dev); local = iface->local; - dev->last_rx = jiffies; if (dev->type == ARPHRD_IEEE80211_PRISM) { if (local->monitor_type == PRISM2_MONITOR_PRISM) { @@ -557,7 +555,6 @@ static int hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr_4addr *hdr, u16 fc, struct net_device **wds) { - DECLARE_MAC_BUF(mac); /* FIX: is this really supposed to accept WDS frames only in Master * mode? What about Repeater or Managed with WDS frames? */ if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) != @@ -573,10 +570,10 @@ hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr_4addr *hdr, hdr->addr1[4] != 0xff || hdr->addr1[5] != 0xff)) { /* RA (or BSSID) is not ours - drop */ PDEBUG(DEBUG_EXTRA2, "%s: received WDS frame with " - "not own or broadcast %s=%s\n", + "not own or broadcast %s=%pM\n", local->dev->name, fc & IEEE80211_FCTL_FROMDS ? "RA" : "BSSID", - print_mac(mac, hdr->addr1)); + hdr->addr1); return -1; } @@ -589,8 +586,8 @@ hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr_4addr *hdr, /* require that WDS link has been registered with TA or the * frame is from current AP when using 'AP client mode' */ PDEBUG(DEBUG_EXTRA, "%s: received WDS[4 addr] frame " - "from unknown TA=%s\n", - local->dev->name, print_mac(mac, hdr->addr2)); + "from unknown TA=%pM\n", + local->dev->name, hdr->addr2); if (local->ap && local->ap->autom_ap_wds) hostap_wds_link_oper(local, hdr->addr2, WDS_ADD); return -1; @@ -652,7 +649,7 @@ static int hostap_is_eapol_frame(local_info_t *local, struct sk_buff *skb) /* Called only as a tasklet (software IRQ) */ static int hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb, - struct ieee80211_crypt_data *crypt) + struct lib80211_crypt_data *crypt) { struct ieee80211_hdr_4addr *hdr; int res, hdrlen; @@ -667,10 +664,8 @@ hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb, strcmp(crypt->ops->name, "TKIP") == 0) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " - "received packet from " MAC_FMT "\n", - local->dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5]); + "received packet from %pM\n", + local->dev->name, hdr->addr2); } return -1; } @@ -679,12 +674,8 @@ hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb, res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv); atomic_dec(&crypt->refcnt); if (res < 0) { - printk(KERN_DEBUG "%s: decryption failed (SA=" MAC_FMT - ") res=%d\n", - local->dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5], - res); + printk(KERN_DEBUG "%s: decryption failed (SA=%pM) res=%d\n", + local->dev->name, hdr->addr2, res); local->comm_tallies.rx_discards_wep_undecryptable++; return -1; } @@ -696,11 +687,10 @@ hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb, /* Called only as a tasklet (software IRQ) */ static int hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb, - int keyidx, struct ieee80211_crypt_data *crypt) + int keyidx, struct lib80211_crypt_data *crypt) { struct ieee80211_hdr_4addr *hdr; int res, hdrlen; - DECLARE_MAC_BUF(mac); if (crypt == NULL || crypt->ops->decrypt_msdu == NULL) return 0; @@ -713,8 +703,8 @@ hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb, atomic_dec(&crypt->refcnt); if (res < 0) { printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed" - " (SA=%s keyidx=%d)\n", - local->dev->name, print_mac(mac, hdr->addr2), keyidx); + " (SA=%pM keyidx=%d)\n", + local->dev->name, hdr->addr2, keyidx); return -1; } @@ -743,7 +733,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, int from_assoc_ap = 0; u8 dst[ETH_ALEN]; u8 src[ETH_ALEN]; - struct ieee80211_crypt_data *crypt = NULL; + struct lib80211_crypt_data *crypt = NULL; void *sta = NULL; int keyidx = 0; @@ -795,7 +785,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, int idx = 0; if (skb->len >= hdrlen + 3) idx = skb->data[hdrlen + 3] >> 6; - crypt = local->crypt[idx]; + crypt = local->crypt_info.crypt[idx]; sta = NULL; /* Use station specific key to override default keys if the @@ -822,10 +812,8 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, * frames silently instead of filling system log with * these reports. */ printk(KERN_DEBUG "%s: WEP decryption failed (not set)" - " (SA=" MAC_FMT ")\n", - local->dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5]); + " (SA=%pM)\n", + local->dev->name, hdr->addr2); #endif local->comm_tallies.rx_discards_wep_undecryptable++; goto rx_dropped; @@ -839,9 +827,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, (keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0) { printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth " - "from " MAC_FMT "\n", dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5]); + "from %pM\n", dev->name, hdr->addr2); /* TODO: could inform hostapd about this so that it * could send auth failure report */ goto rx_dropped; @@ -896,8 +882,6 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, from_assoc_ap = 1; } - dev->last_rx = jiffies; - if ((local->iw_mode == IW_MODE_MASTER || local->iw_mode == IW_MODE_REPEAT) && !from_assoc_ap) { @@ -1009,10 +993,8 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, "unencrypted EAPOL frame\n", local->dev->name); } else { printk(KERN_DEBUG "%s: encryption configured, but RX " - "frame not encrypted (SA=" MAC_FMT ")\n", - local->dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5]); + "frame not encrypted (SA=%pM)\n", + local->dev->name, hdr->addr2); goto rx_dropped; } } @@ -1021,10 +1003,8 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, !hostap_is_eapol_frame(local, skb)) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: dropped unencrypted RX data " - "frame from " MAC_FMT " (drop_unencrypted=1)\n", - dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5]); + "frame from %pM (drop_unencrypted=1)\n", + dev->name, hdr->addr2); } goto rx_dropped; } diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c index 921c984416f8b03270e57b199b2be839a6e61b50..078a010f39a0835c765d5e706f7f53600aa8d30a 100644 --- a/drivers/net/wireless/hostap/hostap_80211_tx.c +++ b/drivers/net/wireless/hostap/hostap_80211_tx.c @@ -17,7 +17,6 @@ void hostap_dump_tx_80211(const char *name, struct sk_buff *skb) { struct ieee80211_hdr_4addr *hdr; u16 fc; - DECLARE_MAC_BUF(mac); hdr = (struct ieee80211_hdr_4addr *) skb->data; @@ -41,11 +40,11 @@ void hostap_dump_tx_80211(const char *name, struct sk_buff *skb) printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id), le16_to_cpu(hdr->seq_ctl)); - printk(KERN_DEBUG " A1=%s", print_mac(mac, hdr->addr1)); - printk(" A2=%s", print_mac(mac, hdr->addr2)); - printk(" A3=%s", print_mac(mac, hdr->addr3)); + printk(KERN_DEBUG " A1=%pM", hdr->addr1); + printk(" A2=%pM", hdr->addr2); + printk(" A3=%pM", hdr->addr3); if (skb->len >= 30) - printk(" A4=%s", print_mac(mac, hdr->addr4)); + printk(" A4=%pM", hdr->addr4); printk("\n"); } @@ -307,7 +306,7 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Called only from software IRQ */ static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, - struct ieee80211_crypt_data *crypt) + struct lib80211_crypt_data *crypt) { struct hostap_interface *iface; local_info_t *local; @@ -328,10 +327,8 @@ static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, hdr = (struct ieee80211_hdr_4addr *) skb->data; if (net_ratelimit()) { printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " - "TX packet to " MAC_FMT "\n", - local->dev->name, - hdr->addr1[0], hdr->addr1[1], hdr->addr1[2], - hdr->addr1[3], hdr->addr1[4], hdr->addr1[5]); + "TX packet to %pM\n", + local->dev->name, hdr->addr1); } kfree_skb(skb); return NULL; @@ -408,7 +405,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) if (local->host_encrypt) { /* Set crypt to default algorithm and key; will be replaced in * AP code if STA has own alg/key */ - tx.crypt = local->crypt[local->tx_keyidx]; + tx.crypt = local->crypt_info.crypt[local->crypt_info.tx_keyidx]; tx.host_encrypt = 1; } else { tx.crypt = NULL; @@ -490,7 +487,9 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) if (tx.crypt && (!tx.crypt->ops || !tx.crypt->ops->encrypt_mpdu)) tx.crypt = NULL; - else if ((tx.crypt || local->crypt[local->tx_keyidx]) && !no_encrypt) { + else if ((tx.crypt || + local->crypt_info.crypt[local->crypt_info.tx_keyidx]) && + !no_encrypt) { /* Add ISWEP flag both for firmware and host based encryption */ fc |= IEEE80211_FCTL_PROTECTED; diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c index af3d4ef2a80b75218b52f538e93e58e8215f5930..0903db786d5f94d565e67ed82d7a42216eb41cf9 100644 --- a/drivers/net/wireless/hostap/hostap_ap.c +++ b/drivers/net/wireless/hostap/hostap_ap.c @@ -94,7 +94,6 @@ static void ap_sta_hash_add(struct ap_data *ap, struct sta_info *sta) static void ap_sta_hash_del(struct ap_data *ap, struct sta_info *sta) { struct sta_info *s; - DECLARE_MAC_BUF(mac); s = ap->sta_hash[STA_HASH(sta->addr)]; if (s == NULL) return; @@ -109,20 +108,18 @@ static void ap_sta_hash_del(struct ap_data *ap, struct sta_info *sta) if (s->hnext != NULL) s->hnext = s->hnext->hnext; else - printk("AP: could not remove STA %s" - " from hash table\n", - print_mac(mac, sta->addr)); + printk("AP: could not remove STA %pM from hash table\n", + sta->addr); } static void ap_free_sta(struct ap_data *ap, struct sta_info *sta) { - DECLARE_MAC_BUF(mac); if (sta->ap && sta->local) hostap_event_expired_sta(sta->local->dev, sta); if (ap->proc != NULL) { char name[20]; - sprintf(name, "%s", print_mac(mac, sta->addr)); + sprintf(name, "%pM", sta->addr); remove_proc_entry(name, ap->proc); } @@ -185,7 +182,6 @@ static void ap_handle_timer(unsigned long data) struct ap_data *ap; unsigned long next_time = 0; int was_assoc; - DECLARE_MAC_BUF(mac); if (sta == NULL || sta->local == NULL || sta->local->ap == NULL) { PDEBUG(DEBUG_AP, "ap_handle_timer() called with NULL data\n"); @@ -242,8 +238,8 @@ static void ap_handle_timer(unsigned long data) if (sta->ap) { if (ap->autom_ap_wds) { PDEBUG(DEBUG_AP, "%s: removing automatic WDS " - "connection to AP %s\n", - local->dev->name, print_mac(mac, sta->addr)); + "connection to AP %pM\n", + local->dev->name, sta->addr); hostap_wds_link_oper(local, sta->addr, WDS_DEL); } } else if (sta->timeout_next == STA_NULLFUNC) { @@ -259,11 +255,11 @@ static void ap_handle_timer(unsigned long data) } else { int deauth = sta->timeout_next == STA_DEAUTH; __le16 resp; - PDEBUG(DEBUG_AP, "%s: sending %s info to STA %s" + PDEBUG(DEBUG_AP, "%s: sending %s info to STA %pM" "(last=%lu, jiffies=%lu)\n", local->dev->name, deauth ? "deauthentication" : "disassociation", - print_mac(mac, sta->addr), sta->last_rx, jiffies); + sta->addr, sta->last_rx, jiffies); resp = cpu_to_le16(deauth ? WLAN_REASON_PREV_AUTH_NOT_VALID : WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); @@ -275,10 +271,10 @@ static void ap_handle_timer(unsigned long data) if (sta->timeout_next == STA_DEAUTH) { if (sta->flags & WLAN_STA_PERM) { - PDEBUG(DEBUG_AP, "%s: STA %s" + PDEBUG(DEBUG_AP, "%s: STA %pM" " would have been removed, " "but it has 'perm' flag\n", - local->dev->name, print_mac(mac, sta->addr)); + local->dev->name, sta->addr); } else ap_free_sta(ap, sta); return; @@ -332,7 +328,6 @@ static int ap_control_proc_read(char *page, char **start, off_t off, struct ap_data *ap = (struct ap_data *) data; char *policy_txt; struct mac_entry *entry; - DECLARE_MAC_BUF(mac); if (off != 0) { *eof = 1; @@ -363,7 +358,7 @@ static int ap_control_proc_read(char *page, char **start, off_t off, break; } - p += sprintf(p, "%s\n", print_mac(mac, entry->addr)); + p += sprintf(p, "%pM\n", entry->addr); } spin_unlock_bh(&ap->mac_restrictions.lock); @@ -520,7 +515,6 @@ static int prism2_ap_proc_read(char *page, char **start, off_t off, struct ap_data *ap = (struct ap_data *) data; struct sta_info *sta; int i; - DECLARE_MAC_BUF(mac); if (off > PROC_LIMIT) { *eof = 1; @@ -533,8 +527,8 @@ static int prism2_ap_proc_read(char *page, char **start, off_t off, if (!sta->ap) continue; - p += sprintf(p, "%s %d %d %d %d '", - print_mac(mac, sta->addr), + p += sprintf(p, "%pM %d %d %d %d '", + sta->addr, sta->u.ap.channel, sta->last_rx_signal, sta->last_rx_silence, sta->last_rx_rate); for (i = 0; i < sta->u.ap.ssid_len; i++) @@ -683,11 +677,9 @@ static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data) if (sta) atomic_dec(&sta->users); if (txt) { - PDEBUG(DEBUG_AP, "%s: " MAC_FMT " auth_cb - alg=%d " + PDEBUG(DEBUG_AP, "%s: %pM auth_cb - alg=%d " "trans#=%d status=%d - %s\n", - dev->name, - hdr->addr1[0], hdr->addr1[1], hdr->addr1[2], - hdr->addr1[3], hdr->addr1[4], hdr->addr1[5], + dev->name, hdr->addr1, auth_alg, auth_transaction, status, txt); } dev_kfree_skb(skb); @@ -754,11 +746,8 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data) if (sta) atomic_dec(&sta->users); if (txt) { - PDEBUG(DEBUG_AP, "%s: " MAC_FMT " assoc_cb - %s\n", - dev->name, - hdr->addr1[0], hdr->addr1[1], hdr->addr1[2], - hdr->addr1[3], hdr->addr1[4], hdr->addr1[5], - txt); + PDEBUG(DEBUG_AP, "%s: %pM assoc_cb - %s\n", + dev->name, hdr->addr1, txt); } dev_kfree_skb(skb); } @@ -781,11 +770,9 @@ static void hostap_ap_tx_cb_poll(struct sk_buff *skb, int ok, void *data) sta->flags &= ~WLAN_STA_PENDING_POLL; spin_unlock(&ap->sta_table_lock); } else { - PDEBUG(DEBUG_AP, "%s: STA " MAC_FMT - " did not ACK activity poll frame\n", - ap->local->dev->name, - hdr->addr1[0], hdr->addr1[1], hdr->addr1[2], - hdr->addr1[3], hdr->addr1[4], hdr->addr1[5]); + PDEBUG(DEBUG_AP, + "%s: STA %pM did not ACK activity poll frame\n", + ap->local->dev->name, hdr->addr1); } fail: @@ -1002,7 +989,6 @@ static int prism2_sta_proc_read(char *page, char **start, off_t off, char *p = page; struct sta_info *sta = (struct sta_info *) data; int i; - DECLARE_MAC_BUF(mac); /* FIX: possible race condition.. the STA data could have just expired, * but proc entry was still here so that the read could have started; @@ -1013,11 +999,11 @@ static int prism2_sta_proc_read(char *page, char **start, off_t off, return 0; } - p += sprintf(p, "%s=%s\nusers=%d\naid=%d\n" + p += sprintf(p, "%s=%pM\nusers=%d\naid=%d\n" "flags=0x%04x%s%s%s%s%s%s%s\n" "capability=0x%02x\nlisten_interval=%d\nsupported_rates=", sta->ap ? "AP" : "STA", - print_mac(mac, sta->addr), atomic_read(&sta->users), sta->aid, + sta->addr, atomic_read(&sta->users), sta->aid, sta->flags, sta->flags & WLAN_STA_AUTH ? " AUTH" : "", sta->flags & WLAN_STA_ASSOC ? " ASSOC" : "", @@ -1078,7 +1064,6 @@ static void handle_add_proc_queue(struct work_struct *work) struct sta_info *sta; char name[20]; struct add_sta_proc_data *entry, *prev; - DECLARE_MAC_BUF(mac); entry = ap->add_sta_proc_entries; ap->add_sta_proc_entries = NULL; @@ -1091,7 +1076,7 @@ static void handle_add_proc_queue(struct work_struct *work) spin_unlock_bh(&ap->sta_table_lock); if (sta) { - sprintf(name, "%s", print_mac(mac, sta->addr)); + sprintf(name, "%pM", sta->addr); sta->proc = create_proc_read_entry( name, 0, ap->proc, prism2_sta_proc_read, sta); @@ -1221,7 +1206,7 @@ static void prism2_check_tx_rates(struct sta_info *sta) static void ap_crypt_init(struct ap_data *ap) { - ap->crypt = ieee80211_get_crypto_ops("WEP"); + ap->crypt = lib80211_get_crypto_ops("WEP"); if (ap->crypt) { if (ap->crypt->init) { @@ -1239,7 +1224,7 @@ static void ap_crypt_init(struct ap_data *ap) if (ap->crypt == NULL) { printk(KERN_WARNING "AP could not initialize WEP: load module " - "ieee80211_crypt_wep.ko\n"); + "lib80211_crypt_wep.ko\n"); } } @@ -1308,7 +1293,7 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb, __le16 *pos; u16 resp = WLAN_STATUS_SUCCESS, fc; struct sta_info *sta = NULL; - struct ieee80211_crypt_data *crypt; + struct lib80211_crypt_data *crypt; char *txt = ""; len = skb->len - IEEE80211_MGMT_HDR_LEN; @@ -1318,9 +1303,7 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb, if (len < 6) { PDEBUG(DEBUG_AP, "%s: handle_authen - too short payload " - "(len=%d) from " MAC_FMT "\n", dev->name, len, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5]); + "(len=%d) from %pM\n", dev->name, len, hdr->addr2); return; } @@ -1336,7 +1319,7 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb, int idx = 0; if (skb->len >= hdrlen + 3) idx = skb->data[hdrlen + 3] >> 6; - crypt = local->crypt[idx]; + crypt = local->crypt_info.crypt[idx]; } pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); @@ -1385,10 +1368,8 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb, if (time_after(jiffies, sta->u.ap.last_beacon + (10 * sta->listen_interval * HZ) / 1024)) { PDEBUG(DEBUG_AP, "%s: no beacons received for a while," - " assuming AP " MAC_FMT " is now STA\n", - dev->name, - sta->addr[0], sta->addr[1], sta->addr[2], - sta->addr[3], sta->addr[4], sta->addr[5]); + " assuming AP %pM is now STA\n", + dev->name, sta->addr); sta->ap = 0; sta->flags = 0; sta->u.sta.challenge = NULL; @@ -1503,11 +1484,9 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb, } if (resp) { - PDEBUG(DEBUG_AP, "%s: " MAC_FMT " auth (alg=%d " + PDEBUG(DEBUG_AP, "%s: %pM auth (alg=%d " "trans#=%d stat=%d len=%d fc=%04x) ==> %d (%s)\n", - dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5], + dev->name, hdr->addr2, auth_alg, auth_transaction, status_code, len, fc, resp, txt); } @@ -1533,10 +1512,8 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb, if (len < (reassoc ? 10 : 4)) { PDEBUG(DEBUG_AP, "%s: handle_assoc - too short payload " - "(len=%d, reassoc=%d) from " MAC_FMT "\n", - dev->name, len, reassoc, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5]); + "(len=%d, reassoc=%d) from %pM\n", + dev->name, len, reassoc, hdr->addr2); return; } @@ -1613,12 +1590,9 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb, } if (left > 0) { - PDEBUG(DEBUG_AP, "%s: assoc from " MAC_FMT + PDEBUG(DEBUG_AP, "%s: assoc from %pM" " with extra data (%d bytes) [", - dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5], - left); + dev->name, hdr->addr2, left); while (left > 0) { PDEBUG2(DEBUG_AP, "<%02x>", *u); u++; left--; @@ -1717,14 +1691,12 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb, } #if 0 - PDEBUG(DEBUG_AP, "%s: " MAC_FMT" %sassoc (len=%d " - "prev_ap=" MAC_FMT") => %d(%d) (%s)\n", + PDEBUG(DEBUG_AP, "%s: %pM %sassoc (len=%d " + "prev_ap=%pM) => %d(%d) (%s)\n", dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5], + hdr->addr2, reassoc ? "re" : "", len, - prev_ap[0], prev_ap[1], prev_ap[2], - prev_ap[3], prev_ap[4], prev_ap[5], + prev_ap, resp, send_deauth, txt); #endif } @@ -1741,7 +1713,6 @@ static void handle_deauth(local_info_t *local, struct sk_buff *skb, u16 reason_code; __le16 *pos; struct sta_info *sta = NULL; - DECLARE_MAC_BUF(mac); len = skb->len - IEEE80211_MGMT_HDR_LEN; @@ -1753,10 +1724,8 @@ static void handle_deauth(local_info_t *local, struct sk_buff *skb, pos = (__le16 *) body; reason_code = le16_to_cpu(*pos); - PDEBUG(DEBUG_AP, "%s: deauthentication: " MAC_FMT " len=%d, " - "reason_code=%d\n", dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5], + PDEBUG(DEBUG_AP, "%s: deauthentication: %pM len=%d, " + "reason_code=%d\n", dev->name, hdr->addr2, len, reason_code); spin_lock_bh(&local->ap->sta_table_lock); @@ -1768,11 +1737,9 @@ static void handle_deauth(local_info_t *local, struct sk_buff *skb, } spin_unlock_bh(&local->ap->sta_table_lock); if (sta == NULL) { - printk("%s: deauthentication from " MAC_FMT ", " + printk("%s: deauthentication from %pM, " "reason_code=%d, but STA not authenticated\n", dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5], - reason_code); + hdr->addr2, reason_code); } } @@ -1799,10 +1766,8 @@ static void handle_disassoc(local_info_t *local, struct sk_buff *skb, pos = (__le16 *) body; reason_code = le16_to_cpu(*pos); - PDEBUG(DEBUG_AP, "%s: disassociation: " MAC_FMT " len=%d, " - "reason_code=%d\n", dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5], + PDEBUG(DEBUG_AP, "%s: disassociation: %pM len=%d, " + "reason_code=%d\n", dev->name, hdr->addr2, len, reason_code); spin_lock_bh(&local->ap->sta_table_lock); @@ -1814,12 +1779,9 @@ static void handle_disassoc(local_info_t *local, struct sk_buff *skb, } spin_unlock_bh(&local->ap->sta_table_lock); if (sta == NULL) { - printk("%s: disassociation from " MAC_FMT ", " + printk("%s: disassociation from %pM, " "reason_code=%d, but STA not authenticated\n", - dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5], - reason_code); + dev->name, hdr->addr2, reason_code); } } @@ -1909,19 +1871,14 @@ static void handle_pspoll(local_info_t *local, u16 aid; struct sk_buff *skb; - PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=" MAC_FMT - ", TA=" MAC_FMT " PWRMGT=%d\n", - hdr->addr1[0], hdr->addr1[1], hdr->addr1[2], - hdr->addr1[3], hdr->addr1[4], hdr->addr1[5], - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5], + PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=%pM, TA=%pM PWRMGT=%d\n", + hdr->addr1, hdr->addr2, !!(le16_to_cpu(hdr->frame_ctl) & IEEE80211_FCTL_PM)); if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) { - PDEBUG(DEBUG_AP, "handle_pspoll - addr1(BSSID)=" MAC_FMT - " not own MAC\n", - hdr->addr1[0], hdr->addr1[1], hdr->addr1[2], - hdr->addr1[3], hdr->addr1[4], hdr->addr1[5]); + PDEBUG(DEBUG_AP, + "handle_pspoll - addr1(BSSID)=%pM not own MAC\n", + hdr->addr1); return; } @@ -2007,11 +1964,10 @@ static void handle_wds_oper_queue(struct work_struct *work) while (entry) { PDEBUG(DEBUG_AP, "%s: %s automatic WDS connection " - "to AP " MAC_FMT "\n", + "to AP %pM\n", local->dev->name, entry->type == WDS_ADD ? "adding" : "removing", - entry->addr[0], entry->addr[1], entry->addr[2], - entry->addr[3], entry->addr[4], entry->addr[5]); + entry->addr); if (entry->type == WDS_ADD) prism2_wds_add(local, entry->addr, 0); else if (entry->type == WDS_DEL) @@ -2215,10 +2171,8 @@ static void handle_ap_item(local_info_t *local, struct sk_buff *skb, } if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) { - PDEBUG(DEBUG_AP, "handle_ap_item - addr1(BSSID)=" - MAC_FMT " not own MAC\n", - hdr->addr1[0], hdr->addr1[1], hdr->addr1[2], - hdr->addr1[3], hdr->addr1[4], hdr->addr1[5]); + PDEBUG(DEBUG_AP, "handle_ap_item - addr1(BSSID)=%pM" + " not own MAC\n", hdr->addr1); goto done; } @@ -2254,18 +2208,14 @@ static void handle_ap_item(local_info_t *local, struct sk_buff *skb, } if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) { - PDEBUG(DEBUG_AP, "handle_ap_item - addr1(DA)=" MAC_FMT - " not own MAC\n", - hdr->addr1[0], hdr->addr1[1], hdr->addr1[2], - hdr->addr1[3], hdr->addr1[4], hdr->addr1[5]); + PDEBUG(DEBUG_AP, "handle_ap_item - addr1(DA)=%pM" + " not own MAC\n", hdr->addr1); goto done; } if (memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN)) { - PDEBUG(DEBUG_AP, "handle_ap_item - addr3(BSSID)=" MAC_FMT - " not own MAC\n", - hdr->addr3[0], hdr->addr3[1], hdr->addr3[2], - hdr->addr3[3], hdr->addr3[4], hdr->addr3[5]); + PDEBUG(DEBUG_AP, "handle_ap_item - addr3(BSSID)=%pM" + " not own MAC\n", hdr->addr3); goto done; } @@ -2366,10 +2316,9 @@ static void schedule_packet_send(local_info_t *local, struct sta_info *sta) memcpy(hdr->addr2, sta->addr, ETH_ALEN); hdr->duration_id = cpu_to_le16(sta->aid | BIT(15) | BIT(14)); - PDEBUG(DEBUG_PS2, "%s: Scheduling buffered packet delivery for STA " - MAC_FMT "\n", local->dev->name, - sta->addr[0], sta->addr[1], sta->addr[2], - sta->addr[3], sta->addr[4], sta->addr[5]); + PDEBUG(DEBUG_PS2, + "%s: Scheduling buffered packet delivery for STA %pM\n", + local->dev->name, sta->addr); skb->dev = local->dev; @@ -2723,12 +2672,8 @@ static int ap_update_sta_tx_rate(struct sta_info *sta, struct net_device *dev) case 3: sta->tx_rate = 110; break; default: sta->tx_rate = 0; break; } - PDEBUG(DEBUG_AP, "%s: STA " MAC_FMT - " TX rate raised to %d\n", - dev->name, - sta->addr[0], sta->addr[1], sta->addr[2], - sta->addr[3], sta->addr[4], sta->addr[5], - sta->tx_rate); + PDEBUG(DEBUG_AP, "%s: STA %pM TX rate raised to %d\n", + dev->name, sta->addr, sta->tx_rate); } sta->tx_since_last_failure = 0; } @@ -2781,9 +2726,7 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx) * print out any errors here. */ if (net_ratelimit()) { printk(KERN_DEBUG "AP: drop packet to non-associated " - "STA " MAC_FMT "\n", - hdr->addr1[0], hdr->addr1[1], hdr->addr1[2], - hdr->addr1[3], hdr->addr1[4], hdr->addr1[5]); + "STA %pM\n", hdr->addr1); } #endif local->ap->tx_drop_nonassoc++; @@ -2821,11 +2764,9 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx) } if (skb_queue_len(&sta->tx_buf) >= STA_MAX_TX_BUFFER) { - PDEBUG(DEBUG_PS, "%s: No more space in STA (" MAC_FMT - ")'s PS mode buffer\n", - local->dev->name, - sta->addr[0], sta->addr[1], sta->addr[2], - sta->addr[3], sta->addr[4], sta->addr[5]); + PDEBUG(DEBUG_PS, "%s: No more space in STA (%pM)'s" + "PS mode buffer\n", + local->dev->name, sta->addr); /* Make sure that TIM is set for the station (it might not be * after AP wlan hw reset). */ /* FIX: should fix hw reset to restore bits based on STA @@ -2897,12 +2838,9 @@ void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb) sta = ap_get_sta(local->ap, hdr->addr1); if (!sta) { spin_unlock(&local->ap->sta_table_lock); - PDEBUG(DEBUG_AP, "%s: Could not find STA " MAC_FMT + PDEBUG(DEBUG_AP, "%s: Could not find STA %pM" " for this TX error (@%lu)\n", - local->dev->name, - hdr->addr1[0], hdr->addr1[1], hdr->addr1[2], - hdr->addr1[3], hdr->addr1[4], hdr->addr1[5], - jiffies); + local->dev->name, hdr->addr1, jiffies); return; } @@ -2929,12 +2867,9 @@ void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb) case 3: sta->tx_rate = 110; break; default: sta->tx_rate = 0; break; } - PDEBUG(DEBUG_AP, "%s: STA " MAC_FMT - " TX rate lowered to %d\n", - local->dev->name, - sta->addr[0], sta->addr[1], sta->addr[2], - sta->addr[3], sta->addr[4], sta->addr[5], - sta->tx_rate); + PDEBUG(DEBUG_AP, + "%s: STA %pM TX rate lowered to %d\n", + local->dev->name, sta->addr, sta->tx_rate); } sta->tx_consecutive_exc = 0; } @@ -2945,17 +2880,16 @@ void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb) static void hostap_update_sta_ps2(local_info_t *local, struct sta_info *sta, int pwrmgt, int type, int stype) { - DECLARE_MAC_BUF(mac); if (pwrmgt && !(sta->flags & WLAN_STA_PS)) { sta->flags |= WLAN_STA_PS; - PDEBUG(DEBUG_PS2, "STA %s changed to use PS " + PDEBUG(DEBUG_PS2, "STA %pM changed to use PS " "mode (type=0x%02X, stype=0x%02X)\n", - print_mac(mac, sta->addr), type >> 2, stype >> 4); + sta->addr, type >> 2, stype >> 4); } else if (!pwrmgt && (sta->flags & WLAN_STA_PS)) { sta->flags &= ~WLAN_STA_PS; - PDEBUG(DEBUG_PS2, "STA %s changed to not use " + PDEBUG(DEBUG_PS2, "STA %pM changed to not use " "PS mode (type=0x%02X, stype=0x%02X)\n", - print_mac(mac, sta->addr), type >> 2, stype >> 4); + sta->addr, type >> 2, stype >> 4); if (type != IEEE80211_FTYPE_CTL || stype != IEEE80211_STYPE_PSPOLL) schedule_packet_send(local, sta); @@ -3029,13 +2963,9 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT } else { printk(KERN_DEBUG "%s: dropped received packet" - " from non-associated STA " - MAC_FMT + " from non-associated STA %pM" " (type=0x%02x, subtype=0x%02x)\n", - dev->name, - hdr->addr2[0], hdr->addr2[1], - hdr->addr2[2], hdr->addr2[3], - hdr->addr2[4], hdr->addr2[5], + dev->name, hdr->addr2, type >> 2, stype >> 4); hostap_rx(dev, skb, rx_stats); #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ @@ -3068,13 +2998,9 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, * after being unavailable for some time. Speed up * re-association by informing the station about it not * being associated. */ - printk(KERN_DEBUG "%s: rejected received nullfunc " - "frame without ToDS from not associated STA " - MAC_FMT "\n", - dev->name, - hdr->addr2[0], hdr->addr2[1], - hdr->addr2[2], hdr->addr2[3], - hdr->addr2[4], hdr->addr2[5]); + printk(KERN_DEBUG "%s: rejected received nullfunc frame" + " without ToDS from not associated STA %pM\n", + dev->name, hdr->addr2); hostap_rx(dev, skb, rx_stats); #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ } @@ -3090,13 +3016,10 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, * broadcast frame from an IBSS network. Drop it silently. * If BSSID is own, report the dropping of this frame. */ if (memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) { - printk(KERN_DEBUG "%s: dropped received packet from " - MAC_FMT " with no ToDS flag " + printk(KERN_DEBUG "%s: dropped received packet from %pM" + " with no ToDS flag " "(type=0x%02x, subtype=0x%02x)\n", dev->name, - hdr->addr2[0], hdr->addr2[1], - hdr->addr2[2], hdr->addr2[3], - hdr->addr2[4], hdr->addr2[5], - type >> 2, stype >> 4); + hdr->addr2, type >> 2, stype >> 4); hostap_dump_rx_80211(dev->name, skb, rx_stats); } ret = AP_RX_DROP; @@ -3142,7 +3065,7 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, /* Called only as a tasklet (software IRQ) */ int hostap_handle_sta_crypto(local_info_t *local, struct ieee80211_hdr_4addr *hdr, - struct ieee80211_crypt_data **crypt, + struct lib80211_crypt_data **crypt, void **sta_ptr) { struct sta_info *sta; @@ -3290,7 +3213,7 @@ void hostap_update_rates(local_info_t *local) void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent, - struct ieee80211_crypt_data ***crypt) + struct lib80211_crypt_data ***crypt) { struct sta_info *sta; diff --git a/drivers/net/wireless/hostap/hostap_ap.h b/drivers/net/wireless/hostap/hostap_ap.h index 2fa2452b6b07de6d6c06f76b2e4b0742c90e7dc2..d36e4b17533615462c9694332764abdc15eba7d3 100644 --- a/drivers/net/wireless/hostap/hostap_ap.h +++ b/drivers/net/wireless/hostap/hostap_ap.h @@ -74,7 +74,7 @@ struct sta_info { u32 tx_since_last_failure; u32 tx_consecutive_exc; - struct ieee80211_crypt_data *crypt; + struct lib80211_crypt_data *crypt; int ap; /* whether this station is an AP */ @@ -209,7 +209,7 @@ struct ap_data { /* WEP operations for generating challenges to be used with shared key * authentication */ - struct ieee80211_crypto_ops *crypt; + struct lib80211_crypto_ops *crypt; void *crypt_priv; #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ }; @@ -229,7 +229,7 @@ typedef enum { struct hostap_tx_data { struct sk_buff *skb; int host_encrypt; - struct ieee80211_crypt_data *crypt; + struct lib80211_crypt_data *crypt; void *sta_ptr; }; ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx); @@ -244,7 +244,7 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, struct hostap_80211_rx_status *rx_stats, int wds); int hostap_handle_sta_crypto(local_info_t *local, struct ieee80211_hdr_4addr *hdr, - struct ieee80211_crypt_data **crypt, + struct lib80211_crypt_data **crypt, void **sta_ptr); int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr); int hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr); diff --git a/drivers/net/wireless/hostap/hostap_common.h b/drivers/net/wireless/hostap/hostap_common.h index b470c743c2d1923d5214fe0507ebb6d3fbf3aba2..90b64b09200716c31cb9af9a4e2761ba0ba7100d 100644 --- a/drivers/net/wireless/hostap/hostap_common.h +++ b/drivers/net/wireless/hostap/hostap_common.h @@ -6,19 +6,6 @@ /* IEEE 802.11 defines */ -/* Information Element IDs */ -#define WLAN_EID_SSID 0 -#define WLAN_EID_SUPP_RATES 1 -#define WLAN_EID_FH_PARAMS 2 -#define WLAN_EID_DS_PARAMS 3 -#define WLAN_EID_CF_PARAMS 4 -#define WLAN_EID_TIM 5 -#define WLAN_EID_IBSS_PARAMS 6 -#define WLAN_EID_CHALLENGE 16 -#define WLAN_EID_RSN 48 -#define WLAN_EID_GENERIC 221 - - /* HFA384X Configuration RIDs */ #define HFA384X_RID_CNFPORTTYPE 0xFC00 #define HFA384X_RID_CNFOWNMACADDR 0xFC01 diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index 3153fe9d7ce09dc32bf8764bc6437569c270ba14..0f27059bbe85a88d20aacc0ec127e63a12fe475f 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c @@ -47,7 +47,7 @@ #include #include #include -#include +#include #include #include "hostap_80211.h" @@ -2335,10 +2335,6 @@ static void prism2_txexc(local_info_t *local) int show_dump, res; char *payload = NULL; struct hfa384x_tx_frame txdesc; - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); - DECLARE_MAC_BUF(mac3); - DECLARE_MAC_BUF(mac4); show_dump = local->frame_dump & PRISM2_DUMP_TXEXC_HDR; local->stats.tx_errors++; @@ -2404,9 +2400,9 @@ static void prism2_txexc(local_info_t *local) WLAN_FC_GET_STYPE(fc) >> 4, fc & IEEE80211_FCTL_TODS ? " ToDS" : "", fc & IEEE80211_FCTL_FROMDS ? " FromDS" : ""); - PDEBUG(DEBUG_EXTRA, " A1=%s A2=%s A3=%s A4=%s\n", - print_mac(mac, txdesc.addr1), print_mac(mac2, txdesc.addr2), - print_mac(mac3, txdesc.addr3), print_mac(mac4, txdesc.addr4)); + PDEBUG(DEBUG_EXTRA, " A1=%pM A2=%pM A3=%pM A4=%pM\n", + txdesc.addr1, txdesc.addr2, + txdesc.addr3, txdesc.addr4); } @@ -2792,45 +2788,6 @@ static void prism2_check_sta_fw_version(local_info_t *local) } -static void prism2_crypt_deinit_entries(local_info_t *local, int force) -{ - struct list_head *ptr, *n; - struct ieee80211_crypt_data *entry; - - for (ptr = local->crypt_deinit_list.next, n = ptr->next; - ptr != &local->crypt_deinit_list; ptr = n, n = ptr->next) { - entry = list_entry(ptr, struct ieee80211_crypt_data, list); - - if (atomic_read(&entry->refcnt) != 0 && !force) - continue; - - list_del(ptr); - - if (entry->ops) - entry->ops->deinit(entry->priv); - kfree(entry); - } -} - - -static void prism2_crypt_deinit_handler(unsigned long data) -{ - local_info_t *local = (local_info_t *) data; - unsigned long flags; - - spin_lock_irqsave(&local->lock, flags); - prism2_crypt_deinit_entries(local, 0); - if (!list_empty(&local->crypt_deinit_list)) { - printk(KERN_DEBUG "%s: entries remaining in delayed crypt " - "deletion list\n", local->dev->name); - local->crypt_deinit_timer.expires = jiffies + HZ; - add_timer(&local->crypt_deinit_timer); - } - spin_unlock_irqrestore(&local->lock, flags); - -} - - static void hostap_passive_scan(unsigned long data) { local_info_t *local = (local_info_t *) data; @@ -3254,10 +3211,8 @@ while (0) INIT_LIST_HEAD(&local->cmd_queue); init_waitqueue_head(&local->hostscan_wq); - INIT_LIST_HEAD(&local->crypt_deinit_list); - init_timer(&local->crypt_deinit_timer); - local->crypt_deinit_timer.data = (unsigned long) local; - local->crypt_deinit_timer.function = prism2_crypt_deinit_handler; + + lib80211_crypt_info_init(&local->crypt_info, dev->name, &local->lock); init_timer(&local->passive_scan_timer); local->passive_scan_timer.data = (unsigned long) local; @@ -3358,9 +3313,7 @@ static void prism2_free_local_data(struct net_device *dev) flush_scheduled_work(); - if (timer_pending(&local->crypt_deinit_timer)) - del_timer(&local->crypt_deinit_timer); - prism2_crypt_deinit_entries(local, 1); + lib80211_crypt_info_free(&local->crypt_info); if (timer_pending(&local->passive_scan_timer)) del_timer(&local->passive_scan_timer); @@ -3377,16 +3330,6 @@ static void prism2_free_local_data(struct net_device *dev) if (local->dev_enabled) prism2_callback(local, PRISM2_CALLBACK_DISABLE); - for (i = 0; i < WEP_KEYS; i++) { - struct ieee80211_crypt_data *crypt = local->crypt[i]; - if (crypt) { - if (crypt->ops) - crypt->ops->deinit(crypt->priv); - kfree(crypt); - local->crypt[i] = NULL; - } - } - if (local->ap != NULL) hostap_free_data(local->ap); diff --git a/drivers/net/wireless/hostap/hostap_info.c b/drivers/net/wireless/hostap/hostap_info.c index 7cd3fb79230e51d12f5b226049e64a474d562eb3..99b4cf41edf2c59d5d5d2ea2baa5273a21d28d43 100644 --- a/drivers/net/wireless/hostap/hostap_info.c +++ b/drivers/net/wireless/hostap/hostap_info.c @@ -166,7 +166,6 @@ static void prism2_host_roaming(local_info_t *local) struct hfa384x_hostscan_result *selected, *entry; int i; unsigned long flags; - DECLARE_MAC_BUF(mac); if (local->last_join_time && time_before(jiffies, local->last_join_time + 10 * HZ)) { @@ -199,9 +198,8 @@ static void prism2_host_roaming(local_info_t *local) local->preferred_ap[2] || local->preferred_ap[3] || local->preferred_ap[4] || local->preferred_ap[5]) { /* Try to find preferred AP */ - PDEBUG(DEBUG_EXTRA, "%s: Preferred AP BSSID " - "%s\n", - dev->name, print_mac(mac, local->preferred_ap)); + PDEBUG(DEBUG_EXTRA, "%s: Preferred AP BSSID %pM\n", + dev->name, local->preferred_ap); for (i = 0; i < local->last_scan_results_count; i++) { entry = &local->last_scan_results[i]; if (memcmp(local->preferred_ap, entry->bssid, 6) == 0) @@ -218,9 +216,9 @@ static void prism2_host_roaming(local_info_t *local) req.channel = selected->chid; spin_unlock_irqrestore(&local->lock, flags); - PDEBUG(DEBUG_EXTRA, "%s: JoinRequest: BSSID=%s" + PDEBUG(DEBUG_EXTRA, "%s: JoinRequest: BSSID=%pM" " channel=%d\n", - dev->name, print_mac(mac, req.bssid), le16_to_cpu(req.channel)); + dev->name, req.bssid, le16_to_cpu(req.channel)); if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req, sizeof(req))) { printk(KERN_DEBUG "%s: JoinRequest failed\n", dev->name); @@ -413,7 +411,6 @@ static void handle_info_queue_linkstatus(local_info_t *local) int val = local->prev_link_status; int connected; union iwreq_data wrqu; - DECLARE_MAC_BUF(mac); connected = val == HFA384X_LINKSTATUS_CONNECTED || @@ -425,10 +422,9 @@ static void handle_info_queue_linkstatus(local_info_t *local) printk(KERN_DEBUG "%s: could not read CURRENTBSSID after " "LinkStatus event\n", local->dev->name); } else { - PDEBUG(DEBUG_EXTRA, "%s: LinkStatus: BSSID=" - "%s\n", + PDEBUG(DEBUG_EXTRA, "%s: LinkStatus: BSSID=%pM\n", local->dev->name, - print_mac(mac, (unsigned char *) local->bssid)); + (unsigned char *) local->bssid); if (local->wds_type & HOSTAP_WDS_AP_CLIENT) hostap_add_sta(local->ap, local->bssid); } diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c index 3f8b1d7036e51467879b1dcaf44a895223325c11..c40fdf4c79de8af8193c78d7c8340641b1ddf724 100644 --- a/drivers/net/wireless/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/hostap/hostap_ioctl.c @@ -2,7 +2,7 @@ #include #include -#include +#include #include "hostap_wlan.h" #include "hostap.h" @@ -116,32 +116,6 @@ static int prism2_get_name(struct net_device *dev, } -static void prism2_crypt_delayed_deinit(local_info_t *local, - struct ieee80211_crypt_data **crypt) -{ - struct ieee80211_crypt_data *tmp; - unsigned long flags; - - tmp = *crypt; - *crypt = NULL; - - if (tmp == NULL) - return; - - /* must not run ops->deinit() while there may be pending encrypt or - * decrypt operations. Use a list of delayed deinits to avoid needing - * locking. */ - - spin_lock_irqsave(&local->lock, flags); - list_add(&tmp->list, &local->crypt_deinit_list); - if (!timer_pending(&local->crypt_deinit_timer)) { - local->crypt_deinit_timer.expires = jiffies + HZ; - add_timer(&local->crypt_deinit_timer); - } - spin_unlock_irqrestore(&local->lock, flags); -} - - static int prism2_ioctl_siwencode(struct net_device *dev, struct iw_request_info *info, struct iw_point *erq, char *keybuf) @@ -149,47 +123,47 @@ static int prism2_ioctl_siwencode(struct net_device *dev, struct hostap_interface *iface; local_info_t *local; int i; - struct ieee80211_crypt_data **crypt; + struct lib80211_crypt_data **crypt; iface = netdev_priv(dev); local = iface->local; i = erq->flags & IW_ENCODE_INDEX; if (i < 1 || i > 4) - i = local->tx_keyidx; + i = local->crypt_info.tx_keyidx; else i--; if (i < 0 || i >= WEP_KEYS) return -EINVAL; - crypt = &local->crypt[i]; + crypt = &local->crypt_info.crypt[i]; if (erq->flags & IW_ENCODE_DISABLED) { if (*crypt) - prism2_crypt_delayed_deinit(local, crypt); + lib80211_crypt_delayed_deinit(&local->crypt_info, crypt); goto done; } if (*crypt != NULL && (*crypt)->ops != NULL && strcmp((*crypt)->ops->name, "WEP") != 0) { /* changing to use WEP; deinit previously used algorithm */ - prism2_crypt_delayed_deinit(local, crypt); + lib80211_crypt_delayed_deinit(&local->crypt_info, crypt); } if (*crypt == NULL) { - struct ieee80211_crypt_data *new_crypt; + struct lib80211_crypt_data *new_crypt; /* take WEP into use */ - new_crypt = kzalloc(sizeof(struct ieee80211_crypt_data), + new_crypt = kzalloc(sizeof(struct lib80211_crypt_data), GFP_KERNEL); if (new_crypt == NULL) return -ENOMEM; - new_crypt->ops = ieee80211_get_crypto_ops("WEP"); + new_crypt->ops = lib80211_get_crypto_ops("WEP"); if (!new_crypt->ops) { - request_module("ieee80211_crypt_wep"); - new_crypt->ops = ieee80211_get_crypto_ops("WEP"); + request_module("lib80211_crypt_wep"); + new_crypt->ops = lib80211_get_crypto_ops("WEP"); } - if (new_crypt->ops) + if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) new_crypt->priv = new_crypt->ops->init(i); if (!new_crypt->ops || !new_crypt->priv) { kfree(new_crypt); @@ -210,16 +184,16 @@ static int prism2_ioctl_siwencode(struct net_device *dev, memset(keybuf + erq->length, 0, len - erq->length); (*crypt)->ops->set_key(keybuf, len, NULL, (*crypt)->priv); for (j = 0; j < WEP_KEYS; j++) { - if (j != i && local->crypt[j]) { + if (j != i && local->crypt_info.crypt[j]) { first = 0; break; } } if (first) - local->tx_keyidx = i; + local->crypt_info.tx_keyidx = i; } else { /* No key data - just set the default TX key index */ - local->tx_keyidx = i; + local->crypt_info.tx_keyidx = i; } done: @@ -252,20 +226,20 @@ static int prism2_ioctl_giwencode(struct net_device *dev, local_info_t *local; int i, len; u16 val; - struct ieee80211_crypt_data *crypt; + struct lib80211_crypt_data *crypt; iface = netdev_priv(dev); local = iface->local; i = erq->flags & IW_ENCODE_INDEX; if (i < 1 || i > 4) - i = local->tx_keyidx; + i = local->crypt_info.tx_keyidx; else i--; if (i < 0 || i >= WEP_KEYS) return -EINVAL; - crypt = local->crypt[i]; + crypt = local->crypt_info.crypt[i]; erq->flags = i + 1; if (crypt == NULL || crypt->ops == NULL) { @@ -664,7 +638,6 @@ static int hostap_join_ap(struct net_device *dev) unsigned long flags; int i; struct hfa384x_hostscan_result *entry; - DECLARE_MAC_BUF(mac); iface = netdev_priv(dev); local = iface->local; @@ -686,14 +659,13 @@ static int hostap_join_ap(struct net_device *dev) if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req, sizeof(req))) { - printk(KERN_DEBUG "%s: JoinRequest %s" - " failed\n", - dev->name, print_mac(mac, local->preferred_ap)); + printk(KERN_DEBUG "%s: JoinRequest %pM failed\n", + dev->name, local->preferred_ap); return -1; } - printk(KERN_DEBUG "%s: Trying to join BSSID %s\n", - dev->name, print_mac(mac, local->preferred_ap)); + printk(KERN_DEBUG "%s: Trying to join BSSID %pM\n", + dev->name, local->preferred_ap); return 0; } @@ -3229,8 +3201,8 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev, local_info_t *local = iface->local; struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; int i, ret = 0; - struct ieee80211_crypto_ops *ops; - struct ieee80211_crypt_data **crypt; + struct lib80211_crypto_ops *ops; + struct lib80211_crypt_data **crypt; void *sta_ptr; u8 *addr; const char *alg, *module; @@ -3239,7 +3211,7 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev, if (i > WEP_KEYS) return -EINVAL; if (i < 1 || i > WEP_KEYS) - i = local->tx_keyidx; + i = local->crypt_info.tx_keyidx; else i--; if (i < 0 || i >= WEP_KEYS) @@ -3249,7 +3221,7 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev, if (addr[0] == 0xff && addr[1] == 0xff && addr[2] == 0xff && addr[3] == 0xff && addr[4] == 0xff && addr[5] == 0xff) { sta_ptr = NULL; - crypt = &local->crypt[i]; + crypt = &local->crypt_info.crypt[i]; } else { if (i != 0) return -EINVAL; @@ -3262,7 +3234,7 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev, * is emulated by using default key idx 0. */ i = 0; - crypt = &local->crypt[i]; + crypt = &local->crypt_info.crypt[i]; } else return -EINVAL; } @@ -3271,22 +3243,22 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev, if ((erq->flags & IW_ENCODE_DISABLED) || ext->alg == IW_ENCODE_ALG_NONE) { if (*crypt) - prism2_crypt_delayed_deinit(local, crypt); + lib80211_crypt_delayed_deinit(&local->crypt_info, crypt); goto done; } switch (ext->alg) { case IW_ENCODE_ALG_WEP: alg = "WEP"; - module = "ieee80211_crypt_wep"; + module = "lib80211_crypt_wep"; break; case IW_ENCODE_ALG_TKIP: alg = "TKIP"; - module = "ieee80211_crypt_tkip"; + module = "lib80211_crypt_tkip"; break; case IW_ENCODE_ALG_CCMP: alg = "CCMP"; - module = "ieee80211_crypt_ccmp"; + module = "lib80211_crypt_ccmp"; break; default: printk(KERN_DEBUG "%s: unsupported algorithm %d\n", @@ -3295,10 +3267,10 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev, goto done; } - ops = ieee80211_get_crypto_ops(alg); + ops = lib80211_get_crypto_ops(alg); if (ops == NULL) { request_module(module); - ops = ieee80211_get_crypto_ops(alg); + ops = lib80211_get_crypto_ops(alg); } if (ops == NULL) { printk(KERN_DEBUG "%s: unknown crypto alg '%s'\n", @@ -3317,18 +3289,19 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev, } if (*crypt == NULL || (*crypt)->ops != ops) { - struct ieee80211_crypt_data *new_crypt; + struct lib80211_crypt_data *new_crypt; - prism2_crypt_delayed_deinit(local, crypt); + lib80211_crypt_delayed_deinit(&local->crypt_info, crypt); - new_crypt = kzalloc(sizeof(struct ieee80211_crypt_data), + new_crypt = kzalloc(sizeof(struct lib80211_crypt_data), GFP_KERNEL); if (new_crypt == NULL) { ret = -ENOMEM; goto done; } new_crypt->ops = ops; - new_crypt->priv = new_crypt->ops->init(i); + if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) + new_crypt->priv = new_crypt->ops->init(i); if (new_crypt->priv == NULL) { kfree(new_crypt); ret = -EINVAL; @@ -3356,20 +3329,20 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev, if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { if (!sta_ptr) - local->tx_keyidx = i; + local->crypt_info.tx_keyidx = i; } if (sta_ptr == NULL && ext->key_len > 0) { int first = 1, j; for (j = 0; j < WEP_KEYS; j++) { - if (j != i && local->crypt[j]) { + if (j != i && local->crypt_info.crypt[j]) { first = 0; break; } } if (first) - local->tx_keyidx = i; + local->crypt_info.tx_keyidx = i; } done: @@ -3401,7 +3374,7 @@ static int prism2_ioctl_giwencodeext(struct net_device *dev, { struct hostap_interface *iface = netdev_priv(dev); local_info_t *local = iface->local; - struct ieee80211_crypt_data **crypt; + struct lib80211_crypt_data **crypt; void *sta_ptr; int max_key_len, i; struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; @@ -3413,7 +3386,7 @@ static int prism2_ioctl_giwencodeext(struct net_device *dev, i = erq->flags & IW_ENCODE_INDEX; if (i < 1 || i > WEP_KEYS) - i = local->tx_keyidx; + i = local->crypt_info.tx_keyidx; else i--; @@ -3421,7 +3394,7 @@ static int prism2_ioctl_giwencodeext(struct net_device *dev, if (addr[0] == 0xff && addr[1] == 0xff && addr[2] == 0xff && addr[3] == 0xff && addr[4] == 0xff && addr[5] == 0xff) { sta_ptr = NULL; - crypt = &local->crypt[i]; + crypt = &local->crypt_info.crypt[i]; } else { i = 0; sta_ptr = ap_crypt_get_ptrs(local->ap, addr, 0, &crypt); @@ -3470,8 +3443,8 @@ static int prism2_ioctl_set_encryption(local_info_t *local, int param_len) { int ret = 0; - struct ieee80211_crypto_ops *ops; - struct ieee80211_crypt_data **crypt; + struct lib80211_crypto_ops *ops; + struct lib80211_crypt_data **crypt; void *sta_ptr; param->u.crypt.err = 0; @@ -3488,7 +3461,7 @@ static int prism2_ioctl_set_encryption(local_info_t *local, if (param->u.crypt.idx >= WEP_KEYS) return -EINVAL; sta_ptr = NULL; - crypt = &local->crypt[param->u.crypt.idx]; + crypt = &local->crypt_info.crypt[param->u.crypt.idx]; } else { if (param->u.crypt.idx) return -EINVAL; @@ -3505,20 +3478,20 @@ static int prism2_ioctl_set_encryption(local_info_t *local, if (strcmp(param->u.crypt.alg, "none") == 0) { if (crypt) - prism2_crypt_delayed_deinit(local, crypt); + lib80211_crypt_delayed_deinit(&local->crypt_info, crypt); goto done; } - ops = ieee80211_get_crypto_ops(param->u.crypt.alg); + ops = lib80211_get_crypto_ops(param->u.crypt.alg); if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) { - request_module("ieee80211_crypt_wep"); - ops = ieee80211_get_crypto_ops(param->u.crypt.alg); + request_module("lib80211_crypt_wep"); + ops = lib80211_get_crypto_ops(param->u.crypt.alg); } else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0) { - request_module("ieee80211_crypt_tkip"); - ops = ieee80211_get_crypto_ops(param->u.crypt.alg); + request_module("lib80211_crypt_tkip"); + ops = lib80211_get_crypto_ops(param->u.crypt.alg); } else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0) { - request_module("ieee80211_crypt_ccmp"); - ops = ieee80211_get_crypto_ops(param->u.crypt.alg); + request_module("lib80211_crypt_ccmp"); + ops = lib80211_get_crypto_ops(param->u.crypt.alg); } if (ops == NULL) { printk(KERN_DEBUG "%s: unknown crypto alg '%s'\n", @@ -3533,11 +3506,11 @@ static int prism2_ioctl_set_encryption(local_info_t *local, local->host_decrypt = local->host_encrypt = 1; if (*crypt == NULL || (*crypt)->ops != ops) { - struct ieee80211_crypt_data *new_crypt; + struct lib80211_crypt_data *new_crypt; - prism2_crypt_delayed_deinit(local, crypt); + lib80211_crypt_delayed_deinit(&local->crypt_info, crypt); - new_crypt = kzalloc(sizeof(struct ieee80211_crypt_data), + new_crypt = kzalloc(sizeof(struct lib80211_crypt_data), GFP_KERNEL); if (new_crypt == NULL) { ret = -ENOMEM; @@ -3570,7 +3543,7 @@ static int prism2_ioctl_set_encryption(local_info_t *local, if (param->u.crypt.flags & HOSTAP_CRYPT_FLAG_SET_TX_KEY) { if (!sta_ptr) - local->tx_keyidx = param->u.crypt.idx; + local->crypt_info.tx_keyidx = param->u.crypt.idx; else if (param->u.crypt.idx) { printk(KERN_DEBUG "%s: TX key idx setting failed\n", local->dev->name); @@ -3606,7 +3579,7 @@ static int prism2_ioctl_get_encryption(local_info_t *local, struct prism2_hostapd_param *param, int param_len) { - struct ieee80211_crypt_data **crypt; + struct lib80211_crypt_data **crypt; void *sta_ptr; int max_key_len; @@ -3622,8 +3595,8 @@ static int prism2_ioctl_get_encryption(local_info_t *local, param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { sta_ptr = NULL; if (param->u.crypt.idx >= WEP_KEYS) - param->u.crypt.idx = local->tx_keyidx; - crypt = &local->crypt[param->u.crypt.idx]; + param->u.crypt.idx = local->crypt_info.tx_keyidx; + crypt = &local->crypt_info.crypt[param->u.crypt.idx]; } else { param->u.crypt.idx = 0; sta_ptr = ap_crypt_get_ptrs(local->ap, param->sta_addr, 0, @@ -3701,10 +3674,8 @@ static int prism2_ioctl_set_assoc_ap_addr(local_info_t *local, struct prism2_hostapd_param *param, int param_len) { - DECLARE_MAC_BUF(mac); - printk(KERN_DEBUG "%ssta: associated as client with AP " - "%s\n", - local->dev->name, print_mac(mac, param->sta_addr)); + printk(KERN_DEBUG "%ssta: associated as client with AP %pM\n", + local->dev->name, param->sta_addr); memcpy(local->assoc_ap_addr, param->sta_addr, ETH_ALEN); return 0; } diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index 756ab56c1f4034de12c77b2ba067987aebbcd555..02a312ca860752ad7c4324570499ee139a771d66 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include "hostap_wlan.h" @@ -343,10 +343,11 @@ int hostap_set_encryption(local_info_t *local) char keybuf[WEP_KEY_LEN + 1]; enum { NONE, WEP, OTHER } encrypt_type; - idx = local->tx_keyidx; - if (local->crypt[idx] == NULL || local->crypt[idx]->ops == NULL) + idx = local->crypt_info.tx_keyidx; + if (local->crypt_info.crypt[idx] == NULL || + local->crypt_info.crypt[idx]->ops == NULL) encrypt_type = NONE; - else if (strcmp(local->crypt[idx]->ops->name, "WEP") == 0) + else if (strcmp(local->crypt_info.crypt[idx]->ops->name, "WEP") == 0) encrypt_type = WEP; else encrypt_type = OTHER; @@ -394,17 +395,17 @@ int hostap_set_encryption(local_info_t *local) /* 104-bit support seems to require that all the keys are set to the * same keylen */ keylen = 6; /* first 5 octets */ - len = local->crypt[idx]->ops->get_key(keybuf, sizeof(keybuf), - NULL, local->crypt[idx]->priv); + len = local->crypt_info.crypt[idx]->ops->get_key(keybuf, sizeof(keybuf), NULL, + local->crypt_info.crypt[idx]->priv); if (idx >= 0 && idx < WEP_KEYS && len > 5) keylen = WEP_KEY_LEN + 1; /* first 13 octets */ for (i = 0; i < WEP_KEYS; i++) { memset(keybuf, 0, sizeof(keybuf)); - if (local->crypt[i]) { - (void) local->crypt[i]->ops->get_key( + if (local->crypt_info.crypt[i]) { + (void) local->crypt_info.crypt[i]->ops->get_key( keybuf, sizeof(keybuf), - NULL, local->crypt[i]->priv); + NULL, local->crypt_info.crypt[i]->priv); } if (local->func->set_rid(local->dev, HFA384X_RID_CNFDEFAULTKEY0 + i, @@ -530,10 +531,6 @@ int hostap_set_auth_algs(local_info_t *local) void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx) { u16 status, fc; - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); - DECLARE_MAC_BUF(mac3); - DECLARE_MAC_BUF(mac4); status = __le16_to_cpu(rx->status); @@ -552,12 +549,11 @@ void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx) fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : ""); - printk(KERN_DEBUG " A1=%s A2=%s A3=%s A4=%s\n", - print_mac(mac, rx->addr1), print_mac(mac2, rx->addr2), - print_mac(mac3, rx->addr3), print_mac(mac4, rx->addr4)); + printk(KERN_DEBUG " A1=%pM A2=%pM A3=%pM A4=%pM\n", + rx->addr1, rx->addr2, rx->addr3, rx->addr4); - printk(KERN_DEBUG " dst=%s src=%s len=%d\n", - print_mac(mac, rx->dst_addr), print_mac(mac2, rx->src_addr), + printk(KERN_DEBUG " dst=%pM src=%pM len=%d\n", + rx->dst_addr, rx->src_addr, __be16_to_cpu(rx->len)); } @@ -565,10 +561,6 @@ void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx) void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx) { u16 fc; - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); - DECLARE_MAC_BUF(mac3); - DECLARE_MAC_BUF(mac4); printk(KERN_DEBUG "%s: TX status=0x%04x retry_count=%d tx_rate=%d " "tx_control=0x%04x; jiffies=%ld\n", @@ -584,12 +576,11 @@ void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx) fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : ""); - printk(KERN_DEBUG " A1=%s A2=%s A3=%s A4=%s\n", - print_mac(mac, tx->addr1), print_mac(mac2, tx->addr2), - print_mac(mac3, tx->addr3), print_mac(mac4, tx->addr4)); + printk(KERN_DEBUG " A1=%pM A2=%pM A3=%pM A4=%pM\n", + tx->addr1, tx->addr2, tx->addr3, tx->addr4); - printk(KERN_DEBUG " dst=%s src=%s len=%d\n", - print_mac(mac, tx->dst_addr), print_mac(mac2, tx->src_addr), + printk(KERN_DEBUG " dst=%pM src=%pM len=%d\n", + tx->dst_addr, tx->src_addr, __be16_to_cpu(tx->len)); } diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c index 3a874fc621d386a3c7ccfb160c54d443ec2c664d..8fdd41f4b4f2121a65f70d322bfe3951d1e233e0 100644 --- a/drivers/net/wireless/hostap/hostap_pci.c +++ b/drivers/net/wireless/hostap/hostap_pci.c @@ -312,7 +312,7 @@ static int prism2_pci_probe(struct pci_dev *pdev, goto err_out_disable; } - mem = ioremap(phymem, pci_resource_len(pdev, 0)); + mem = pci_ioremap_bar(pdev, 0); if (mem == NULL) { printk(KERN_ERR "prism2: Cannot remap PCI memory region\n") ; goto fail; diff --git a/drivers/net/wireless/hostap/hostap_proc.c b/drivers/net/wireless/hostap/hostap_proc.c index b03536008ad98df43218fe8a9aef9e7b05fb0fe2..005ff25a405f2bfde34adf66d4e9e85f85c44f2a 100644 --- a/drivers/net/wireless/hostap/hostap_proc.c +++ b/drivers/net/wireless/hostap/hostap_proc.c @@ -2,7 +2,7 @@ #include #include -#include +#include #include "hostap_wlan.h" #include "hostap.h" @@ -36,9 +36,10 @@ static int prism2_debug_proc_read(char *page, char **start, off_t off, p += sprintf(p, "dev_enabled=%d\n", local->dev_enabled); p += sprintf(p, "sw_tick_stuck=%d\n", local->sw_tick_stuck); for (i = 0; i < WEP_KEYS; i++) { - if (local->crypt[i] && local->crypt[i]->ops) { - p += sprintf(p, "crypt[%d]=%s\n", - i, local->crypt[i]->ops->name); + if (local->crypt_info.crypt[i] && + local->crypt_info.crypt[i]->ops) { + p += sprintf(p, "crypt[%d]=%s\n", i, + local->crypt_info.crypt[i]->ops->name); } } p += sprintf(p, "pri_only=%d\n", local->pri_only); @@ -106,7 +107,6 @@ static int prism2_wds_proc_read(char *page, char **start, off_t off, local_info_t *local = (local_info_t *) data; struct list_head *ptr; struct hostap_interface *iface; - DECLARE_MAC_BUF(mac); if (off > PROC_LIMIT) { *eof = 1; @@ -118,9 +118,9 @@ static int prism2_wds_proc_read(char *page, char **start, off_t off, iface = list_entry(ptr, struct hostap_interface, list); if (iface->type != HOSTAP_INTERFACE_WDS) continue; - p += sprintf(p, "%s\t%s\n", + p += sprintf(p, "%s\t%pM\n", iface->dev->name, - print_mac(mac, iface->u.wds.remote_addr)); + iface->u.wds.remote_addr); if ((p - page) > PROC_LIMIT) { printk(KERN_DEBUG "%s: wds proc did not fit\n", local->dev->name); @@ -148,7 +148,6 @@ static int prism2_bss_list_proc_read(char *page, char **start, off_t off, struct list_head *ptr; struct hostap_bss_info *bss; int i; - DECLARE_MAC_BUF(mac); if (off > PROC_LIMIT) { *eof = 1; @@ -160,8 +159,8 @@ static int prism2_bss_list_proc_read(char *page, char **start, off_t off, spin_lock_bh(&local->lock); list_for_each(ptr, &local->bss_list) { bss = list_entry(ptr, struct hostap_bss_info, list); - p += sprintf(p, "%s\t%lu\t%u\t0x%x\t", - print_mac(mac, bss->bssid), bss->last_update, + p += sprintf(p, "%pM\t%lu\t%u\t0x%x\t", + bss->bssid, bss->last_update, bss->count, bss->capab_info); for (i = 0; i < bss->ssid_len; i++) { p += sprintf(p, "%c", @@ -208,12 +207,13 @@ static int prism2_crypt_proc_read(char *page, char **start, off_t off, return 0; } - p += sprintf(p, "tx_keyidx=%d\n", local->tx_keyidx); + p += sprintf(p, "tx_keyidx=%d\n", local->crypt_info.tx_keyidx); for (i = 0; i < WEP_KEYS; i++) { - if (local->crypt[i] && local->crypt[i]->ops && - local->crypt[i]->ops->print_stats) { - p = local->crypt[i]->ops->print_stats( - p, local->crypt[i]->priv); + if (local->crypt_info.crypt[i] && + local->crypt_info.crypt[i]->ops && + local->crypt_info.crypt[i]->ops->print_stats) { + p = local->crypt_info.crypt[i]->ops->print_stats( + p, local->crypt_info.crypt[i]->priv); } } @@ -314,7 +314,6 @@ static int prism2_scan_results_proc_read(char *page, char **start, off_t off, int entry, i, len, total = 0; struct hfa384x_hostscan_result *scanres; u8 *pos; - DECLARE_MAC_BUF(mac); p += sprintf(p, "CHID ANL SL BcnInt Capab Rate BSSID ATIM SupRates " "SSID\n"); @@ -332,14 +331,14 @@ static int prism2_scan_results_proc_read(char *page, char **start, off_t off, if ((p - page) > (PAGE_SIZE - 200)) break; - p += sprintf(p, "%d %d %d %d 0x%02x %d %s %d ", + p += sprintf(p, "%d %d %d %d 0x%02x %d %pM %d ", le16_to_cpu(scanres->chid), (s16) le16_to_cpu(scanres->anl), (s16) le16_to_cpu(scanres->sl), le16_to_cpu(scanres->beacon_interval), le16_to_cpu(scanres->capability), le16_to_cpu(scanres->rate), - print_mac(mac, scanres->bssid), + scanres->bssid, le16_to_cpu(scanres->atim)); pos = scanres->sup_rates; diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h index a68f97c3935947a59990d188f7d95d05b19c600c..4d8d51a353cd3cf02395e7ab6c1eaf4333314303 100644 --- a/drivers/net/wireless/hostap/hostap_wlan.h +++ b/drivers/net/wireless/hostap/hostap_wlan.h @@ -6,6 +6,7 @@ #include #include #include +#include #include "hostap_config.h" #include "hostap_common.h" @@ -763,10 +764,7 @@ struct local_info { #define WEP_KEYS 4 #define WEP_KEY_LEN 13 - struct ieee80211_crypt_data *crypt[WEP_KEYS]; - int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */ - struct timer_list crypt_deinit_timer; - struct list_head crypt_deinit_list; + struct lib80211_crypt_info crypt_info; int open_wep; /* allow unencrypted frames */ int host_encrypt; @@ -822,7 +820,7 @@ struct local_info { int last_scan_results_count; enum { PRISM2_SCAN, PRISM2_HOSTSCAN } last_scan_type; struct work_struct info_queue; - long pending_info; /* bit field of pending info_queue items */ + unsigned long pending_info; /* bit field of pending info_queue items */ #define PRISM2_INFO_PENDING_LINKSTATUS 0 #define PRISM2_INFO_PENDING_SCANRESULTS 1 int prev_link_status; /* previous received LinkStatus info */ diff --git a/drivers/net/wireless/ipw2x00/Kconfig b/drivers/net/wireless/ipw2x00/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..3d5cc4463d4d5e641601aa3fbc4eb3438007da0f --- /dev/null +++ b/drivers/net/wireless/ipw2x00/Kconfig @@ -0,0 +1,191 @@ +# +# Intel Centrino wireless drivers +# + +config IPW2100 + tristate "Intel PRO/Wireless 2100 Network Connection" + depends on PCI && WLAN_80211 + select WIRELESS_EXT + select FW_LOADER + select LIB80211 + select LIBIPW + ---help--- + A driver for the Intel PRO/Wireless 2100 Network + Connection 802.11b wireless network adapter. + + See for information on + the capabilities currently enabled in this driver and for tips + for debugging issues and problems. + + In order to use this driver, you will need a firmware image for it. + You can obtain the firmware from + . Once you have the firmware image, you + will need to place it in /lib/firmware. + + You will also very likely need the Wireless Tools in order to + configure your card: + + . + + It is recommended that you compile this driver as a module (M) + rather than built-in (Y). This driver requires firmware at device + initialization time, and when built-in this typically happens + before the filesystem is accessible (hence firmware will be + unavailable and initialization will fail). If you do choose to build + this driver into your kernel image, you can avoid this problem by + including the firmware and a firmware loader in an initramfs. + +config IPW2100_MONITOR + bool "Enable promiscuous mode" + depends on IPW2100 + ---help--- + Enables promiscuous/monitor mode support for the ipw2100 driver. + With this feature compiled into the driver, you can switch to + promiscuous mode via the Wireless Tool's Monitor mode. While in this + mode, no packets can be sent. + +config IPW2100_DEBUG + bool "Enable full debugging output in IPW2100 module." + depends on IPW2100 + ---help--- + This option will enable debug tracing output for the IPW2100. + + This will result in the kernel module being ~60k larger. You can + control which debug output is sent to the kernel log by setting the + value in + + /sys/bus/pci/drivers/ipw2100/debug_level + + This entry will only exist if this option is enabled. + + If you are not trying to debug or develop the IPW2100 driver, you + most likely want to say N here. + +config IPW2200 + tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection" + depends on PCI && WLAN_80211 + select WIRELESS_EXT + select FW_LOADER + select LIB80211 + select LIBIPW + ---help--- + A driver for the Intel PRO/Wireless 2200BG and 2915ABG Network + Connection adapters. + + See for + information on the capabilities currently enabled in this + driver and for tips for debugging issues and problems. + + In order to use this driver, you will need a firmware image for it. + You can obtain the firmware from + . See the above referenced README.ipw2200 + for information on where to install the firmware images. + + You will also very likely need the Wireless Tools in order to + configure your card: + + . + + It is recommended that you compile this driver as a module (M) + rather than built-in (Y). This driver requires firmware at device + initialization time, and when built-in this typically happens + before the filesystem is accessible (hence firmware will be + unavailable and initialization will fail). If you do choose to build + this driver into your kernel image, you can avoid this problem by + including the firmware and a firmware loader in an initramfs. + +config IPW2200_MONITOR + bool "Enable promiscuous mode" + depends on IPW2200 + ---help--- + Enables promiscuous/monitor mode support for the ipw2200 driver. + With this feature compiled into the driver, you can switch to + promiscuous mode via the Wireless Tool's Monitor mode. While in this + mode, no packets can be sent. + +config IPW2200_RADIOTAP + bool "Enable radiotap format 802.11 raw packet support" + depends on IPW2200_MONITOR + +config IPW2200_PROMISCUOUS + bool "Enable creation of a RF radiotap promiscuous interface" + depends on IPW2200_MONITOR + select IPW2200_RADIOTAP + ---help--- + Enables the creation of a second interface prefixed 'rtap'. + This second interface will provide every received in radiotap + format. + + This is useful for performing wireless network analysis while + maintaining an active association. + + Example usage: + + % modprobe ipw2200 rtap_iface=1 + % ifconfig rtap0 up + % tethereal -i rtap0 + + If you do not specify 'rtap_iface=1' as a module parameter then + the rtap interface will not be created and you will need to turn + it on via sysfs: + + % echo 1 > /sys/bus/pci/drivers/ipw2200/*/rtap_iface + +config IPW2200_QOS + bool "Enable QoS support" + depends on IPW2200 && EXPERIMENTAL + +config IPW2200_DEBUG + bool "Enable full debugging output in IPW2200 module." + depends on IPW2200 + ---help--- + This option will enable low level debug tracing output for IPW2200. + + Note, normal debug code is already compiled in. This low level + debug option enables debug on hot paths (e.g Tx, Rx, ISR) and + will result in the kernel module being ~70 larger. Most users + will typically not need this high verbosity debug information. + + If you are not sure, say N here. + +config LIBIPW + tristate + select WIRELESS_EXT + select CRYPTO + select CRYPTO_ARC4 + select CRYPTO_ECB + select CRYPTO_AES + select CRYPTO_MICHAEL_MIC + select CRYPTO_ECB + select CRC32 + select LIB80211 + select LIB80211_CRYPT_WEP + select LIB80211_CRYPT_TKIP + select LIB80211_CRYPT_CCMP + ---help--- + This option enables the hardware independent IEEE 802.11 + networking stack. This component is deprecated in favor of the + mac80211 component. + +config LIBIPW_DEBUG + bool "Full debugging output for the LIBIPW component" + depends on LIBIPW + ---help--- + This option will enable debug tracing output for the + libipw component. + + This will result in the kernel module being ~70k larger. You + can control which debug output is sent to the kernel log by + setting the value in + + /proc/net/ieee80211/debug_level + + For example: + + % echo 0x00000FFO > /proc/net/ieee80211/debug_level + + For a list of values you can assign to debug_level, you + can look at the bit mask values in + + If you are not trying to debug or develop the libipw + component, you most likely want to say N here. diff --git a/drivers/net/wireless/ipw2x00/Makefile b/drivers/net/wireless/ipw2x00/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..aecd2cff462bda30f0419aeff80f8b31c4e5a517 --- /dev/null +++ b/drivers/net/wireless/ipw2x00/Makefile @@ -0,0 +1,14 @@ +# +# Makefile for the Intel Centrino wireless drivers +# + +obj-$(CONFIG_IPW2100) += ipw2100.o +obj-$(CONFIG_IPW2200) += ipw2200.o + +obj-$(CONFIG_LIBIPW) += libipw.o +libipw-objs := \ + libipw_module.o \ + libipw_tx.o \ + libipw_rx.o \ + libipw_wx.o \ + libipw_geo.o diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c similarity index 99% rename from drivers/net/wireless/ipw2100.c rename to drivers/net/wireless/ipw2x00/ipw2100.c index bca74811bc7ff34dd946d6ef0c5b852b54165935..1667065b86a7568b7212a26fb25d76924564ad21 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -163,6 +163,8 @@ that only one external action is invoked at a time. #include #include +#include + #include "ipw2100.h" #define IPW2100_VERSION "git-1.2.2" @@ -185,7 +187,7 @@ MODULE_LICENSE("GPL"); static int debug = 0; static int mode = 0; static int channel = 0; -static int associate = 1; +static int associate = 0; static int disable = 0; #ifdef CONFIG_PM static struct ipw2100_fw ipw2100_firmware; @@ -201,7 +203,7 @@ module_param(disable, int, 0444); MODULE_PARM_DESC(debug, "debug level"); MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS,2=Monitor)"); MODULE_PARM_DESC(channel, "channel"); -MODULE_PARM_DESC(associate, "auto associate when scanning (default on)"); +MODULE_PARM_DESC(associate, "auto associate when scanning (default off)"); MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])"); static u32 ipw2100_debug_level = IPW_DL_NONE; @@ -1914,7 +1916,7 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status) u32 chan; char *txratename; u8 bssid[ETH_ALEN]; - DECLARE_MAC_BUF(mac); + DECLARE_SSID_BUF(ssid); /* * TBD: BSSID is usually 00:00:00:00:00:00 here and not @@ -1975,10 +1977,9 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status) break; } - IPW_DEBUG_INFO("%s: Associated with '%s' at %s, channel %d (BSSID=" - "%s)\n", - priv->net_dev->name, escape_essid(essid, essid_len), - txratename, chan, print_mac(mac, bssid)); + IPW_DEBUG_INFO("%s: Associated with '%s' at %s, channel %d (BSSID=%pM)\n", + priv->net_dev->name, print_ssid(ssid, essid, essid_len), + txratename, chan, bssid); /* now we copy read ssid into dev */ if (!(priv->config & CFG_STATIC_ESSID)) { @@ -2004,8 +2005,9 @@ static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid, .host_command_length = ssid_len }; int err; + DECLARE_SSID_BUF(ssid); - IPW_DEBUG_HC("SSID: '%s'\n", escape_essid(essid, ssid_len)); + IPW_DEBUG_HC("SSID: '%s'\n", print_ssid(ssid, essid, ssid_len)); if (ssid_len) memcpy(cmd.host_command_parameters, essid, ssid_len); @@ -2046,12 +2048,12 @@ static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid, static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status) { - DECLARE_MAC_BUF(mac); + DECLARE_SSID_BUF(ssid); IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, - "disassociated: '%s' %s \n", - escape_essid(priv->essid, priv->essid_len), - print_mac(mac, priv->bssid)); + "disassociated: '%s' %pM \n", + print_ssid(ssid, priv->essid, priv->essid_len), + priv->bssid); priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); @@ -4008,7 +4010,7 @@ static ssize_t show_internals(struct device *d, struct device_attribute *attr, else len += sprintf(buf + len, "not connected\n"); - DUMP_VAR(ieee->crypt[priv->ieee->tx_keyidx], "p"); + DUMP_VAR(ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx], "p"); DUMP_VAR(status, "08lx"); DUMP_VAR(config, "08lx"); DUMP_VAR(capability, "08lx"); @@ -4058,7 +4060,6 @@ static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr, char *out = buf; int length; int ret; - DECLARE_MAC_BUF(mac); if (priv->status & STATUS_RF_KILL_MASK) return 0; @@ -4086,7 +4087,7 @@ static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr, __LINE__); out += sprintf(out, "ESSID: %s\n", essid); - out += sprintf(out, "BSSID: %s\n", print_mac(mac, bssid)); + out += sprintf(out, "BSSID: %pM\n", bssid); out += sprintf(out, "Channel: %d\n", chan); return out - buf; @@ -4662,7 +4663,6 @@ static int ipw2100_read_mac_address(struct ipw2100_priv *priv) { u32 length = ETH_ALEN; u8 addr[ETH_ALEN]; - DECLARE_MAC_BUF(mac); int err; @@ -4673,8 +4673,7 @@ static int ipw2100_read_mac_address(struct ipw2100_priv *priv) } memcpy(priv->net_dev->dev_addr, addr, ETH_ALEN); - IPW_DEBUG_INFO("card MAC is %s\n", - print_mac(mac, priv->net_dev->dev_addr)); + IPW_DEBUG_INFO("card MAC is %pM\n", priv->net_dev->dev_addr); return 0; } @@ -5053,10 +5052,8 @@ static int ipw2100_set_mandatory_bssid(struct ipw2100_priv *priv, u8 * bssid, int err; #ifdef CONFIG_IPW2100_DEBUG - DECLARE_MAC_BUF(mac); if (bssid != NULL) - IPW_DEBUG_HC("MANDATORY_BSSID: %s\n", - print_mac(mac, bssid)); + IPW_DEBUG_HC("MANDATORY_BSSID: %pM\n", bssid); else IPW_DEBUG_HC("MANDATORY_BSSID: \n"); #endif @@ -5271,21 +5268,21 @@ static int ipw2100_set_ibss_beacon_interval(struct ipw2100_priv *priv, return 0; } -void ipw2100_queues_initialize(struct ipw2100_priv *priv) +static void ipw2100_queues_initialize(struct ipw2100_priv *priv) { ipw2100_tx_initialize(priv); ipw2100_rx_initialize(priv); ipw2100_msg_initialize(priv); } -void ipw2100_queues_free(struct ipw2100_priv *priv) +static void ipw2100_queues_free(struct ipw2100_priv *priv) { ipw2100_tx_free(priv); ipw2100_rx_free(priv); ipw2100_msg_free(priv); } -int ipw2100_queues_allocate(struct ipw2100_priv *priv) +static int ipw2100_queues_allocate(struct ipw2100_priv *priv) { if (ipw2100_tx_allocate(priv) || ipw2100_rx_allocate(priv) || ipw2100_msg_allocate(priv)) @@ -5517,7 +5514,7 @@ static int ipw2100_configure_security(struct ipw2100_priv *priv, int batch_mode) } } - ipw2100_set_key_index(priv, priv->ieee->tx_keyidx, 1); + ipw2100_set_key_index(priv, priv->ieee->crypt_info.tx_keyidx, 1); } /* Always enable privacy so the Host can filter WEP packets if @@ -6905,7 +6902,6 @@ static int ipw2100_wx_set_wap(struct net_device *dev, static const unsigned char off[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - DECLARE_MAC_BUF(mac); // sanity checks if (wrqu->ap_addr.sa_family != ARPHRD_ETHER) @@ -6931,8 +6927,7 @@ static int ipw2100_wx_set_wap(struct net_device *dev, err = ipw2100_set_mandatory_bssid(priv, wrqu->ap_addr.sa_data, 0); - IPW_DEBUG_WX("SET BSSID -> %s\n", - print_mac(mac, wrqu->ap_addr.sa_data)); + IPW_DEBUG_WX("SET BSSID -> %pM\n", wrqu->ap_addr.sa_data); done: mutex_unlock(&priv->action_mutex); @@ -6948,7 +6943,6 @@ static int ipw2100_wx_get_wap(struct net_device *dev, */ struct ipw2100_priv *priv = ieee80211_priv(dev); - DECLARE_MAC_BUF(mac); /* If we are associated, trying to associate, or have a statically * configured BSSID then return that; otherwise return ANY */ @@ -6958,8 +6952,7 @@ static int ipw2100_wx_get_wap(struct net_device *dev, } else memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); - IPW_DEBUG_WX("Getting WAP BSSID: %s\n", - print_mac(mac, wrqu->ap_addr.sa_data)); + IPW_DEBUG_WX("Getting WAP BSSID: %pM\n", wrqu->ap_addr.sa_data); return 0; } @@ -6971,6 +6964,7 @@ static int ipw2100_wx_set_essid(struct net_device *dev, char *essid = ""; /* ANY */ int length = 0; int err = 0; + DECLARE_SSID_BUF(ssid); mutex_lock(&priv->action_mutex); if (!(priv->status & STATUS_INITIALIZED)) { @@ -7000,8 +6994,8 @@ static int ipw2100_wx_set_essid(struct net_device *dev, goto done; } - IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", escape_essid(essid, length), - length); + IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", + print_ssid(ssid, essid, length), length); priv->essid_len = length; memcpy(priv->essid, essid, priv->essid_len); @@ -7022,12 +7016,13 @@ static int ipw2100_wx_get_essid(struct net_device *dev, */ struct ipw2100_priv *priv = ieee80211_priv(dev); + DECLARE_SSID_BUF(ssid); /* If we are associated, trying to associate, or have a statically * configured ESSID then return that; otherwise return ANY */ if (priv->config & CFG_STATIC_ESSID || priv->status & STATUS_ASSOCIATED) { IPW_DEBUG_WX("Getting essid: '%s'\n", - escape_essid(priv->essid, priv->essid_len)); + print_ssid(ssid, priv->essid, priv->essid_len)); memcpy(extra, priv->essid, priv->essid_len); wrqu->essid.length = priv->essid_len; wrqu->essid.flags = 1; /* active */ @@ -7625,7 +7620,7 @@ static int ipw2100_wx_set_auth(struct net_device *dev, struct ipw2100_priv *priv = ieee80211_priv(dev); struct ieee80211_device *ieee = priv->ieee; struct iw_param *param = &wrqu->param; - struct ieee80211_crypt_data *crypt; + struct lib80211_crypt_data *crypt; unsigned long flags; int ret = 0; @@ -7640,7 +7635,7 @@ static int ipw2100_wx_set_auth(struct net_device *dev, break; case IW_AUTH_TKIP_COUNTERMEASURES: - crypt = priv->ieee->crypt[priv->ieee->tx_keyidx]; + crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx]; if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags) break; @@ -7717,7 +7712,7 @@ static int ipw2100_wx_get_auth(struct net_device *dev, { struct ipw2100_priv *priv = ieee80211_priv(dev); struct ieee80211_device *ieee = priv->ieee; - struct ieee80211_crypt_data *crypt; + struct lib80211_crypt_data *crypt; struct iw_param *param = &wrqu->param; int ret = 0; @@ -7733,7 +7728,7 @@ static int ipw2100_wx_get_auth(struct net_device *dev, break; case IW_AUTH_TKIP_COUNTERMEASURES: - crypt = priv->ieee->crypt[priv->ieee->tx_keyidx]; + crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx]; if (!crypt || !crypt->ops->get_flags) { IPW_DEBUG_WARNING("Can't get TKIP countermeasures: " "crypt not set!\n"); diff --git a/drivers/net/wireless/ipw2100.h b/drivers/net/wireless/ipw2x00/ipw2100.h similarity index 100% rename from drivers/net/wireless/ipw2100.h rename to drivers/net/wireless/ipw2x00/ipw2100.h diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c similarity index 97% rename from drivers/net/wireless/ipw2200.c rename to drivers/net/wireless/ipw2x00/ipw2200.c index 7a9f901d4ff6dee5cf15ae78d0f9bb763344bdd7..625f2cf99fa9f9a7bf4976aeb460523e18b1b920 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -87,7 +87,7 @@ static int channel = 0; static int mode = 0; static u32 ipw_debug_level; -static int associate = 1; +static int associate; static int auto_create = 1; static int led = 0; static int disable = 0; @@ -2265,8 +2265,8 @@ static int ipw_send_adapter_address(struct ipw_priv *priv, u8 * mac) return -1; } - IPW_DEBUG_INFO("%s: Setting MAC to %s\n", - priv->net_dev->name, print_mac(mac, mac)); + IPW_DEBUG_INFO("%s: Setting MAC to %pM\n", + priv->net_dev->name, mac); return ipw_send_cmd_pdu(priv, IPW_CMD_ADAPTER_ADDRESS, ETH_ALEN, mac); } @@ -3812,7 +3812,6 @@ static u8 ipw_add_station(struct ipw_priv *priv, u8 * bssid) { struct ipw_station_entry entry; int i; - DECLARE_MAC_BUF(mac); for (i = 0; i < priv->num_stations; i++) { if (!memcmp(priv->stations[i], bssid, ETH_ALEN)) { @@ -3829,7 +3828,7 @@ static u8 ipw_add_station(struct ipw_priv *priv, u8 * bssid) if (i == MAX_STATIONS) return IPW_INVALID_STATION; - IPW_DEBUG_SCAN("Adding AdHoc station: %s\n", print_mac(mac, bssid)); + IPW_DEBUG_SCAN("Adding AdHoc station: %pM\n", bssid); entry.reserved = 0; entry.support_mode = 0; @@ -3856,7 +3855,6 @@ static u8 ipw_find_station(struct ipw_priv *priv, u8 * bssid) static void ipw_send_disassociate(struct ipw_priv *priv, int quiet) { int err; - DECLARE_MAC_BUF(mac); if (priv->status & STATUS_ASSOCIATING) { IPW_DEBUG_ASSOC("Disassociating while associating.\n"); @@ -3869,9 +3867,9 @@ static void ipw_send_disassociate(struct ipw_priv *priv, int quiet) return; } - IPW_DEBUG_ASSOC("Disassocation attempt from %s " + IPW_DEBUG_ASSOC("Disassocation attempt from %pM " "on channel %d.\n", - print_mac(mac, priv->assoc_request.bssid), + priv->assoc_request.bssid, priv->assoc_request.channel); priv->status &= ~(STATUS_ASSOCIATING | STATUS_ASSOCIATED); @@ -4347,7 +4345,8 @@ static void ipw_handle_missed_beacon(struct ipw_priv *priv, return; } - if (priv->status & STATUS_SCANNING) { + if (priv->status & STATUS_SCANNING && + missed_count > IPW_MB_SCAN_CANCEL_THRESHOLD) { /* Stop scan to keep fw from getting * stuck (only if we aren't roaming -- * otherwise we'll never scan more than 2 or 3 @@ -4398,7 +4397,7 @@ static void handle_scan_event(struct ipw_priv *priv) static void ipw_rx_notification(struct ipw_priv *priv, struct ipw_rx_notification *notif) { - DECLARE_MAC_BUF(mac); + DECLARE_SSID_BUF(ssid); u16 size = le16_to_cpu(notif->size); notif->size = le16_to_cpu(notif->size); @@ -4412,11 +4411,10 @@ static void ipw_rx_notification(struct ipw_priv *priv, case CMAS_ASSOCIATED:{ IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, - "associated: '%s' %s" - " \n", - escape_essid(priv->essid, - priv->essid_len), - print_mac(mac, priv->bssid)); + "associated: '%s' %pM \n", + print_ssid(ssid, priv->essid, + priv->essid_len), + priv->bssid); switch (priv->ieee->iw_mode) { case IW_MODE_INFRA: @@ -4450,7 +4448,7 @@ static void ipw_rx_notification(struct ipw_priv *priv, #ifdef CONFIG_IPW2200_QOS #define IPW_GET_PACKET_STYPE(x) WLAN_FC_GET_STYPE( \ - le16_to_cpu(((struct ieee80211_hdr *)(x))->frame_ctl)) + le16_to_cpu(((struct ieee80211_hdr *)(x))->frame_control)) if ((priv->status & STATUS_AUTH) && (IPW_GET_PACKET_STYPE(¬if->u.raw) == IEEE80211_STYPE_ASSOC_RESP)) { @@ -4493,13 +4491,14 @@ static void ipw_rx_notification(struct ipw_priv *priv, IPW_DL_STATE | IPW_DL_ASSOC, "deauthenticated: '%s' " - "%s" + "%pM" ": (0x%04X) - %s \n", - escape_essid(priv-> - essid, - priv-> - essid_len), - print_mac(mac, priv->bssid), + print_ssid(ssid, + priv-> + essid, + priv-> + essid_len), + priv->bssid, le16_to_cpu(auth->status), ipw_get_status_code (le16_to_cpu @@ -4516,11 +4515,10 @@ static void ipw_rx_notification(struct ipw_priv *priv, IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, - "authenticated: '%s' %s" - "\n", - escape_essid(priv->essid, - priv->essid_len), - print_mac(mac, priv->bssid)); + "authenticated: '%s' %pM\n", + print_ssid(ssid, priv->essid, + priv->essid_len), + priv->bssid); break; } @@ -4545,11 +4543,10 @@ static void ipw_rx_notification(struct ipw_priv *priv, IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, - "disassociated: '%s' %s" - " \n", - escape_essid(priv->essid, - priv->essid_len), - print_mac(mac, priv->bssid)); + "disassociated: '%s' %pM \n", + print_ssid(ssid, priv->essid, + priv->essid_len), + priv->bssid); priv->status &= ~(STATUS_DISASSOCIATING | @@ -4584,10 +4581,10 @@ static void ipw_rx_notification(struct ipw_priv *priv, switch (auth->state) { case CMAS_AUTHENTICATED: IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE, - "authenticated: '%s' %s \n", - escape_essid(priv->essid, - priv->essid_len), - print_mac(mac, priv->bssid)); + "authenticated: '%s' %pM \n", + print_ssid(ssid, priv->essid, + priv->essid_len), + priv->bssid); priv->status |= STATUS_AUTH; break; @@ -4603,10 +4600,10 @@ static void ipw_rx_notification(struct ipw_priv *priv, } IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, - "deauthenticated: '%s' %s\n", - escape_essid(priv->essid, - priv->essid_len), - print_mac(mac, priv->bssid)); + "deauthenticated: '%s' %pM\n", + print_ssid(ssid, priv->essid, + priv->essid_len), + priv->bssid); priv->status &= ~(STATUS_ASSOCIATING | STATUS_AUTH | @@ -5430,27 +5427,17 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, int roaming) { struct ipw_supported_rates rates; - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); + DECLARE_SSID_BUF(ssid); /* Verify that this network's capability is compatible with the * current mode (AdHoc or Infrastructure) */ if ((priv->ieee->iw_mode == IW_MODE_ADHOC && !(network->capability & WLAN_CAPABILITY_IBSS))) { - IPW_DEBUG_MERGE("Network '%s (%s)' excluded due to " + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded due to " "capability mismatch.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); - return 0; - } - - /* If we do not have an ESSID for this AP, we can not associate with - * it */ - if (network->flags & NETWORK_EMPTY_ESSID) { - IPW_DEBUG_MERGE("Network '%s (%s)' excluded " - "because of hidden ESSID.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); return 0; } @@ -5460,11 +5447,11 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, if ((network->ssid_len != match->network->ssid_len) || memcmp(network->ssid, match->network->ssid, network->ssid_len)) { - IPW_DEBUG_MERGE("Network '%s (%s)' excluded " + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of non-network ESSID.\n", - escape_essid(network->ssid, - network->ssid_len), - print_mac(mac, network->bssid)); + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); return 0; } } else { @@ -5477,13 +5464,14 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; strncpy(escaped, - escape_essid(network->ssid, network->ssid_len), + print_ssid(ssid, network->ssid, + network->ssid_len), sizeof(escaped)); - IPW_DEBUG_MERGE("Network '%s (%s)' excluded " + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of ESSID mismatch: '%s'.\n", - escaped, print_mac(mac, network->bssid), - escape_essid(priv->essid, - priv->essid_len)); + escaped, network->bssid, + print_ssid(ssid, priv->essid, + priv->essid_len)); return 0; } } @@ -5494,24 +5482,25 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, if (network->time_stamp[0] < match->network->time_stamp[0]) { IPW_DEBUG_MERGE("Network '%s excluded because newer than " "current network.\n", - escape_essid(match->network->ssid, - match->network->ssid_len)); + print_ssid(ssid, match->network->ssid, + match->network->ssid_len)); return 0; } else if (network->time_stamp[1] < match->network->time_stamp[1]) { IPW_DEBUG_MERGE("Network '%s excluded because newer than " "current network.\n", - escape_essid(match->network->ssid, - match->network->ssid_len)); + print_ssid(ssid, match->network->ssid, + match->network->ssid_len)); return 0; } /* Now go through and see if the requested network is valid... */ if (priv->ieee->scan_age != 0 && time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) { - IPW_DEBUG_MERGE("Network '%s (%s)' excluded " + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of age: %ums.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid), + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid, jiffies_to_msecs(jiffies - network->last_scanned)); return 0; @@ -5519,10 +5508,11 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, if ((priv->config & CFG_STATIC_CHANNEL) && (network->channel != priv->channel)) { - IPW_DEBUG_MERGE("Network '%s (%s)' excluded " + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of channel mismatch: %d != %d.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid), + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid, network->channel, priv->channel); return 0; } @@ -5530,10 +5520,11 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, /* Verify privacy compatability */ if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) != ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) { - IPW_DEBUG_MERGE("Network '%s (%s)' excluded " + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of privacy mismatch: %s != %s.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid), + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid, priv-> capability & CAP_PRIVACY_ON ? "on" : "off", network-> @@ -5543,41 +5534,44 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, } if (!memcmp(network->bssid, priv->bssid, ETH_ALEN)) { - IPW_DEBUG_MERGE("Network '%s (%s)' excluded " - "because of the same BSSID match: %s" - ".\n", escape_essid(network->ssid, - network->ssid_len), - print_mac(mac, network->bssid), - print_mac(mac2, priv->bssid)); + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " + "because of the same BSSID match: %pM" + ".\n", print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid, + priv->bssid); return 0; } /* Filter out any incompatible freq / mode combinations */ if (!ieee80211_is_valid_mode(priv->ieee, network->mode)) { - IPW_DEBUG_MERGE("Network '%s (%s)' excluded " + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of invalid frequency/mode " "combination.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); return 0; } /* Ensure that the rates supported by the driver are compatible with * this AP, including verification of basic rates (mandatory) */ if (!ipw_compatible_rates(priv, network, &rates)) { - IPW_DEBUG_MERGE("Network '%s (%s)' excluded " + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because configured rate mask excludes " "AP mandatory rate.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); return 0; } if (rates.num_rates == 0) { - IPW_DEBUG_MERGE("Network '%s (%s)' excluded " + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of no compatible rates.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); return 0; } @@ -5588,15 +5582,16 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, /* Set up 'new' AP to this network */ ipw_copy_rates(&match->rates, &rates); match->network = network; - IPW_DEBUG_MERGE("Network '%s (%s)' is a viable match.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + IPW_DEBUG_MERGE("Network '%s (%pM)' is a viable match.\n", + print_ssid(ssid, network->ssid, network->ssid_len), + network->bssid); return 1; } static void ipw_merge_adhoc_network(struct work_struct *work) { + DECLARE_SSID_BUF(ssid); struct ipw_priv *priv = container_of(work, struct ipw_priv, merge_networks); struct ieee80211_network *network = NULL; @@ -5627,8 +5622,8 @@ static void ipw_merge_adhoc_network(struct work_struct *work) mutex_lock(&priv->mutex); if ((priv->ieee->iw_mode == IW_MODE_ADHOC)) { IPW_DEBUG_MERGE("remove network %s\n", - escape_essid(priv->essid, - priv->essid_len)); + print_ssid(ssid, priv->essid, + priv->essid_len)); ipw_remove_current_network(priv); } @@ -5644,7 +5639,7 @@ static int ipw_best_network(struct ipw_priv *priv, struct ieee80211_network *network, int roaming) { struct ipw_supported_rates rates; - DECLARE_MAC_BUF(mac); + DECLARE_SSID_BUF(ssid); /* Verify that this network's capability is compatible with the * current mode (AdHoc or Infrastructure) */ @@ -5652,20 +5647,11 @@ static int ipw_best_network(struct ipw_priv *priv, !(network->capability & WLAN_CAPABILITY_ESS)) || (priv->ieee->iw_mode == IW_MODE_ADHOC && !(network->capability & WLAN_CAPABILITY_IBSS))) { - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded due to " + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded due to " "capability mismatch.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); - return 0; - } - - /* If we do not have an ESSID for this AP, we can not associate with - * it */ - if (network->flags & NETWORK_EMPTY_ESSID) { - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " - "because of hidden ESSID.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); return 0; } @@ -5675,11 +5661,11 @@ static int ipw_best_network(struct ipw_priv *priv, if ((network->ssid_len != match->network->ssid_len) || memcmp(network->ssid, match->network->ssid, network->ssid_len)) { - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of non-network ESSID.\n", - escape_essid(network->ssid, - network->ssid_len), - print_mac(mac, network->bssid)); + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); return 0; } } else { @@ -5691,13 +5677,14 @@ static int ipw_best_network(struct ipw_priv *priv, min(network->ssid_len, priv->essid_len)))) { char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; strncpy(escaped, - escape_essid(network->ssid, network->ssid_len), + print_ssid(ssid, network->ssid, + network->ssid_len), sizeof(escaped)); - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of ESSID mismatch: '%s'.\n", - escaped, print_mac(mac, network->bssid), - escape_essid(priv->essid, - priv->essid_len)); + escaped, network->bssid, + print_ssid(ssid, priv->essid, + priv->essid_len)); return 0; } } @@ -5707,14 +5694,14 @@ static int ipw_best_network(struct ipw_priv *priv, if (match->network && match->network->stats.rssi > network->stats.rssi) { char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; strncpy(escaped, - escape_essid(network->ssid, network->ssid_len), + print_ssid(ssid, network->ssid, network->ssid_len), sizeof(escaped)); - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded because " - "'%s (%s)' has a stronger signal.\n", - escaped, print_mac(mac, network->bssid), - escape_essid(match->network->ssid, - match->network->ssid_len), - print_mac(mac, 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; } @@ -5722,11 +5709,12 @@ static int ipw_best_network(struct ipw_priv *priv, * last 3 seconds, do not try and associate again... */ if (network->last_associate && time_after(network->last_associate + (HZ * 3UL), jiffies)) { - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of storming (%ums since last " "assoc attempt).\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid), + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid, jiffies_to_msecs(jiffies - network->last_associate)); return 0; @@ -5735,10 +5723,11 @@ static int ipw_best_network(struct ipw_priv *priv, /* Now go through and see if the requested network is valid... */ if (priv->ieee->scan_age != 0 && time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) { - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of age: %ums.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid), + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid, jiffies_to_msecs(jiffies - network->last_scanned)); return 0; @@ -5746,10 +5735,11 @@ static int ipw_best_network(struct ipw_priv *priv, if ((priv->config & CFG_STATIC_CHANNEL) && (network->channel != priv->channel)) { - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of channel mismatch: %d != %d.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid), + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid, network->channel, priv->channel); return 0; } @@ -5757,10 +5747,11 @@ static int ipw_best_network(struct ipw_priv *priv, /* Verify privacy compatability */ if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) != ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) { - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of privacy mismatch: %s != %s.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid), + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid, priv->capability & CAP_PRIVACY_ON ? "on" : "off", network->capability & @@ -5770,48 +5761,53 @@ static int ipw_best_network(struct ipw_priv *priv, if ((priv->config & CFG_STATIC_BSSID) && memcmp(network->bssid, priv->bssid, ETH_ALEN)) { - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " - "because of BSSID mismatch: %s.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid), print_mac(mac, priv->bssid)); + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " + "because of BSSID mismatch: %pM.\n", + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid, priv->bssid); return 0; } /* Filter out any incompatible freq / mode combinations */ if (!ieee80211_is_valid_mode(priv->ieee, network->mode)) { - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of invalid frequency/mode " "combination.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); return 0; } /* Filter out invalid channel in current GEO */ if (!ieee80211_is_valid_channel(priv->ieee, network->channel)) { - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of invalid channel in current GEO\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); return 0; } /* Ensure that the rates supported by the driver are compatible with * this AP, including verification of basic rates (mandatory) */ if (!ipw_compatible_rates(priv, network, &rates)) { - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because configured rate mask excludes " "AP mandatory rate.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); return 0; } if (rates.num_rates == 0) { - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of no compatible rates.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); return 0; } @@ -5823,9 +5819,9 @@ static int ipw_best_network(struct ipw_priv *priv, ipw_copy_rates(&match->rates, &rates); match->network = network; - IPW_DEBUG_ASSOC("Network '%s (%s)' is a viable match.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + IPW_DEBUG_ASSOC("Network '%s (%pM)' is a viable match.\n", + print_ssid(ssid, network->ssid, network->ssid_len), + network->bssid); return 1; } @@ -6067,7 +6063,7 @@ static void ipw_bg_adhoc_check(struct work_struct *work) static void ipw_debug_config(struct ipw_priv *priv) { - DECLARE_MAC_BUF(mac); + DECLARE_SSID_BUF(ssid); IPW_DEBUG_INFO("Scan completed, no valid APs matched " "[CFG 0x%08X]\n", priv->config); if (priv->config & CFG_STATIC_CHANNEL) @@ -6076,12 +6072,11 @@ static void ipw_debug_config(struct ipw_priv *priv) IPW_DEBUG_INFO("Channel unlocked.\n"); if (priv->config & CFG_STATIC_ESSID) IPW_DEBUG_INFO("ESSID locked to '%s'\n", - escape_essid(priv->essid, priv->essid_len)); + print_ssid(ssid, priv->essid, priv->essid_len)); else IPW_DEBUG_INFO("ESSID unlocked.\n"); if (priv->config & CFG_STATIC_BSSID) - IPW_DEBUG_INFO("BSSID locked to %s\n", - print_mac(mac, priv->bssid)); + IPW_DEBUG_INFO("BSSID locked to %pM\n", priv->bssid); else IPW_DEBUG_INFO("BSSID unlocked.\n"); if (priv->capability & CAP_PRIVACY_ON) @@ -6277,6 +6272,20 @@ static void ipw_add_scan_channels(struct ipw_priv *priv, } } +static int ipw_passive_dwell_time(struct ipw_priv *priv) +{ + /* staying on passive channels longer than the DTIM interval during a + * scan, while associated, causes the firmware to cancel the scan + * without notification. Hence, don't stay on passive channels longer + * than the beacon interval. + */ + if (priv->status & STATUS_ASSOCIATED + && priv->assoc_network->beacon_interval > 10) + return priv->assoc_network->beacon_interval - 10; + else + return 120; +} + static int ipw_request_scan_helper(struct ipw_priv *priv, int type, int direct) { struct ipw_scan_request_ext scan; @@ -6320,16 +6329,16 @@ static int ipw_request_scan_helper(struct ipw_priv *priv, int type, int direct) scan.full_scan_index = cpu_to_le32(ieee80211_get_scans(priv->ieee)); if (type == IW_SCAN_TYPE_PASSIVE) { - IPW_DEBUG_WX("use passive scanning\n"); - scan_type = IPW_SCAN_PASSIVE_FULL_DWELL_SCAN; + IPW_DEBUG_WX("use passive scanning\n"); + scan_type = IPW_SCAN_PASSIVE_FULL_DWELL_SCAN; scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = - cpu_to_le16(120); + cpu_to_le16(ipw_passive_dwell_time(priv)); ipw_add_scan_channels(priv, &scan, scan_type); goto send_request; } /* Use active scan by default. */ - if (priv->config & CFG_SPEED_SCAN) + if (priv->config & CFG_SPEED_SCAN) scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] = cpu_to_le16(30); else @@ -6339,7 +6348,8 @@ static int ipw_request_scan_helper(struct ipw_priv *priv, int type, int direct) scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] = cpu_to_le16(20); - scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = cpu_to_le16(120); + scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = + cpu_to_le16(ipw_passive_dwell_time(priv)); scan.dwell_time[IPW_SCAN_ACTIVE_DIRECT_SCAN] = cpu_to_le16(20); #ifdef CONFIG_IPW2200_MONITOR @@ -6607,7 +6617,7 @@ static int ipw_wx_set_auth(struct net_device *dev, struct ipw_priv *priv = ieee80211_priv(dev); struct ieee80211_device *ieee = priv->ieee; struct iw_param *param = &wrqu->param; - struct ieee80211_crypt_data *crypt; + struct lib80211_crypt_data *crypt; unsigned long flags; int ret = 0; @@ -6629,7 +6639,7 @@ static int ipw_wx_set_auth(struct net_device *dev, break; case IW_AUTH_TKIP_COUNTERMEASURES: - crypt = priv->ieee->crypt[priv->ieee->tx_keyidx]; + crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx]; if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags) break; @@ -6706,7 +6716,7 @@ static int ipw_wx_get_auth(struct net_device *dev, { struct ipw_priv *priv = ieee80211_priv(dev); struct ieee80211_device *ieee = priv->ieee; - struct ieee80211_crypt_data *crypt; + struct lib80211_crypt_data *crypt; struct iw_param *param = &wrqu->param; int ret = 0; @@ -6722,7 +6732,7 @@ static int ipw_wx_get_auth(struct net_device *dev, break; case IW_AUTH_TKIP_COUNTERMEASURES: - crypt = priv->ieee->crypt[priv->ieee->tx_keyidx]; + crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx]; if (!crypt || !crypt->ops->get_flags) break; @@ -6893,8 +6903,7 @@ static int ipw_qos_handle_probe_response(struct ipw_priv *priv, if ((priv->status & STATUS_ASSOCIATED) && (priv->ieee->iw_mode == IW_MODE_ADHOC) && (active_network == 0)) { if (memcmp(network->bssid, priv->bssid, ETH_ALEN)) - if ((network->capability & WLAN_CAPABILITY_IBSS) && - !(network->flags & NETWORK_EMPTY_ESSID)) + if (network->capability & WLAN_CAPABILITY_IBSS) if ((network->ssid_len == priv->assoc_network->ssid_len) && !memcmp(network->ssid, @@ -7296,7 +7305,7 @@ static int ipw_associate_network(struct ipw_priv *priv, struct ipw_supported_rates *rates, int roaming) { int err; - DECLARE_MAC_BUF(mac); + DECLARE_SSID_BUF(ssid); if (priv->config & CFG_FIXED_RATE) ipw_set_fixed_rate(priv, network->mode); @@ -7365,7 +7374,7 @@ static int ipw_associate_network(struct ipw_priv *priv, IPW_DEBUG_ASSOC("%sssocation attempt: '%s', channel %d, " "802.11%c [%d], %s[:%s], enc=%s%s%s%c%c\n", roaming ? "Rea" : "A", - escape_essid(priv->essid, priv->essid_len), + print_ssid(ssid, priv->essid, priv->essid_len), network->channel, ipw_modes[priv->assoc_request.ieee_mode], rates->num_rates, @@ -7464,9 +7473,9 @@ static int ipw_associate_network(struct ipw_priv *priv, return err; } - IPW_DEBUG(IPW_DL_STATE, "associating: '%s' %s \n", - escape_essid(priv->essid, priv->essid_len), - print_mac(mac, priv->bssid)); + IPW_DEBUG(IPW_DL_STATE, "associating: '%s' %pM \n", + print_ssid(ssid, priv->essid, priv->essid_len), + priv->bssid); return 0; } @@ -7556,6 +7565,7 @@ static int ipw_associate(void *data) struct ipw_supported_rates *rates; struct list_head *element; unsigned long flags; + DECLARE_SSID_BUF(ssid); if (priv->ieee->iw_mode == IW_MODE_MONITOR) { IPW_DEBUG_ASSOC("Not attempting association (monitor mode)\n"); @@ -7582,8 +7592,7 @@ static int ipw_associate(void *data) } if (!(priv->config & CFG_ASSOCIATE) && - !(priv->config & (CFG_STATIC_ESSID | - CFG_STATIC_CHANNEL | CFG_STATIC_BSSID))) { + !(priv->config & (CFG_STATIC_ESSID | CFG_STATIC_BSSID))) { IPW_DEBUG_ASSOC("Not attempting association (associate=0)\n"); return 0; } @@ -7605,7 +7614,6 @@ static int ipw_associate(void *data) if (list_empty(&priv->ieee->network_free_list)) { struct ieee80211_network *oldest = NULL; struct ieee80211_network *target; - DECLARE_MAC_BUF(mac); list_for_each_entry(target, &priv->ieee->network_list, list) { if ((oldest == NULL) || @@ -7616,11 +7624,11 @@ static int ipw_associate(void *data) /* If there are no more slots, expire the oldest */ list_del(&oldest->list); target = oldest; - IPW_DEBUG_ASSOC("Expired '%s' (%s) from " + IPW_DEBUG_ASSOC("Expired '%s' (%pM) from " "network list.\n", - escape_essid(target->ssid, - target->ssid_len), - print_mac(mac, target->bssid)); + print_ssid(ssid, target->ssid, + target->ssid_len), + target->bssid); list_add_tail(&target->list, &priv->ieee->network_free_list); } @@ -7673,12 +7681,12 @@ static void ipw_rebuild_decrypted_skb(struct ipw_priv *priv, u16 fc; hdr = (struct ieee80211_hdr *)skb->data; - fc = le16_to_cpu(hdr->frame_ctl); + fc = le16_to_cpu(hdr->frame_control); if (!(fc & IEEE80211_FCTL_PROTECTED)) return; fc &= ~IEEE80211_FCTL_PROTECTED; - hdr->frame_ctl = cpu_to_le16(fc); + hdr->frame_control = cpu_to_le16(fc); switch (priv->ieee->sec.level) { case SEC_LEVEL_3: /* Remove CCMP HDR */ @@ -7806,15 +7814,6 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv, memmove(rxb->skb->data + sizeof(struct ipw_rt_hdr), rxb->skb->data + IPW_RX_FRAME_SIZE, len); - /* Zero the radiotap static buffer ... We only need to zero the bytes NOT - * part of our real header, saves a little time. - * - * No longer necessary since we fill in all our data. Purge before merging - * patch officially. - * memset(rxb->skb->data + sizeof(struct ipw_rt_hdr), 0, - * IEEE80211_RADIOTAP_HDRLEN - sizeof(struct ipw_rt_hdr)); - */ - ipw_rt = (struct ipw_rt_hdr *)rxb->skb->data; ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; @@ -7990,17 +7989,17 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv, } hdr = (void *)rxb->skb->data + IPW_RX_FRAME_SIZE; - if (ieee80211_is_management(le16_to_cpu(hdr->frame_ctl))) { + if (ieee80211_is_management(le16_to_cpu(hdr->frame_control))) { if (filter & IPW_PROM_NO_MGMT) return; if (filter & IPW_PROM_MGMT_HEADER_ONLY) hdr_only = 1; - } else if (ieee80211_is_control(le16_to_cpu(hdr->frame_ctl))) { + } else if (ieee80211_is_control(le16_to_cpu(hdr->frame_control))) { if (filter & IPW_PROM_NO_CTL) return; if (filter & IPW_PROM_CTL_HEADER_ONLY) hdr_only = 1; - } else if (ieee80211_is_data(le16_to_cpu(hdr->frame_ctl))) { + } else if (ieee80211_is_data(le16_to_cpu(hdr->frame_control))) { if (filter & IPW_PROM_NO_DATA) return; if (filter & IPW_PROM_DATA_HEADER_ONLY) @@ -8018,19 +8017,10 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv, ipw_rt = (void *)skb->data; if (hdr_only) - len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); + len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)); memcpy(ipw_rt->payload, hdr, len); - /* Zero the radiotap static buffer ... We only need to zero the bytes - * NOT part of our real header, saves a little time. - * - * No longer necessary since we fill in all our data. Purge before - * merging patch officially. - * memset(rxb->skb->data + sizeof(struct ipw_rt_hdr), 0, - * IEEE80211_RADIOTAP_HDRLEN - sizeof(struct ipw_rt_hdr)); - */ - ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */ ipw_rt->rt_hdr.it_len = cpu_to_le16(sizeof(*ipw_rt)); /* total header+data */ @@ -8238,7 +8228,7 @@ static int is_duplicate_packet(struct ipw_priv *priv, /* Comment this line now since we observed the card receives * duplicate packets but the FCTL_RETRY bit is not set in the * IBSS mode with fragmentation enabled. - BUG_ON(!(le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_RETRY)); */ + BUG_ON(!(le16_to_cpu(header->frame_control) & IEEE80211_FCTL_RETRY)); */ return 1; } @@ -8302,9 +8292,6 @@ static void ipw_rx(struct ipw_priv *priv) u32 r, w, i; u8 network_packet; u8 fill_rx = 0; - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); - DECLARE_MAC_BUF(mac3); r = ipw_read32(priv, IPW_RX_READ_INDEX); w = ipw_read32(priv, IPW_RX_WRITE_INDEX); @@ -8434,18 +8421,12 @@ static void ipw_rx(struct ipw_priv *priv) header))) { IPW_DEBUG_DROP("Dropping: " - "%s, " - "%s, " - "%s\n", - print_mac(mac, - header-> - addr1), - print_mac(mac2, - header-> - addr2), - print_mac(mac3, - header-> - addr3)); + "%pM, " + "%pM, " + "%pM\n", + header->addr1, + header->addr2, + header->addr3); break; } @@ -8984,7 +8965,6 @@ static int ipw_wx_set_wap(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - DECLARE_MAC_BUF(mac); static const unsigned char any[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff @@ -9015,8 +8995,8 @@ static int ipw_wx_set_wap(struct net_device *dev, return 0; } - IPW_DEBUG_WX("Setting mandatory BSSID to %s\n", - print_mac(mac, wrqu->ap_addr.sa_data)); + IPW_DEBUG_WX("Setting mandatory BSSID to %pM\n", + wrqu->ap_addr.sa_data); memcpy(priv->bssid, wrqu->ap_addr.sa_data, ETH_ALEN); @@ -9034,7 +9014,6 @@ static int ipw_wx_get_wap(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - DECLARE_MAC_BUF(mac); /* If we are associated, trying to associate, or have a statically * configured BSSID then return that; otherwise return ANY */ @@ -9046,8 +9025,8 @@ static int ipw_wx_get_wap(struct net_device *dev, } else memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); - IPW_DEBUG_WX("Getting WAP BSSID: %s\n", - print_mac(mac, wrqu->ap_addr.sa_data)); + IPW_DEBUG_WX("Getting WAP BSSID: %pM\n", + wrqu->ap_addr.sa_data); mutex_unlock(&priv->mutex); return 0; } @@ -9058,6 +9037,7 @@ static int ipw_wx_set_essid(struct net_device *dev, { struct ipw_priv *priv = ieee80211_priv(dev); int length; + DECLARE_SSID_BUF(ssid); mutex_lock(&priv->mutex); @@ -9082,8 +9062,8 @@ static int ipw_wx_set_essid(struct net_device *dev, return 0; } - IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", escape_essid(extra, length), - length); + IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", + print_ssid(ssid, extra, length), length); priv->essid_len = length; memcpy(priv->essid, extra, priv->essid_len); @@ -9102,6 +9082,7 @@ static int ipw_wx_get_essid(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); + DECLARE_SSID_BUF(ssid); /* If we are associated, trying to associate, or have a statically * configured ESSID then return that; otherwise return ANY */ @@ -9109,7 +9090,7 @@ static int ipw_wx_get_essid(struct net_device *dev, if (priv->config & CFG_STATIC_ESSID || priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { IPW_DEBUG_WX("Getting essid: '%s'\n", - escape_essid(priv->essid, priv->essid_len)); + print_ssid(ssid, priv->essid, priv->essid_len)); memcpy(extra, priv->essid, priv->essid_len); wrqu->essid.length = priv->essid_len; wrqu->essid.flags = 1; /* active */ @@ -10203,10 +10184,8 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, id = ipw_add_station(priv, hdr->addr1); if (id == IPW_INVALID_STATION) { IPW_WARNING("Attempt to send data to " - "invalid cell: " MAC_FMT "\n", - hdr->addr1[0], hdr->addr1[1], - hdr->addr1[2], hdr->addr1[3], - hdr->addr1[4], hdr->addr1[5]); + "invalid cell: %pM\n", + hdr->addr1); goto drop; } } @@ -10274,8 +10253,8 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, case SEC_LEVEL_1: tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); - tfd->u.data.key_index = priv->ieee->tx_keyidx; - if (priv->ieee->sec.key_sizes[priv->ieee->tx_keyidx] <= + tfd->u.data.key_index = priv->ieee->crypt_info.tx_keyidx; + if (priv->ieee->sec.key_sizes[priv->ieee->crypt_info.tx_keyidx] <= 40) tfd->u.data.key_index |= DCT_WEP_KEY_64Bit; else @@ -10403,17 +10382,17 @@ static void ipw_handle_promiscuous_tx(struct ipw_priv *priv, /* Filtering of fragment chains is done agains the first fragment */ hdr = (void *)txb->fragments[0]->data; - if (ieee80211_is_management(le16_to_cpu(hdr->frame_ctl))) { + if (ieee80211_is_management(le16_to_cpu(hdr->frame_control))) { if (filter & IPW_PROM_NO_MGMT) return; if (filter & IPW_PROM_MGMT_HEADER_ONLY) hdr_only = 1; - } else if (ieee80211_is_control(le16_to_cpu(hdr->frame_ctl))) { + } else if (ieee80211_is_control(le16_to_cpu(hdr->frame_control))) { if (filter & IPW_PROM_NO_CTL) return; if (filter & IPW_PROM_CTL_HEADER_ONLY) hdr_only = 1; - } else if (ieee80211_is_data(le16_to_cpu(hdr->frame_ctl))) { + } else if (ieee80211_is_data(le16_to_cpu(hdr->frame_control))) { if (filter & IPW_PROM_NO_DATA) return; if (filter & IPW_PROM_DATA_HEADER_ONLY) @@ -10428,13 +10407,13 @@ static void ipw_handle_promiscuous_tx(struct ipw_priv *priv, if (hdr_only) { hdr = (void *)src->data; - len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); + len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)); } else len = src->len; - dst = alloc_skb( - len + IEEE80211_RADIOTAP_HDRLEN, GFP_ATOMIC); - if (!dst) continue; + dst = alloc_skb(len + sizeof(*rt_hdr), GFP_ATOMIC); + if (!dst) + continue; rt_hdr = (void *)skb_put(dst, sizeof(*rt_hdr)); @@ -10509,15 +10488,14 @@ static int ipw_net_set_mac_address(struct net_device *dev, void *p) { struct ipw_priv *priv = ieee80211_priv(dev); struct sockaddr *addr = p; - DECLARE_MAC_BUF(mac); if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; mutex_lock(&priv->mutex); priv->config |= CFG_CUSTOM_MAC; memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN); - printk(KERN_INFO "%s: Setting MAC to %s\n", - priv->net_dev->name, print_mac(mac, priv->mac_addr)); + printk(KERN_INFO "%s: Setting MAC to %pM\n", + priv->net_dev->name, priv->mac_addr); queue_work(priv->workqueue, &priv->adapter_restart); mutex_unlock(&priv->mutex); return 0; @@ -11652,7 +11630,7 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev, length = pci_resource_len(pdev, 0); priv->hw_len = length; - base = ioremap_nocache(pci_resource_start(pdev, 0), length); + base = pci_ioremap_bar(pdev, 0); if (!base) { err = -ENODEV; goto out_pci_release_regions; @@ -11944,7 +11922,7 @@ module_param(disable, int, 0444); MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])"); module_param(associate, int, 0444); -MODULE_PARM_DESC(associate, "auto associate when scanning (default on)"); +MODULE_PARM_DESC(associate, "auto associate when scanning (default off)"); module_param(auto_create, int, 0444); MODULE_PARM_DESC(auto_create, "auto create adhoc network (default on)"); diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2x00/ipw2200.h similarity index 99% rename from drivers/net/wireless/ipw2200.h rename to drivers/net/wireless/ipw2x00/ipw2200.h index 0bad1ec3e7e0af7c9594d6cdc2deb0cce002811a..277b274d4be5d10f6552d5273591895cc138a460 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2x00/ipw2200.h @@ -48,6 +48,7 @@ #include #include +#include #include #include @@ -244,6 +245,7 @@ enum connection_manager_assoc_states { #define HOST_NOTIFICATION_S36_MEASUREMENT_REFUSED 31 #define HOST_NOTIFICATION_STATUS_BEACON_MISSING 1 +#define IPW_MB_SCAN_CANCEL_THRESHOLD 3 #define IPW_MB_ROAMING_THRESHOLD_MIN 1 #define IPW_MB_ROAMING_THRESHOLD_DEFAULT 8 #define IPW_MB_ROAMING_THRESHOLD_MAX 30 diff --git a/net/ieee80211/ieee80211_geo.c b/drivers/net/wireless/ipw2x00/libipw_geo.c similarity index 100% rename from net/ieee80211/ieee80211_geo.c rename to drivers/net/wireless/ipw2x00/libipw_geo.c diff --git a/net/ieee80211/ieee80211_module.c b/drivers/net/wireless/ipw2x00/libipw_module.c similarity index 88% rename from net/ieee80211/ieee80211_module.c rename to drivers/net/wireless/ipw2x00/libipw_module.c index 949772a5a7dc15bd35152c3ada3df912681acfd7..a2f5616d5b095a2f80bea548871fbac24f05f751 100644 --- a/net/ieee80211/ieee80211_module.c +++ b/drivers/net/wireless/ipw2x00/libipw_module.c @@ -180,13 +180,10 @@ struct net_device *alloc_ieee80211(int sizeof_priv) ieee->host_open_frag = 1; ieee->ieee802_1x = 1; /* Default to supporting 802.1x */ - INIT_LIST_HEAD(&ieee->crypt_deinit_list); - setup_timer(&ieee->crypt_deinit_timer, ieee80211_crypt_deinit_handler, - (unsigned long)ieee); - ieee->crypt_quiesced = 0; - spin_lock_init(&ieee->lock); + lib80211_crypt_info_init(&ieee->crypt_info, dev->name, &ieee->lock); + ieee->wpa_enabled = 0; ieee->drop_unencrypted = 0; ieee->privacy_invoked = 0; @@ -203,23 +200,7 @@ void free_ieee80211(struct net_device *dev) { struct ieee80211_device *ieee = netdev_priv(dev); - int i; - - ieee80211_crypt_quiescing(ieee); - del_timer_sync(&ieee->crypt_deinit_timer); - ieee80211_crypt_deinit_entries(ieee, 1); - - for (i = 0; i < WEP_KEYS; i++) { - struct ieee80211_crypt_data *crypt = ieee->crypt[i]; - if (crypt) { - if (crypt->ops) { - crypt->ops->deinit(crypt->priv); - module_put(crypt->ops->owner); - } - kfree(crypt); - ieee->crypt[i] = NULL; - } - } + lib80211_crypt_info_free(&ieee->crypt_info); ieee80211_networks_free(ieee); free_netdev(dev); @@ -308,31 +289,5 @@ MODULE_PARM_DESC(debug, "debug output mask"); module_exit(ieee80211_exit); module_init(ieee80211_init); -const char *escape_essid(const char *essid, u8 essid_len) -{ - static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; - const char *s = essid; - char *d = escaped; - - if (ieee80211_is_empty_essid(essid, essid_len)) { - memcpy(escaped, "", sizeof("")); - return escaped; - } - - essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE); - while (essid_len--) { - if (*s == '\0') { - *d++ = '\\'; - *d++ = '0'; - s++; - } else { - *d++ = *s++; - } - } - *d = '\0'; - return escaped; -} - EXPORT_SYMBOL(alloc_ieee80211); EXPORT_SYMBOL(free_ieee80211); -EXPORT_SYMBOL(escape_essid); diff --git a/net/ieee80211/ieee80211_rx.c b/drivers/net/wireless/ipw2x00/libipw_rx.c similarity index 94% rename from net/ieee80211/ieee80211_rx.c rename to drivers/net/wireless/ipw2x00/libipw_rx.c index 69dbc342a4649271341946341b6231495e293c91..9c67dfae43200c0e0516abfc794e906be98539b9 100644 --- a/net/ieee80211/ieee80211_rx.c +++ b/drivers/net/wireless/ipw2x00/libipw_rx.c @@ -32,6 +32,7 @@ #include #include +#include #include static void ieee80211_monitor_rx(struct ieee80211_device *ieee, @@ -39,7 +40,7 @@ static void ieee80211_monitor_rx(struct ieee80211_device *ieee, struct ieee80211_rx_stats *rx_stats) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - u16 fc = le16_to_cpu(hdr->frame_ctl); + u16 fc = le16_to_cpu(hdr->frame_control); skb->dev = ieee->dev; skb_reset_mac_header(skb); @@ -267,7 +268,7 @@ static int ieee80211_is_eapol_frame(struct ieee80211_device *ieee, /* Called only as a tasklet (software IRQ), by ieee80211_rx */ static int ieee80211_rx_frame_decrypt(struct ieee80211_device *ieee, struct sk_buff *skb, - struct ieee80211_crypt_data *crypt) + struct lib80211_crypt_data *crypt) { struct ieee80211_hdr_3addr *hdr; int res, hdrlen; @@ -282,12 +283,8 @@ ieee80211_rx_frame_decrypt(struct ieee80211_device *ieee, struct sk_buff *skb, res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv); atomic_dec(&crypt->refcnt); if (res < 0) { - IEEE80211_DEBUG_DROP("decryption failed (SA=" MAC_FMT - ") res=%d\n", - hdr->addr2[0], hdr->addr2[1], - hdr->addr2[2], hdr->addr2[3], - hdr->addr2[4], hdr->addr2[5], - res); + IEEE80211_DEBUG_DROP("decryption failed (SA=%pM) res=%d\n", + hdr->addr2, res); if (res == -2) IEEE80211_DEBUG_DROP("Decryption failed ICV " "mismatch (key %d)\n", @@ -303,7 +300,7 @@ ieee80211_rx_frame_decrypt(struct ieee80211_device *ieee, struct sk_buff *skb, static int ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device *ieee, struct sk_buff *skb, int keyidx, - struct ieee80211_crypt_data *crypt) + struct lib80211_crypt_data *crypt) { struct ieee80211_hdr_3addr *hdr; int res, hdrlen; @@ -319,11 +316,7 @@ ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device *ieee, atomic_dec(&crypt->refcnt); if (res < 0) { printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed" - " (SA=" MAC_FMT " keyidx=%d)\n", - ieee->dev->name, - hdr->addr2[0], hdr->addr2[1], - hdr->addr2[2], hdr->addr2[3], - hdr->addr2[4], hdr->addr2[5], + " (SA=%pM keyidx=%d)\n", ieee->dev->name, hdr->addr2, keyidx); return -1; } @@ -355,10 +348,9 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, #endif u8 dst[ETH_ALEN]; u8 src[ETH_ALEN]; - struct ieee80211_crypt_data *crypt = NULL; + struct lib80211_crypt_data *crypt = NULL; int keyidx = 0; int can_be_decrypted = 0; - DECLARE_MAC_BUF(mac); hdr = (struct ieee80211_hdr_4addr *)skb->data; stats = &ieee->stats; @@ -439,7 +431,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, * is only allowed 2-bits of storage, no value of keyidx can * be provided via above code that would result in keyidx * being out of range */ - crypt = ieee->crypt[keyidx]; + crypt = ieee->crypt_info.crypt[keyidx]; #ifdef NOT_YET sta = NULL; @@ -468,10 +460,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, * frames silently instead of filling system log with * these reports. */ IEEE80211_DEBUG_DROP("Decryption failed (not set)" - " (SA=" MAC_FMT ")\n", - hdr->addr2[0], hdr->addr2[1], - hdr->addr2[2], hdr->addr2[3], - hdr->addr2[4], hdr->addr2[5]); + " (SA=%pM)\n", hdr->addr2); ieee->ieee_stats.rx_discards_undecryptable++; goto rx_dropped; } @@ -482,10 +471,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, fc & IEEE80211_FCTL_PROTECTED && ieee->host_decrypt && (keyidx = hostap_rx_frame_decrypt(ieee, skb, crypt)) < 0) { printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth " - "from " MAC_FMT "\n", dev->name, - hdr->addr2[0], hdr->addr2[1], - hdr->addr2[2], hdr->addr2[3], - hdr->addr2[4], hdr->addr2[5]); + "from %pM\n", dev->name, hdr->addr2); /* TODO: could inform hostapd about this so that it * could send auth failure report */ goto rx_dropped; @@ -547,8 +533,6 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, } #endif - dev->last_rx = jiffies; - #ifdef NOT_YET if ((ieee->iw_mode == IW_MODE_MASTER || ieee->iw_mode == IW_MODE_REPEAT) && !from_assoc_ap) { @@ -663,11 +647,8 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, * configured */ } else { IEEE80211_DEBUG_DROP("encryption configured, but RX " - "frame not encrypted (SA=" - MAC_FMT ")\n", - hdr->addr2[0], hdr->addr2[1], - hdr->addr2[2], hdr->addr2[3], - hdr->addr2[4], hdr->addr2[5]); + "frame not encrypted (SA=%pM)\n", + hdr->addr2); goto rx_dropped; } } @@ -675,11 +656,8 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !ieee->open_wep && !ieee80211_is_eapol_frame(ieee, skb)) { IEEE80211_DEBUG_DROP("dropped unencrypted RX data " - "frame from " MAC_FMT - " (drop_unencrypted=1)\n", - hdr->addr2[0], hdr->addr2[1], - hdr->addr2[2], hdr->addr2[3], - hdr->addr2[4], hdr->addr2[5]); + "frame from %pM (drop_unencrypted=1)\n", + hdr->addr2); goto rx_dropped; } @@ -1144,6 +1122,7 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element *info_element, u16 length, struct ieee80211_network *network) { + DECLARE_SSID_BUF(ssid); u8 i; #ifdef CONFIG_IEEE80211_DEBUG char rates_str[64]; @@ -1166,12 +1145,6 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element switch (info_element->id) { case MFIE_TYPE_SSID: - if (ieee80211_is_empty_essid(info_element->data, - info_element->len)) { - network->flags |= NETWORK_EMPTY_ESSID; - break; - } - network->ssid_len = min(info_element->len, (u8) IW_ESSID_MAX_SIZE); memcpy(network->ssid, info_element->data, @@ -1181,7 +1154,9 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element IW_ESSID_MAX_SIZE - network->ssid_len); IEEE80211_DEBUG_MGMT("MFIE_TYPE_SSID: '%s' len=%d.\n", - network->ssid, network->ssid_len); + print_ssid(ssid, network->ssid, + network->ssid_len), + network->ssid_len); break; case MFIE_TYPE_RATES: @@ -1411,9 +1386,6 @@ static int ieee80211_handle_assoc_resp(struct ieee80211_device *ieee, struct iee network->mode |= IEEE_B; } - if (ieee80211_is_empty_essid(network->ssid, network->ssid_len)) - network->flags |= NETWORK_EMPTY_ESSID; - memcpy(&network->stats, stats, sizeof(network->stats)); if (ieee->handle_assoc_response != NULL) @@ -1429,7 +1401,7 @@ static int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee8021 struct ieee80211_network *network, struct ieee80211_rx_stats *stats) { - DECLARE_MAC_BUF(mac); + DECLARE_SSID_BUF(ssid); network->qos_data.active = 0; network->qos_data.supported = 0; @@ -1477,17 +1449,14 @@ static int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee8021 } if (network->mode == 0) { - IEEE80211_DEBUG_SCAN("Filtered out '%s (%s)' " + IEEE80211_DEBUG_SCAN("Filtered out '%s (%pM)' " "network.\n", - escape_essid(network->ssid, - network->ssid_len), - print_mac(mac, network->bssid)); + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); return 1; } - if (ieee80211_is_empty_essid(network->ssid, network->ssid_len)) - network->flags |= NETWORK_EMPTY_ESSID; - memcpy(&network->stats, stats, sizeof(network->stats)); return 0; @@ -1510,7 +1479,6 @@ static void update_network(struct ieee80211_network *dst, { int qos_active; u8 old_param; - DECLARE_MAC_BUF(mac); ieee80211_network_reset(dst); dst->ibss_dfs = src->ibss_dfs; @@ -1524,8 +1492,8 @@ static void update_network(struct ieee80211_network *dst, memcpy(&dst->stats, &src->stats, sizeof(struct ieee80211_rx_stats)); else - IEEE80211_DEBUG_SCAN("Network %s info received " - "off channel (%d vs. %d)\n", print_mac(mac, src->bssid), + IEEE80211_DEBUG_SCAN("Network %pM info received " + "off channel (%d vs. %d)\n", src->bssid, dst->channel, src->stats.received_channel); dst->capability = src->capability; @@ -1597,12 +1565,12 @@ static void ieee80211_process_probe_response(struct ieee80211_device struct ieee80211_info_element *info_element = beacon->info_element; #endif unsigned long flags; - DECLARE_MAC_BUF(mac); + DECLARE_SSID_BUF(ssid); - IEEE80211_DEBUG_SCAN("'%s' (%s" + IEEE80211_DEBUG_SCAN("'%s' (%pM" "): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n", - escape_essid(info_element->data, info_element->len), - print_mac(mac, beacon->header.addr3), + print_ssid(ssid, info_element->data, info_element->len), + beacon->header.addr3, (beacon->capability & cpu_to_le16(1 << 0xf)) ? '1' : '0', (beacon->capability & cpu_to_le16(1 << 0xe)) ? '1' : '0', (beacon->capability & cpu_to_le16(1 << 0xd)) ? '1' : '0', @@ -1621,10 +1589,10 @@ static void ieee80211_process_probe_response(struct ieee80211_device (beacon->capability & cpu_to_le16(1 << 0x0)) ? '1' : '0'); if (ieee80211_network_init(ieee, beacon, &network, stats)) { - IEEE80211_DEBUG_SCAN("Dropped '%s' (%s) via %s.\n", - escape_essid(info_element->data, - info_element->len), - print_mac(mac, beacon->header.addr3), + IEEE80211_DEBUG_SCAN("Dropped '%s' (%pM) via %s.\n", + print_ssid(ssid, info_element->data, + info_element->len), + beacon->header.addr3, is_beacon(beacon->header.frame_ctl) ? "BEACON" : "PROBE RESPONSE"); return; @@ -1658,11 +1626,11 @@ static void ieee80211_process_probe_response(struct ieee80211_device /* If there are no more slots, expire the oldest */ list_del(&oldest->list); target = oldest; - IEEE80211_DEBUG_SCAN("Expired '%s' (%s) from " + IEEE80211_DEBUG_SCAN("Expired '%s' (%pM) from " "network list.\n", - escape_essid(target->ssid, - target->ssid_len), - print_mac(mac, target->bssid)); + print_ssid(ssid, target->ssid, + target->ssid_len), + target->bssid); ieee80211_network_reset(target); } else { /* Otherwise just pull from the free list */ @@ -1672,10 +1640,10 @@ static void ieee80211_process_probe_response(struct ieee80211_device } #ifdef CONFIG_IEEE80211_DEBUG - IEEE80211_DEBUG_SCAN("Adding '%s' (%s) via %s.\n", - escape_essid(network.ssid, - network.ssid_len), - print_mac(mac, network.bssid), + IEEE80211_DEBUG_SCAN("Adding '%s' (%pM) via %s.\n", + print_ssid(ssid, network.ssid, + network.ssid_len), + network.bssid, is_beacon(beacon->header.frame_ctl) ? "BEACON" : "PROBE RESPONSE"); #endif @@ -1683,10 +1651,10 @@ static void ieee80211_process_probe_response(struct ieee80211_device network.ibss_dfs = NULL; list_add_tail(&target->list, &ieee->network_list); } else { - IEEE80211_DEBUG_SCAN("Updating '%s' (%s) via %s.\n", - escape_essid(target->ssid, - target->ssid_len), - print_mac(mac, target->bssid), + IEEE80211_DEBUG_SCAN("Updating '%s' (%pM) via %s.\n", + print_ssid(ssid, target->ssid, + target->ssid_len), + target->bssid, is_beacon(beacon->header.frame_ctl) ? "BEACON" : "PROBE RESPONSE"); update_network(target, &network); diff --git a/net/ieee80211/ieee80211_tx.c b/drivers/net/wireless/ipw2x00/libipw_tx.c similarity index 98% rename from net/ieee80211/ieee80211_tx.c rename to drivers/net/wireless/ipw2x00/libipw_tx.c index d996547f7a629564aeb4fb99164054a41165c746..f78f57e8844a9c1eb2d08bbc9b3f4ba6a66b9b94 100644 --- a/net/ieee80211/ieee80211_tx.c +++ b/drivers/net/wireless/ipw2x00/libipw_tx.c @@ -152,7 +152,8 @@ static int ieee80211_copy_snap(u8 * data, __be16 h_proto) static int ieee80211_encrypt_fragment(struct ieee80211_device *ieee, struct sk_buff *frag, int hdr_len) { - struct ieee80211_crypt_data *crypt = ieee->crypt[ieee->tx_keyidx]; + struct lib80211_crypt_data *crypt = + ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx]; int res; if (crypt == NULL) @@ -270,7 +271,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) .qos_ctl = 0 }; u8 dest[ETH_ALEN], src[ETH_ALEN]; - struct ieee80211_crypt_data *crypt; + struct lib80211_crypt_data *crypt; int priority = skb->priority; int snapped = 0; @@ -294,7 +295,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) ether_type = ((struct ethhdr *)skb->data)->h_proto; - crypt = ieee->crypt[ieee->tx_keyidx]; + crypt = ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx]; encrypt = !(ether_type == htons(ETH_P_PAE) && ieee->ieee802_1x) && ieee->sec.encrypt; diff --git a/net/ieee80211/ieee80211_wx.c b/drivers/net/wireless/ipw2x00/libipw_wx.c similarity index 91% rename from net/ieee80211/ieee80211_wx.c rename to drivers/net/wireless/ipw2x00/libipw_wx.c index 973832dd7faf6a56c189290f89a1d33e87184871..31ea3abfc3277cb672d930007992dd504276186e 100644 --- a/net/ieee80211/ieee80211_wx.c +++ b/drivers/net/wireless/ipw2x00/libipw_wx.c @@ -34,6 +34,7 @@ #include #include +#include #include #include @@ -65,15 +66,9 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, /* Add the ESSID */ iwe.cmd = SIOCGIWESSID; iwe.u.data.flags = 1; - if (network->flags & NETWORK_EMPTY_ESSID) { - iwe.u.data.length = sizeof(""); - start = iwe_stream_add_point(info, start, stop, - &iwe, ""); - } else { - iwe.u.data.length = min(network->ssid_len, (u8) 32); - start = iwe_stream_add_point(info, start, stop, - &iwe, network->ssid); - } + iwe.u.data.length = min(network->ssid_len, (u8) 32); + start = iwe_stream_add_point(info, start, stop, + &iwe, network->ssid); /* Add the protocol name */ iwe.cmd = SIOCGIWNAME; @@ -264,7 +259,7 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee, char *ev = extra; char *stop = ev + wrqu->data.length; int i = 0; - DECLARE_MAC_BUF(mac); + DECLARE_SSID_BUF(ssid); IEEE80211_DEBUG_WX("Getting scan\n"); @@ -283,10 +278,10 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee, info); else IEEE80211_DEBUG_SCAN("Not showing network '%s (" - "%s)' due to age (%dms).\n", - escape_essid(network->ssid, - network->ssid_len), - print_mac(mac, network->bssid), + "%pM)' due to age (%dms).\n", + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid, jiffies_to_msecs(jiffies - network-> last_scanned)); @@ -312,8 +307,9 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, .flags = 0 }; int i, key, key_provided, len; - struct ieee80211_crypt_data **crypt; + struct lib80211_crypt_data **crypt; int host_crypto = ieee->host_encrypt || ieee->host_decrypt || ieee->host_build_iv; + DECLARE_SSID_BUF(ssid); IEEE80211_DEBUG_WX("SET_ENCODE\n"); @@ -325,30 +321,30 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, key_provided = 1; } else { key_provided = 0; - key = ieee->tx_keyidx; + key = ieee->crypt_info.tx_keyidx; } IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ? "provided" : "default"); - crypt = &ieee->crypt[key]; + crypt = &ieee->crypt_info.crypt[key]; if (erq->flags & IW_ENCODE_DISABLED) { if (key_provided && *crypt) { IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n", key); - ieee80211_crypt_delayed_deinit(ieee, crypt); + lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); } else IEEE80211_DEBUG_WX("Disabling encryption.\n"); /* Check all the keys to see if any are still configured, * and if no key index was provided, de-init them all */ for (i = 0; i < WEP_KEYS; i++) { - if (ieee->crypt[i] != NULL) { + if (ieee->crypt_info.crypt[i] != NULL) { if (key_provided) break; - ieee80211_crypt_delayed_deinit(ieee, - &ieee->crypt[i]); + lib80211_crypt_delayed_deinit(&ieee->crypt_info, + &ieee->crypt_info.crypt[i]); } } @@ -370,21 +366,21 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, strcmp((*crypt)->ops->name, "WEP") != 0) { /* changing to use WEP; deinit previously used algorithm * on this key */ - ieee80211_crypt_delayed_deinit(ieee, crypt); + lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); } if (*crypt == NULL && host_crypto) { - struct ieee80211_crypt_data *new_crypt; + struct lib80211_crypt_data *new_crypt; /* take WEP into use */ - new_crypt = kzalloc(sizeof(struct ieee80211_crypt_data), + new_crypt = kzalloc(sizeof(struct lib80211_crypt_data), GFP_KERNEL); if (new_crypt == NULL) return -ENOMEM; - new_crypt->ops = ieee80211_get_crypto_ops("WEP"); + new_crypt->ops = lib80211_get_crypto_ops("WEP"); if (!new_crypt->ops) { - request_module("ieee80211_crypt_wep"); - new_crypt->ops = ieee80211_get_crypto_ops("WEP"); + request_module("lib80211_crypt_wep"); + new_crypt->ops = lib80211_get_crypto_ops("WEP"); } if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) @@ -395,7 +391,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, new_crypt = NULL; printk(KERN_WARNING "%s: could not initialize WEP: " - "load module ieee80211_crypt_wep\n", dev->name); + "load module lib80211_crypt_wep\n", dev->name); return -EOPNOTSUPP; } *crypt = new_crypt; @@ -403,13 +399,17 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, /* If a new key was provided, set it up */ if (erq->length > 0) { +#ifdef CONFIG_IEEE80211_DEBUG + DECLARE_SSID_BUF(ssid); +#endif + len = erq->length <= 5 ? 5 : 13; memcpy(sec.keys[key], keybuf, erq->length); if (len > erq->length) memset(sec.keys[key] + erq->length, 0, len - erq->length); IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n", - key, escape_essid(sec.keys[key], len), + key, print_ssid(ssid, sec.keys[key], len), erq->length, len); sec.key_sizes[key] = len; if (*crypt) @@ -440,7 +440,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, if (key_provided) { IEEE80211_DEBUG_WX("Setting key %d to default Tx " "key.\n", key); - ieee->tx_keyidx = key; + ieee->crypt_info.tx_keyidx = key; sec.active_key = key; sec.flags |= SEC_ACTIVE_KEY; } @@ -485,7 +485,7 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee, { struct iw_point *erq = &(wrqu->encoding); int len, key; - struct ieee80211_crypt_data *crypt; + struct lib80211_crypt_data *crypt; struct ieee80211_security *sec = &ieee->sec; IEEE80211_DEBUG_WX("GET_ENCODE\n"); @@ -496,9 +496,9 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee, return -EINVAL; key--; } else - key = ieee->tx_keyidx; + key = ieee->crypt_info.tx_keyidx; - crypt = ieee->crypt[key]; + crypt = ieee->crypt_info.crypt[key]; erq->flags = key + 1; if (!sec->enabled) { @@ -531,8 +531,8 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, int i, idx, ret = 0; int group_key = 0; const char *alg, *module; - struct ieee80211_crypto_ops *ops; - struct ieee80211_crypt_data **crypt; + struct lib80211_crypto_ops *ops; + struct lib80211_crypt_data **crypt; struct ieee80211_security sec = { .flags = 0, @@ -544,17 +544,17 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, return -EINVAL; idx--; } else - idx = ieee->tx_keyidx; + idx = ieee->crypt_info.tx_keyidx; if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { - crypt = &ieee->crypt[idx]; + crypt = &ieee->crypt_info.crypt[idx]; group_key = 1; } else { /* some Cisco APs use idx>0 for unicast in dynamic WEP */ if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP) return -EINVAL; if (ieee->iw_mode == IW_MODE_INFRA) - crypt = &ieee->crypt[idx]; + crypt = &ieee->crypt_info.crypt[idx]; else return -EINVAL; } @@ -563,10 +563,10 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, if ((encoding->flags & IW_ENCODE_DISABLED) || ext->alg == IW_ENCODE_ALG_NONE) { if (*crypt) - ieee80211_crypt_delayed_deinit(ieee, crypt); + lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); for (i = 0; i < WEP_KEYS; i++) - if (ieee->crypt[i] != NULL) + if (ieee->crypt_info.crypt[i] != NULL) break; if (i == WEP_KEYS) { @@ -589,15 +589,15 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, switch (ext->alg) { case IW_ENCODE_ALG_WEP: alg = "WEP"; - module = "ieee80211_crypt_wep"; + module = "lib80211_crypt_wep"; break; case IW_ENCODE_ALG_TKIP: alg = "TKIP"; - module = "ieee80211_crypt_tkip"; + module = "lib80211_crypt_tkip"; break; case IW_ENCODE_ALG_CCMP: alg = "CCMP"; - module = "ieee80211_crypt_ccmp"; + module = "lib80211_crypt_ccmp"; break; default: IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", @@ -606,10 +606,10 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, goto done; } - ops = ieee80211_get_crypto_ops(alg); + ops = lib80211_get_crypto_ops(alg); if (ops == NULL) { request_module(module); - ops = ieee80211_get_crypto_ops(alg); + ops = lib80211_get_crypto_ops(alg); } if (ops == NULL) { IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", @@ -619,9 +619,9 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, } if (*crypt == NULL || (*crypt)->ops != ops) { - struct ieee80211_crypt_data *new_crypt; + struct lib80211_crypt_data *new_crypt; - ieee80211_crypt_delayed_deinit(ieee, crypt); + lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL); if (new_crypt == NULL) { @@ -649,7 +649,7 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, skip_host_crypt: if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { - ieee->tx_keyidx = idx; + ieee->crypt_info.tx_keyidx = idx; sec.active_key = idx; sec.flags |= SEC_ACTIVE_KEY; } @@ -715,7 +715,7 @@ int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee, return -EINVAL; idx--; } else - idx = ieee->tx_keyidx; + idx = ieee->crypt_info.tx_keyidx; if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) && ext->alg != IW_ENCODE_ALG_WEP) diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index b0ac0ce3fb9f6dfb4c8d126ded42f4621d9e2877..47bee0ee0a7c3b1a040f477f450a2ecd4692e4ee 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -4,6 +4,7 @@ config IWLWIFI config IWLCORE tristate "Intel Wireless Wifi Core" depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL + select LIB80211 select IWLWIFI select MAC80211_LEDS if IWLWIFI_LEDS select LEDS_CLASS if IWLWIFI_LEDS @@ -105,6 +106,7 @@ config IWL3945 tristate "Intel PRO/Wireless 3945ABG/BG Network Connection" depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL select FW_LOADER + select LIB80211 select IWLWIFI select MAC80211_LEDS if IWL3945_LEDS select LEDS_CLASS if IWL3945_LEDS diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 47aa28f6a5138993a7ad4d82000c8d50917f2c6f..0be9e6b66aa0f0187b8072dbf1c5879b0b3f8b58 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -5,9 +5,10 @@ iwlcore-objs += iwl-scan.o iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o iwlcore-$(CONFIG_IWLWIFI_LEDS) += iwl-led.o iwlcore-$(CONFIG_IWLWIFI_RFKILL) += iwl-rfkill.o +iwlcore-$(CONFIG_IWLAGN_SPECTRUM_MEASUREMENT) += iwl-spectrum.o obj-$(CONFIG_IWLAGN) += iwlagn.o -iwlagn-objs := iwl-agn.o iwl-agn-rs.o +iwlagn-objs := iwl-agn.o iwl-agn-rs.o iwl-agn-hcmd-check.o iwlagn-$(CONFIG_IWL4965) += iwl-4965.o iwlagn-$(CONFIG_IWL5000) += iwl-5000.o diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-commands.h b/drivers/net/wireless/iwlwifi/iwl-3945-commands.h index 817ece7736434f9645749c2e12940aca11f1106a..c6f4eb54a2b1d6d2fe0a6a88932a4ad06725527b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-commands.h @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -69,6 +69,12 @@ #ifndef __iwl_3945_commands_h__ #define __iwl_3945_commands_h__ +/* uCode version contains 4 values: Major/Minor/API/Serial */ +#define IWL_UCODE_MAJOR(ver) (((ver) & 0xFF000000) >> 24) +#define IWL_UCODE_MINOR(ver) (((ver) & 0x00FF0000) >> 16) +#define IWL_UCODE_API(ver) (((ver) & 0x0000FF00) >> 8) +#define IWL_UCODE_SERIAL(ver) ((ver) & 0x000000FF) + enum { REPLY_ALIVE = 0x1, REPLY_ERROR = 0x2, @@ -121,7 +127,7 @@ enum { REPLY_TX_PWR_TABLE_CMD = 0x97, MEASURE_ABORT_NOTIFICATION = 0x99, /* not used */ - /* Bluetooth device coexistance config command */ + /* Bluetooth device coexistence config command */ REPLY_BT_CONFIG = 0x9b, /* Statistics */ @@ -158,7 +164,7 @@ struct iwl3945_cmd_header { u8 cmd; /* Command ID: REPLY_RXON, etc. */ u8 flags; /* IWL_CMD_* */ /* - * The driver sets up the sequence number to values of its chosing. + * The driver sets up the sequence number to values of its choosing. * uCode does not use this value, but passes it back to the driver * when sending the response to each driver-originated command, so * the driver can match the response to the command. Since the values @@ -220,7 +226,7 @@ struct iwl3945_power_per_rate { * *****************************************************************************/ -#define UCODE_VALID_OK __constant_cpu_to_le32(0x1) +#define UCODE_VALID_OK cpu_to_le32(0x1) #define INITIALIZE_SUBTYPE (9) /* @@ -322,42 +328,42 @@ enum { /* rx_config flags */ /* band & modulation selection */ -#define RXON_FLG_BAND_24G_MSK __constant_cpu_to_le32(1 << 0) -#define RXON_FLG_CCK_MSK __constant_cpu_to_le32(1 << 1) +#define RXON_FLG_BAND_24G_MSK cpu_to_le32(1 << 0) +#define RXON_FLG_CCK_MSK cpu_to_le32(1 << 1) /* auto detection enable */ -#define RXON_FLG_AUTO_DETECT_MSK __constant_cpu_to_le32(1 << 2) +#define RXON_FLG_AUTO_DETECT_MSK cpu_to_le32(1 << 2) /* TGg protection when tx */ -#define RXON_FLG_TGG_PROTECT_MSK __constant_cpu_to_le32(1 << 3) +#define RXON_FLG_TGG_PROTECT_MSK cpu_to_le32(1 << 3) /* cck short slot & preamble */ -#define RXON_FLG_SHORT_SLOT_MSK __constant_cpu_to_le32(1 << 4) -#define RXON_FLG_SHORT_PREAMBLE_MSK __constant_cpu_to_le32(1 << 5) +#define RXON_FLG_SHORT_SLOT_MSK cpu_to_le32(1 << 4) +#define RXON_FLG_SHORT_PREAMBLE_MSK cpu_to_le32(1 << 5) /* antenna selection */ -#define RXON_FLG_DIS_DIV_MSK __constant_cpu_to_le32(1 << 7) -#define RXON_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0x0f00) -#define RXON_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8) -#define RXON_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9) +#define RXON_FLG_DIS_DIV_MSK cpu_to_le32(1 << 7) +#define RXON_FLG_ANT_SEL_MSK cpu_to_le32(0x0f00) +#define RXON_FLG_ANT_A_MSK cpu_to_le32(1 << 8) +#define RXON_FLG_ANT_B_MSK cpu_to_le32(1 << 9) /* radar detection enable */ -#define RXON_FLG_RADAR_DETECT_MSK __constant_cpu_to_le32(1 << 12) -#define RXON_FLG_TGJ_NARROW_BAND_MSK __constant_cpu_to_le32(1 << 13) +#define RXON_FLG_RADAR_DETECT_MSK cpu_to_le32(1 << 12) +#define RXON_FLG_TGJ_NARROW_BAND_MSK cpu_to_le32(1 << 13) /* rx response to host with 8-byte TSF * (according to ON_AIR deassertion) */ -#define RXON_FLG_TSF2HOST_MSK __constant_cpu_to_le32(1 << 15) +#define RXON_FLG_TSF2HOST_MSK cpu_to_le32(1 << 15) /* rx_config filter flags */ /* accept all data frames */ -#define RXON_FILTER_PROMISC_MSK __constant_cpu_to_le32(1 << 0) +#define RXON_FILTER_PROMISC_MSK cpu_to_le32(1 << 0) /* pass control & management to host */ -#define RXON_FILTER_CTL2HOST_MSK __constant_cpu_to_le32(1 << 1) +#define RXON_FILTER_CTL2HOST_MSK cpu_to_le32(1 << 1) /* accept multi-cast */ -#define RXON_FILTER_ACCEPT_GRP_MSK __constant_cpu_to_le32(1 << 2) +#define RXON_FILTER_ACCEPT_GRP_MSK cpu_to_le32(1 << 2) /* don't decrypt uni-cast frames */ -#define RXON_FILTER_DIS_DECRYPT_MSK __constant_cpu_to_le32(1 << 3) +#define RXON_FILTER_DIS_DECRYPT_MSK cpu_to_le32(1 << 3) /* don't decrypt multi-cast frames */ -#define RXON_FILTER_DIS_GRP_DECRYPT_MSK __constant_cpu_to_le32(1 << 4) +#define RXON_FILTER_DIS_GRP_DECRYPT_MSK cpu_to_le32(1 << 4) /* STA is associated */ -#define RXON_FILTER_ASSOC_MSK __constant_cpu_to_le32(1 << 5) +#define RXON_FILTER_ASSOC_MSK cpu_to_le32(1 << 5) /* transfer to host non bssid beacons in associated state */ -#define RXON_FILTER_BCON_AWARE_MSK __constant_cpu_to_le32(1 << 6) +#define RXON_FILTER_BCON_AWARE_MSK cpu_to_le32(1 << 6) /** * REPLY_RXON = 0x10 (command, has simple generic response) @@ -471,9 +477,9 @@ struct iwl3945_ac_qos { } __attribute__ ((packed)); /* QoS flags defines */ -#define QOS_PARAM_FLG_UPDATE_EDCA_MSK __constant_cpu_to_le32(0x01) -#define QOS_PARAM_FLG_TGN_MSK __constant_cpu_to_le32(0x02) -#define QOS_PARAM_FLG_TXOP_TYPE_MSK __constant_cpu_to_le32(0x10) +#define QOS_PARAM_FLG_UPDATE_EDCA_MSK cpu_to_le32(0x01) +#define QOS_PARAM_FLG_TGN_MSK cpu_to_le32(0x02) +#define QOS_PARAM_FLG_TXOP_TYPE_MSK cpu_to_le32(0x10) /* Number of Access Categories (AC) (EDCA), queues 0..3 */ #define AC_NUM 4 @@ -508,27 +514,27 @@ struct iwl3945_qosparam_cmd { #define IWL_STATION_COUNT 32 /* MAX(3945,4965)*/ #define IWL_INVALID_STATION 255 -#define STA_FLG_TX_RATE_MSK __constant_cpu_to_le32(1 << 2); -#define STA_FLG_PWR_SAVE_MSK __constant_cpu_to_le32(1 << 8); +#define STA_FLG_TX_RATE_MSK cpu_to_le32(1 << 2); +#define STA_FLG_PWR_SAVE_MSK cpu_to_le32(1 << 8); /* Use in mode field. 1: modify existing entry, 0: add new station entry */ #define STA_CONTROL_MODIFY_MSK 0x01 /* key flags __le16*/ -#define STA_KEY_FLG_ENCRYPT_MSK __constant_cpu_to_le16(0x0007) -#define STA_KEY_FLG_NO_ENC __constant_cpu_to_le16(0x0000) -#define STA_KEY_FLG_WEP __constant_cpu_to_le16(0x0001) -#define STA_KEY_FLG_CCMP __constant_cpu_to_le16(0x0002) -#define STA_KEY_FLG_TKIP __constant_cpu_to_le16(0x0003) +#define STA_KEY_FLG_ENCRYPT_MSK cpu_to_le16(0x0007) +#define STA_KEY_FLG_NO_ENC cpu_to_le16(0x0000) +#define STA_KEY_FLG_WEP cpu_to_le16(0x0001) +#define STA_KEY_FLG_CCMP cpu_to_le16(0x0002) +#define STA_KEY_FLG_TKIP cpu_to_le16(0x0003) #define STA_KEY_FLG_KEYID_POS 8 -#define STA_KEY_FLG_INVALID __constant_cpu_to_le16(0x0800) +#define STA_KEY_FLG_INVALID cpu_to_le16(0x0800) /* wep key is either from global key (0) or from station info array (1) */ -#define STA_KEY_FLG_WEP_KEY_MAP_MSK __constant_cpu_to_le16(0x0008) +#define STA_KEY_FLG_WEP_KEY_MAP_MSK cpu_to_le16(0x0008) /* wep key in STA: 5-bytes (0) or 13-bytes (1) */ -#define STA_KEY_FLG_KEY_SIZE_MSK __constant_cpu_to_le16(0x1000) -#define STA_KEY_MULTICAST_MSK __constant_cpu_to_le16(0x4000) +#define STA_KEY_FLG_KEY_SIZE_MSK cpu_to_le16(0x1000) +#define STA_KEY_MULTICAST_MSK cpu_to_le16(0x4000) /* Flags indicate whether to modify vs. don't change various station params */ #define STA_MODIFY_KEY_MASK 0x01 @@ -666,14 +672,14 @@ struct iwl3945_rx_frame_hdr { u8 payload[0]; } __attribute__ ((packed)); -#define RX_RES_STATUS_NO_CRC32_ERROR __constant_cpu_to_le32(1 << 0) -#define RX_RES_STATUS_NO_RXE_OVERFLOW __constant_cpu_to_le32(1 << 1) +#define RX_RES_STATUS_NO_CRC32_ERROR cpu_to_le32(1 << 0) +#define RX_RES_STATUS_NO_RXE_OVERFLOW cpu_to_le32(1 << 1) -#define RX_RES_PHY_FLAGS_BAND_24_MSK __constant_cpu_to_le16(1 << 0) -#define RX_RES_PHY_FLAGS_MOD_CCK_MSK __constant_cpu_to_le16(1 << 1) -#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK __constant_cpu_to_le16(1 << 2) -#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK __constant_cpu_to_le16(1 << 3) -#define RX_RES_PHY_FLAGS_ANTENNA_MSK __constant_cpu_to_le16(0xf0) +#define RX_RES_PHY_FLAGS_BAND_24_MSK cpu_to_le16(1 << 0) +#define RX_RES_PHY_FLAGS_MOD_CCK_MSK cpu_to_le16(1 << 1) +#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK cpu_to_le16(1 << 2) +#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK cpu_to_le16(1 << 3) +#define RX_RES_PHY_FLAGS_ANTENNA_MSK cpu_to_le16(0xf0) #define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8) #define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8) @@ -733,57 +739,57 @@ struct iwl3945_rx_frame { /* 1: Use Request-To-Send protocol before this frame. * Mutually exclusive vs. TX_CMD_FLG_CTS_MSK. */ -#define TX_CMD_FLG_RTS_MSK __constant_cpu_to_le32(1 << 1) +#define TX_CMD_FLG_RTS_MSK cpu_to_le32(1 << 1) /* 1: Transmit Clear-To-Send to self before this frame. * Driver should set this for AUTH/DEAUTH/ASSOC-REQ/REASSOC mgmnt frames. * Mutually exclusive vs. TX_CMD_FLG_RTS_MSK. */ -#define TX_CMD_FLG_CTS_MSK __constant_cpu_to_le32(1 << 2) +#define TX_CMD_FLG_CTS_MSK cpu_to_le32(1 << 2) /* 1: Expect ACK from receiving station * 0: Don't expect ACK (MAC header's duration field s/b 0) * Set this for unicast frames, but not broadcast/multicast. */ -#define TX_CMD_FLG_ACK_MSK __constant_cpu_to_le32(1 << 3) +#define TX_CMD_FLG_ACK_MSK cpu_to_le32(1 << 3) /* 1: Use rate scale table (see REPLY_TX_LINK_QUALITY_CMD). * Tx command's initial_rate_index indicates first rate to try; * uCode walks through table for additional Tx attempts. * 0: Use Tx rate/MCS from Tx command's rate_n_flags field. * This rate will be used for all Tx attempts; it will not be scaled. */ -#define TX_CMD_FLG_STA_RATE_MSK __constant_cpu_to_le32(1 << 4) +#define TX_CMD_FLG_STA_RATE_MSK cpu_to_le32(1 << 4) /* 1: Expect immediate block-ack. * Set when Txing a block-ack request frame. Also set TX_CMD_FLG_ACK_MSK. */ -#define TX_CMD_FLG_IMM_BA_RSP_MASK __constant_cpu_to_le32(1 << 6) +#define TX_CMD_FLG_IMM_BA_RSP_MASK cpu_to_le32(1 << 6) /* 1: Frame requires full Tx-Op protection. * Set this if either RTS or CTS Tx Flag gets set. */ -#define TX_CMD_FLG_FULL_TXOP_PROT_MSK __constant_cpu_to_le32(1 << 7) +#define TX_CMD_FLG_FULL_TXOP_PROT_MSK cpu_to_le32(1 << 7) /* Tx antenna selection field; used only for 3945, reserved (0) for 4965. * Set field to "0" to allow 3945 uCode to select antenna (normal usage). */ -#define TX_CMD_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0xf00) -#define TX_CMD_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8) -#define TX_CMD_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9) +#define TX_CMD_FLG_ANT_SEL_MSK cpu_to_le32(0xf00) +#define TX_CMD_FLG_ANT_A_MSK cpu_to_le32(1 << 8) +#define TX_CMD_FLG_ANT_B_MSK cpu_to_le32(1 << 9) /* 1: Ignore Bluetooth priority for this frame. * 0: Delay Tx until Bluetooth device is done (normal usage). */ -#define TX_CMD_FLG_BT_DIS_MSK __constant_cpu_to_le32(1 << 12) +#define TX_CMD_FLG_BT_DIS_MSK cpu_to_le32(1 << 12) /* 1: uCode overrides sequence control field in MAC header. * 0: Driver provides sequence control field in MAC header. * Set this for management frames, non-QOS data frames, non-unicast frames, * and also in Tx command embedded in REPLY_SCAN_CMD for active scans. */ -#define TX_CMD_FLG_SEQ_CTL_MSK __constant_cpu_to_le32(1 << 13) +#define TX_CMD_FLG_SEQ_CTL_MSK cpu_to_le32(1 << 13) /* 1: This frame is non-last MPDU; more fragments are coming. * 0: Last fragment, or not using fragmentation. */ -#define TX_CMD_FLG_MORE_FRAG_MSK __constant_cpu_to_le32(1 << 14) +#define TX_CMD_FLG_MORE_FRAG_MSK cpu_to_le32(1 << 14) /* 1: uCode calculates and inserts Timestamp Function (TSF) in outgoing frame. * 0: No TSF required in outgoing frame. * Set this for transmitting beacons and probe responses. */ -#define TX_CMD_FLG_TSF_MSK __constant_cpu_to_le32(1 << 16) +#define TX_CMD_FLG_TSF_MSK cpu_to_le32(1 << 16) /* 1: Driver inserted 2 bytes pad after the MAC header, for (required) dword * alignment of frame's payload data field. @@ -791,10 +797,10 @@ struct iwl3945_rx_frame { * Set this for MAC headers with 26 or 30 bytes, i.e. those with QOS or ADDR4 * field (but not both). Driver must align frame data (i.e. data following * MAC header) to DWORD boundary. */ -#define TX_CMD_FLG_MH_PAD_MSK __constant_cpu_to_le32(1 << 20) +#define TX_CMD_FLG_MH_PAD_MSK cpu_to_le32(1 << 20) /* HCCA-AP - disable duration overwriting. */ -#define TX_CMD_FLG_DUR_MSK __constant_cpu_to_le32(1 << 25) +#define TX_CMD_FLG_DUR_MSK cpu_to_le32(1 << 25) /* * TX command security control @@ -991,7 +997,7 @@ struct iwl3945_rate_scaling_cmd { * * 3945 and 4965 support hardware handshake with Bluetooth device on * same platform. Bluetooth device alerts wireless device when it will Tx; - * wireless device can delay or kill its own Tx to accomodate. + * wireless device can delay or kill its own Tx to accommodate. */ struct iwl3945_bt_cmd { u8 flags; @@ -1158,9 +1164,9 @@ struct iwl3945_spectrum_notification { */ #define IWL_POWER_VEC_SIZE 5 -#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK __constant_cpu_to_le32(1 << 0) -#define IWL_POWER_SLEEP_OVER_DTIM_MSK __constant_cpu_to_le32(1 << 2) -#define IWL_POWER_PCI_PM_MSK __constant_cpu_to_le32(1 << 3) +#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK cpu_to_le32(1 << 0) +#define IWL_POWER_SLEEP_OVER_DTIM_MSK cpu_to_le32(1 << 2) +#define IWL_POWER_PCI_PM_MSK cpu_to_le32(1 << 3) struct iwl3945_powertable_cmd { __le32 flags; __le32 rx_data_timeout; @@ -1278,8 +1284,8 @@ struct iwl3945_ssid_ie { } __attribute__ ((packed)); #define PROBE_OPTION_MAX 0x4 -#define TX_CMD_LIFE_TIME_INFINITE __constant_cpu_to_le32(0xFFFFFFFF) -#define IWL_GOOD_CRC_TH __constant_cpu_to_le16(1) +#define TX_CMD_LIFE_TIME_INFINITE cpu_to_le32(0xFFFFFFFF) +#define IWL_GOOD_CRC_TH cpu_to_le16(1) #define IWL_MAX_SCAN_SIZE 1024 /* @@ -1379,7 +1385,7 @@ struct iwl3945_scan_cmd { } __attribute__ ((packed)); /* Can abort will notify by complete notification with abort status. */ -#define CAN_ABORT_STATUS __constant_cpu_to_le32(0x1) +#define CAN_ABORT_STATUS cpu_to_le32(0x1) /* complete notification statuses */ #define ABORT_STATUS 0x2 @@ -1572,8 +1578,8 @@ struct statistics_general { * STATISTICS_NOTIFICATIONs after received beacons (see below). This flag * does not affect the response to the REPLY_STATISTICS_CMD 0x9c itself. */ -#define IWL_STATS_CONF_CLEAR_STATS __constant_cpu_to_le32(0x1) /* see above */ -#define IWL_STATS_CONF_DISABLE_NOTIF __constant_cpu_to_le32(0x2)/* see above */ +#define IWL_STATS_CONF_CLEAR_STATS cpu_to_le32(0x1) /* see above */ +#define IWL_STATS_CONF_DISABLE_NOTIF cpu_to_le32(0x2)/* see above */ struct iwl3945_statistics_cmd { __le32 configuration_flags; /* IWL_STATS_CONF_* */ } __attribute__ ((packed)); @@ -1593,8 +1599,8 @@ struct iwl3945_statistics_cmd { * appropriately so that each notification contains statistics for only the * one channel that has just been scanned. */ -#define STATISTICS_REPLY_FLG_BAND_24G_MSK __constant_cpu_to_le32(0x2) -#define STATISTICS_REPLY_FLG_FAT_MODE_MSK __constant_cpu_to_le32(0x8) +#define STATISTICS_REPLY_FLG_BAND_24G_MSK cpu_to_le32(0x2) +#define STATISTICS_REPLY_FLG_FAT_MODE_MSK cpu_to_le32(0x8) struct iwl3945_notif_statistics { __le32 flag; struct statistics_rx rx; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-core.h b/drivers/net/wireless/iwlwifi/iwl-3945-core.h index bc12f97ba0b1d82ab9087900840ff640593861df..6f463555402c7bb1b751d1ec9846730efca355bc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-core.h @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * Tomas Winkler + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -71,9 +71,33 @@ #define IWL_SKU_G 0x1 #define IWL_SKU_A 0x2 +/** + * struct iwl_3945_cfg + * @fw_name_pre: Firmware filename prefix. The api version and extension + * (.ucode) will be added to filename before loading from disk. The + * filename is constructed as fw_name_pre.ucode. + * @ucode_api_max: Highest version of uCode API supported by driver. + * @ucode_api_min: Lowest version of uCode API supported by driver. + * + * We enable the driver to be backward compatible wrt API version. The + * driver specifies which APIs it supports (with @ucode_api_max being the + * highest and @ucode_api_min the lowest). Firmware will only be loaded if + * it has a supported API version. The firmware's API version will be + * stored in @iwl_priv, enabling the driver to make runtime changes based + * on firmware version used. + * + * For example, + * if (IWL_UCODE_API(priv->ucode_ver) >= 2) { + * Driver interacts with Firmware API version >= 2. + * } else { + * Driver interacts with Firmware API version 1. + * } + */ struct iwl_3945_cfg { const char *name; - const char *fw_name; + const char *fw_name_pre; + const unsigned int ucode_api_max; + const unsigned int ucode_api_min; unsigned int sku; }; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-debug.h b/drivers/net/wireless/iwlwifi/iwl-3945-debug.h index 33016fb5e9b3c01d3e0e9af04bf023b239bab0c4..85eb778f9df1e0232a6d6cf16509ac5ab59fa9b3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-debug.h @@ -21,7 +21,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h index 644bd9e0805217f2b399260a073487537f3de918..94ea0e60c41076d9d5fa6a656595bc4bbda57cf8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -103,7 +103,6 @@ * Driver reads 16-bit value from bits 31-16 of CSR_EEPROM_REG. */ #define IWL_EEPROM_ACCESS_TIMEOUT 5000 /* uSec */ -#define IWL_EEPROM_ACCESS_DELAY 10 /* uSec */ /* * Regulatory channel usage flags in EEPROM struct iwl_eeprom_channel.flags. @@ -321,6 +320,7 @@ struct iwl3945_eeprom { /* RSSR */ #define FH_RSSR_CTRL (FH_RSSR_TABLE+0x000) #define FH_RSSR_STATUS (FH_RSSR_TABLE+0x004) +#define FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE (0x01000000) /* TCSR */ #define FH_TCSR(_channel) (FH_TCSR_TABLE+(_channel)*0x20) #define FH_TCSR_CONFIG(_channel) (FH_TCSR(_channel)+0x00) diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-io.h b/drivers/net/wireless/iwlwifi/iwl-3945-io.h index b3fe48de3ae7b819d17bffd7cd7d01013cd632b1..2440fd664dd59ad4dc88808d5f320c43b4c2b9c4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-io.h @@ -21,7 +21,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -53,7 +53,7 @@ * _iwl3945_read32.) * * These declarations are *extremely* useful in quickly isolating code deltas - * which result in misconfiguring of the hardware I/O. In combination with + * which result in misconfiguration of the hardware I/O. In combination with * git-bisect and the IO debug level you can quickly determine the specific * commit which breaks the IO sequence to the hardware. * @@ -93,7 +93,7 @@ static inline int _iwl3945_poll_bit(struct iwl3945_priv *priv, u32 addr, do { if ((_iwl3945_read32(priv, addr) & mask) == (bits & mask)) return i; - mdelay(10); + udelay(10); i += 10; } while (i < timeout); @@ -107,7 +107,7 @@ static inline int __iwl3945_poll_bit(const char *f, u32 l, int ret = _iwl3945_poll_bit(priv, addr, bits, mask, timeout); IWL_DEBUG_IO("poll_bit(0x%08X, 0x%08X, 0x%08X) - %s- %s %d\n", addr, bits, mask, - unlikely(ret == -ETIMEDOUT)?"timeout":"", f, l); + unlikely(ret == -ETIMEDOUT) ? "timeout" : "", f, l); return ret; } #define iwl3945_poll_bit(priv, addr, bits, mask, timeout) \ @@ -271,16 +271,7 @@ static inline void iwl3945_write_reg_buf(struct iwl3945_priv *priv, static inline int _iwl3945_poll_direct_bit(struct iwl3945_priv *priv, u32 addr, u32 mask, int timeout) { - int i = 0; - - do { - if ((_iwl3945_read_direct32(priv, addr) & mask) == mask) - return i; - mdelay(10); - i += 10; - } while (i < timeout); - - return -ETIMEDOUT; + return _iwl3945_poll_bit(priv, addr, mask, mask, timeout); } #ifdef CONFIG_IWL3945_DEBUG @@ -307,6 +298,7 @@ static inline int __iwl3945_poll_direct_bit(const char *f, u32 l, static inline u32 _iwl3945_read_prph(struct iwl3945_priv *priv, u32 reg) { _iwl3945_write_direct32(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24)); + rmb(); return _iwl3945_read_direct32(priv, HBUS_TARG_PRPH_RDAT); } #ifdef CONFIG_IWL3945_DEBUG @@ -328,6 +320,7 @@ static inline void _iwl3945_write_prph(struct iwl3945_priv *priv, { _iwl3945_write_direct32(priv, HBUS_TARG_PRPH_WADDR, ((addr & 0x0000FFFF) | (3 << 24))); + wmb(); _iwl3945_write_direct32(priv, HBUS_TARG_PRPH_WDAT, val); } #ifdef CONFIG_IWL3945_DEBUG @@ -389,12 +382,14 @@ static inline void iwl3945_clear_bits_prph(struct iwl3945_priv static inline u32 iwl3945_read_targ_mem(struct iwl3945_priv *priv, u32 addr) { iwl3945_write_direct32(priv, HBUS_TARG_MEM_RADDR, addr); + rmb(); return iwl3945_read_direct32(priv, HBUS_TARG_MEM_RDAT); } static inline void iwl3945_write_targ_mem(struct iwl3945_priv *priv, u32 addr, u32 val) { iwl3945_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); + wmb(); iwl3945_write_direct32(priv, HBUS_TARG_MEM_WDAT, val); } @@ -402,6 +397,7 @@ static inline void iwl3945_write_targ_mem_buf(struct iwl3945_priv *priv, u32 add u32 len, u32 *values) { iwl3945_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); + wmb(); for (; 0 < len; len -= sizeof(u32), values++) iwl3945_write_direct32(priv, HBUS_TARG_MEM_WDAT, *values); } diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c index 705c65bed9fd7a719c22b355e8ad6fe7c8eee07c..4c638909a7db325bd6314c3f2f065824f8d66f0a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.h b/drivers/net/wireless/iwlwifi/iwl-3945-led.h index 2fbd126c13478b4b6a0cb6ad6be6037123c69b1c..749ac035fd6aa3a20d4a7c85b8778f2084dc11e1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-led.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.h @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index 6fc5e7361f267dad0e01deb1a5c2a155cdc72bc6..9b60a0c5de5f3f55bf45bd7acf8594e3973f172a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -63,6 +63,9 @@ struct iwl3945_rs_sta { u8 ibss_sta_added; struct timer_list rate_scale_flush; struct iwl3945_rate_scale_data win[IWL_RATE_COUNT]; +#ifdef CONFIG_MAC80211_DEBUGFS + struct dentry *rs_sta_dbgfs_stats_table_file; +#endif /* used to be in sta_info */ int last_txrate_idx; @@ -114,9 +117,11 @@ static struct iwl3945_tpt_entry iwl3945_tpt_table_g[] = { }; #define IWL_RATE_MAX_WINDOW 62 -#define IWL_RATE_FLUSH (3*HZ/10) +#define IWL_RATE_FLUSH (3*HZ) #define IWL_RATE_WIN_FLUSH (HZ/2) #define IWL_RATE_HIGH_TH 11520 +#define IWL_SUCCESS_UP_TH 8960 +#define IWL_SUCCESS_DOWN_TH 10880 #define IWL_RATE_MIN_FAILURE_TH 8 #define IWL_RATE_MIN_SUCCESS_TH 8 #define IWL_RATE_DECREASE_TH 1920 @@ -203,6 +208,7 @@ static int iwl3945_rate_scale_flush_windows(struct iwl3945_rs_sta *rs_sta) #define IWL_RATE_FLUSH_MAX 5000 /* msec */ #define IWL_RATE_FLUSH_MIN 50 /* msec */ +#define IWL_AVERAGE_PACKETS 1500 static void iwl3945_bg_rate_scale_flush(unsigned long data) { @@ -217,8 +223,6 @@ static void iwl3945_bg_rate_scale_flush(unsigned long data) spin_lock_irqsave(&rs_sta->lock, flags); - rs_sta->flush_pending = 0; - /* Number of packets Rx'd since last time this timer ran */ packet_count = (rs_sta->tx_packets - rs_sta->last_tx_packets) + 1; @@ -227,7 +231,6 @@ static void iwl3945_bg_rate_scale_flush(unsigned long data) if (unflushed) { duration = jiffies_to_msecs(jiffies - rs_sta->last_partial_flush); -/* duration = jiffies_to_msecs(rs_sta->flush_time); */ IWL_DEBUG_RATE("Tx'd %d packets in %dms\n", packet_count, duration); @@ -239,9 +242,11 @@ static void iwl3945_bg_rate_scale_flush(unsigned long data) pps = 0; if (pps) { - duration = IWL_RATE_FLUSH_MAX / pps; + duration = (IWL_AVERAGE_PACKETS * 1000) / pps; if (duration < IWL_RATE_FLUSH_MIN) duration = IWL_RATE_FLUSH_MIN; + else if (duration > IWL_RATE_FLUSH_MAX) + duration = IWL_RATE_FLUSH_MAX; } else duration = IWL_RATE_FLUSH_MAX; @@ -254,8 +259,10 @@ static void iwl3945_bg_rate_scale_flush(unsigned long data) rs_sta->flush_time); rs_sta->last_partial_flush = jiffies; + } else { + rs_sta->flush_time = IWL_RATE_FLUSH; + rs_sta->flush_pending = 0; } - /* If there weren't any unflushed entries, we don't schedule the timer * to run again */ @@ -275,17 +282,18 @@ static void iwl3945_bg_rate_scale_flush(unsigned long data) */ static void iwl3945_collect_tx_data(struct iwl3945_rs_sta *rs_sta, struct iwl3945_rate_scale_data *window, - int success, int retries) + int success, int retries, int index) { unsigned long flags; + s32 fail_count; if (!retries) { IWL_DEBUG_RATE("leave: retries == 0 -- should be at least 1\n"); return; } + spin_lock_irqsave(&rs_sta->lock, flags); while (retries--) { - spin_lock_irqsave(&rs_sta->lock, flags); /* If we have filled up the window then subtract one from the * success counter if the high-bit is counting toward @@ -313,14 +321,25 @@ static void iwl3945_collect_tx_data(struct iwl3945_rs_sta *rs_sta, /* Tag this window as having been updated */ window->stamp = jiffies; - spin_unlock_irqrestore(&rs_sta->lock, flags); } + + fail_count = window->counter - window->success_counter; + if ((fail_count >= IWL_RATE_MIN_FAILURE_TH) || + (window->success_counter >= IWL_RATE_MIN_SUCCESS_TH)) + window->average_tpt = ((window->success_ratio * + rs_sta->expected_tpt[index] + 64) / 128); + else + window->average_tpt = IWL_INV_TPT; + + spin_unlock_irqrestore(&rs_sta->lock, flags); + } -static void rs_rate_init(void *priv, struct ieee80211_supported_band *sband, +static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, struct ieee80211_sta *sta, void *priv_sta) { struct iwl3945_rs_sta *rs_sta = priv_sta; + struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_r; int i; IWL_DEBUG_RATE("enter\n"); @@ -330,16 +349,21 @@ static void rs_rate_init(void *priv, struct ieee80211_supported_band *sband, * previous packets? Need to have IEEE 802.1X auth succeed immediately * after assoc.. */ - for (i = IWL_RATE_COUNT - 1; i >= 0; i--) { + for (i = sband->n_bitrates - 1; i >= 0; i--) { if (sta->supp_rates[sband->band] & (1 << i)) { rs_sta->last_txrate_idx = i; break; } } + priv->sta_supp_rates = sta->supp_rates[sband->band]; /* For 5 GHz band it start at IWL_FIRST_OFDM_RATE */ - if (sband->band == IEEE80211_BAND_5GHZ) + if (sband->band == IEEE80211_BAND_5GHZ) { rs_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; + priv->sta_supp_rates = priv->sta_supp_rates << + IWL_FIRST_OFDM_RATE; + } + IWL_DEBUG_RATE("leave\n"); } @@ -355,12 +379,6 @@ static void rs_free(void *priv) return; } -static void rs_clear(void *priv) -{ - return; -} - - static void *rs_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp) { struct iwl3945_rs_sta *rs_sta; @@ -422,34 +440,6 @@ static void rs_free_sta(void *priv, struct ieee80211_sta *sta, } -/* - * get ieee prev rate from rate scale table. - * for A and B mode we need to overright prev - * value - */ -static int rs_adjust_next_rate(struct iwl3945_priv *priv, int rate) -{ - int next_rate = iwl3945_get_prev_ieee_rate(rate); - - switch (priv->band) { - case IEEE80211_BAND_5GHZ: - if (rate == IWL_RATE_12M_INDEX) - next_rate = IWL_RATE_9M_INDEX; - else if (rate == IWL_RATE_6M_INDEX) - next_rate = IWL_RATE_6M_INDEX; - break; -/* XXX cannot be invoked in current mac80211 so not a regression - case MODE_IEEE80211B: - if (rate == IWL_RATE_11M_INDEX_TABLE) - next_rate = IWL_RATE_5M_INDEX_TABLE; - break; - */ - default: - break; - } - - return next_rate; -} /** * rs_tx_status - Update rate control values based on Tx results * @@ -460,7 +450,7 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband struct ieee80211_sta *sta, void *priv_sta, struct sk_buff *skb) { - u8 retries, current_count; + s8 retries = 0, current_count; int scale_rate_index, first_index, last_index; unsigned long flags; struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_rate; @@ -469,8 +459,9 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband IWL_DEBUG_RATE("enter\n"); - retries = info->status.retry_count; - first_index = sband->bitrates[info->tx_rate_idx].hw_value; + retries = info->status.rates[0].count; + + first_index = sband->bitrates[info->status.rates[0].idx].hw_value; if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) { IWL_DEBUG_RATE("leave: Rate out of bounds: %d\n", first_index); return; @@ -496,13 +487,13 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband * at which the frame was finally transmitted (or failed if no * ACK) */ - while (retries > 0) { - if (retries < priv->retry_rate) { - current_count = retries; + while (retries > 1) { + if ((retries - 1) < priv->retry_rate) { + current_count = (retries - 1); last_index = scale_rate_index; } else { current_count = priv->retry_rate; - last_index = rs_adjust_next_rate(priv, + last_index = iwl3945_rs_next_rate(priv, scale_rate_index); } @@ -510,15 +501,13 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband * as was used for it (per current_count) */ iwl3945_collect_tx_data(rs_sta, &rs_sta->win[scale_rate_index], - 0, current_count); + 0, current_count, scale_rate_index); IWL_DEBUG_RATE("Update rate %d for %d retries.\n", scale_rate_index, current_count); retries -= current_count; - if (retries) - scale_rate_index = - rs_adjust_next_rate(priv, scale_rate_index); + scale_rate_index = last_index; } @@ -529,7 +518,7 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband "success" : "failure"); iwl3945_collect_tx_data(rs_sta, &rs_sta->win[last_index], - info->flags & IEEE80211_TX_STAT_ACK, 1); + info->flags & IEEE80211_TX_STAT_ACK, 1, last_index); /* We updated the rate scale window -- if its been more than * flush_time since the last run, schedule the flush @@ -537,9 +526,10 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband spin_lock_irqsave(&rs_sta->lock, flags); if (!rs_sta->flush_pending && - time_after(jiffies, rs_sta->last_partial_flush + + time_after(jiffies, rs_sta->last_flush + rs_sta->flush_time)) { + rs_sta->last_partial_flush = jiffies; rs_sta->flush_pending = 1; mod_timer(&rs_sta->rate_scale_flush, jiffies + rs_sta->flush_time); @@ -630,10 +620,11 @@ static u16 iwl3945_get_adjacent_rate(struct iwl3945_rs_sta *rs_sta, * rate table and must reference the driver allocated rate table * */ -static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, void *priv_sta, - struct sk_buff *skb, struct rate_selection *sel) +static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, + void *priv_sta, struct ieee80211_tx_rate_control *txrc) { + struct ieee80211_supported_band *sband = txrc->sband; + struct sk_buff *skb = txrc->skb; u8 low = IWL_RATE_INVALID; u8 high = IWL_RATE_INVALID; u16 high_low; @@ -649,7 +640,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; u16 fc, rate_mask; struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_r; - DECLARE_MAC_BUF(mac); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); IWL_DEBUG_RATE("enter\n"); @@ -660,7 +651,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, is_multicast_ether_addr(hdr->addr1) || !sta || !priv_sta) { IWL_DEBUG_RATE("leave: No STA priv data to update!\n"); - sel->rate_idx = rate_lowest_index(sband, sta); + info->control.rates[0].idx = rate_lowest_index(sband, sta); return; } @@ -675,8 +666,8 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, u8 sta_id = iwl3945_hw_find_station(priv, hdr->addr1); if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_RATE("LQ: ADD station %s\n", - print_mac(mac, hdr->addr1)); + IWL_DEBUG_RATE("LQ: ADD station %pm\n", + hdr->addr1); sta_id = iwl3945_add_station(priv, hdr->addr1, 0, CMD_ASYNC); } @@ -686,8 +677,13 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, spin_lock_irqsave(&rs_sta->lock, flags); + /* for recent assoc, choose best rate regarding + * to rssi value + */ if (rs_sta->start_rate != IWL_RATE_INVALID) { - index = rs_sta->start_rate; + if (rs_sta->start_rate < index && + (rate_mask & (1 << rs_sta->start_rate))) + index = rs_sta->start_rate; rs_sta->start_rate = IWL_RATE_INVALID; } @@ -697,7 +693,6 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, if (((fail_count <= IWL_RATE_MIN_FAILURE_TH) && (window->success_counter < IWL_RATE_MIN_SUCCESS_TH))) { - window->average_tpt = IWL_INV_TPT; spin_unlock_irqrestore(&rs_sta->lock, flags); IWL_DEBUG_RATE("Invalid average_tpt on rate %d: " @@ -711,8 +706,6 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, } - window->average_tpt = ((window->success_ratio * - rs_sta->expected_tpt[index] + 64) / 128); current_tpt = window->average_tpt; high_low = iwl3945_get_adjacent_rate(rs_sta, index, rate_mask, @@ -760,13 +753,15 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, } } - if ((window->success_ratio > IWL_RATE_HIGH_TH) || - (current_tpt > window->average_tpt)) { - IWL_DEBUG_RATE("No action -- success_ratio [%d] > HIGH_TH or " - "current_tpt [%d] > average_tpt [%d]\n", - window->success_ratio, - current_tpt, window->average_tpt); - scale_action = 0; + if (scale_action == -1) { + if (window->success_ratio > IWL_SUCCESS_DOWN_TH) + scale_action = 0; + } else if (scale_action == 1) { + if (window->success_ratio < IWL_SUCCESS_UP_TH) { + IWL_DEBUG_RATE("No action -- success_ratio [%d] < " + "SUCCESS UP\n", window->success_ratio); + scale_action = 0; + } } switch (scale_action) { @@ -793,24 +788,83 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, rs_sta->last_txrate_idx = index; if (sband->band == IEEE80211_BAND_5GHZ) - sel->rate_idx = rs_sta->last_txrate_idx - IWL_FIRST_OFDM_RATE; + info->control.rates[0].idx = rs_sta->last_txrate_idx - + IWL_FIRST_OFDM_RATE; else - sel->rate_idx = rs_sta->last_txrate_idx; + info->control.rates[0].idx = rs_sta->last_txrate_idx; IWL_DEBUG_RATE("leave: %d\n", index); } +#ifdef CONFIG_MAC80211_DEBUGFS +static int iwl3945_open_file_generic(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t iwl3945_sta_dbgfs_stats_table_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + char buff[1024]; + int desc = 0; + int j; + struct iwl3945_rs_sta *lq_sta = file->private_data; + + desc += sprintf(buff + desc, "tx packets=%d last rate index=%d\n" + "rate=0x%X flush time %d\n", + lq_sta->tx_packets, + lq_sta->last_txrate_idx, + lq_sta->start_rate, jiffies_to_msecs(lq_sta->flush_time)); + for (j = 0; j < IWL_RATE_COUNT; j++) { + desc += sprintf(buff+desc, + "counter=%d success=%d %%=%d\n", + lq_sta->win[j].counter, + lq_sta->win[j].success_counter, + lq_sta->win[j].success_ratio); + } + return simple_read_from_buffer(user_buf, count, ppos, buff, desc); +} + +static const struct file_operations rs_sta_dbgfs_stats_table_ops = { + .read = iwl3945_sta_dbgfs_stats_table_read, + .open = iwl3945_open_file_generic, +}; + +static void iwl3945_add_debugfs(void *priv, void *priv_sta, + struct dentry *dir) +{ + struct iwl3945_rs_sta *lq_sta = priv_sta; + + lq_sta->rs_sta_dbgfs_stats_table_file = + debugfs_create_file("rate_stats_table", 0600, dir, + lq_sta, &rs_sta_dbgfs_stats_table_ops); + +} + +static void iwl3945_remove_debugfs(void *priv, void *priv_sta) +{ + struct iwl3945_rs_sta *lq_sta = priv_sta; + debugfs_remove(lq_sta->rs_sta_dbgfs_stats_table_file); +} +#endif + static struct rate_control_ops rs_ops = { .module = NULL, .name = RS_NAME, .tx_status = rs_tx_status, .get_rate = rs_get_rate, .rate_init = rs_rate_init, - .clear = rs_clear, .alloc = rs_alloc, .free = rs_free, .alloc_sta = rs_alloc_sta, .free_sta = rs_free_sta, +#ifdef CONFIG_MAC80211_DEBUGFS + .add_sta_debugfs = iwl3945_add_debugfs, + .remove_sta_debugfs = iwl3945_remove_debugfs, +#endif + }; void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) @@ -827,13 +881,12 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) rcu_read_lock(); sta = ieee80211_find_sta(hw, priv->stations[sta_id].sta.sta.addr); - psta = (void *) sta->drv_priv; - if (!sta || !psta) { - IWL_DEBUG_RATE("leave - no private rate data!\n"); + if (!sta) { rcu_read_unlock(); return; } + psta = (void *) sta->drv_priv; rs_sta = psta->rs_sta; spin_lock_irqsave(&rs_sta->lock, flags); @@ -857,7 +910,6 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) break; } - rcu_read_unlock(); spin_unlock_irqrestore(&rs_sta->lock, flags); rssi = priv->last_rx_rssi; @@ -871,6 +923,7 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) IWL_DEBUG_RATE("leave: rssi %d assign rate index: " "%d (plcp 0x%x)\n", rssi, rs_sta->start_rate, iwl3945_rates[rs_sta->start_rate].plcp); + rcu_read_unlock(); } int iwl3945_rate_control_register(void) diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.h b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h index 98b17ae6ef246d62720760cf4c5416e10300eb4d..b5a66135deddf0f1fcbd2b6f4c0d3f3b71287d02 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 7ca5627cc078bed3944190d36ab201c39b31c9e8..8fdb34222c0a4f3e3ba8c11644fc429ed6de7300 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -200,7 +200,7 @@ static int iwl3945_hwrate_to_plcp_idx(u8 plcp) * priv->eeprom is used to determine if antenna AUX/MAIN are reversed * priv->antenna specifies the antenna diversity mode: * - * IWL_ANTENNA_DIVERISTY - NIC selects best antenna by itself + * IWL_ANTENNA_DIVERSITY - NIC selects best antenna by itself * IWL_ANTENNA_MAIN - Force MAIN antenna * IWL_ANTENNA_AUX - Force AUX antenna */ @@ -261,6 +261,37 @@ static inline const char *iwl3945_get_tx_fail_reason(u32 status) } #endif +/* + * get ieee prev rate from rate scale table. + * for A and B mode we need to overright prev + * value + */ +int iwl3945_rs_next_rate(struct iwl3945_priv *priv, int rate) +{ + int next_rate = iwl3945_get_prev_ieee_rate(rate); + + switch (priv->band) { + case IEEE80211_BAND_5GHZ: + if (rate == IWL_RATE_12M_INDEX) + next_rate = IWL_RATE_9M_INDEX; + else if (rate == IWL_RATE_6M_INDEX) + next_rate = IWL_RATE_6M_INDEX; + break; + case IEEE80211_BAND_2GHZ: + if (!(priv->sta_supp_rates & IWL_OFDM_RATES_MASK) && + iwl3945_is_associated(priv)) { + if (rate == IWL_RATE_11M_INDEX) + next_rate = IWL_RATE_5M_INDEX; + } + break; + + default: + break; + } + + return next_rate; +} + /** * iwl3945_tx_queue_reclaim - Reclaim Tx queue entries already Tx'd @@ -308,6 +339,7 @@ static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv, struct iwl3945_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; u32 status = le32_to_cpu(tx_resp->status); int rate_idx; + int fail; if ((index >= txq->q.n_bd) || (iwl3945_x2_queue_used(&txq->q, index) == 0)) { IWL_ERROR("Read index for DMA queue txq_id (%d) index %d " @@ -318,9 +350,18 @@ static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv, } info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]); - memset(&info->status, 0, sizeof(info->status)); + ieee80211_tx_info_clear_status(info); + + /* Fill the MRR chain with some info about on-chip retransmissions */ + rate_idx = iwl3945_hwrate_to_plcp_idx(tx_resp->rate); + if (info->band == IEEE80211_BAND_5GHZ) + rate_idx -= IWL_FIRST_OFDM_RATE; + + fail = tx_resp->failure_frame; + + info->status.rates[0].idx = rate_idx; + info->status.rates[0].count = fail + 1; /* add final attempt */ - info->status.retry_count = tx_resp->failure_frame; /* tx_status->rts_retry_count = tx_resp->failure_rts; */ info->flags |= ((status & TX_STATUS_MSK) == TX_STATUS_SUCCESS) ? IEEE80211_TX_STAT_ACK : 0; @@ -329,10 +370,6 @@ static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv, txq_id, iwl3945_get_tx_fail_reason(status), status, tx_resp->rate, tx_resp->failure_frame); - rate_idx = iwl3945_hwrate_to_plcp_idx(tx_resp->rate); - if (info->band == IEEE80211_BAND_5GHZ) - rate_idx -= IWL_FIRST_OFDM_RATE; - info->tx_rate_idx = rate_idx; IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); iwl3945_tx_queue_reclaim(priv, txq_id, index); @@ -756,13 +793,19 @@ int iwl3945_hw_txq_free_tfd(struct iwl3945_priv *priv, struct iwl3945_tx_queue * u8 iwl3945_hw_find_station(struct iwl3945_priv *priv, const u8 *addr) { - int i; + int i, start = IWL_AP_ID; int ret = IWL_INVALID_STATION; unsigned long flags; - DECLARE_MAC_BUF(mac); + + if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) || + (priv->iw_mode == NL80211_IFTYPE_AP)) + start = IWL_STA_ID; + + if (is_broadcast_ether_addr(addr)) + return priv->hw_setting.bcast_sta_id; spin_lock_irqsave(&priv->sta_lock, flags); - for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++) + for (i = start; i < priv->hw_setting.max_stations; i++) if ((priv->stations[i].used) && (!compare_ether_addr (priv->stations[i].sta.sta.addr, addr))) { @@ -770,8 +813,8 @@ u8 iwl3945_hw_find_station(struct iwl3945_priv *priv, const u8 *addr) goto out; } - IWL_DEBUG_INFO("can not find STA %s (total %d)\n", - print_mac(mac, addr), priv->num_stations); + IWL_DEBUG_INFO("can not find STA %pM (total %d)\n", + addr, priv->num_stations); out: spin_unlock_irqrestore(&priv->sta_lock, flags); return ret; @@ -1060,9 +1103,8 @@ int iwl3945_hw_nic_init(struct iwl3945_priv *priv) CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - rc = iwl3945_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + rc = iwl3945_poll_direct_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (rc < 0) { spin_unlock_irqrestore(&priv->lock, flags); IWL_DEBUG_INFO("Failed to init the card\n"); @@ -1243,8 +1285,7 @@ int iwl3945_hw_nic_stop_master(struct iwl3945_priv *priv) IWL_DEBUG_INFO("Card in power save, master is already " "stopped\n"); else { - rc = iwl3945_poll_bit(priv, CSR_RESET, - CSR_RESET_REG_FLAG_MASTER_DISABLED, + rc = iwl3945_poll_direct_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); if (rc < 0) { spin_unlock_irqrestore(&priv->lock, flags); @@ -1269,9 +1310,8 @@ int iwl3945_hw_nic_reset(struct iwl3945_priv *priv) iwl3945_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - rc = iwl3945_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + iwl3945_poll_direct_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); rc = iwl3945_grab_nic_access(priv); if (!rc) { @@ -1830,7 +1870,7 @@ static int iwl3945_hw_reg_comp_txpower_temp(struct iwl3945_priv *priv) ref_temp = (s16)priv->eeprom.groups[ch_info->group_index]. temperature; - /* get power index adjustment based on curr and factory + /* get power index adjustment based on current and factory * temps */ delta_index = iwl3945_hw_reg_adjust_power_by_temp(temperature, ref_temp); @@ -2268,7 +2308,8 @@ int iwl3945_hw_rxq_stop(struct iwl3945_priv *priv) } iwl3945_write_direct32(priv, FH_RCSR_CONFIG(0), 0); - rc = iwl3945_poll_direct_bit(priv, FH_RSSR_STATUS, (1 << 24), 1000); + rc = iwl3945_poll_direct_bit(priv, FH_RSSR_STATUS, + FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000); if (rc < 0) IWL_ERROR("Can't stop Rx DMA.\n"); @@ -2337,7 +2378,8 @@ int iwl3945_init_hw_rate_table(struct iwl3945_priv *priv) iwl3945_hw_set_rate_n_flags(iwl3945_rates[i].plcp, 0); table[index].try_cnt = priv->retry_rate; prev_index = iwl3945_get_prev_ieee_rate(i); - table[index].next_rate_index = iwl3945_rates[prev_index].table_rs_index; + table[index].next_rate_index = + iwl3945_rates[prev_index].table_rs_index; } switch (priv->band) { @@ -2345,11 +2387,14 @@ int iwl3945_init_hw_rate_table(struct iwl3945_priv *priv) IWL_DEBUG_RATE("Select A mode rate scale\n"); /* If one of the following CCK rates is used, * have it fall back to the 6M OFDM rate */ - for (i = IWL_RATE_1M_INDEX_TABLE; i <= IWL_RATE_11M_INDEX_TABLE; i++) - table[i].next_rate_index = iwl3945_rates[IWL_FIRST_OFDM_RATE].table_rs_index; + for (i = IWL_RATE_1M_INDEX_TABLE; + i <= IWL_RATE_11M_INDEX_TABLE; i++) + table[i].next_rate_index = + iwl3945_rates[IWL_FIRST_OFDM_RATE].table_rs_index; /* Don't fall back to CCK rates */ - table[IWL_RATE_12M_INDEX_TABLE].next_rate_index = IWL_RATE_9M_INDEX_TABLE; + table[IWL_RATE_12M_INDEX_TABLE].next_rate_index = + IWL_RATE_9M_INDEX_TABLE; /* Don't drop out of OFDM rates */ table[IWL_RATE_6M_INDEX_TABLE].next_rate_index = @@ -2360,11 +2405,20 @@ int iwl3945_init_hw_rate_table(struct iwl3945_priv *priv) IWL_DEBUG_RATE("Select B/G mode rate scale\n"); /* If an OFDM rate is used, have it fall back to the * 1M CCK rates */ - for (i = IWL_RATE_6M_INDEX_TABLE; i <= IWL_RATE_54M_INDEX_TABLE; i++) - table[i].next_rate_index = iwl3945_rates[IWL_FIRST_CCK_RATE].table_rs_index; - /* CCK shouldn't fall back to OFDM... */ - table[IWL_RATE_11M_INDEX_TABLE].next_rate_index = IWL_RATE_5M_INDEX_TABLE; + if (!(priv->sta_supp_rates & IWL_OFDM_RATES_MASK) && + iwl3945_is_associated(priv)) { + + index = IWL_FIRST_CCK_RATE; + for (i = IWL_RATE_6M_INDEX_TABLE; + i <= IWL_RATE_54M_INDEX_TABLE; i++) + table[i].next_rate_index = + iwl3945_rates[index].table_rs_index; + + index = IWL_RATE_11M_INDEX_TABLE; + /* CCK shouldn't fall back to OFDM... */ + table[index].next_rate_index = IWL_RATE_5M_INDEX_TABLE; + } break; default: @@ -2428,7 +2482,6 @@ unsigned int iwl3945_hw_get_beacon_cmd(struct iwl3945_priv *priv, frame_size = iwl3945_fill_beacon_frame(priv, tx_beacon_cmd->frame, - iwl3945_broadcast_addr, sizeof(frame->u) - sizeof(*tx_beacon_cmd)); BUG_ON(frame_size > MAX_MPDU_SIZE); @@ -2467,13 +2520,17 @@ void iwl3945_hw_cancel_deferred_work(struct iwl3945_priv *priv) static struct iwl_3945_cfg iwl3945_bg_cfg = { .name = "3945BG", - .fw_name = "iwlwifi-3945" IWL3945_UCODE_API ".ucode", + .fw_name_pre = IWL3945_FW_PRE, + .ucode_api_max = IWL3945_UCODE_API_MAX, + .ucode_api_min = IWL3945_UCODE_API_MIN, .sku = IWL_SKU_G, }; static struct iwl_3945_cfg iwl3945_abg_cfg = { .name = "3945ABG", - .fw_name = "iwlwifi-3945" IWL3945_UCODE_API ".ucode", + .fw_name_pre = IWL3945_FW_PRE, + .ucode_api_max = IWL3945_UCODE_API_MAX, + .ucode_api_min = IWL3945_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index bdd32475b99ca6b0ca7ae1562f85b878edfa55fc..2c0ddc5110c6b1611e631239a8ef84a16c8e0539 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -50,11 +50,15 @@ extern struct pci_device_id iwl3945_hw_card_ids[]; #include "iwl-3945-debug.h" #include "iwl-3945-led.h" -/* Change firmware file name, using "-" and incrementing number, - * *only* when uCode interface or architecture changes so that it - * is not compatible with earlier drivers. - * This number will also appear in << 8 position of 1st dword of uCode file */ -#define IWL3945_UCODE_API "-1" +/* Highest firmware API version supported */ +#define IWL3945_UCODE_API_MAX 2 + +/* Lowest firmware API version supported */ +#define IWL3945_UCODE_API_MIN 1 + +#define IWL3945_FW_PRE "iwlwifi-3945-" +#define _IWL3945_MODULE_FIRMWARE(api) IWL3945_FW_PRE #api ".ucode" +#define IWL3945_MODULE_FIRMWARE(api) _IWL3945_MODULE_FIRMWARE(api) /* Default noise level to report when noise measurement is not available. * This may be because we're: @@ -401,12 +405,6 @@ struct iwl3945_rx_queue { #define SCAN_INTERVAL 100 -#define MAX_A_CHANNELS 252 -#define MIN_A_CHANNELS 7 - -#define MAX_B_CHANNELS 14 -#define MIN_B_CHANNELS 1 - #define STATUS_HCMD_ACTIVE 0 /* host command in progress */ #define STATUS_HCMD_SYNC_ACTIVE 1 /* sync host command in progress */ #define STATUS_INT_ENABLED 2 @@ -472,7 +470,6 @@ union iwl3945_qos_capabity { /* QoS structures */ struct iwl3945_qos_info { - int qos_enable; int qos_active; union iwl3945_qos_capabity qos_cap; struct iwl3945_qosparam_cmd def_qos_parm; @@ -505,7 +502,7 @@ struct fw_desc { /* uCode file layout */ struct iwl3945_ucode { - __le32 ver; /* major/minor/subminor */ + __le32 ver; /* major/minor/API/serial */ __le32 inst_size; /* bytes of runtime instructions */ __le32 data_size; /* bytes of runtime data */ __le32 init_size; /* bytes of initialization instructions */ @@ -587,8 +584,7 @@ extern int iwl3945_send_cmd_pdu(struct iwl3945_priv *priv, u8 id, u16 len, extern int __must_check iwl3945_send_cmd(struct iwl3945_priv *priv, struct iwl3945_host_cmd *cmd); extern unsigned int iwl3945_fill_beacon_frame(struct iwl3945_priv *priv, - struct ieee80211_hdr *hdr, - const u8 *dest, int left); + struct ieee80211_hdr *hdr,int left); extern int iwl3945_rx_queue_update_write_ptr(struct iwl3945_priv *priv, struct iwl3945_rx_queue *q); extern int iwl3945_send_statistics_request(struct iwl3945_priv *priv); @@ -762,6 +758,8 @@ struct iwl3945_priv { void __iomem *hw_base; /* uCode images, save to reload in case of failure */ + u32 ucode_ver; /* ucode version, copy of + iwl3945_ucode.ver */ struct fw_desc ucode_code; /* runtime inst */ struct fw_desc ucode_data; /* runtime data original */ struct fw_desc ucode_data_backup; /* runtime data save/restore */ @@ -804,6 +802,8 @@ struct iwl3945_priv { u16 active_rate; u16 active_rate_basic; + u32 sta_supp_rates; + u8 call_post_assoc_from_beacon; /* Rate scaling data */ s8 data_retry_limit; @@ -828,8 +828,6 @@ struct iwl3945_priv { unsigned long last_statistics_time; /* context information */ - u8 essid[IW_ESSID_MAX_SIZE]; - u8 essid_len; u16 rates_mask; u32 power_mode; @@ -888,7 +886,6 @@ struct iwl3945_priv { struct work_struct report_work; struct work_struct request_scan; struct work_struct beacon_update; - struct work_struct set_monitor; struct tasklet_struct irq_tasklet; @@ -903,9 +900,6 @@ struct iwl3945_priv { s8 user_txpower_limit; s8 max_channel_txpower_limit; -#ifdef CONFIG_PM - u32 pm_state[16]; -#endif #ifdef CONFIG_IWL3945_DEBUG /* debugging info */ @@ -954,6 +948,8 @@ static inline int is_channel_ibss(const struct iwl3945_channel_info *ch) extern const struct iwl3945_channel_info *iwl3945_get_channel_info( const struct iwl3945_priv *priv, enum ieee80211_band band, u16 channel); +extern int iwl3945_rs_next_rate(struct iwl3945_priv *priv, int rate); + /* Requires full declaration of iwl3945_priv before including */ #include "iwl-3945-io.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h index f4793a609443eca52ded350777ea0f0967deb130..6649f7b55650012ef01310bab088fc2f56455526 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -71,7 +71,7 @@ #include "iwl-fh.h" -/* EERPROM */ +/* EEPROM */ #define IWL4965_EEPROM_IMG_SIZE 1024 /* @@ -84,12 +84,6 @@ #define IWL_CMD_FIFO_NUM 4 #define IWL49_FIRST_AMPDU_QUEUE 7 -/* Tx rates */ -#define IWL_CCK_RATES 4 -#define IWL_OFDM_RATES 8 -#define IWL_HT_RATES 16 -#define IWL_MAX_RATES (IWL_CCK_RATES+IWL_OFDM_RATES+IWL_HT_RATES) - /* Time constants */ #define SHORT_SLOT_TIME 9 #define LONG_SLOT_TIME 20 @@ -111,7 +105,6 @@ #define PCI_CFG_CMD_REG_INT_DIS_MSK 0x04 #define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT (0x80000000) -#define TFD_QUEUE_SIZE_MAX (256) #define IWL_NUM_SCAN_RATES (2) @@ -287,13 +280,13 @@ static inline int iwl4965_hw_valid_rtc_data_addr(u32 addr) * that target txpower. * * - * 3) Determine (EEPROM) calibration subband for the target channel, by - * comparing against first and last channels in each subband + * 3) Determine (EEPROM) calibration sub band for the target channel, by + * comparing against first and last channels in each sub band * (see struct iwl4965_eeprom_calib_subband_info). * * * 4) Linearly interpolate (EEPROM) factory calibration measurement sets, - * referencing the 2 factory-measured (sample) channels within the subband. + * referencing the 2 factory-measured (sample) channels within the sub band. * * Interpolation is based on difference between target channel's frequency * and the sample channels' frequencies. Since channel numbers are based @@ -301,7 +294,7 @@ static inline int iwl4965_hw_valid_rtc_data_addr(u32 addr) * to interpolating based on channel number differences. * * Note that the sample channels may or may not be the channels at the - * edges of the subband. The target channel may be "outside" of the + * edges of the sub band. The target channel may be "outside" of the * span of the sampled channels. * * Driver may choose the pair (for 2 Tx chains) of measurements (see @@ -345,7 +338,7 @@ static inline int iwl4965_hw_valid_rtc_data_addr(u32 addr) * "4965 temperature calculation". * * If current temperature is higher than factory temperature, driver must - * increase gain (lower gain table index), and vice versa. + * increase gain (lower gain table index), and vice verse. * * Temperature affects gain differently for different channels: * @@ -815,125 +808,14 @@ enum { * up to 7 DMA channels (FIFOs). Each Tx queue is supported by a circular array * in DRAM containing 256 Transmit Frame Descriptors (TFDs). */ -#define IWL49_MAX_WIN_SIZE 64 -#define IWL49_QUEUE_SIZE 256 #define IWL49_NUM_FIFOS 7 #define IWL49_CMD_FIFO_NUM 4 #define IWL49_NUM_QUEUES 16 #define IWL49_NUM_AMPDU_QUEUES 8 -/** - * struct iwl_tfd_frame_data - * - * Describes up to 2 buffers containing (contiguous) portions of a Tx frame. - * Each buffer must be on dword boundary. - * Up to 10 iwl_tfd_frame_data structures, describing up to 20 buffers, - * may be filled within a TFD (iwl_tfd_frame). - * - * Bit fields in tb1_addr: - * 31- 0: Tx buffer 1 address bits [31:0] - * - * Bit fields in val1: - * 31-16: Tx buffer 2 address bits [15:0] - * 15- 4: Tx buffer 1 length (bytes) - * 3- 0: Tx buffer 1 address bits [32:32] - * - * Bit fields in val2: - * 31-20: Tx buffer 2 length (bytes) - * 19- 0: Tx buffer 2 address bits [35:16] - */ -struct iwl_tfd_frame_data { - __le32 tb1_addr; - - __le32 val1; - /* __le32 ptb1_32_35:4; */ -#define IWL_tb1_addr_hi_POS 0 -#define IWL_tb1_addr_hi_LEN 4 -#define IWL_tb1_addr_hi_SYM val1 - /* __le32 tb_len1:12; */ -#define IWL_tb1_len_POS 4 -#define IWL_tb1_len_LEN 12 -#define IWL_tb1_len_SYM val1 - /* __le32 ptb2_0_15:16; */ -#define IWL_tb2_addr_lo16_POS 16 -#define IWL_tb2_addr_lo16_LEN 16 -#define IWL_tb2_addr_lo16_SYM val1 - - __le32 val2; - /* __le32 ptb2_16_35:20; */ -#define IWL_tb2_addr_hi20_POS 0 -#define IWL_tb2_addr_hi20_LEN 20 -#define IWL_tb2_addr_hi20_SYM val2 - /* __le32 tb_len2:12; */ -#define IWL_tb2_len_POS 20 -#define IWL_tb2_len_LEN 12 -#define IWL_tb2_len_SYM val2 -} __attribute__ ((packed)); - /** - * struct iwl_tfd_frame - * - * Transmit Frame Descriptor (TFD) - * - * 4965 supports up to 16 Tx queues resident in host DRAM. - * Each Tx queue uses a circular buffer of 256 TFDs stored in host DRAM. - * Both driver and device share these circular buffers, each of which must be - * contiguous 256 TFDs x 128 bytes-per-TFD = 32 KBytes for 4965. - * - * Driver must indicate the physical address of the base of each - * circular buffer via the 4965's FH_MEM_CBBC_QUEUE registers. - * - * Each TFD contains pointer/size information for up to 20 data buffers - * in host DRAM. These buffers collectively contain the (one) frame described - * by the TFD. Each buffer must be a single contiguous block of memory within - * itself, but buffers may be scattered in host DRAM. Each buffer has max size - * of (4K - 4). The 4965 concatenates all of a TFD's buffers into a single - * Tx frame, up to 8 KBytes in size. - * - * Bit fields in the control dword (val0): - * 31-30: # dwords (0-3) of padding required at end of frame for 16-byte bound - * 29: reserved - * 28-24: # Transmit Buffer Descriptors in TFD - * 23- 0: reserved - * - * A maximum of 255 (not 256!) TFDs may be on a queue waiting for Tx. - */ -struct iwl_tfd_frame { - __le32 val0; - /* __le32 rsvd1:24; */ - /* __le32 num_tbs:5; */ -#define IWL_num_tbs_POS 24 -#define IWL_num_tbs_LEN 5 -#define IWL_num_tbs_SYM val0 - /* __le32 rsvd2:1; */ - /* __le32 padding:2; */ - struct iwl_tfd_frame_data pa[10]; - __le32 reserved; -} __attribute__ ((packed)); - - -/** - * struct iwl4965_queue_byte_cnt_entry - * - * Byte Count Table Entry - * - * Bit fields: - * 15-12: reserved - * 11- 0: total to-be-transmitted byte count of frame (does not include command) - */ -struct iwl4965_queue_byte_cnt_entry { - __le16 val; - /* __le16 byte_cnt:12; */ -#define IWL_byte_cnt_POS 0 -#define IWL_byte_cnt_LEN 12 -#define IWL_byte_cnt_SYM val - /* __le16 rsvd:4; */ -} __attribute__ ((packed)); - - -/** - * struct iwl4965_sched_queue_byte_cnt_tbl + * struct iwl4965_schedq_bc_tbl * * Byte Count table * @@ -947,71 +829,12 @@ struct iwl4965_queue_byte_cnt_entry { * count table for the chosen Tx queue. If the TFD index is 0-63, the driver * must duplicate the byte count entry in corresponding index 256-319. * - * "dont_care" padding puts each byte count table on a 1024-byte boundary; + * padding puts each byte count table on a 1024-byte boundary; * 4965 assumes tables are separated by 1024 bytes. */ -struct iwl4965_sched_queue_byte_cnt_tbl { - struct iwl4965_queue_byte_cnt_entry tfd_offset[IWL49_QUEUE_SIZE + - IWL49_MAX_WIN_SIZE]; - u8 dont_care[1024 - - (IWL49_QUEUE_SIZE + IWL49_MAX_WIN_SIZE) * - sizeof(__le16)]; -} __attribute__ ((packed)); - - -/** - * struct iwl4965_shared - handshake area for Tx and Rx - * - * For convenience in allocating memory, this structure combines 2 areas of - * DRAM which must be shared between driver and 4965. These do not need to - * be combined, if better allocation would result from keeping them separate: - * - * 1) The Tx byte count tables occupy 1024 bytes each (16 KBytes total for - * 16 queues). Driver uses SCD_DRAM_BASE_ADDR to tell 4965 where to find - * the first of these tables. 4965 assumes tables are 1024 bytes apart. - * - * 2) The Rx status (val0 and val1) occupies only 8 bytes. Driver uses - * FH_RSCSR_CHNL0_STTS_WPTR_REG to tell 4965 where to find this area. - * Driver reads val0 to determine the latest Receive Buffer Descriptor (RBD) - * that has been filled by the 4965. - * - * Bit fields val0: - * 31-12: Not used - * 11- 0: Index of last filled Rx buffer descriptor (4965 writes, driver reads) - * - * Bit fields val1: - * 31- 0: Not used - */ -struct iwl4965_shared { - struct iwl4965_sched_queue_byte_cnt_tbl - queues_byte_cnt_tbls[IWL49_NUM_QUEUES]; - __le32 rb_closed; - - /* __le32 rb_closed_stts_rb_num:12; */ -#define IWL_rb_closed_stts_rb_num_POS 0 -#define IWL_rb_closed_stts_rb_num_LEN 12 -#define IWL_rb_closed_stts_rb_num_SYM rb_closed - /* __le32 rsrv1:4; */ - /* __le32 rb_closed_stts_rx_frame_num:12; */ -#define IWL_rb_closed_stts_rx_frame_num_POS 16 -#define IWL_rb_closed_stts_rx_frame_num_LEN 12 -#define IWL_rb_closed_stts_rx_frame_num_SYM rb_closed - /* __le32 rsrv2:4; */ - - __le32 frm_finished; - /* __le32 frame_finished_stts_rb_num:12; */ -#define IWL_frame_finished_stts_rb_num_POS 0 -#define IWL_frame_finished_stts_rb_num_LEN 12 -#define IWL_frame_finished_stts_rb_num_SYM frm_finished - /* __le32 rsrv3:4; */ - /* __le32 frame_finished_stts_rx_frame_num:12; */ -#define IWL_frame_finished_stts_rx_frame_num_POS 16 -#define IWL_frame_finished_stts_rx_frame_num_LEN 12 -#define IWL_frame_finished_stts_rx_frame_num_SYM frm_finished - /* __le32 rsrv4:4; */ - - __le32 padding1; /* so that allocation will be aligned to 16B */ - __le32 padding2; +struct iwl4965_scd_bc_tbl { + __le16 tfd_offset[TFD_QUEUE_BC_SIZE]; + u8 pad[1024 - (TFD_QUEUE_BC_SIZE) * sizeof(__le16)]; } __attribute__ ((packed)); -#endif /* __iwl4965_4965_hw_h__ */ +#endif /* !__iwl_4965_hw_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 9838de5f436918762c0fafdca82102ea01993094..5a72bc0377ded292dcfd7048b9fbfc86373eab4e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -48,18 +48,21 @@ static int iwl4965_send_tx_power(struct iwl_priv *priv); static int iwl4965_hw_get_temperature(const struct iwl_priv *priv); -/* Change firmware file name, using "-" and incrementing number, - * *only* when uCode interface or architecture changes so that it - * is not compatible with earlier drivers. - * This number will also appear in << 8 position of 1st dword of uCode file */ -#define IWL4965_UCODE_API "-2" +/* Highest firmware API version supported */ +#define IWL4965_UCODE_API_MAX 2 + +/* Lowest firmware API version supported */ +#define IWL4965_UCODE_API_MIN 2 + +#define IWL4965_FW_PRE "iwlwifi-4965-" +#define _IWL4965_MODULE_FIRMWARE(api) IWL4965_FW_PRE #api ".ucode" +#define IWL4965_MODULE_FIRMWARE(api) _IWL4965_MODULE_FIRMWARE(api) /* module parameters */ static struct iwl_mod_params iwl4965_mod_params = { .num_of_queues = IWL49_NUM_QUEUES, .num_of_ampdu_queues = IWL49_NUM_AMPDU_QUEUES, - .enable_qos = 1, .amsdu_size_8K = 1, .restart_fw = 1, /* the rest are 0 by default */ @@ -246,7 +249,7 @@ static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv) iwl_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG, priv->ucode_data.len); - /* Inst bytecount must be last to set up, bit 31 signals uCode + /* Inst byte count must be last to set up, bit 31 signals uCode * that all new ptr/size info is in place */ iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, priv->ucode_code.len | BSM_DRAM_INST_LOAD); @@ -318,31 +321,13 @@ static int is_fat_channel(__le32 rxon_flags) /* * EEPROM handlers */ - -static int iwl4965_eeprom_check_version(struct iwl_priv *priv) +static u16 iwl4965_eeprom_calib_version(struct iwl_priv *priv) { - u16 eeprom_ver; - u16 calib_ver; - - eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); - - calib_ver = iwl_eeprom_query16(priv, EEPROM_4965_CALIB_VERSION_OFFSET); - - if (eeprom_ver < EEPROM_4965_EEPROM_VERSION || - calib_ver < EEPROM_4965_TX_POWER_VERSION) - goto err; - - return 0; -err: - IWL_ERROR("Unsuported EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n", - eeprom_ver, EEPROM_4965_EEPROM_VERSION, - calib_ver, EEPROM_4965_TX_POWER_VERSION); - return -EINVAL; - + return iwl_eeprom_query16(priv, EEPROM_4965_CALIB_VERSION_OFFSET); } /* - * Activate/Deactivat Tx DMA/FIFO channels according tx fifos mask + * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask * must be called under priv->lock and mac access */ static void iwl4965_txq_set_sched(struct iwl_priv *priv, u32 mask) @@ -366,9 +351,8 @@ static int iwl4965_apm_init(struct iwl_priv *priv) iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); /* wait for clock stabilization */ - ret = iwl_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (ret < 0) { IWL_DEBUG_INFO("Failed to init the card\n"); goto out; @@ -414,7 +398,7 @@ static void iwl4965_nic_config(struct iwl_priv *priv) /* L1 is enabled by BIOS */ if ((link & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN) - /* diable L0S disabled L1A enabled */ + /* disable L0S disabled L1A enabled */ iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); else /* L0S enabled L1A disabled */ @@ -442,7 +426,6 @@ static void iwl4965_nic_config(struct iwl_priv *priv) static int iwl4965_apm_stop_master(struct iwl_priv *priv) { - int ret = 0; unsigned long flags; spin_lock_irqsave(&priv->lock, flags); @@ -450,17 +433,13 @@ static int iwl4965_apm_stop_master(struct iwl_priv *priv) /* set stop master bit */ iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); - ret = iwl_poll_bit(priv, CSR_RESET, - CSR_RESET_REG_FLAG_MASTER_DISABLED, - CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); - if (ret < 0) - goto out; + iwl_poll_direct_bit(priv, CSR_RESET, + CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); -out: spin_unlock_irqrestore(&priv->lock, flags); IWL_DEBUG_INFO("stop master\n"); - return ret; + return 0; } static void iwl4965_apm_stop(struct iwl_priv *priv) @@ -496,11 +475,9 @@ static int iwl4965_apm_reset(struct iwl_priv *priv) iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - ret = iwl_poll_bit(priv, CSR_RESET, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25); - - if (ret) + ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + if (ret < 0) goto out; udelay(10); @@ -537,10 +514,10 @@ static void iwl4965_chain_noise_reset(struct iwl_priv *priv) struct iwl_chain_noise_data *data = &(priv->chain_noise_data); if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) { - struct iwl4965_calibration_cmd cmd; + struct iwl_calib_diff_gain_cmd cmd; memset(&cmd, 0, sizeof(cmd)); - cmd.opCode = PHY_CALIBRATE_DIFF_GAIN_CMD; + cmd.hdr.op_code = IWL_PHY_CALIBRATE_DIFF_GAIN_CMD; cmd.diff_gain_a = 0; cmd.diff_gain_b = 0; cmd.diff_gain_c = 0; @@ -587,11 +564,11 @@ static void iwl4965_gain_computation(struct iwl_priv *priv, /* Differential gain gets sent to uCode only once */ if (!data->radio_write) { - struct iwl4965_calibration_cmd cmd; + struct iwl_calib_diff_gain_cmd cmd; data->radio_write = 1; memset(&cmd, 0, sizeof(cmd)); - cmd.opCode = PHY_CALIBRATE_DIFF_GAIN_CMD; + cmd.hdr.op_code = IWL_PHY_CALIBRATE_DIFF_GAIN_CMD; cmd.diff_gain_a = data->delta_gain_code[0]; cmd.diff_gain_b = data->delta_gain_code[1]; cmd.diff_gain_c = data->delta_gain_code[2]; @@ -619,10 +596,10 @@ static void iwl4965_gain_computation(struct iwl_priv *priv, static void iwl4965_rts_tx_cmd_flag(struct ieee80211_tx_info *info, __le32 *tx_flags) { - if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) { *tx_flags |= TX_CMD_FLG_RTS_MSK; *tx_flags &= ~TX_CMD_FLG_CTS_MSK; - } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { + } else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { *tx_flags &= ~TX_CMD_FLG_RTS_MSK; *tx_flags |= TX_CMD_FLG_CTS_MSK; } @@ -643,7 +620,7 @@ static void iwl4965_bg_txpower_work(struct work_struct *work) mutex_lock(&priv->mutex); - /* Regardless of if we are assocaited, we must reconfigure the + /* Regardless of if we are associated, we must reconfigure the * TX power since frames can be sent on non-radar channels while * not associated */ iwl4965_send_tx_power(priv); @@ -679,7 +656,7 @@ static void iwl4965_tx_queue_set_status(struct iwl_priv *priv, int txq_id = txq->q.id; /* Find out whether to activate Tx queue */ - int active = test_bit(txq_id, &priv->txq_ctx_active_msk)?1:0; + int active = test_bit(txq_id, &priv->txq_ctx_active_msk) ? 1 : 0; /* Set up and activate */ iwl_write_prph(priv, IWL49_SCD_QUEUE_STATUS_BITS(txq_id), @@ -709,9 +686,10 @@ static const u16 default_queue_to_tx_fifo[] = { static int iwl4965_alive_notify(struct iwl_priv *priv) { u32 a; - int i = 0; unsigned long flags; int ret; + int i, chan; + u32 reg_val; spin_lock_irqsave(&priv->lock, flags); @@ -733,8 +711,18 @@ static int iwl4965_alive_notify(struct iwl_priv *priv) /* Tel 4965 where to find Tx byte count tables */ iwl_write_prph(priv, IWL49_SCD_DRAM_BASE_ADDR, - (priv->shared_phys + - offsetof(struct iwl4965_shared, queues_byte_cnt_tbls)) >> 10); + priv->scd_bc_tbls.dma >> 10); + + /* Enable DMA channel */ + for (chan = 0; chan < FH49_TCSR_CHNL_NUM ; chan++) + iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(chan), + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE); + + /* Update FH chicken bits */ + reg_val = iwl_read_direct32(priv, FH_TX_CHICKEN_BITS_REG); + iwl_write_direct32(priv, FH_TX_CHICKEN_BITS_REG, + reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN); /* Disable chain mode for all queues */ iwl_write_prph(priv, IWL49_SCD_QUEUECHAIN_SEL, 0); @@ -766,7 +754,7 @@ static int iwl4965_alive_notify(struct iwl_priv *priv) (1 << priv->hw_params.max_txq_num) - 1); /* Activate all Tx DMA/FIFO channels */ - priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 7)); + priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 6)); iwl4965_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0); @@ -822,7 +810,9 @@ static int iwl4965_hw_set_hw_params(struct iwl_priv *priv) } priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues; - priv->hw_params.first_ampdu_q = IWL49_FIRST_AMPDU_QUEUE; + priv->hw_params.dma_chnl_num = FH49_TCSR_CHNL_NUM; + priv->hw_params.scd_bc_tbls_size = + IWL49_NUM_QUEUES * sizeof(struct iwl4965_scd_bc_tbl); priv->hw_params.max_stations = IWL4965_STATION_COUNT; priv->hw_params.bcast_sta_id = IWL4965_BROADCAST_ID; priv->hw_params.max_data_size = IWL49_RTC_DATA_SIZE; @@ -1650,36 +1640,6 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) } #endif -static int iwl4965_shared_mem_rx_idx(struct iwl_priv *priv) -{ - struct iwl4965_shared *s = priv->shared_virt; - return le32_to_cpu(s->rb_closed) & 0xFFF; -} - -static int iwl4965_alloc_shared_mem(struct iwl_priv *priv) -{ - priv->shared_virt = pci_alloc_consistent(priv->pci_dev, - sizeof(struct iwl4965_shared), - &priv->shared_phys); - if (!priv->shared_virt) - return -ENOMEM; - - memset(priv->shared_virt, 0, sizeof(struct iwl4965_shared)); - - priv->rb_closed_offset = offsetof(struct iwl4965_shared, rb_closed); - - return 0; -} - -static void iwl4965_free_shared_mem(struct iwl_priv *priv) -{ - if (priv->shared_virt) - pci_free_consistent(priv->pci_dev, - sizeof(struct iwl4965_shared), - priv->shared_virt, - priv->shared_phys); -} - /** * iwl4965_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array */ @@ -1687,21 +1647,22 @@ static void iwl4965_txq_update_byte_cnt_tbl(struct iwl_priv *priv, struct iwl_tx_queue *txq, u16 byte_cnt) { - int len; + struct iwl4965_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr; int txq_id = txq->q.id; - struct iwl4965_shared *shared_data = priv->shared_virt; + int write_ptr = txq->q.write_ptr; + int len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE; + __le16 bc_ent; - len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE; + WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX); + bc_ent = cpu_to_le16(len & 0xFFF); /* Set up byte count within first 256 entries */ - IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. - tfd_offset[txq->q.write_ptr], byte_cnt, len); + scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent; /* If within first 64 entries, duplicate at end */ - if (txq->q.write_ptr < IWL49_MAX_WIN_SIZE) - IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. - tfd_offset[IWL49_QUEUE_SIZE + txq->q.write_ptr], - byte_cnt, len); + if (write_ptr < TFD_QUEUE_SIZE_BC_DUP) + scd_bc_tbl[txq_id]. + tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent; } /** @@ -1956,7 +1917,7 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id, ra_tid = BUILD_RAxTID(sta_id, tid); /* Modify device's station table to Tx this TID */ - iwl_sta_modify_enable_tid_tx(priv, sta_id, tid); + iwl_sta_tx_modify_enable_tid(priv, sta_id, tid); spin_lock_irqsave(&priv->lock, flags); ret = iwl_grab_nic_access(priv); @@ -2037,7 +1998,7 @@ static inline u32 iwl4965_get_scd_ssn(struct iwl4965_tx_resp *tx_resp) } /** - * iwl4965_tx_status_reply_tx - Handle Tx rspnse for frames in aggregation queue + * iwl4965_tx_status_reply_tx - Handle Tx response for frames in aggregation queue */ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, struct iwl_ht_agg *agg, @@ -2059,7 +2020,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, agg->rate_n_flags = rate_n_flags; agg->bitmap = 0; - /* # frames attempted by Tx command */ + /* num frames attempted by Tx command */ if (agg->frame_count == 1) { /* Only one frame was attempted; no block-ack will arrive */ status = le16_to_cpu(frame_status[0].status); @@ -2070,9 +2031,9 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, agg->frame_count, agg->start_idx, idx); info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]); - info->status.retry_count = tx_resp->failure_frame; + info->status.rates[0].count = tx_resp->failure_frame + 1; info->flags &= ~IEEE80211_TX_CTL_AMPDU; - info->flags |= iwl_is_tx_success(status)? + info->flags |= iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0; iwl_hwrate_to_tx_control(priv, rate_n_flags, info); /* FIXME: code repetition end */ @@ -2158,12 +2119,13 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, int txq_id = SEQ_TO_QUEUE(sequence); int index = SEQ_TO_INDEX(sequence); struct iwl_tx_queue *txq = &priv->txq[txq_id]; + struct ieee80211_hdr *hdr; struct ieee80211_tx_info *info; struct iwl4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; u32 status = le32_to_cpu(tx_resp->u.status); - int tid = MAX_TID_COUNT, sta_id = IWL_INVALID_STATION; - __le16 fc; - struct ieee80211_hdr *hdr; + int tid = MAX_TID_COUNT; + int sta_id; + int freed; u8 *qc = NULL; if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) { @@ -2178,8 +2140,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, memset(&info->status, 0, sizeof(info->status)); hdr = iwl_tx_queue_get_hdr(priv, txq_id, index); - fc = hdr->frame_control; - if (ieee80211_is_data_qos(fc)) { + if (ieee80211_is_data_qos(hdr->frame_control)) { qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & 0xf; } @@ -2194,8 +2155,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, const u32 scd_ssn = iwl4965_get_scd_ssn(tx_resp); struct iwl_ht_agg *agg = NULL; - if (!qc) - return; + WARN_ON(!qc); agg = &priv->stations[sta_id].tid[tid].agg; @@ -2206,54 +2166,49 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; if (txq->q.read_ptr != (scd_ssn & 0xff)) { - int freed, ampdu_q; index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd); IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn " "%d index %d\n", scd_ssn , index); freed = iwl_tx_queue_reclaim(priv, txq_id, index); priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; - if (iwl_queue_space(&txq->q) > txq->q.low_mark && - txq_id >= 0 && priv->mac80211_registered && - agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) { - /* calculate mac80211 ampdu sw queue to wake */ - ampdu_q = txq_id - IWL49_FIRST_AMPDU_QUEUE + - priv->hw->queues; + if (priv->mac80211_registered && + (iwl_queue_space(&txq->q) > txq->q.low_mark) && + (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) { if (agg->state == IWL_AGG_OFF) ieee80211_wake_queue(priv->hw, txq_id); else - ieee80211_wake_queue(priv->hw, ampdu_q); + ieee80211_wake_queue(priv->hw, + txq->swq_id); } - iwl_txq_check_empty(priv, sta_id, tid, txq_id); } } else { - info->status.retry_count = tx_resp->failure_frame; - info->flags |= - iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0; + info->status.rates[0].count = tx_resp->failure_frame + 1; + info->flags |= iwl_is_tx_success(status) ? + IEEE80211_TX_STAT_ACK : 0; iwl_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags), info); - IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags " - "0x%x retries %d\n", txq_id, - iwl_get_tx_fail_reason(status), - status, le32_to_cpu(tx_resp->rate_n_flags), - tx_resp->failure_frame); + IWL_DEBUG_TX_REPLY("TXQ %d status %s (0x%08x) " + "rate_n_flags 0x%x retries %d\n", + txq_id, + iwl_get_tx_fail_reason(status), status, + le32_to_cpu(tx_resp->rate_n_flags), + tx_resp->failure_frame); - IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); - - if (index != -1) { - int freed = iwl_tx_queue_reclaim(priv, txq_id, index); - if (tid != MAX_TID_COUNT) + freed = iwl_tx_queue_reclaim(priv, txq_id, index); + if (qc && likely(sta_id != IWL_INVALID_STATION)) priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; - if (iwl_queue_space(&txq->q) > txq->q.low_mark && - (txq_id >= 0) && priv->mac80211_registered) + + if (priv->mac80211_registered && + (iwl_queue_space(&txq->q) > txq->q.low_mark)) ieee80211_wake_queue(priv->hw, txq_id); - if (tid != MAX_TID_COUNT) - iwl_txq_check_empty(priv, sta_id, tid, txq_id); - } } + if (qc && likely(sta_id != IWL_INVALID_STATION)) + iwl_txq_check_empty(priv, sta_id, tid, txq_id); + if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK)) IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n"); } @@ -2328,9 +2283,6 @@ static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = { static struct iwl_lib_ops iwl4965_lib = { .set_hw_params = iwl4965_hw_set_hw_params, - .alloc_shared_mem = iwl4965_alloc_shared_mem, - .free_shared_mem = iwl4965_free_shared_mem, - .shared_mem_rx_idx = iwl4965_shared_mem_rx_idx, .txq_update_byte_cnt_tbl = iwl4965_txq_update_byte_cnt_tbl, .txq_set_sched = iwl4965_txq_set_sched, .txq_agg_enable = iwl4965_txq_agg_enable, @@ -2347,7 +2299,7 @@ static struct iwl_lib_ops iwl4965_lib = { .reset = iwl4965_apm_reset, .stop = iwl4965_apm_stop, .config = iwl4965_nic_config, - .set_pwr_src = iwl4965_set_pwr_src, + .set_pwr_src = iwl_set_pwr_src, }, .eeprom_ops = { .regulatory_bands = { @@ -2362,11 +2314,11 @@ static struct iwl_lib_ops iwl4965_lib = { .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, .release_semaphore = iwlcore_eeprom_release_semaphore, - .check_version = iwl4965_eeprom_check_version, + .calib_version = iwl4965_eeprom_calib_version, .query_addr = iwlcore_eeprom_query_addr, }, .send_tx_power = iwl4965_send_tx_power, - .update_chain_flags = iwl4965_update_chain_flags, + .update_chain_flags = iwl_update_chain_flags, .temperature = iwl4965_temperature_calib, }; @@ -2378,15 +2330,19 @@ static struct iwl_ops iwl4965_ops = { struct iwl_cfg iwl4965_agn_cfg = { .name = "4965AGN", - .fw_name = "iwlwifi-4965" IWL4965_UCODE_API ".ucode", + .fw_name_pre = IWL4965_FW_PRE, + .ucode_api_max = IWL4965_UCODE_API_MAX, + .ucode_api_min = IWL4965_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .eeprom_size = IWL4965_EEPROM_IMG_SIZE, + .eeprom_ver = EEPROM_4965_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_4965_TX_POWER_VERSION, .ops = &iwl4965_ops, .mod_params = &iwl4965_mod_params, }; /* Module firmware */ -MODULE_FIRMWARE("iwlwifi-4965" IWL4965_UCODE_API ".ucode"); +MODULE_FIRMWARE(IWL4965_MODULE_FIRMWARE(IWL4965_UCODE_API_MAX)); module_param_named(antenna, iwl4965_mod_params.antenna, int, 0444); MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])"); @@ -2394,7 +2350,7 @@ module_param_named(disable, iwl4965_mod_params.disable, int, 0444); MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])"); module_param_named(swcrypto, iwl4965_mod_params.sw_crypto, int, 0444); MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])"); -module_param_named(debug, iwl4965_mod_params.debug, int, 0444); +module_param_named(debug, iwl4965_mod_params.debug, uint, 0444); MODULE_PARM_DESC(debug, "debug output mask"); module_param_named( disable_hw_scan, iwl4965_mod_params.disable_hw_scan, int, 0444); @@ -2402,9 +2358,6 @@ MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); module_param_named(queues_num, iwl4965_mod_params.num_of_queues, int, 0444); MODULE_PARM_DESC(queues_num, "number of hw queues."); -/* QoS */ -module_param_named(qos_enable, iwl4965_mod_params.enable_qos, int, 0444); -MODULE_PARM_DESC(qos_enable, "enable all QoS functionality"); /* 11n */ module_param_named(11n_disable, iwl4965_mod_params.disable_11n, int, 0444); MODULE_PARM_DESC(11n_disable, "disable 11n functionality"); diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h index c479ee211c5cf14d322db770c0c9e91a17a9e27a..82c3859ce0f8bf8fb95ac751ef53810984986458 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -73,69 +73,27 @@ #define IWL50_RTC_INST_SIZE (IWL50_RTC_INST_UPPER_BOUND - RTC_INST_LOWER_BOUND) #define IWL50_RTC_DATA_SIZE (IWL50_RTC_DATA_UPPER_BOUND - RTC_DATA_LOWER_BOUND) -/* EERPROM */ +/* EEPROM */ #define IWL_5000_EEPROM_IMG_SIZE 2048 - -#define IWL50_MAX_WIN_SIZE 64 -#define IWL50_QUEUE_SIZE 256 #define IWL50_CMD_FIFO_NUM 7 #define IWL50_NUM_QUEUES 20 #define IWL50_NUM_AMPDU_QUEUES 10 #define IWL50_FIRST_AMPDU_QUEUE 10 -#define IWL_sta_id_POS 12 -#define IWL_sta_id_LEN 4 -#define IWL_sta_id_SYM val - /* Fixed (non-configurable) rx data from phy */ -/* Base physical address of iwl5000_shared is provided to SCD_DRAM_BASE_ADDR - * and &iwl5000_shared.val0 is provided to FH_RSCSR_CHNL0_STTS_WPTR_REG */ -struct iwl5000_sched_queue_byte_cnt_tbl { - struct iwl4965_queue_byte_cnt_entry tfd_offset[IWL50_QUEUE_SIZE + - IWL50_MAX_WIN_SIZE]; -} __attribute__ ((packed)); - -struct iwl5000_shared { - struct iwl5000_sched_queue_byte_cnt_tbl - queues_byte_cnt_tbls[IWL50_NUM_QUEUES]; - __le32 rb_closed; - - /* __le32 rb_closed_stts_rb_num:12; */ -#define IWL_rb_closed_stts_rb_num_POS 0 -#define IWL_rb_closed_stts_rb_num_LEN 12 -#define IWL_rb_closed_stts_rb_num_SYM rb_closed - /* __le32 rsrv1:4; */ - /* __le32 rb_closed_stts_rx_frame_num:12; */ -#define IWL_rb_closed_stts_rx_frame_num_POS 16 -#define IWL_rb_closed_stts_rx_frame_num_LEN 12 -#define IWL_rb_closed_stts_rx_frame_num_SYM rb_closed - /* __le32 rsrv2:4; */ - - __le32 frm_finished; - /* __le32 frame_finished_stts_rb_num:12; */ -#define IWL_frame_finished_stts_rb_num_POS 0 -#define IWL_frame_finished_stts_rb_num_LEN 12 -#define IWL_frame_finished_stts_rb_num_SYM frm_finished - /* __le32 rsrv3:4; */ - /* __le32 frame_finished_stts_rx_frame_num:12; */ -#define IWL_frame_finished_stts_rx_frame_num_POS 16 -#define IWL_frame_finished_stts_rx_frame_num_LEN 12 -#define IWL_frame_finished_stts_rx_frame_num_SYM frm_finished - /* __le32 rsrv4:4; */ - - __le32 padding1; /* so that allocation will be aligned to 16B */ - __le32 padding2; +/** + * struct iwl5000_schedq_bc_tbl scheduler byte count table + * base physical address of iwl5000_shared + * is provided to SCD_DRAM_BASE_ADDR + * @tfd_offset 0-12 - tx command byte count + * 12-16 - station index + */ +struct iwl5000_scd_bc_tbl { + __le16 tfd_offset[TFD_QUEUE_BC_SIZE]; } __attribute__ ((packed)); -/* calibrations defined for 5000 */ -/* defines the order in which results should be sent to the runtime uCode */ -enum iwl5000_calib { - IWL5000_CALIB_LO, - IWL5000_CALIB_TX_IQ, - IWL5000_CALIB_TX_IQ_PERD, -}; #endif /* __iwl_5000_hw_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 5155b8a760a7299cd5b01ae139821ec3c5dd0fe1..66d053d28a7470dbb395dd57202edb224cd36b15 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -44,7 +44,21 @@ #include "iwl-helpers.h" #include "iwl-5000-hw.h" -#define IWL5000_UCODE_API "-1" +/* Highest firmware API version supported */ +#define IWL5000_UCODE_API_MAX 1 +#define IWL5150_UCODE_API_MAX 1 + +/* Lowest firmware API version supported */ +#define IWL5000_UCODE_API_MIN 1 +#define IWL5150_UCODE_API_MIN 1 + +#define IWL5000_FW_PRE "iwlwifi-5000-" +#define _IWL5000_MODULE_FIRMWARE(api) IWL5000_FW_PRE #api ".ucode" +#define IWL5000_MODULE_FIRMWARE(api) _IWL5000_MODULE_FIRMWARE(api) + +#define IWL5150_FW_PRE "iwlwifi-5150-" +#define _IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE #api ".ucode" +#define IWL5150_MODULE_FIRMWARE(api) _IWL5150_MODULE_FIRMWARE(api) static const u16 iwl5000_default_queue_to_tx_fifo[] = { IWL_TX_FIFO_AC3, @@ -59,7 +73,6 @@ static const u16 iwl5000_default_queue_to_tx_fifo[] = { /* FIXME: same implementation as 4965 */ static int iwl5000_apm_stop_master(struct iwl_priv *priv) { - int ret = 0; unsigned long flags; spin_lock_irqsave(&priv->lock, flags); @@ -67,17 +80,13 @@ static int iwl5000_apm_stop_master(struct iwl_priv *priv) /* set stop master bit */ iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); - ret = iwl_poll_bit(priv, CSR_RESET, - CSR_RESET_REG_FLAG_MASTER_DISABLED, + iwl_poll_direct_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); - if (ret < 0) - goto out; -out: spin_unlock_irqrestore(&priv->lock, flags); IWL_DEBUG_INFO("stop master\n"); - return ret; + return 0; } @@ -92,7 +101,7 @@ static int iwl5000_apm_init(struct iwl_priv *priv) iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); - /* Set FH wait treshold to maximum (HW error during stress W/A) */ + /* Set FH wait threshold to maximum (HW error during stress W/A) */ iwl_set_bit(priv, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL); /* enable HAP INTA to move device L1a -> L0s */ @@ -106,9 +115,8 @@ static int iwl5000_apm_init(struct iwl_priv *priv) iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); /* wait for clock stabilization */ - ret = iwl_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (ret < 0) { IWL_DEBUG_INFO("Failed to init the card\n"); return ret; @@ -132,7 +140,7 @@ static int iwl5000_apm_init(struct iwl_priv *priv) return ret; } -/* FIXME: this is indentical to 4965 */ +/* FIXME: this is identical to 4965 */ static void iwl5000_apm_stop(struct iwl_priv *priv) { unsigned long flags; @@ -175,9 +183,8 @@ static int iwl5000_apm_reset(struct iwl_priv *priv) iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); /* wait for clock stabilization */ - ret = iwl_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (ret < 0) { IWL_DEBUG_INFO("Failed to init the card\n"); goto out; @@ -217,7 +224,7 @@ static void iwl5000_nic_config(struct iwl_priv *priv) /* L1 is enabled by BIOS */ if ((link & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN) - /* diable L0S disabled L1A enabled */ + /* disable L0S disabled L1A enabled */ iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); else /* L0S enabled L1A disabled */ @@ -291,30 +298,17 @@ static u32 eeprom_indirect_address(const struct iwl_priv *priv, u32 address) return (address & ADDRESS_MSK) + (offset << 1); } -static int iwl5000_eeprom_check_version(struct iwl_priv *priv) +static u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv) { - u16 eeprom_ver; struct iwl_eeprom_calib_hdr { u8 version; u8 pa_type; u16 voltage; } *hdr; - eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); - hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(priv, EEPROM_5000_CALIB_ALL); - - if (eeprom_ver < EEPROM_5000_EEPROM_VERSION || - hdr->version < EEPROM_5000_TX_POWER_VERSION) - goto err; - - return 0; -err: - IWL_ERROR("Unsuported EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n", - eeprom_ver, EEPROM_5000_EEPROM_VERSION, - hdr->version, EEPROM_5000_TX_POWER_VERSION); - return -EINVAL; + return hdr->version; } @@ -348,10 +342,14 @@ static void iwl5000_gain_computation(struct iwl_priv *priv, data->delta_gain_code[1], data->delta_gain_code[2]); if (!data->radio_write) { - struct iwl5000_calibration_chain_noise_gain_cmd cmd; + struct iwl_calib_chain_noise_gain_cmd cmd; + memset(&cmd, 0, sizeof(cmd)); - cmd.op_code = IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD; + cmd.hdr.op_code = IWL_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD; + cmd.hdr.first_group = 0; + cmd.hdr.groups_num = 1; + cmd.hdr.data_valid = 1; cmd.delta_gain_1 = data->delta_gain_code[1]; cmd.delta_gain_2 = data->delta_gain_code[2]; iwl_send_cmd_pdu_async(priv, REPLY_PHY_CALIBRATION_CMD, @@ -373,14 +371,19 @@ static void iwl5000_gain_computation(struct iwl_priv *priv, static void iwl5000_chain_noise_reset(struct iwl_priv *priv) { struct iwl_chain_noise_data *data = &priv->chain_noise_data; + int ret; if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) { - struct iwl5000_calibration_chain_noise_reset_cmd cmd; - + struct iwl_calib_chain_noise_reset_cmd cmd; memset(&cmd, 0, sizeof(cmd)); - cmd.op_code = IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD; - if (iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, - sizeof(cmd), &cmd)) + + cmd.hdr.op_code = IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD; + cmd.hdr.first_group = 0; + cmd.hdr.groups_num = 1; + cmd.hdr.data_valid = 1; + ret = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, + sizeof(cmd), &cmd); + if (ret) IWL_ERROR("Could not send REPLY_PHY_CALIBRATION_CMD\n"); data->state = IWL_CHAIN_NOISE_ACCUMULATE; IWL_DEBUG_CALIB("Run chain_noise_calibrate\n"); @@ -390,8 +393,8 @@ static void iwl5000_chain_noise_reset(struct iwl_priv *priv) static void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info, __le32 *tx_flags) { - if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) || - (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) + if ((info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || + (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) *tx_flags |= TX_CMD_FLG_RTS_CTS_MSK; else *tx_flags &= ~TX_CMD_FLG_RTS_CTS_MSK; @@ -426,31 +429,41 @@ static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, return &priv->eeprom[address]; } +static s32 iwl5150_get_ct_threshold(struct iwl_priv *priv) +{ + const s32 volt2temp_coef = -5; + u16 *temp_calib = (u16 *)iwl_eeprom_query_addr(priv, + EEPROM_5000_TEMPERATURE); + /* offset = temperate - voltage / coef */ + s32 offset = temp_calib[0] - temp_calib[1] / volt2temp_coef; + s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD) - offset; + return threshold * volt2temp_coef; +} + /* * Calibration */ -static int iwl5000_send_Xtal_calib(struct iwl_priv *priv) +static int iwl5000_set_Xtal_calib(struct iwl_priv *priv) { + struct iwl_calib_xtal_freq_cmd cmd; u16 *xtal_calib = (u16 *)iwl_eeprom_query_addr(priv, EEPROM_5000_XTAL); - struct iwl5000_calibration cal_cmd = { - .op_code = IWL5000_PHY_CALIBRATE_CRYSTAL_FRQ_CMD, - .data = { - (u8)xtal_calib[0], - (u8)xtal_calib[1], - } - }; - - return iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, - sizeof(cal_cmd), &cal_cmd); + cmd.hdr.op_code = IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD; + cmd.hdr.first_group = 0; + cmd.hdr.groups_num = 1; + cmd.hdr.data_valid = 1; + cmd.cap_pin1 = (u8)xtal_calib[0]; + cmd.cap_pin2 = (u8)xtal_calib[1]; + return iwl_calib_set(&priv->calib_results[IWL_CALIB_XTAL], + (u8 *)&cmd, sizeof(cmd)); } static int iwl5000_send_calib_cfg(struct iwl_priv *priv) { - struct iwl5000_calib_cfg_cmd calib_cfg_cmd; + struct iwl_calib_cfg_cmd calib_cfg_cmd; struct iwl_host_cmd cmd = { .id = CALIBRATION_CFG_CMD, - .len = sizeof(struct iwl5000_calib_cfg_cmd), + .len = sizeof(struct iwl_calib_cfg_cmd), .data = &calib_cfg_cmd, }; @@ -467,7 +480,7 @@ static void iwl5000_rx_calib_result(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { struct iwl_rx_packet *pkt = (void *)rxb->skb->data; - struct iwl5000_calib_hdr *hdr = (struct iwl5000_calib_hdr *)pkt->u.raw; + struct iwl_calib_hdr *hdr = (struct iwl_calib_hdr *)pkt->u.raw; int len = le32_to_cpu(pkt->len) & FH_RSCSR_FRAME_SIZE_MSK; int index; @@ -478,14 +491,20 @@ static void iwl5000_rx_calib_result(struct iwl_priv *priv, * uCode. iwl_send_calib_results sends them in a row according to their * index. We sort them here */ switch (hdr->op_code) { - case IWL5000_PHY_CALIBRATE_LO_CMD: - index = IWL5000_CALIB_LO; + case IWL_PHY_CALIBRATE_DC_CMD: + index = IWL_CALIB_DC; + break; + case IWL_PHY_CALIBRATE_LO_CMD: + index = IWL_CALIB_LO; break; - case IWL5000_PHY_CALIBRATE_TX_IQ_CMD: - index = IWL5000_CALIB_TX_IQ; + case IWL_PHY_CALIBRATE_TX_IQ_CMD: + index = IWL_CALIB_TX_IQ; break; - case IWL5000_PHY_CALIBRATE_TX_IQ_PERD_CMD: - index = IWL5000_CALIB_TX_IQ_PERD; + case IWL_PHY_CALIBRATE_TX_IQ_PERD_CMD: + index = IWL_CALIB_TX_IQ_PERD; + break; + case IWL_PHY_CALIBRATE_BASE_BAND_CMD: + index = IWL_CALIB_BASE_BAND; break; default: IWL_ERROR("Unknown calibration notification %d\n", @@ -535,7 +554,7 @@ static int iwl5000_load_section(struct iwl_priv *priv, iwl_write_direct32(priv, FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL), - (iwl_get_dma_hi_address(phy_addr) + (iwl_get_dma_hi_addr(phy_addr) << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt); iwl_write_direct32(priv, @@ -547,7 +566,7 @@ static int iwl5000_load_section(struct iwl_priv *priv, iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL), FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | - FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL | + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE | FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD); iwl_release_nic_access(priv); @@ -561,14 +580,13 @@ static int iwl5000_load_given_ucode(struct iwl_priv *priv, { int ret = 0; - ret = iwl5000_load_section( - priv, inst_image, RTC_INST_LOWER_BOUND); + ret = iwl5000_load_section(priv, inst_image, RTC_INST_LOWER_BOUND); if (ret) return ret; IWL_DEBUG_INFO("INST uCode section being loaded...\n"); ret = wait_event_interruptible_timeout(priv->wait_command_queue, - priv->ucode_write_complete, 5 * HZ); + priv->ucode_write_complete, 5 * HZ); if (ret == -ERESTARTSYS) { IWL_ERROR("Could not load the INST uCode section due " "to interrupt\n"); @@ -682,7 +700,7 @@ static void iwl5000_tx_queue_set_status(struct iwl_priv *priv, int tx_fifo_id, int scd_retry) { int txq_id = txq->q.id; - int active = test_bit(txq_id, &priv->txq_ctx_active_msk)?1:0; + int active = test_bit(txq_id, &priv->txq_ctx_active_msk) ? 1 : 0; iwl_write_prph(priv, IWL50_SCD_QUEUE_STATUS_BITS(txq_id), (active << IWL50_SCD_QUEUE_STTS_REG_POS_ACTIVE) | @@ -710,9 +728,10 @@ static int iwl5000_send_wimax_coex(struct iwl_priv *priv) static int iwl5000_alive_notify(struct iwl_priv *priv) { u32 a; - int i = 0; unsigned long flags; int ret; + int i, chan; + u32 reg_val; spin_lock_irqsave(&priv->lock, flags); @@ -734,11 +753,21 @@ static int iwl5000_alive_notify(struct iwl_priv *priv) iwl_write_targ_mem(priv, a, 0); iwl_write_prph(priv, IWL50_SCD_DRAM_BASE_ADDR, - (priv->shared_phys + - offsetof(struct iwl5000_shared, queues_byte_cnt_tbls)) >> 10); + priv->scd_bc_tbls.dma >> 10); + + /* Enable DMA channel */ + for (chan = 0; chan < FH50_TCSR_CHNL_NUM ; chan++) + iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(chan), + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE); + + /* Update FH chicken bits */ + reg_val = iwl_read_direct32(priv, FH_TX_CHICKEN_BITS_REG); + iwl_write_direct32(priv, FH_TX_CHICKEN_BITS_REG, + reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN); + iwl_write_prph(priv, IWL50_SCD_QUEUECHAIN_SEL, - IWL50_SCD_QUEUECHAIN_SEL_ALL( - priv->hw_params.max_txq_num)); + IWL50_SCD_QUEUECHAIN_SEL_ALL(priv->hw_params.max_txq_num)); iwl_write_prph(priv, IWL50_SCD_AGGR_SEL, 0); /* initiate the queues */ @@ -765,6 +794,7 @@ static int iwl5000_alive_notify(struct iwl_priv *priv) priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 7)); iwl5000_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0); + /* map qos queues to fifos one-to-one */ for (i = 0; i < ARRAY_SIZE(iwl5000_default_queue_to_tx_fifo); i++) { int ac = iwl5000_default_queue_to_tx_fifo[i]; @@ -784,10 +814,8 @@ static int iwl5000_alive_notify(struct iwl_priv *priv) iwl5000_send_wimax_coex(priv); - iwl5000_send_Xtal_calib(priv); - - if (priv->ucode_type == UCODE_RT) - iwl_send_calib_results(priv); + iwl5000_set_Xtal_calib(priv); + iwl_send_calib_results(priv); return 0; } @@ -802,7 +830,9 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) } priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues; - priv->hw_params.first_ampdu_q = IWL50_FIRST_AMPDU_QUEUE; + priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; + priv->hw_params.scd_bc_tbls_size = + IWL50_NUM_QUEUES * sizeof(struct iwl5000_scd_bc_tbl); priv->hw_params.max_stations = IWL5000_STATION_COUNT; priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID; priv->hw_params.max_data_size = IWL50_RTC_DATA_SIZE; @@ -814,10 +844,14 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { case CSR_HW_REV_TYPE_5100: + priv->hw_params.tx_chains_num = 1; + priv->hw_params.rx_chains_num = 2; + priv->hw_params.valid_tx_ant = ANT_B; + priv->hw_params.valid_rx_ant = ANT_AB; + break; case CSR_HW_REV_TYPE_5150: priv->hw_params.tx_chains_num = 1; priv->hw_params.rx_chains_num = 2; - /* FIXME: move to ANT_A, ANT_B, ANT_C enum */ priv->hw_params.valid_tx_ant = ANT_A; priv->hw_params.valid_rx_ant = ANT_AB; break; @@ -840,43 +874,36 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) case CSR_HW_REV_TYPE_5150: /* 5150 wants in Kelvin */ priv->hw_params.ct_kill_threshold = - CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD); + iwl5150_get_ct_threshold(priv); break; } - return 0; -} - -static int iwl5000_alloc_shared_mem(struct iwl_priv *priv) -{ - priv->shared_virt = pci_alloc_consistent(priv->pci_dev, - sizeof(struct iwl5000_shared), - &priv->shared_phys); - if (!priv->shared_virt) - return -ENOMEM; + /* Set initial calibration set */ + switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { + case CSR_HW_REV_TYPE_5100: + case CSR_HW_REV_TYPE_5300: + case CSR_HW_REV_TYPE_5350: + priv->hw_params.calib_init_cfg = + BIT(IWL_CALIB_XTAL) | + BIT(IWL_CALIB_LO) | + BIT(IWL_CALIB_TX_IQ) | + BIT(IWL_CALIB_TX_IQ_PERD) | + BIT(IWL_CALIB_BASE_BAND); + break; + case CSR_HW_REV_TYPE_5150: + priv->hw_params.calib_init_cfg = + BIT(IWL_CALIB_DC) | + BIT(IWL_CALIB_LO) | + BIT(IWL_CALIB_TX_IQ) | + BIT(IWL_CALIB_BASE_BAND); - memset(priv->shared_virt, 0, sizeof(struct iwl5000_shared)); + break; + } - priv->rb_closed_offset = offsetof(struct iwl5000_shared, rb_closed); return 0; } -static void iwl5000_free_shared_mem(struct iwl_priv *priv) -{ - if (priv->shared_virt) - pci_free_consistent(priv->pci_dev, - sizeof(struct iwl5000_shared), - priv->shared_virt, - priv->shared_phys); -} - -static int iwl5000_shared_mem_rx_idx(struct iwl_priv *priv) -{ - struct iwl5000_shared *s = priv->shared_virt; - return le32_to_cpu(s->rb_closed) & 0xFFF; -} - /** * iwl5000_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array */ @@ -884,16 +911,18 @@ static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv, struct iwl_tx_queue *txq, u16 byte_cnt) { - struct iwl5000_shared *shared_data = priv->shared_virt; + struct iwl5000_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr; + int write_ptr = txq->q.write_ptr; int txq_id = txq->q.id; u8 sec_ctl = 0; - u8 sta = 0; - int len; + u8 sta_id = 0; + u16 len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE; + __le16 bc_ent; - len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE; + WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX); if (txq_id != IWL_CMD_QUEUE_NUM) { - sta = txq->cmd[txq->q.write_ptr]->cmd.tx.sta_id; + sta_id = txq->cmd[txq->q.write_ptr]->cmd.tx.sta_id; sec_ctl = txq->cmd[txq->q.write_ptr]->cmd.tx.sec_ctl; switch (sec_ctl & TX_CMD_SEC_MSK) { @@ -909,40 +938,35 @@ static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv, } } - IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. - tfd_offset[txq->q.write_ptr], byte_cnt, len); + bc_ent = cpu_to_le16((len & 0xFFF) | (sta_id << 12)); - IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. - tfd_offset[txq->q.write_ptr], sta_id, sta); + scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent; - if (txq->q.write_ptr < IWL50_MAX_WIN_SIZE) { - IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. - tfd_offset[IWL50_QUEUE_SIZE + txq->q.write_ptr], - byte_cnt, len); - IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. - tfd_offset[IWL50_QUEUE_SIZE + txq->q.write_ptr], - sta_id, sta); - } + if (txq->q.write_ptr < TFD_QUEUE_SIZE_BC_DUP) + scd_bc_tbl[txq_id]. + tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent; } static void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv, struct iwl_tx_queue *txq) { + struct iwl5000_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr; int txq_id = txq->q.id; - struct iwl5000_shared *shared_data = priv->shared_virt; - u8 sta = 0; + int read_ptr = txq->q.read_ptr; + u8 sta_id = 0; + __le16 bc_ent; + + WARN_ON(read_ptr >= TFD_QUEUE_SIZE_MAX); if (txq_id != IWL_CMD_QUEUE_NUM) - sta = txq->cmd[txq->q.read_ptr]->cmd.tx.sta_id; + sta_id = txq->cmd[read_ptr]->cmd.tx.sta_id; - shared_data->queues_byte_cnt_tbls[txq_id].tfd_offset[txq->q.read_ptr]. - val = cpu_to_le16(1 | (sta << 12)); + bc_ent = cpu_to_le16(1 | (sta_id << 12)); + scd_bc_tbl[txq_id].tfd_offset[read_ptr] = bc_ent; - if (txq->q.write_ptr < IWL50_MAX_WIN_SIZE) { - shared_data->queues_byte_cnt_tbls[txq_id]. - tfd_offset[IWL50_QUEUE_SIZE + txq->q.read_ptr]. - val = cpu_to_le16(1 | (sta << 12)); - } + if (txq->q.write_ptr < TFD_QUEUE_SIZE_BC_DUP) + scd_bc_tbl[txq_id]. + tfd_offset[TFD_QUEUE_SIZE_MAX + read_ptr] = bc_ent; } static int iwl5000_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid, @@ -996,7 +1020,7 @@ static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id, ra_tid = BUILD_RAxTID(sta_id, tid); /* Modify device's station table to Tx this TID */ - iwl_sta_modify_enable_tid_tx(priv, sta_id, tid); + iwl_sta_tx_modify_enable_tid(priv, sta_id, tid); spin_lock_irqsave(&priv->lock, flags); ret = iwl_grab_nic_access(priv); @@ -1089,7 +1113,7 @@ static u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) /* - * Activate/Deactivat Tx DMA/FIFO channels according tx fifos mask + * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask * must be called under priv->lock and mac access */ static void iwl5000_txq_set_sched(struct iwl_priv *priv, u32 mask) @@ -1136,10 +1160,10 @@ static int iwl5000_tx_status_reply_tx(struct iwl_priv *priv, agg->frame_count, agg->start_idx, idx); info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]); - info->status.retry_count = tx_resp->failure_frame; + info->status.rates[0].count = tx_resp->failure_frame + 1; info->flags &= ~IEEE80211_TX_CTL_AMPDU; - info->flags |= iwl_is_tx_success(status)? - IEEE80211_TX_STAT_ACK : 0; + info->flags |= iwl_is_tx_success(status) ? + IEEE80211_TX_STAT_ACK : 0; iwl_hwrate_to_tx_control(priv, rate_n_flags, info); /* FIXME: code repetition end */ @@ -1225,9 +1249,9 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv, struct ieee80211_tx_info *info; struct iwl5000_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; u32 status = le16_to_cpu(tx_resp->status.status); - int tid = MAX_TID_COUNT, sta_id = IWL_INVALID_STATION; - struct ieee80211_hdr *hdr; - u8 *qc = NULL; + int tid; + int sta_id; + int freed; if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) { IWL_ERROR("Read index for DMA queue txq_id (%d) index %d " @@ -1240,25 +1264,13 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv, info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]); memset(&info->status, 0, sizeof(info->status)); - hdr = iwl_tx_queue_get_hdr(priv, txq_id, index); - if (ieee80211_is_data_qos(hdr->frame_control)) { - qc = ieee80211_get_qos_ctl(hdr); - tid = qc[0] & 0xf; - } - - sta_id = iwl_get_ra_sta_id(priv, hdr); - if (txq->sched_retry && unlikely(sta_id == IWL_INVALID_STATION)) { - IWL_ERROR("Station not known\n"); - return; - } + tid = (tx_resp->ra_tid & IWL50_TX_RES_TID_MSK) >> IWL50_TX_RES_TID_POS; + sta_id = (tx_resp->ra_tid & IWL50_TX_RES_RA_MSK) >> IWL50_TX_RES_RA_POS; if (txq->sched_retry) { const u32 scd_ssn = iwl5000_get_scd_ssn(tx_resp); struct iwl_ht_agg *agg = NULL; - if (!qc) - return; - agg = &priv->stations[sta_id].tid[tid].agg; iwl5000_tx_status_reply_tx(priv, agg, tx_resp, txq_id, index); @@ -1268,58 +1280,58 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv, info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; if (txq->q.read_ptr != (scd_ssn & 0xff)) { - int freed, ampdu_q; index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd); - IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn " - "%d index %d\n", scd_ssn , index); + IWL_DEBUG_TX_REPLY("Retry scheduler reclaim " + "scd_ssn=%d idx=%d txq=%d swq=%d\n", + scd_ssn , index, txq_id, txq->swq_id); + freed = iwl_tx_queue_reclaim(priv, txq_id, index); priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; - if (iwl_queue_space(&txq->q) > txq->q.low_mark && - txq_id >= 0 && priv->mac80211_registered && - agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) { - /* calculate mac80211 ampdu sw queue to wake */ - ampdu_q = txq_id - IWL50_FIRST_AMPDU_QUEUE + - priv->hw->queues; + if (priv->mac80211_registered && + (iwl_queue_space(&txq->q) > txq->q.low_mark) && + (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) { if (agg->state == IWL_AGG_OFF) ieee80211_wake_queue(priv->hw, txq_id); else - ieee80211_wake_queue(priv->hw, ampdu_q); + ieee80211_wake_queue(priv->hw, + txq->swq_id); } - iwl_txq_check_empty(priv, sta_id, tid, txq_id); } } else { - info->status.retry_count = tx_resp->failure_frame; - info->flags = - iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0; + BUG_ON(txq_id != txq->swq_id); + + info->status.rates[0].count = tx_resp->failure_frame + 1; + info->flags |= iwl_is_tx_success(status) ? + IEEE80211_TX_STAT_ACK : 0; iwl_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags), info); - IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags " - "0x%x retries %d\n", txq_id, - iwl_get_tx_fail_reason(status), - status, le32_to_cpu(tx_resp->rate_n_flags), - tx_resp->failure_frame); + IWL_DEBUG_TX_REPLY("TXQ %d status %s (0x%08x) rate_n_flags " + "0x%x retries %d\n", + txq_id, + iwl_get_tx_fail_reason(status), status, + le32_to_cpu(tx_resp->rate_n_flags), + tx_resp->failure_frame); - IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); - if (index != -1) { - int freed = iwl_tx_queue_reclaim(priv, txq_id, index); - if (tid != MAX_TID_COUNT) + freed = iwl_tx_queue_reclaim(priv, txq_id, index); + if (ieee80211_is_data_qos(tx_resp->frame_ctrl)) priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; - if (iwl_queue_space(&txq->q) > txq->q.low_mark && - (txq_id >= 0) && priv->mac80211_registered) + + if (priv->mac80211_registered && + (iwl_queue_space(&txq->q) > txq->q.low_mark)) ieee80211_wake_queue(priv->hw, txq_id); - if (tid != MAX_TID_COUNT) - iwl_txq_check_empty(priv, sta_id, tid, txq_id); - } } + if (ieee80211_is_data_qos(tx_resp->frame_ctrl)) + iwl_txq_check_empty(priv, sta_id, tid, txq_id); + if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK)) IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n"); } -/* Currently 5000 is the supperset of everything */ +/* Currently 5000 is the superset of everything */ static u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len) { return len; @@ -1466,9 +1478,6 @@ static struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = { static struct iwl_lib_ops iwl5000_lib = { .set_hw_params = iwl5000_hw_set_hw_params, - .alloc_shared_mem = iwl5000_alloc_shared_mem, - .free_shared_mem = iwl5000_free_shared_mem, - .shared_mem_rx_idx = iwl5000_shared_mem_rx_idx, .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, .txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl, .txq_set_sched = iwl5000_txq_set_sched, @@ -1482,13 +1491,13 @@ static struct iwl_lib_ops iwl5000_lib = { .alive_notify = iwl5000_alive_notify, .send_tx_power = iwl5000_send_tx_power, .temperature = iwl5000_temperature, - .update_chain_flags = iwl4965_update_chain_flags, + .update_chain_flags = iwl_update_chain_flags, .apm_ops = { .init = iwl5000_apm_init, .reset = iwl5000_apm_reset, .stop = iwl5000_apm_stop, .config = iwl5000_nic_config, - .set_pwr_src = iwl4965_set_pwr_src, + .set_pwr_src = iwl_set_pwr_src, }, .eeprom_ops = { .regulatory_bands = { @@ -1503,7 +1512,7 @@ static struct iwl_lib_ops iwl5000_lib = { .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, .release_semaphore = iwlcore_eeprom_release_semaphore, - .check_version = iwl5000_eeprom_check_version, + .calib_version = iwl5000_eeprom_calib_version, .query_addr = iwl5000_eeprom_query_addr, }, }; @@ -1517,7 +1526,6 @@ static struct iwl_ops iwl5000_ops = { static struct iwl_mod_params iwl50_mod_params = { .num_of_queues = IWL50_NUM_QUEUES, .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, - .enable_qos = 1, .amsdu_size_8K = 1, .restart_fw = 1, /* the rest are 0 by default */ @@ -1526,50 +1534,84 @@ static struct iwl_mod_params iwl50_mod_params = { struct iwl_cfg iwl5300_agn_cfg = { .name = "5300AGN", - .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", + .fw_name_pre = IWL5000_FW_PRE, + .ucode_api_max = IWL5000_UCODE_API_MAX, + .ucode_api_min = IWL5000_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl5000_ops, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_ver = EEPROM_5000_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, }; struct iwl_cfg iwl5100_bg_cfg = { .name = "5100BG", - .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", + .fw_name_pre = IWL5000_FW_PRE, + .ucode_api_max = IWL5000_UCODE_API_MAX, + .ucode_api_min = IWL5000_UCODE_API_MIN, .sku = IWL_SKU_G, .ops = &iwl5000_ops, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_ver = EEPROM_5000_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, }; struct iwl_cfg iwl5100_abg_cfg = { .name = "5100ABG", - .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", + .fw_name_pre = IWL5000_FW_PRE, + .ucode_api_max = IWL5000_UCODE_API_MAX, + .ucode_api_min = IWL5000_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G, .ops = &iwl5000_ops, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_ver = EEPROM_5000_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, }; struct iwl_cfg iwl5100_agn_cfg = { .name = "5100AGN", - .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", + .fw_name_pre = IWL5000_FW_PRE, + .ucode_api_max = IWL5000_UCODE_API_MAX, + .ucode_api_min = IWL5000_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl5000_ops, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_ver = EEPROM_5000_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, }; struct iwl_cfg iwl5350_agn_cfg = { .name = "5350AGN", - .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", + .fw_name_pre = IWL5000_FW_PRE, + .ucode_api_max = IWL5000_UCODE_API_MAX, + .ucode_api_min = IWL5000_UCODE_API_MIN, + .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, + .ops = &iwl5000_ops, + .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_ver = EEPROM_5050_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, + .mod_params = &iwl50_mod_params, +}; + +struct iwl_cfg iwl5150_agn_cfg = { + .name = "5150AGN", + .fw_name_pre = IWL5150_FW_PRE, + .ucode_api_max = IWL5150_UCODE_API_MAX, + .ucode_api_min = IWL5150_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl5000_ops, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_ver = EEPROM_5050_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, }; -MODULE_FIRMWARE("iwlwifi-5000" IWL5000_UCODE_API ".ucode"); +MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE(IWL5150_UCODE_API_MAX)); module_param_named(disable50, iwl50_mod_params.disable, int, 0444); MODULE_PARM_DESC(disable50, @@ -1577,12 +1619,10 @@ MODULE_PARM_DESC(disable50, module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, 0444); MODULE_PARM_DESC(swcrypto50, "using software crypto engine (default 0 [hardware])\n"); -module_param_named(debug50, iwl50_mod_params.debug, int, 0444); +module_param_named(debug50, iwl50_mod_params.debug, uint, 0444); MODULE_PARM_DESC(debug50, "50XX debug output mask"); module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, 0444); MODULE_PARM_DESC(queues_num50, "number of hw queues in 50xx series"); -module_param_named(qos_enable50, iwl50_mod_params.enable_qos, int, 0444); -MODULE_PARM_DESC(qos_enable50, "enable all 50XX QoS functionality"); module_param_named(11n_disable50, iwl50_mod_params.disable_11n, int, 0444); MODULE_PARM_DESC(11n_disable50, "disable 50XX 11n functionality"); module_param_named(amsdu_size_8K50, iwl50_mod_params.amsdu_size_8K, int, 0444); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd-check.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd-check.c new file mode 100644 index 0000000000000000000000000000000000000000..b8137eeae1db87eae6a6dd19fda2e65c8e19712f --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd-check.c @@ -0,0 +1,108 @@ +/****************************************************************************** + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + *****************************************************************************/ + +#include +#include +#include "iwl-dev.h" +#include "iwl-debug.h" +#include "iwl-commands.h" + + +/** + * iwl_check_rxon_cmd - validate RXON structure is valid + * + * NOTE: This is really only useful during development and can eventually + * be #ifdef'd out once the driver is stable and folks aren't actively + * making changes + */ +int iwl_agn_check_rxon_cmd(struct iwl_rxon_cmd *rxon) +{ + int error = 0; + int counter = 1; + + if (rxon->flags & RXON_FLG_BAND_24G_MSK) { + error |= le32_to_cpu(rxon->flags & + (RXON_FLG_TGJ_NARROW_BAND_MSK | + RXON_FLG_RADAR_DETECT_MSK)); + if (error) + IWL_WARNING("check 24G fields %d | %d\n", + counter++, error); + } else { + error |= (rxon->flags & RXON_FLG_SHORT_SLOT_MSK) ? + 0 : le32_to_cpu(RXON_FLG_SHORT_SLOT_MSK); + if (error) + IWL_WARNING("check 52 fields %d | %d\n", + counter++, error); + error |= le32_to_cpu(rxon->flags & RXON_FLG_CCK_MSK); + if (error) + IWL_WARNING("check 52 CCK %d | %d\n", + counter++, error); + } + error |= (rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1; + if (error) + IWL_WARNING("check mac addr %d | %d\n", counter++, error); + + /* make sure basic rates 6Mbps and 1Mbps are supported */ + error |= (((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0) && + ((rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0)); + if (error) + IWL_WARNING("check basic rate %d | %d\n", counter++, error); + + error |= (le16_to_cpu(rxon->assoc_id) > 2007); + if (error) + IWL_WARNING("check assoc id %d | %d\n", counter++, error); + + error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) + == (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)); + if (error) + IWL_WARNING("check CCK and short slot %d | %d\n", + counter++, error); + + error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) + == (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)); + if (error) + IWL_WARNING("check CCK & auto detect %d | %d\n", + counter++, error); + + error |= ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK | + RXON_FLG_TGG_PROTECT_MSK)) == RXON_FLG_TGG_PROTECT_MSK); + if (error) + IWL_WARNING("check TGG and auto detect %d | %d\n", + counter++, error); + + if (error) + IWL_WARNING("Tuning to channel %d\n", + le16_to_cpu(rxon->channel)); + + if (error) { + IWL_ERROR("Not a valid iwl4965_rxon_assoc_cmd field values\n"); + return -1; + } + return 0; +} + diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index e2a58e477036e611da5ffc78abeda5748f7392ce..f3f17929ca0bb1546721f0a1a22e8b7fe2a6dc8d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -38,7 +38,6 @@ #include "iwl-dev.h" #include "iwl-sta.h" #include "iwl-core.h" -#include "iwl-helpers.h" #define RS_NAME "iwl-agn-rs" @@ -188,7 +187,7 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, * 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 60 MBits * "G" is the only table that supports CCK (the first 4 rates). */ -/*FIXME:RS:need to spearate tables for MIMO2/MIMO3*/ +/*FIXME:RS:need to separate tables for MIMO2/MIMO3*/ static s32 expected_tpt_A[IWL_RATE_COUNT] = { 0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186, 186 }; @@ -281,10 +280,9 @@ static u8 rs_tl_add_packet(struct iwl_lq_sta *lq_data, u32 time_diff; s32 index; struct iwl_traffic_load *tl = NULL; - __le16 fc = hdr->frame_control; u8 tid; - if (ieee80211_is_data_qos(fc)) { + if (ieee80211_is_data_qos(hdr->frame_control)) { u8 *qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & 0xf; } else @@ -357,11 +355,9 @@ static void rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv, struct iwl_lq_sta *lq_data, u8 tid, struct ieee80211_sta *sta) { - DECLARE_MAC_BUF(mac); - if (rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) { - IWL_DEBUG_HT("Starting Tx agg: STA: %s tid: %d\n", - print_mac(mac, sta->addr), tid); + IWL_DEBUG_HT("Starting Tx agg: STA: %pM tid: %d\n", + sta->addr, tid); ieee80211_start_tx_ba_session(priv->hw, sta->addr, tid); } } @@ -775,7 +771,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, int status; u8 retries; int rs_index, index = 0; - struct iwl_lq_sta *lq_sta; + struct iwl_lq_sta *lq_sta = priv_sta; struct iwl_link_quality_cmd *table; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct iwl_priv *priv = (struct iwl_priv *)priv_r; @@ -787,12 +783,12 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, struct iwl_scale_tbl_info tbl_type; struct iwl_scale_tbl_info *curr_tbl, *search_tbl; u8 active_index = 0; - __le16 fc = hdr->frame_control; s32 tpt = 0; IWL_DEBUG_RATE_LIMIT("get frame ack response, update rate scale window\n"); - if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) + if (!ieee80211_is_data(hdr->frame_control) || + is_multicast_ether_addr(hdr->addr1)) return; /* This packet was aggregated but doesn't carry rate scale info */ @@ -800,13 +796,11 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, !(info->flags & IEEE80211_TX_STAT_AMPDU)) return; - retries = info->status.retry_count; + retries = info->status.rates[0].count - 1; if (retries > 15) retries = 15; - lq_sta = (struct iwl_lq_sta *)priv_sta; - if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && !lq_sta->ibss_sta_added) goto out; @@ -832,21 +826,20 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, if (priv->band == IEEE80211_BAND_5GHZ) rs_index -= IWL_FIRST_OFDM_RATE; - if ((info->tx_rate_idx < 0) || - (tbl_type.is_SGI ^ - !!(info->flags & IEEE80211_TX_CTL_SHORT_GI)) || - (tbl_type.is_fat ^ - !!(info->flags & IEEE80211_TX_CTL_40_MHZ_WIDTH)) || - (tbl_type.is_dup ^ - !!(info->flags & IEEE80211_TX_CTL_DUP_DATA)) || - (tbl_type.ant_type ^ info->antenna_sel_tx) || - (!!(tx_rate & RATE_MCS_HT_MSK) ^ - !!(info->flags & IEEE80211_TX_CTL_OFDM_HT)) || - (!!(tx_rate & RATE_MCS_GF_MSK) ^ - !!(info->flags & IEEE80211_TX_CTL_GREEN_FIELD)) || + if ((info->status.rates[0].idx < 0) || + (tbl_type.is_SGI != !!(info->status.rates[0].flags & IEEE80211_TX_RC_SHORT_GI)) || + (tbl_type.is_fat != !!(info->status.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) || + (tbl_type.is_dup != !!(info->status.rates[0].flags & IEEE80211_TX_RC_DUP_DATA)) || + (tbl_type.ant_type != info->antenna_sel_tx) || + (!!(tx_rate & RATE_MCS_HT_MSK) != !!(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) || + (!!(tx_rate & RATE_MCS_GF_MSK) != !!(info->status.rates[0].flags & IEEE80211_TX_RC_GREEN_FIELD)) || (hw->wiphy->bands[priv->band]->bitrates[rs_index].bitrate != - hw->wiphy->bands[info->band]->bitrates[info->tx_rate_idx].bitrate)) { + hw->wiphy->bands[info->band]->bitrates[info->status.rates[0].idx].bitrate)) { IWL_DEBUG_RATE("initial rate does not match 0x%x\n", tx_rate); + /* the last LQ command could failed so the LQ in ucode not + * the same in driver sync up + */ + iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); goto out; } @@ -1135,11 +1128,10 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, s32 rate; s8 is_green = lq_sta->is_green; - if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) || - !sta->ht_info.ht_supported) + if (!conf->ht.enabled || !sta->ht_cap.ht_supported) return -1; - if (((sta->ht_info.cap & IEEE80211_HT_CAP_SM_PS) >> 2) + if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2) == WLAN_HT_CAP_SM_PS_STATIC) return -1; @@ -1203,8 +1195,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv, u8 is_green = lq_sta->is_green; s32 rate; - if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) || - !sta->ht_info.ht_supported) + if (!conf->ht.enabled || !sta->ht_cap.ht_supported) return -1; IWL_DEBUG_RATE("LQ: try to switch to SISO\n"); @@ -1684,7 +1675,6 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, int high_tpt = IWL_INVALID_VALUE; u32 fail_count; s8 scale_action = 0; - __le16 fc; u16 rate_mask; u8 update_lq = 0; struct iwl_scale_tbl_info *tbl, *tbl1; @@ -1699,13 +1689,12 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, IWL_DEBUG_RATE("rate scale calculate new rate for skb\n"); - fc = hdr->frame_control; - if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) { - /* Send management frames and broadcast/multicast data using - * lowest rate. */ - /* TODO: this could probably be improved.. */ + /* Send management frames and broadcast/multicast data using + * lowest rate. */ + /* TODO: this could probably be improved.. */ + if (!ieee80211_is_data(hdr->frame_control) || + is_multicast_ether_addr(hdr->addr1)) return; - } if (!sta || !lq_sta) return; @@ -2003,9 +1992,8 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, * stay with best antenna legacy modulation for a while * before next round of mode comparisons. */ tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]); - if (is_legacy(tbl1->lq_type) && - (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)) && - (lq_sta->action_counter >= 1)) { + if (is_legacy(tbl1->lq_type) && !conf->ht.enabled && + lq_sta->action_counter >= 1) { lq_sta->action_counter = 0; IWL_DEBUG_RATE("LQ: STAY in legacy table\n"); rs_set_stay_in_table(priv, 1, lq_sta); @@ -2081,15 +2069,13 @@ static void rs_initialize_lq(struct iwl_priv *priv, if ((i < 0) || (i >= IWL_RATE_COUNT)) i = 0; - /* FIXME:RS: This is also wrong in 4965 */ rate = iwl_rates[i].plcp; - rate |= RATE_MCS_ANT_B_MSK; - rate &= ~RATE_MCS_ANT_A_MSK; + tbl->ant_type = first_antenna(valid_tx_ant); + rate |= tbl->ant_type << RATE_MCS_ANT_POS; if (i >= IWL_FIRST_CCK_RATE && i <= IWL_LAST_CCK_RATE) rate |= RATE_MCS_CCK_MSK; - tbl->ant_type = ANT_B; rs_get_tbl_info_from_mcs(rate, priv->band, tbl, &rate_idx); if (!rs_is_valid_ant(valid_tx_ant, tbl->ant_type)) rs_toggle_antenna(valid_tx_ant, &rate, tbl); @@ -2103,40 +2089,38 @@ static void rs_initialize_lq(struct iwl_priv *priv, return; } -static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, void *priv_sta, - struct sk_buff *skb, struct rate_selection *sel) +static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, + struct ieee80211_tx_rate_control *txrc) { - int i; + struct sk_buff *skb = txrc->skb; + struct ieee80211_supported_band *sband = txrc->sband; struct iwl_priv *priv = (struct iwl_priv *)priv_r; struct ieee80211_conf *conf = &priv->hw->conf; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - __le16 fc; - struct iwl_lq_sta *lq_sta; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct iwl_lq_sta *lq_sta = priv_sta; + int rate_idx; IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n"); /* Send management frames and broadcast/multicast data using lowest * rate. */ - fc = hdr->frame_control; - if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) || - !sta || !priv_sta) { - sel->rate_idx = rate_lowest_index(sband, sta); + if (!ieee80211_is_data(hdr->frame_control) || + is_multicast_ether_addr(hdr->addr1) || !sta || !lq_sta) { + info->control.rates[0].idx = rate_lowest_index(sband, sta); return; } - lq_sta = (struct iwl_lq_sta *)priv_sta; - i = lq_sta->last_txrate_idx; + rate_idx = lq_sta->last_txrate_idx; if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && !lq_sta->ibss_sta_added) { u8 sta_id = iwl_find_station(priv, hdr->addr1); - DECLARE_MAC_BUF(mac); if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_RATE("LQ: ADD station %s\n", - print_mac(mac, hdr->addr1)); + IWL_DEBUG_RATE("LQ: ADD station %pM\n", + hdr->addr1); sta_id = iwl_add_station_flags(priv, hdr->addr1, 0, CMD_ASYNC, NULL); } @@ -2148,14 +2132,12 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, } } - if ((i < 0) || (i > IWL_RATE_COUNT)) { - sel->rate_idx = rate_lowest_index(sband, sta); - return; - } + if (rate_idx < 0 || rate_idx > IWL_RATE_COUNT) + rate_idx = rate_lowest_index(sband, sta); + else if (sband->band == IEEE80211_BAND_5GHZ) + rate_idx -= IWL_FIRST_OFDM_RATE; - if (sband->band == IEEE80211_BAND_5GHZ) - i -= IWL_FIRST_OFDM_RATE; - sel->rate_idx = i; + info->control.rates[0].idx = rate_idx; } static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta, @@ -2189,6 +2171,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, struct iwl_priv *priv = (struct iwl_priv *)priv_r; struct ieee80211_conf *conf = &priv->hw->conf; struct iwl_lq_sta *lq_sta = priv_sta; + u16 mask_bit = 0; lq_sta->flush_timer = 0; lq_sta->supp_rates = sta->supp_rates[sband->band]; @@ -2205,15 +2188,12 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, lq_sta->ibss_sta_added = 0; if (priv->iw_mode == NL80211_IFTYPE_AP) { u8 sta_id = iwl_find_station(priv, sta->addr); - DECLARE_MAC_BUF(mac); /* for IBSS the call are from tasklet */ - IWL_DEBUG_RATE("LQ: ADD station %s\n", - print_mac(mac, sta->addr)); + IWL_DEBUG_RATE("LQ: ADD station %pM\n", sta->addr); if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_RATE("LQ: ADD station %s\n", - print_mac(mac, sta->addr)); + IWL_DEBUG_RATE("LQ: ADD station %pM\n", sta->addr); sta_id = iwl_add_station_flags(priv, sta->addr, 0, CMD_ASYNC, NULL); } @@ -2225,16 +2205,6 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, priv->assoc_station_added = 1; } - /* Find highest tx rate supported by hardware and destination station */ - lq_sta->last_txrate_idx = 3; - for (i = 0; i < sband->n_bitrates; i++) - if (sta->supp_rates[sband->band] & BIT(i)) - lq_sta->last_txrate_idx = i; - - /* For MODE_IEEE80211A, skip over cck rates in global rate table */ - if (sband->band == IEEE80211_BAND_5GHZ) - lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; - lq_sta->is_dup = 0; lq_sta->is_green = rs_use_green(priv, conf); lq_sta->active_legacy_rate = priv->active_rate & ~(0x1000); @@ -2244,19 +2214,19 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3), * supp_rates[] does not; shift to convert format, force 9 MBits off. */ - lq_sta->active_siso_rate = conf->ht_conf.supp_mcs_set[0] << 1; - lq_sta->active_siso_rate |= conf->ht_conf.supp_mcs_set[0] & 0x1; + lq_sta->active_siso_rate = sta->ht_cap.mcs.rx_mask[0] << 1; + lq_sta->active_siso_rate |= sta->ht_cap.mcs.rx_mask[0] & 0x1; lq_sta->active_siso_rate &= ~((u16)0x2); lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE; /* Same here */ - lq_sta->active_mimo2_rate = conf->ht_conf.supp_mcs_set[1] << 1; - lq_sta->active_mimo2_rate |= conf->ht_conf.supp_mcs_set[1] & 0x1; + lq_sta->active_mimo2_rate = sta->ht_cap.mcs.rx_mask[1] << 1; + lq_sta->active_mimo2_rate |= sta->ht_cap.mcs.rx_mask[1] & 0x1; lq_sta->active_mimo2_rate &= ~((u16)0x2); lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE; - lq_sta->active_mimo3_rate = conf->ht_conf.supp_mcs_set[2] << 1; - lq_sta->active_mimo3_rate |= conf->ht_conf.supp_mcs_set[2] & 0x1; + lq_sta->active_mimo3_rate = sta->ht_cap.mcs.rx_mask[2] << 1; + lq_sta->active_mimo3_rate |= sta->ht_cap.mcs.rx_mask[2] & 0x1; lq_sta->active_mimo3_rate &= ~((u16)0x2); lq_sta->active_mimo3_rate <<= IWL_FIRST_OFDM_RATE; @@ -2265,7 +2235,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, lq_sta->active_mimo2_rate, lq_sta->active_mimo3_rate); - /* These values will be overriden later */ + /* These values will be overridden later */ lq_sta->lq.general_params.single_stream_ant_msk = ANT_A; lq_sta->lq.general_params.dual_stream_ant_msk = ANT_AB; @@ -2273,6 +2243,17 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID; lq_sta->drv = priv; + /* Find highest tx rate supported by hardware and destination station */ + mask_bit = sta->supp_rates[sband->band] & lq_sta->active_legacy_rate; + lq_sta->last_txrate_idx = 3; + for (i = 0; i < sband->n_bitrates; i++) + if (mask_bit & BIT(i)) + lq_sta->last_txrate_idx = i; + + /* For MODE_IEEE80211A, skip over cck rates in global rate table */ + if (sband->band == IEEE80211_BAND_5GHZ) + lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; + rs_initialize_lq(priv, conf, sta, lq_sta); } @@ -2405,19 +2386,6 @@ static void rs_free(void *priv_rate) return; } -static void rs_clear(void *priv_rate) -{ -#ifdef CONFIG_IWLWIFI_DEBUG - struct iwl_priv *priv = (struct iwl_priv *) priv_rate; - - IWL_DEBUG_RATE("enter\n"); - - /* TODO - add rate scale state reset */ - - IWL_DEBUG_RATE("leave\n"); -#endif /* CONFIG_IWLWIFI_DEBUG */ -} - static void rs_free_sta(void *priv_r, struct ieee80211_sta *sta, void *priv_sta) { @@ -2552,7 +2520,7 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file, for (i = 0; i < LQ_SIZE; i++) { desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d\n" "rate=0x%X\n", - lq_sta->active_tbl == i?"*":"x", + lq_sta->active_tbl == i ? "*" : "x", lq_sta->lq_info[i].lq_type, lq_sta->lq_info[i].is_SGI, lq_sta->lq_info[i].is_fat, @@ -2605,7 +2573,6 @@ static struct rate_control_ops rs_ops = { .tx_status = rs_tx_status, .get_rate = rs_get_rate, .rate_init = rs_rate_init, - .clear = rs_clear, .alloc = rs_alloc, .free = rs_free, .alloc_sta = rs_alloc_sta, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h index d148d73635eb5ddec4669fc1fe0bf185959a5d04..78ee83adf742d632c440710d4bdd7ec056ffb6f6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -229,7 +229,7 @@ enum { #define IWL_MIMO2_SWITCH_SISO_C 4 #define IWL_MIMO2_SWITCH_GI 5 -/*FIXME:RS:add posible acctions for MIMO3*/ +/*FIXME:RS:add possible actions for MIMO3*/ #define IWL_ACTION_LIMIT 3 /* # possible actions */ @@ -284,7 +284,17 @@ static inline u8 num_of_ant(u8 mask) !!((mask) & ANT_C); } -static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index) +static inline u8 first_antenna(u8 mask) +{ + if (mask & ANT_A) + return ANT_A; + if (mask & ANT_B) + return ANT_B; + return ANT_C; +} + + +static inline u8 iwl_get_prev_ieee_rate(u8 rate_index) { u8 rate = iwl_rates[rate_index].prev_ieee; @@ -294,11 +304,11 @@ static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index) } /** - * iwl4965_rate_control_register - Register the rate control algorithm callbacks + * iwl_rate_control_register - Register the rate control algorithm callbacks * * Since the rate control algorithm is hardware specific, there is no need * or reason to place it as a stand alone module. The driver can call - * iwl4965_rate_control_register in order to register the rate control callbacks + * iwl_rate_control_register in order to register the rate control callbacks * with the mac80211 subsystem. This should be performed prior to calling * ieee80211_register_hw * @@ -306,7 +316,7 @@ static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index) extern int iwlagn_rate_control_register(void); /** - * iwl4965_rate_control_unregister - Unregister the rate control callbacks + * iwl_rate_control_unregister - Unregister the rate control callbacks * * This should be called after calling ieee80211_unregister_hw, but before * the driver is unloaded. diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index c4c0371c763b5d3b0e1ee13bfd1fcc1a386a6a6f..5da6b35cd26dbfa52da035a6ed78b871957b5c42 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -83,7 +83,7 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_VERSION(DRV_VERSION); -MODULE_AUTHOR(DRV_COPYRIGHT); +MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); MODULE_LICENSE("GPL"); MODULE_ALIAS("iwl4965"); @@ -96,7 +96,7 @@ MODULE_ALIAS("iwl4965"); -static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) +static void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) { struct iwl_rxon_cmd *rxon = &priv->staging_rxon; @@ -107,79 +107,6 @@ static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) } -/** - * iwl4965_check_rxon_cmd - validate RXON structure is valid - * - * NOTE: This is really only useful during development and can eventually - * be #ifdef'd out once the driver is stable and folks aren't actively - * making changes - */ -static int iwl4965_check_rxon_cmd(struct iwl_rxon_cmd *rxon) -{ - int error = 0; - int counter = 1; - - if (rxon->flags & RXON_FLG_BAND_24G_MSK) { - error |= le32_to_cpu(rxon->flags & - (RXON_FLG_TGJ_NARROW_BAND_MSK | - RXON_FLG_RADAR_DETECT_MSK)); - if (error) - IWL_WARNING("check 24G fields %d | %d\n", - counter++, error); - } else { - error |= (rxon->flags & RXON_FLG_SHORT_SLOT_MSK) ? - 0 : le32_to_cpu(RXON_FLG_SHORT_SLOT_MSK); - if (error) - IWL_WARNING("check 52 fields %d | %d\n", - counter++, error); - error |= le32_to_cpu(rxon->flags & RXON_FLG_CCK_MSK); - if (error) - IWL_WARNING("check 52 CCK %d | %d\n", - counter++, error); - } - error |= (rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1; - if (error) - IWL_WARNING("check mac addr %d | %d\n", counter++, error); - - /* make sure basic rates 6Mbps and 1Mbps are supported */ - error |= (((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0) && - ((rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0)); - if (error) - IWL_WARNING("check basic rate %d | %d\n", counter++, error); - - error |= (le16_to_cpu(rxon->assoc_id) > 2007); - if (error) - IWL_WARNING("check assoc id %d | %d\n", counter++, error); - - error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) - == (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)); - if (error) - IWL_WARNING("check CCK and short slot %d | %d\n", - counter++, error); - - error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) - == (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)); - if (error) - IWL_WARNING("check CCK & auto detect %d | %d\n", - counter++, error); - - error |= ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK | - RXON_FLG_TGG_PROTECT_MSK)) == RXON_FLG_TGG_PROTECT_MSK); - if (error) - IWL_WARNING("check TGG and auto detect %d | %d\n", - counter++, error); - - if (error) - IWL_WARNING("Tuning to channel %d\n", - le16_to_cpu(rxon->channel)); - - if (error) { - IWL_ERROR("Not a valid iwl4965_rxon_assoc_cmd field values\n"); - return -1; - } - return 0; -} - /** * iwl_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed * @priv: staging_rxon is compared to active_rxon @@ -228,18 +155,17 @@ static int iwl_full_rxon_required(struct iwl_priv *priv) } /** - * iwl4965_commit_rxon - commit staging_rxon to hardware + * iwl_commit_rxon - commit staging_rxon to hardware * * The RXON command in staging_rxon is committed to the hardware and * the active_rxon structure is updated with the new data. This * function correctly transitions out of the RXON_ASSOC_MSK state if * a HW tune is required based on the RXON structure changes. */ -static int iwl4965_commit_rxon(struct iwl_priv *priv) +static int iwl_commit_rxon(struct iwl_priv *priv) { /* cast away the const for active_rxon in this function */ struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon; - DECLARE_MAC_BUF(mac); int ret; bool new_assoc = !!(priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK); @@ -253,14 +179,14 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) * 5000, but will not damage 4965 */ priv->staging_rxon.flags |= RXON_FLG_SELF_CTS_EN; - ret = iwl4965_check_rxon_cmd(&priv->staging_rxon); + ret = iwl_agn_check_rxon_cmd(&priv->staging_rxon); if (ret) { IWL_ERROR("Invalid RXON configuration. Not committing.\n"); return -EINVAL; } /* If we don't need to send a full RXON, we can use - * iwl4965_rxon_assoc_cmd which is used to reconfigure filter + * iwl_rxon_assoc_cmd which is used to reconfigure filter * and other flags for the current radio configuration. */ if (!iwl_full_rxon_required(priv)) { ret = iwl_send_rxon_assoc(priv); @@ -300,12 +226,12 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) IWL_DEBUG_INFO("Sending RXON\n" "* with%s RXON_FILTER_ASSOC_MSK\n" "* channel = %d\n" - "* bssid = %s\n", + "* bssid = %pM\n", (new_assoc ? "" : "out"), le16_to_cpu(priv->staging_rxon.channel), - print_mac(mac, priv->staging_rxon.bssid_addr)); + priv->staging_rxon.bssid_addr); - iwl4965_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto); + iwl_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto); /* Apply the new configuration * RXON unassoc clears the station table in uCode, send it before @@ -375,16 +301,16 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) return 0; } -void iwl4965_update_chain_flags(struct iwl_priv *priv) +void iwl_update_chain_flags(struct iwl_priv *priv) { iwl_set_rxon_chain(priv); - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); } -static int iwl4965_send_bt_config(struct iwl_priv *priv) +static int iwl_send_bt_config(struct iwl_priv *priv) { - struct iwl4965_bt_cmd bt_cmd = { + struct iwl_bt_cmd bt_cmd = { .flags = 3, .lead_time = 0xAA, .max_kill = 1, @@ -393,7 +319,7 @@ static int iwl4965_send_bt_config(struct iwl_priv *priv) }; return iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG, - sizeof(struct iwl4965_bt_cmd), &bt_cmd); + sizeof(struct iwl_bt_cmd), &bt_cmd); } static void iwl_clear_free_frames(struct iwl_priv *priv) @@ -445,7 +371,7 @@ static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame) static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv, struct ieee80211_hdr *hdr, - const u8 *dest, int left) + int left) { if (!iwl_is_associated(priv) || !priv->ibss_beacon || ((priv->iw_mode != NL80211_IFTYPE_ADHOC) && @@ -460,16 +386,16 @@ static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv, return priv->ibss_beacon->len; } -static u8 iwl4965_rate_get_lowest_plcp(struct iwl_priv *priv) +static u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv) { int i; int rate_mask; /* Set rate mask*/ if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) - rate_mask = priv->active_rate_basic & 0xF; + rate_mask = priv->active_rate_basic & IWL_CCK_RATES_MASK; else - rate_mask = priv->active_rate_basic & 0xFF0; + rate_mask = priv->active_rate_basic & IWL_OFDM_RATES_MASK; /* Find lowest valid rate */ for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID; @@ -485,7 +411,7 @@ static u8 iwl4965_rate_get_lowest_plcp(struct iwl_priv *priv) return IWL_RATE_6M_PLCP; } -static unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, +static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv, struct iwl_frame *frame, u8 rate) { struct iwl_tx_beacon_cmd *tx_beacon_cmd; @@ -498,7 +424,6 @@ static unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; frame_size = iwl_fill_beacon_frame(priv, tx_beacon_cmd->frame, - iwl_bcast_addr, sizeof(frame->u) - sizeof(*tx_beacon_cmd)); BUG_ON(frame_size > MAX_MPDU_SIZE); @@ -517,7 +442,7 @@ static unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, return sizeof(*tx_beacon_cmd) + frame_size; } -static int iwl4965_send_beacon_cmd(struct iwl_priv *priv) +static int iwl_send_beacon_cmd(struct iwl_priv *priv) { struct iwl_frame *frame; unsigned int frame_size; @@ -532,9 +457,9 @@ static int iwl4965_send_beacon_cmd(struct iwl_priv *priv) return -ENOMEM; } - rate = iwl4965_rate_get_lowest_plcp(priv); + rate = iwl_rate_get_lowest_plcp(priv); - frame_size = iwl4965_hw_get_beacon_cmd(priv, frame, rate); + frame_size = iwl_hw_get_beacon_cmd(priv, frame, rate); rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size, &frame->u.cmd[0]); @@ -550,20 +475,33 @@ static int iwl4965_send_beacon_cmd(struct iwl_priv *priv) * ******************************************************************************/ -static void iwl4965_ht_conf(struct iwl_priv *priv, +static void iwl_ht_conf(struct iwl_priv *priv, struct ieee80211_bss_conf *bss_conf) { - struct ieee80211_ht_info *ht_conf = bss_conf->ht_conf; - struct ieee80211_ht_bss_info *ht_bss_conf = bss_conf->ht_bss_conf; + struct ieee80211_sta_ht_cap *ht_conf; struct iwl_ht_info *iwl_conf = &priv->current_ht_config; + struct ieee80211_sta *sta; IWL_DEBUG_MAC80211("enter: \n"); - iwl_conf->is_ht = bss_conf->assoc_ht; - if (!iwl_conf->is_ht) return; + + /* + * It is totally wrong to base global information on something + * that is valid only when associated, alas, this driver works + * that way and I don't know how to fix it. + */ + + rcu_read_lock(); + sta = ieee80211_find_sta(priv->hw, priv->bssid); + if (!sta) { + rcu_read_unlock(); + return; + } + ht_conf = &sta->ht_cap; + if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20) iwl_conf->sgf |= HT_SHORT_GI_20MHZ; if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40) @@ -574,29 +512,36 @@ static void iwl4965_ht_conf(struct iwl_priv *priv, !!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU); iwl_conf->supported_chan_width = - !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH); - iwl_conf->extension_chan_offset = - ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_SEC_OFFSET; + !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40); + + /* + * XXX: The HT configuration needs to be moved into iwl_mac_config() + * to be done there correctly. + */ + + iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; + if (priv->hw->conf.ht.channel_type == NL80211_CHAN_HT40MINUS) + iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_BELOW; + else if(priv->hw->conf.ht.channel_type == NL80211_CHAN_HT40PLUS) + iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; + /* If no above or below channel supplied disable FAT channel */ - if (iwl_conf->extension_chan_offset != IEEE80211_HT_IE_CHA_SEC_ABOVE && - iwl_conf->extension_chan_offset != IEEE80211_HT_IE_CHA_SEC_BELOW) { - iwl_conf->extension_chan_offset = IEEE80211_HT_IE_CHA_SEC_NONE; + if (iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_ABOVE && + iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW) iwl_conf->supported_chan_width = 0; - } iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2); - memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16); + memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16); - iwl_conf->control_channel = ht_bss_conf->primary_channel; - iwl_conf->tx_chan_width = - !!(ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_WIDTH); + iwl_conf->tx_chan_width = iwl_conf->supported_chan_width != 0; iwl_conf->ht_protection = - ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_HT_PROTECTION; + bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_PROTECTION; iwl_conf->non_GF_STA_present = - !!(ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_NON_GF_STA_PRSNT); + !!(bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); + + rcu_read_unlock(); - IWL_DEBUG_MAC80211("control channel %d\n", iwl_conf->control_channel); IWL_DEBUG_MAC80211("leave\n"); } @@ -608,9 +553,6 @@ static void iwl_activate_qos(struct iwl_priv *priv, u8 force) if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; - if (!priv->qos_data.qos_enable) - return; - priv->qos_data.def_qos_parm.qos_flags = 0; if (priv->qos_data.qos_cap.q_AP.queue_request && @@ -637,23 +579,22 @@ static void iwl_activate_qos(struct iwl_priv *priv, u8 force) #define MAX_UCODE_BEACON_INTERVAL 4096 -static __le16 iwl4965_adjust_beacon_interval(u16 beacon_val) +static u16 iwl_adjust_beacon_interval(u16 beacon_val) { u16 new_val = 0; u16 beacon_factor = 0; - beacon_factor = - (beacon_val + MAX_UCODE_BEACON_INTERVAL) - / MAX_UCODE_BEACON_INTERVAL; + beacon_factor = (beacon_val + MAX_UCODE_BEACON_INTERVAL) + / MAX_UCODE_BEACON_INTERVAL; new_val = beacon_val / beacon_factor; - return cpu_to_le16(new_val); + return new_val; } -static void iwl4965_setup_rxon_timing(struct iwl_priv *priv) +static void iwl_setup_rxon_timing(struct iwl_priv *priv) { - u64 interval_tm_unit; - u64 tsf, result; + u64 tsf; + s32 interval_tm, rem; unsigned long flags; struct ieee80211_conf *conf = NULL; u16 beacon_int = 0; @@ -661,49 +602,32 @@ static void iwl4965_setup_rxon_timing(struct iwl_priv *priv) conf = ieee80211_get_hw_conf(priv->hw); spin_lock_irqsave(&priv->lock, flags); - priv->rxon_timing.timestamp.dw[1] = cpu_to_le32(priv->timestamp >> 32); - priv->rxon_timing.timestamp.dw[0] = - cpu_to_le32(priv->timestamp & 0xFFFFFFFF); - + priv->rxon_timing.timestamp = cpu_to_le64(priv->timestamp); priv->rxon_timing.listen_interval = cpu_to_le16(conf->listen_interval); - tsf = priv->timestamp; - - beacon_int = priv->beacon_int; - spin_unlock_irqrestore(&priv->lock, flags); - if (priv->iw_mode == NL80211_IFTYPE_STATION) { - if (beacon_int == 0) { - priv->rxon_timing.beacon_interval = cpu_to_le16(100); - priv->rxon_timing.beacon_init_val = cpu_to_le32(102400); - } else { - priv->rxon_timing.beacon_interval = - cpu_to_le16(beacon_int); - priv->rxon_timing.beacon_interval = - iwl4965_adjust_beacon_interval( - le16_to_cpu(priv->rxon_timing.beacon_interval)); - } - + beacon_int = iwl_adjust_beacon_interval(priv->beacon_int); priv->rxon_timing.atim_window = 0; } else { - priv->rxon_timing.beacon_interval = - iwl4965_adjust_beacon_interval(conf->beacon_int); + beacon_int = iwl_adjust_beacon_interval(conf->beacon_int); + /* TODO: we need to get atim_window from upper stack * for now we set to 0 */ priv->rxon_timing.atim_window = 0; } - interval_tm_unit = - (le16_to_cpu(priv->rxon_timing.beacon_interval) * 1024); - result = do_div(tsf, interval_tm_unit); - priv->rxon_timing.beacon_init_val = - cpu_to_le32((u32) ((u64) interval_tm_unit - result)); + priv->rxon_timing.beacon_interval = cpu_to_le16(beacon_int); - IWL_DEBUG_ASSOC - ("beacon interval %d beacon timer %d beacon tim %d\n", - le16_to_cpu(priv->rxon_timing.beacon_interval), - le32_to_cpu(priv->rxon_timing.beacon_init_val), - le16_to_cpu(priv->rxon_timing.atim_window)); + tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */ + interval_tm = beacon_int * 1024; + rem = do_div(tsf, interval_tm); + priv->rxon_timing.beacon_init_val = cpu_to_le32(interval_tm - rem); + + spin_unlock_irqrestore(&priv->lock, flags); + IWL_DEBUG_ASSOC("beacon interval %d beacon timer %d beacon tim %d\n", + le16_to_cpu(priv->rxon_timing.beacon_interval), + le32_to_cpu(priv->rxon_timing.beacon_init_val), + le16_to_cpu(priv->rxon_timing.atim_window)); } static void iwl_set_flags_for_band(struct iwl_priv *priv, @@ -715,7 +639,7 @@ static void iwl_set_flags_for_band(struct iwl_priv *priv, | RXON_FLG_CCK_MSK); priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK; } else { - /* Copied from iwl4965_post_associate() */ + /* Copied from iwl_post_associate() */ if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK; else @@ -733,13 +657,13 @@ static void iwl_set_flags_for_band(struct iwl_priv *priv, /* * initialize rxon structure with default values from eeprom */ -static void iwl4965_connection_init_rx_config(struct iwl_priv *priv) +static void iwl_connection_init_rx_config(struct iwl_priv *priv, int mode) { const struct iwl_channel_info *ch_info; memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon)); - switch (priv->iw_mode) { + switch (mode) { case NL80211_IFTYPE_AP: priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP; break; @@ -762,7 +686,7 @@ static void iwl4965_connection_init_rx_config(struct iwl_priv *priv) RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK; break; default: - IWL_ERROR("Unsupported interface type %d\n", priv->iw_mode); + IWL_ERROR("Unsupported interface type %d\n", mode); break; } @@ -808,11 +732,9 @@ static void iwl4965_connection_init_rx_config(struct iwl_priv *priv) iwl_set_rxon_chain(priv); } -static int iwl4965_set_mode(struct iwl_priv *priv, int mode) +static int iwl_set_mode(struct iwl_priv *priv, int mode) { - priv->iw_mode = mode; - - iwl4965_connection_init_rx_config(priv); + iwl_connection_init_rx_config(priv, mode); memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); iwl_clear_stations_table(priv); @@ -828,12 +750,12 @@ static int iwl4965_set_mode(struct iwl_priv *priv, int mode) return -EAGAIN; } - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); return 0; } -static void iwl4965_set_rate(struct iwl_priv *priv) +static void iwl_set_rate(struct iwl_priv *priv) { const struct ieee80211_supported_band *hw = NULL; struct ieee80211_rate *rate; @@ -880,138 +802,6 @@ static void iwl4965_set_rate(struct iwl_priv *priv) (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; } -#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT - -#include "iwl-spectrum.h" - -#define BEACON_TIME_MASK_LOW 0x00FFFFFF -#define BEACON_TIME_MASK_HIGH 0xFF000000 -#define TIME_UNIT 1024 - -/* - * extended beacon time format - * time in usec will be changed into a 32-bit value in 8:24 format - * the high 1 byte is the beacon counts - * the lower 3 bytes is the time in usec within one beacon interval - */ - -static u32 iwl4965_usecs_to_beacons(u32 usec, u32 beacon_interval) -{ - u32 quot; - u32 rem; - u32 interval = beacon_interval * 1024; - - if (!interval || !usec) - return 0; - - quot = (usec / interval) & (BEACON_TIME_MASK_HIGH >> 24); - rem = (usec % interval) & BEACON_TIME_MASK_LOW; - - return (quot << 24) + rem; -} - -/* base is usually what we get from ucode with each received frame, - * the same as HW timer counter counting down - */ - -static __le32 iwl4965_add_beacon_time(u32 base, u32 addon, u32 beacon_interval) -{ - u32 base_low = base & BEACON_TIME_MASK_LOW; - u32 addon_low = addon & BEACON_TIME_MASK_LOW; - u32 interval = beacon_interval * TIME_UNIT; - u32 res = (base & BEACON_TIME_MASK_HIGH) + - (addon & BEACON_TIME_MASK_HIGH); - - if (base_low > addon_low) - res += base_low - addon_low; - else if (base_low < addon_low) { - res += interval + base_low - addon_low; - res += (1 << 24); - } else - res += (1 << 24); - - return cpu_to_le32(res); -} - -static int iwl4965_get_measurement(struct iwl_priv *priv, - struct ieee80211_measurement_params *params, - u8 type) -{ - struct iwl4965_spectrum_cmd spectrum; - struct iwl_rx_packet *res; - struct iwl_host_cmd cmd = { - .id = REPLY_SPECTRUM_MEASUREMENT_CMD, - .data = (void *)&spectrum, - .meta.flags = CMD_WANT_SKB, - }; - u32 add_time = le64_to_cpu(params->start_time); - int rc; - int spectrum_resp_status; - int duration = le16_to_cpu(params->duration); - - if (iwl_is_associated(priv)) - add_time = - iwl4965_usecs_to_beacons( - le64_to_cpu(params->start_time) - priv->last_tsf, - le16_to_cpu(priv->rxon_timing.beacon_interval)); - - memset(&spectrum, 0, sizeof(spectrum)); - - spectrum.channel_count = cpu_to_le16(1); - spectrum.flags = - RXON_FLG_TSF2HOST_MSK | RXON_FLG_ANT_A_MSK | RXON_FLG_DIS_DIV_MSK; - spectrum.filter_flags = MEASUREMENT_FILTER_FLAG; - cmd.len = sizeof(spectrum); - spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len)); - - if (iwl_is_associated(priv)) - spectrum.start_time = - iwl4965_add_beacon_time(priv->last_beacon_time, - add_time, - le16_to_cpu(priv->rxon_timing.beacon_interval)); - else - spectrum.start_time = 0; - - spectrum.channels[0].duration = cpu_to_le32(duration * TIME_UNIT); - spectrum.channels[0].channel = params->channel; - spectrum.channels[0].type = type; - if (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK) - spectrum.flags |= RXON_FLG_BAND_24G_MSK | - RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK; - - rc = iwl_send_cmd_sync(priv, &cmd); - if (rc) - return rc; - - res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; - if (res->hdr.flags & IWL_CMD_FAILED_MSK) { - IWL_ERROR("Bad return from REPLY_RX_ON_ASSOC command\n"); - rc = -EIO; - } - - spectrum_resp_status = le16_to_cpu(res->u.spectrum.status); - switch (spectrum_resp_status) { - case 0: /* Command will be handled */ - if (res->u.spectrum.id != 0xff) { - IWL_DEBUG_INFO - ("Replaced existing measurement: %d\n", - res->u.spectrum.id); - priv->measurement_status &= ~MEASUREMENT_READY; - } - priv->measurement_status |= MEASUREMENT_ACTIVE; - rc = 0; - break; - - case 1: /* Command will not be handled */ - rc = -EAGAIN; - break; - } - - dev_kfree_skb_any(cmd.meta.u.skb); - - return rc; -} -#endif /****************************************************************************** * @@ -1054,7 +844,7 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv, IWL_WARNING("uCode did not respond OK.\n"); } -static void iwl4965_rx_reply_error(struct iwl_priv *priv, +static void iwl_rx_reply_error(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; @@ -1070,47 +860,29 @@ static void iwl4965_rx_reply_error(struct iwl_priv *priv, #define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x -static void iwl4965_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) +static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon; - struct iwl4965_csa_notification *csa = &(pkt->u.csa_notif); + struct iwl_csa_notification *csa = &(pkt->u.csa_notif); IWL_DEBUG_11H("CSA notif: channel %d, status %d\n", le16_to_cpu(csa->channel), le32_to_cpu(csa->status)); rxon->channel = csa->channel; priv->staging_rxon.channel = csa->channel; } -static void iwl4965_rx_spectrum_measure_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ -#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - struct iwl4965_spectrum_notification *report = &(pkt->u.spectrum_notif); - - if (!report->state) { - IWL_DEBUG(IWL_DL_11H, - "Spectrum Measure Notification: Start\n"); - return; - } - - memcpy(&priv->measure_report, report, sizeof(*report)); - priv->measurement_status |= MEASUREMENT_READY; -#endif -} - -static void iwl4965_rx_pm_sleep_notif(struct iwl_priv *priv, +static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - struct iwl4965_sleep_notification *sleep = &(pkt->u.sleep_notif); + struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif); IWL_DEBUG_RX("sleep mode: %d, src: %d\n", sleep->pm_sleep_mode, sleep->pm_wakeup_src); #endif } -static void iwl4965_rx_pm_debug_statistics_notif(struct iwl_priv *priv, +static void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; @@ -1120,7 +892,7 @@ static void iwl4965_rx_pm_debug_statistics_notif(struct iwl_priv *priv, iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len)); } -static void iwl4965_bg_beacon_update(struct work_struct *work) +static void iwl_bg_beacon_update(struct work_struct *work) { struct iwl_priv *priv = container_of(work, struct iwl_priv, beacon_update); @@ -1142,11 +914,11 @@ static void iwl4965_bg_beacon_update(struct work_struct *work) priv->ibss_beacon = beacon; mutex_unlock(&priv->mutex); - iwl4965_send_beacon_cmd(priv); + iwl_send_beacon_cmd(priv); } /** - * iwl4965_bg_statistics_periodic - Timer callback to queue statistics + * iwl_bg_statistics_periodic - Timer callback to queue statistics * * This callback is provided in order to send a statistics request. * @@ -1155,22 +927,27 @@ static void iwl4965_bg_beacon_update(struct work_struct *work) * was received. We need to ensure we receive the statistics in order * to update the temperature used for calibrating the TXPOWER. */ -static void iwl4965_bg_statistics_periodic(unsigned long data) +static void iwl_bg_statistics_periodic(unsigned long data) { struct iwl_priv *priv = (struct iwl_priv *)data; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; + /* dont send host command if rf-kill is on */ + if (!iwl_is_ready_rf(priv)) + return; + iwl_send_statistics_request(priv, CMD_ASYNC); } -static void iwl4965_rx_beacon_notif(struct iwl_priv *priv, +static void iwl_rx_beacon_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - struct iwl4965_beacon_notif *beacon = &(pkt->u.beacon_status); + struct iwl4965_beacon_notif *beacon = + (struct iwl4965_beacon_notif *)pkt->u.raw; u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags); IWL_DEBUG_RX("beacon status %x retries %d iss %d " @@ -1189,7 +966,7 @@ static void iwl4965_rx_beacon_notif(struct iwl_priv *priv, /* Handle notification from uCode that card's power state is changing * due to software, hardware, or critical temperature RFKILL */ -static void iwl4965_rx_card_state_notif(struct iwl_priv *priv, +static void iwl_rx_card_state_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; @@ -1258,7 +1035,7 @@ static void iwl4965_rx_card_state_notif(struct iwl_priv *priv, wake_up_interruptible(&priv->wait_command_queue); } -int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) +int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) { int ret; unsigned long flags; @@ -1290,7 +1067,7 @@ int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) } /** - * iwl4965_setup_rx_handlers - Initialize Rx handler callbacks + * iwl_setup_rx_handlers - Initialize Rx handler callbacks * * Setup the RX handlers for each of the reply types sent from the uCode * to the host. @@ -1301,14 +1078,12 @@ int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) static void iwl_setup_rx_handlers(struct iwl_priv *priv) { priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive; - priv->rx_handlers[REPLY_ERROR] = iwl4965_rx_reply_error; - priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl4965_rx_csa; - priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] = - iwl4965_rx_spectrum_measure_notif; - priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl4965_rx_pm_sleep_notif; + priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error; + priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa; + priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif; priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] = - iwl4965_rx_pm_debug_statistics_notif; - priv->rx_handlers[BEACON_NOTIFICATION] = iwl4965_rx_beacon_notif; + iwl_rx_pm_debug_statistics_notif; + priv->rx_handlers[BEACON_NOTIFICATION] = iwl_rx_beacon_notif; /* * The same handler is used for both the REPLY to a discrete @@ -1318,10 +1093,11 @@ static void iwl_setup_rx_handlers(struct iwl_priv *priv) priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_rx_statistics; priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_rx_statistics; + iwl_setup_spectrum_handlers(priv); iwl_setup_rx_scan_handlers(priv); /* status change handler */ - priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl4965_rx_card_state_notif; + priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl_rx_card_state_notif; priv->rx_handlers[MISSED_BEACONS_NOTIFICATION] = iwl_rx_missed_beacon_notif; @@ -1334,16 +1110,6 @@ static void iwl_setup_rx_handlers(struct iwl_priv *priv) priv->cfg->ops->lib->rx_handler_setup(priv); } -/* - * this should be called while priv->lock is locked -*/ -static void __iwl_rx_replenish(struct iwl_priv *priv) -{ - iwl_rx_allocate(priv); - iwl_rx_queue_restock(priv); -} - - /** * iwl_rx_handle - Main entry function for receiving responses from uCode * @@ -1364,7 +1130,7 @@ void iwl_rx_handle(struct iwl_priv *priv) /* uCode's read index (stored in shared DRAM) indicates the last Rx * buffer that the driver may process (last buffer filled by ucode). */ - r = priv->cfg->ops->lib->shared_mem_rx_idx(priv); + r = le16_to_cpu(rxq->rb_stts->closed_rb_num) & 0x0FFF; i = rxq->read; /* Rx interrupt, but nothing sent from uCode */ @@ -1400,13 +1166,14 @@ void iwl_rx_handle(struct iwl_priv *priv) reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) && (pkt->hdr.cmd != REPLY_RX_PHY_CMD) && (pkt->hdr.cmd != REPLY_RX) && + (pkt->hdr.cmd != REPLY_RX_MPDU_CMD) && (pkt->hdr.cmd != REPLY_COMPRESSED_BA) && (pkt->hdr.cmd != STATISTICS_NOTIFICATION) && (pkt->hdr.cmd != REPLY_TX); /* Based on type of command response or notification, * handle those that need handling via function in - * rx_handlers table. See iwl4965_setup_rx_handlers() */ + * rx_handlers table. See iwl_setup_rx_handlers() */ if (priv->rx_handlers[pkt->hdr.cmd]) { IWL_DEBUG(IWL_DL_RX, "r = %d, i = %d, %s, 0x%02x\n", r, i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); @@ -1451,7 +1218,7 @@ void iwl_rx_handle(struct iwl_priv *priv) count++; if (count >= 8) { priv->rxq.read = i; - __iwl_rx_replenish(priv); + iwl_rx_queue_restock(priv); count = 0; } } @@ -1463,10 +1230,9 @@ void iwl_rx_handle(struct iwl_priv *priv) } #ifdef CONFIG_IWLWIFI_DEBUG -static void iwl4965_print_rx_config_cmd(struct iwl_priv *priv) +static void iwl_print_rx_config_cmd(struct iwl_priv *priv) { struct iwl_rxon_cmd *rxon = &priv->staging_rxon; - DECLARE_MAC_BUF(mac); IWL_DEBUG_RADIO("RX CONFIG:\n"); iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); @@ -1478,50 +1244,26 @@ static void iwl4965_print_rx_config_cmd(struct iwl_priv *priv) IWL_DEBUG_RADIO("u8 ofdm_basic_rates: 0x%02x\n", rxon->ofdm_basic_rates); IWL_DEBUG_RADIO("u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates); - IWL_DEBUG_RADIO("u8[6] node_addr: %s\n", - print_mac(mac, rxon->node_addr)); - IWL_DEBUG_RADIO("u8[6] bssid_addr: %s\n", - print_mac(mac, rxon->bssid_addr)); + IWL_DEBUG_RADIO("u8[6] node_addr: %pM\n", rxon->node_addr); + IWL_DEBUG_RADIO("u8[6] bssid_addr: %pM\n", rxon->bssid_addr); IWL_DEBUG_RADIO("u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id)); } #endif -static void iwl4965_enable_interrupts(struct iwl_priv *priv) -{ - IWL_DEBUG_ISR("Enabling interrupts\n"); - set_bit(STATUS_INT_ENABLED, &priv->status); - iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK); -} - /* call this function to flush any scheduled tasklet */ static inline void iwl_synchronize_irq(struct iwl_priv *priv) { - /* wait to make sure we flush pedding tasklet*/ + /* wait to make sure we flush pending tasklet*/ synchronize_irq(priv->pci_dev->irq); tasklet_kill(&priv->irq_tasklet); } -static inline void iwl4965_disable_interrupts(struct iwl_priv *priv) -{ - clear_bit(STATUS_INT_ENABLED, &priv->status); - - /* disable interrupts from uCode/NIC to host */ - iwl_write32(priv, CSR_INT_MASK, 0x00000000); - - /* acknowledge/clear/reset any interrupts still pending - * from uCode or flow handler (Rx/Tx DMA) */ - iwl_write32(priv, CSR_INT, 0xffffffff); - iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff); - IWL_DEBUG_ISR("Disabled interrupts\n"); -} - - /** - * iwl4965_irq_handle_error - called for HW or SW error interrupt from card + * iwl_irq_handle_error - called for HW or SW error interrupt from card */ -static void iwl4965_irq_handle_error(struct iwl_priv *priv) +static void iwl_irq_handle_error(struct iwl_priv *priv) { - /* Set the FW error flag -- cleared on iwl4965_down */ + /* Set the FW error flag -- cleared on iwl_down */ set_bit(STATUS_FW_ERROR, &priv->status); /* Cancel currently queued command. */ @@ -1531,7 +1273,7 @@ static void iwl4965_irq_handle_error(struct iwl_priv *priv) if (priv->debug_level & IWL_DL_FW_ERRORS) { iwl_dump_nic_error_log(priv); iwl_dump_nic_event_log(priv); - iwl4965_print_rx_config_cmd(priv); + iwl_print_rx_config_cmd(priv); } #endif @@ -1555,14 +1297,14 @@ static void iwl4965_irq_handle_error(struct iwl_priv *priv) } } -static void iwl4965_error_recovery(struct iwl_priv *priv) +static void iwl_error_recovery(struct iwl_priv *priv) { unsigned long flags; memcpy(&priv->staging_rxon, &priv->recovery_rxon, sizeof(priv->staging_rxon)); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); iwl_rxon_add_station(priv, priv->bssid, 1); @@ -1572,7 +1314,7 @@ static void iwl4965_error_recovery(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } -static void iwl4965_irq_tasklet(struct iwl_priv *priv) +static void iwl_irq_tasklet(struct iwl_priv *priv) { u32 inta, handled = 0; u32 inta_fh; @@ -1618,9 +1360,9 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv) IWL_ERROR("Microcode HW error detected. Restarting.\n"); /* Tell the device to stop sending interrupts */ - iwl4965_disable_interrupts(priv); + iwl_disable_interrupts(priv); - iwl4965_irq_handle_error(priv); + iwl_irq_handle_error(priv); handled |= CSR_INT_BIT_HW_ERR; @@ -1652,14 +1394,17 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv) hw_rf_kill = 1; IWL_DEBUG(IWL_DL_RF_KILL, "RF_KILL bit toggled to %s.\n", - hw_rf_kill ? "disable radio":"enable radio"); + hw_rf_kill ? "disable radio" : "enable radio"); /* driver only loads ucode once setting the interface up. * the driver as well won't allow loading if RFKILL is set * therefore no need to restart the driver from this handler */ - if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status)) + if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status)) { clear_bit(STATUS_RF_KILL_HW, &priv->status); + if (priv->is_open && !iwl_is_rfkill(priv)) + queue_work(priv->workqueue, &priv->up); + } handled |= CSR_INT_BIT_RF_KILL; } @@ -1674,7 +1419,7 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv) if (inta & CSR_INT_BIT_SW_ERR) { IWL_ERROR("Microcode SW error detected. Restarting 0x%X.\n", inta); - iwl4965_irq_handle_error(priv); + iwl_irq_handle_error(priv); handled |= CSR_INT_BIT_SW_ERR; } @@ -1720,7 +1465,7 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv) /* Re-enable all interrupts */ /* only Re-enable if diabled by irq */ if (test_bit(STATUS_INT_ENABLED, &priv->status)) - iwl4965_enable_interrupts(priv); + iwl_enable_interrupts(priv); #ifdef CONFIG_IWLWIFI_DEBUG if (priv->debug_level & (IWL_DL_ISR)) { @@ -1734,7 +1479,7 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } -static irqreturn_t iwl4965_isr(int irq, void *data) +static irqreturn_t iwl_isr(int irq, void *data) { struct iwl_priv *priv = data; u32 inta, inta_mask; @@ -1766,7 +1511,7 @@ static irqreturn_t iwl4965_isr(int irq, void *data) if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) { /* Hardware disappeared. It might have already raised * an interrupt */ - IWL_WARNING("HARDWARE GONE?? INTA == 0x%080x\n", inta); + IWL_WARNING("HARDWARE GONE?? INTA == 0x%08x\n", inta); goto unplugged; } @@ -1775,7 +1520,7 @@ static irqreturn_t iwl4965_isr(int irq, void *data) inta &= ~CSR_INT_BIT_SCD; - /* iwl4965_irq_tasklet() will service interrupts and re-enable them */ + /* iwl_irq_tasklet() will service interrupts and re-enable them */ if (likely(inta || inta_fh)) tasklet_schedule(&priv->irq_tasklet); @@ -1787,7 +1532,7 @@ static irqreturn_t iwl4965_isr(int irq, void *data) /* re-enable interrupts here since we don't have anything to service. */ /* only Re-enable if diabled by irq */ if (test_bit(STATUS_INT_ENABLED, &priv->status)) - iwl4965_enable_interrupts(priv); + iwl_enable_interrupts(priv); spin_unlock(&priv->lock); return IRQ_NONE; } @@ -1798,7 +1543,7 @@ static irqreturn_t iwl4965_isr(int irq, void *data) * ******************************************************************************/ -static void iwl4965_dealloc_ucode_pci(struct iwl_priv *priv) +static void iwl_dealloc_ucode_pci(struct iwl_priv *priv) { iwl_free_fw_desc(priv->pci_dev, &priv->ucode_code); iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data); @@ -1808,7 +1553,7 @@ static void iwl4965_dealloc_ucode_pci(struct iwl_priv *priv) iwl_free_fw_desc(priv->pci_dev, &priv->ucode_boot); } -static void iwl4965_nic_start(struct iwl_priv *priv) +static void iwl_nic_start(struct iwl_priv *priv) { /* Remove all resets to allow NIC to operate */ iwl_write32(priv, CSR_RESET, 0); @@ -1816,31 +1561,47 @@ static void iwl4965_nic_start(struct iwl_priv *priv) /** - * iwl4965_read_ucode - Read uCode images from disk file. + * iwl_read_ucode - Read uCode images from disk file. * * Copy into buffers for card to fetch via bus-mastering */ -static int iwl4965_read_ucode(struct iwl_priv *priv) +static int iwl_read_ucode(struct iwl_priv *priv) { struct iwl_ucode *ucode; - int ret; + int ret = -EINVAL, index; const struct firmware *ucode_raw; - const char *name = priv->cfg->fw_name; + const char *name_pre = priv->cfg->fw_name_pre; + const unsigned int api_max = priv->cfg->ucode_api_max; + const unsigned int api_min = priv->cfg->ucode_api_min; + char buf[25]; u8 *src; size_t len; - u32 ver, inst_size, data_size, init_size, init_data_size, boot_size; + u32 api_ver, inst_size, data_size, init_size, init_data_size, boot_size; /* Ask kernel firmware_class module to get the boot firmware off disk. * request_firmware() is synchronous, file is in memory on return. */ - ret = request_firmware(&ucode_raw, name, &priv->pci_dev->dev); - if (ret < 0) { - IWL_ERROR("%s firmware file req failed: Reason %d\n", - name, ret); - goto error; + for (index = api_max; index >= api_min; index--) { + sprintf(buf, "%s%d%s", name_pre, index, ".ucode"); + ret = request_firmware(&ucode_raw, buf, &priv->pci_dev->dev); + if (ret < 0) { + IWL_ERROR("%s firmware file req failed: Reason %d\n", + buf, ret); + if (ret == -ENOENT) + continue; + else + goto error; + } else { + if (index < api_max) + IWL_ERROR("Loaded firmware %s, which is deprecated. Please use API v%u instead.\n", + buf, api_max); + IWL_DEBUG_INFO("Got firmware '%s' file (%zd bytes) from disk\n", + buf, ucode_raw->size); + break; + } } - IWL_DEBUG_INFO("Got firmware '%s' file (%zd bytes) from disk\n", - name, ucode_raw->size); + if (ret < 0) + goto error; /* Make sure that we got at least our header! */ if (ucode_raw->size < sizeof(*ucode)) { @@ -1852,14 +1613,40 @@ static int iwl4965_read_ucode(struct iwl_priv *priv) /* Data from ucode file: header followed by uCode images */ ucode = (void *)ucode_raw->data; - ver = le32_to_cpu(ucode->ver); + priv->ucode_ver = le32_to_cpu(ucode->ver); + api_ver = IWL_UCODE_API(priv->ucode_ver); inst_size = le32_to_cpu(ucode->inst_size); data_size = le32_to_cpu(ucode->data_size); init_size = le32_to_cpu(ucode->init_size); init_data_size = le32_to_cpu(ucode->init_data_size); boot_size = le32_to_cpu(ucode->boot_size); - IWL_DEBUG_INFO("f/w package hdr ucode version = 0x%x\n", ver); + /* api_ver should match the api version forming part of the + * firmware filename ... but we don't check for that and only rely + * on the API version read from firware header from here on forward */ + + if (api_ver < api_min || api_ver > api_max) { + IWL_ERROR("Driver unable to support your firmware API. " + "Driver supports v%u, firmware is v%u.\n", + api_max, api_ver); + priv->ucode_ver = 0; + ret = -EINVAL; + goto err_release; + } + if (api_ver != api_max) + IWL_ERROR("Firmware has old API version. Expected v%u, " + "got v%u. New firmware can be obtained " + "from http://www.intellinuxwireless.org.\n", + api_max, api_ver); + + printk(KERN_INFO DRV_NAME " loaded firmware version %u.%u.%u.%u\n", + IWL_UCODE_MAJOR(priv->ucode_ver), + IWL_UCODE_MINOR(priv->ucode_ver), + IWL_UCODE_API(priv->ucode_ver), + IWL_UCODE_SERIAL(priv->ucode_ver)); + + IWL_DEBUG_INFO("f/w package hdr ucode version raw = 0x%x\n", + priv->ucode_ver); IWL_DEBUG_INFO("f/w package hdr runtime inst size = %u\n", inst_size); IWL_DEBUG_INFO("f/w package hdr runtime data size = %u\n", @@ -1964,7 +1751,7 @@ static int iwl4965_read_ucode(struct iwl_priv *priv) priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr); /* Runtime data (2nd block) - * NOTE: Copy into backup buffer will be done in iwl4965_up() */ + * NOTE: Copy into backup buffer will be done in iwl_up() */ src = &ucode->data[inst_size]; len = priv->ucode_data.len; IWL_DEBUG_INFO("Copying (but not loading) uCode data len %Zd\n", len); @@ -2002,7 +1789,7 @@ static int iwl4965_read_ucode(struct iwl_priv *priv) err_pci_alloc: IWL_ERROR("failed to allocate pci memory\n"); ret = -ENOMEM; - iwl4965_dealloc_ucode_pci(priv); + iwl_dealloc_ucode_pci(priv); err_release: release_firmware(ucode_raw); @@ -2011,6 +1798,10 @@ static int iwl4965_read_ucode(struct iwl_priv *priv) return ret; } +/* temporary */ +static int iwl_mac_beacon_update(struct ieee80211_hw *hw, + struct sk_buff *skb); + /** * iwl_alive_start - called after REPLY_ALIVE notification received * from protocol/runtime uCode (initialization uCode's @@ -2047,7 +1838,7 @@ static void iwl_alive_start(struct iwl_priv *priv) goto restart; } - /* After the ALIVE response, we can send host commands to 4965 uCode */ + /* After the ALIVE response, we can send host commands to the uCode */ set_bit(STATUS_ALIVE, &priv->status); if (iwl_is_rfkill(priv)) @@ -2067,17 +1858,17 @@ static void iwl_alive_start(struct iwl_priv *priv) active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; } else { /* Initialize our rx_config data */ - iwl4965_connection_init_rx_config(priv); + iwl_connection_init_rx_config(priv, priv->iw_mode); memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); } /* Configure Bluetooth device coexistence support */ - iwl4965_send_bt_config(priv); + iwl_send_bt_config(priv); iwl_reset_run_time_calib(priv); /* Configure the adapter for unassociated operation */ - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); /* At this point, the NIC is initialized and operational */ iwl_rf_kill_ct_config(priv); @@ -2089,12 +1880,21 @@ static void iwl_alive_start(struct iwl_priv *priv) wake_up_interruptible(&priv->wait_command_queue); if (priv->error_recovering) - iwl4965_error_recovery(priv); + iwl_error_recovery(priv); iwl_power_update_mode(priv, 1); + /* reassociate for ADHOC mode */ + if (priv->vif && (priv->iw_mode == NL80211_IFTYPE_ADHOC)) { + struct sk_buff *beacon = ieee80211_beacon_get(priv->hw, + priv->vif); + if (beacon) + iwl_mac_beacon_update(priv->hw, beacon); + } + + if (test_and_clear_bit(STATUS_MODE_PENDING, &priv->status)) - iwl4965_set_mode(priv, priv->iw_mode); + iwl_set_mode(priv, priv->iw_mode); return; @@ -2104,7 +1904,7 @@ static void iwl_alive_start(struct iwl_priv *priv) static void iwl_cancel_deferred_work(struct iwl_priv *priv); -static void __iwl4965_down(struct iwl_priv *priv) +static void __iwl_down(struct iwl_priv *priv) { unsigned long flags; int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status); @@ -2131,14 +1931,14 @@ static void __iwl4965_down(struct iwl_priv *priv) /* tell the device to stop sending interrupts */ spin_lock_irqsave(&priv->lock, flags); - iwl4965_disable_interrupts(priv); + iwl_disable_interrupts(priv); spin_unlock_irqrestore(&priv->lock, flags); iwl_synchronize_irq(priv); if (priv->mac80211_registered) ieee80211_stop_queues(priv->hw); - /* If we have not previously called iwl4965_init() then + /* If we have not previously called iwl_init() then * clear all bits but the RF Kill and SUSPEND bits and return */ if (!iwl_is_init(priv)) { priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) << @@ -2192,8 +1992,6 @@ static void __iwl4965_down(struct iwl_priv *priv) priv->cfg->ops->lib->apm_ops.stop(priv); else priv->cfg->ops->lib->apm_ops.reset(priv); - priv->cfg->ops->lib->free_shared_mem(priv); - exit: memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp)); @@ -2205,10 +2003,10 @@ static void __iwl4965_down(struct iwl_priv *priv) iwl_clear_free_frames(priv); } -static void iwl4965_down(struct iwl_priv *priv) +static void iwl_down(struct iwl_priv *priv) { mutex_lock(&priv->mutex); - __iwl4965_down(priv); + __iwl_down(priv); mutex_unlock(&priv->mutex); iwl_cancel_deferred_work(priv); @@ -2216,7 +2014,7 @@ static void iwl4965_down(struct iwl_priv *priv) #define MAX_HW_RESTARTS 5 -static int __iwl4965_up(struct iwl_priv *priv) +static int __iwl_up(struct iwl_priv *priv) { int i; int ret; @@ -2238,7 +2036,7 @@ static int __iwl4965_up(struct iwl_priv *priv) set_bit(STATUS_RF_KILL_HW, &priv->status); if (iwl_is_rfkill(priv)) { - iwl4965_enable_interrupts(priv); + iwl_enable_interrupts(priv); IWL_WARNING("Radio disabled by %s RF Kill switch\n", test_bit(STATUS_RF_KILL_HW, &priv->status) ? "HW" : "SW"); return 0; @@ -2246,12 +2044,6 @@ static int __iwl4965_up(struct iwl_priv *priv) iwl_write32(priv, CSR_INT, 0xFFFFFFFF); - ret = priv->cfg->ops->lib->alloc_shared_mem(priv); - if (ret) { - IWL_ERROR("Unable to allocate shared memory\n"); - return ret; - } - ret = iwl_hw_nic_init(priv); if (ret) { IWL_ERROR("Unable to init nic\n"); @@ -2265,7 +2057,7 @@ static int __iwl4965_up(struct iwl_priv *priv) /* clear (again), then enable host interrupts */ iwl_write32(priv, CSR_INT, 0xFFFFFFFF); - iwl4965_enable_interrupts(priv); + iwl_enable_interrupts(priv); /* really make sure rfkill handshake bits are cleared */ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); @@ -2295,7 +2087,7 @@ static int __iwl4965_up(struct iwl_priv *priv) clear_bit(STATUS_FW_ERROR, &priv->status); /* start card; "initialize" will load runtime ucode */ - iwl4965_nic_start(priv); + iwl_nic_start(priv); IWL_DEBUG_INFO(DRV_NAME " is coming up\n"); @@ -2303,7 +2095,7 @@ static int __iwl4965_up(struct iwl_priv *priv) } set_bit(STATUS_EXIT_PENDING, &priv->status); - __iwl4965_down(priv); + __iwl_down(priv); clear_bit(STATUS_EXIT_PENDING, &priv->status); /* tried to restart and config the device for as long as our @@ -2345,7 +2137,7 @@ static void iwl_bg_alive_start(struct work_struct *data) mutex_unlock(&priv->mutex); } -static void iwl4965_bg_rf_kill(struct work_struct *work) +static void iwl_bg_rf_kill(struct work_struct *work) { struct iwl_priv *priv = container_of(work, struct iwl_priv, rf_kill); @@ -2379,28 +2171,6 @@ static void iwl4965_bg_rf_kill(struct work_struct *work) iwl_rfkill_set_hw_state(priv); } -static void iwl4965_bg_set_monitor(struct work_struct *work) -{ - struct iwl_priv *priv = container_of(work, - struct iwl_priv, set_monitor); - int ret; - - IWL_DEBUG(IWL_DL_STATE, "setting monitor mode\n"); - - mutex_lock(&priv->mutex); - - ret = iwl4965_set_mode(priv, NL80211_IFTYPE_MONITOR); - - if (ret) { - if (ret == -EAGAIN) - IWL_DEBUG(IWL_DL_STATE, "leave - not ready\n"); - else - IWL_ERROR("iwl4965_set_mode() failed ret = %d\n", ret); - } - - mutex_unlock(&priv->mutex); -} - static void iwl_bg_run_time_calib_work(struct work_struct *work) { struct iwl_priv *priv = container_of(work, struct iwl_priv, @@ -2424,7 +2194,7 @@ static void iwl_bg_run_time_calib_work(struct work_struct *work) return; } -static void iwl4965_bg_up(struct work_struct *data) +static void iwl_bg_up(struct work_struct *data) { struct iwl_priv *priv = container_of(data, struct iwl_priv, up); @@ -2432,23 +2202,23 @@ static void iwl4965_bg_up(struct work_struct *data) return; mutex_lock(&priv->mutex); - __iwl4965_up(priv); + __iwl_up(priv); mutex_unlock(&priv->mutex); iwl_rfkill_set_hw_state(priv); } -static void iwl4965_bg_restart(struct work_struct *data) +static void iwl_bg_restart(struct work_struct *data) { struct iwl_priv *priv = container_of(data, struct iwl_priv, restart); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; - iwl4965_down(priv); + iwl_down(priv); queue_work(priv->workqueue, &priv->up); } -static void iwl4965_bg_rx_replenish(struct work_struct *data) +static void iwl_bg_rx_replenish(struct work_struct *data) { struct iwl_priv *priv = container_of(data, struct iwl_priv, rx_replenish); @@ -2463,11 +2233,10 @@ static void iwl4965_bg_rx_replenish(struct work_struct *data) #define IWL_DELAY_NEXT_SCAN (HZ*2) -static void iwl4965_post_associate(struct iwl_priv *priv) +static void iwl_post_associate(struct iwl_priv *priv) { struct ieee80211_conf *conf = NULL; int ret = 0; - DECLARE_MAC_BUF(mac); unsigned long flags; if (priv->iw_mode == NL80211_IFTYPE_AP) { @@ -2475,9 +2244,8 @@ static void iwl4965_post_associate(struct iwl_priv *priv) return; } - IWL_DEBUG_ASSOC("Associated as %d to: %s\n", - priv->assoc_id, - print_mac(mac, priv->active_rxon.bssid_addr)); + IWL_DEBUG_ASSOC("Associated as %d to: %pM\n", + priv->assoc_id, priv->active_rxon.bssid_addr); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) @@ -2493,10 +2261,9 @@ static void iwl4965_post_associate(struct iwl_priv *priv) conf = ieee80211_get_hw_conf(priv->hw); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); - memset(&priv->rxon_timing, 0, sizeof(struct iwl4965_rxon_time_cmd)); - iwl4965_setup_rxon_timing(priv); + iwl_setup_rxon_timing(priv); ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, sizeof(priv->rxon_timing), &priv->rxon_timing); if (ret) @@ -2529,7 +2296,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv) } - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); switch (priv->iw_mode) { case NL80211_IFTYPE_STATION: @@ -2541,7 +2308,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv) priv->assoc_id = 1; iwl_rxon_add_station(priv, priv->bssid, 0); - iwl4965_send_beacon_cmd(priv); + iwl_send_beacon_cmd(priv); break; @@ -2578,7 +2345,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv) #define UCODE_READY_TIMEOUT (4 * HZ) -static int iwl4965_mac_start(struct ieee80211_hw *hw) +static int iwl_mac_start(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; int ret; @@ -2600,7 +2367,7 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw) pci_write_config_word(priv->pci_dev, PCI_COMMAND, pci_cmd); } - ret = request_irq(priv->pci_dev->irq, iwl4965_isr, IRQF_SHARED, + ret = request_irq(priv->pci_dev->irq, iwl_isr, IRQF_SHARED, DRV_NAME, priv); if (ret) { IWL_ERROR("Error allocating IRQ %d\n", priv->pci_dev->irq); @@ -2615,7 +2382,7 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw) * ucode filename and max sizes are card-specific. */ if (!priv->ucode_code.len) { - ret = iwl4965_read_ucode(priv); + ret = iwl_read_ucode(priv); if (ret) { IWL_ERROR("Could not read microcode: %d\n", ret); mutex_unlock(&priv->mutex); @@ -2623,7 +2390,7 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw) } } - ret = __iwl4965_up(priv); + ret = __iwl_up(priv); mutex_unlock(&priv->mutex); @@ -2669,7 +2436,7 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw) return ret; } -static void iwl4965_mac_stop(struct ieee80211_hw *hw) +static void iwl_mac_stop(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; @@ -2691,7 +2458,7 @@ static void iwl4965_mac_stop(struct ieee80211_hw *hw) mutex_unlock(&priv->mutex); } - iwl4965_down(priv); + iwl_down(priv); flush_workqueue(priv->workqueue); free_irq(priv->pci_dev->irq, priv); @@ -2702,7 +2469,7 @@ static void iwl4965_mac_stop(struct ieee80211_hw *hw) IWL_DEBUG_MAC80211("leave\n"); } -static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct iwl_priv *priv = hw->priv; @@ -2718,12 +2485,11 @@ static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) return 0; } -static int iwl4965_mac_add_interface(struct ieee80211_hw *hw, +static int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { struct iwl_priv *priv = hw->priv; unsigned long flags; - DECLARE_MAC_BUF(mac); IWL_DEBUG_MAC80211("enter: type %d\n", conf->type); @@ -2734,17 +2500,18 @@ static int iwl4965_mac_add_interface(struct ieee80211_hw *hw, spin_lock_irqsave(&priv->lock, flags); priv->vif = conf->vif; + priv->iw_mode = conf->type; spin_unlock_irqrestore(&priv->lock, flags); mutex_lock(&priv->mutex); if (conf->mac_addr) { - IWL_DEBUG_MAC80211("Set %s\n", print_mac(mac, conf->mac_addr)); + IWL_DEBUG_MAC80211("Set %pM\n", conf->mac_addr); memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); } - if (iwl4965_set_mode(priv, conf->type) == -EAGAIN) + if (iwl_set_mode(priv, conf->type) == -EAGAIN) /* we are not ready, will run again when ready */ set_bit(STATUS_MODE_PENDING, &priv->status); @@ -2755,16 +2522,17 @@ static int iwl4965_mac_add_interface(struct ieee80211_hw *hw, } /** - * iwl4965_mac_config - mac80211 config callback + * iwl_mac_config - mac80211 config callback * * We ignore conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME since it seems to * be set inappropriately and the driver currently sets the hardware up to * use it whenever needed. */ -static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +static int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) { struct iwl_priv *priv = hw->priv; const struct iwl_channel_info *ch_info; + struct ieee80211_conf *conf = &hw->conf; unsigned long flags; int ret = 0; u16 channel; @@ -2772,6 +2540,8 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co mutex_lock(&priv->mutex); IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel->hw_value); + priv->current_ht_config.is_ht = conf->ht.enabled; + if (conf->radio_enabled && iwl_radio_kill_sw_enable_radio(priv)) { IWL_DEBUG_MAC80211("leave - RF-KILL - waiting for uCode\n"); goto out; @@ -2829,13 +2599,13 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co /* The list of supported rates and rate mask can be different * for each band; since the band may have changed, reset * the rate mask to what mac80211 lists */ - iwl4965_set_rate(priv); + iwl_set_rate(priv); spin_unlock_irqrestore(&priv->lock, flags); #ifdef IEEE80211_CONF_CHANNEL_SWITCH if (conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) { - iwl4965_hw_channel_switch(priv, conf->channel); + iwl_hw_channel_switch(priv, conf->channel); goto out; } #endif @@ -2863,11 +2633,11 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co iwl_set_tx_power(priv, conf->power_level, false); - iwl4965_set_rate(priv); + iwl_set_rate(priv); if (memcmp(&priv->active_rxon, &priv->staging_rxon, sizeof(priv->staging_rxon))) - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); else IWL_DEBUG_INFO("No re-sending same RXON configuration.\n"); @@ -2878,7 +2648,7 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co return ret; } -static void iwl4965_config_ap(struct iwl_priv *priv) +static void iwl_config_ap(struct iwl_priv *priv) { int ret = 0; unsigned long flags; @@ -2887,15 +2657,14 @@ static void iwl4965_config_ap(struct iwl_priv *priv) return; /* The following should be done only at AP bring up */ - if (!(iwl_is_associated(priv))) { + if (!iwl_is_associated(priv)) { /* RXON - unassoc (to set timing command) */ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); /* RXON Timing */ - memset(&priv->rxon_timing, 0, sizeof(struct iwl4965_rxon_time_cmd)); - iwl4965_setup_rxon_timing(priv); + iwl_setup_rxon_timing(priv); ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, sizeof(priv->rxon_timing), &priv->rxon_timing); if (ret) @@ -2928,29 +2697,25 @@ static void iwl4965_config_ap(struct iwl_priv *priv) } /* restore RXON assoc */ priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); spin_lock_irqsave(&priv->lock, flags); iwl_activate_qos(priv, 1); spin_unlock_irqrestore(&priv->lock, flags); iwl_rxon_add_station(priv, iwl_bcast_addr, 0); } - iwl4965_send_beacon_cmd(priv); + iwl_send_beacon_cmd(priv); /* FIXME - we need to add code here to detect a totally new * configuration, reset the AP, unassoc, rxon timing, assoc, * clear sta table, add BCAST sta... */ } -/* temporary */ -static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb); -static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, +static int iwl_mac_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_if_conf *conf) { struct iwl_priv *priv = hw->priv; - DECLARE_MAC_BUF(mac); - unsigned long flags; int rc; if (conf == NULL) @@ -2966,26 +2731,20 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); if (!beacon) return -ENOMEM; - rc = iwl4965_mac_beacon_update(hw, beacon); + mutex_lock(&priv->mutex); + rc = iwl_mac_beacon_update(hw, beacon); + mutex_unlock(&priv->mutex); if (rc) return rc; } - if ((priv->iw_mode == NL80211_IFTYPE_AP) && - (!conf->ssid_len)) { - IWL_DEBUG_MAC80211 - ("Leaving in AP mode because HostAPD is not ready.\n"); - return 0; - } - if (!iwl_is_alive(priv)) return -EAGAIN; mutex_lock(&priv->mutex); if (conf->bssid) - IWL_DEBUG_MAC80211("bssid: %s\n", - print_mac(mac, conf->bssid)); + IWL_DEBUG_MAC80211("bssid: %pM\n", conf->bssid); /* * very dubious code was here; the probe filtering flag is never set: @@ -2998,8 +2757,8 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, if (!conf->bssid) { conf->bssid = priv->mac_addr; memcpy(priv->bssid, priv->mac_addr, ETH_ALEN); - IWL_DEBUG_MAC80211("bssid was set to: %s\n", - print_mac(mac, conf->bssid)); + IWL_DEBUG_MAC80211("bssid was set to: %pM\n", + conf->bssid); } if (priv->ibss_beacon) dev_kfree_skb(priv->ibss_beacon); @@ -3030,9 +2789,9 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, memcpy(priv->bssid, conf->bssid, ETH_ALEN); if (priv->iw_mode == NL80211_IFTYPE_AP) - iwl4965_config_ap(priv); + iwl_config_ap(priv); else { - rc = iwl4965_commit_rxon(priv); + rc = iwl_commit_rxon(priv); if ((priv->iw_mode == NL80211_IFTYPE_STATION) && rc) iwl_rxon_add_station( priv, priv->active_rxon.bssid_addr, 1); @@ -3041,45 +2800,63 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, } else { iwl_scan_cancel_timeout(priv, 100); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); } done: - spin_lock_irqsave(&priv->lock, flags); - if (!conf->ssid_len) - memset(priv->essid, 0, IW_ESSID_MAX_SIZE); - else - memcpy(priv->essid, conf->ssid, conf->ssid_len); - - priv->essid_len = conf->ssid_len; - spin_unlock_irqrestore(&priv->lock, flags); - IWL_DEBUG_MAC80211("leave\n"); mutex_unlock(&priv->mutex); return 0; } -static void iwl4965_configure_filter(struct ieee80211_hw *hw, +static void iwl_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, int mc_count, struct dev_addr_list *mc_list) { struct iwl_priv *priv = hw->priv; + __le32 *filter_flags = &priv->staging_rxon.filter_flags; - if (changed_flags & (*total_flags) & FIF_OTHER_BSS) { - IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n", - NL80211_IFTYPE_MONITOR, - changed_flags, *total_flags); - /* queue work 'cuz mac80211 is holding a lock which - * prevents us from issuing (synchronous) f/w cmds */ - queue_work(priv->workqueue, &priv->set_monitor); + IWL_DEBUG_MAC80211("Enter: changed: 0x%x, total: 0x%x\n", + changed_flags, *total_flags); + + if (changed_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS)) { + if (*total_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS)) + *filter_flags |= RXON_FILTER_PROMISC_MSK; + else + *filter_flags &= ~RXON_FILTER_PROMISC_MSK; + } + if (changed_flags & FIF_ALLMULTI) { + if (*total_flags & FIF_ALLMULTI) + *filter_flags |= RXON_FILTER_ACCEPT_GRP_MSK; + else + *filter_flags &= ~RXON_FILTER_ACCEPT_GRP_MSK; + } + if (changed_flags & FIF_CONTROL) { + if (*total_flags & FIF_CONTROL) + *filter_flags |= RXON_FILTER_CTL2HOST_MSK; + else + *filter_flags &= ~RXON_FILTER_CTL2HOST_MSK; } - *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | + if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { + if (*total_flags & FIF_BCN_PRBRESP_PROMISC) + *filter_flags |= RXON_FILTER_BCON_AWARE_MSK; + else + *filter_flags &= ~RXON_FILTER_BCON_AWARE_MSK; + } + + /* We avoid iwl_commit_rxon here to commit the new filter flags + * since mac80211 will call ieee80211_hw_config immediately. + * (mc_list is not supported at this time). Otherwise, we need to + * queue a background iwl_commit_rxon work. + */ + + *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS | FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; } -static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw, +static void iwl_mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { struct iwl_priv *priv = hw->priv; @@ -3091,13 +2868,11 @@ static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw, if (iwl_is_ready_rf(priv)) { iwl_scan_cancel_timeout(priv, 100); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); } if (priv->vif == conf->vif) { priv->vif = NULL; memset(priv->bssid, 0, ETH_ALEN); - memset(priv->essid, 0, IW_ESSID_MAX_SIZE); - priv->essid_len = 0; } mutex_unlock(&priv->mutex); @@ -3106,7 +2881,7 @@ static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw, } #define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6) -static void iwl4965_bss_info_changed(struct ieee80211_hw *hw, +static void iwl_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, u32 changes) @@ -3133,8 +2908,7 @@ static void iwl4965_bss_info_changed(struct ieee80211_hw *hw, } if (changes & BSS_CHANGED_HT) { - IWL_DEBUG_MAC80211("HT %d\n", bss_conf->assoc_ht); - iwl4965_ht_conf(priv, bss_conf); + iwl_ht_conf(priv, bss_conf); iwl_set_rxon_chain(priv); } @@ -3157,7 +2931,7 @@ static void iwl4965_bss_info_changed(struct ieee80211_hw *hw, priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN_AFTER_ASSOC; mutex_lock(&priv->mutex); - iwl4965_post_associate(priv); + iwl_post_associate(priv); mutex_unlock(&priv->mutex); } else { priv->assoc_id = 0; @@ -3187,12 +2961,6 @@ static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t ssid_len) goto out_unlock; } - if (priv->iw_mode == NL80211_IFTYPE_AP) { /* APs don't scan */ - ret = -EIO; - IWL_ERROR("ERROR: APs don't scan\n"); - goto out_unlock; - } - /* We don't schedule scan within next_scan_jiffies period. * Avoid scanning during possible EAPOL exchange, return * success immediately. @@ -3233,64 +3001,24 @@ static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t ssid_len) return ret; } -static void iwl4965_mac_update_tkip_key(struct ieee80211_hw *hw, +static void iwl_mac_update_tkip_key(struct ieee80211_hw *hw, struct ieee80211_key_conf *keyconf, const u8 *addr, u32 iv32, u16 *phase1key) { - struct iwl_priv *priv = hw->priv; - u8 sta_id = IWL_INVALID_STATION; - unsigned long flags; - __le16 key_flags = 0; - int i; - DECLARE_MAC_BUF(mac); + struct iwl_priv *priv = hw->priv; IWL_DEBUG_MAC80211("enter\n"); - sta_id = iwl_find_station(priv, addr); - if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_MAC80211("leave - %s not in station map.\n", - print_mac(mac, addr)); - return; - } - - if (iwl_scan_cancel(priv)) { - /* cancel scan failed, just live w/ bad key and rely - briefly on SW decryption */ - return; - } - - key_flags |= (STA_KEY_FLG_TKIP | STA_KEY_FLG_MAP_KEY_MSK); - key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); - key_flags &= ~STA_KEY_FLG_INVALID; - - if (sta_id == priv->hw_params.bcast_sta_id) - key_flags |= STA_KEY_MULTICAST_MSK; - - spin_lock_irqsave(&priv->sta_lock, flags); - - priv->stations[sta_id].sta.key.key_flags = key_flags; - priv->stations[sta_id].sta.key.tkip_rx_tsc_byte2 = (u8) iv32; - - for (i = 0; i < 5; i++) - priv->stations[sta_id].sta.key.tkip_rx_ttak[i] = - cpu_to_le16(phase1key[i]); - - priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; - priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; - - iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); - - spin_unlock_irqrestore(&priv->sta_lock, flags); + iwl_update_tkip_key(priv, keyconf, addr, iv32, phase1key); IWL_DEBUG_MAC80211("leave\n"); } -static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, +static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, const u8 *local_addr, const u8 *addr, struct ieee80211_key_conf *key) { struct iwl_priv *priv = hw->priv; - DECLARE_MAC_BUF(mac); int ret = 0; u8 sta_id = IWL_INVALID_STATION; u8 is_default_wep_key = 0; @@ -3308,8 +3036,8 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, sta_id = iwl_find_station(priv, addr); if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_MAC80211("leave - %s not in station map.\n", - print_mac(mac, addr)); + IWL_DEBUG_MAC80211("leave - %pM not in station map.\n", + addr); return -EINVAL; } @@ -3357,7 +3085,7 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return ret; } -static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, +static int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params) { struct iwl_priv *priv = hw->priv; @@ -3376,11 +3104,6 @@ static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, return 0; } - if (!priv->qos_data.qos_enable) { - priv->qos_data.qos_active = 0; - IWL_DEBUG_MAC80211("leave - qos not enabled\n"); - return 0; - } q = AC_NUM - 1 - queue; spin_lock_irqsave(&priv->lock, flags); @@ -3405,15 +3128,14 @@ static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, return 0; } -static int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, +static int iwl_mac_ampdu_action(struct ieee80211_hw *hw, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn) { struct iwl_priv *priv = hw->priv; - DECLARE_MAC_BUF(mac); - IWL_DEBUG_HT("A-MPDU action on addr %s tid %d\n", - print_mac(mac, sta->addr), tid); + IWL_DEBUG_HT("A-MPDU action on addr %pM tid %d\n", + sta->addr, tid); if (!(priv->cfg->sku & IWL_SKU_N)) return -EACCES; @@ -3421,10 +3143,10 @@ static int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, switch (action) { case IEEE80211_AMPDU_RX_START: IWL_DEBUG_HT("start Rx\n"); - return iwl_rx_agg_start(priv, sta->addr, tid, *ssn); + return iwl_sta_rx_agg_start(priv, sta->addr, tid, *ssn); case IEEE80211_AMPDU_RX_STOP: IWL_DEBUG_HT("stop Rx\n"); - return iwl_rx_agg_stop(priv, sta->addr, tid); + return iwl_sta_rx_agg_stop(priv, sta->addr, tid); case IEEE80211_AMPDU_TX_START: IWL_DEBUG_HT("start Tx\n"); return iwl_tx_agg_start(priv, sta->addr, tid, ssn); @@ -3438,7 +3160,8 @@ static int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, } return 0; } -static int iwl4965_mac_get_tx_stats(struct ieee80211_hw *hw, + +static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, struct ieee80211_tx_queue_stats *stats) { struct iwl_priv *priv = hw->priv; @@ -3473,7 +3196,7 @@ static int iwl4965_mac_get_tx_stats(struct ieee80211_hw *hw, return 0; } -static int iwl4965_mac_get_stats(struct ieee80211_hw *hw, +static int iwl_mac_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats) { struct iwl_priv *priv = hw->priv; @@ -3485,7 +3208,7 @@ static int iwl4965_mac_get_stats(struct ieee80211_hw *hw, return 0; } -static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw) +static void iwl_mac_reset_tsf(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; unsigned long flags; @@ -3529,7 +3252,7 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw) if (priv->iw_mode != NL80211_IFTYPE_AP) { iwl_scan_cancel_timeout(priv, 100); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); } iwl_power_update_mode(priv, 0); @@ -3552,31 +3275,28 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw) return; } - iwl4965_set_rate(priv); + iwl_set_rate(priv); mutex_unlock(&priv->mutex); IWL_DEBUG_MAC80211("leave\n"); } -static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) +static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) { struct iwl_priv *priv = hw->priv; unsigned long flags; __le64 timestamp; - mutex_lock(&priv->mutex); IWL_DEBUG_MAC80211("enter\n"); if (!iwl_is_ready_rf(priv)) { IWL_DEBUG_MAC80211("leave - RF not ready\n"); - mutex_unlock(&priv->mutex); return -EIO; } if (priv->iw_mode != NL80211_IFTYPE_ADHOC) { IWL_DEBUG_MAC80211("leave - not IBSS\n"); - mutex_unlock(&priv->mutex); return -EIO; } @@ -3596,9 +3316,8 @@ static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk iwl_reset_qos(priv); - iwl4965_post_associate(priv); + iwl_post_associate(priv); - mutex_unlock(&priv->mutex); return 0; } @@ -3613,7 +3332,7 @@ static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk /* * The following adds a new attribute to the sysfs representation - * of this device driver (i.e. a new file in /sys/bus/pci/drivers/iwl/) + * of this device driver (i.e. a new file in /sys/class/net/wlan0/device/) * used for controlling the debug level. * * See the level definitions in iwl for details. @@ -3699,7 +3418,11 @@ static ssize_t show_tx_power(struct device *d, struct device_attribute *attr, char *buf) { struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; - return sprintf(buf, "%d\n", priv->tx_power_user_lmt); + + if (!iwl_is_ready_rf(priv)) + return sprintf(buf, "off\n"); + else + return sprintf(buf, "%d\n", priv->tx_power_user_lmt); } static ssize_t store_tx_power(struct device *d, @@ -3750,7 +3473,7 @@ static ssize_t store_flags(struct device *d, else { IWL_DEBUG_INFO("Commit rxon.flags = 0x%04X\n", flags); priv->staging_rxon.flags = cpu_to_le32(flags); - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); } } mutex_unlock(&priv->mutex); @@ -3791,7 +3514,7 @@ static ssize_t store_filter_flags(struct device *d, "0x%04X\n", filter_flags); priv->staging_rxon.filter_flags = cpu_to_le32(filter_flags); - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); } } mutex_unlock(&priv->mutex); @@ -3802,79 +3525,6 @@ static ssize_t store_filter_flags(struct device *d, static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags, store_filter_flags); -#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT - -static ssize_t show_measurement(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - struct iwl4965_spectrum_notification measure_report; - u32 size = sizeof(measure_report), len = 0, ofs = 0; - u8 *data = (u8 *)&measure_report; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - if (!(priv->measurement_status & MEASUREMENT_READY)) { - spin_unlock_irqrestore(&priv->lock, flags); - return 0; - } - memcpy(&measure_report, &priv->measure_report, size); - priv->measurement_status = 0; - spin_unlock_irqrestore(&priv->lock, flags); - - while (size && (PAGE_SIZE - len)) { - hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len, - PAGE_SIZE - len, 1); - len = strlen(buf); - if (PAGE_SIZE - len) - buf[len++] = '\n'; - - ofs += 16; - size -= min(size, 16U); - } - - return len; -} - -static ssize_t store_measurement(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - struct ieee80211_measurement_params params = { - .channel = le16_to_cpu(priv->active_rxon.channel), - .start_time = cpu_to_le64(priv->last_tsf), - .duration = cpu_to_le16(1), - }; - u8 type = IWL_MEASURE_BASIC; - u8 buffer[32]; - u8 channel; - - if (count) { - char *p = buffer; - strncpy(buffer, buf, min(sizeof(buffer), count)); - channel = simple_strtoul(p, NULL, 0); - if (channel) - params.channel = channel; - - p = buffer; - while (*p && *p != ' ') - p++; - if (*p) - type = simple_strtoul(p + 1, NULL, 0); - } - - IWL_DEBUG_INFO("Invoking measurement of type %d on " - "channel %d (for '%s')\n", type, params.channel, buf); - iwl4965_get_measurement(priv, ¶ms, type); - - return count; -} - -static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR, - show_measurement, store_measurement); -#endif /* CONFIG_IWLAGN_SPECTRUM_MEASUREMENT */ - static ssize_t store_retry_rate(struct device *d, struct device_attribute *attr, const char *buf, size_t count) @@ -3953,7 +3603,8 @@ static ssize_t show_power_level(struct device *d, break; } - p += sprintf(p, "\tMODE:%s", (mode < IWL_POWER_AUTO)?"fixed":"auto"); + p += sprintf(p, "\tMODE:%s", (mode < IWL_POWER_AUTO) ? + "fixed" : "auto"); p += sprintf(p, "\tINDEX:%d", level); p += sprintf(p, "\n"); return p - buf + 1; @@ -3962,68 +3613,6 @@ static ssize_t show_power_level(struct device *d, static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level, store_power_level); -static ssize_t show_channels(struct device *d, - struct device_attribute *attr, char *buf) -{ - - struct iwl_priv *priv = dev_get_drvdata(d); - struct ieee80211_channel *channels = NULL; - const struct ieee80211_supported_band *supp_band = NULL; - int len = 0, i; - int count = 0; - - if (!test_bit(STATUS_GEO_CONFIGURED, &priv->status)) - return -EAGAIN; - - supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_2GHZ); - channels = supp_band->channels; - count = supp_band->n_channels; - - len += sprintf(&buf[len], - "Displaying %d channels in 2.4GHz band " - "(802.11bg):\n", count); - - for (i = 0; i < count; i++) - len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n", - ieee80211_frequency_to_channel( - channels[i].center_freq), - channels[i].max_power, - channels[i].flags & IEEE80211_CHAN_RADAR ? - " (IEEE 802.11h required)" : "", - (!(channels[i].flags & IEEE80211_CHAN_NO_IBSS) - || (channels[i].flags & - IEEE80211_CHAN_RADAR)) ? "" : - ", IBSS", - channels[i].flags & - IEEE80211_CHAN_PASSIVE_SCAN ? - "passive only" : "active/passive"); - - supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_5GHZ); - channels = supp_band->channels; - count = supp_band->n_channels; - - len += sprintf(&buf[len], "Displaying %d channels in 5.2GHz band " - "(802.11a):\n", count); - - for (i = 0; i < count; i++) - len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n", - ieee80211_frequency_to_channel( - channels[i].center_freq), - channels[i].max_power, - channels[i].flags & IEEE80211_CHAN_RADAR ? - " (IEEE 802.11h required)" : "", - ((channels[i].flags & IEEE80211_CHAN_NO_IBSS) - || (channels[i].flags & - IEEE80211_CHAN_RADAR)) ? "" : - ", IBSS", - channels[i].flags & - IEEE80211_CHAN_PASSIVE_SCAN ? - "passive only" : "active/passive"); - - return len; -} - -static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL); static ssize_t show_statistics(struct device *d, struct device_attribute *attr, char *buf) @@ -4086,12 +3675,11 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) init_waitqueue_head(&priv->wait_command_queue); - INIT_WORK(&priv->up, iwl4965_bg_up); - INIT_WORK(&priv->restart, iwl4965_bg_restart); - INIT_WORK(&priv->rx_replenish, iwl4965_bg_rx_replenish); - INIT_WORK(&priv->rf_kill, iwl4965_bg_rf_kill); - INIT_WORK(&priv->beacon_update, iwl4965_bg_beacon_update); - INIT_WORK(&priv->set_monitor, iwl4965_bg_set_monitor); + INIT_WORK(&priv->up, iwl_bg_up); + INIT_WORK(&priv->restart, iwl_bg_restart); + INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish); + INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill); + INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update); INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work); INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start); INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start); @@ -4104,10 +3692,10 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) init_timer(&priv->statistics_periodic); priv->statistics_periodic.data = (unsigned long)priv; - priv->statistics_periodic.function = iwl4965_bg_statistics_periodic; + priv->statistics_periodic.function = iwl_bg_statistics_periodic; tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) - iwl4965_irq_tasklet, (unsigned long)priv); + iwl_irq_tasklet, (unsigned long)priv); } static void iwl_cancel_deferred_work(struct iwl_priv *priv) @@ -4123,13 +3711,9 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv) del_timer_sync(&priv->statistics_periodic); } -static struct attribute *iwl4965_sysfs_entries[] = { - &dev_attr_channels.attr, +static struct attribute *iwl_sysfs_entries[] = { &dev_attr_flags.attr, &dev_attr_filter_flags.attr, -#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT - &dev_attr_measurement.attr, -#endif &dev_attr_power_level.attr, &dev_attr_retry_rate.attr, &dev_attr_statistics.attr, @@ -4144,39 +3728,38 @@ static struct attribute *iwl4965_sysfs_entries[] = { NULL }; -static struct attribute_group iwl4965_attribute_group = { +static struct attribute_group iwl_attribute_group = { .name = NULL, /* put in device directory */ - .attrs = iwl4965_sysfs_entries, + .attrs = iwl_sysfs_entries, }; -static struct ieee80211_ops iwl4965_hw_ops = { - .tx = iwl4965_mac_tx, - .start = iwl4965_mac_start, - .stop = iwl4965_mac_stop, - .add_interface = iwl4965_mac_add_interface, - .remove_interface = iwl4965_mac_remove_interface, - .config = iwl4965_mac_config, - .config_interface = iwl4965_mac_config_interface, - .configure_filter = iwl4965_configure_filter, - .set_key = iwl4965_mac_set_key, - .update_tkip_key = iwl4965_mac_update_tkip_key, - .get_stats = iwl4965_mac_get_stats, - .get_tx_stats = iwl4965_mac_get_tx_stats, - .conf_tx = iwl4965_mac_conf_tx, - .reset_tsf = iwl4965_mac_reset_tsf, - .bss_info_changed = iwl4965_bss_info_changed, - .ampdu_action = iwl4965_mac_ampdu_action, +static struct ieee80211_ops iwl_hw_ops = { + .tx = iwl_mac_tx, + .start = iwl_mac_start, + .stop = iwl_mac_stop, + .add_interface = iwl_mac_add_interface, + .remove_interface = iwl_mac_remove_interface, + .config = iwl_mac_config, + .config_interface = iwl_mac_config_interface, + .configure_filter = iwl_configure_filter, + .set_key = iwl_mac_set_key, + .update_tkip_key = iwl_mac_update_tkip_key, + .get_stats = iwl_mac_get_stats, + .get_tx_stats = iwl_mac_get_tx_stats, + .conf_tx = iwl_mac_conf_tx, + .reset_tsf = iwl_mac_reset_tsf, + .bss_info_changed = iwl_bss_info_changed, + .ampdu_action = iwl_mac_ampdu_action, .hw_scan = iwl_mac_hw_scan }; -static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { int err = 0; struct iwl_priv *priv; struct ieee80211_hw *hw; struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data); unsigned long flags; - DECLARE_MAC_BUF(mac); /************************ * 1. Allocating HW data @@ -4188,10 +3771,10 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e if (cfg->mod_params->debug & IWL_DL_INFO) dev_printk(KERN_DEBUG, &(pdev->dev), "Disabling hw_scan\n"); - iwl4965_hw_ops.hw_scan = NULL; + iwl_hw_ops.hw_scan = NULL; } - hw = iwl_alloc_all(cfg, &iwl4965_hw_ops); + hw = iwl_alloc_all(cfg, &iwl_hw_ops); if (!hw) { err = -ENOMEM; goto out; @@ -4285,7 +3868,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e /* extract MAC Address */ iwl_eeprom_get_mac(priv, priv->mac_addr); - IWL_DEBUG_INFO("MAC address: %s\n", print_mac(mac, priv->mac_addr)); + IWL_DEBUG_INFO("MAC address: %pM\n", priv->mac_addr); SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr); /************************ @@ -4319,10 +3902,10 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e * 8. Setup services ********************/ spin_lock_irqsave(&priv->lock, flags); - iwl4965_disable_interrupts(priv); + iwl_disable_interrupts(priv); spin_unlock_irqrestore(&priv->lock, flags); - err = sysfs_create_group(&pdev->dev.kobj, &iwl4965_attribute_group); + err = sysfs_create_group(&pdev->dev.kobj, &iwl_attribute_group); if (err) { IWL_ERROR("failed to create sysfs device attributes\n"); goto out_uninit_drv; @@ -4358,7 +3941,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e return 0; out_remove_sysfs: - sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group); + sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group); out_uninit_drv: iwl_uninit_drv(priv); out_free_eeprom: @@ -4376,7 +3959,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e return err; } -static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) +static void __devexit iwl_pci_remove(struct pci_dev *pdev) { struct iwl_priv *priv = pci_get_drvdata(pdev); unsigned long flags; @@ -4387,10 +3970,10 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) IWL_DEBUG_INFO("*** UNLOAD DRIVER ***\n"); iwl_dbgfs_unregister(priv); - sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group); + sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group); - /* ieee80211_unregister_hw call wil cause iwl4965_mac_stop to - * to be called and iwl4965_down since we are removing the device + /* ieee80211_unregister_hw call wil cause iwl_mac_stop to + * to be called and iwl_down since we are removing the device * we need to set STATUS_EXIT_PENDING bit. */ set_bit(STATUS_EXIT_PENDING, &priv->status); @@ -4398,20 +3981,20 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) ieee80211_unregister_hw(priv->hw); priv->mac80211_registered = 0; } else { - iwl4965_down(priv); + iwl_down(priv); } /* make sure we flush any pending irq or * tasklet for the driver */ spin_lock_irqsave(&priv->lock, flags); - iwl4965_disable_interrupts(priv); + iwl_disable_interrupts(priv); spin_unlock_irqrestore(&priv->lock, flags); iwl_synchronize_irq(priv); iwl_rfkill_unregister(priv); - iwl4965_dealloc_ucode_pci(priv); + iwl_dealloc_ucode_pci(priv); if (priv->rxq.bd) iwl_rx_queue_free(priv, &priv->rxq); @@ -4424,7 +4007,7 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) /*netif_stop_queue(dev); */ flush_workqueue(priv->workqueue); - /* ieee80211_unregister_hw calls iwl4965_mac_stop, which flushes + /* ieee80211_unregister_hw calls iwl_mac_stop, which flushes * priv->workqueue... so we can't take down the workqueue * until now... */ destroy_workqueue(priv->workqueue); @@ -4445,13 +4028,13 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) #ifdef CONFIG_PM -static int iwl4965_pci_suspend(struct pci_dev *pdev, pm_message_t state) +static int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) { struct iwl_priv *priv = pci_get_drvdata(pdev); if (priv->is_open) { set_bit(STATUS_IN_SUSPEND, &priv->status); - iwl4965_mac_stop(priv->hw); + iwl_mac_stop(priv->hw); priv->is_open = 1; } @@ -4460,14 +4043,14 @@ static int iwl4965_pci_suspend(struct pci_dev *pdev, pm_message_t state) return 0; } -static int iwl4965_pci_resume(struct pci_dev *pdev) +static int iwl_pci_resume(struct pci_dev *pdev) { struct iwl_priv *priv = pci_get_drvdata(pdev); pci_set_power_state(pdev, PCI_D0); if (priv->is_open) - iwl4965_mac_start(priv->hw); + iwl_mac_start(priv->hw); clear_bit(STATUS_IN_SUSPEND, &priv->status); return 0; @@ -4502,7 +4085,11 @@ static struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x423A, 0x1001, iwl5350_agn_cfg)}, {IWL_PCI_DEVICE(0x423A, 0x1021, iwl5350_agn_cfg)}, {IWL_PCI_DEVICE(0x423B, 0x1011, iwl5350_agn_cfg)}, +/* 5150 Wifi/WiMax */ + {IWL_PCI_DEVICE(0x423C, PCI_ANY_ID, iwl5150_agn_cfg)}, + {IWL_PCI_DEVICE(0x423D, PCI_ANY_ID, iwl5150_agn_cfg)}, #endif /* CONFIG_IWL5000 */ + {0} }; MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids); @@ -4510,15 +4097,15 @@ MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids); static struct pci_driver iwl_driver = { .name = DRV_NAME, .id_table = iwl_hw_card_ids, - .probe = iwl4965_pci_probe, - .remove = __devexit_p(iwl4965_pci_remove), + .probe = iwl_pci_probe, + .remove = __devexit_p(iwl_pci_remove), #ifdef CONFIG_PM - .suspend = iwl4965_pci_suspend, - .resume = iwl4965_pci_resume, + .suspend = iwl_pci_suspend, + .resume = iwl_pci_resume, #endif }; -static int __init iwl4965_init(void) +static int __init iwl_init(void) { int ret; @@ -4544,11 +4131,11 @@ static int __init iwl4965_init(void) return ret; } -static void __exit iwl4965_exit(void) +static void __exit iwl_exit(void) { pci_unregister_driver(&iwl_driver); iwlagn_rate_control_unregister(); } -module_exit(iwl4965_exit); -module_init(iwl4965_init); +module_exit(iwl_exit); +module_init(iwl_init); diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index 72fbf47229db7da9832c3eb05a6c2722df651b7e..f836ecc55758a4d4ab12bf0a796fbd17b9ef2556 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * Tomas Winkler + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -70,7 +70,16 @@ * INIT calibrations framework *****************************************************************************/ - int iwl_send_calib_results(struct iwl_priv *priv) +struct statistics_general_data { + u32 beacon_silence_rssi_a; + u32 beacon_silence_rssi_b; + u32 beacon_silence_rssi_c; + u32 beacon_energy_a; + u32 beacon_energy_b; + u32 beacon_energy_c; +}; + +int iwl_send_calib_results(struct iwl_priv *priv) { int ret = 0; int i = 0; @@ -80,14 +89,16 @@ .meta.flags = CMD_SIZE_HUGE, }; - for (i = 0; i < IWL_CALIB_MAX; i++) - if (priv->calib_results[i].buf) { + for (i = 0; i < IWL_CALIB_MAX; i++) { + if ((BIT(i) & priv->hw_params.calib_init_cfg) && + priv->calib_results[i].buf) { hcmd.len = priv->calib_results[i].buf_len; hcmd.data = priv->calib_results[i].buf; ret = iwl_send_cmd_sync(priv, &hcmd); if (ret) goto err; } + } return 0; err: diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.h b/drivers/net/wireless/iwlwifi/iwl-calib.h index 94c8e316382a4a9140dae3ede569dc34b770d29d..1abe84bb74ad0bd022e3a7318160f3c2e31c8c21 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.h +++ b/drivers/net/wireless/iwlwifi/iwl-calib.h @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * Tomas Winkler + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 8d04e966ad48fe31bc3cad9fbc0d5e010895e54b..52966ffbef6ec6231bfbb18fc2228572faec23a6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -66,8 +66,14 @@ * Please use iwl-dev.h for driver implementation definitions. */ -#ifndef __iwl4965_commands_h__ -#define __iwl4965_commands_h__ +#ifndef __iwl_commands_h__ +#define __iwl_commands_h__ + +/* uCode version contains 4 values: Major/Minor/API/Serial */ +#define IWL_UCODE_MAJOR(ver) (((ver) & 0xFF000000) >> 24) +#define IWL_UCODE_MINOR(ver) (((ver) & 0x00FF0000) >> 16) +#define IWL_UCODE_API(ver) (((ver) & 0x0000FF00) >> 8) +#define IWL_UCODE_SERIAL(ver) ((ver) & 0x000000FF) enum { REPLY_ALIVE = 0x1, @@ -88,6 +94,7 @@ enum { REPLY_WEPKEY = 0x20, /* RX, TX, LEDs */ + REPLY_3945_RX = 0x1b, /* 3945 only */ REPLY_TX = 0x1c, REPLY_RATE_SCALE = 0x47, /* 3945 only */ REPLY_LEDS_CMD = 0x48, @@ -98,6 +105,11 @@ enum { COEX_MEDIUM_NOTIFICATION = 0x5b, COEX_EVENT_CMD = 0x5c, + /* Calibration */ + CALIBRATION_CFG_CMD = 0x65, + CALIBRATION_RES_NOTIFICATION = 0x66, + CALIBRATION_COMPLETE_NOTIFICATION = 0x67, + /* 802.11h related */ RADAR_NOTIFICATION = 0x70, /* not used */ REPLY_QUIET_CMD = 0x71, /* not used */ @@ -129,7 +141,7 @@ enum { REPLY_TX_POWER_DBM_CMD = 0x98, MEASURE_ABORT_NOTIFICATION = 0x99, /* not used */ - /* Bluetooth device coexistance config command */ + /* Bluetooth device coexistence config command */ REPLY_BT_CONFIG = 0x9b, /* Statistics */ @@ -167,8 +179,8 @@ enum { #define QUEUE_TO_SEQ(q) (((q) & 0x1f) << 8) #define SEQ_TO_INDEX(s) ((s) & 0xff) #define INDEX_TO_SEQ(i) ((i) & 0xff) -#define SEQ_HUGE_FRAME __constant_cpu_to_le16(0x4000) -#define SEQ_RX_FRAME __constant_cpu_to_le16(0x8000) +#define SEQ_HUGE_FRAME cpu_to_le16(0x4000) +#define SEQ_RX_FRAME cpu_to_le16(0x8000) /** * struct iwl_cmd_header @@ -180,7 +192,7 @@ struct iwl_cmd_header { u8 cmd; /* Command ID: REPLY_RXON, etc. */ u8 flags; /* 0:5 reserved, 6 abort, 7 internal */ /* - * The driver sets up the sequence number to values of its chosing. + * The driver sets up the sequence number to values of its choosing. * uCode does not use this value, but passes it back to the driver * when sending the response to each driver-originated command, so * the driver can match the response to the command. Since the values @@ -208,10 +220,11 @@ struct iwl_cmd_header { } __attribute__ ((packed)); /** - * 4965 rate_n_flags bit fields + * iwlagn rate_n_flags bit fields * - * rate_n_flags format is used in following 4965 commands: + * rate_n_flags format is used in following iwlagn commands: * REPLY_RX (response only) + * REPLY_RX_MPDU (response only) * REPLY_TX (both command and response) * REPLY_TX_LINK_QUALITY_CMD * @@ -225,8 +238,9 @@ struct iwl_cmd_header { * 6) 54 Mbps * 7) 60 Mbps * - * 3: 0) Single stream (SISO) + * 4-3: 0) Single stream (SISO) * 1) Dual stream (MIMO) + * 2) Triple stream (MIMO) * * 5: Value of 0x20 in bits 7:0 indicates 6 Mbps FAT duplicate data * @@ -247,8 +261,8 @@ struct iwl_cmd_header { * 110) 11 Mbps */ #define RATE_MCS_CODE_MSK 0x7 -#define RATE_MCS_MIMO_POS 3 -#define RATE_MCS_MIMO_MSK 0x8 +#define RATE_MCS_SPATIAL_POS 3 +#define RATE_MCS_SPATIAL_MSK 0x18 #define RATE_MCS_HT_DUP_POS 5 #define RATE_MCS_HT_DUP_MSK 0x20 @@ -278,18 +292,20 @@ struct iwl_cmd_header { #define RATE_MCS_SGI_MSK 0x2000 /** - * rate_n_flags Tx antenna masks (4965 has 2 transmitters): - * bit14:15 01 B inactive, A active - * 10 B active, A inactive - * 11 Both active + * rate_n_flags Tx antenna masks + * 4965 has 2 transmitters + * 5100 has 1 transmitter B + * 5150 has 1 transmitter A + * 5300 has 3 transmitters + * 5350 has 3 transmitters + * bit14:16 */ #define RATE_MCS_ANT_POS 14 #define RATE_MCS_ANT_A_MSK 0x04000 #define RATE_MCS_ANT_B_MSK 0x08000 #define RATE_MCS_ANT_C_MSK 0x10000 #define RATE_MCS_ANT_ABC_MSK 0x1C000 - -#define RATE_MCS_ANT_INIT_IND 1 +#define RATE_ANT_NUM 3 #define POWER_TABLE_NUM_ENTRIES 33 #define POWER_TABLE_NUM_HT_OFDM_ENTRIES 32 @@ -340,7 +356,7 @@ struct iwl4965_tx_power_db { } __attribute__ ((packed)); /** - * Commad REPLY_TX_POWER_DBM_CMD = 0x98 + * Command REPLY_TX_POWER_DBM_CMD = 0x98 * struct iwl5000_tx_power_dbm_cmd */ #define IWL50_TX_POWER_AUTO 0x7f @@ -359,7 +375,7 @@ struct iwl5000_tx_power_dbm_cmd { * *****************************************************************************/ -#define UCODE_VALID_OK __constant_cpu_to_le32(0x1) +#define UCODE_VALID_OK cpu_to_le32(0x1) #define INITIALIZE_SUBTYPE (9) /* @@ -376,7 +392,7 @@ struct iwl5000_tx_power_dbm_cmd { * calculating txpower settings: * * 1) Power supply voltage indication. The voltage sensor outputs higher - * values for lower voltage, and vice versa. + * values for lower voltage, and vice verse. * * 2) Temperature measurement parameters, for each of two channel widths * (20 MHz and 40 MHz) supported by the radios. Temperature sensing @@ -477,11 +493,6 @@ struct iwl_alive_resp { } __attribute__ ((packed)); -union tsf { - u8 byte[8]; - __le16 word[4]; - __le32 dw[2]; -}; /* * REPLY_ERROR = 0x2 (response only, not a command) @@ -492,7 +503,7 @@ struct iwl_error_resp { u8 reserved1; __le16 bad_cmd_seq_num; __le32 error_info; - union tsf timestamp; + __le64 timestamp; } __attribute__ ((packed)); /****************************************************************************** @@ -513,75 +524,75 @@ enum { }; -#define RXON_RX_CHAIN_DRIVER_FORCE_MSK __constant_cpu_to_le16(0x1 << 0) -#define RXON_RX_CHAIN_VALID_MSK __constant_cpu_to_le16(0x7 << 1) +#define RXON_RX_CHAIN_DRIVER_FORCE_MSK cpu_to_le16(0x1 << 0) +#define RXON_RX_CHAIN_VALID_MSK cpu_to_le16(0x7 << 1) #define RXON_RX_CHAIN_VALID_POS (1) -#define RXON_RX_CHAIN_FORCE_SEL_MSK __constant_cpu_to_le16(0x7 << 4) +#define RXON_RX_CHAIN_FORCE_SEL_MSK cpu_to_le16(0x7 << 4) #define RXON_RX_CHAIN_FORCE_SEL_POS (4) -#define RXON_RX_CHAIN_FORCE_MIMO_SEL_MSK __constant_cpu_to_le16(0x7 << 7) +#define RXON_RX_CHAIN_FORCE_MIMO_SEL_MSK cpu_to_le16(0x7 << 7) #define RXON_RX_CHAIN_FORCE_MIMO_SEL_POS (7) -#define RXON_RX_CHAIN_CNT_MSK __constant_cpu_to_le16(0x3 << 10) +#define RXON_RX_CHAIN_CNT_MSK cpu_to_le16(0x3 << 10) #define RXON_RX_CHAIN_CNT_POS (10) -#define RXON_RX_CHAIN_MIMO_CNT_MSK __constant_cpu_to_le16(0x3 << 12) +#define RXON_RX_CHAIN_MIMO_CNT_MSK cpu_to_le16(0x3 << 12) #define RXON_RX_CHAIN_MIMO_CNT_POS (12) -#define RXON_RX_CHAIN_MIMO_FORCE_MSK __constant_cpu_to_le16(0x1 << 14) +#define RXON_RX_CHAIN_MIMO_FORCE_MSK cpu_to_le16(0x1 << 14) #define RXON_RX_CHAIN_MIMO_FORCE_POS (14) /* rx_config flags */ /* band & modulation selection */ -#define RXON_FLG_BAND_24G_MSK __constant_cpu_to_le32(1 << 0) -#define RXON_FLG_CCK_MSK __constant_cpu_to_le32(1 << 1) +#define RXON_FLG_BAND_24G_MSK cpu_to_le32(1 << 0) +#define RXON_FLG_CCK_MSK cpu_to_le32(1 << 1) /* auto detection enable */ -#define RXON_FLG_AUTO_DETECT_MSK __constant_cpu_to_le32(1 << 2) +#define RXON_FLG_AUTO_DETECT_MSK cpu_to_le32(1 << 2) /* TGg protection when tx */ -#define RXON_FLG_TGG_PROTECT_MSK __constant_cpu_to_le32(1 << 3) +#define RXON_FLG_TGG_PROTECT_MSK cpu_to_le32(1 << 3) /* cck short slot & preamble */ -#define RXON_FLG_SHORT_SLOT_MSK __constant_cpu_to_le32(1 << 4) -#define RXON_FLG_SHORT_PREAMBLE_MSK __constant_cpu_to_le32(1 << 5) +#define RXON_FLG_SHORT_SLOT_MSK cpu_to_le32(1 << 4) +#define RXON_FLG_SHORT_PREAMBLE_MSK cpu_to_le32(1 << 5) /* antenna selection */ -#define RXON_FLG_DIS_DIV_MSK __constant_cpu_to_le32(1 << 7) -#define RXON_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0x0f00) -#define RXON_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8) -#define RXON_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9) +#define RXON_FLG_DIS_DIV_MSK cpu_to_le32(1 << 7) +#define RXON_FLG_ANT_SEL_MSK cpu_to_le32(0x0f00) +#define RXON_FLG_ANT_A_MSK cpu_to_le32(1 << 8) +#define RXON_FLG_ANT_B_MSK cpu_to_le32(1 << 9) /* radar detection enable */ -#define RXON_FLG_RADAR_DETECT_MSK __constant_cpu_to_le32(1 << 12) -#define RXON_FLG_TGJ_NARROW_BAND_MSK __constant_cpu_to_le32(1 << 13) +#define RXON_FLG_RADAR_DETECT_MSK cpu_to_le32(1 << 12) +#define RXON_FLG_TGJ_NARROW_BAND_MSK cpu_to_le32(1 << 13) /* rx response to host with 8-byte TSF * (according to ON_AIR deassertion) */ -#define RXON_FLG_TSF2HOST_MSK __constant_cpu_to_le32(1 << 15) +#define RXON_FLG_TSF2HOST_MSK cpu_to_le32(1 << 15) /* HT flags */ #define RXON_FLG_CTRL_CHANNEL_LOC_POS (22) -#define RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK __constant_cpu_to_le32(0x1 << 22) +#define RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK cpu_to_le32(0x1 << 22) #define RXON_FLG_HT_OPERATING_MODE_POS (23) -#define RXON_FLG_HT_PROT_MSK __constant_cpu_to_le32(0x1 << 23) -#define RXON_FLG_FAT_PROT_MSK __constant_cpu_to_le32(0x2 << 23) +#define RXON_FLG_HT_PROT_MSK cpu_to_le32(0x1 << 23) +#define RXON_FLG_FAT_PROT_MSK cpu_to_le32(0x2 << 23) #define RXON_FLG_CHANNEL_MODE_POS (25) -#define RXON_FLG_CHANNEL_MODE_MSK __constant_cpu_to_le32(0x3 << 25) -#define RXON_FLG_CHANNEL_MODE_PURE_40_MSK __constant_cpu_to_le32(0x1 << 25) -#define RXON_FLG_CHANNEL_MODE_MIXED_MSK __constant_cpu_to_le32(0x2 << 25) +#define RXON_FLG_CHANNEL_MODE_MSK cpu_to_le32(0x3 << 25) +#define RXON_FLG_CHANNEL_MODE_PURE_40_MSK cpu_to_le32(0x1 << 25) +#define RXON_FLG_CHANNEL_MODE_MIXED_MSK cpu_to_le32(0x2 << 25) /* CTS to self (if spec allows) flag */ -#define RXON_FLG_SELF_CTS_EN __constant_cpu_to_le32(0x1<<30) +#define RXON_FLG_SELF_CTS_EN cpu_to_le32(0x1<<30) /* rx_config filter flags */ /* accept all data frames */ -#define RXON_FILTER_PROMISC_MSK __constant_cpu_to_le32(1 << 0) +#define RXON_FILTER_PROMISC_MSK cpu_to_le32(1 << 0) /* pass control & management to host */ -#define RXON_FILTER_CTL2HOST_MSK __constant_cpu_to_le32(1 << 1) +#define RXON_FILTER_CTL2HOST_MSK cpu_to_le32(1 << 1) /* accept multi-cast */ -#define RXON_FILTER_ACCEPT_GRP_MSK __constant_cpu_to_le32(1 << 2) +#define RXON_FILTER_ACCEPT_GRP_MSK cpu_to_le32(1 << 2) /* don't decrypt uni-cast frames */ -#define RXON_FILTER_DIS_DECRYPT_MSK __constant_cpu_to_le32(1 << 3) +#define RXON_FILTER_DIS_DECRYPT_MSK cpu_to_le32(1 << 3) /* don't decrypt multi-cast frames */ -#define RXON_FILTER_DIS_GRP_DECRYPT_MSK __constant_cpu_to_le32(1 << 4) +#define RXON_FILTER_DIS_GRP_DECRYPT_MSK cpu_to_le32(1 << 4) /* STA is associated */ -#define RXON_FILTER_ASSOC_MSK __constant_cpu_to_le32(1 << 5) +#define RXON_FILTER_ASSOC_MSK cpu_to_le32(1 << 5) /* transfer to host non bssid beacons in associated state */ -#define RXON_FILTER_BCON_AWARE_MSK __constant_cpu_to_le32(1 << 6) +#define RXON_FILTER_BCON_AWARE_MSK cpu_to_le32(1 << 6) /** * REPLY_RXON = 0x10 (command, has simple generic response) @@ -620,7 +631,7 @@ struct iwl4965_rxon_cmd { u8 ofdm_ht_dual_stream_basic_rates; } __attribute__ ((packed)); -/* 5000 HW just extend this cmmand */ +/* 5000 HW just extend this command */ struct iwl_rxon_cmd { u8 node_addr[6]; __le16 reserved1; @@ -679,8 +690,8 @@ struct iwl4965_rxon_assoc_cmd { /* * REPLY_RXON_TIMING = 0x14 (command, has simple generic response) */ -struct iwl4965_rxon_time_cmd { - union tsf timestamp; +struct iwl_rxon_time_cmd { + __le64 timestamp; __le16 beacon_interval; __le16 atim_window; __le32 beacon_init_val; @@ -691,7 +702,7 @@ struct iwl4965_rxon_time_cmd { /* * REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response) */ -struct iwl4965_channel_switch_cmd { +struct iwl_channel_switch_cmd { u8 band; u8 expect_beacon; __le16 channel; @@ -704,7 +715,7 @@ struct iwl4965_channel_switch_cmd { /* * CHANNEL_SWITCH_NOTIFICATION = 0x73 (notification only, not a command) */ -struct iwl4965_csa_notification { +struct iwl_csa_notification { __le16 band; __le16 channel; __le32 status; /* 0 - OK, 1 - fail */ @@ -741,9 +752,9 @@ struct iwl_ac_qos { } __attribute__ ((packed)); /* QoS flags defines */ -#define QOS_PARAM_FLG_UPDATE_EDCA_MSK __constant_cpu_to_le32(0x01) -#define QOS_PARAM_FLG_TGN_MSK __constant_cpu_to_le32(0x02) -#define QOS_PARAM_FLG_TXOP_TYPE_MSK __constant_cpu_to_le32(0x10) +#define QOS_PARAM_FLG_UPDATE_EDCA_MSK cpu_to_le32(0x01) +#define QOS_PARAM_FLG_TGN_MSK cpu_to_le32(0x02) +#define QOS_PARAM_FLG_TXOP_TYPE_MSK cpu_to_le32(0x10) /* Number of Access Categories (AC) (EDCA), queues 0..3 */ #define AC_NUM 4 @@ -780,34 +791,34 @@ struct iwl_qosparam_cmd { #define IWL_STATION_COUNT 32 /* MAX(3945,4965)*/ #define IWL_INVALID_STATION 255 -#define STA_FLG_PWR_SAVE_MSK __constant_cpu_to_le32(1 << 8); -#define STA_FLG_RTS_MIMO_PROT_MSK __constant_cpu_to_le32(1 << 17) -#define STA_FLG_AGG_MPDU_8US_MSK __constant_cpu_to_le32(1 << 18) +#define STA_FLG_PWR_SAVE_MSK cpu_to_le32(1 << 8); +#define STA_FLG_RTS_MIMO_PROT_MSK cpu_to_le32(1 << 17) +#define STA_FLG_AGG_MPDU_8US_MSK cpu_to_le32(1 << 18) #define STA_FLG_MAX_AGG_SIZE_POS (19) -#define STA_FLG_MAX_AGG_SIZE_MSK __constant_cpu_to_le32(3 << 19) -#define STA_FLG_FAT_EN_MSK __constant_cpu_to_le32(1 << 21) -#define STA_FLG_MIMO_DIS_MSK __constant_cpu_to_le32(1 << 22) +#define STA_FLG_MAX_AGG_SIZE_MSK cpu_to_le32(3 << 19) +#define STA_FLG_FAT_EN_MSK cpu_to_le32(1 << 21) +#define STA_FLG_MIMO_DIS_MSK cpu_to_le32(1 << 22) #define STA_FLG_AGG_MPDU_DENSITY_POS (23) -#define STA_FLG_AGG_MPDU_DENSITY_MSK __constant_cpu_to_le32(7 << 23) +#define STA_FLG_AGG_MPDU_DENSITY_MSK cpu_to_le32(7 << 23) /* Use in mode field. 1: modify existing entry, 0: add new station entry */ #define STA_CONTROL_MODIFY_MSK 0x01 /* key flags __le16*/ -#define STA_KEY_FLG_ENCRYPT_MSK __constant_cpu_to_le16(0x0007) -#define STA_KEY_FLG_NO_ENC __constant_cpu_to_le16(0x0000) -#define STA_KEY_FLG_WEP __constant_cpu_to_le16(0x0001) -#define STA_KEY_FLG_CCMP __constant_cpu_to_le16(0x0002) -#define STA_KEY_FLG_TKIP __constant_cpu_to_le16(0x0003) +#define STA_KEY_FLG_ENCRYPT_MSK cpu_to_le16(0x0007) +#define STA_KEY_FLG_NO_ENC cpu_to_le16(0x0000) +#define STA_KEY_FLG_WEP cpu_to_le16(0x0001) +#define STA_KEY_FLG_CCMP cpu_to_le16(0x0002) +#define STA_KEY_FLG_TKIP cpu_to_le16(0x0003) #define STA_KEY_FLG_KEYID_POS 8 -#define STA_KEY_FLG_INVALID __constant_cpu_to_le16(0x0800) +#define STA_KEY_FLG_INVALID cpu_to_le16(0x0800) /* wep key is either from global key (0) or from station info array (1) */ -#define STA_KEY_FLG_MAP_KEY_MSK __constant_cpu_to_le16(0x0008) +#define STA_KEY_FLG_MAP_KEY_MSK cpu_to_le16(0x0008) /* wep key in STA: 5-bytes (0) or 13-bytes (1) */ -#define STA_KEY_FLG_KEY_SIZE_MSK __constant_cpu_to_le16(0x1000) -#define STA_KEY_MULTICAST_MSK __constant_cpu_to_le16(0x4000) +#define STA_KEY_FLG_KEY_SIZE_MSK cpu_to_le16(0x1000) +#define STA_KEY_MULTICAST_MSK cpu_to_le16(0x4000) #define STA_KEY_MAX_NUM 8 /* Flags indicate whether to modify vs. don't change various station params */ @@ -1013,33 +1024,14 @@ struct iwl_wep_cmd { * *****************************************************************************/ -struct iwl4965_rx_frame_stats { - u8 phy_count; - u8 id; - u8 rssi; - u8 agc; - __le16 sig_avg; - __le16 noise_diff; - u8 payload[0]; -} __attribute__ ((packed)); - -struct iwl4965_rx_frame_hdr { - __le16 channel; - __le16 phy_flags; - u8 reserved1; - u8 rate; - __le16 len; - u8 payload[0]; -} __attribute__ ((packed)); - -#define RX_RES_STATUS_NO_CRC32_ERROR __constant_cpu_to_le32(1 << 0) -#define RX_RES_STATUS_NO_RXE_OVERFLOW __constant_cpu_to_le32(1 << 1) +#define RX_RES_STATUS_NO_CRC32_ERROR cpu_to_le32(1 << 0) +#define RX_RES_STATUS_NO_RXE_OVERFLOW cpu_to_le32(1 << 1) -#define RX_RES_PHY_FLAGS_BAND_24_MSK __constant_cpu_to_le16(1 << 0) -#define RX_RES_PHY_FLAGS_MOD_CCK_MSK __constant_cpu_to_le16(1 << 1) -#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK __constant_cpu_to_le16(1 << 2) -#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK __constant_cpu_to_le16(1 << 3) -#define RX_RES_PHY_FLAGS_ANTENNA_MSK __constant_cpu_to_le16(0xf0) +#define RX_RES_PHY_FLAGS_BAND_24_MSK cpu_to_le16(1 << 0) +#define RX_RES_PHY_FLAGS_MOD_CCK_MSK cpu_to_le16(1 << 1) +#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK cpu_to_le16(1 << 2) +#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK cpu_to_le16(1 << 3) +#define RX_RES_PHY_FLAGS_ANTENNA_MSK cpu_to_le16(0xf0) #define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8) #define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8) @@ -1062,26 +1054,6 @@ struct iwl4965_rx_frame_hdr { #define RX_MPDU_RES_STATUS_TTAK_OK (1 << 7) #define RX_MPDU_RES_STATUS_DEC_DONE_MSK (0x800) -struct iwl4965_rx_frame_end { - __le32 status; - __le64 timestamp; - __le32 beacon_timestamp; -} __attribute__ ((packed)); - -/* - * REPLY_3945_RX = 0x1b (response only, not a command) - * - * NOTE: DO NOT dereference from casts to this structure - * It is provided only for calculating minimum data set size. - * The actual offsets of the hdr and end are dynamic based on - * stats.phy_count - */ -struct iwl4965_rx_frame { - struct iwl4965_rx_frame_stats stats; - struct iwl4965_rx_frame_hdr hdr; - struct iwl4965_rx_frame_end end; -} __attribute__ ((packed)); - /* Fixed (non-configurable) rx data from phy */ #define IWL49_RX_RES_PHY_CNT 14 @@ -1111,7 +1083,7 @@ struct iwl4965_rx_non_cfg_phy { #define IWL50_OFDM_RSSI_C_BIT_POS 0 struct iwl5000_non_cfg_phy { - __le32 non_cfg_phy[IWL50_RX_RES_PHY_CNT]; /* upto 8 phy entries */ + __le32 non_cfg_phy[IWL50_RX_RES_PHY_CNT]; /* up to 8 phy entries */ } __attribute__ ((packed)); @@ -1167,24 +1139,24 @@ struct iwl4965_rx_mpdu_res_start { /* REPLY_TX Tx flags field */ -/* 1: Use RTS/CTS protocol or CTS-to-self if spec alows it +/* 1: Use RTS/CTS protocol or CTS-to-self if spec allows it * before this frame. if CTS-to-self required check * RXON_FLG_SELF_CTS_EN status. */ -#define TX_CMD_FLG_RTS_CTS_MSK __constant_cpu_to_le32(1 << 0) +#define TX_CMD_FLG_RTS_CTS_MSK cpu_to_le32(1 << 0) /* 1: Use Request-To-Send protocol before this frame. * Mutually exclusive vs. TX_CMD_FLG_CTS_MSK. */ -#define TX_CMD_FLG_RTS_MSK __constant_cpu_to_le32(1 << 1) +#define TX_CMD_FLG_RTS_MSK cpu_to_le32(1 << 1) /* 1: Transmit Clear-To-Send to self before this frame. * Driver should set this for AUTH/DEAUTH/ASSOC-REQ/REASSOC mgmnt frames. * Mutually exclusive vs. TX_CMD_FLG_RTS_MSK. */ -#define TX_CMD_FLG_CTS_MSK __constant_cpu_to_le32(1 << 2) +#define TX_CMD_FLG_CTS_MSK cpu_to_le32(1 << 2) /* 1: Expect ACK from receiving station * 0: Don't expect ACK (MAC header's duration field s/b 0) * Set this for unicast frames, but not broadcast/multicast. */ -#define TX_CMD_FLG_ACK_MSK __constant_cpu_to_le32(1 << 3) +#define TX_CMD_FLG_ACK_MSK cpu_to_le32(1 << 3) /* For 4965: * 1: Use rate scale table (see REPLY_TX_LINK_QUALITY_CMD). @@ -1192,40 +1164,40 @@ struct iwl4965_rx_mpdu_res_start { * uCode walks through table for additional Tx attempts. * 0: Use Tx rate/MCS from Tx command's rate_n_flags field. * This rate will be used for all Tx attempts; it will not be scaled. */ -#define TX_CMD_FLG_STA_RATE_MSK __constant_cpu_to_le32(1 << 4) +#define TX_CMD_FLG_STA_RATE_MSK cpu_to_le32(1 << 4) /* 1: Expect immediate block-ack. * Set when Txing a block-ack request frame. Also set TX_CMD_FLG_ACK_MSK. */ -#define TX_CMD_FLG_IMM_BA_RSP_MASK __constant_cpu_to_le32(1 << 6) +#define TX_CMD_FLG_IMM_BA_RSP_MASK cpu_to_le32(1 << 6) /* 1: Frame requires full Tx-Op protection. * Set this if either RTS or CTS Tx Flag gets set. */ -#define TX_CMD_FLG_FULL_TXOP_PROT_MSK __constant_cpu_to_le32(1 << 7) +#define TX_CMD_FLG_FULL_TXOP_PROT_MSK cpu_to_le32(1 << 7) /* Tx antenna selection field; used only for 3945, reserved (0) for 4965. * Set field to "0" to allow 3945 uCode to select antenna (normal usage). */ -#define TX_CMD_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0xf00) -#define TX_CMD_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8) -#define TX_CMD_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9) +#define TX_CMD_FLG_ANT_SEL_MSK cpu_to_le32(0xf00) +#define TX_CMD_FLG_ANT_A_MSK cpu_to_le32(1 << 8) +#define TX_CMD_FLG_ANT_B_MSK cpu_to_le32(1 << 9) /* 1: Ignore Bluetooth priority for this frame. * 0: Delay Tx until Bluetooth device is done (normal usage). */ -#define TX_CMD_FLG_BT_DIS_MSK __constant_cpu_to_le32(1 << 12) +#define TX_CMD_FLG_BT_DIS_MSK cpu_to_le32(1 << 12) /* 1: uCode overrides sequence control field in MAC header. * 0: Driver provides sequence control field in MAC header. * Set this for management frames, non-QOS data frames, non-unicast frames, * and also in Tx command embedded in REPLY_SCAN_CMD for active scans. */ -#define TX_CMD_FLG_SEQ_CTL_MSK __constant_cpu_to_le32(1 << 13) +#define TX_CMD_FLG_SEQ_CTL_MSK cpu_to_le32(1 << 13) /* 1: This frame is non-last MPDU; more fragments are coming. * 0: Last fragment, or not using fragmentation. */ -#define TX_CMD_FLG_MORE_FRAG_MSK __constant_cpu_to_le32(1 << 14) +#define TX_CMD_FLG_MORE_FRAG_MSK cpu_to_le32(1 << 14) /* 1: uCode calculates and inserts Timestamp Function (TSF) in outgoing frame. * 0: No TSF required in outgoing frame. * Set this for transmitting beacons and probe responses. */ -#define TX_CMD_FLG_TSF_MSK __constant_cpu_to_le32(1 << 16) +#define TX_CMD_FLG_TSF_MSK cpu_to_le32(1 << 16) /* 1: Driver inserted 2 bytes pad after the MAC header, for (required) dword * alignment of frame's payload data field. @@ -1233,14 +1205,14 @@ struct iwl4965_rx_mpdu_res_start { * Set this for MAC headers with 26 or 30 bytes, i.e. those with QOS or ADDR4 * field (but not both). Driver must align frame data (i.e. data following * MAC header) to DWORD boundary. */ -#define TX_CMD_FLG_MH_PAD_MSK __constant_cpu_to_le32(1 << 20) +#define TX_CMD_FLG_MH_PAD_MSK cpu_to_le32(1 << 20) /* accelerate aggregation support * 0 - no CCMP encryption; 1 - CCMP encryption */ -#define TX_CMD_FLG_AGG_CCMP_MSK __constant_cpu_to_le32(1 << 22) +#define TX_CMD_FLG_AGG_CCMP_MSK cpu_to_le32(1 << 22) /* HCCA-AP - disable duration overwriting. */ -#define TX_CMD_FLG_DUR_MSK __constant_cpu_to_le32(1 << 25) +#define TX_CMD_FLG_DUR_MSK cpu_to_le32(1 << 25) /* @@ -1266,7 +1238,7 @@ struct iwl4965_rx_mpdu_res_start { * Used for managing Tx retries when expecting block-acks. * Driver should set these fields to 0. */ -struct iwl4965_dram_scratch { +struct iwl_dram_scratch { u8 try_cnt; /* Tx attempts */ u8 bt_kill_cnt; /* Tx attempts blocked by Bluetooth device */ __le16 reserved; @@ -1297,9 +1269,9 @@ struct iwl_tx_cmd { __le32 tx_flags; /* TX_CMD_FLG_* */ - /* 4965's uCode may modify this field of the Tx command (in host DRAM!). + /* uCode may modify this field of the Tx command (in host DRAM!). * Driver must also set dram_lsb_ptr and dram_msb_ptr in this cmd. */ - struct iwl4965_dram_scratch scratch; + struct iwl_dram_scratch scratch; /* Rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is cleared. */ __le32 rate_n_flags; /* RATE_MCS_* */ @@ -1411,21 +1383,21 @@ enum { }; enum { - TX_STATUS_MSK = 0x000000ff, /* bits 0:7 */ + TX_STATUS_MSK = 0x000000ff, /* bits 0:7 */ TX_STATUS_DELAY_MSK = 0x00000040, TX_STATUS_ABORT_MSK = 0x00000080, TX_PACKET_MODE_MSK = 0x0000ff00, /* bits 8:15 */ TX_FIFO_NUMBER_MSK = 0x00070000, /* bits 16:18 */ - TX_RESERVED = 0x00780000, /* bits 19:22 */ + TX_RESERVED = 0x00780000, /* bits 19:22 */ TX_POWER_PA_DETECT_MSK = 0x7f800000, /* bits 23:30 */ TX_ABORT_REQUIRED_MSK = 0x80000000, /* bits 31:31 */ }; -static inline int iwl_is_tx_success(u32 status) +static inline bool iwl_is_tx_success(u32 status) { status &= TX_STATUS_MSK; - return (status == TX_STATUS_SUCCESS) - || (status == TX_STATUS_DIRECT_DONE); + return (status == TX_STATUS_SUCCESS) || + (status == TX_STATUS_DIRECT_DONE); } @@ -1450,10 +1422,9 @@ enum { AGG_TX_STATE_DELAY_TX_MSK = 0x400 }; -#define AGG_TX_STATE_LAST_SENT_MSK \ -(AGG_TX_STATE_LAST_SENT_TTL_MSK | \ - AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK | \ - AGG_TX_STATE_LAST_SENT_BT_KILL_MSK) +#define AGG_TX_STATE_LAST_SENT_MSK (AGG_TX_STATE_LAST_SENT_TTL_MSK | \ + AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK | \ + AGG_TX_STATE_LAST_SENT_BT_KILL_MSK) /* # tx attempts for first frame in aggregation */ #define AGG_TX_STATE_TRY_CNT_POS 12 @@ -1526,6 +1497,28 @@ struct iwl4965_tx_resp { } u; } __attribute__ ((packed)); +/* + * definitions for initial rate index field + * bits [3:0] initial rate index + * bits [6:4] rate table color, used for the initial rate + * bit-7 invalid rate indication + * i.e. rate was not chosen from rate table + * or rate table color was changed during frame retries + * refer tlc rate info + */ + +#define IWL50_TX_RES_INIT_RATE_INDEX_POS 0 +#define IWL50_TX_RES_INIT_RATE_INDEX_MSK 0x0f +#define IWL50_TX_RES_RATE_TABLE_COLOR_POS 4 +#define IWL50_TX_RES_RATE_TABLE_COLOR_MSK 0x70 +#define IWL50_TX_RES_INV_RATE_INDEX_MSK 0x80 + +/* refer to ra_tid */ +#define IWL50_TX_RES_TID_POS 0 +#define IWL50_TX_RES_TID_MSK 0x0f +#define IWL50_TX_RES_RA_POS 4 +#define IWL50_TX_RES_RA_MSK 0xf0 + struct iwl5000_tx_resp { u8 frame_count; /* 1 no aggregation, >1 aggregation */ u8 bt_kill_count; /* # blocked by bluetooth (unused for agg) */ @@ -1540,14 +1533,17 @@ struct iwl5000_tx_resp { * For agg: RTS + CTS + aggregation tx time + block-ack time. */ __le16 wireless_media_time; /* uSecs */ - __le16 reserved; - __le32 pa_power1; /* RF power amplifier measurement (not used) */ - __le32 pa_power2; + u8 pa_status; /* RF power amplifier measurement (not used) */ + u8 pa_integ_res_a[3]; + u8 pa_integ_res_b[3]; + u8 pa_integ_res_C[3]; __le32 tfd_info; __le16 seq_ctl; __le16 byte_cnt; - __le32 tlc_info; + u8 tlc_info; + u8 ra_tid; /* tid (0:3), sta_id (4:7) */ + __le16 frame_ctrl; /* * For non-agg: frame status TX_STATUS_* * For agg: status of 1st frame, AGG_TX_STATE_*; other frame status @@ -1742,7 +1738,7 @@ struct iwl_link_qual_agg_params { * match the modulation characteristics of the history set. * * When using block-ack (aggregation), all frames are transmitted at the same - * rate, since there is no per-attempt acknowledgement from the destination + * rate, since there is no per-attempt acknowledgment from the destination * station. The Tx response struct iwl_tx_resp indicates the Tx rate in * rate_n_flags field. After receiving a block-ack, the driver can update * history for the entire block all at once. @@ -1881,9 +1877,9 @@ struct iwl_link_quality_cmd { * * 3945 and 4965 support hardware handshake with Bluetooth device on * same platform. Bluetooth device alerts wireless device when it will Tx; - * wireless device can delay or kill its own Tx to accomodate. + * wireless device can delay or kill its own Tx to accommodate. */ -struct iwl4965_bt_cmd { +struct iwl_bt_cmd { u8 flags; u8 lead_time; u8 max_kill; @@ -1909,18 +1905,18 @@ struct iwl4965_bt_cmd { RXON_FILTER_ASSOC_MSK | \ RXON_FILTER_BCON_AWARE_MSK) -struct iwl4965_measure_channel { +struct iwl_measure_channel { __le32 duration; /* measurement duration in extended beacon * format */ u8 channel; /* channel to measure */ - u8 type; /* see enum iwl4965_measure_type */ + u8 type; /* see enum iwl_measure_type */ __le16 reserved; } __attribute__ ((packed)); /* * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (command) */ -struct iwl4965_spectrum_cmd { +struct iwl_spectrum_cmd { __le16 len; /* number of bytes starting from token */ u8 token; /* token id */ u8 id; /* measurement id -- 0 or 1 */ @@ -1933,13 +1929,13 @@ struct iwl4965_spectrum_cmd { __le32 filter_flags; /* rxon filter flags */ __le16 channel_count; /* minimum 1, maximum 10 */ __le16 reserved3; - struct iwl4965_measure_channel channels[10]; + struct iwl_measure_channel channels[10]; } __attribute__ ((packed)); /* * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (response) */ -struct iwl4965_spectrum_resp { +struct iwl_spectrum_resp { u8 token; u8 id; /* id of the prior command replaced, or 0xff */ __le16 status; /* 0 - command will be handled @@ -1947,12 +1943,12 @@ struct iwl4965_spectrum_resp { * measurement) */ } __attribute__ ((packed)); -enum iwl4965_measurement_state { +enum iwl_measurement_state { IWL_MEASUREMENT_START = 0, IWL_MEASUREMENT_STOP = 1, }; -enum iwl4965_measurement_status { +enum iwl_measurement_status { IWL_MEASUREMENT_OK = 0, IWL_MEASUREMENT_CONCURRENT = 1, IWL_MEASUREMENT_CSA_CONFLICT = 2, @@ -1965,18 +1961,18 @@ enum iwl4965_measurement_status { #define NUM_ELEMENTS_IN_HISTOGRAM 8 -struct iwl4965_measurement_histogram { +struct iwl_measurement_histogram { __le32 ofdm[NUM_ELEMENTS_IN_HISTOGRAM]; /* in 0.8usec counts */ __le32 cck[NUM_ELEMENTS_IN_HISTOGRAM]; /* in 1usec counts */ } __attribute__ ((packed)); /* clear channel availability counters */ -struct iwl4965_measurement_cca_counters { +struct iwl_measurement_cca_counters { __le32 ofdm; __le32 cck; } __attribute__ ((packed)); -enum iwl4965_measure_type { +enum iwl_measure_type { IWL_MEASURE_BASIC = (1 << 0), IWL_MEASURE_CHANNEL_LOAD = (1 << 1), IWL_MEASURE_HISTOGRAM_RPI = (1 << 2), @@ -1989,7 +1985,7 @@ enum iwl4965_measure_type { /* * SPECTRUM_MEASURE_NOTIFICATION = 0x75 (notification only, not a command) */ -struct iwl4965_spectrum_notification { +struct iwl_spectrum_notification { u8 id; /* measurement id -- 0 or 1 */ u8 token; u8 channel_index; /* index in measurement channel list */ @@ -1997,7 +1993,7 @@ struct iwl4965_spectrum_notification { __le32 start_time; /* lower 32-bits of TSF */ u8 band; /* 0 - 5.2GHz, 1 - 2.4GHz */ u8 channel; - u8 type; /* see enum iwl4965_measurement_type */ + u8 type; /* see enum iwl_measurement_type */ u8 reserved1; /* NOTE: cca_ofdm, cca_cck, basic_type, and histogram are only only * valid if applicable for measurement type requested. */ @@ -2007,9 +2003,9 @@ struct iwl4965_spectrum_notification { u8 basic_type; /* 0 - bss, 1 - ofdm preamble, 2 - * unidentified */ u8 reserved2[3]; - struct iwl4965_measurement_histogram histogram; + struct iwl_measurement_histogram histogram; __le32 stop_time; /* lower 32-bits of TSF */ - __le32 status; /* see iwl4965_measurement_status */ + __le32 status; /* see iwl_measurement_status */ } __attribute__ ((packed)); /****************************************************************************** @@ -2043,15 +2039,15 @@ struct iwl4965_spectrum_notification { * '11' Illegal set * * NOTE: if sleep_interval[SLEEP_INTRVL_TABLE_SIZE-1] > DTIM period then - * ucode assume sleep over DTIM is allowed and we don't need to wakeup + * ucode assume sleep over DTIM is allowed and we don't need to wake up * for every DTIM. */ #define IWL_POWER_VEC_SIZE 5 -#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK __constant_cpu_to_le16(1 << 0) -#define IWL_POWER_SLEEP_OVER_DTIM_MSK __constant_cpu_to_le16(1 << 2) -#define IWL_POWER_PCI_PM_MSK __constant_cpu_to_le16(1 << 3) -#define IWL_POWER_FAST_PD __constant_cpu_to_le16(1 << 4) +#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK cpu_to_le16(1 << 0) +#define IWL_POWER_SLEEP_OVER_DTIM_MSK cpu_to_le16(1 << 2) +#define IWL_POWER_PCI_PM_MSK cpu_to_le16(1 << 3) +#define IWL_POWER_FAST_PD cpu_to_le16(1 << 4) struct iwl_powertable_cmd { __le16 flags; @@ -2067,7 +2063,7 @@ struct iwl_powertable_cmd { * PM_SLEEP_NOTIFICATION = 0x7A (notification only, not a command) * 3945 and 4965 identical. */ -struct iwl4965_sleep_notification { +struct iwl_sleep_notification { u8 pm_sleep_mode; u8 pm_wakeup_src; __le16 reserved; @@ -2097,14 +2093,14 @@ enum { #define CARD_STATE_CMD_DISABLE 0x00 /* Put card to sleep */ #define CARD_STATE_CMD_ENABLE 0x01 /* Wake up card */ #define CARD_STATE_CMD_HALT 0x02 /* Power down permanently */ -struct iwl4965_card_state_cmd { +struct iwl_card_state_cmd { __le32 status; /* CARD_STATE_CMD_* request new power state */ } __attribute__ ((packed)); /* * CARD_STATE_NOTIFICATION = 0xa1 (notification only, not a command) */ -struct iwl4965_card_state_notif { +struct iwl_card_state_notif { __le32 flags; } __attribute__ ((packed)); @@ -2125,8 +2121,8 @@ struct iwl_ct_kill_config { * *****************************************************************************/ -#define SCAN_CHANNEL_TYPE_PASSIVE __constant_cpu_to_le32(0) -#define SCAN_CHANNEL_TYPE_ACTIVE __constant_cpu_to_le32(1) +#define SCAN_CHANNEL_TYPE_PASSIVE cpu_to_le32(0) +#define SCAN_CHANNEL_TYPE_ACTIVE cpu_to_le32(1) /** * struct iwl_scan_channel - entry in REPLY_SCAN_CMD channel table @@ -2167,7 +2163,7 @@ struct iwl_scan_channel { * struct iwl_ssid_ie - directed scan network information element * * Up to 4 of these may appear in REPLY_SCAN_CMD, selected by "type" field - * in struct iwl4965_scan_channel; each channel may select different ssids from + * in struct iwl_scan_channel; each channel may select different ssids from * among the 4 entries. SSID IEs get transmitted in reverse order of entry. */ struct iwl_ssid_ie { @@ -2177,8 +2173,8 @@ struct iwl_ssid_ie { } __attribute__ ((packed)); #define PROBE_OPTION_MAX 0x14 -#define TX_CMD_LIFE_TIME_INFINITE __constant_cpu_to_le32(0xFFFFFFFF) -#define IWL_GOOD_CRC_TH __constant_cpu_to_le16(1) +#define TX_CMD_LIFE_TIME_INFINITE cpu_to_le32(0xFFFFFFFF) +#define IWL_GOOD_CRC_TH cpu_to_le16(1) #define IWL_MAX_SCAN_SIZE 1024 /* @@ -2267,7 +2263,7 @@ struct iwl_scan_cmd { * Number of channels in list is specified by channel_count. * Each channel in list is of type: * - * struct iwl4965_scan_channel channels[0]; + * struct iwl_scan_channel channels[0]; * * NOTE: Only one band of channels can be scanned per pass. You * must not mix 2.4GHz channels and 5.2GHz channels, and you must wait @@ -2278,7 +2274,7 @@ struct iwl_scan_cmd { } __attribute__ ((packed)); /* Can abort will notify by complete notification with abort status. */ -#define CAN_ABORT_STATUS __constant_cpu_to_le32(0x1) +#define CAN_ABORT_STATUS cpu_to_le32(0x1) /* complete notification statuses */ #define ABORT_STATUS 0x2 @@ -2422,6 +2418,8 @@ struct statistics_rx_ht_phy { __le32 reserved2; } __attribute__ ((packed)); +#define INTERFERENCE_DATA_AVAILABLE __constant_cpu_to_le32(1) + struct statistics_rx_non_phy { __le32 bogus_cts; /* CTS received when not expecting CTS */ __le32 bogus_ack; /* ACK received when not expecting ACK */ @@ -2540,8 +2538,8 @@ struct statistics_general { * STATISTICS_NOTIFICATIONs after received beacons (see below). This flag * does not affect the response to the REPLY_STATISTICS_CMD 0x9c itself. */ -#define IWL_STATS_CONF_CLEAR_STATS __constant_cpu_to_le32(0x1) /* see above */ -#define IWL_STATS_CONF_DISABLE_NOTIF __constant_cpu_to_le32(0x2)/* see above */ +#define IWL_STATS_CONF_CLEAR_STATS cpu_to_le32(0x1) /* see above */ +#define IWL_STATS_CONF_DISABLE_NOTIF cpu_to_le32(0x2)/* see above */ struct iwl_statistics_cmd { __le32 configuration_flags; /* IWL_STATS_CONF_* */ } __attribute__ ((packed)); @@ -2561,8 +2559,8 @@ struct iwl_statistics_cmd { * appropriately so that each notification contains statistics for only the * one channel that has just been scanned. */ -#define STATISTICS_REPLY_FLG_BAND_24G_MSK __constant_cpu_to_le32(0x2) -#define STATISTICS_REPLY_FLG_FAT_MODE_MSK __constant_cpu_to_le32(0x8) +#define STATISTICS_REPLY_FLG_BAND_24G_MSK cpu_to_le32(0x2) +#define STATISTICS_REPLY_FLG_FAT_MODE_MSK cpu_to_le32(0x8) struct iwl_notif_statistics { __le32 flag; struct statistics_rx rx; @@ -2578,7 +2576,7 @@ struct iwl_notif_statistics { * then this notification will be sent. */ #define CONSECUTIVE_MISSED_BCONS_TH 20 -struct iwl4965_missed_beacon_notif { +struct iwl_missed_beacon_notif { __le32 consequtive_missed_beacons; __le32 total_missed_becons; __le32 num_expected_beacons; @@ -2778,8 +2776,8 @@ struct iwl4965_missed_beacon_notif { #define HD_OFDM_ENERGY_TH_IN_INDEX (10) /* Control field in struct iwl_sensitivity_cmd */ -#define SENSITIVITY_CMD_CONTROL_DEFAULT_TABLE __constant_cpu_to_le16(0) -#define SENSITIVITY_CMD_CONTROL_WORK_TABLE __constant_cpu_to_le16(1) +#define SENSITIVITY_CMD_CONTROL_DEFAULT_TABLE cpu_to_le16(0) +#define SENSITIVITY_CMD_CONTROL_WORK_TABLE cpu_to_le16(1) /** * struct iwl_sensitivity_cmd @@ -2849,56 +2847,26 @@ struct iwl_sensitivity_cmd { * 1-0: amount of gain, units of 1.5 dB */ -/* "Differential Gain" opcode used in REPLY_PHY_CALIBRATION_CMD. */ -#define PHY_CALIBRATE_DIFF_GAIN_CMD (7) - -struct iwl4965_calibration_cmd { - u8 opCode; /* PHY_CALIBRATE_DIFF_GAIN_CMD (7) */ - u8 flags; /* not used */ - __le16 reserved; - s8 diff_gain_a; /* see above */ - s8 diff_gain_b; - s8 diff_gain_c; - u8 reserved1; -} __attribute__ ((packed)); - -/* Phy calibration command for 5000 series */ - -enum { - IWL5000_PHY_CALIBRATE_DC_CMD = 8, - IWL5000_PHY_CALIBRATE_LO_CMD = 9, - IWL5000_PHY_CALIBRATE_RX_BB_CMD = 10, - IWL5000_PHY_CALIBRATE_TX_IQ_CMD = 11, - IWL5000_PHY_CALIBRATE_RX_IQ_CMD = 12, - IWL5000_PHY_CALIBRATION_NOISE_CMD = 13, - IWL5000_PHY_CALIBRATE_AGC_TABLE_CMD = 14, - IWL5000_PHY_CALIBRATE_CRYSTAL_FRQ_CMD = 15, - IWL5000_PHY_CALIBRATE_BASE_BAND_CMD = 16, - IWL5000_PHY_CALIBRATE_TX_IQ_PERD_CMD = 17, - IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD = 18, - IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD = 19, -}; +/* Phy calibration command for series */ enum { - CALIBRATION_CFG_CMD = 0x65, - CALIBRATION_RES_NOTIFICATION = 0x66, - CALIBRATION_COMPLETE_NOTIFICATION = 0x67 + IWL_PHY_CALIBRATE_DIFF_GAIN_CMD = 7, + IWL_PHY_CALIBRATE_DC_CMD = 8, + IWL_PHY_CALIBRATE_LO_CMD = 9, + IWL_PHY_CALIBRATE_RX_BB_CMD = 10, + IWL_PHY_CALIBRATE_TX_IQ_CMD = 11, + IWL_PHY_CALIBRATE_RX_IQ_CMD = 12, + IWL_PHY_CALIBRATION_NOISE_CMD = 13, + IWL_PHY_CALIBRATE_AGC_TABLE_CMD = 14, + IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD = 15, + IWL_PHY_CALIBRATE_BASE_BAND_CMD = 16, + IWL_PHY_CALIBRATE_TX_IQ_PERD_CMD = 17, + IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD = 18, + IWL_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD = 19, }; -struct iwl_cal_crystal_freq_cmd { - u8 cap_pin1; - u8 cap_pin2; -} __attribute__ ((packed)); - -struct iwl5000_calibration { - u8 op_code; - u8 first_group; - u8 num_groups; - u8 all_data_valid; - struct iwl_cal_crystal_freq_cmd data; -} __attribute__ ((packed)); -#define IWL_CALIB_INIT_CFG_ALL __constant_cpu_to_le32(0xffffffff) +#define IWL_CALIB_INIT_CFG_ALL cpu_to_le32(0xffffffff) struct iwl_calib_cfg_elmnt_s { __le32 is_enable; @@ -2914,32 +2882,52 @@ struct iwl_calib_cfg_status_s { __le32 flags; } __attribute__ ((packed)); -struct iwl5000_calib_cfg_cmd { +struct iwl_calib_cfg_cmd { struct iwl_calib_cfg_status_s ucd_calib_cfg; struct iwl_calib_cfg_status_s drv_calib_cfg; __le32 reserved1; } __attribute__ ((packed)); -struct iwl5000_calib_hdr { +struct iwl_calib_hdr { u8 op_code; u8 first_group; u8 groups_num; u8 data_valid; } __attribute__ ((packed)); -struct iwl5000_calibration_chain_noise_reset_cmd { - u8 op_code; /* IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */ - u8 flags; /* not used */ - __le16 reserved; +struct iwl_calib_cmd { + struct iwl_calib_hdr hdr; + u8 data[0]; } __attribute__ ((packed)); -struct iwl5000_calibration_chain_noise_gain_cmd { - u8 op_code; /* IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD */ - u8 flags; /* not used */ - __le16 reserved; +/* IWL_PHY_CALIBRATE_DIFF_GAIN_CMD (7) */ +struct iwl_calib_diff_gain_cmd { + struct iwl_calib_hdr hdr; + s8 diff_gain_a; /* see above */ + s8 diff_gain_b; + s8 diff_gain_c; + u8 reserved1; +} __attribute__ ((packed)); + +struct iwl_calib_xtal_freq_cmd { + struct iwl_calib_hdr hdr; + u8 cap_pin1; + u8 cap_pin2; + u8 pad[2]; +} __attribute__ ((packed)); + +/* IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */ +struct iwl_calib_chain_noise_reset_cmd { + struct iwl_calib_hdr hdr; + u8 data[0]; +}; + +/* IWL_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD */ +struct iwl_calib_chain_noise_gain_cmd { + struct iwl_calib_hdr hdr; u8 delta_gain_1; u8 delta_gain_2; - __le16 reserved1; + u8 pad[2]; } __attribute__ ((packed)); /****************************************************************************** @@ -2999,11 +2987,11 @@ struct iwl_wimax_coex_event_entry { /* COEX flag masks */ -/* Staion table is valid */ +/* Station table is valid */ #define COEX_FLAGS_STA_TABLE_VALID_MSK (0x1) -/* UnMask wakeup src at unassociated sleep */ +/* UnMask wake up src at unassociated sleep */ #define COEX_FLAGS_UNASSOC_WA_UNMASK_MSK (0x4) -/* UnMask wakeup src at associated sleep */ +/* UnMask wake up src at associated sleep */ #define COEX_FLAGS_ASSOC_WA_UNMASK_MSK (0x8) /* Enable CoEx feature. */ #define COEX_FLAGS_COEX_ENABLE_MSK (0x80) @@ -3025,26 +3013,22 @@ struct iwl_rx_packet { struct iwl_cmd_header hdr; union { struct iwl_alive_resp alive_frame; - struct iwl4965_rx_frame rx_frame; - struct iwl4965_tx_resp tx_resp; - struct iwl4965_spectrum_notification spectrum_notif; - struct iwl4965_csa_notification csa_notif; + struct iwl_spectrum_notification spectrum_notif; + struct iwl_csa_notification csa_notif; struct iwl_error_resp err_resp; - struct iwl4965_card_state_notif card_state_notif; - struct iwl4965_beacon_notif beacon_status; + struct iwl_card_state_notif card_state_notif; struct iwl_add_sta_resp add_sta; struct iwl_rem_sta_resp rem_sta; - struct iwl4965_sleep_notification sleep_notif; - struct iwl4965_spectrum_resp spectrum; + struct iwl_sleep_notification sleep_notif; + struct iwl_spectrum_resp spectrum; struct iwl_notif_statistics stats; struct iwl_compressed_ba_resp compressed_ba; - struct iwl4965_missed_beacon_notif missed_beacon; - struct iwl5000_calibration calib; + struct iwl_missed_beacon_notif missed_beacon; __le32 status; u8 raw[0]; } u; } __attribute__ ((packed)); -#define IWL_RX_FRAME_SIZE (4 + sizeof(struct iwl4965_rx_frame)) +int iwl_agn_check_rxon_cmd(struct iwl_rxon_cmd *rxon); -#endif /* __iwl4965_commands_h__ */ +#endif /* __iwl_commands_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 01a84585133834a45c603a0c55763b7864441181..73d7973707eb023243dccc545a9bc0f29570e291 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -22,7 +22,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * Tomas Winkler + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *****************************************************************************/ @@ -30,19 +30,19 @@ #include #include -struct iwl_priv; /* FIXME: remove */ -#include "iwl-debug.h" #include "iwl-eeprom.h" #include "iwl-dev.h" /* FIXME: remove */ +#include "iwl-debug.h" #include "iwl-core.h" #include "iwl-io.h" #include "iwl-rfkill.h" #include "iwl-power.h" +#include "iwl-sta.h" MODULE_DESCRIPTION("iwl core"); MODULE_VERSION(IWLWIFI_VERSION); -MODULE_AUTHOR(DRV_COPYRIGHT); +MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); MODULE_LICENSE("GPL"); #define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np) \ @@ -88,26 +88,27 @@ EXPORT_SYMBOL(iwl_rates); * translate ucode response to mac80211 tx status control values */ void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, - struct ieee80211_tx_info *control) + struct ieee80211_tx_info *info) { int rate_index; + struct ieee80211_tx_rate *r = &info->control.rates[0]; - control->antenna_sel_tx = + info->antenna_sel_tx = ((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS); if (rate_n_flags & RATE_MCS_HT_MSK) - control->flags |= IEEE80211_TX_CTL_OFDM_HT; + r->flags |= IEEE80211_TX_RC_MCS; if (rate_n_flags & RATE_MCS_GF_MSK) - control->flags |= IEEE80211_TX_CTL_GREEN_FIELD; + r->flags |= IEEE80211_TX_RC_GREEN_FIELD; if (rate_n_flags & RATE_MCS_FAT_MSK) - control->flags |= IEEE80211_TX_CTL_40_MHZ_WIDTH; + r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; if (rate_n_flags & RATE_MCS_DUP_MSK) - control->flags |= IEEE80211_TX_CTL_DUP_DATA; + r->flags |= IEEE80211_TX_RC_DUP_DATA; if (rate_n_flags & RATE_MCS_SGI_MSK) - control->flags |= IEEE80211_TX_CTL_SHORT_GI; + r->flags |= IEEE80211_TX_RC_SHORT_GI; rate_index = iwl_hwrate_to_plcp_idx(rate_n_flags); - if (control->band == IEEE80211_BAND_5GHZ) + if (info->band == IEEE80211_BAND_5GHZ) rate_index -= IWL_FIRST_OFDM_RATE; - control->tx_rate_idx = rate_index; + r->idx = rate_index; } EXPORT_SYMBOL(iwl_hwrate_to_tx_control); @@ -119,7 +120,9 @@ int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) if (rate_n_flags & RATE_MCS_HT_MSK) { idx = (rate_n_flags & 0xff); - if (idx >= IWL_RATE_MIMO2_6M_PLCP) + if (idx >= IWL_RATE_MIMO3_6M_PLCP) + idx = idx - IWL_RATE_MIMO3_6M_PLCP; + else if (idx >= IWL_RATE_MIMO2_6M_PLCP) idx = idx - IWL_RATE_MIMO2_6M_PLCP; idx += IWL_FIRST_OFDM_RATE; @@ -140,7 +143,17 @@ int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) } EXPORT_SYMBOL(iwl_hwrate_to_plcp_idx); - +u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant) +{ + int i; + u8 ind = ant; + for (i = 0; i < RATE_ANT_NUM - 1; i++) { + ind = (ind + 1) < RATE_ANT_NUM ? ind + 1 : 0; + if (priv->hw_params.valid_tx_ant & BIT(ind)) + return ind; + } + return ant; +} const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; EXPORT_SYMBOL(iwl_bcast_addr); @@ -177,52 +190,6 @@ void iwl_hw_detect(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_hw_detect); -/* Tell nic where to find the "keep warm" buffer */ -int iwl_kw_init(struct iwl_priv *priv) -{ - unsigned long flags; - int ret; - - spin_lock_irqsave(&priv->lock, flags); - ret = iwl_grab_nic_access(priv); - if (ret) - goto out; - - iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, - priv->kw.dma_addr >> 4); - iwl_release_nic_access(priv); -out: - spin_unlock_irqrestore(&priv->lock, flags); - return ret; -} - -int iwl_kw_alloc(struct iwl_priv *priv) -{ - struct pci_dev *dev = priv->pci_dev; - struct iwl_kw *kw = &priv->kw; - - kw->size = IWL_KW_SIZE; - kw->v_addr = pci_alloc_consistent(dev, kw->size, &kw->dma_addr); - if (!kw->v_addr) - return -ENOMEM; - - return 0; -} - -/** - * iwl_kw_free - Free the "keep warm" buffer - */ -void iwl_kw_free(struct iwl_priv *priv) -{ - struct pci_dev *dev = priv->pci_dev; - struct iwl_kw *kw = &priv->kw; - - if (kw->v_addr) { - pci_free_consistent(dev, kw->size, kw->v_addr, kw->dma_addr); - memset(kw, 0, sizeof(*kw)); - } -} - int iwl_hw_nic_init(struct iwl_priv *priv) { unsigned long flags; @@ -271,55 +238,30 @@ int iwl_hw_nic_init(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_hw_nic_init); -/** - * iwl_clear_stations_table - Clear the driver's station table - * - * NOTE: This does not clear or otherwise alter the device's station table. - */ -void iwl_clear_stations_table(struct iwl_priv *priv) -{ - unsigned long flags; - - spin_lock_irqsave(&priv->sta_lock, flags); - - if (iwl_is_alive(priv) && - !test_bit(STATUS_EXIT_PENDING, &priv->status) && - iwl_send_cmd_pdu_async(priv, REPLY_REMOVE_ALL_STA, 0, NULL, NULL)) - IWL_ERROR("Couldn't clear the station table\n"); - - priv->num_stations = 0; - memset(priv->stations, 0, sizeof(priv->stations)); - - /* clean ucode key table bit map */ - priv->ucode_key_table = 0; - - spin_unlock_irqrestore(&priv->sta_lock, flags); -} -EXPORT_SYMBOL(iwl_clear_stations_table); - void iwl_reset_qos(struct iwl_priv *priv) { u16 cw_min = 15; u16 cw_max = 1023; u8 aifs = 2; - u8 is_legacy = 0; + bool is_legacy = false; unsigned long flags; int i; spin_lock_irqsave(&priv->lock, flags); - priv->qos_data.qos_active = 0; + /* QoS always active in AP and ADHOC mode + * In STA mode wait for association + */ + if (priv->iw_mode == NL80211_IFTYPE_ADHOC || + priv->iw_mode == NL80211_IFTYPE_AP) + priv->qos_data.qos_active = 1; + else + priv->qos_data.qos_active = 0; - if (priv->iw_mode == NL80211_IFTYPE_ADHOC) { - if (priv->qos_data.qos_enable) - priv->qos_data.qos_active = 1; - if (!(priv->active_rate & 0xfff0)) { - cw_min = 31; - is_legacy = 1; - } - } else if (priv->iw_mode == NL80211_IFTYPE_AP) { - if (priv->qos_data.qos_enable) - priv->qos_data.qos_active = 1; - } else if (!(priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK)) { + /* check for legacy mode */ + if ((priv->iw_mode == NL80211_IFTYPE_ADHOC && + (priv->active_rate & IWL_OFDM_RATES_MASK) == 0) || + (priv->iw_mode == NL80211_IFTYPE_STATION && + (priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK) == 0)) { cw_min = 31; is_legacy = 1; } @@ -385,10 +327,10 @@ void iwl_reset_qos(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_reset_qos); -#define MAX_BIT_RATE_40_MHZ 0x96 /* 150 Mbps */ -#define MAX_BIT_RATE_20_MHZ 0x48 /* 72 Mbps */ +#define MAX_BIT_RATE_40_MHZ 150 /* Mbps */ +#define MAX_BIT_RATE_20_MHZ 72 /* Mbps */ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, - struct ieee80211_ht_info *ht_info, + struct ieee80211_sta_ht_cap *ht_info, enum ieee80211_band band) { u16 max_bit_rate = 0; @@ -396,45 +338,46 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, u8 tx_chains_num = priv->hw_params.tx_chains_num; ht_info->cap = 0; - memset(ht_info->supp_mcs_set, 0, 16); + memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); - ht_info->ht_supported = 1; + ht_info->ht_supported = true; - ht_info->cap |= (u16)IEEE80211_HT_CAP_GRN_FLD; - ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_20; - ht_info->cap |= (u16)(IEEE80211_HT_CAP_SM_PS & + ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD; + ht_info->cap |= IEEE80211_HT_CAP_SGI_20; + ht_info->cap |= (IEEE80211_HT_CAP_SM_PS & (WLAN_HT_CAP_SM_PS_DISABLED << 2)); max_bit_rate = MAX_BIT_RATE_20_MHZ; if (priv->hw_params.fat_channel & BIT(band)) { - ht_info->cap |= (u16)IEEE80211_HT_CAP_SUP_WIDTH; - ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_40; - ht_info->supp_mcs_set[4] = 0x01; + ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; + ht_info->cap |= IEEE80211_HT_CAP_SGI_40; + ht_info->mcs.rx_mask[4] = 0x01; max_bit_rate = MAX_BIT_RATE_40_MHZ; } if (priv->cfg->mod_params->amsdu_size_8K) - ht_info->cap |= (u16)IEEE80211_HT_CAP_MAX_AMSDU; + ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU; ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF; ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF; - ht_info->supp_mcs_set[0] = 0xFF; + ht_info->mcs.rx_mask[0] = 0xFF; if (rx_chains_num >= 2) - ht_info->supp_mcs_set[1] = 0xFF; + ht_info->mcs.rx_mask[1] = 0xFF; if (rx_chains_num >= 3) - ht_info->supp_mcs_set[2] = 0xFF; + ht_info->mcs.rx_mask[2] = 0xFF; /* Highest supported Rx data rate */ max_bit_rate *= rx_chains_num; - ht_info->supp_mcs_set[10] = (u8)(max_bit_rate & 0x00FF); - ht_info->supp_mcs_set[11] = (u8)((max_bit_rate & 0xFF00) >> 8); + WARN_ON(max_bit_rate & ~IEEE80211_HT_MCS_RX_HIGHEST_MASK); + ht_info->mcs.rx_highest = cpu_to_le16(max_bit_rate); /* Tx MCS capabilities */ - ht_info->supp_mcs_set[12] = IEEE80211_HT_CAP_MCS_TX_DEFINED; + ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; if (tx_chains_num != rx_chains_num) { - ht_info->supp_mcs_set[12] |= IEEE80211_HT_CAP_MCS_TX_RX_DIFF; - ht_info->supp_mcs_set[12] |= ((tx_chains_num - 1) << 2); + ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; + ht_info->mcs.tx_params |= ((tx_chains_num - 1) << + IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); } } @@ -498,7 +441,7 @@ static int iwlcore_init_geos(struct iwl_priv *priv) sband->n_bitrates = IWL_RATE_COUNT - IWL_FIRST_OFDM_RATE; if (priv->cfg->sku & IWL_SKU_N) - iwlcore_init_ht_hw_capab(priv, &sband->ht_info, + iwlcore_init_ht_hw_capab(priv, &sband->ht_cap, IEEE80211_BAND_5GHZ); sband = &priv->bands[IEEE80211_BAND_2GHZ]; @@ -508,7 +451,7 @@ static int iwlcore_init_geos(struct iwl_priv *priv) sband->n_bitrates = IWL_RATE_COUNT; if (priv->cfg->sku & IWL_SKU_N) - iwlcore_init_ht_hw_capab(priv, &sband->ht_info, + iwlcore_init_ht_hw_capab(priv, &sband->ht_cap, IEEE80211_BAND_2GHZ); priv->ieee_channels = channels; @@ -598,8 +541,8 @@ static void iwlcore_free_geos(struct iwl_priv *priv) static bool is_single_rx_stream(struct iwl_priv *priv) { return !priv->current_ht_config.is_ht || - ((priv->current_ht_config.supp_mcs_set[1] == 0) && - (priv->current_ht_config.supp_mcs_set[2] == 0)); + ((priv->current_ht_config.mcs.rx_mask[1] == 0) && + (priv->current_ht_config.mcs.rx_mask[2] == 0)); } static u8 iwl_is_channel_extension(struct iwl_priv *priv, @@ -612,10 +555,10 @@ static u8 iwl_is_channel_extension(struct iwl_priv *priv, if (!is_channel_valid(ch_info)) return 0; - if (extension_chan_offset == IEEE80211_HT_IE_CHA_SEC_ABOVE) + if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) return !(ch_info->fat_extension_channel & IEEE80211_CHAN_NO_FAT_ABOVE); - else if (extension_chan_offset == IEEE80211_HT_IE_CHA_SEC_BELOW) + else if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) return !(ch_info->fat_extension_channel & IEEE80211_CHAN_NO_FAT_BELOW); @@ -623,24 +566,24 @@ static u8 iwl_is_channel_extension(struct iwl_priv *priv, } u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, - struct ieee80211_ht_info *sta_ht_inf) + struct ieee80211_sta_ht_cap *sta_ht_inf) { struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config; if ((!iwl_ht_conf->is_ht) || (iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ) || - (iwl_ht_conf->extension_chan_offset == IEEE80211_HT_IE_CHA_SEC_NONE)) + (iwl_ht_conf->extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE)) return 0; if (sta_ht_inf) { if ((!sta_ht_inf->ht_supported) || - (!(sta_ht_inf->cap & IEEE80211_HT_CAP_SUP_WIDTH))) + (!(sta_ht_inf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))) return 0; } return iwl_is_channel_extension(priv, priv->band, - iwl_ht_conf->control_channel, - iwl_ht_conf->extension_chan_offset); + le16_to_cpu(priv->staging_rxon.channel), + iwl_ht_conf->extension_chan_offset); } EXPORT_SYMBOL(iwl_is_fat_tx_allowed); @@ -665,22 +608,15 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK | RXON_FLG_CHANNEL_MODE_PURE_40_MSK); - if (le16_to_cpu(rxon->channel) != ht_info->control_channel) { - IWL_DEBUG_ASSOC("control diff than current %d %d\n", - le16_to_cpu(rxon->channel), - ht_info->control_channel); - return; - } - /* Note: control channel is opposite of extension channel */ switch (ht_info->extension_chan_offset) { - case IEEE80211_HT_IE_CHA_SEC_ABOVE: + case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); break; - case IEEE80211_HT_IE_CHA_SEC_BELOW: + case IEEE80211_HT_PARAM_CHA_SEC_BELOW: rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; break; - case IEEE80211_HT_IE_CHA_SEC_NONE: + case IEEE80211_HT_PARAM_CHA_SEC_NONE: default: rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK; break; @@ -694,14 +630,12 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) IWL_DEBUG_ASSOC("supported HT rate 0x%X 0x%X 0x%X " "rxon flags 0x%X operation mode :0x%X " - "extension channel offset 0x%x " - "control chan %d\n", - ht_info->supp_mcs_set[0], - ht_info->supp_mcs_set[1], - ht_info->supp_mcs_set[2], + "extension channel offset 0x%x\n", + ht_info->mcs.rx_mask[0], + ht_info->mcs.rx_mask[1], + ht_info->mcs.rx_mask[2], le32_to_cpu(rxon->flags), ht_info->ht_protection, - ht_info->extension_chan_offset, - ht_info->control_channel); + ht_info->extension_chan_offset); return; } EXPORT_SYMBOL(iwl_set_rxon_ht); @@ -745,7 +679,7 @@ static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt) break; case WLAN_HT_CAP_SM_PS_INVALID: default: - IWL_ERROR("invalide mimo ps mode %d\n", + IWL_ERROR("invalid mimo ps mode %d\n", priv->current_ht_config.sm_ps); WARN_ON(1); idle_cnt = -1; @@ -871,11 +805,14 @@ int iwl_setup_mac(struct iwl_priv *priv) /* Tell mac80211 our characteristics */ hw->flags = IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_NOISE_DBM; + IEEE80211_HW_NOISE_DBM | + IEEE80211_HW_AMPDU_AGGREGATION; hw->wiphy->interface_modes = - BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); + + hw->wiphy->fw_handles_regulatory = true; + /* Default value; 4 EDCA QOS priorities */ hw->queues = 4; /* queues to support 11n aggregation */ @@ -948,16 +885,12 @@ int iwl_init_drv(struct iwl_priv *priv) priv->iw_mode = NL80211_IFTYPE_STATION; - priv->use_ant_b_for_management_frame = 1; /* start with ant B */ priv->current_ht_config.sm_ps = WLAN_HT_CAP_SM_PS_DISABLED; /* Choose which receivers/antennas to use */ iwl_set_rxon_chain(priv); iwl_init_scan_params(priv); - if (priv->cfg->mod_params->enable_qos) - priv->qos_data.qos_enable = 1; - iwl_reset_qos(priv); priv->qos_data.qos_active = 0; @@ -1025,6 +958,30 @@ void iwl_uninit_drv(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_uninit_drv); + +void iwl_disable_interrupts(struct iwl_priv *priv) +{ + clear_bit(STATUS_INT_ENABLED, &priv->status); + + /* disable interrupts from uCode/NIC to host */ + iwl_write32(priv, CSR_INT_MASK, 0x00000000); + + /* acknowledge/clear/reset any interrupts still pending + * from uCode or flow handler (Rx/Tx DMA) */ + iwl_write32(priv, CSR_INT, 0xffffffff); + iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff); + IWL_DEBUG_ISR("Disabled interrupts\n"); +} +EXPORT_SYMBOL(iwl_disable_interrupts); + +void iwl_enable_interrupts(struct iwl_priv *priv) +{ + IWL_DEBUG_ISR("Enabling interrupts\n"); + set_bit(STATUS_INT_ENABLED, &priv->status); + iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK); +} +EXPORT_SYMBOL(iwl_enable_interrupts); + int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags) { u32 stat_flags = 0; @@ -1172,24 +1129,47 @@ int iwl_verify_ucode(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_verify_ucode); + +static const char *desc_lookup_text[] = { + "OK", + "FAIL", + "BAD_PARAM", + "BAD_CHECKSUM", + "NMI_INTERRUPT_WDG", + "SYSASSERT", + "FATAL_ERROR", + "BAD_COMMAND", + "HW_ERROR_TUNE_LOCK", + "HW_ERROR_TEMPERATURE", + "ILLEGAL_CHAN_FREQ", + "VCC_NOT_STABLE", + "FH_ERROR", + "NMI_INTERRUPT_HOST", + "NMI_INTERRUPT_ACTION_PT", + "NMI_INTERRUPT_UNKNOWN", + "UCODE_VERSION_MISMATCH", + "HW_ERROR_ABS_LOCK", + "HW_ERROR_CAL_LOCK_FAIL", + "NMI_INTERRUPT_INST_ACTION_PT", + "NMI_INTERRUPT_DATA_ACTION_PT", + "NMI_TRM_HW_ER", + "NMI_INTERRUPT_TRM", + "NMI_INTERRUPT_BREAK_POINT" + "DEBUG_0", + "DEBUG_1", + "DEBUG_2", + "DEBUG_3", + "UNKNOWN" +}; + static const char *desc_lookup(int i) { - switch (i) { - case 1: - return "FAIL"; - case 2: - return "BAD_PARAM"; - case 3: - return "BAD_CHECKSUM"; - case 4: - return "NMI_INTERRUPT"; - case 5: - return "SYSASSERT"; - case 6: - return "FATAL_ERROR"; - } + int max = ARRAY_SIZE(desc_lookup_text) - 1; - return "UNKNOWN"; + if (i < 0 || i > max) + i = max; + + return desc_lookup_text[i]; } #define ERROR_START_OFFSET (1 * sizeof(u32)) @@ -1235,9 +1215,9 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32)); time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32)); - IWL_ERROR("Desc Time " + IWL_ERROR("Desc Time " "data1 data2 line\n"); - IWL_ERROR("%-13s (#%d) %010u 0x%08X 0x%08X %u\n", + IWL_ERROR("%-28s (#%02d) %010u 0x%08X 0x%08X %u\n", desc_lookup(desc), desc, time, data1, data2, line); IWL_ERROR("blink1 blink2 ilink1 ilink2\n"); IWL_ERROR("0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2, @@ -1377,6 +1357,7 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_rf_kill_ct_config); + /* * CARD_STATE_CMD * @@ -1465,6 +1446,16 @@ int iwl_radio_kill_sw_enable_radio(struct iwl_priv *priv) return 0; } + /* when driver is up while rfkill is on, it wont receive + * any CARD_STATE_NOTIFICATION notifications so we have to + * restart it in here + */ + if (priv->is_open && !test_bit(STATUS_ALIVE, &priv->status)) { + clear_bit(STATUS_RF_KILL_SW, &priv->status); + if (!iwl_is_rfkill(priv)) + queue_work(priv->workqueue, &priv->up); + } + /* If the driver is already loaded, it will receive * CARD_STATE_NOTIFICATION notifications and the handler will * call restart to reload the driver. diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 288b6a800e03306cc2cc34885e364450b9389cb2..7c3a20a986bbd3567a6ed7c9102206e0d81e9aa1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * Tomas Winkler + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -72,6 +72,7 @@ struct iwl_cmd; #define IWLWIFI_VERSION "1.3.27k" #define DRV_COPYRIGHT "Copyright(c) 2003-2008 Intel Corporation" +#define DRV_AUTHOR "" #define IWL_PCI_DEVICE(dev, subdev, cfg) \ .vendor = PCI_VENDOR_ID_INTEL, .device = (dev), \ @@ -100,12 +101,8 @@ struct iwl_hcmd_utils_ops { }; struct iwl_lib_ops { - /* set hw dependant perameters */ + /* set hw dependent parameters */ int (*set_hw_params)(struct iwl_priv *priv); - /* ucode shared memory */ - int (*alloc_shared_mem)(struct iwl_priv *priv); - void (*free_shared_mem)(struct iwl_priv *priv); - int (*shared_mem_rx_idx)(struct iwl_priv *priv); /* Handling TX */ void (*txq_update_byte_cnt_tbl)(struct iwl_priv *priv, struct iwl_tx_queue *txq, @@ -157,22 +154,53 @@ struct iwl_ops { struct iwl_mod_params { int disable; /* def: 0 = enable radio */ int sw_crypto; /* def: 0 = using hardware encryption */ - int debug; /* def: 0 = minimal debug log messages */ + u32 debug; /* def: 0 = minimal debug log messages */ int disable_hw_scan; /* def: 0 = use h/w scan */ int num_of_queues; /* def: HW dependent */ int num_of_ampdu_queues;/* def: HW dependent */ - int enable_qos; /* def: 1 = use quality of service */ int disable_11n; /* def: 0 = disable 11n capabilities */ int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */ int antenna; /* def: 0 = both antennas (use diversity) */ int restart_fw; /* def: 1 = restart firmware */ }; +/** + * struct iwl_cfg + * @fw_name_pre: Firmware filename prefix. The api version and extension + * (.ucode) will be added to filename before loading from disk. The + * filename is constructed as fw_name_pre.ucode. + * @ucode_api_max: Highest version of uCode API supported by driver. + * @ucode_api_min: Lowest version of uCode API supported by driver. + * + * We enable the driver to be backward compatible wrt API version. The + * driver specifies which APIs it supports (with @ucode_api_max being the + * highest and @ucode_api_min the lowest). Firmware will only be loaded if + * it has a supported API version. The firmware's API version will be + * stored in @iwl_priv, enabling the driver to make runtime changes based + * on firmware version used. + * + * For example, + * if (IWL_UCODE_API(priv->ucode_ver) >= 2) { + * Driver interacts with Firmware API version >= 2. + * } else { + * Driver interacts with Firmware API version 1. + * } + * + * The ideal usage of this infrastructure is to treat a new ucode API + * release as a new hardware revision. That is, through utilizing the + * iwl_hcmd_utils_ops etc. we accommodate different command structures + * and flows between hardware versions (4965/5000) as well as their API + * versions. + */ struct iwl_cfg { const char *name; - const char *fw_name; + const char *fw_name_pre; + const unsigned int ucode_api_max; + const unsigned int ucode_api_min; unsigned int sku; int eeprom_size; + u16 eeprom_ver; + u16 eeprom_calib_ver; const struct iwl_ops *ops; const struct iwl_mod_params *mod_params; }; @@ -184,22 +212,17 @@ struct iwl_cfg { struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg, struct ieee80211_ops *hw_ops); void iwl_hw_detect(struct iwl_priv *priv); -void iwl_clear_stations_table(struct iwl_priv *priv); void iwl_reset_qos(struct iwl_priv *priv); void iwl_set_rxon_chain(struct iwl_priv *priv); int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch); void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info); u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, - struct ieee80211_ht_info *sta_ht_inf); + struct ieee80211_sta_ht_cap *sta_ht_inf); int iwl_hw_nic_init(struct iwl_priv *priv); int iwl_setup_mac(struct iwl_priv *priv); int iwl_set_hw_params(struct iwl_priv *priv); int iwl_init_drv(struct iwl_priv *priv); void iwl_uninit_drv(struct iwl_priv *priv); -/* "keep warm" functions */ -int iwl_kw_init(struct iwl_priv *priv); -int iwl_kw_alloc(struct iwl_priv *priv); -void iwl_kw_free(struct iwl_priv *priv); /***************************************************** * RX @@ -212,8 +235,6 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq); void iwl_rx_replenish(struct iwl_priv *priv); int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq); -int iwl_rx_agg_start(struct iwl_priv *priv, const u8 *addr, int tid, u16 ssn); -int iwl_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid); int iwl_rx_queue_restock(struct iwl_priv *priv); int iwl_rx_queue_space(const struct iwl_rx_queue *q); void iwl_rx_allocate(struct iwl_priv *priv); @@ -237,7 +258,6 @@ int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq); int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn); int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid); int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id); - /***************************************************** * TX power ****************************************************/ @@ -259,6 +279,13 @@ void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, struct ieee80211_tx_info *info); int iwl_hwrate_to_plcp_idx(u32 rate_n_flags); +u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant_idx); + +static inline u32 iwl_ant_idx_to_flags(u8 ant_idx) +{ + return BIT(ant_idx) << RATE_MCS_ANT_POS; +} + static inline u8 iwl_hw_get_rate(__le32 rate_n_flags) { return le32_to_cpu(rate_n_flags) & 0xFF; @@ -289,6 +316,14 @@ int iwl_send_calib_results(struct iwl_priv *priv); int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len); void iwl_calib_free_results(struct iwl_priv *priv); +/******************************************************************************* + * Spectrum Measureemtns in iwl-spectrum.c + ******************************************************************************/ +#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT +void iwl_setup_spectrum_handlers(struct iwl_priv *priv); +#else +static inline void iwl_setup_spectrum_handlers(struct iwl_priv *priv) {} +#endif /***************************************************** * S e n d i n g H o s t C o m m a n d s * *****************************************************/ @@ -307,12 +342,19 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len, int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd); +/***************************************************** + * PCI * + *****************************************************/ +void iwl_disable_interrupts(struct iwl_priv *priv); +void iwl_enable_interrupts(struct iwl_priv *priv); + /***************************************************** * Error Handling Debugging ******************************************************/ void iwl_dump_nic_error_log(struct iwl_priv *priv); void iwl_dump_nic_event_log(struct iwl_priv *priv); + /*************** DRIVER STATUS FUNCTIONS *****/ #define STATUS_HCMD_ACTIVE 0 /* host command in progress */ diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 662edf4f8d226a13e8ce915e9c2aa085d581adc5..f34ede44ed109604d0463fac8a39d0a2ae9b483b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -60,6 +60,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *****************************************************************************/ +#ifndef __iwl_csr_h__ +#define __iwl_csr_h__ /*=== CSR (control and status registers) ===*/ #define CSR_BASE (0x000) @@ -214,6 +216,8 @@ /* EEPROM REG */ #define CSR_EEPROM_REG_READ_VALID_MSK (0x00000001) #define CSR_EEPROM_REG_BIT_CMD (0x00000002) +#define CSR_EEPROM_REG_MSK_ADDR (0x0000FFFC) +#define CSR_EEPROM_REG_MSK_DATA (0xFFFF0000) /* EEPROM GP */ #define CSR_EEPROM_GP_VALID_MSK (0x00000006) @@ -286,4 +290,4 @@ #define HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED (0x00000004) - +#endif /* !__iwl_csr_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index e548d67f87fd400583d1ff61ab06d24f78a2885b..56c13b458de7fc7571298591ec3d2eb2b20bfc27 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -21,7 +21,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -40,6 +40,13 @@ do { if ((priv->debug_level & (level)) && net_ratelimit()) \ dev_printk(KERN_ERR, &(priv->hw->wiphy->dev), "%c %s " fmt, \ in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0) +#define iwl_print_hex_dump(priv, level, p, len) \ +do { \ + if (priv->debug_level & level) \ + print_hex_dump(KERN_DEBUG, "iwl data: ", \ + DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \ +} while (0) + #ifdef CONFIG_IWLWIFI_DEBUGFS struct iwl_debugfs { const char *name; @@ -53,6 +60,7 @@ struct iwl_debugfs { struct dentry *file_rx_statistics; struct dentry *file_tx_statistics; struct dentry *file_log_event; + struct dentry *file_channels; } dbgfs_data_files; struct dir_rf_files { struct dentry *file_disable_sensitivity; @@ -70,6 +78,9 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv); #else #define IWL_DEBUG(level, fmt, args...) #define IWL_DEBUG_LIMIT(level, fmt, args...) +static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level, + void *p, u32 len) +{} #endif /* CONFIG_IWLWIFI_DEBUG */ @@ -85,29 +96,25 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv) #endif /* CONFIG_IWLWIFI_DEBUGFS */ /* - * To use the debug system; + * To use the debug system: * * If you are defining a new debug classification, simply add it to the #define - * list here in the form of: + * list here in the form of * * #define IWL_DL_xxxx VALUE * - * shifting value to the left one bit from the previous entry. xxxx should be - * the name of the classification (for example, WEP) + * where xxxx should be the name of the classification (for example, WEP). * * You then need to either add a IWL_xxxx_DEBUG() macro definition for your * classification, or use IWL_DEBUG(IWL_DL_xxxx, ...) whenever you want * to send output to that classification. * - * To add your debug level to the list of levels seen when you perform - * - * % cat /proc/net/iwl/debug_level - * - * you simply need to add your entry to the iwl_debug_levels array. + * The active debug levels can be accessed via files * - * If you do not see debug_level in /proc/net/iwl then you do not have - * CONFIG_IWLWIFI_DEBUG defined in your kernel configuration + * /sys/module/iwlagn/parameters/debug{50} + * /sys/class/net/wlan0/device/debug_level * + * when CONFIG_IWLWIFI_DEBUG=y. */ #define IWL_DL_INFO (1 << 0) @@ -183,6 +190,8 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv) #define IWL_DEBUG_STATS(f, a...) IWL_DEBUG(IWL_DL_STATS, f, ## a) #define IWL_DEBUG_STATS_LIMIT(f, a...) IWL_DEBUG_LIMIT(IWL_DL_STATS, f, ## a) #define IWL_DEBUG_TX_REPLY(f, a...) IWL_DEBUG(IWL_DL_TX_REPLY, f, ## a) +#define IWL_DEBUG_TX_REPLY_LIMIT(f, a...) \ + IWL_DEBUG_LIMIT(IWL_DL_TX_REPLY, f, ## a) #define IWL_DEBUG_QOS(f, a...) IWL_DEBUG(IWL_DL_QOS, f, ## a) #define IWL_DEBUG_RADIO(f, a...) IWL_DEBUG(IWL_DL_RADIO, f, ## a) #define IWL_DEBUG_POWER(f, a...) IWL_DEBUG(IWL_DL_POWER, f, ## a) diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 20db0eb636a82b64a85f403ef5c096ab37827aaf..d5253a179dec6fd35cd37a4d9687046899ca782a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -22,7 +22,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * Tomas Winkler + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *****************************************************************************/ @@ -58,7 +58,8 @@ #define DEBUGFS_ADD_BOOL(name, parent, ptr) do { \ dbgfs->dbgfs_##parent##_files.file_##name = \ debugfs_create_bool(#name, 0644, dbgfs->dir_##parent, ptr); \ - if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name)) \ + if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name) \ + || !dbgfs->dbgfs_##parent##_files.file_##name) \ goto err; \ } while (0) @@ -228,7 +229,6 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, ssize_t ret; /* Add 30 for initial string */ const size_t bufsz = 30 + sizeof(char) * 500 * (priv->num_stations); - DECLARE_MAC_BUF(mac); buf = kmalloc(bufsz, GFP_KERNEL); if (!buf) @@ -242,7 +242,6 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, if (station->used) { pos += scnprintf(buf + pos, bufsz - pos, "station %d:\ngeneral data:\n", i+1); - print_mac(mac, station->sta.sta.addr); pos += scnprintf(buf + pos, bufsz - pos, "id: %u\n", station->sta.sta.sta_id); pos += scnprintf(buf + pos, bufsz - pos, "mode: %u\n", @@ -349,12 +348,86 @@ static ssize_t iwl_dbgfs_log_event_write(struct file *file, return count; } + + +static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + struct ieee80211_channel *channels = NULL; + const struct ieee80211_supported_band *supp_band = NULL; + int pos = 0, i, bufsz = PAGE_SIZE; + char *buf; + ssize_t ret; + + if (!test_bit(STATUS_GEO_CONFIGURED, &priv->status)) + return -EAGAIN; + + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERROR("Can not allocate Buffer\n"); + return -ENOMEM; + } + + supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_2GHZ); + channels = supp_band->channels; + + pos += scnprintf(buf + pos, bufsz - pos, + "Displaying %d channels in 2.4GHz band 802.11bg):\n", + supp_band->n_channels); + + for (i = 0; i < supp_band->n_channels; i++) + pos += scnprintf(buf + pos, bufsz - pos, + "%d: %ddBm: BSS%s%s, %s.\n", + ieee80211_frequency_to_channel( + channels[i].center_freq), + channels[i].max_power, + channels[i].flags & IEEE80211_CHAN_RADAR ? + " (IEEE 802.11h required)" : "", + (!(channels[i].flags & IEEE80211_CHAN_NO_IBSS) + || (channels[i].flags & + IEEE80211_CHAN_RADAR)) ? "" : + ", IBSS", + channels[i].flags & + IEEE80211_CHAN_PASSIVE_SCAN ? + "passive only" : "active/passive"); + + supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_5GHZ); + channels = supp_band->channels; + + pos += scnprintf(buf + pos, bufsz - pos, + "Displaying %d channels in 5.2GHz band (802.11a)\n", + supp_band->n_channels); + + for (i = 0; i < supp_band->n_channels; i++) + pos += scnprintf(buf + pos, bufsz - pos, + "%d: %ddBm: BSS%s%s, %s.\n", + ieee80211_frequency_to_channel( + channels[i].center_freq), + channels[i].max_power, + channels[i].flags & IEEE80211_CHAN_RADAR ? + " (IEEE 802.11h required)" : "", + ((channels[i].flags & IEEE80211_CHAN_NO_IBSS) + || (channels[i].flags & + IEEE80211_CHAN_RADAR)) ? "" : + ", IBSS", + channels[i].flags & + IEEE80211_CHAN_PASSIVE_SCAN ? + "passive only" : "active/passive"); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + + DEBUGFS_READ_WRITE_FILE_OPS(sram); DEBUGFS_WRITE_FILE_OPS(log_event); DEBUGFS_READ_FILE_OPS(eeprom); DEBUGFS_READ_FILE_OPS(stations); DEBUGFS_READ_FILE_OPS(rx_statistics); DEBUGFS_READ_FILE_OPS(tx_statistics); +DEBUGFS_READ_FILE_OPS(channels); /* * Create the debugfs files and directories @@ -388,6 +461,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(stations, data); DEBUGFS_ADD_FILE(rx_statistics, data); DEBUGFS_ADD_FILE(tx_statistics, data); + DEBUGFS_ADD_FILE(channels, data); DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); DEBUGFS_ADD_BOOL(disable_chain_noise, rf, &priv->disable_chain_noise_cal); @@ -416,6 +490,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_log_event); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_stations); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_channels); DEBUGFS_REMOVE(priv->dbgfs->dir_data); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 9966d4e384ce75d37264345431be2122a5304c68..0468fcc1ea98ed58d42e6988cb248a7a162a3589 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -54,6 +54,7 @@ extern struct iwl_cfg iwl5100_agn_cfg; extern struct iwl_cfg iwl5350_agn_cfg; extern struct iwl_cfg iwl5100_bg_cfg; extern struct iwl_cfg iwl5100_abg_cfg; +extern struct iwl_cfg iwl5150_agn_cfg; /* CT-KILL constants */ #define CT_KILL_THRESHOLD 110 /* in Celsius */ @@ -113,11 +114,9 @@ struct iwl_queue { * space less than this */ } __attribute__ ((packed)); -#define MAX_NUM_OF_TBS (20) - /* One for each TFD */ struct iwl_tx_info { - struct sk_buff *skb[MAX_NUM_OF_TBS]; + struct sk_buff *skb[IWL_NUM_OF_TBS - 1]; }; /** @@ -135,12 +134,13 @@ struct iwl_tx_info { */ struct iwl_tx_queue { struct iwl_queue q; - struct iwl_tfd_frame *bd; + struct iwl_tfd *tfds; struct iwl_cmd *cmd[TFD_TX_CMD_SLOTS]; struct iwl_tx_info *txb; - int need_update; - int sched_retry; - int active; + u8 need_update; + u8 sched_retry; + u8 active; + u8 swq_id; }; #define IWL_NUM_SCAN_RATES (2) @@ -186,12 +186,6 @@ struct iwl_channel_info { u8 fat_extension_channel; /* HT_IE_EXT_CHANNEL_* */ }; -struct iwl4965_clip_group { - /* maximum power level to prevent clipping for each rate, derived by - * us from this band's saturation power in EEPROM */ - const s8 clip_powers[IWL_MAX_RATES]; -}; - #define IWL_TX_FIFO_AC0 0 #define IWL_TX_FIFO_AC1 1 @@ -253,7 +247,8 @@ struct iwl_cmd_meta { /* The CMD_SIZE_HUGE flag bit indicates that the command * structure is stored at the end of the shared queue memory. */ u32 flags; - + DECLARE_PCI_UNMAP_ADDR(mapping) + DECLARE_PCI_UNMAP_LEN(len) } __attribute__ ((packed)); #define IWL_CMD_MAX_PAYLOAD 320 @@ -269,24 +264,16 @@ struct iwl_cmd { struct iwl_cmd_meta meta; /* driver data */ struct iwl_cmd_header hdr; /* uCode API */ union { - struct iwl_addsta_cmd addsta; - struct iwl_led_cmd led; u32 flags; u8 val8; u16 val16; u32 val32; - struct iwl4965_bt_cmd bt; - struct iwl4965_rxon_time_cmd rxon_time; - struct iwl_powertable_cmd powertable; - struct iwl_qosparam_cmd qosparam; struct iwl_tx_cmd tx; - struct iwl4965_rxon_assoc_cmd rxon_assoc; - struct iwl_rem_sta_cmd rm_sta; - u8 *indirect; u8 payload[IWL_CMD_MAX_PAYLOAD]; } __attribute__ ((packed)) cmd; } __attribute__ ((packed)); + struct iwl_host_cmd { u8 id; u16 len; @@ -309,7 +296,6 @@ struct iwl_host_cmd { /** * struct iwl_rx_queue - Rx queue - * @processed: Internal index to last handled Rx packet * @read: Shared index to newest available Rx buffer * @write: Shared index to oldest written Rx packet * @free_count: Number of pre-allocated buffers in rx_free @@ -324,26 +310,19 @@ struct iwl_rx_queue { dma_addr_t dma_addr; struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS]; struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE]; - u32 processed; u32 read; u32 write; u32 free_count; struct list_head rx_free; struct list_head rx_used; int need_update; + struct iwl_rb_status *rb_stts; + dma_addr_t rb_stts_dma; spinlock_t lock; }; #define IWL_SUPPORTED_RATES_IE_LEN 8 -#define SCAN_INTERVAL 100 - -#define MAX_A_CHANNELS 252 -#define MIN_A_CHANNELS 7 - -#define MAX_B_CHANNELS 14 -#define MIN_B_CHANNELS 1 - #define MAX_TID_COUNT 9 #define IWL_INVALID_RATE 0xFF @@ -413,9 +392,8 @@ struct iwl_ht_info { u8 max_amsdu_size; u8 ampdu_factor; u8 mpdu_density; - u8 supp_mcs_set[16]; + struct ieee80211_mcs_info mcs; /* BSS related data */ - u8 control_channel; u8 extension_chan_offset; u8 tx_chan_width; u8 ht_protection; @@ -444,7 +422,6 @@ union iwl_qos_capabity { /* QoS structures */ struct iwl_qos_info { - int qos_enable; int qos_active; union iwl_qos_capabity qos_cap; struct iwl_qosparam_cmd def_qos_parm; @@ -470,7 +447,7 @@ struct fw_desc { /* uCode file layout */ struct iwl_ucode { - __le32 ver; /* major/minor/subminor */ + __le32 ver; /* major/minor/API/serial */ __le32 inst_size; /* bytes of runtime instructions */ __le32 data_size; /* bytes of runtime data */ __le32 init_size; /* bytes of initialization instructions */ @@ -511,11 +488,15 @@ struct iwl_sensitivity_ranges { }; -#define IWL_FAT_CHANNEL_52 BIT(IEEE80211_BAND_5GHZ) +#define KELVIN_TO_CELSIUS(x) ((x)-273) +#define CELSIUS_TO_KELVIN(x) ((x)+273) + /** * struct iwl_hw_params * @max_txq_num: Max # Tx queues supported + * @dma_chnl_num: Number of Tx DMA/FIFO channels + * @scd_bc_tbls_size: size of scheduler byte count tables * @tx/rx_chains_num: Number of TX/RX chains * @valid_tx/rx_ant: usable antennas * @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2) @@ -528,11 +509,13 @@ struct iwl_sensitivity_ranges { * @sw_crypto: 0 for hw, 1 for sw * @max_xxx_size: for ucode uses * @ct_kill_threshold: temperature threshold + * @calib_init_cfg: setup initial calibrations for the hw * @struct iwl_sensitivity_ranges: range of sensitivity values - * @first_ampdu_q: first HW queue available for ampdu */ struct iwl_hw_params { - u16 max_txq_num; + u8 max_txq_num; + u8 dma_chnl_num; + u16 scd_bc_tbls_size; u8 tx_chains_num; u8 rx_chains_num; u8 valid_tx_ant; @@ -549,22 +532,10 @@ struct iwl_hw_params { u32 max_data_size; u32 max_bsm_size; u32 ct_kill_threshold; /* value in hw-dependent units */ + u32 calib_init_cfg; const struct iwl_sensitivity_ranges *sens; - u8 first_ampdu_q; }; -#define HT_SHORT_GI_20MHZ (1 << 0) -#define HT_SHORT_GI_40MHZ (1 << 1) - - -#define IWL_RX_HDR(x) ((struct iwl4965_rx_frame_hdr *)(\ - x->u.rx_frame.stats.payload + \ - x->u.rx_frame.stats.phy_count)) -#define IWL_RX_END(x) ((struct iwl4965_rx_frame_end *)(\ - IWL_RX_HDR(x)->payload + \ - le16_to_cpu(IWL_RX_HDR(x)->len))) -#define IWL_RX_STATS(x) (&x->u.rx_frame.stats) -#define IWL_RX_DATA(x) (IWL_RX_HDR(x)->payload) /****************************************************************************** * @@ -581,13 +552,8 @@ struct iwl_hw_params { * iwl4965_mac_ <-- mac80211 callback * ****************************************************************************/ -struct iwl_addsta_cmd; -extern int iwl_send_add_sta(struct iwl_priv *priv, - struct iwl_addsta_cmd *sta, u8 flags); -extern u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, - int is_ap, u8 flags, struct ieee80211_ht_info *ht_info); -extern void iwl4965_update_chain_flags(struct iwl_priv *priv); -extern int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src); +extern void iwl_update_chain_flags(struct iwl_priv *priv); +extern int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src); extern const u8 iwl_bcast_addr[ETH_ALEN]; extern int iwl_rxq_stop(struct iwl_priv *priv); extern void iwl_txq_ctx_stop(struct iwl_priv *priv); @@ -611,19 +577,15 @@ static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge) } -struct iwl_priv; - - -/* Structures, enum, and defines specific to the 4965 */ - -#define IWL_KW_SIZE 0x1000 /*4k */ - -struct iwl_kw { - dma_addr_t dma_addr; - void *v_addr; +struct iwl_dma_ptr { + dma_addr_t dma; + void *addr; size_t size; }; +#define HT_SHORT_GI_20MHZ (1 << 0) +#define HT_SHORT_GI_40MHZ (1 << 1) + #define IWL_CHANNEL_WIDTH_20MHZ 0 #define IWL_CHANNEL_WIDTH_40MHZ 1 @@ -638,7 +600,6 @@ struct iwl_kw { #define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000 /* Sensitivity and chain noise calibration */ -#define INTERFERENCE_DATA_AVAILABLE __constant_cpu_to_le32(1) #define INITIALIZATION_VALUE 0xFFFF #define CAL_NUM_OF_BEACONS 20 #define MAXIMUM_ALLOWED_PATHLOSS 15 @@ -691,13 +652,20 @@ enum iwl4965_calib_enabled_state { IWL_CALIB_ENABLED = 1, }; -struct statistics_general_data { - u32 beacon_silence_rssi_a; - u32 beacon_silence_rssi_b; - u32 beacon_silence_rssi_c; - u32 beacon_energy_a; - u32 beacon_energy_b; - u32 beacon_energy_c; + +/* + * enum iwl_calib + * defines the order in which results of initial calibrations + * should be sent to the runtime uCode + */ +enum iwl_calib { + IWL_CALIB_XTAL, + IWL_CALIB_DC, + IWL_CALIB_LO, + IWL_CALIB_TX_IQ, + IWL_CALIB_TX_IQ_PERD, + IWL_CALIB_BASE_BAND, + IWL_CALIB_MAX }; /* Opaque calibration results */ @@ -766,7 +734,6 @@ enum { #define IWL_MAX_NUM_QUEUES 20 /* FIXME: do dynamic allocation */ -#define IWL_CALIB_MAX 3 struct iwl_priv { @@ -790,7 +757,7 @@ struct iwl_priv { #ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT /* spectrum measurement report caching */ - struct iwl4965_spectrum_notification measure_report; + struct iwl_spectrum_notification measure_report; u8 measurement_status; #endif /* ucode beacon time */ @@ -801,10 +768,6 @@ struct iwl_priv { struct iwl_channel_info *channel_info; /* channel info array */ u8 channel_count; /* # of channels */ - /* each calibration channel group in the EEPROM has a derived - * clip setting for each rate. */ - const struct iwl4965_clip_group clip_groups[5]; - /* thermal calibration */ s32 temperature; /* degrees Kelvin */ s32 last_temperature; @@ -818,12 +781,13 @@ struct iwl_priv { unsigned long scan_start; unsigned long scan_pass_start; unsigned long scan_start_tsf; + struct iwl_scan_cmd *scan; int scan_bands; int one_direct_scan; u8 direct_ssid_len; u8 direct_ssid[IW_ESSID_MAX_SIZE]; - struct iwl_scan_cmd *scan; - u32 scan_tx_ant[IEEE80211_NUM_BANDS]; + u8 scan_tx_ant[IEEE80211_NUM_BANDS]; + u8 mgmt_tx_ant; /* spinlock */ spinlock_t lock; /* protect general shared data */ @@ -840,6 +804,8 @@ struct iwl_priv { u8 rev_id; /* uCode images, save to reload in case of failure */ + u32 ucode_ver; /* version of ucode, copy of + iwl_ucode.ver */ struct fw_desc ucode_code; /* runtime inst */ struct fw_desc ucode_data; /* runtime data original */ struct fw_desc ucode_data_backup; /* runtime data save/restore */ @@ -850,7 +816,7 @@ struct iwl_priv { u8 ucode_write_complete; /* the image write is complete */ - struct iwl4965_rxon_time_cmd rxon_timing; + struct iwl_rxon_time_cmd rxon_timing; /* We declare this const so it can only be * changed via explicit cast within the @@ -882,7 +848,6 @@ struct iwl_priv { u16 active_rate_basic; u8 assoc_station_added; - u8 use_ant_b_for_management_frame; /* Tx antenna selection */ u8 start_calib; struct iwl_sensitivity_data sensitivity_data; struct iwl_chain_noise_data chain_noise_data; @@ -903,12 +868,14 @@ struct iwl_priv { struct iwl_rx_queue rxq; struct iwl_tx_queue txq[IWL_MAX_NUM_QUEUES]; unsigned long txq_ctx_active_msk; - struct iwl_kw kw; /* keep warm address */ + struct iwl_dma_ptr kw; /* keep warm address */ + struct iwl_dma_ptr scd_bc_tbls; + u32 scd_base_addr; /* scheduler sram base address */ unsigned long status; - int last_rx_rssi; /* From Rx packet statisitics */ + int last_rx_rssi; /* From Rx packet statistics */ int last_rx_noise; /* From beacon statistics */ /* counts mgmt, ctl, and data packets */ @@ -923,8 +890,6 @@ struct iwl_priv { unsigned long last_statistics_time; /* context information */ - u8 essid[IW_ESSID_MAX_SIZE]; - u8 essid_len; u16 rates_mask; u32 power_mode; @@ -965,11 +930,7 @@ struct iwl_priv { struct ieee80211_vif *vif; struct iwl_hw_params hw_params; - /* driver/uCode shared Tx Byte Counts and Rx status */ - void *shared_virt; - int rb_closed_offset; - /* Physical Pointer to Tx Byte Counts and Rx status */ - dma_addr_t shared_phys; + /* Current association information needed to configure the * hardware */ @@ -992,7 +953,6 @@ struct iwl_priv { struct work_struct report_work; struct work_struct request_scan; struct work_struct beacon_update; - struct work_struct set_monitor; struct tasklet_struct irq_tasklet; @@ -1004,9 +964,6 @@ struct iwl_priv { s8 tx_power_user_lmt; s8 tx_power_channel_lmt; -#ifdef CONFIG_PM - u32 pm_state[16]; -#endif #ifdef CONFIG_IWLWIFI_DEBUG /* debugging info */ @@ -1091,26 +1048,4 @@ static inline int is_channel_ibss(const struct iwl_channel_info *ch) return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0; } -#ifdef CONFIG_IWLWIFI_DEBUG -static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level, - void *p, u32 len) -{ - if (!(priv->debug_level & level)) - return; - - print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1, - p, len, 1); -} -#else -static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level, - void *p, u32 len) -{ -} -#endif - -extern const struct iwl_channel_info *iwl_get_channel_info( - const struct iwl_priv *priv, enum ieee80211_band band, u16 channel); - -/* Requires full declaration of iwl_priv before including */ - #endif /* __iwl_dev_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 37155755efc596bb51d3dc395374bf40a533b086..ce2f47306cea3bce863d7a87de4728d629c5c664 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * Tomas Winkler + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -169,10 +169,9 @@ int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv) CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); /* See if we got it */ - ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, - CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, - EEPROM_SEM_TIMEOUT); + ret = iwl_poll_direct_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, + EEPROM_SEM_TIMEOUT); if (ret >= 0) { IWL_DEBUG_IO("Acquired semaphore after %d tries.\n", count+1); @@ -210,10 +209,8 @@ int iwl_eeprom_init(struct iwl_priv *priv) { u16 *e; u32 gp = iwl_read32(priv, CSR_EEPROM_GP); - u32 r; int sz = priv->cfg->eeprom_size; int ret; - int i; u16 addr; /* allocate eeprom */ @@ -241,22 +238,19 @@ int iwl_eeprom_init(struct iwl_priv *priv) /* eeprom is an array of 16bit values */ for (addr = 0; addr < sz; addr += sizeof(u16)) { - _iwl_write32(priv, CSR_EEPROM_REG, addr << 1); - _iwl_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD); - - for (i = 0; i < IWL_EEPROM_ACCESS_TIMEOUT; - i += IWL_EEPROM_ACCESS_DELAY) { - r = _iwl_read_direct32(priv, CSR_EEPROM_REG); - if (r & CSR_EEPROM_REG_READ_VALID_MSK) - break; - udelay(IWL_EEPROM_ACCESS_DELAY); - } + u32 r; + + _iwl_write32(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); - if (!(r & CSR_EEPROM_REG_READ_VALID_MSK)) { + ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_READ_VALID_MSK, + IWL_EEPROM_ACCESS_TIMEOUT); + if (ret < 0) { IWL_ERROR("Time out reading EEPROM[%d]\n", addr); - ret = -ETIMEDOUT; goto done; } + r = _iwl_read_direct32(priv, CSR_EEPROM_REG); e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16)); } ret = 0; @@ -279,7 +273,23 @@ EXPORT_SYMBOL(iwl_eeprom_free); int iwl_eeprom_check_version(struct iwl_priv *priv) { - return priv->cfg->ops->lib->eeprom_ops.check_version(priv); + u16 eeprom_ver; + u16 calib_ver; + + eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); + calib_ver = priv->cfg->ops->lib->eeprom_ops.calib_version(priv); + + if (eeprom_ver < priv->cfg->eeprom_ver || + calib_ver < priv->cfg->eeprom_calib_ver) + goto err; + + return 0; +err: + IWL_ERROR("Unsupported EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n", + eeprom_ver, priv->cfg->eeprom_ver, + calib_ver, priv->cfg->eeprom_calib_ver); + return -EINVAL; + } EXPORT_SYMBOL(iwl_eeprom_check_version); diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index d3a2a5b4ac56214f4127c4a6456650e0f6fc82b6..603c84bed6300b2e195082377c242f48b4a90930 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * Tomas Winkler + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -68,17 +68,14 @@ struct iwl_priv; /* * EEPROM access time values: * - * Driver initiates EEPROM read by writing byte address << 1 to CSR_EEPROM_REG, - * then clearing (with subsequent read/modify/write) CSR_EEPROM_REG bit - * CSR_EEPROM_REG_BIT_CMD (0x2). + * Driver initiates EEPROM read by writing byte address << 1 to CSR_EEPROM_REG. * Driver then polls CSR_EEPROM_REG for CSR_EEPROM_REG_READ_VALID_MSK (0x1). * When polling, wait 10 uSec between polling loops, up to a maximum 5000 uSec. * Driver reads 16-bit value from bits 31-16 of CSR_EEPROM_REG. */ #define IWL_EEPROM_ACCESS_TIMEOUT 5000 /* uSec */ -#define IWL_EEPROM_ACCESS_DELAY 10 /* uSec */ -#define IWL_EEPROM_SEM_TIMEOUT 10 /* milliseconds */ +#define IWL_EEPROM_SEM_TIMEOUT 10 /* microseconds */ #define IWL_EEPROM_SEM_RETRY_LIMIT 1000 /* number of attempts (not time) */ @@ -147,6 +144,7 @@ struct iwl_eeprom_channel { /*5000 calibrations */ #define EEPROM_5000_CALIB_ALL (INDIRECT_ADDRESS | INDIRECT_CALIBRATION) #define EEPROM_5000_XTAL ((2*0x128) | EEPROM_5000_CALIB_ALL) +#define EEPROM_5000_TEMPERATURE ((2*0x12A) | EEPROM_5000_CALIB_ALL) /* 5000 links */ #define EEPROM_5000_LINK_HOST (2*0x64) @@ -174,6 +172,9 @@ struct iwl_eeprom_channel { #define EEPROM_5000_REG_BAND_52_FAT_CHANNELS ((0x92)\ | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 22 bytes */ +/* 5050 Specific */ +#define EEPROM_5050_TX_POWER_VERSION (4) +#define EEPROM_5050_EEPROM_VERSION (0x21E) /* 2.4 GHz */ extern const u8 iwl_eeprom_band_1[14]; @@ -371,7 +372,7 @@ struct iwl_eeprom_ops { int (*verify_signature) (struct iwl_priv *priv); int (*acquire_semaphore) (struct iwl_priv *priv); void (*release_semaphore) (struct iwl_priv *priv); - int (*check_version) (struct iwl_priv *priv); + u16 (*calib_version) (struct iwl_priv *priv); const u8* (*query_addr) (const struct iwl_priv *priv, size_t offset); }; diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index a72efdf6d1dd20160f5bf1526717007615ad875e..d7da1986455092ac6b5cfe47582630f436caeffb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -60,6 +60,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *****************************************************************************/ +#ifndef __iwl_fh_h__ +#define __iwl_fh_h__ /****************************/ /* Flow Handler Definitions */ @@ -70,7 +72,7 @@ * Addresses are offsets from device's PCI hardware base address. */ #define FH_MEM_LOWER_BOUND (0x1000) -#define FH_MEM_UPPER_BOUND (0x1EF0) +#define FH_MEM_UPPER_BOUND (0x2000) /** * Keep-Warm (KW) buffer base address. @@ -264,6 +266,7 @@ #define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_NO_INT_VAL (0x00000000) #define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL (0x00001000) +#define FH_RSCSR_FRAME_SIZE_MSK (0x00003FFF) /* bits 0-13 */ /** * Rx Shared Status Registers (RSSR) @@ -290,6 +293,13 @@ #define FH_MEM_TFDIB_REG1_ADDR_BITSHIFT 28 +/* TFDB Area - TFDs buffer table */ +#define FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK (0xFFFFFFFF) +#define FH_TFDIB_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0x900) +#define FH_TFDIB_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0x958) +#define FH_TFDIB_CTRL0_REG(_chnl) (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl)) +#define FH_TFDIB_CTRL1_REG(_chnl) (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl) + 0x4) + /** * Transmit DMA Channel Control/Status Registers (TCSR) * @@ -316,34 +326,41 @@ #define FH_TCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xE60) /* Find Control/Status reg for given Tx DMA/FIFO channel */ -#define FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \ - (FH_TCSR_LOWER_BOUND + 0x20 * _chnl) +#define FH49_TCSR_CHNL_NUM (7) +#define FH50_TCSR_CHNL_NUM (8) + +/* TCSR: tx_config register values */ +#define FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \ + (FH_TCSR_LOWER_BOUND + 0x20 * (_chnl)) +#define FH_TCSR_CHNL_TX_CREDIT_REG(_chnl) \ + (FH_TCSR_LOWER_BOUND + 0x20 * (_chnl) + 0x4) +#define FH_TCSR_CHNL_TX_BUF_STS_REG(_chnl) \ + (FH_TCSR_LOWER_BOUND + 0x20 * (_chnl) + 0x8) + +#define FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF (0x00000000) +#define FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_DRV (0x00000001) -#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL (0x00000000) -#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL (0x00000008) +#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE (0x00000000) +#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE (0x00000008) -#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE (0x00000000) -#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE_EOF (0x40000000) -#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE (0x80000000) +#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_NOINT (0x00000000) +#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD (0x00100000) +#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD (0x00200000) -#define FH_TCSR_CHNL_NUM (7) +#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT (0x00000000) +#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_ENDTFD (0x00400000) +#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_IFTFD (0x00800000) -#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_EMPTY (0x00000000) -#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_WAIT (0x00002000) -#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID (0x00000003) +#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE (0x00000000) +#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE_EOF (0x40000000) +#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE (0x80000000) -#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_NOINT (0x00000000) -#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD (0x00100000) -#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD (0x00200000) +#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_EMPTY (0x00000000) +#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_WAIT (0x00002000) +#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID (0x00000003) -#define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM (20) -#define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX (12) -#define FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \ - (FH_TCSR_LOWER_BOUND + 0x20 * _chnl) -#define FH_TCSR_CHNL_TX_CREDIT_REG(_chnl) \ - (FH_TCSR_LOWER_BOUND + 0x20 * _chnl + 0x4) -#define FH_TCSR_CHNL_TX_BUF_STS_REG(_chnl) \ - (FH_TCSR_LOWER_BOUND + 0x20 * _chnl + 0x8) +#define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM (20) +#define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX (12) /** * Tx Shared Status Registers (TSSR) @@ -360,7 +377,7 @@ #define FH_TSSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xEA0) #define FH_TSSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xEC0) -#define FH_TSSR_TX_STATUS_REG (FH_TSSR_LOWER_BOUND + 0x010) +#define FH_TSSR_TX_STATUS_REG (FH_TSSR_LOWER_BOUND + 0x010) #define FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) ((1 << (_chnl)) << 24) #define FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl) ((1 << (_chnl)) << 16) @@ -369,25 +386,99 @@ (FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) | \ FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl)) - - -#define FH_REGS_LOWER_BOUND (0x1000) -#define FH_REGS_UPPER_BOUND (0x2000) - /* Tx service channels */ -#define FH_SRVC_CHNL (9) -#define FH_SRVC_LOWER_BOUND (FH_REGS_LOWER_BOUND + 0x9C8) -#define FH_SRVC_UPPER_BOUND (FH_REGS_LOWER_BOUND + 0x9D0) +#define FH_SRVC_CHNL (9) +#define FH_SRVC_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0x9C8) +#define FH_SRVC_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0x9D0) #define FH_SRVC_CHNL_SRAM_ADDR_REG(_chnl) \ (FH_SRVC_LOWER_BOUND + ((_chnl) - 9) * 0x4) -/* TFDB Area - TFDs buffer table */ -#define FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK (0xFFFFFFFF) -#define FH_TFDIB_LOWER_BOUND (FH_REGS_LOWER_BOUND + 0x900) -#define FH_TFDIB_UPPER_BOUND (FH_REGS_LOWER_BOUND + 0x958) -#define FH_TFDIB_CTRL0_REG(_chnl) (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl)) -#define FH_TFDIB_CTRL1_REG(_chnl) (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl) + 0x4) +#define FH_TX_CHICKEN_BITS_REG (FH_MEM_LOWER_BOUND + 0xE98) +/* Instruct FH to increment the retry count of a packet when + * it is brought from the memory to TX-FIFO + */ +#define FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN (0x00000002) -/* TCSR: tx_config register values */ -#define FH_RSCSR_FRAME_SIZE_MSK (0x00003FFF) /* bits 0-13 */ +/** + * struct iwl_rb_status - reseve buffer status + * host memory mapped FH registers + * @closed_rb_num [0:11] - Indicates the index of the RB which was closed + * @closed_fr_num [0:11] - Indicates the index of the RX Frame which was closed + * @finished_rb_num [0:11] - Indicates the index of the current RB + * in which the last frame was written to + * @finished_fr_num [0:11] - Indicates the index of the RX Frame + * which was transfered + */ +struct iwl_rb_status { + __le16 closed_rb_num; + __le16 closed_fr_num; + __le16 finished_rb_num; + __le16 finished_fr_nam; +} __attribute__ ((packed)); + + +#define TFD_QUEUE_SIZE_MAX (256) +#define TFD_QUEUE_SIZE_BC_DUP (64) +#define TFD_QUEUE_BC_SIZE (TFD_QUEUE_SIZE_MAX + TFD_QUEUE_SIZE_BC_DUP) +#define IWL_TX_DMA_MASK DMA_BIT_MASK(36) +#define IWL_NUM_OF_TBS 20 + +static inline u8 iwl_get_dma_hi_addr(dma_addr_t addr) +{ + return (sizeof(addr) > sizeof(u32) ? (addr >> 16) >> 16 : 0) & 0xF; +} +/** + * struct iwl_tfd_tb transmit buffer descriptor within transmit frame descriptor + * + * This structure contains dma address and length of transmission address + * + * @lo: low [31:0] portion of the dma address of TX buffer + * every even is unaligned on 16 bit boundary + * @hi_n_len 0-3 [35:32] portion of dma + * 4-15 length of the tx buffer + */ +struct iwl_tfd_tb { + __le32 lo; + __le16 hi_n_len; +} __attribute__((packed)); + +/** + * struct iwl_tfd + * + * Transmit Frame Descriptor (TFD) + * + * @ __reserved1[3] reserved + * @ num_tbs 0-4 number of active tbs + * 5 reserved + * 6-7 padding (not used) + * @ tbs[20] transmit frame buffer descriptors + * @ __pad padding + * + * Each Tx queue uses a circular buffer of 256 TFDs stored in host DRAM. + * Both driver and device share these circular buffers, each of which must be + * contiguous 256 TFDs x 128 bytes-per-TFD = 32 KBytes + * + * Driver must indicate the physical address of the base of each + * circular buffer via the FH_MEM_CBBC_QUEUE registers. + * + * Each TFD contains pointer/size information for up to 20 data buffers + * in host DRAM. These buffers collectively contain the (one) frame described + * by the TFD. Each buffer must be a single contiguous block of memory within + * itself, but buffers may be scattered in host DRAM. Each buffer has max size + * of (4K - 4). The concatenates all of a TFD's buffers into a single + * Tx frame, up to 8 KBytes in size. + * + * A maximum of 255 (not 256!) TFDs may be on a queue waiting for Tx. + */ +struct iwl_tfd { + u8 __reserved1[3]; + u8 num_tbs; + struct iwl_tfd_tb tbs[IWL_NUM_OF_TBS]; + __le32 __pad; +} __attribute__ ((packed)); + + +/* Keep Warm Size */ +#define IWL_KW_SIZE 0x1000 /* 4k */ +#endif /* !__iwl_fh_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index 8300f3d00a0691ff52d5d65c0340779c28b9128a..01a2169cececb1dc7abbed3d2bf8b41ece10d3d3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -22,7 +22,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * Tomas Winkler + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *****************************************************************************/ @@ -36,7 +36,7 @@ #include "iwl-core.h" -#define IWL_CMD(x) case x : return #x +#define IWL_CMD(x) case x: return #x const char *get_cmd_string(u8 cmd) { diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h index 41eed67933289c6f732dfd08892a229cd369d8ef..ca4f638ab9d0e8f4cd7b26712191c5162961d166 100644 --- a/drivers/net/wireless/iwlwifi/iwl-helpers.h +++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -32,110 +32,6 @@ #include -/* - * The structures defined by the hardware/uCode interface - * have bit-wise operations. For each bit-field there is - * a data symbol in the structure, the start bit position - * and the length of the bit-field. - * - * iwl_get_bits and iwl_set_bits will return or set the - * appropriate bits on a 32-bit value. - * - * IWL_GET_BITS and IWL_SET_BITS use symbol expansion to - * expand out to the appropriate call to iwl_get_bits - * and iwl_set_bits without having to reference all of the - * numerical constants and defines provided in the hardware - * definition - */ - -/** - * iwl_get_bits - Extract a hardware bit-field value - * @src: source hardware value (__le32) - * @pos: bit-position (0-based) of first bit of value - * @len: length of bit-field - * - * iwl_get_bits will return the bit-field in cpu endian ordering. - * - * NOTE: If used from IWL_GET_BITS then pos and len are compile-constants and - * will collapse to minimal code by the compiler. - */ -static inline u32 iwl_get_bits(__le32 src, u8 pos, u8 len) -{ - u32 tmp = le32_to_cpu(src); - - tmp >>= pos; - tmp &= (1UL << len) - 1; - return tmp; -} - -/** - * iwl_set_bits - Set a hardware bit-field value - * @dst: Address of __le32 hardware value - * @pos: bit-position (0-based) of first bit of value - * @len: length of bit-field - * @val: cpu endian value to encode into the bit-field - * - * iwl_set_bits will encode val into dst, masked to be len bits long at bit - * position pos. - * - * NOTE: If used IWL_SET_BITS pos and len will be compile-constants and - * will collapse to minimal code by the compiler. - */ -static inline void iwl_set_bits(__le32 *dst, u8 pos, u8 len, int val) -{ - u32 tmp = le32_to_cpu(*dst); - - tmp &= ~(((1UL << len) - 1) << pos); - tmp |= (val & ((1UL << len) - 1)) << pos; - *dst = cpu_to_le32(tmp); -} - -static inline void iwl_set_bits16(__le16 *dst, u8 pos, u8 len, int val) -{ - u16 tmp = le16_to_cpu(*dst); - - tmp &= ~((1UL << (pos + len)) - (1UL << pos)); - tmp |= (val & ((1UL << len) - 1)) << pos; - *dst = cpu_to_le16(tmp); -} - -/* - * The bit-field definitions in iwl-xxxx-hw.h are in the form of: - * - * struct example { - * __le32 val1; - * #define IWL_name_POS 8 - * #define IWL_name_LEN 4 - * #define IWL_name_SYM val1 - * }; - * - * The IWL_SET_BITS and IWL_GET_BITS macros are provided to allow the driver - * to call: - * - * struct example bar; - * u32 val = IWL_GET_BITS(bar, name); - * val = val * 2; - * IWL_SET_BITS(bar, name, val); - * - * All cpu / host ordering, masking, and shifts are performed by the macros - * and iwl_{get,set}_bits. - * - */ -#define IWL_SET_BITS(s, sym, v) \ - iwl_set_bits(&(s).IWL_ ## sym ## _SYM, IWL_ ## sym ## _POS, \ - IWL_ ## sym ## _LEN, (v)) - -#define IWL_SET_BITS16(s, sym, v) \ - iwl_set_bits16(&(s).IWL_ ## sym ## _SYM, IWL_ ## sym ## _POS, \ - IWL_ ## sym ## _LEN, (v)) - -#define IWL_GET_BITS(s, sym) \ - iwl_get_bits((s).IWL_ ## sym ## _SYM, IWL_ ## sym ## _POS, \ - IWL_ ## sym ## _LEN) - - -#define KELVIN_TO_CELSIUS(x) ((x)-273) -#define CELSIUS_TO_KELVIN(x) ((x)+273) #define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo)))) @@ -159,11 +55,6 @@ static inline unsigned long elapsed_jiffies(unsigned long start, return end + (MAX_JIFFY_OFFSET - start) + 1; } -static inline u8 iwl_get_dma_hi_address(dma_addr_t addr) -{ - return sizeof(addr) > sizeof(u32) ? (addr >> 16) >> 16 : 0; -} - /** * iwl_queue_inc_wrap - increment queue index, wrap back to beginning * @index -- current index diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index 9740fcc1805e7eb27f99ed6fd3ccd711aadcccf2..0a92e7431adaa023cc6a6916cdf454406c0ca6fc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -21,7 +21,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -55,7 +55,7 @@ * _iwl_read32.) * * These declarations are *extremely* useful in quickly isolating code deltas - * which result in misconfiguring of the hardware I/O. In combination with + * which result in misconfiguration of the hardware I/O. In combination with * git-bisect and the IO debug level you can quickly determine the specific * commit which breaks the IO sequence to the hardware. * @@ -87,17 +87,18 @@ static inline u32 __iwl_read32(char *f, u32 l, struct iwl_priv *priv, u32 ofs) #define iwl_read32(p, o) _iwl_read32(p, o) #endif +#define IWL_POLL_INTERVAL 10 /* microseconds */ static inline int _iwl_poll_bit(struct iwl_priv *priv, u32 addr, u32 bits, u32 mask, int timeout) { - int i = 0; + int t = 0; do { if ((_iwl_read32(priv, addr) & mask) == (bits & mask)) - return i; - mdelay(10); - i += 10; - } while (i < timeout); + return t; + udelay(IWL_POLL_INTERVAL); + t += IWL_POLL_INTERVAL; + } while (t < timeout); return -ETIMEDOUT; } @@ -109,7 +110,7 @@ static inline int __iwl_poll_bit(const char *f, u32 l, int ret = _iwl_poll_bit(priv, addr, bits, mask, timeout); IWL_DEBUG_IO("poll_bit(0x%08X, 0x%08X, 0x%08X) - %s- %s %d\n", addr, bits, mask, - unlikely(ret == -ETIMEDOUT)?"timeout":"", f, l); + unlikely(ret == -ETIMEDOUT) ? "timeout" : "", f, l); return ret; } #define iwl_poll_bit(priv, addr, bits, mask, timeout) \ @@ -269,19 +270,10 @@ static inline void iwl_write_reg_buf(struct iwl_priv *priv, } } -static inline int _iwl_poll_direct_bit(struct iwl_priv *priv, - u32 addr, u32 mask, int timeout) +static inline int _iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, + u32 mask, int timeout) { - int i = 0; - - do { - if ((_iwl_read_direct32(priv, addr) & mask) == mask) - return i; - mdelay(10); - i += 10; - } while (i < timeout); - - return -ETIMEDOUT; + return _iwl_poll_bit(priv, addr, mask, mask, timeout); } #ifdef CONFIG_IWLWIFI_DEBUG @@ -308,6 +300,7 @@ static inline int __iwl_poll_direct_bit(const char *f, u32 l, static inline u32 _iwl_read_prph(struct iwl_priv *priv, u32 reg) { _iwl_write_direct32(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24)); + rmb(); return _iwl_read_direct32(priv, HBUS_TARG_PRPH_RDAT); } #ifdef CONFIG_IWLWIFI_DEBUG @@ -330,6 +323,7 @@ static inline void _iwl_write_prph(struct iwl_priv *priv, { _iwl_write_direct32(priv, HBUS_TARG_PRPH_WADDR, ((addr & 0x0000FFFF) | (3 << 24))); + wmb(); _iwl_write_direct32(priv, HBUS_TARG_PRPH_WDAT, val); } #ifdef CONFIG_IWLWIFI_DEBUG @@ -392,12 +386,14 @@ static inline void iwl_clear_bits_prph(struct iwl_priv static inline u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr) { iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, addr); + rmb(); return iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); } static inline void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val) { iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); + wmb(); iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, val); } @@ -405,6 +401,7 @@ static inline void iwl_write_targ_mem_buf(struct iwl_priv *priv, u32 addr, u32 len, u32 *values) { iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); + wmb(); for (; 0 < len; len -= sizeof(u32), values++) iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, *values); } diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 4eee1b163cd2c27115fa46ce95cc9cc0193011dc..11eccd7d268c2946cc13715ee93160314b8fa48a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -41,7 +41,6 @@ #include "iwl-dev.h" #include "iwl-core.h" #include "iwl-io.h" -#include "iwl-helpers.h" #ifdef CONFIG_IWLWIFI_DEBUG static const char *led_type_str[] = { @@ -278,7 +277,7 @@ static int iwl_get_blink_rate(struct iwl_priv *priv) /* FIXME: + priv->rx_stats[2].bytes; */ s64 tpt = current_tpt - priv->led_tpt; - if (tpt < 0) /* wrapparound */ + if (tpt < 0) /* wraparound */ tpt = -tpt; IWL_DEBUG_LED("tpt %lld current_tpt %llu\n", @@ -293,7 +292,7 @@ static int iwl_get_blink_rate(struct iwl_priv *priv) if (tpt > (blink_tbl[i].tpt * IWL_1MB_RATE)) break; - IWL_DEBUG_LED("LED BLINK IDX=%d", i); + IWL_DEBUG_LED("LED BLINK IDX=%d\n", i); return i; } diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h index 588c9ad20e83332d11ffbcce7e44aa9daef70e03..021e00bcd1be1af1fa3296875ae5cba2fbe42365 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.h +++ b/drivers/net/wireless/iwlwifi/iwl-led.h @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 60a03d2d2d0e451bc4f56a742b50b99d48a2b5dc..75ca6a542174fd9ef847697b96605ea00403088a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *****************************************************************************/ @@ -39,7 +39,6 @@ #include "iwl-commands.h" #include "iwl-debug.h" #include "iwl-power.h" -#include "iwl-helpers.h" /* * Setting power level allow the card to go to sleep when not busy @@ -80,7 +79,7 @@ #define IWL_REDUCED_POWER_TEMPERATURE 95 /* default power management (not Tx power) table values */ -/* for tim 0-10 */ +/* for TIM 0-10 */ static struct iwl_power_vec_entry range_0[IWL_POWER_MAX] = { {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, @@ -91,7 +90,7 @@ static struct iwl_power_vec_entry range_0[IWL_POWER_MAX] = { }; -/* for tim = 3-10 */ +/* for TIM = 3-10 */ static struct iwl_power_vec_entry range_1[IWL_POWER_MAX] = { {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0}, @@ -101,7 +100,7 @@ static struct iwl_power_vec_entry range_1[IWL_POWER_MAX] = { {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 7, 10, 10)}, 2} }; -/* for tim > 11 */ +/* for TIM > 11 */ static struct iwl_power_vec_entry range_2[IWL_POWER_MAX] = { {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0}, @@ -183,7 +182,7 @@ static int iwl_power_init_handle(struct iwl_priv *priv) return 0; } -/* adjust power command according to dtim period and power level*/ +/* adjust power command according to DTIM period and power level*/ static int iwl_update_power_command(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd, u16 mode) @@ -257,15 +256,11 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) struct iwl_power_mgr *setting = &(priv->power_data); int ret = 0; u16 uninitialized_var(final_mode); + bool update_chains; /* Don't update the RX chain when chain noise calibration is running */ - if (priv->chain_noise_data.state != IWL_CHAIN_NOISE_DONE && - priv->chain_noise_data.state != IWL_CHAIN_NOISE_ALIVE) { - IWL_DEBUG_POWER("Cannot update the power, chain noise " - "calibration running: %d\n", - priv->chain_noise_data.state); - return -EAGAIN; - } + update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE || + priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE; /* If on battery, set to 3, * if plugged into AC power, set to CAM ("continuously aware mode"), @@ -313,9 +308,12 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) else set_bit(STATUS_POWER_PMI, &priv->status); - if (priv->cfg->ops->lib->update_chain_flags) + if (priv->cfg->ops->lib->update_chain_flags && update_chains) priv->cfg->ops->lib->update_chain_flags(priv); - + else + IWL_DEBUG_POWER("Cannot update the power, chain noise " + "calibration running: %d\n", + priv->chain_noise_data.state); if (!ret) setting->power_mode = final_mode; } @@ -325,7 +323,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) EXPORT_SYMBOL(iwl_power_update_mode); /* Allow other iwl code to disable/enable power management active - * this will be usefull for rate scale to disable PM during heavy + * this will be useful for rate scale to disable PM during heavy * Tx/Rx activities */ int iwl_power_disable_management(struct iwl_priv *priv, u32 ms) @@ -352,8 +350,8 @@ int iwl_power_disable_management(struct iwl_priv *priv, u32 ms) EXPORT_SYMBOL(iwl_power_disable_management); /* Allow other iwl code to disable/enable power management active - * this will be usefull for rate scale to disable PM during hight - * valume activities + * this will be useful for rate scale to disable PM during high + * volume activities */ int iwl_power_enable_management(struct iwl_priv *priv) { @@ -391,7 +389,7 @@ int iwl_power_set_system_mode(struct iwl_priv *priv, u16 mode) } EXPORT_SYMBOL(iwl_power_set_system_mode); -/* initilize to default */ +/* initialize to default */ void iwl_power_initialize(struct iwl_priv *priv) { @@ -443,7 +441,7 @@ static void iwl_bg_set_power_save(struct work_struct *work) mutex_lock(&priv->mutex); - /* on starting association we disable power managment + /* on starting association we disable power management * until association, if association failed then this * timer will expire and enable PM again. */ diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index df484a90ae64f521e798243ebb751eef2ffd0bf1..fa098d8975cec38d84161e51a1f5db3a9ea006ad 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *****************************************************************************/ #ifndef __iwl_power_setting_h__ diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index ee5afd48d3af035ed22527c29c1b98264216077d..b7a5f23351c303c994a835124d5add570bb99ec6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -158,9 +158,9 @@ * * 4) Point (via BSM_DRAM_*) to the "runtime" uCode data and instruction * images in host DRAM. The last register loaded must be the instruction - * bytecount register ("1" in MSbit tells initialization uCode to load + * byte count register ("1" in MSbit tells initialization uCode to load * the runtime uCode): - * BSM_DRAM_INST_BYTECOUNT_REG = bytecount | BSM_DRAM_INST_LOAD + * BSM_DRAM_INST_BYTECOUNT_REG = byte count | BSM_DRAM_INST_LOAD * * 5) Wait for "alive" notification, then issue normal runtime commands. * @@ -244,7 +244,7 @@ /** * Tx Scheduler * - * The Tx Scheduler selects the next frame to be transmitted, chosing TFDs + * The Tx Scheduler selects the next frame to be transmitted, choosing TFDs * (Transmit Frame Descriptors) from up to 16 circular Tx queues resident in * host DRAM. It steers each frame's Tx command (which contains the frame * data) into one of up to 7 prioritized Tx DMA FIFO channels within the diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.c b/drivers/net/wireless/iwlwifi/iwl-rfkill.c index 5d642298f04c33014c896e5cec97d143a38f1b66..4b69da30665c3b1bd74c93f0dd516aaf4e89809e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rfkill.c +++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.c @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *****************************************************************************/ #include @@ -34,8 +34,6 @@ #include "iwl-eeprom.h" #include "iwl-dev.h" #include "iwl-core.h" -#include "iwl-helpers.h" - /* software rf-kill from user */ static int iwl_rfkill_soft_rf_kill(void *data, enum rfkill_state state) @@ -64,7 +62,7 @@ static int iwl_rfkill_soft_rf_kill(void *data, enum rfkill_state state) iwl_radio_kill_sw_disable_radio(priv); break; default: - IWL_WARNING("we recieved unexpected RFKILL state %d\n", state); + IWL_WARNING("we received unexpected RFKILL state %d\n", state); break; } out_unlock: @@ -83,7 +81,7 @@ int iwl_rfkill_init(struct iwl_priv *priv) IWL_DEBUG_RF_KILL("Initializing RFKILL.\n"); priv->rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN); if (!priv->rfkill) { - IWL_ERROR("Unable to allocate rfkill device.\n"); + IWL_ERROR("Unable to allocate RFKILL device.\n"); ret = -ENOMEM; goto error; } @@ -99,7 +97,7 @@ int iwl_rfkill_init(struct iwl_priv *priv) ret = rfkill_register(priv->rfkill); if (ret) { - IWL_ERROR("Unable to register rfkill: %d\n", ret); + IWL_ERROR("Unable to register RFKILL: %d\n", ret); goto free_rfkill; } @@ -127,7 +125,7 @@ void iwl_rfkill_unregister(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_rfkill_unregister); -/* set rf-kill to the right state. */ +/* set RFKILL to the right state. */ void iwl_rfkill_set_hw_state(struct iwl_priv *priv) { if (!priv->rfkill) diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.h b/drivers/net/wireless/iwlwifi/iwl-rfkill.h index 402fd4c781dab6de6987fc0d8c184f07839a8f67..86dc055a2e9400cf684ea212935789309c6ffa60 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rfkill.h +++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.h @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *****************************************************************************/ #ifndef __iwl_rf_kill_h__ diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 0509c16dbe758b32e1a23db7da1a09100493b0c8..c5f1aa0feac8c49ecb635e44b7b89e1c98681158 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -218,8 +218,7 @@ int iwl_rx_queue_restock(struct iwl_priv *priv) /* If we've added more space for the firmware to place data, tell it. * Increment device's write pointer in multiples of 8. */ - if ((write != (rxq->write & ~0x7)) - || (abs(rxq->write - rxq->read) > 7)) { + if (write != (rxq->write & ~0x7)) { spin_lock_irqsave(&rxq->lock, flags); rxq->need_update = 1; spin_unlock_irqrestore(&rxq->lock, flags); @@ -245,25 +244,31 @@ void iwl_rx_allocate(struct iwl_priv *priv) struct list_head *element; struct iwl_rx_mem_buffer *rxb; unsigned long flags; - spin_lock_irqsave(&rxq->lock, flags); - while (!list_empty(&rxq->rx_used)) { + + while (1) { + spin_lock_irqsave(&rxq->lock, flags); + + if (list_empty(&rxq->rx_used)) { + spin_unlock_irqrestore(&rxq->lock, flags); + return; + } element = rxq->rx_used.next; rxb = list_entry(element, struct iwl_rx_mem_buffer, list); + list_del(element); + + spin_unlock_irqrestore(&rxq->lock, flags); /* Alloc a new receive buffer */ rxb->skb = alloc_skb(priv->hw_params.rx_buf_size + 256, - __GFP_NOWARN | GFP_ATOMIC); + GFP_KERNEL); if (!rxb->skb) { - if (net_ratelimit()) - printk(KERN_CRIT DRV_NAME - ": Can not allocate SKB buffers\n"); + printk(KERN_CRIT DRV_NAME + "Can not allocate SKB buffers\n"); /* We don't reschedule replenish work here -- we will * call the restock method and if it still needs * more buffers it will schedule replenish */ break; } - priv->alloc_rxb_skb++; - list_del(element); /* Get physical address of RB/SKB */ rxb->real_dma_addr = pci_map_single( @@ -277,12 +282,15 @@ void iwl_rx_allocate(struct iwl_priv *priv) rxb->aligned_dma_addr = ALIGN(rxb->real_dma_addr, 256); skb_reserve(rxb->skb, rxb->aligned_dma_addr - rxb->real_dma_addr); + spin_lock_irqsave(&rxq->lock, flags); + list_add_tail(&rxb->list, &rxq->rx_free); rxq->free_count++; + priv->alloc_rxb_skb++; + + spin_unlock_irqrestore(&rxq->lock, flags); } - spin_unlock_irqrestore(&rxq->lock, flags); } -EXPORT_SYMBOL(iwl_rx_allocate); void iwl_rx_replenish(struct iwl_priv *priv) { @@ -317,7 +325,10 @@ void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq) pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd, rxq->dma_addr); + pci_free_consistent(priv->pci_dev, sizeof(struct iwl_rb_status), + rxq->rb_stts, rxq->rb_stts_dma); rxq->bd = NULL; + rxq->rb_stts = NULL; } EXPORT_SYMBOL(iwl_rx_queue_free); @@ -334,7 +345,12 @@ int iwl_rx_queue_alloc(struct iwl_priv *priv) /* Alloc the circular buffer of Read Buffer Descriptors (RBDs) */ rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr); if (!rxq->bd) - return -ENOMEM; + goto err_bd; + + rxq->rb_stts = pci_alloc_consistent(dev, sizeof(struct iwl_rb_status), + &rxq->rb_stts_dma); + if (!rxq->rb_stts) + goto err_rb; /* Fill the rx_used queue with _all_ of the Rx buffers */ for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) @@ -346,6 +362,12 @@ int iwl_rx_queue_alloc(struct iwl_priv *priv) rxq->free_count = 0; rxq->need_update = 0; return 0; + +err_rb: + pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd, + rxq->dma_addr); +err_bd: + return -ENOMEM; } EXPORT_SYMBOL(iwl_rx_queue_alloc); @@ -412,10 +434,10 @@ int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) /* Tell device where in DRAM to update its Rx status */ iwl_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG, - (priv->shared_phys + priv->rb_closed_offset) >> 4); + rxq->rb_stts_dma >> 4); /* Enable Rx DMA - * FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set becuase of HW bug in + * FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set because of HW bug in * the credit mechanism in 5000 HW RX FIFO * Direct rx interrupts to hosts * Rx buffer size 4 or 8k @@ -426,6 +448,7 @@ int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL | FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY | FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL | + FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MSK | rb_size| (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)| (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS)); @@ -453,10 +476,8 @@ int iwl_rxq_stop(struct iwl_priv *priv) /* stop Rx DMA */ iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); - ret = iwl_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG, - (1 << 24), 1000); - if (ret < 0) - IWL_ERROR("Can't stop Rx DMA.\n"); + iwl_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG, + FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000); iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); @@ -470,7 +491,7 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, { struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - struct iwl4965_missed_beacon_notif *missed_beacon; + struct iwl_missed_beacon_notif *missed_beacon; missed_beacon = &pkt->u.missed_beacon; if (le32_to_cpu(missed_beacon->consequtive_missed_beacons) > 5) { @@ -485,49 +506,6 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, } EXPORT_SYMBOL(iwl_rx_missed_beacon_notif); -int iwl_rx_agg_start(struct iwl_priv *priv, const u8 *addr, int tid, u16 ssn) -{ - unsigned long flags; - int sta_id; - - sta_id = iwl_find_station(priv, addr); - if (sta_id == IWL_INVALID_STATION) - return -ENXIO; - - spin_lock_irqsave(&priv->sta_lock, flags); - priv->stations[sta_id].sta.station_flags_msk = 0; - priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK; - priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid; - priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn); - priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; - spin_unlock_irqrestore(&priv->sta_lock, flags); - - return iwl_send_add_sta(priv, &priv->stations[sta_id].sta, - CMD_ASYNC); -} -EXPORT_SYMBOL(iwl_rx_agg_start); - -int iwl_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid) -{ - unsigned long flags; - int sta_id; - - sta_id = iwl_find_station(priv, addr); - if (sta_id == IWL_INVALID_STATION) - return -ENXIO; - - spin_lock_irqsave(&priv->sta_lock, flags); - priv->stations[sta_id].sta.station_flags_msk = 0; - priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK; - priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid; - priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; - spin_unlock_irqrestore(&priv->sta_lock, flags); - - return iwl_send_add_sta(priv, &priv->stations[sta_id].sta, - CMD_ASYNC); -} -EXPORT_SYMBOL(iwl_rx_agg_stop); - /* Calculate noise level, based on measurements during network silence just * before arriving beacon. This measurement can be done only if we know @@ -651,20 +629,24 @@ static int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm) return sig_qual; } -#ifdef CONFIG_IWLWIFI_DEBUG +/* Calc max signal level (dBm) among 3 possible receivers */ +static inline int iwl_calc_rssi(struct iwl_priv *priv, + struct iwl_rx_phy_res *rx_resp) +{ + return priv->cfg->ops->utils->calc_rssi(priv, rx_resp); +} +#ifdef CONFIG_IWLWIFI_DEBUG /** * iwl_dbg_report_frame - dump frame to syslog during debug sessions * * You may hack this function to show different aspects of received frames, * including selective frame dumps. - * group100 parameter selects whether to show 1 out of 100 good frames. - * - * TODO: This was originally written for 3945, need to audit for - * proper operation with 4965. + * group100 parameter selects whether to show 1 out of 100 good data frames. + * All beacon and probe response frames are printed. */ static void iwl_dbg_report_frame(struct iwl_priv *priv, - struct iwl_rx_packet *pkt, + struct iwl_rx_phy_res *phy_res, u16 length, struct ieee80211_hdr *header, int group100) { u32 to_us; @@ -676,20 +658,9 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv, u16 seq_ctl; u16 channel; u16 phy_flags; - int rate_sym; - u16 length; - u16 status; - u16 bcn_tmr; + u32 rate_n_flags; u32 tsf_low; - u64 tsf; - u8 rssi; - u8 agc; - u16 sig_avg; - u16 noise_diff; - struct iwl4965_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); - struct iwl4965_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); - struct iwl4965_rx_frame_end *rx_end = IWL_RX_END(pkt); - u8 *data = IWL_RX_DATA(pkt); + int rssi; if (likely(!(priv->debug_level & IWL_DL_RX))) return; @@ -699,22 +670,13 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv, seq_ctl = le16_to_cpu(header->seq_ctrl); /* metadata */ - channel = le16_to_cpu(rx_hdr->channel); - phy_flags = le16_to_cpu(rx_hdr->phy_flags); - rate_sym = rx_hdr->rate; - length = le16_to_cpu(rx_hdr->len); - - /* end-of-frame status and timestamp */ - status = le32_to_cpu(rx_end->status); - bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp); - tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff; - tsf = le64_to_cpu(rx_end->timestamp); + channel = le16_to_cpu(phy_res->channel); + phy_flags = le16_to_cpu(phy_res->phy_flags); + rate_n_flags = le32_to_cpu(phy_res->rate_n_flags); /* signal statistics */ - rssi = rx_stats->rssi; - agc = rx_stats->agc; - sig_avg = le16_to_cpu(rx_stats->sig_avg); - noise_diff = le16_to_cpu(rx_stats->noise_diff); + rssi = iwl_calc_rssi(priv, phy_res); + tsf_low = le64_to_cpu(phy_res->timestamp) & 0x0ffffffff; to_us = !compare_ether_addr(header->addr1, priv->mac_addr); @@ -768,11 +730,13 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv, else title = "Frame"; - rate_idx = iwl_hwrate_to_plcp_idx(rate_sym); - if (unlikely(rate_idx == -1)) + rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags); + if (unlikely((rate_idx < 0) || (rate_idx >= IWL_RATE_COUNT))) { bitrate = 0; - else + WARN_ON_ONCE(1); + } else { bitrate = iwl_rates[rate_idx].ieee / 2; + } /* print frame summary. * MAC addresses show just the last byte (for brevity), @@ -784,24 +748,17 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv, length, rssi, channel, bitrate); else { /* src/dst addresses assume managed mode */ - IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, " - "src=0x%02x, rssi=%u, tim=%lu usec, " + IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, src=0x%02x, " + "len=%u, rssi=%d, tim=%lu usec, " "phy=0x%02x, chnl=%d\n", title, le16_to_cpu(fc), header->addr1[5], - header->addr3[5], rssi, + header->addr3[5], length, rssi, tsf_low - priv->scan_start_tsf, phy_flags, channel); } } if (print_dump) - iwl_print_hex_dump(priv, IWL_DL_RX, data, length); -} -#else -static inline void iwl_dbg_report_frame(struct iwl_priv *priv, - struct iwl_rx_packet *pkt, - struct ieee80211_hdr *header, - int group100) -{ + iwl_print_hex_dump(priv, IWL_DL_RX, header, length); } #endif @@ -995,46 +952,6 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, rxb->skb = NULL; } -/* Calc max signal level (dBm) among 3 possible receivers */ -static inline int iwl_calc_rssi(struct iwl_priv *priv, - struct iwl_rx_phy_res *rx_resp) -{ - return priv->cfg->ops->utils->calc_rssi(priv, rx_resp); -} - - -static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) -{ - unsigned long flags; - - spin_lock_irqsave(&priv->sta_lock, flags); - priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK; - priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK; - priv->stations[sta_id].sta.sta.modify_mask = 0; - priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; - spin_unlock_irqrestore(&priv->sta_lock, flags); - - iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); -} - -static void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr) -{ - /* FIXME: need locking over ps_status ??? */ - u8 sta_id = iwl_find_station(priv, addr); - - if (sta_id != IWL_INVALID_STATION) { - u8 sta_awake = priv->stations[sta_id]. - ps_status == STA_PS_STATUS_WAKE; - - if (sta_awake && ps_bit) - priv->stations[sta_id].ps_status = STA_PS_STATUS_SLEEP; - else if (!sta_awake && !ps_bit) { - iwl_sta_modify_ps_wake(priv, sta_id); - priv->stations[sta_id].ps_status = STA_PS_STATUS_WAKE; - } - } -} - /* This is necessary only for a number of statistics, see the caller. */ static int iwl_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) @@ -1157,9 +1074,10 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; /* Set "1" to report good data frames in groups of 100 */ - /* FIXME: need to optimze the call: */ - iwl_dbg_report_frame(priv, pkt, header, 1); - +#ifdef CONFIG_IWLWIFI_DEBUG + if (unlikely(priv->debug_level & IWL_DL_RX)) + iwl_dbg_report_frame(priv, rx_start, len, header, 1); +#endif IWL_DEBUG_STATS_LIMIT("Rssi %d, noise %d, qual %d, TSF %llu\n", rx_status.signal, rx_status.noise, rx_status.signal, (unsigned long long)rx_status.mactime); @@ -1168,12 +1086,12 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, * "antenna number" * * It seems that the antenna field in the phy flags value - * is actually a bitfield. This is undefined by radiotap, + * is actually a bit field. This is undefined by radiotap, * it wants an actual antenna number but I always get "7" * for most legacy frames I receive indicating that the * same frame was received on all three RX chains. * - * I think this field should be removed in favour of a + * I think this field should be removed in favor of a * new 802.11n radiotap field "RX chains" that is defined * as a bitmask. */ diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index c89365e2ca58e3f4c5d142e9f9d11ed75d7642cc..3c803f6922efe0a03c498fe2efc53c78c4db5c50 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -22,11 +22,13 @@ * in the file called LICENSE.GPL. * * Contact Information: - * Tomas Winkler + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *****************************************************************************/ -#include +#include #include +#include +#include #include "iwl-eeprom.h" #include "iwl-dev.h" @@ -64,54 +66,6 @@ #define IWL_SCAN_PROBE_MASK(n) cpu_to_le32((BIT(n) | (BIT(n) - BIT(1)))) -static int scan_tx_ant[3] = { - RATE_MCS_ANT_A_MSK, RATE_MCS_ANT_B_MSK, RATE_MCS_ANT_C_MSK -}; - - - -static int iwl_is_empty_essid(const char *essid, int essid_len) -{ - /* Single white space is for Linksys APs */ - if (essid_len == 1 && essid[0] == ' ') - return 1; - - /* Otherwise, if the entire essid is 0, we assume it is hidden */ - while (essid_len) { - essid_len--; - if (essid[essid_len] != '\0') - return 0; - } - - return 1; -} - - - -static const char *iwl_escape_essid(const char *essid, u8 essid_len) -{ - static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; - const char *s = essid; - char *d = escaped; - - if (iwl_is_empty_essid(essid, essid_len)) { - memcpy(escaped, "", sizeof("")); - return escaped; - } - - essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE); - while (essid_len--) { - if (*s == '\0') { - *d++ = '\\'; - *d++ = '0'; - s++; - } else - *d++ = *s++; - } - *d = '\0'; - return escaped; -} - /** * iwl_scan_cancel - Cancel any currently executing HW scan * @@ -455,10 +409,11 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, void iwl_init_scan_params(struct iwl_priv *priv) { + u8 ant_idx = fls(priv->hw_params.valid_tx_ant) - 1; if (!priv->scan_tx_ant[IEEE80211_BAND_5GHZ]) - priv->scan_tx_ant[IEEE80211_BAND_5GHZ] = RATE_MCS_ANT_INIT_IND; + priv->scan_tx_ant[IEEE80211_BAND_5GHZ] = ant_idx; if (!priv->scan_tx_ant[IEEE80211_BAND_2GHZ]) - priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = RATE_MCS_ANT_INIT_IND; + priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = ant_idx; } int iwl_scan_initiate(struct iwl_priv *priv) @@ -550,7 +505,7 @@ static void iwl_ht_cap_to_ie(const struct ieee80211_supported_band *sband, { struct ieee80211_ht_cap *ht_cap; - if (!sband || !sband->ht_info.ht_supported) + if (!sband || !sband->ht_cap.ht_supported) return; if (*left < sizeof(struct ieee80211_ht_cap)) @@ -559,12 +514,12 @@ static void iwl_ht_cap_to_ie(const struct ieee80211_supported_band *sband, *pos++ = sizeof(struct ieee80211_ht_cap); ht_cap = (struct ieee80211_ht_cap *) pos; - ht_cap->cap_info = cpu_to_le16(sband->ht_info.cap); - memcpy(ht_cap->supp_mcs_set, sband->ht_info.supp_mcs_set, 16); + ht_cap->cap_info = cpu_to_le16(sband->ht_cap.cap); + memcpy(&ht_cap->mcs, &sband->ht_cap.mcs, 16); ht_cap->ampdu_params_info = - (sband->ht_info.ampdu_factor & IEEE80211_HT_CAP_AMPDU_FACTOR) | - ((sband->ht_info.ampdu_density << 2) & - IEEE80211_HT_CAP_AMPDU_DENSITY); + (sband->ht_cap.ampdu_factor & IEEE80211_HT_AMPDU_PARM_FACTOR) | + ((sband->ht_cap.ampdu_density << 2) & + IEEE80211_HT_AMPDU_PARM_DENSITY); *left -= sizeof(struct ieee80211_ht_cap); } @@ -670,23 +625,6 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv, return (u16)len; } -static u32 iwl_scan_tx_ant(struct iwl_priv *priv, enum ieee80211_band band) -{ - int i, ind; - - ind = priv->scan_tx_ant[band]; - for (i = 0; i < priv->hw_params.tx_chains_num; i++) { - ind = (ind+1) >= priv->hw_params.tx_chains_num ? 0 : ind+1; - if (priv->hw_params.valid_tx_ant & (1 << ind)) { - priv->scan_tx_ant[band] = ind; - break; - } - } - IWL_DEBUG_SCAN("select TX ANT = %c\n", 'A' + ind); - return scan_tx_ant[ind]; -} - - static void iwl_bg_request_scan(struct work_struct *data) { struct iwl_priv *priv = @@ -699,11 +637,13 @@ static void iwl_bg_request_scan(struct work_struct *data) struct iwl_scan_cmd *scan; struct ieee80211_conf *conf = NULL; int ret = 0; - u32 tx_ant; + u32 rate_flags = 0; u16 cmd_len; enum ieee80211_band band; u8 n_probes = 2; u8 rx_chain = priv->hw_params.valid_rx_ant; + u8 rate; + DECLARE_SSID_BUF(ssid); conf = ieee80211_get_hw_conf(priv->hw); @@ -714,7 +654,7 @@ static void iwl_bg_request_scan(struct work_struct *data) goto done; } - /* Make sure the scan wasn't cancelled before this queued work + /* Make sure the scan wasn't canceled before this queued work * was given the chance to run... */ if (!test_bit(STATUS_SCANNING, &priv->status)) goto done; @@ -796,20 +736,13 @@ static void iwl_bg_request_scan(struct work_struct *data) /* We should add the ability for user to lock to PASSIVE ONLY */ if (priv->one_direct_scan) { IWL_DEBUG_SCAN("Start direct scan for '%s'\n", - iwl_escape_essid(priv->direct_ssid, - priv->direct_ssid_len)); + print_ssid(ssid, priv->direct_ssid, + priv->direct_ssid_len)); scan->direct_scan[0].id = WLAN_EID_SSID; scan->direct_scan[0].len = priv->direct_ssid_len; memcpy(scan->direct_scan[0].ssid, priv->direct_ssid, priv->direct_ssid_len); n_probes++; - } else if (!iwl_is_associated(priv) && priv->essid_len) { - IWL_DEBUG_SCAN("Start direct scan for '%s' (not associated)\n", - iwl_escape_essid(priv->essid, priv->essid_len)); - scan->direct_scan[0].id = WLAN_EID_SSID; - scan->direct_scan[0].len = priv->essid_len; - memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len); - n_probes++; } else { IWL_DEBUG_SCAN("Start indirect scan.\n"); } @@ -822,23 +755,16 @@ static void iwl_bg_request_scan(struct work_struct *data) if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) { band = IEEE80211_BAND_2GHZ; scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK; - tx_ant = iwl_scan_tx_ant(priv, band); - if (priv->active_rxon.flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) - scan->tx_cmd.rate_n_flags = - iwl_hw_set_rate_n_flags(IWL_RATE_6M_PLCP, - tx_ant); - else - scan->tx_cmd.rate_n_flags = - iwl_hw_set_rate_n_flags(IWL_RATE_1M_PLCP, - tx_ant | - RATE_MCS_CCK_MSK); + if (priv->active_rxon.flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) { + rate = IWL_RATE_6M_PLCP; + } else { + rate = IWL_RATE_1M_PLCP; + rate_flags = RATE_MCS_CCK_MSK; + } scan->good_CRC_th = 0; } else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) { band = IEEE80211_BAND_5GHZ; - tx_ant = iwl_scan_tx_ant(priv, band); - scan->tx_cmd.rate_n_flags = - iwl_hw_set_rate_n_flags(IWL_RATE_6M_PLCP, - tx_ant); + rate = IWL_RATE_6M_PLCP; scan->good_CRC_th = IWL_GOOD_CRC_TH; /* Force use of chains B and C (0x6) for scan Rx for 4965 @@ -851,6 +777,11 @@ static void iwl_bg_request_scan(struct work_struct *data) goto done; } + priv->scan_tx_ant[band] = + iwl_toggle_tx_ant(priv, priv->scan_tx_ant[band]); + rate_flags |= iwl_ant_idx_to_flags(priv->scan_tx_ant[band]); + scan->tx_cmd.rate_n_flags = iwl_hw_set_rate_n_flags(rate, rate_flags); + /* MIMO is not used here, but value is required */ scan->rx_chain = RXON_RX_CHAIN_DRIVER_FORCE_MSK | cpu_to_le16((0x7 << RXON_RX_CHAIN_VALID_POS) | diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.c b/drivers/net/wireless/iwlwifi/iwl-spectrum.c new file mode 100644 index 0000000000000000000000000000000000000000..836c3c80b69ebbe712a9bd09c6cb3596eb2c1d95 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-spectrum.c @@ -0,0 +1,198 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project, as well + * as portions of the ieee80211 subsystem header files. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "iwl-eeprom.h" +#include "iwl-dev.h" +#include "iwl-core.h" +#include "iwl-io.h" +#include "iwl-spectrum.h" + +#define BEACON_TIME_MASK_LOW 0x00FFFFFF +#define BEACON_TIME_MASK_HIGH 0xFF000000 +#define TIME_UNIT 1024 + +/* + * extended beacon time format + * time in usec will be changed into a 32-bit value in 8:24 format + * the high 1 byte is the beacon counts + * the lower 3 bytes is the time in usec within one beacon interval + */ + +/* TOOD: was used in sysfs debug interface need to add to mac */ +#if 0 +static u32 iwl_usecs_to_beacons(u32 usec, u32 beacon_interval) +{ + u32 quot; + u32 rem; + u32 interval = beacon_interval * 1024; + + if (!interval || !usec) + return 0; + + quot = (usec / interval) & (BEACON_TIME_MASK_HIGH >> 24); + rem = (usec % interval) & BEACON_TIME_MASK_LOW; + + return (quot << 24) + rem; +} + +/* base is usually what we get from ucode with each received frame, + * the same as HW timer counter counting down + */ + +static __le32 iwl_add_beacon_time(u32 base, u32 addon, u32 beacon_interval) +{ + u32 base_low = base & BEACON_TIME_MASK_LOW; + u32 addon_low = addon & BEACON_TIME_MASK_LOW; + u32 interval = beacon_interval * TIME_UNIT; + u32 res = (base & BEACON_TIME_MASK_HIGH) + + (addon & BEACON_TIME_MASK_HIGH); + + if (base_low > addon_low) + res += base_low - addon_low; + else if (base_low < addon_low) { + res += interval + base_low - addon_low; + res += (1 << 24); + } else + res += (1 << 24); + + return cpu_to_le32(res); +} +static int iwl_get_measurement(struct iwl_priv *priv, + struct ieee80211_measurement_params *params, + u8 type) +{ + struct iwl4965_spectrum_cmd spectrum; + struct iwl_rx_packet *res; + struct iwl_host_cmd cmd = { + .id = REPLY_SPECTRUM_MEASUREMENT_CMD, + .data = (void *)&spectrum, + .meta.flags = CMD_WANT_SKB, + }; + u32 add_time = le64_to_cpu(params->start_time); + int rc; + int spectrum_resp_status; + int duration = le16_to_cpu(params->duration); + + if (iwl_is_associated(priv)) + add_time = + iwl_usecs_to_beacons( + le64_to_cpu(params->start_time) - priv->last_tsf, + le16_to_cpu(priv->rxon_timing.beacon_interval)); + + memset(&spectrum, 0, sizeof(spectrum)); + + spectrum.channel_count = cpu_to_le16(1); + spectrum.flags = + RXON_FLG_TSF2HOST_MSK | RXON_FLG_ANT_A_MSK | RXON_FLG_DIS_DIV_MSK; + spectrum.filter_flags = MEASUREMENT_FILTER_FLAG; + cmd.len = sizeof(spectrum); + spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len)); + + if (iwl_is_associated(priv)) + spectrum.start_time = + iwl_add_beacon_time(priv->last_beacon_time, + add_time, + le16_to_cpu(priv->rxon_timing.beacon_interval)); + else + spectrum.start_time = 0; + + spectrum.channels[0].duration = cpu_to_le32(duration * TIME_UNIT); + spectrum.channels[0].channel = params->channel; + spectrum.channels[0].type = type; + if (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK) + spectrum.flags |= RXON_FLG_BAND_24G_MSK | + RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK; + + rc = iwl_send_cmd_sync(priv, &cmd); + if (rc) + return rc; + + res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERROR("Bad return from REPLY_RX_ON_ASSOC command\n"); + rc = -EIO; + } + + spectrum_resp_status = le16_to_cpu(res->u.spectrum.status); + switch (spectrum_resp_status) { + case 0: /* Command will be handled */ + if (res->u.spectrum.id != 0xff) { + IWL_DEBUG_INFO + ("Replaced existing measurement: %d\n", + res->u.spectrum.id); + priv->measurement_status &= ~MEASUREMENT_READY; + } + priv->measurement_status |= MEASUREMENT_ACTIVE; + rc = 0; + break; + + case 1: /* Command will not be handled */ + rc = -EAGAIN; + break; + } + + dev_kfree_skb_any(cmd.meta.u.skb); + + return rc; +} +#endif + +static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif); + + if (!report->state) { + IWL_DEBUG(IWL_DL_11H, + "Spectrum Measure Notification: Start\n"); + return; + } + + memcpy(&priv->measure_report, report, sizeof(*report)); + priv->measurement_status |= MEASUREMENT_READY; +} + +void iwl_setup_spectrum_handlers(struct iwl_priv *priv) +{ + priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] = + iwl_rx_spectrum_measure_notif; +} +EXPORT_SYMBOL(iwl_setup_spectrum_handlers); diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.h b/drivers/net/wireless/iwlwifi/iwl-spectrum.h index a40a2174df985df31a19409d72a1f100c63c8bb5..b7d7943e476b055ad7d6204b0fbd8f3ad7e342e5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-spectrum.h +++ b/drivers/net/wireless/iwlwifi/iwl-spectrum.h @@ -21,7 +21,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -88,4 +88,5 @@ struct ieee80211_measurement_report { struct ieee80211_basic_report basic[0]; } u; } __attribute__ ((packed)); + #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 26f7084d3011b7f8f514a4e23090ddfce33ca62c..412f66bac1afc0f4024169b719f179405345a86e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -33,8 +33,6 @@ #include "iwl-dev.h" #include "iwl-core.h" #include "iwl-sta.h" -#include "iwl-helpers.h" - #define IWL_STA_DRIVER_ACTIVE BIT(0) /* driver entry is active */ #define IWL_STA_UCODE_ACTIVE BIT(1) /* ucode entry is active */ @@ -45,7 +43,6 @@ u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr) int start = 0; int ret = IWL_INVALID_STATION; unsigned long flags; - DECLARE_MAC_BUF(mac); if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) || (priv->iw_mode == NL80211_IFTYPE_AP)) @@ -63,8 +60,8 @@ u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr) goto out; } - IWL_DEBUG_ASSOC_LIMIT("can not find STA %s total %d\n", - print_mac(mac, addr), priv->num_stations); + IWL_DEBUG_ASSOC_LIMIT("can not find STA %pM total %d\n", + addr, priv->num_stations); out: spin_unlock_irqrestore(&priv->sta_lock, flags); @@ -86,7 +83,6 @@ EXPORT_SYMBOL(iwl_get_ra_sta_id); static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id) { unsigned long flags; - DECLARE_MAC_BUF(mac); spin_lock_irqsave(&priv->sta_lock, flags); @@ -94,8 +90,8 @@ static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id) IWL_ERROR("ACTIVATE a non DRIVER active station %d\n", sta_id); priv->stations[sta_id].used |= IWL_STA_UCODE_ACTIVE; - IWL_DEBUG_ASSOC("Added STA to Ucode: %s\n", - print_mac(mac, priv->stations[sta_id].sta.sta.addr)); + IWL_DEBUG_ASSOC("Added STA to Ucode: %pM\n", + priv->stations[sta_id].sta.sta.addr); spin_unlock_irqrestore(&priv->sta_lock, flags); } @@ -104,7 +100,9 @@ static int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_cmd *cmd, struct sk_buff *skb) { struct iwl_rx_packet *res = NULL; - u8 sta_id = cmd->cmd.addsta.sta.sta_id; + struct iwl_addsta_cmd *addsta = + (struct iwl_addsta_cmd *)cmd->cmd.payload; + u8 sta_id = addsta->sta.sta_id; if (!skb) { IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n"); @@ -132,7 +130,7 @@ static int iwl_add_sta_callback(struct iwl_priv *priv, return 1; } -int iwl_send_add_sta(struct iwl_priv *priv, +static int iwl_send_add_sta(struct iwl_priv *priv, struct iwl_addsta_cmd *sta, u8 flags) { struct iwl_rx_packet *res = NULL; @@ -180,10 +178,9 @@ int iwl_send_add_sta(struct iwl_priv *priv, return ret; } -EXPORT_SYMBOL(iwl_send_add_sta); static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, - struct ieee80211_ht_info *sta_ht_inf) + struct ieee80211_sta_ht_cap *sta_ht_inf) { __le32 sta_flags; u8 mimo_ps_mode; @@ -231,13 +228,12 @@ static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, * iwl_add_station_flags - Add station to tables in driver and device */ u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, - u8 flags, struct ieee80211_ht_info *ht_info) + u8 flags, struct ieee80211_sta_ht_cap *ht_info) { int i; int sta_id = IWL_INVALID_STATION; struct iwl_station_entry *station; unsigned long flags_spin; - DECLARE_MAC_BUF(mac); spin_lock_irqsave(&priv->sta_lock, flags_spin); if (is_ap) @@ -273,8 +269,8 @@ u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, station = &priv->stations[sta_id]; station->used = IWL_STA_DRIVER_ACTIVE; - IWL_DEBUG_ASSOC("Add STA to driver ID %d: %s\n", - sta_id, print_mac(mac, addr)); + IWL_DEBUG_ASSOC("Add STA to driver ID %d: %pM\n", + sta_id, addr); priv->num_stations++; /* Set up the REPLY_ADD_STA command to send to device */ @@ -301,14 +297,11 @@ EXPORT_SYMBOL(iwl_add_station_flags); static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr) { unsigned long flags; - DECLARE_MAC_BUF(mac); - u8 sta_id = iwl_find_station(priv, addr); BUG_ON(sta_id == IWL_INVALID_STATION); - IWL_DEBUG_ASSOC("Removed STA from Ucode: %s\n", - print_mac(mac, addr)); + IWL_DEBUG_ASSOC("Removed STA from Ucode: %pM\n", addr); spin_lock_irqsave(&priv->sta_lock, flags); @@ -326,7 +319,9 @@ static int iwl_remove_sta_callback(struct iwl_priv *priv, struct iwl_cmd *cmd, struct sk_buff *skb) { struct iwl_rx_packet *res = NULL; - const char *addr = cmd->cmd.rm_sta.addr; + struct iwl_rem_sta_cmd *rm_sta = + (struct iwl_rem_sta_cmd *)cmd->cmd.payload; + const char *addr = rm_sta->addr; if (!skb) { IWL_ERROR("Error: Response NULL in REPLY_REMOVE_STA.\n"); @@ -415,7 +410,6 @@ int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap) int sta_id = IWL_INVALID_STATION; int i, ret = -EINVAL; unsigned long flags; - DECLARE_MAC_BUF(mac); spin_lock_irqsave(&priv->sta_lock, flags); @@ -435,18 +429,18 @@ int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap) if (unlikely(sta_id == IWL_INVALID_STATION)) goto out; - IWL_DEBUG_ASSOC("Removing STA from driver:%d %s\n", - sta_id, print_mac(mac, addr)); + IWL_DEBUG_ASSOC("Removing STA from driver:%d %pM\n", + sta_id, addr); if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) { - IWL_ERROR("Removing %s but non DRIVER active\n", - print_mac(mac, addr)); + IWL_ERROR("Removing %pM but non DRIVER active\n", + addr); goto out; } if (!(priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) { - IWL_ERROR("Removing %s but non UCODE active\n", - print_mac(mac, addr)); + IWL_ERROR("Removing %pM but non UCODE active\n", + addr); goto out; } @@ -467,6 +461,29 @@ int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap) } EXPORT_SYMBOL(iwl_remove_station); +/** + * iwl_clear_stations_table - Clear the driver's station table + * + * NOTE: This does not clear or otherwise alter the device's station table. + */ +void iwl_clear_stations_table(struct iwl_priv *priv) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->sta_lock, flags); + + if (iwl_is_alive(priv) && + !test_bit(STATUS_EXIT_PENDING, &priv->status) && + iwl_send_cmd_pdu_async(priv, REPLY_REMOVE_ALL_STA, 0, NULL, NULL)) + IWL_ERROR("Couldn't clear the station table\n"); + + priv->num_stations = 0; + memset(priv->stations, 0, sizeof(priv->stations)); + + spin_unlock_irqrestore(&priv->sta_lock, flags); +} +EXPORT_SYMBOL(iwl_clear_stations_table); + static int iwl_get_free_ucode_key_index(struct iwl_priv *priv) { int i; @@ -717,6 +734,55 @@ static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv, return ret; } +void iwl_update_tkip_key(struct iwl_priv *priv, + struct ieee80211_key_conf *keyconf, + const u8 *addr, u32 iv32, u16 *phase1key) +{ + u8 sta_id = IWL_INVALID_STATION; + unsigned long flags; + __le16 key_flags = 0; + int i; + DECLARE_MAC_BUF(mac); + + sta_id = iwl_find_station(priv, addr); + if (sta_id == IWL_INVALID_STATION) { + IWL_DEBUG_MAC80211("leave - %pM not in station map.\n", + addr); + return; + } + + if (iwl_scan_cancel(priv)) { + /* cancel scan failed, just live w/ bad key and rely + briefly on SW decryption */ + return; + } + + key_flags |= (STA_KEY_FLG_TKIP | STA_KEY_FLG_MAP_KEY_MSK); + key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); + key_flags &= ~STA_KEY_FLG_INVALID; + + if (sta_id == priv->hw_params.bcast_sta_id) + key_flags |= STA_KEY_MULTICAST_MSK; + + spin_lock_irqsave(&priv->sta_lock, flags); + + priv->stations[sta_id].sta.key.key_flags = key_flags; + priv->stations[sta_id].sta.key.tkip_rx_tsc_byte2 = (u8) iv32; + + for (i = 0; i < 5; i++) + priv->stations[sta_id].sta.key.tkip_rx_ttak[i] = + cpu_to_le16(phase1key[i]); + + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + + iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); + + spin_unlock_irqrestore(&priv->sta_lock, flags); + +} +EXPORT_SYMBOL(iwl_update_tkip_key); + int iwl_remove_dynamic_key(struct iwl_priv *priv, struct ieee80211_key_conf *keyconf, u8 sta_id) @@ -809,7 +875,7 @@ static void iwl_dump_lq_cmd(struct iwl_priv *priv, { int i; IWL_DEBUG_RATE("lq station id 0x%x\n", lq->sta_id); - IWL_DEBUG_RATE("lq dta 0x%X 0x%X\n", + IWL_DEBUG_RATE("lq ant 0x%X 0x%X\n", lq->general_params.single_stream_ant_msk, lq->general_params.dual_stream_ant_msk); @@ -870,7 +936,7 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap) struct iwl_link_quality_cmd link_cmd = { .reserved1 = 0, }; - u16 rate_flags; + u32 rate_flags; /* Set up the rate scaling to start at selected rate, fall back * all the way down to 1M in IEEE order, and then spin on 1M */ @@ -886,15 +952,16 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap) if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE) rate_flags |= RATE_MCS_CCK_MSK; - /* Use Tx antenna B only */ - rate_flags |= RATE_MCS_ANT_B_MSK; /*FIXME:RS*/ + rate_flags |= first_antenna(priv->hw_params.valid_tx_ant) << + RATE_MCS_ANT_POS; link_cmd.rs_table[i].rate_n_flags = iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags); - r = iwl4965_get_prev_ieee_rate(r); + r = iwl_get_prev_ieee_rate(r); } - link_cmd.general_params.single_stream_ant_msk = 2; + link_cmd.general_params.single_stream_ant_msk = + first_antenna(priv->hw_params.valid_tx_ant); link_cmd.general_params.dual_stream_ant_msk = 3; link_cmd.agg_params.agg_dis_start_th = 3; link_cmd.agg_params.agg_time_limit = cpu_to_le16(4000); @@ -910,24 +977,35 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap) * iwl_rxon_add_station - add station into station table. * * there is only one AP station with id= IWL_AP_ID - * NOTE: mutex must be held before calling this fnction + * NOTE: mutex must be held before calling this function */ int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) { + struct ieee80211_sta *sta; + struct ieee80211_sta_ht_cap ht_config; + struct ieee80211_sta_ht_cap *cur_ht_config = NULL; u8 sta_id; /* Add station to device's station table */ - struct ieee80211_conf *conf = &priv->hw->conf; - struct ieee80211_ht_info *cur_ht_config = &conf->ht_conf; - - if ((is_ap) && - (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) && - (priv->iw_mode == NL80211_IFTYPE_STATION)) - sta_id = iwl_add_station_flags(priv, addr, is_ap, - 0, cur_ht_config); - else - sta_id = iwl_add_station_flags(priv, addr, is_ap, - 0, NULL); + + /* + * XXX: This check is definitely not correct, if we're an AP + * it'll always be false which is not what we want, but + * it doesn't look like iwlagn is prepared to be an HT + * AP anyway. + */ + if (priv->current_ht_config.is_ht) { + rcu_read_lock(); + sta = ieee80211_find_sta(priv->hw, addr); + if (sta) { + memcpy(&ht_config, &sta->ht_cap, sizeof(ht_config)); + cur_ht_config = &ht_config; + } + rcu_read_unlock(); + } + + sta_id = iwl_add_station_flags(priv, addr, is_ap, + 0, cur_ht_config); /* Set up default rate scaling table in device's station table */ iwl_sta_init_lq(priv, addr, is_ap); @@ -945,7 +1023,6 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) { int sta_id; u16 fc = le16_to_cpu(hdr->frame_control); - DECLARE_MAC_BUF(mac); /* If this frame is broadcast or management, use broadcast station id */ if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) || @@ -980,9 +1057,9 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) if (sta_id != IWL_INVALID_STATION) return sta_id; - IWL_DEBUG_DROP("Station %s not in station map. " + IWL_DEBUG_DROP("Station %pM not in station map. " "Defaulting to broadcast...\n", - print_mac(mac, hdr->addr1)); + hdr->addr1); iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); return priv->hw_params.bcast_sta_id; @@ -999,9 +1076,9 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) EXPORT_SYMBOL(iwl_get_sta_id); /** - * iwl_sta_modify_enable_tid_tx - Enable Tx for this TID in station table + * iwl_sta_tx_modify_enable_tid - Enable Tx for this TID in station table */ -void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv, int sta_id, int tid) +void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid) { unsigned long flags; @@ -1014,5 +1091,81 @@ void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv, int sta_id, int tid) iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); } -EXPORT_SYMBOL(iwl_sta_modify_enable_tid_tx); +EXPORT_SYMBOL(iwl_sta_tx_modify_enable_tid); + +int iwl_sta_rx_agg_start(struct iwl_priv *priv, + const u8 *addr, int tid, u16 ssn) +{ + unsigned long flags; + int sta_id; + + sta_id = iwl_find_station(priv, addr); + if (sta_id == IWL_INVALID_STATION) + return -ENXIO; + + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].sta.station_flags_msk = 0; + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK; + priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid; + priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn); + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + return iwl_send_add_sta(priv, &priv->stations[sta_id].sta, + CMD_ASYNC); +} +EXPORT_SYMBOL(iwl_sta_rx_agg_start); + +int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid) +{ + unsigned long flags; + int sta_id; + + sta_id = iwl_find_station(priv, addr); + if (sta_id == IWL_INVALID_STATION) + return -ENXIO; + + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].sta.station_flags_msk = 0; + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK; + priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + return iwl_send_add_sta(priv, &priv->stations[sta_id].sta, + CMD_ASYNC); +} +EXPORT_SYMBOL(iwl_sta_rx_agg_stop); + +static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK; + priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK; + priv->stations[sta_id].sta.sta.modify_mask = 0; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); +} + +void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr) +{ + /* FIXME: need locking over ps_status ??? */ + u8 sta_id = iwl_find_station(priv, addr); + + if (sta_id != IWL_INVALID_STATION) { + u8 sta_awake = priv->stations[sta_id]. + ps_status == STA_PS_STATUS_WAKE; + + if (sta_awake && ps_bit) + priv->stations[sta_id].ps_status = STA_PS_STATUS_SLEEP; + else if (!sta_awake && !ps_bit) { + iwl_sta_modify_ps_wake(priv, sta_id); + priv->stations[sta_id].ps_status = STA_PS_STATUS_WAKE; + } + } +} diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h index 221b93e670a6c4e4d0d29d1431af2e388020f7a8..9bb7cefc1f3cd2fc2157831c7958024ef5c7214e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.h +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -47,9 +47,21 @@ int iwl_set_dynamic_key(struct iwl_priv *priv, struct ieee80211_key_conf *key, u8 sta_id); int iwl_remove_dynamic_key(struct iwl_priv *priv, struct ieee80211_key_conf *key, u8 sta_id); +void iwl_update_tkip_key(struct iwl_priv *priv, + struct ieee80211_key_conf *keyconf, + const u8 *addr, u32 iv32, u16 *phase1key); + int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap); int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap); +void iwl_clear_stations_table(struct iwl_priv *priv); int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr); -void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv, int sta_id, int tid); int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr); +u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, + int is_ap, u8 flags, + struct ieee80211_sta_ht_cap *ht_info); +void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid); +int iwl_sta_rx_agg_start(struct iwl_priv *priv, + const u8 *addr, int tid, u16 ssn); +int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid); +void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr); #endif /* __iwl_sta_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 907a53ebc6e4dc62fc7a5226b6706af72d1e0d85..b0ee86c6268501754651206d88b87fdcfceb2401 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -56,96 +56,132 @@ static const u16 default_tid_to_tx_fifo[] = { IWL_TX_FIFO_AC3 }; +static inline int iwl_alloc_dma_ptr(struct iwl_priv *priv, + struct iwl_dma_ptr *ptr, size_t size) +{ + ptr->addr = pci_alloc_consistent(priv->pci_dev, size, &ptr->dma); + if (!ptr->addr) + return -ENOMEM; + ptr->size = size; + return 0; +} + +static inline void iwl_free_dma_ptr(struct iwl_priv *priv, + struct iwl_dma_ptr *ptr) +{ + if (unlikely(!ptr->addr)) + return; + + pci_free_consistent(priv->pci_dev, ptr->size, ptr->addr, ptr->dma); + memset(ptr, 0, sizeof(*ptr)); +} + +static inline dma_addr_t iwl_tfd_tb_get_addr(struct iwl_tfd *tfd, u8 idx) +{ + struct iwl_tfd_tb *tb = &tfd->tbs[idx]; + + dma_addr_t addr = get_unaligned_le32(&tb->lo); + if (sizeof(dma_addr_t) > sizeof(u32)) + addr |= + ((dma_addr_t)(le16_to_cpu(tb->hi_n_len) & 0xF) << 16) << 16; + + return addr; +} + +static inline u16 iwl_tfd_tb_get_len(struct iwl_tfd *tfd, u8 idx) +{ + struct iwl_tfd_tb *tb = &tfd->tbs[idx]; + + return le16_to_cpu(tb->hi_n_len) >> 4; +} + +static inline void iwl_tfd_set_tb(struct iwl_tfd *tfd, u8 idx, + dma_addr_t addr, u16 len) +{ + struct iwl_tfd_tb *tb = &tfd->tbs[idx]; + u16 hi_n_len = len << 4; + + put_unaligned_le32(addr, &tb->lo); + if (sizeof(dma_addr_t) > sizeof(u32)) + hi_n_len |= ((addr >> 16) >> 16) & 0xF; + + tb->hi_n_len = cpu_to_le16(hi_n_len); + + tfd->num_tbs = idx + 1; +} + +static inline u8 iwl_tfd_get_num_tbs(struct iwl_tfd *tfd) +{ + return tfd->num_tbs & 0x1f; +} /** * iwl_hw_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr] + * @priv - driver private data + * @txq - tx queue * * Does NOT advance any TFD circular buffer read/write indexes * Does NOT free the TFD itself (which is within circular buffer) */ -static int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) +static void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) { - struct iwl_tfd_frame *bd_tmp = (struct iwl_tfd_frame *)&txq->bd[0]; - struct iwl_tfd_frame *bd = &bd_tmp[txq->q.read_ptr]; + struct iwl_tfd *tfd_tmp = (struct iwl_tfd *)&txq->tfds[0]; + struct iwl_tfd *tfd; struct pci_dev *dev = priv->pci_dev; + int index = txq->q.read_ptr; int i; - int counter = 0; - int index, is_odd; + int num_tbs; - /* Host command buffers stay mapped in memory, nothing to clean */ - if (txq->q.id == IWL_CMD_QUEUE_NUM) - return 0; + tfd = &tfd_tmp[index]; /* Sanity check on number of chunks */ - counter = IWL_GET_BITS(*bd, num_tbs); - if (counter > MAX_NUM_OF_TBS) { - IWL_ERROR("Too many chunks: %i\n", counter); + num_tbs = iwl_tfd_get_num_tbs(tfd); + + if (num_tbs >= IWL_NUM_OF_TBS) { + IWL_ERROR("Too many chunks: %i\n", num_tbs); /* @todo issue fatal error, it is quite serious situation */ - return 0; + return; } - /* Unmap chunks, if any. - * TFD info for odd chunks is different format than for even chunks. */ - for (i = 0; i < counter; i++) { - index = i / 2; - is_odd = i & 0x1; - - if (is_odd) - pci_unmap_single( - dev, - IWL_GET_BITS(bd->pa[index], tb2_addr_lo16) | - (IWL_GET_BITS(bd->pa[index], - tb2_addr_hi20) << 16), - IWL_GET_BITS(bd->pa[index], tb2_len), + /* Unmap tx_cmd */ + if (num_tbs) + pci_unmap_single(dev, + pci_unmap_addr(&txq->cmd[index]->meta, mapping), + pci_unmap_len(&txq->cmd[index]->meta, len), PCI_DMA_TODEVICE); - else if (i > 0) - pci_unmap_single(dev, - le32_to_cpu(bd->pa[index].tb1_addr), - IWL_GET_BITS(bd->pa[index], tb1_len), - PCI_DMA_TODEVICE); + /* Unmap chunks, if any. */ + for (i = 1; i < num_tbs; i++) { + pci_unmap_single(dev, iwl_tfd_tb_get_addr(tfd, i), + iwl_tfd_tb_get_len(tfd, i), PCI_DMA_TODEVICE); - /* Free SKB, if any, for this chunk */ - if (txq->txb[txq->q.read_ptr].skb[i]) { - struct sk_buff *skb = txq->txb[txq->q.read_ptr].skb[i]; - - dev_kfree_skb(skb); - txq->txb[txq->q.read_ptr].skb[i] = NULL; + if (txq->txb) { + dev_kfree_skb(txq->txb[txq->q.read_ptr].skb[i - 1]); + txq->txb[txq->q.read_ptr].skb[i - 1] = NULL; } } - return 0; } -static int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, - dma_addr_t addr, u16 len) +static int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, + struct iwl_tfd *tfd, + dma_addr_t addr, u16 len) { - int index, is_odd; - struct iwl_tfd_frame *tfd = ptr; - u32 num_tbs = IWL_GET_BITS(*tfd, num_tbs); + + u32 num_tbs = iwl_tfd_get_num_tbs(tfd); /* Each TFD can point to a maximum 20 Tx buffers */ - if (num_tbs >= MAX_NUM_OF_TBS) { + if (num_tbs >= IWL_NUM_OF_TBS) { IWL_ERROR("Error can not send more than %d chunks\n", - MAX_NUM_OF_TBS); + IWL_NUM_OF_TBS); return -EINVAL; } - index = num_tbs / 2; - is_odd = num_tbs & 0x1; - - if (!is_odd) { - tfd->pa[index].tb1_addr = cpu_to_le32(addr); - IWL_SET_BITS(tfd->pa[index], tb1_addr_hi, - iwl_get_dma_hi_address(addr)); - IWL_SET_BITS(tfd->pa[index], tb1_len, len); - } else { - IWL_SET_BITS(tfd->pa[index], tb2_addr_lo16, - (u32) (addr & 0xffff)); - IWL_SET_BITS(tfd->pa[index], tb2_addr_hi20, addr >> 16); - IWL_SET_BITS(tfd->pa[index], tb2_len, len); - } + BUG_ON(addr & ~DMA_BIT_MASK(36)); + if (unlikely(addr & ~IWL_TX_DMA_MASK)) + IWL_ERROR("Unaligned address = %llx\n", + (unsigned long long)addr); - IWL_SET_BITS(*tfd, num_tbs, num_tbs + 1); + iwl_tfd_set_tb(tfd, num_tbs, addr, len); return 0; } @@ -210,7 +246,7 @@ static void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id) struct iwl_tx_queue *txq = &priv->txq[txq_id]; struct iwl_queue *q = &txq->q; struct pci_dev *dev = priv->pci_dev; - int i, slots_num, len; + int i, len; if (q->n_bd == 0) return; @@ -221,21 +257,15 @@ static void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id) iwl_hw_txq_free_tfd(priv, txq); len = sizeof(struct iwl_cmd) * q->n_window; - if (q->id == IWL_CMD_QUEUE_NUM) - len += IWL_MAX_SCAN_SIZE; /* De-alloc array of command/tx buffers */ - slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ? - TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; - for (i = 0; i < slots_num; i++) + for (i = 0; i < TFD_TX_CMD_SLOTS; i++) kfree(txq->cmd[i]); - if (txq_id == IWL_CMD_QUEUE_NUM) - kfree(txq->cmd[slots_num]); /* De-alloc circular buffer of TFDs */ if (txq->q.n_bd) - pci_free_consistent(dev, sizeof(struct iwl_tfd_frame) * - txq->q.n_bd, txq->bd, txq->q.dma_addr); + pci_free_consistent(dev, sizeof(struct iwl_tfd) * + txq->q.n_bd, txq->tfds, txq->q.dma_addr); /* De-alloc array of per-TFD driver data */ kfree(txq->txb); @@ -245,6 +275,40 @@ static void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id) memset(txq, 0, sizeof(*txq)); } + +/** + * iwl_cmd_queue_free - Deallocate DMA queue. + * @txq: Transmit queue to deallocate. + * + * Empty queue by removing and destroying all BD's. + * Free all buffers. + * 0-fill, but do not free "txq" descriptor structure. + */ +static void iwl_cmd_queue_free(struct iwl_priv *priv) +{ + struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; + struct iwl_queue *q = &txq->q; + struct pci_dev *dev = priv->pci_dev; + int i, len; + + if (q->n_bd == 0) + return; + + len = sizeof(struct iwl_cmd) * q->n_window; + len += IWL_MAX_SCAN_SIZE; + + /* De-alloc array of command/tx buffers */ + for (i = 0; i <= TFD_CMD_SLOTS; i++) + kfree(txq->cmd[i]); + + /* De-alloc circular buffer of TFDs */ + if (txq->q.n_bd) + pci_free_consistent(dev, sizeof(struct iwl_tfd) * + txq->q.n_bd, txq->tfds, txq->q.dma_addr); + + /* 0-fill queue descriptor structure */ + memset(txq, 0, sizeof(*txq)); +} /*************** DMA-QUEUE-GENERAL-FUNCTIONS ***** * DMA services * @@ -340,13 +404,13 @@ static int iwl_tx_queue_alloc(struct iwl_priv *priv, /* Circular buffer of transmit frame descriptors (TFDs), * shared with device */ - txq->bd = pci_alloc_consistent(dev, - sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX, + txq->tfds = pci_alloc_consistent(dev, + sizeof(txq->tfds[0]) * TFD_QUEUE_SIZE_MAX, &txq->q.dma_addr); - if (!txq->bd) { + if (!txq->tfds) { IWL_ERROR("pci_alloc_consistent(%zd) failed\n", - sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX); + sizeof(txq->tfds[0]) * TFD_QUEUE_SIZE_MAX); goto error; } txq->q.id = id; @@ -370,26 +434,21 @@ static int iwl_tx_queue_alloc(struct iwl_priv *priv, static int iwl_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq) { - int rc; + int ret; unsigned long flags; int txq_id = txq->q.id; spin_lock_irqsave(&priv->lock, flags); - rc = iwl_grab_nic_access(priv); - if (rc) { + ret = iwl_grab_nic_access(priv); + if (ret) { spin_unlock_irqrestore(&priv->lock, flags); - return rc; + return ret; } /* Circular buffer (TFD queue in DRAM) physical base address */ iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id), txq->q.dma_addr >> 8); - /* Enable DMA channel, using same id as for TFD queue */ - iwl_write_direct32( - priv, FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), - FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | - FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL); iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); @@ -468,16 +527,20 @@ void iwl_hw_txq_ctx_free(struct iwl_priv *priv) /* Tx queues */ for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) - iwl_tx_queue_free(priv, txq_id); + if (txq_id == IWL_CMD_QUEUE_NUM) + iwl_cmd_queue_free(priv); + else + iwl_tx_queue_free(priv, txq_id); - /* Keep-warm buffer */ - iwl_kw_free(priv); + iwl_free_dma_ptr(priv, &priv->kw); + + iwl_free_dma_ptr(priv, &priv->scd_bc_tbls); } EXPORT_SYMBOL(iwl_hw_txq_ctx_free); /** * iwl_txq_ctx_reset - Reset TX queue context - * Destroys all DMA structures and initialise them again + * Destroys all DMA structures and initialize them again * * @param priv * @return error code @@ -488,13 +551,17 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv) int txq_id, slots_num; unsigned long flags; - iwl_kw_free(priv); - /* Free all tx/cmd queues and keep-warm buffer */ iwl_hw_txq_ctx_free(priv); + ret = iwl_alloc_dma_ptr(priv, &priv->scd_bc_tbls, + priv->hw_params.scd_bc_tbls_size); + if (ret) { + IWL_ERROR("Scheduler BC Table allocation failed\n"); + goto error_bc_tbls; + } /* Alloc keep-warm buffer */ - ret = iwl_kw_alloc(priv); + ret = iwl_alloc_dma_ptr(priv, &priv->kw, IWL_KW_SIZE); if (ret) { IWL_ERROR("Keep Warm allocation failed\n"); goto error_kw; @@ -509,17 +576,12 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv) /* Turn off all Tx DMA fifos */ priv->cfg->ops->lib->txq_set_sched(priv, 0); + /* Tell NIC where to find the "keep warm" buffer */ + iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4); + iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); - - /* Tell nic where to find the keep-warm buffer */ - ret = iwl_kw_init(priv); - if (ret) { - IWL_ERROR("kw_init failed\n"); - goto error_reset; - } - /* Alloc and init all Tx queues, including the command queue (#4) */ for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ? @@ -537,8 +599,10 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv) error: iwl_hw_txq_ctx_free(priv); error_reset: - iwl_kw_free(priv); + iwl_free_dma_ptr(priv, &priv->kw); error_kw: + iwl_free_dma_ptr(priv, &priv->scd_bc_tbls); + error_bc_tbls: return ret; } @@ -547,11 +611,9 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv) */ void iwl_txq_ctx_stop(struct iwl_priv *priv) { - - int txq_id; + int ch; unsigned long flags; - /* Turn off all Tx DMA fifos */ spin_lock_irqsave(&priv->lock, flags); if (iwl_grab_nic_access(priv)) { @@ -562,12 +624,11 @@ void iwl_txq_ctx_stop(struct iwl_priv *priv) priv->cfg->ops->lib->txq_set_sched(priv, 0); /* Stop each Tx DMA channel, and wait for it to be idle */ - for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { - iwl_write_direct32(priv, - FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), 0x0); + for (ch = 0; ch < priv->hw_params.dma_chnl_num; ch++) { + iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0); iwl_poll_direct_bit(priv, FH_TSSR_TX_STATUS_REG, - FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE - (txq_id), 200); + FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch), + 1000); } iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); @@ -584,7 +645,7 @@ static void iwl_tx_cmd_build_basic(struct iwl_priv *priv, struct iwl_tx_cmd *tx_cmd, struct ieee80211_tx_info *info, struct ieee80211_hdr *hdr, - int is_unicast, u8 std_id) + u8 std_id) { __le16 fc = hdr->frame_control; __le32 tx_flags = tx_cmd->tx_flags; @@ -647,11 +708,11 @@ static void iwl_tx_cmd_build_rate(struct iwl_priv *priv, __le16 fc, int sta_id, int is_hcca) { + u32 rate_flags = 0; + int rate_idx; u8 rts_retry_limit = 0; u8 data_retry_limit = 0; u8 rate_plcp; - u16 rate_flags = 0; - int rate_idx; rate_idx = min(ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xffff, IWL_RATE_COUNT - 1); @@ -694,14 +755,8 @@ static void iwl_tx_cmd_build_rate(struct iwl_priv *priv, break; } - /* Alternate between antenna A and B for successive frames */ - if (priv->use_ant_b_for_management_frame) { - priv->use_ant_b_for_management_frame = 0; - rate_flags |= RATE_MCS_ANT_B_MSK; - } else { - priv->use_ant_b_for_management_frame = 1; - rate_flags |= RATE_MCS_ANT_A_MSK; - } + priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant); + rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant); } tx_cmd->rts_retry_limit = rts_retry_limit; @@ -723,7 +778,7 @@ static void iwl_tx_cmd_build_hwcrypto(struct iwl_priv *priv, memcpy(tx_cmd->key, keyconf->key, keyconf->keylen); if (info->flags & IEEE80211_TX_CTL_AMPDU) tx_cmd->tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK; - IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n"); + IWL_DEBUG_TX("tx_cmd with AES hwcrypto\n"); break; case ALG_TKIP: @@ -767,7 +822,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct iwl_tfd_frame *tfd; + struct iwl_tfd *tfd; struct iwl_tx_queue *txq; struct iwl_queue *q; struct iwl_cmd *out_cmd; @@ -776,10 +831,10 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) dma_addr_t phys_addr; dma_addr_t txcmd_phys; dma_addr_t scratch_phys; - u16 len, idx, len_org; + u16 len, len_org; u16 seq_number = 0; __le16 fc; - u8 hdr_len, unicast; + u8 hdr_len; u8 sta_id; u8 wait_write_ptr = 0; u8 tid = 0; @@ -799,8 +854,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) goto drop_unlock; } - unicast = !is_multicast_ether_addr(hdr->addr1); - fc = hdr->frame_control; #ifdef CONFIG_IWLWIFI_DEBUG @@ -830,10 +883,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* Find (or create) index into station table for destination station */ sta_id = iwl_get_sta_id(priv, hdr); if (sta_id == IWL_INVALID_STATION) { - DECLARE_MAC_BUF(mac); - - IWL_DEBUG_DROP("Dropping - INVALID STATION: %s\n", - print_mac(mac, hdr->addr1)); + IWL_DEBUG_DROP("Dropping - INVALID STATION: %pM\n", + hdr->addr1); goto drop; } @@ -856,23 +907,22 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) priv->stations[sta_id].tid[tid].tfds_in_queue++; } - /* Descriptor for chosen Tx queue */ txq = &priv->txq[txq_id]; q = &txq->q; + txq->swq_id = swq_id; spin_lock_irqsave(&priv->lock, flags); /* Set up first empty TFD within this queue's circular TFD buffer */ - tfd = &txq->bd[q->write_ptr]; + tfd = &txq->tfds[q->write_ptr]; memset(tfd, 0, sizeof(*tfd)); - idx = get_cmd_index(q, q->write_ptr, 0); /* Set up driver data for this TFD */ memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info)); txq->txb[q->write_ptr].skb[0] = skb; /* Set up first empty entry in queue's array of Tx/cmd buffers */ - out_cmd = txq->cmd[idx]; + out_cmd = txq->cmd[q->write_ptr]; tx_cmd = &out_cmd->cmd.tx; memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr)); memset(tx_cmd, 0, sizeof(struct iwl_tx_cmd)); @@ -912,12 +962,14 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* Physical address of this Tx command's header (not MAC header!), * within command buffer array. */ - txcmd_phys = pci_map_single(priv->pci_dev, out_cmd, - sizeof(struct iwl_cmd), PCI_DMA_TODEVICE); - txcmd_phys += offsetof(struct iwl_cmd, hdr); - + txcmd_phys = pci_map_single(priv->pci_dev, + out_cmd, sizeof(struct iwl_cmd), + PCI_DMA_TODEVICE); + pci_unmap_addr_set(&out_cmd->meta, mapping, txcmd_phys); + pci_unmap_len_set(&out_cmd->meta, len, sizeof(struct iwl_cmd)); /* Add buffer containing Tx command and MAC(!) header to TFD's * first entry */ + txcmd_phys += offsetof(struct iwl_cmd, hdr); iwl_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len); if (info->control.hw_key) @@ -940,7 +992,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) len = (u16)skb->len; tx_cmd->len = cpu_to_le16(len); /* TODO need this for burst mode later on */ - iwl_tx_cmd_build_basic(priv, tx_cmd, info, hdr, unicast, sta_id); + iwl_tx_cmd_build_basic(priv, tx_cmd, info, hdr, sta_id); /* set is_hcca to 0; it probably will never be implemented */ iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, sta_id, 0); @@ -950,7 +1002,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) + offsetof(struct iwl_tx_cmd, scratch); tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys); - tx_cmd->dram_msb_ptr = iwl_get_dma_hi_address(scratch_phys); + tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys); if (!ieee80211_has_morefrags(hdr->frame_control)) { txq->need_update = 1; @@ -983,7 +1035,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) iwl_txq_update_write_ptr(priv, txq); spin_unlock_irqrestore(&priv->lock, flags); } else { - ieee80211_stop_queue(priv->hw, swq_id); + ieee80211_stop_queue(priv->hw, txq->swq_id); } } @@ -1011,7 +1063,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) { struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; struct iwl_queue *q = &txq->q; - struct iwl_tfd_frame *tfd; + struct iwl_tfd *tfd; struct iwl_cmd *out_cmd; dma_addr_t phys_addr; unsigned long flags; @@ -1040,7 +1092,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) spin_lock_irqsave(&priv->hcmd_lock, flags); - tfd = &txq->bd[q->write_ptr]; + tfd = &txq->tfds[q->write_ptr]; memset(tfd, 0, sizeof(*tfd)); @@ -1061,9 +1113,13 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) out_cmd->hdr.sequence |= SEQ_HUGE_FRAME; len = (idx == TFD_CMD_SLOTS) ? IWL_MAX_SCAN_SIZE : sizeof(struct iwl_cmd); - phys_addr = pci_map_single(priv->pci_dev, out_cmd, len, - PCI_DMA_TODEVICE); + + phys_addr = pci_map_single(priv->pci_dev, out_cmd, + len, PCI_DMA_TODEVICE); + pci_unmap_addr_set(&out_cmd->meta, mapping, phys_addr); + pci_unmap_len_set(&out_cmd->meta, len, len); phys_addr += offsetof(struct iwl_cmd, hdr); + iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size); #ifdef CONFIG_IWLWIFI_DEBUG @@ -1113,8 +1169,9 @@ int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) return 0; } - for (index = iwl_queue_inc_wrap(index, q->n_bd); q->read_ptr != index; - q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { + for (index = iwl_queue_inc_wrap(index, q->n_bd); + q->read_ptr != index; + q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { tx_info = &txq->txb[txq->q.read_ptr]; ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0]); @@ -1138,44 +1195,34 @@ EXPORT_SYMBOL(iwl_tx_queue_reclaim); * need to be reclaimed. As result, some free space forms. If there is * enough free space (> low mark), wake the stack that feeds us. */ -static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) +static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, + int idx, int cmd_idx) { struct iwl_tx_queue *txq = &priv->txq[txq_id]; struct iwl_queue *q = &txq->q; - struct iwl_tfd_frame *bd = &txq->bd[index]; - dma_addr_t dma_addr; - int is_odd, buf_len; int nfreed = 0; - if ((index >= q->n_bd) || (iwl_queue_used(q, index) == 0)) { + if ((idx >= q->n_bd) || (iwl_queue_used(q, idx) == 0)) { IWL_ERROR("Read index for DMA queue txq id (%d), index %d, " "is out of range [0-%d] %d %d.\n", txq_id, - index, q->n_bd, q->write_ptr, q->read_ptr); + idx, q->n_bd, q->write_ptr, q->read_ptr); return; } - for (index = iwl_queue_inc_wrap(index, q->n_bd); q->read_ptr != index; - q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { + pci_unmap_single(priv->pci_dev, + pci_unmap_addr(&txq->cmd[cmd_idx]->meta, mapping), + pci_unmap_len(&txq->cmd[cmd_idx]->meta, len), + PCI_DMA_TODEVICE); + + for (idx = iwl_queue_inc_wrap(idx, q->n_bd); q->read_ptr != idx; + q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { - if (nfreed > 1) { - IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index, + if (nfreed++ > 0) { + IWL_ERROR("HCMD skipped: index (%d) %d %d\n", idx, q->write_ptr, q->read_ptr); queue_work(priv->workqueue, &priv->restart); } - is_odd = (index/2) & 0x1; - if (is_odd) { - dma_addr = IWL_GET_BITS(bd->pa[index], tb2_addr_lo16) | - (IWL_GET_BITS(bd->pa[index], - tb2_addr_hi20) << 16); - buf_len = IWL_GET_BITS(bd->pa[index], tb2_len); - } else { - dma_addr = le32_to_cpu(bd->pa[index].tb1_addr); - buf_len = IWL_GET_BITS(bd->pa[index], tb1_len); - } - pci_unmap_single(priv->pci_dev, dma_addr, buf_len, - PCI_DMA_TODEVICE); - nfreed++; } } @@ -1201,8 +1248,13 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) * command queue then there a command routing bug has been introduced * in the queue management code. */ if (WARN(txq_id != IWL_CMD_QUEUE_NUM, - "wrong command queue %d, command id 0x%X\n", txq_id, pkt->hdr.cmd)) + "wrong command queue %d, sequence 0x%X readp=%d writep=%d\n", + txq_id, sequence, + priv->txq[IWL_CMD_QUEUE_NUM].q.read_ptr, + priv->txq[IWL_CMD_QUEUE_NUM].q.write_ptr)) { + iwl_print_hex_dump(priv, IWL_DL_INFO , rxb, 32); return; + } cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge); cmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index]; @@ -1215,7 +1267,7 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) !cmd->meta.u.callback(priv, cmd, rxb->skb)) rxb->skb = NULL; - iwl_hcmd_queue_reclaim(priv, txq_id, index); + iwl_hcmd_queue_reclaim(priv, txq_id, index, cmd_index); if (!(cmd->meta.flags & CMD_ASYNC)) { clear_bit(STATUS_HCMD_ACTIVE, &priv->status); @@ -1248,15 +1300,14 @@ int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn) int ret; unsigned long flags; struct iwl_tid_data *tid_data; - DECLARE_MAC_BUF(mac); if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo))) tx_fifo = default_tid_to_tx_fifo[tid]; else return -EINVAL; - IWL_WARNING("%s on ra = %s tid = %d\n", - __func__, print_mac(mac, ra), tid); + IWL_WARNING("%s on ra = %pM tid = %d\n", + __func__, ra, tid); sta_id = iwl_find_station(priv, ra); if (sta_id == IWL_INVALID_STATION) @@ -1301,7 +1352,6 @@ int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid) struct iwl_tid_data *tid_data; int ret, write_ptr, read_ptr; unsigned long flags; - DECLARE_MAC_BUF(mac); if (!ra) { IWL_ERROR("ra = NULL\n"); @@ -1362,8 +1412,8 @@ int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id) case IWL_EMPTYING_HW_QUEUE_DELBA: /* We are reclaiming the last packet of the */ /* aggregated HW queue */ - if (txq_id == tid_data->agg.txq_id && - q->read_ptr == q->write_ptr) { + if ((txq_id == tid_data->agg.txq_id) && + (q->read_ptr == q->write_ptr)) { u16 ssn = SEQ_TO_SN(tid_data->seq_number); int tx_fifo = default_tid_to_tx_fifo[tid]; IWL_DEBUG_HT("HW queue empty: continue DELBA flow\n"); @@ -1414,7 +1464,7 @@ static int iwl_tx_status_reply_compressed_ba(struct iwl_priv *priv, IWL_DEBUG_TX_REPLY("BA %d %d\n", agg->start_idx, ba_resp->seq_ctl); /* Calculate shift to align block-ack bits with our Tx window bits */ - sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl>>4); + sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl >> 4); if (sh < 0) /* tbw something is wrong with indices */ sh += 0x100; @@ -1436,7 +1486,7 @@ static int iwl_tx_status_reply_compressed_ba(struct iwl_priv *priv, ack = bitmap & (1ULL << i); successes += !!ack; IWL_DEBUG_TX_REPLY("%s ON i=%d idx=%d raw=%d\n", - ack? "ACK":"NACK", i, (agg->start_idx + i) & 0xff, + ack ? "ACK" : "NACK", i, (agg->start_idx + i) & 0xff, agg->start_idx + i); } @@ -1464,10 +1514,11 @@ void iwl_rx_reply_compressed_ba(struct iwl_priv *priv, { struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba; - int index; struct iwl_tx_queue *txq = NULL; struct iwl_ht_agg *agg; - DECLARE_MAC_BUF(mac); + int index; + int sta_id; + int tid; /* "flow" corresponds to Tx queue */ u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); @@ -1482,17 +1533,19 @@ void iwl_rx_reply_compressed_ba(struct iwl_priv *priv, } txq = &priv->txq[scd_flow]; - agg = &priv->stations[ba_resp->sta_id].tid[ba_resp->tid].agg; + sta_id = ba_resp->sta_id; + tid = ba_resp->tid; + agg = &priv->stations[sta_id].tid[tid].agg; /* Find index just before block-ack window */ index = iwl_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd); /* TODO: Need to get this copy more safely - now good for debug */ - IWL_DEBUG_TX_REPLY("REPLY_COMPRESSED_BA [%d]Received from %s, " + IWL_DEBUG_TX_REPLY("REPLY_COMPRESSED_BA [%d] Received from %pM, " "sta_id = %d\n", agg->wait_for_ba, - print_mac(mac, (u8 *) &ba_resp->sta_addr_lo32), + (u8 *) &ba_resp->sta_addr_lo32, ba_resp->sta_id); IWL_DEBUG_TX_REPLY("TID = %d, SeqCtl = %d, bitmap = 0x%llx, scd_flow = " "%d, scd_ssn = %d\n", @@ -1513,18 +1566,15 @@ void iwl_rx_reply_compressed_ba(struct iwl_priv *priv, * transmitted ... if not, it's too late anyway). */ if (txq->q.read_ptr != (ba_resp_scd_ssn & 0xff)) { /* calculate mac80211 ampdu sw queue to wake */ - int ampdu_q = - scd_flow - priv->hw_params.first_ampdu_q + priv->hw->queues; int freed = iwl_tx_queue_reclaim(priv, scd_flow, index); - priv->stations[ba_resp->sta_id]. - tid[ba_resp->tid].tfds_in_queue -= freed; - if (iwl_queue_space(&txq->q) > txq->q.low_mark && - priv->mac80211_registered && - agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) - ieee80211_wake_queue(priv->hw, ampdu_q); - - iwl_txq_check_empty(priv, ba_resp->sta_id, - ba_resp->tid, scd_flow); + priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; + + if ((iwl_queue_space(&txq->q) > txq->q.low_mark) && + priv->mac80211_registered && + (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) + ieee80211_wake_queue(priv->hw, txq->swq_id); + + iwl_txq_check_empty(priv, sta_id, tid, scd_flow); } } EXPORT_SYMBOL(iwl_rx_reply_compressed_ba); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 45a6b0c356953f1d88c32747b322d0dbc253756f..d64580805d6efbef7cb48a5bafec23ca02f55f6d 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -41,6 +41,7 @@ #include #include +#include #include #include @@ -64,11 +65,10 @@ static int iwl3945_tx_queue_update_write_ptr(struct iwl3945_priv *priv, /* module parameters */ static int iwl3945_param_disable_hw_scan; /* def: 0 = use 3945's h/w scan */ -static int iwl3945_param_debug; /* def: 0 = minimal debug log messages */ +static u32 iwl3945_param_debug; /* def: 0 = minimal debug log messages */ static int iwl3945_param_disable; /* def: 0 = enable radio */ static int iwl3945_param_antenna; /* def: 0 = both antennas (use diversity) */ int iwl3945_param_hwcrypto; /* def: 0 = use software encryption */ -static int iwl3945_param_qos_enable = 1; /* def: 1 = use quality of service */ int iwl3945_param_queues_num = IWL39_MAX_NUM_QUEUES; /* def: 8 Tx queues */ /* @@ -93,12 +93,13 @@ int iwl3945_param_queues_num = IWL39_MAX_NUM_QUEUES; /* def: 8 Tx queues */ #define IWLWIFI_VERSION "1.2.26k" VD VS #define DRV_COPYRIGHT "Copyright(c) 2003-2008 Intel Corporation" +#define DRV_AUTHOR "" #define DRV_VERSION IWLWIFI_VERSION MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_VERSION(DRV_VERSION); -MODULE_AUTHOR(DRV_COPYRIGHT); +MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); MODULE_LICENSE("GPL"); static const struct ieee80211_supported_band *iwl3945_get_band( @@ -107,46 +108,6 @@ static const struct ieee80211_supported_band *iwl3945_get_band( return priv->hw->wiphy->bands[band]; } -static int iwl3945_is_empty_essid(const char *essid, int essid_len) -{ - /* Single white space is for Linksys APs */ - if (essid_len == 1 && essid[0] == ' ') - return 1; - - /* Otherwise, if the entire essid is 0, we assume it is hidden */ - while (essid_len) { - essid_len--; - if (essid[essid_len] != '\0') - return 0; - } - - return 1; -} - -static const char *iwl3945_escape_essid(const char *essid, u8 essid_len) -{ - static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; - const char *s = essid; - char *d = escaped; - - if (iwl3945_is_empty_essid(essid, essid_len)) { - memcpy(escaped, "", sizeof("")); - return escaped; - } - - essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE); - while (essid_len--) { - if (*s == '\0') { - *d++ = '\\'; - *d++ = '0'; - s++; - } else - *d++ = *s++; - } - *d = '\0'; - return escaped; -} - /*************** DMA-QUEUE-GENERAL-FUNCTIONS ***** * DMA services * @@ -446,7 +407,6 @@ u8 iwl3945_add_station(struct iwl3945_priv *priv, const u8 *addr, int is_ap, u8 int index = IWL_INVALID_STATION; struct iwl3945_station_entry *station; unsigned long flags_spin; - DECLARE_MAC_BUF(mac); u8 rate; spin_lock_irqsave(&priv->sta_lock, flags_spin); @@ -480,7 +440,7 @@ u8 iwl3945_add_station(struct iwl3945_priv *priv, const u8 *addr, int is_ap, u8 return index; } - IWL_DEBUG_ASSOC("Add STA ID %d: %s\n", index, print_mac(mac, addr)); + IWL_DEBUG_ASSOC("Add STA ID %d: %pM\n", index, addr); station = &priv->stations[index]; station->used = 1; priv->num_stations++; @@ -559,7 +519,7 @@ static inline int iwl3945_is_ready_rf(struct iwl3945_priv *priv) /*************** HOST COMMAND QUEUE FUNCTIONS *****/ -#define IWL_CMD(x) case x : return #x +#define IWL_CMD(x) case x: return #x static const char *get_cmd_string(u8 cmd) { @@ -1063,7 +1023,6 @@ static int iwl3945_commit_rxon(struct iwl3945_priv *priv) /* cast away the const for active_rxon in this function */ struct iwl3945_rxon_cmd *active_rxon = (void *)&priv->active_rxon; int rc = 0; - DECLARE_MAC_BUF(mac); if (!iwl3945_is_alive(priv)) return -1; @@ -1124,11 +1083,11 @@ static int iwl3945_commit_rxon(struct iwl3945_priv *priv) IWL_DEBUG_INFO("Sending RXON\n" "* with%s RXON_FILTER_ASSOC_MSK\n" "* channel = %d\n" - "* bssid = %s\n", + "* bssid = %pM\n", ((priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? "" : "out"), le16_to_cpu(priv->staging_rxon.channel), - print_mac(mac, priv->staging_rxon.bssid_addr)); + priv->staging_rxon.bssid_addr); /* Apply the new configuration */ rc = iwl3945_send_cmd_pdu(priv, REPLY_RXON, @@ -1443,7 +1402,7 @@ static void iwl3945_free_frame(struct iwl3945_priv *priv, struct iwl3945_frame * unsigned int iwl3945_fill_beacon_frame(struct iwl3945_priv *priv, struct ieee80211_hdr *hdr, - const u8 *dest, int left) + int left) { if (!iwl3945_is_associated(priv) || !priv->ibss_beacon || @@ -1459,9 +1418,16 @@ unsigned int iwl3945_fill_beacon_frame(struct iwl3945_priv *priv, return priv->ibss_beacon->len; } -static u8 iwl3945_rate_get_lowest_plcp(int rate_mask) +static u8 iwl3945_rate_get_lowest_plcp(struct iwl3945_priv *priv) { u8 i; + int rate_mask; + + /* Set rate mask*/ + if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) + rate_mask = priv->active_rate_basic & IWL_CCK_RATES_MASK; + else + rate_mask = priv->active_rate_basic & IWL_OFDM_RATES_MASK; for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID; i = iwl3945_rates[i].next_ieee) { @@ -1469,7 +1435,11 @@ static u8 iwl3945_rate_get_lowest_plcp(int rate_mask) return iwl3945_rates[i].plcp; } - return IWL_RATE_INVALID; + /* No valid rate was found. Assign the lowest one */ + if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) + return IWL_RATE_1M_PLCP; + else + return IWL_RATE_6M_PLCP; } static int iwl3945_send_beacon_cmd(struct iwl3945_priv *priv) @@ -1487,16 +1457,7 @@ static int iwl3945_send_beacon_cmd(struct iwl3945_priv *priv) return -ENOMEM; } - if (!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)) { - rate = iwl3945_rate_get_lowest_plcp(priv->active_rate_basic & - 0xFF0); - if (rate == IWL_INVALID_RATE) - rate = IWL_RATE_6M_PLCP; - } else { - rate = iwl3945_rate_get_lowest_plcp(priv->active_rate_basic & 0xF); - if (rate == IWL_INVALID_RATE) - rate = IWL_RATE_1M_PLCP; - } + rate = iwl3945_rate_get_lowest_plcp(priv); frame_size = iwl3945_hw_get_beacon_cmd(priv, frame, rate); @@ -1544,10 +1505,8 @@ int iwl3945_eeprom_init(struct iwl3945_priv *priv) { u16 *e = (u16 *)&priv->eeprom; u32 gp = iwl3945_read32(priv, CSR_EEPROM_GP); - u32 r; int sz = sizeof(priv->eeprom); - int rc; - int i; + int ret; u16 addr; /* The EEPROM structure has several padding buffers within it @@ -1562,29 +1521,28 @@ int iwl3945_eeprom_init(struct iwl3945_priv *priv) } /* Make sure driver (instead of uCode) is allowed to read EEPROM */ - rc = iwl3945_eeprom_acquire_semaphore(priv); - if (rc < 0) { + ret = iwl3945_eeprom_acquire_semaphore(priv); + if (ret < 0) { IWL_ERROR("Failed to acquire EEPROM semaphore.\n"); return -ENOENT; } /* eeprom is an array of 16bit values */ for (addr = 0; addr < sz; addr += sizeof(u16)) { - _iwl3945_write32(priv, CSR_EEPROM_REG, addr << 1); - _iwl3945_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD); - - for (i = 0; i < IWL_EEPROM_ACCESS_TIMEOUT; - i += IWL_EEPROM_ACCESS_DELAY) { - r = _iwl3945_read_direct32(priv, CSR_EEPROM_REG); - if (r & CSR_EEPROM_REG_READ_VALID_MSK) - break; - udelay(IWL_EEPROM_ACCESS_DELAY); - } + u32 r; - if (!(r & CSR_EEPROM_REG_READ_VALID_MSK)) { + _iwl3945_write32(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); + _iwl3945_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD); + ret = iwl3945_poll_direct_bit(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_READ_VALID_MSK, + IWL_EEPROM_ACCESS_TIMEOUT); + if (ret < 0) { IWL_ERROR("Time out reading EEPROM[%d]\n", addr); - return -ETIMEDOUT; + return ret; } + + r = _iwl3945_read_direct32(priv, CSR_EEPROM_REG); e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16)); } @@ -1634,7 +1592,7 @@ static u16 iwl3945_supported_rate_to_ie(u8 *ie, u16 supported_rate, */ static u16 iwl3945_fill_probe_req(struct iwl3945_priv *priv, struct ieee80211_mgmt *frame, - int left, int is_direct) + int left) { int len = 0; u8 *pos = NULL; @@ -1664,20 +1622,6 @@ static u16 iwl3945_fill_probe_req(struct iwl3945_priv *priv, *pos++ = WLAN_EID_SSID; *pos++ = 0; - /* fill in our direct SSID IE... */ - if (is_direct) { - /* ...next IE... */ - left -= 2 + priv->essid_len; - if (left < 0) - return 0; - /* ... fill it in... */ - *pos++ = WLAN_EID_SSID; - *pos++ = priv->essid_len; - memcpy(pos, priv->essid, priv->essid_len); - pos += priv->essid_len; - len += 2 + priv->essid_len; - } - /* fill in supported rate */ /* ...next IE... */ left -= 2; @@ -1746,17 +1690,21 @@ static void iwl3945_reset_qos(struct iwl3945_priv *priv) spin_lock_irqsave(&priv->lock, flags); priv->qos_data.qos_active = 0; - if (priv->iw_mode == NL80211_IFTYPE_ADHOC) { - if (priv->qos_data.qos_enable) - priv->qos_data.qos_active = 1; - if (!(priv->active_rate & 0xfff0)) { - cw_min = 31; - is_legacy = 1; - } - } else if (priv->iw_mode == NL80211_IFTYPE_AP) { - if (priv->qos_data.qos_enable) - priv->qos_data.qos_active = 1; - } else if (!(priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK)) { + /* QoS always active in AP and ADHOC mode + * In STA mode wait for association + */ + if (priv->iw_mode == NL80211_IFTYPE_ADHOC || + priv->iw_mode == NL80211_IFTYPE_AP) + priv->qos_data.qos_active = 1; + else + priv->qos_data.qos_active = 0; + + + /* check for legacy mode */ + if ((priv->iw_mode == NL80211_IFTYPE_ADHOC && + (priv->active_rate & IWL_OFDM_RATES_MASK) == 0) || + (priv->iw_mode == NL80211_IFTYPE_STATION && + (priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK) == 0)) { cw_min = 31; is_legacy = 1; } @@ -1828,9 +1776,6 @@ static void iwl3945_activate_qos(struct iwl3945_priv *priv, u8 force) if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; - if (!priv->qos_data.qos_enable) - return; - spin_lock_irqsave(&priv->lock, flags); priv->qos_data.def_qos_parm.qos_flags = 0; @@ -1846,7 +1791,7 @@ static void iwl3945_activate_qos(struct iwl3945_priv *priv, u8 force) spin_unlock_irqrestore(&priv->lock, flags); if (force || iwl3945_is_associated(priv)) { - IWL_DEBUG_QOS("send QoS cmd with Qos active %d \n", + IWL_DEBUG_QOS("send QoS cmd with QoS active %d \n", priv->qos_data.qos_active); iwl3945_send_qos_params_command(priv, @@ -1870,7 +1815,7 @@ static void iwl3945_activate_qos(struct iwl3945_priv *priv, u8 force) /* default power management (not Tx power) table values */ -/* for tim 0-10 */ +/* for TIM 0-10 */ static struct iwl3945_power_vec_entry range_0[IWL_POWER_AC] = { {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0}, @@ -1880,7 +1825,7 @@ static struct iwl3945_power_vec_entry range_0[IWL_POWER_AC] = { {{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25), SLP_VEC(4, 7, 10, 10, 10)}, 1} }; -/* for tim > 10 */ +/* for TIM > 10 */ static struct iwl3945_power_vec_entry range_1[IWL_POWER_AC] = { {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), @@ -2156,11 +2101,6 @@ static void iwl3945_setup_rxon_timing(struct iwl3945_priv *priv) static int iwl3945_scan_initiate(struct iwl3945_priv *priv) { - if (priv->iw_mode == NL80211_IFTYPE_AP) { - IWL_ERROR("APs don't scan.\n"); - return 0; - } - if (!iwl3945_is_ready_rf(priv)) { IWL_DEBUG_SCAN("Aborting scan due to not ready.\n"); return -EIO; @@ -2230,13 +2170,14 @@ static void iwl3945_set_flags_for_phymode(struct iwl3945_priv *priv, /* * initialize rxon structure with default values from eeprom */ -static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv) +static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv, + int mode) { const struct iwl3945_channel_info *ch_info; memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon)); - switch (priv->iw_mode) { + switch (mode) { case NL80211_IFTYPE_AP: priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP; break; @@ -2259,7 +2200,7 @@ static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv) RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK; break; default: - IWL_ERROR("Unsupported interface type %d\n", priv->iw_mode); + IWL_ERROR("Unsupported interface type %d\n", mode); break; } @@ -2282,8 +2223,7 @@ static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv) * in some case A channels are all non IBSS * in this case force B/G channel */ - if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && - !(is_channel_ibss(ch_info))) + if ((mode == NL80211_IFTYPE_ADHOC) && !(is_channel_ibss(ch_info))) ch_info = &priv->channel_info[0]; priv->staging_rxon.channel = cpu_to_le16(ch_info->channel); @@ -2316,14 +2256,12 @@ static int iwl3945_set_mode(struct iwl3945_priv *priv, int mode) } } - priv->iw_mode = mode; - - iwl3945_connection_init_rx_config(priv); + iwl3945_connection_init_rx_config(priv, mode); memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); iwl3945_clear_stations_table(priv); - /* dont commit rxon if rf-kill is on*/ + /* don't commit rxon if rf-kill is on*/ if (!iwl3945_is_ready_rf(priv)) return -EAGAIN; @@ -2352,7 +2290,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl3945_priv *priv, case ALG_CCMP: cmd->cmd.tx.sec_ctl = TX_CMD_SEC_CCM; memcpy(cmd->cmd.tx.key, keyinfo->key, keyinfo->keylen); - IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n"); + IWL_DEBUG_TX("tx_cmd with AES hwcrypto\n"); break; case ALG_TKIP: @@ -2397,6 +2335,7 @@ static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv, { __le16 fc = hdr->frame_control; __le32 tx_flags = cmd->cmd.tx.tx_flags; + u8 rc_flags = info->control.rates[0].flags; cmd->cmd.tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { @@ -2423,10 +2362,10 @@ static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv, tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; } - if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { + if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) { tx_flags |= TX_CMD_FLG_RTS_MSK; tx_flags &= ~TX_CMD_FLG_CTS_MSK; - } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { + } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { tx_flags &= ~TX_CMD_FLG_RTS_MSK; tx_flags |= TX_CMD_FLG_CTS_MSK; } @@ -2482,8 +2421,6 @@ static int iwl3945_get_sta_id(struct iwl3945_priv *priv, struct ieee80211_hdr *h /* If this frame is going out to an IBSS network, find the station, * or create a new station table entry */ case NL80211_IFTYPE_ADHOC: { - DECLARE_MAC_BUF(mac); - /* Create new station table entry */ sta_id = iwl3945_hw_find_station(priv, hdr->addr1); if (sta_id != IWL_INVALID_STATION) @@ -2494,9 +2431,9 @@ static int iwl3945_get_sta_id(struct iwl3945_priv *priv, struct ieee80211_hdr *h if (sta_id != IWL_INVALID_STATION) return sta_id; - IWL_DEBUG_DROP("Station %s not in station map. " + IWL_DEBUG_DROP("Station %pM not in station map. " "Defaulting to broadcast...\n", - print_mac(mac, hdr->addr1)); + hdr->addr1); iwl3945_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); return priv->hw_setting.bcast_sta_id; } @@ -2579,10 +2516,8 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb) /* Find (or create) index into station table for destination station */ sta_id = iwl3945_get_sta_id(priv, hdr); if (sta_id == IWL_INVALID_STATION) { - DECLARE_MAC_BUF(mac); - - IWL_DEBUG_DROP("Dropping - INVALID STATION: %s\n", - print_mac(mac, hdr->addr1)); + IWL_DEBUG_DROP("Dropping - INVALID STATION: %pM\n", + hdr->addr1); goto drop; } @@ -4019,8 +3954,6 @@ static int iwl3945_tx_queue_update_write_ptr(struct iwl3945_priv *priv, #ifdef CONFIG_IWL3945_DEBUG static void iwl3945_print_rx_config_cmd(struct iwl3945_rxon_cmd *rxon) { - DECLARE_MAC_BUF(mac); - IWL_DEBUG_RADIO("RX CONFIG:\n"); iwl3945_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); IWL_DEBUG_RADIO("u16 channel: 0x%x\n", le16_to_cpu(rxon->channel)); @@ -4031,10 +3964,8 @@ static void iwl3945_print_rx_config_cmd(struct iwl3945_rxon_cmd *rxon) IWL_DEBUG_RADIO("u8 ofdm_basic_rates: 0x%02x\n", rxon->ofdm_basic_rates); IWL_DEBUG_RADIO("u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates); - IWL_DEBUG_RADIO("u8[6] node_addr: %s\n", - print_mac(mac, rxon->node_addr)); - IWL_DEBUG_RADIO("u8[6] bssid_addr: %s\n", - print_mac(mac, rxon->bssid_addr)); + IWL_DEBUG_RADIO("u8[6] node_addr: %pM\n", rxon->node_addr); + IWL_DEBUG_RADIO("u8[6] bssid_addr: %pM\n", rxon->bssid_addr); IWL_DEBUG_RADIO("u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id)); } #endif @@ -4050,7 +3981,7 @@ static void iwl3945_enable_interrupts(struct iwl3945_priv *priv) /* call this function to flush any scheduled tasklet */ static inline void iwl_synchronize_irq(struct iwl3945_priv *priv) { - /* wait to make sure we flush pedding tasklet*/ + /* wait to make sure we flush pending tasklet*/ synchronize_irq(priv->pci_dev->irq); tasklet_kill(&priv->irq_tasklet); } @@ -4373,35 +4304,6 @@ static void iwl3945_irq_tasklet(struct iwl3945_priv *priv) /* Safely ignore these bits for debug checks below */ inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE); - /* HW RF KILL switch toggled (4965 only) */ - if (inta & CSR_INT_BIT_RF_KILL) { - int hw_rf_kill = 0; - if (!(iwl3945_read32(priv, CSR_GP_CNTRL) & - CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) - hw_rf_kill = 1; - - IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL | IWL_DL_ISR, - "RF_KILL bit toggled to %s.\n", - hw_rf_kill ? "disable radio":"enable radio"); - - /* Queue restart only if RF_KILL switch was set to "kill" - * when we loaded driver, and is now set to "enable". - * After we're Alive, RF_KILL gets handled by - * iwl3945_rx_card_state_notif() */ - if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status)) { - clear_bit(STATUS_RF_KILL_HW, &priv->status); - queue_work(priv->workqueue, &priv->restart); - } - - handled |= CSR_INT_BIT_RF_KILL; - } - - /* Chip got too hot and stopped itself (4965 only) */ - if (inta & CSR_INT_BIT_CT_KILL) { - IWL_ERROR("Microcode CT kill error detected.\n"); - handled |= CSR_INT_BIT_CT_KILL; - } - /* Error detected by uCode */ if (inta & CSR_INT_BIT_SW_ERR) { IWL_ERROR("Microcode SW error detected. Restarting 0x%X.\n", @@ -4502,7 +4404,7 @@ static irqreturn_t iwl3945_isr(int irq, void *data) if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) { /* Hardware disappeared */ - IWL_WARNING("HARDWARE GONE?? INTA == 0x%080x\n", inta); + IWL_WARNING("HARDWARE GONE?? INTA == 0x%08x\n", inta); goto unplugged; } @@ -4805,7 +4707,7 @@ static void iwl3945_free_channel_map(struct iwl3945_priv *priv) #define IWL_PASSIVE_DWELL_BASE (100) #define IWL_CHANNEL_TUNE_TIME 5 -#define IWL_SCAN_PROBE_MASK(n) cpu_to_le32((BIT(n) | (BIT(n) - BIT(1)))) +#define IWL_SCAN_PROBE_MASK(n) (BIT(n) | (BIT(n) - BIT(1))) static inline u16 iwl3945_get_active_dwell_time(struct iwl3945_priv *priv, enum ieee80211_band band, @@ -4876,17 +4778,33 @@ static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv, continue; } + scan_ch->active_dwell = cpu_to_le16(active_dwell); + scan_ch->passive_dwell = cpu_to_le16(passive_dwell); + /* If passive , set up for auto-switch + * and use long active_dwell time. + */ if (!is_active || is_channel_passive(ch_info) || - (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN)) + (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN)) { scan_ch->type = 0; /* passive */ - else + if (IWL_UCODE_API(priv->ucode_ver) == 1) + scan_ch->active_dwell = cpu_to_le16(passive_dwell - 1); + } else { scan_ch->type = 1; /* active */ + } - if ((scan_ch->type & 1) && n_probes) - scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes); - - scan_ch->active_dwell = cpu_to_le16(active_dwell); - scan_ch->passive_dwell = cpu_to_le16(passive_dwell); + /* Set direct probe bits. These may be used both for active + * scan channels (probes gets sent right away), + * or for passive channels (probes get se sent only after + * hearing clear Rx packet).*/ + if (IWL_UCODE_API(priv->ucode_ver) >= 2) { + if (n_probes) + scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes); + } else { + /* uCode v1 does not allow setting direct probe bits on + * passive channel. */ + if ((scan_ch->type & 1) && n_probes) + scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes); + } /* Set txpower levels to defaults */ scan_ch->tpc.dsp_atten = 110; @@ -5387,25 +5305,41 @@ static void iwl3945_nic_start(struct iwl3945_priv *priv) static int iwl3945_read_ucode(struct iwl3945_priv *priv) { struct iwl3945_ucode *ucode; - int ret = 0; + int ret = -EINVAL, index; const struct firmware *ucode_raw; /* firmware file name contains uCode/driver compatibility version */ - const char *name = priv->cfg->fw_name; + const char *name_pre = priv->cfg->fw_name_pre; + const unsigned int api_max = priv->cfg->ucode_api_max; + const unsigned int api_min = priv->cfg->ucode_api_min; + char buf[25]; u8 *src; size_t len; - u32 ver, inst_size, data_size, init_size, init_data_size, boot_size; + u32 api_ver, inst_size, data_size, init_size, init_data_size, boot_size; /* Ask kernel firmware_class module to get the boot firmware off disk. * request_firmware() is synchronous, file is in memory on return. */ - ret = request_firmware(&ucode_raw, name, &priv->pci_dev->dev); - if (ret < 0) { - IWL_ERROR("%s firmware file req failed: Reason %d\n", - name, ret); - goto error; + for (index = api_max; index >= api_min; index--) { + sprintf(buf, "%s%u%s", name_pre, index, ".ucode"); + ret = request_firmware(&ucode_raw, buf, &priv->pci_dev->dev); + if (ret < 0) { + IWL_ERROR("%s firmware file req failed: Reason %d\n", + buf, ret); + if (ret == -ENOENT) + continue; + else + goto error; + } else { + if (index < api_max) + IWL_ERROR("Loaded firmware %s, which is deprecated. Please use API v%u instead.\n", + buf, api_max); + IWL_DEBUG_INFO("Got firmware '%s' file (%zd bytes) from disk\n", + buf, ucode_raw->size); + break; + } } - IWL_DEBUG_INFO("Got firmware '%s' file (%zd bytes) from disk\n", - name, ucode_raw->size); + if (ret < 0) + goto error; /* Make sure that we got at least our header! */ if (ucode_raw->size < sizeof(*ucode)) { @@ -5417,20 +5351,46 @@ static int iwl3945_read_ucode(struct iwl3945_priv *priv) /* Data from ucode file: header followed by uCode images */ ucode = (void *)ucode_raw->data; - ver = le32_to_cpu(ucode->ver); + priv->ucode_ver = le32_to_cpu(ucode->ver); + api_ver = IWL_UCODE_API(priv->ucode_ver); inst_size = le32_to_cpu(ucode->inst_size); data_size = le32_to_cpu(ucode->data_size); init_size = le32_to_cpu(ucode->init_size); init_data_size = le32_to_cpu(ucode->init_data_size); boot_size = le32_to_cpu(ucode->boot_size); - IWL_DEBUG_INFO("f/w package hdr ucode version = 0x%x\n", ver); + /* api_ver should match the api version forming part of the + * firmware filename ... but we don't check for that and only rely + * on the API version read from firware header from here on forward */ + + if (api_ver < api_min || api_ver > api_max) { + IWL_ERROR("Driver unable to support your firmware API. " + "Driver supports v%u, firmware is v%u.\n", + api_max, api_ver); + priv->ucode_ver = 0; + ret = -EINVAL; + goto err_release; + } + if (api_ver != api_max) + IWL_ERROR("Firmware has old API version. Expected %u, " + "got %u. New firmware can be obtained " + "from http://www.intellinuxwireless.org.\n", + api_max, api_ver); + + printk(KERN_INFO DRV_NAME " loaded firmware version %u.%u.%u.%u\n", + IWL_UCODE_MAJOR(priv->ucode_ver), + IWL_UCODE_MINOR(priv->ucode_ver), + IWL_UCODE_API(priv->ucode_ver), + IWL_UCODE_SERIAL(priv->ucode_ver)); + IWL_DEBUG_INFO("f/w package hdr ucode version raw = 0x%x\n", + priv->ucode_ver); IWL_DEBUG_INFO("f/w package hdr runtime inst size = %u\n", inst_size); IWL_DEBUG_INFO("f/w package hdr runtime data size = %u\n", data_size); IWL_DEBUG_INFO("f/w package hdr init inst size = %u\n", init_size); IWL_DEBUG_INFO("f/w package hdr init data size = %u\n", init_data_size); IWL_DEBUG_INFO("f/w package hdr boot inst size = %u\n", boot_size); + /* Verify size of file vs. image size info in file's header */ if (ucode_raw->size < sizeof(*ucode) + inst_size + data_size + init_size + @@ -5607,7 +5567,7 @@ static int iwl3945_set_ucode_ptrs(struct iwl3945_priv *priv) iwl3945_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG, priv->ucode_data.len); - /* Inst bytecount must be last to set up, bit 31 signals uCode + /* Inst byte count must be last to set up, bit 31 signals uCode * that all new ptr/size info is in place */ iwl3945_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, priv->ucode_code.len | BSM_DRAM_INST_LOAD); @@ -5665,6 +5625,10 @@ static void iwl3945_init_alive_start(struct iwl3945_priv *priv) } +/* temporary */ +static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, + struct sk_buff *skb); + /** * iwl3945_alive_start - called after REPLY_ALIVE notification received * from protocol/runtime uCode (initialization uCode's @@ -5699,7 +5663,7 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv) rc = iwl3945_grab_nic_access(priv); if (rc) { - IWL_WARNING("Can not read rfkill status from adapter\n"); + IWL_WARNING("Can not read RFKILL status from adapter\n"); return; } @@ -5709,7 +5673,7 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv) if (rfkill & 0x1) { clear_bit(STATUS_RF_KILL_HW, &priv->status); - /* if rfkill is not on, then wait for thermal + /* if RFKILL is not on, then wait for thermal * sensor in adapter to kick in */ while (iwl3945_hw_get_temperature(priv) == 0) { thermal_spin++; @@ -5747,7 +5711,7 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv) active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; } else { /* Initialize our rx_config data */ - iwl3945_connection_init_rx_config(priv); + iwl3945_connection_init_rx_config(priv, priv->iw_mode); memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); } @@ -5768,6 +5732,14 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv) if (priv->error_recovering) iwl3945_error_recovery(priv); + /* reassociate for ADHOC mode */ + if (priv->vif && (priv->iw_mode == NL80211_IFTYPE_ADHOC)) { + struct sk_buff *beacon = ieee80211_beacon_get(priv->hw, + priv->vif); + if (beacon) + iwl3945_mac_beacon_update(priv->hw, beacon); + } + return; restart: @@ -5902,7 +5874,7 @@ static int __iwl3945_up(struct iwl3945_priv *priv) } if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) { - IWL_ERROR("ucode not available for device bringup\n"); + IWL_ERROR("ucode not available for device bring up\n"); return -EIO; } @@ -6046,24 +6018,6 @@ static void iwl3945_bg_rf_kill(struct work_struct *work) iwl3945_rfkill_set_hw_state(priv); } -static void iwl3945_bg_set_monitor(struct work_struct *work) -{ - struct iwl3945_priv *priv = container_of(work, - struct iwl3945_priv, set_monitor); - - IWL_DEBUG(IWL_DL_STATE, "setting monitor mode\n"); - - mutex_lock(&priv->mutex); - - if (!iwl3945_is_ready(priv)) - IWL_DEBUG(IWL_DL_STATE, "leave - not ready\n"); - else - if (iwl3945_set_mode(priv, NL80211_IFTYPE_MONITOR) != 0) - IWL_ERROR("iwl3945_set_mode() failed\n"); - - mutex_unlock(&priv->mutex); -} - #define IWL_SCAN_CHECK_WATCHDOG (7 * HZ) static void iwl3945_bg_scan_check(struct work_struct *data) @@ -6101,6 +6055,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data) struct ieee80211_conf *conf = NULL; u8 n_probes = 2; enum ieee80211_band band; + DECLARE_SSID_BUF(ssid); conf = ieee80211_get_hw_conf(priv->hw); @@ -6111,7 +6066,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data) goto done; } - /* Make sure the scan wasn't cancelled before this queued work + /* Make sure the scan wasn't canceled before this queued work * was given the chance to run... */ if (!test_bit(STATUS_SCANNING, &priv->status)) goto done; @@ -6201,21 +6156,13 @@ static void iwl3945_bg_request_scan(struct work_struct *data) if (priv->one_direct_scan) { IWL_DEBUG_SCAN ("Kicking off one direct scan for '%s'\n", - iwl3945_escape_essid(priv->direct_ssid, - priv->direct_ssid_len)); + print_ssid(ssid, priv->direct_ssid, + priv->direct_ssid_len)); scan->direct_scan[0].id = WLAN_EID_SSID; scan->direct_scan[0].len = priv->direct_ssid_len; memcpy(scan->direct_scan[0].ssid, priv->direct_ssid, priv->direct_ssid_len); n_probes++; - } else if (!iwl3945_is_associated(priv) && priv->essid_len) { - IWL_DEBUG_SCAN - ("Kicking off one direct scan for '%s' when not associated\n", - iwl3945_escape_essid(priv->essid, priv->essid_len)); - scan->direct_scan[0].id = WLAN_EID_SSID; - scan->direct_scan[0].len = priv->essid_len; - memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len); - n_probes++; } else IWL_DEBUG_SCAN("Kicking off one indirect scan.\n"); @@ -6223,7 +6170,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data) * that based on the direct_mask added to each channel entry */ scan->tx_cmd.len = cpu_to_le16( iwl3945_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data, - IWL_MAX_SCAN_SIZE - sizeof(*scan), 0)); + IWL_MAX_SCAN_SIZE - sizeof(*scan))); scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; scan->tx_cmd.sta_id = priv->hw_setting.bcast_sta_id; scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; @@ -6333,7 +6280,6 @@ static void iwl3945_post_associate(struct iwl3945_priv *priv) { int rc = 0; struct ieee80211_conf *conf = NULL; - DECLARE_MAC_BUF(mac); if (priv->iw_mode == NL80211_IFTYPE_AP) { IWL_ERROR("%s Should not be called in AP mode\n", __func__); @@ -6341,9 +6287,8 @@ static void iwl3945_post_associate(struct iwl3945_priv *priv) } - IWL_DEBUG_ASSOC("Associated as %d to: %s\n", - priv->assoc_id, - print_mac(mac, priv->active_rxon.bssid_addr)); + IWL_DEBUG_ASSOC("Associated as %d to: %pM\n", + priv->assoc_id, priv->active_rxon.bssid_addr); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; @@ -6398,10 +6343,7 @@ static void iwl3945_post_associate(struct iwl3945_priv *priv) case NL80211_IFTYPE_ADHOC: - /* clear out the station table */ - iwl3945_clear_stations_table(priv); - - iwl3945_add_station(priv, iwl3945_broadcast_addr, 0, 0); + priv->assoc_id = 1; iwl3945_add_station(priv, priv->bssid, 0, 0); iwl3945_sync_sta(priv, IWL_STA_ID, (priv->band == IEEE80211_BAND_5GHZ) ? @@ -6439,7 +6381,7 @@ static void iwl3945_bg_abort_scan(struct work_struct *work) mutex_unlock(&priv->mutex); } -static int iwl3945_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf); +static int iwl3945_mac_config(struct ieee80211_hw *hw, u32 changed); static void iwl3945_bg_scan_completed(struct work_struct *work) { @@ -6452,7 +6394,7 @@ static void iwl3945_bg_scan_completed(struct work_struct *work) return; if (test_bit(STATUS_CONF_PENDING, &priv->status)) - iwl3945_mac_config(priv->hw, ieee80211_get_hw_conf(priv->hw)); + iwl3945_mac_config(priv->hw, 0); ieee80211_scan_completed(priv->hw); @@ -6604,7 +6546,6 @@ static int iwl3945_mac_add_interface(struct ieee80211_hw *hw, { struct iwl3945_priv *priv = hw->priv; unsigned long flags; - DECLARE_MAC_BUF(mac); IWL_DEBUG_MAC80211("enter: type %d\n", conf->type); @@ -6615,13 +6556,14 @@ static int iwl3945_mac_add_interface(struct ieee80211_hw *hw, spin_lock_irqsave(&priv->lock, flags); priv->vif = conf->vif; + priv->iw_mode = conf->type; spin_unlock_irqrestore(&priv->lock, flags); mutex_lock(&priv->mutex); if (conf->mac_addr) { - IWL_DEBUG_MAC80211("Set: %s\n", print_mac(mac, conf->mac_addr)); + IWL_DEBUG_MAC80211("Set: %pM\n", conf->mac_addr); memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); } @@ -6641,10 +6583,11 @@ static int iwl3945_mac_add_interface(struct ieee80211_hw *hw, * be set inappropriately and the driver currently sets the hardware up to * use it whenever needed. */ -static int iwl3945_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +static int iwl3945_mac_config(struct ieee80211_hw *hw, u32 changed) { struct iwl3945_priv *priv = hw->priv; const struct iwl3945_channel_info *ch_info; + struct ieee80211_conf *conf = &hw->conf; unsigned long flags; int ret = 0; @@ -6782,16 +6725,11 @@ static void iwl3945_config_ap(struct iwl3945_priv *priv) * clear sta table, add BCAST sta... */ } -/* temporary */ -static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb); - static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_if_conf *conf) { struct iwl3945_priv *priv = hw->priv; - DECLARE_MAC_BUF(mac); - unsigned long flags; int rc; if (conf == NULL) @@ -6808,28 +6746,20 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); if (!beacon) return -ENOMEM; + mutex_lock(&priv->mutex); rc = iwl3945_mac_beacon_update(hw, beacon); + mutex_unlock(&priv->mutex); if (rc) return rc; } - /* XXX: this MUST use conf->mac_addr */ - - if ((priv->iw_mode == NL80211_IFTYPE_AP) && - (!conf->ssid_len)) { - IWL_DEBUG_MAC80211 - ("Leaving in AP mode because HostAPD is not ready.\n"); - return 0; - } - if (!iwl3945_is_alive(priv)) return -EAGAIN; mutex_lock(&priv->mutex); if (conf->bssid) - IWL_DEBUG_MAC80211("bssid: %s\n", - print_mac(mac, conf->bssid)); + IWL_DEBUG_MAC80211("bssid: %pM\n", conf->bssid); /* * very dubious code was here; the probe filtering flag is never set: @@ -6842,8 +6772,8 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, if (!conf->bssid) { conf->bssid = priv->mac_addr; memcpy(priv->bssid, priv->mac_addr, ETH_ALEN); - IWL_DEBUG_MAC80211("bssid was set to: %s\n", - print_mac(mac, conf->bssid)); + IWL_DEBUG_MAC80211("bssid was set to: %pM\n", + conf->bssid); } if (priv->ibss_beacon) dev_kfree_skb(priv->ibss_beacon); @@ -6889,15 +6819,6 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, } done: - spin_lock_irqsave(&priv->lock, flags); - if (!conf->ssid_len) - memset(priv->essid, 0, IW_ESSID_MAX_SIZE); - else - memcpy(priv->essid, conf->ssid, conf->ssid_len); - - priv->essid_len = conf->ssid_len; - spin_unlock_irqrestore(&priv->lock, flags); - IWL_DEBUG_MAC80211("leave\n"); mutex_unlock(&priv->mutex); @@ -6910,16 +6831,43 @@ static void iwl3945_configure_filter(struct ieee80211_hw *hw, int mc_count, struct dev_addr_list *mc_list) { struct iwl3945_priv *priv = hw->priv; + __le32 *filter_flags = &priv->staging_rxon.filter_flags; - if (changed_flags & (*total_flags) & FIF_OTHER_BSS) { - IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n", - NL80211_IFTYPE_MONITOR, - changed_flags, *total_flags); - /* queue work 'cuz mac80211 is holding a lock which - * prevents us from issuing (synchronous) f/w cmds */ - queue_work(priv->workqueue, &priv->set_monitor); + IWL_DEBUG_MAC80211("Enter: changed: 0x%x, total: 0x%x\n", + changed_flags, *total_flags); + + if (changed_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS)) { + if (*total_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS)) + *filter_flags |= RXON_FILTER_PROMISC_MSK; + else + *filter_flags &= ~RXON_FILTER_PROMISC_MSK; } - *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | + if (changed_flags & FIF_ALLMULTI) { + if (*total_flags & FIF_ALLMULTI) + *filter_flags |= RXON_FILTER_ACCEPT_GRP_MSK; + else + *filter_flags &= ~RXON_FILTER_ACCEPT_GRP_MSK; + } + if (changed_flags & FIF_CONTROL) { + if (*total_flags & FIF_CONTROL) + *filter_flags |= RXON_FILTER_CTL2HOST_MSK; + else + *filter_flags &= ~RXON_FILTER_CTL2HOST_MSK; + } + if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { + if (*total_flags & FIF_BCN_PRBRESP_PROMISC) + *filter_flags |= RXON_FILTER_BCON_AWARE_MSK; + else + *filter_flags &= ~RXON_FILTER_BCON_AWARE_MSK; + } + + /* We avoid iwl_commit_rxon here to commit the new filter flags + * since mac80211 will call ieee80211_hw_config immediately. + * (mc_list is not supported at this time). Otherwise, we need to + * queue a background iwl_commit_rxon work. + */ + + *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS | FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; } @@ -6940,8 +6888,6 @@ static void iwl3945_mac_remove_interface(struct ieee80211_hw *hw, if (priv->vif == conf->vif) { priv->vif = NULL; memset(priv->bssid, 0, ETH_ALEN); - memset(priv->essid, 0, IW_ESSID_MAX_SIZE); - priv->essid_len = 0; } mutex_unlock(&priv->mutex); @@ -7010,6 +6956,7 @@ static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) int rc = 0; unsigned long flags; struct iwl3945_priv *priv = hw->priv; + DECLARE_SSID_BUF(ssid_buf); IWL_DEBUG_MAC80211("enter\n"); @@ -7022,12 +6969,6 @@ static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) goto out_unlock; } - if (priv->iw_mode == NL80211_IFTYPE_AP) { /* APs don't scan */ - rc = -EIO; - IWL_ERROR("ERROR: APs don't scan\n"); - goto out_unlock; - } - /* we don't schedule scan within next_scan_jiffies period */ if (priv->next_scan_jiffies && time_after(priv->next_scan_jiffies, jiffies)) { @@ -7043,7 +6984,7 @@ static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) } if (len) { IWL_DEBUG_SCAN("direct scan for %s [%d]\n ", - iwl3945_escape_essid(ssid, len), (int)len); + print_ssid(ssid_buf, ssid, len), (int)len); priv->one_direct_scan = 1; priv->direct_ssid_len = (u8) @@ -7084,10 +7025,8 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, sta_id = iwl3945_hw_find_station(priv, addr); if (sta_id == IWL_INVALID_STATION) { - DECLARE_MAC_BUF(mac); - - IWL_DEBUG_MAC80211("leave - %s not in station map.\n", - print_mac(mac, addr)); + IWL_DEBUG_MAC80211("leave - %pM not in station map.\n", + addr); return -EINVAL; } @@ -7143,11 +7082,6 @@ static int iwl3945_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, return 0; } - if (!priv->qos_data.qos_enable) { - priv->qos_data.qos_active = 0; - IWL_DEBUG_MAC80211("leave - qos not enabled\n"); - return 0; - } q = AC_NUM - 1 - queue; spin_lock_irqsave(&priv->lock, flags); @@ -7219,14 +7153,6 @@ static int iwl3945_mac_get_stats(struct ieee80211_hw *hw, return 0; } -static u64 iwl3945_mac_get_tsf(struct ieee80211_hw *hw) -{ - IWL_DEBUG_MAC80211("enter\n"); - IWL_DEBUG_MAC80211("leave\n"); - - return 0; -} - static void iwl3945_mac_reset_tsf(struct ieee80211_hw *hw) { struct iwl3945_priv *priv = hw->priv; @@ -7292,18 +7218,15 @@ static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk struct iwl3945_priv *priv = hw->priv; unsigned long flags; - mutex_lock(&priv->mutex); IWL_DEBUG_MAC80211("enter\n"); if (!iwl3945_is_ready_rf(priv)) { IWL_DEBUG_MAC80211("leave - RF not ready\n"); - mutex_unlock(&priv->mutex); return -EIO; } if (priv->iw_mode != NL80211_IFTYPE_ADHOC) { IWL_DEBUG_MAC80211("leave - not IBSS\n"); - mutex_unlock(&priv->mutex); return -EIO; } @@ -7323,7 +7246,6 @@ static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk iwl3945_post_associate(priv); - mutex_unlock(&priv->mutex); return 0; } @@ -7792,7 +7714,7 @@ static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log); /***************************************************************************** * - * driver setup and teardown + * driver setup and tear down * *****************************************************************************/ @@ -7810,7 +7732,6 @@ static void iwl3945_setup_deferred_work(struct iwl3945_priv *priv) INIT_WORK(&priv->abort_scan, iwl3945_bg_abort_scan); INIT_WORK(&priv->rf_kill, iwl3945_bg_rf_kill); INIT_WORK(&priv->beacon_update, iwl3945_bg_beacon_update); - INIT_WORK(&priv->set_monitor, iwl3945_bg_set_monitor); INIT_DELAYED_WORK(&priv->init_alive_start, iwl3945_bg_init_alive_start); INIT_DELAYED_WORK(&priv->alive_start, iwl3945_bg_alive_start); INIT_DELAYED_WORK(&priv->scan_check, iwl3945_bg_scan_check); @@ -7869,7 +7790,6 @@ static struct ieee80211_ops iwl3945_hw_ops = { .get_stats = iwl3945_mac_get_stats, .get_tx_stats = iwl3945_mac_get_tx_stats, .conf_tx = iwl3945_mac_conf_tx, - .get_tsf = iwl3945_mac_get_tsf, .reset_tsf = iwl3945_mac_reset_tsf, .bss_info_changed = iwl3945_bss_info_changed, .hw_scan = iwl3945_mac_hw_scan @@ -7882,7 +7802,10 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e struct ieee80211_hw *hw; struct iwl_3945_cfg *cfg = (struct iwl_3945_cfg *)(ent->driver_data); unsigned long flags; - DECLARE_MAC_BUF(mac); + + /*********************** + * 1. Allocating HW data + * ********************/ /* Disabling hardware scan means that mac80211 will perform scans * "the hard way", rather than using device's scan. */ @@ -7907,48 +7830,41 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e err = -ENOMEM; goto out; } - SET_IEEE80211_DEV(hw, &pdev->dev); - hw->rate_control_algorithm = "iwl-3945-rs"; - hw->sta_data_size = sizeof(struct iwl3945_sta_priv); + SET_IEEE80211_DEV(hw, &pdev->dev); - IWL_DEBUG_INFO("*** LOAD DRIVER ***\n"); priv = hw->priv; priv->hw = hw; - priv->pci_dev = pdev; priv->cfg = cfg; + IWL_DEBUG_INFO("*** LOAD DRIVER ***\n"); + hw->rate_control_algorithm = "iwl-3945-rs"; + hw->sta_data_size = sizeof(struct iwl3945_sta_priv); + /* Select antenna (may be helpful if only one antenna is connected) */ priv->antenna = (enum iwl3945_antenna)iwl3945_param_antenna; #ifdef CONFIG_IWL3945_DEBUG iwl3945_debug_level = iwl3945_param_debug; atomic_set(&priv->restrict_refcnt, 0); #endif - priv->retry_rate = 1; - - priv->ibss_beacon = NULL; /* Tell mac80211 our characteristics */ hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; hw->wiphy->interface_modes = - BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); + hw->wiphy->fw_handles_regulatory = true; + /* 4 EDCA QOS priorities */ hw->queues = 4; - spin_lock_init(&priv->lock); - spin_lock_init(&priv->power_data.lock); - spin_lock_init(&priv->sta_lock); - spin_lock_init(&priv->hcmd_lock); - - INIT_LIST_HEAD(&priv->free_frames); - - mutex_init(&priv->mutex); + /*************************** + * 2. Initializing PCI bus + * *************************/ if (pci_enable_device(pdev)) { err = -ENODEV; goto out_ieee80211_free_hw; @@ -7956,14 +7872,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e pci_set_master(pdev); - /* Clear the driver's (not device's) station table */ - iwl3945_clear_stations_table(priv); - - priv->data_retry_limit = -1; - priv->ieee_channels = NULL; - priv->ieee_rates = NULL; - priv->band = IEEE80211_BAND_2GHZ; - err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); if (!err) err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); @@ -7977,10 +7885,9 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e if (err) goto out_pci_disable_device; - /* We disable the RETRY_TIMEOUT register (0x41) to keep - * PCI Tx retries from interfering with C3 CPU state */ - pci_write_config_byte(pdev, 0x41, 0x00); - + /*********************** + * 3. Read REV Register + * ********************/ priv->hw_base = pci_iomap(pdev, 0, 0); if (!priv->hw_base) { err = -ENODEV; @@ -7991,97 +7898,144 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e (unsigned long long) pci_resource_len(pdev, 0)); IWL_DEBUG_INFO("pci_resource_base = %p\n", priv->hw_base); - /* Initialize module parameter values here */ + /* We disable the RETRY_TIMEOUT register (0x41) to keep + * PCI Tx retries from interfering with C3 CPU state */ + pci_write_config_byte(pdev, 0x41, 0x00); - /* Disable radio (SW RF KILL) via parameter when loading driver */ - if (iwl3945_param_disable) { - set_bit(STATUS_RF_KILL_SW, &priv->status); - IWL_DEBUG_INFO("Radio disabled.\n"); - } + /* nic init */ + iwl3945_set_bit(priv, CSR_GIO_CHICKEN_BITS, + CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); - priv->iw_mode = NL80211_IFTYPE_STATION; + iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + err = iwl3945_poll_direct_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + if (err < 0) { + IWL_DEBUG_INFO("Failed to init the card\n"); + goto out_remove_sysfs; + } - printk(KERN_INFO DRV_NAME - ": Detected Intel Wireless WiFi Link %s\n", priv->cfg->name); + /*********************** + * 4. Read EEPROM + * ********************/ + /* Read the EEPROM */ + err = iwl3945_eeprom_init(priv); + if (err) { + IWL_ERROR("Unable to init EEPROM\n"); + goto out_remove_sysfs; + } + /* MAC Address location in EEPROM same for 3945/4965 */ + get_eeprom_mac(priv, priv->mac_addr); + IWL_DEBUG_INFO("MAC address: %pM\n", priv->mac_addr); + SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr); + /*********************** + * 5. Setup HW Constants + * ********************/ /* Device-specific setup */ if (iwl3945_hw_set_hw_setting(priv)) { IWL_ERROR("failed to set hw settings\n"); goto out_iounmap; } - if (iwl3945_param_qos_enable) - priv->qos_data.qos_enable = 1; + /*********************** + * 6. Setup priv + * ********************/ + priv->retry_rate = 1; + priv->ibss_beacon = NULL; + + spin_lock_init(&priv->lock); + spin_lock_init(&priv->power_data.lock); + spin_lock_init(&priv->sta_lock); + spin_lock_init(&priv->hcmd_lock); + + INIT_LIST_HEAD(&priv->free_frames); + mutex_init(&priv->mutex); + + /* Clear the driver's (not device's) station table */ + iwl3945_clear_stations_table(priv); + + priv->data_retry_limit = -1; + priv->ieee_channels = NULL; + priv->ieee_rates = NULL; + priv->band = IEEE80211_BAND_2GHZ; + + priv->iw_mode = NL80211_IFTYPE_STATION; iwl3945_reset_qos(priv); priv->qos_data.qos_active = 0; priv->qos_data.qos_cap.val = 0; - iwl3945_set_rxon_channel(priv, IEEE80211_BAND_2GHZ, 6); - iwl3945_setup_deferred_work(priv); - iwl3945_setup_rx_handlers(priv); priv->rates_mask = IWL_RATES_MASK; /* If power management is turned on, default to AC mode */ priv->power_mode = IWL_POWER_AC; priv->user_txpower_limit = IWL_DEFAULT_TX_POWER; - spin_lock_irqsave(&priv->lock, flags); - iwl3945_disable_interrupts(priv); - spin_unlock_irqrestore(&priv->lock, flags); - - err = sysfs_create_group(&pdev->dev.kobj, &iwl3945_attribute_group); + err = iwl3945_init_channel_map(priv); if (err) { - IWL_ERROR("failed to create sysfs device attributes\n"); + IWL_ERROR("initializing regulatory failed: %d\n", err); goto out_release_irq; } - /* nic init */ - iwl3945_set_bit(priv, CSR_GIO_CHICKEN_BITS, - CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); - - iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - err = iwl3945_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); - if (err < 0) { - IWL_DEBUG_INFO("Failed to init the card\n"); - goto out_remove_sysfs; - } - /* Read the EEPROM */ - err = iwl3945_eeprom_init(priv); + err = iwl3945_init_geos(priv); if (err) { - IWL_ERROR("Unable to init EEPROM\n"); - goto out_remove_sysfs; + IWL_ERROR("initializing geos failed: %d\n", err); + goto out_free_channel_map; } - /* MAC Address location in EEPROM same for 3945/4965 */ - get_eeprom_mac(priv, priv->mac_addr); - IWL_DEBUG_INFO("MAC address: %s\n", print_mac(mac, priv->mac_addr)); - SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr); - err = iwl3945_init_channel_map(priv); - if (err) { - IWL_ERROR("initializing regulatory failed: %d\n", err); - goto out_remove_sysfs; + printk(KERN_INFO DRV_NAME + ": Detected Intel Wireless WiFi Link %s\n", priv->cfg->name); + + /*********************************** + * 7. Initialize Module Parameters + * **********************************/ + + /* Initialize module parameter values here */ + /* Disable radio (SW RF KILL) via parameter when loading driver */ + if (iwl3945_param_disable) { + set_bit(STATUS_RF_KILL_SW, &priv->status); + IWL_DEBUG_INFO("Radio disabled.\n"); } - err = iwl3945_init_geos(priv); + + /*********************** + * 8. Setup Services + * ********************/ + + spin_lock_irqsave(&priv->lock, flags); + iwl3945_disable_interrupts(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + err = sysfs_create_group(&pdev->dev.kobj, &iwl3945_attribute_group); if (err) { - IWL_ERROR("initializing geos failed: %d\n", err); - goto out_free_channel_map; + IWL_ERROR("failed to create sysfs device attributes\n"); + goto out_free_geos; } + iwl3945_set_rxon_channel(priv, IEEE80211_BAND_2GHZ, 6); + iwl3945_setup_deferred_work(priv); + iwl3945_setup_rx_handlers(priv); + + /*********************** + * 9. Conclude + * ********************/ + pci_save_state(pdev); + pci_disable_device(pdev); + + /********************************* + * 10. Setup and Register mac80211 + * *******************************/ + err = ieee80211_register_hw(priv->hw); if (err) { IWL_ERROR("Failed to register network device (error %d)\n", err); - goto out_free_geos; + goto out_remove_sysfs; } priv->hw->conf.beacon_int = 100; priv->mac80211_registered = 1; - pci_save_state(pdev); - pci_disable_device(pdev); + err = iwl3945_rfkill_init(priv); if (err) @@ -8090,12 +8044,13 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e return 0; + out_remove_sysfs: + sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group); out_free_geos: iwl3945_free_geos(priv); out_free_channel_map: iwl3945_free_channel_map(priv); - out_remove_sysfs: - sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group); + out_release_irq: destroy_workqueue(priv->workqueue); @@ -8222,7 +8177,7 @@ static int iwl3945_rfkill_soft_rf_kill(void *data, enum rfkill_state state) if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return 0; - IWL_DEBUG_RF_KILL("we recieved soft RFKILL set to state %d\n", state); + IWL_DEBUG_RF_KILL("we received soft RFKILL set to state %d\n", state); mutex_lock(&priv->mutex); switch (state) { @@ -8237,7 +8192,7 @@ static int iwl3945_rfkill_soft_rf_kill(void *data, enum rfkill_state state) iwl3945_radio_kill_sw(priv, 1); break; default: - IWL_WARNING("we recieved unexpected RFKILL state %d\n", state); + IWL_WARNING("we received unexpected RFKILL state %d\n", state); break; } out_unlock: @@ -8379,7 +8334,7 @@ static void __exit iwl3945_exit(void) iwl3945_rate_control_unregister(); } -MODULE_FIRMWARE("iwlwifi-3945" IWL3945_UCODE_API ".ucode"); +MODULE_FIRMWARE(IWL3945_MODULE_FIRMWARE(IWL3945_UCODE_API_MAX)); module_param_named(antenna, iwl3945_param_antenna, int, 0444); MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])"); @@ -8388,7 +8343,7 @@ MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])"); module_param_named(hwcrypto, iwl3945_param_hwcrypto, int, 0444); MODULE_PARM_DESC(hwcrypto, "using hardware crypto engine (default 0 [software])\n"); -module_param_named(debug, iwl3945_param_debug, int, 0444); +module_param_named(debug, iwl3945_param_debug, uint, 0444); MODULE_PARM_DESC(debug, "debug output mask"); module_param_named(disable_hw_scan, iwl3945_param_disable_hw_scan, int, 0444); MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); @@ -8396,9 +8351,5 @@ MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); module_param_named(queues_num, iwl3945_param_queues_num, int, 0444); MODULE_PARM_DESC(queues_num, "number of hw queues."); -/* QoS */ -module_param_named(qos_enable, iwl3945_param_qos_enable, int, 0444); -MODULE_PARM_DESC(qos_enable, "enable all QoS functionality"); - module_exit(iwl3945_exit); module_init(iwl3945_init); diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 92be60415d043e041384bdaeea082f440a9123fb..a0e440cd8967ec55c53ae17b948d678d6c5b7959 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -1,6 +1,10 @@ /* Copyright (C) 2006, Red Hat, Inc. */ +#include #include +#include +#include +#include #include "assoc.h" #include "decl.h" @@ -151,18 +155,18 @@ static int lbs_adhoc_join(struct lbs_private *priv, struct cmd_ds_802_11_ad_hoc_join cmd; struct bss_descriptor *bss = &assoc_req->bss; u8 preamble = RADIO_PREAMBLE_LONG; - DECLARE_MAC_BUF(mac); + DECLARE_SSID_BUF(ssid); u16 ratesize = 0; int ret = 0; lbs_deb_enter(LBS_DEB_ASSOC); lbs_deb_join("current SSID '%s', ssid length %u\n", - escape_essid(priv->curbssparams.ssid, + print_ssid(ssid, priv->curbssparams.ssid, priv->curbssparams.ssid_len), priv->curbssparams.ssid_len); lbs_deb_join("requested ssid '%s', ssid length %u\n", - escape_essid(bss->ssid, bss->ssid_len), + print_ssid(ssid, bss->ssid, bss->ssid_len), bss->ssid_len); /* check if the requested SSID is already joined */ @@ -226,8 +230,8 @@ static int lbs_adhoc_join(struct lbs_private *priv, bss->capability, CAPINFO_MASK); /* information on BSSID descriptor passed to FW */ - lbs_deb_join("ADHOC_J_CMD: BSSID = %s, SSID = '%s'\n", - print_mac(mac, cmd.bss.bssid), cmd.bss.ssid); + lbs_deb_join("ADHOC_J_CMD: BSSID = %pM, SSID = '%s'\n", + cmd.bss.bssid, cmd.bss.ssid); /* Only v8 and below support setting these */ if (priv->fwrelease < 0x09000000) { @@ -307,6 +311,7 @@ static int lbs_adhoc_start(struct lbs_private *priv, size_t ratesize = 0; u16 tmpcap = 0; int ret = 0; + DECLARE_SSID_BUF(ssid); lbs_deb_enter(LBS_DEB_ASSOC); @@ -326,7 +331,7 @@ static int lbs_adhoc_start(struct lbs_private *priv, memcpy(cmd.ssid, assoc_req->ssid, assoc_req->ssid_len); lbs_deb_join("ADHOC_START: SSID '%s', ssid length %u\n", - escape_essid(assoc_req->ssid, assoc_req->ssid_len), + print_ssid(ssid, assoc_req->ssid, assoc_req->ssid_len), assoc_req->ssid_len); cmd.bsstype = CMD_BSS_TYPE_IBSS; @@ -338,12 +343,12 @@ static int lbs_adhoc_start(struct lbs_private *priv, WARN_ON(!assoc_req->channel); /* set Physical parameter set */ - cmd.phyparamset.dsparamset.elementid = MFIE_TYPE_DS_SET; + cmd.phyparamset.dsparamset.elementid = WLAN_EID_DS_PARAMS; cmd.phyparamset.dsparamset.len = 1; cmd.phyparamset.dsparamset.currentchan = assoc_req->channel; /* set IBSS parameter set */ - cmd.ssparamset.ibssparamset.elementid = MFIE_TYPE_IBSS_SET; + cmd.ssparamset.ibssparamset.elementid = WLAN_EID_IBSS_PARAMS; cmd.ssparamset.ibssparamset.len = 2; cmd.ssparamset.ibssparamset.atimwindow = 0; @@ -427,8 +432,8 @@ static inline int match_bss_no_security(struct lbs_802_11_security *secinfo, { if (!secinfo->wep_enabled && !secinfo->WPAenabled && !secinfo->WPA2enabled - && match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC - && match_bss->rsn_ie[0] != MFIE_TYPE_RSN + && match_bss->wpa_ie[0] != WLAN_EID_GENERIC + && match_bss->rsn_ie[0] != WLAN_EID_RSN && !(match_bss->capability & WLAN_CAPABILITY_PRIVACY)) return 1; else @@ -450,7 +455,7 @@ static inline int match_bss_wpa(struct lbs_802_11_security *secinfo, struct bss_descriptor *match_bss) { if (!secinfo->wep_enabled && secinfo->WPAenabled - && (match_bss->wpa_ie[0] == MFIE_TYPE_GENERIC) + && (match_bss->wpa_ie[0] == WLAN_EID_GENERIC) /* privacy bit may NOT be set in some APs like LinkSys WRT54G && (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */ ) @@ -463,7 +468,7 @@ static inline int match_bss_wpa2(struct lbs_802_11_security *secinfo, struct bss_descriptor *match_bss) { if (!secinfo->wep_enabled && secinfo->WPA2enabled && - (match_bss->rsn_ie[0] == MFIE_TYPE_RSN) + (match_bss->rsn_ie[0] == WLAN_EID_RSN) /* privacy bit may NOT be set in some APs like LinkSys WRT54G (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */ ) @@ -477,8 +482,8 @@ static inline int match_bss_dynamic_wep(struct lbs_802_11_security *secinfo, { if (!secinfo->wep_enabled && !secinfo->WPAenabled && !secinfo->WPA2enabled - && (match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC) - && (match_bss->rsn_ie[0] != MFIE_TYPE_RSN) + && (match_bss->wpa_ie[0] != WLAN_EID_GENERIC) + && (match_bss->rsn_ie[0] != WLAN_EID_RSN) && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) return 1; else @@ -694,6 +699,7 @@ static int assoc_helper_essid(struct lbs_private *priv, int ret = 0; struct bss_descriptor * bss; int channel = -1; + DECLARE_SSID_BUF(ssid); lbs_deb_enter(LBS_DEB_ASSOC); @@ -705,7 +711,7 @@ static int assoc_helper_essid(struct lbs_private *priv, channel = assoc_req->channel; lbs_deb_assoc("SSID '%s' requested\n", - escape_essid(assoc_req->ssid, assoc_req->ssid_len)); + print_ssid(ssid, assoc_req->ssid, assoc_req->ssid_len)); if (assoc_req->mode == IW_MODE_INFRA) { lbs_send_specific_ssid_scan(priv, assoc_req->ssid, assoc_req->ssid_len); @@ -752,17 +758,15 @@ static int assoc_helper_bssid(struct lbs_private *priv, { int ret = 0; struct bss_descriptor * bss; - DECLARE_MAC_BUF(mac); - lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID %s", - print_mac(mac, assoc_req->bssid)); + lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID %pM", assoc_req->bssid); /* Search for index position in list for requested MAC */ bss = lbs_find_bssid_in_list(priv, assoc_req->bssid, assoc_req->mode); if (bss == NULL) { - lbs_deb_assoc("ASSOC: WAP: BSSID %s not found, " - "cannot associate.\n", print_mac(mac, assoc_req->bssid)); + lbs_deb_assoc("ASSOC: WAP: BSSID %pM not found, " + "cannot associate.\n", assoc_req->bssid); goto out; } @@ -1208,7 +1212,7 @@ void lbs_association_worker(struct work_struct *work) struct assoc_request * assoc_req = NULL; int ret = 0; int find_any_ssid = 0; - DECLARE_MAC_BUF(mac); + DECLARE_SSID_BUF(ssid); lbs_deb_enter(LBS_DEB_ASSOC); @@ -1228,13 +1232,13 @@ void lbs_association_worker(struct work_struct *work) " chann: %d\n" " band: %d\n" " mode: %d\n" - " BSSID: %s\n" + " BSSID: %pM\n" " secinfo: %s%s%s\n" " auth_mode: %d\n", assoc_req->flags, - escape_essid(assoc_req->ssid, assoc_req->ssid_len), + print_ssid(ssid, assoc_req->ssid, assoc_req->ssid_len), assoc_req->channel, assoc_req->band, assoc_req->mode, - print_mac(mac, assoc_req->bssid), + assoc_req->bssid, assoc_req->secinfo.WPAenabled ? " WPA" : "", assoc_req->secinfo.WPA2enabled ? " WPA2" : "", assoc_req->secinfo.wep_enabled ? " WEP" : "", @@ -1357,8 +1361,8 @@ void lbs_association_worker(struct work_struct *work) } if (success) { - lbs_deb_assoc("associated to %s\n", - print_mac(mac, priv->curbssparams.bssid)); + lbs_deb_assoc("associated to %pM\n", + priv->curbssparams.bssid); lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, CMD_OPTION_WAITFORRSP, 0, NULL); @@ -1478,7 +1482,6 @@ int lbs_cmd_80211_authenticate(struct lbs_private *priv, struct cmd_ds_802_11_authenticate *pauthenticate = &cmd->params.auth; int ret = -1; u8 *bssid = pdata_buf; - DECLARE_MAC_BUF(mac); lbs_deb_enter(LBS_DEB_JOIN); @@ -1505,8 +1508,8 @@ int lbs_cmd_80211_authenticate(struct lbs_private *priv, memcpy(pauthenticate->macaddr, bssid, ETH_ALEN); - lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n", - print_mac(mac, bssid), pauthenticate->authtype); + lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n", + bssid, pauthenticate->authtype); ret = 0; out: @@ -1770,7 +1773,7 @@ static int lbs_adhoc_post(struct lbs_private *priv, struct cmd_header *resp) struct cmd_ds_802_11_ad_hoc_result *adhoc_resp; union iwreq_data wrqu; struct bss_descriptor *bss; - DECLARE_MAC_BUF(mac); + DECLARE_SSID_BUF(ssid); lbs_deb_enter(LBS_DEB_JOIN); @@ -1819,9 +1822,9 @@ static int lbs_adhoc_post(struct lbs_private *priv, struct cmd_header *resp) wrqu.ap_addr.sa_family = ARPHRD_ETHER; wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); - lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %s, channel %d\n", - escape_essid(bss->ssid, bss->ssid_len), - print_mac(mac, priv->curbssparams.bssid), + lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %pM, channel %d\n", + print_ssid(ssid, bss->ssid, bss->ssid_len), + priv->curbssparams.bssid, priv->curbssparams.channel); done: diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 8265c7d25edcb9cbe51478e00828d93e8a26000c..639dd02d3d31d72e74ca916a772aa7406875612b 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -4,7 +4,7 @@ */ #include -#include +#include #include #include "host.h" #include "hostcmd.h" @@ -87,7 +87,6 @@ int lbs_update_hw_spec(struct lbs_private *priv) struct cmd_ds_get_hw_spec cmd; int ret = -1; u32 i; - DECLARE_MAC_BUF(mac); lbs_deb_enter(LBS_DEB_CMD); @@ -110,8 +109,8 @@ int lbs_update_hw_spec(struct lbs_private *priv) * CF card firmware 5.0.16p0: cap 0x00000303 * USB dongle firmware 5.110.17p2: cap 0x00000303 */ - lbs_pr_info("%s, fw %u.%u.%up%u, cap 0x%08x\n", - print_mac(mac, cmd.permanentaddr), + lbs_pr_info("%pM, fw %u.%u.%up%u, cap 0x%08x\n", + cmd.permanentaddr, priv->fwrelease >> 24 & 0xff, priv->fwrelease >> 16 & 0xff, priv->fwrelease >> 8 & 0xff, @@ -160,7 +159,8 @@ int lbs_update_hw_spec(struct lbs_private *priv) return ret; } -int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria) +int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria, + struct wol_config *p_wol_config) { struct cmd_ds_host_sleep cmd_config; int ret; @@ -170,10 +170,21 @@ int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria) cmd_config.gpio = priv->wol_gpio; cmd_config.gap = priv->wol_gap; + if (p_wol_config != NULL) + memcpy((uint8_t *)&cmd_config.wol_conf, (uint8_t *)p_wol_config, + sizeof(struct wol_config)); + else + cmd_config.wol_conf.action = CMD_ACT_ACTION_NONE; + ret = lbs_cmd_with_response(priv, CMD_802_11_HOST_SLEEP_CFG, &cmd_config); if (!ret) { - lbs_deb_cmd("Set WOL criteria to %x\n", criteria); - priv->wol_criteria = criteria; + if (criteria) { + lbs_deb_cmd("Set WOL criteria to %x\n", criteria); + priv->wol_criteria = criteria; + } else + memcpy((uint8_t *) p_wol_config, + (uint8_t *)&cmd_config.wol_conf, + sizeof(struct wol_config)); } else { lbs_pr_info("HOST_SLEEP_CFG failed %d\n", ret); } @@ -1063,6 +1074,7 @@ int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan) { struct cmd_ds_mesh_config cmd; struct mrvl_meshie *ie; + DECLARE_SSID_BUF(ssid); memset(&cmd, 0, sizeof(cmd)); cmd.channel = cpu_to_le16(chan); @@ -1070,7 +1082,7 @@ int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan) switch (action) { case CMD_ACT_MESH_CONFIG_START: - ie->hdr.id = MFIE_TYPE_GENERIC; + ie->id = WLAN_EID_GENERIC; ie->val.oui[0] = 0x00; ie->val.oui[1] = 0x50; ie->val.oui[2] = 0x43; @@ -1082,7 +1094,7 @@ int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan) ie->val.mesh_capability = MARVELL_MESH_CAPABILITY; ie->val.mesh_id_len = priv->mesh_ssid_len; memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len); - ie->hdr.len = sizeof(struct mrvl_meshie_val) - + ie->len = sizeof(struct mrvl_meshie_val) - IW_ESSID_MAX_SIZE + priv->mesh_ssid_len; cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val)); break; @@ -1093,7 +1105,7 @@ int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan) } lbs_deb_cmd("mesh config action %d type %x channel %d SSID %s\n", action, priv->mesh_tlv, chan, - escape_essid(priv->mesh_ssid, priv->mesh_ssid_len)); + print_ssid(ssid, priv->mesh_ssid, priv->mesh_ssid_len)); return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv); } diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h index 36be4c9703e0b0c12fd4f0ee6f4b31db56bc8fe5..392e578ca0952fb5e2d35592844dd0833a469199 100644 --- a/drivers/net/wireless/libertas/cmd.h +++ b/drivers/net/wireless/libertas/cmd.h @@ -56,7 +56,8 @@ int lbs_mesh_config_send(struct lbs_private *priv, uint16_t action, uint16_t type); int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan); -int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria); +int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria, + struct wol_config *p_wol_config); int lbs_suspend(struct lbs_private *priv); void lbs_resume(struct lbs_private *priv); diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index 0aa0ce3b2c425206262997ef1eacb163cb66c977..ec4efd7ff3c85064929fe67a6dee3c10f3c2148a 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "dev.h" #include "decl.h" @@ -65,7 +66,7 @@ static ssize_t lbs_getscantable(struct file *file, char __user *userbuf, int numscansdone = 0, res; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; - DECLARE_MAC_BUF(mac); + DECLARE_SSID_BUF(ssid); struct bss_descriptor * iter_bss; pos += snprintf(buf+pos, len-pos, @@ -77,17 +78,17 @@ static ssize_t lbs_getscantable(struct file *file, char __user *userbuf, u16 privacy = (iter_bss->capability & WLAN_CAPABILITY_PRIVACY); u16 spectrum_mgmt = (iter_bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT); - pos += snprintf(buf+pos, len-pos, - "%02u| %03d | %04d | %s |", + pos += snprintf(buf+pos, len-pos, "%02u| %03d | %04d | %pM |", numscansdone, iter_bss->channel, iter_bss->rssi, - print_mac(mac, iter_bss->bssid)); + iter_bss->bssid); pos += snprintf(buf+pos, len-pos, " %04x-", iter_bss->capability); pos += snprintf(buf+pos, len-pos, "%c%c%c |", ibss ? 'A' : 'I', privacy ? 'P' : ' ', spectrum_mgmt ? 'S' : ' '); pos += snprintf(buf+pos, len-pos, " %04d |", SCAN_RSSI(iter_bss->rssi)); pos += snprintf(buf+pos, len-pos, " %s\n", - escape_essid(iter_bss->ssid, iter_bss->ssid_len)); + print_ssid(ssid, iter_bss->ssid, + iter_bss->ssid_len)); numscansdone++; } diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index 1a8888cceadc080bffd7d9b6dab1222c0529802e..0b84bdca0726129c98ccebbc0fe684a64a63c728 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -74,8 +74,4 @@ void lbs_host_to_card_done(struct lbs_private *priv); int lbs_update_channel(struct lbs_private *priv); -#ifndef CONFIG_IEEE80211 -const char *escape_essid(const char *essid, u8 essid_len); -#endif - #endif diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index 076a636e8f62165252b8f931f88312187e64c1bf..c364e4c01d1b7183f53290206a997e41051b6135 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -79,7 +79,7 @@ do { if ((lbs_debug & (grp)) == (grp)) \ #define lbs_deb_tx(fmt, args...) LBS_DEB_LL(LBS_DEB_TX, " tx", fmt, ##args) #define lbs_deb_fw(fmt, args...) LBS_DEB_LL(LBS_DEB_FW, " fw", fmt, ##args) #define lbs_deb_usb(fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usb", fmt, ##args) -#define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usbd", "%s:" fmt, (dev)->bus_id, ##args) +#define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usbd", "%s:" fmt, dev_name(dev), ##args) #define lbs_deb_cs(fmt, args...) LBS_DEB_LL(LBS_DEB_CS, " cs", fmt, ##args) #define lbs_deb_thread(fmt, args...) LBS_DEB_LL(LBS_DEB_THREAD, " thread", fmt, ##args) #define lbs_deb_sdio(fmt, args...) LBS_DEB_LL(LBS_DEB_SDIO, " sdio", fmt, ##args) @@ -149,6 +149,18 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in #define EHS_WAKE_ON_MAC_EVENT 0x0004 #define EHS_WAKE_ON_MULTICAST_DATA 0x0008 #define EHS_REMOVE_WAKEUP 0xFFFFFFFF +/* Wake rules for Host_Sleep_CFG command */ +#define WOL_RULE_NET_TYPE_INFRA_OR_IBSS 0x00 +#define WOL_RULE_NET_TYPE_MESH 0x10 +#define WOL_RULE_ADDR_TYPE_BCAST 0x01 +#define WOL_RULE_ADDR_TYPE_MCAST 0x08 +#define WOL_RULE_ADDR_TYPE_UCAST 0x02 +#define WOL_RULE_OP_AND 0x01 +#define WOL_RULE_OP_OR 0x02 +#define WOL_RULE_OP_INVALID 0xFF +#define WOL_RESULT_VALID_CMD 0 +#define WOL_RESULT_NOSPC_ERR 1 +#define WOL_RESULT_EEXIST_ERR 2 /** Misc constants */ /* This section defines 802.11 specific contants */ diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index f6f3753da303d80f26bc95d0f51ca52f03106814..dd682c4cfde816929425b3f68417de552e62b0b6 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -10,7 +10,6 @@ #include #include #include -#include #include "defs.h" #include "hostcmd.h" @@ -278,6 +277,12 @@ struct lbs_private { struct enc_key wpa_mcast_key; struct enc_key wpa_unicast_key; +/* + * In theory, the IE is limited to the IE length, 255, + * but in practice 64 bytes are enough. + */ +#define MAX_WPA_IE_LEN 64 + /** WPA Information Elements*/ u8 wpa_ie[MAX_WPA_IE_LEN]; u8 wpa_ie_len; diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c index 688d60de55cb580d89cb3e188377be4203e887ef..61d2f50470c8e82f76e031cc82011846689f4723 100644 --- a/drivers/net/wireless/libertas/ethtool.c +++ b/drivers/net/wireless/libertas/ethtool.c @@ -23,7 +23,7 @@ static const char * mesh_stat_strings[]= { static void lbs_ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct lbs_private *priv = (struct lbs_private *) dev->priv; + struct lbs_private *priv = netdev_priv(dev); snprintf(info->fw_version, 32, "%u.%u.%u.p%u", priv->fwrelease >> 24 & 0xff, @@ -47,7 +47,7 @@ static int lbs_ethtool_get_eeprom_len(struct net_device *dev) static int lbs_ethtool_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 * bytes) { - struct lbs_private *priv = (struct lbs_private *) dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct cmd_ds_802_11_eeprom_access cmd; int ret; @@ -76,7 +76,7 @@ static int lbs_ethtool_get_eeprom(struct net_device *dev, static void lbs_ethtool_get_stats(struct net_device *dev, struct ethtool_stats *stats, uint64_t *data) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct cmd_ds_mesh_access mesh_access; int ret; @@ -113,7 +113,7 @@ static void lbs_ethtool_get_stats(struct net_device *dev, static int lbs_ethtool_get_sset_count(struct net_device *dev, int sset) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); if (sset == ETH_SS_STATS && dev == priv->mesh_dev) return MESH_STATS_NUM; @@ -143,7 +143,7 @@ static void lbs_ethtool_get_strings(struct net_device *dev, static void lbs_ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); if (priv->wol_criteria == 0xffffffff) { /* Interface driver didn't configure wake */ @@ -166,7 +166,7 @@ static void lbs_ethtool_get_wol(struct net_device *dev, static int lbs_ethtool_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); uint32_t criteria = 0; if (priv->wol_criteria == 0xffffffff && wol->wolopts) @@ -180,7 +180,7 @@ static int lbs_ethtool_set_wol(struct net_device *dev, if (wol->wolopts & WAKE_BCAST) criteria |= EHS_WAKE_ON_BROADCAST_DATA; if (wol->wolopts & WAKE_PHY) criteria |= EHS_WAKE_ON_MAC_EVENT; - return lbs_host_sleep_cfg(priv, criteria); + return lbs_host_sleep_cfg(priv, criteria, (struct wol_config *)NULL); } struct ethtool_ops lbs_ethtool_ops = { diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index 5004d7679c020471748790d41f40f6ba2f61ab5d..277ff1975bde8e22ea1009268cf45f94920f39f5 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -220,6 +220,14 @@ enum cmd_fwt_access_opts { CMD_ACT_FWT_ACCESS_TIME, }; +/* Define action or option for CMD_802_11_HOST_SLEEP_CFG */ +enum cmd_wol_cfg_opts { + CMD_ACT_ACTION_NONE = 0, + CMD_ACT_SET_WOL_RULE, + CMD_ACT_GET_WOL_RULE, + CMD_ACT_RESET_WOL_RULE, +}; + /* Define action or option for CMD_MESH_ACCESS */ enum cmd_mesh_access_opts { CMD_ACT_MESH_GET_TTL = 1, @@ -237,6 +245,7 @@ enum cmd_mesh_access_opts { CMD_ACT_MESH_GET_ROUTE_EXP, CMD_ACT_MESH_SET_AUTOSTART_ENABLED, CMD_ACT_MESH_GET_AUTOSTART_ENABLED, + CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT = 17, }; /* Define actions and types for CMD_MESH_CONFIG */ diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index d9f9a12a739e1f045c5d05452f5de4a11b4d293f..e173b1b46c232754efdaca10211af22fff489fe0 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -580,13 +580,37 @@ struct MrvlIEtype_keyParamSet { u8 key[32]; }; +#define MAX_WOL_RULES 16 + +struct host_wol_rule { + uint8_t rule_no; + uint8_t rule_ops; + __le16 sig_offset; + __le16 sig_length; + __le16 reserve; + __be32 sig_mask; + __be32 signature; +}; + +struct wol_config { + uint8_t action; + uint8_t pattern; + uint8_t no_rules_in_cmd; + uint8_t result; + struct host_wol_rule rule[MAX_WOL_RULES]; +}; + + struct cmd_ds_host_sleep { struct cmd_header hdr; __le32 criteria; uint8_t gpio; - uint8_t gap; + uint16_t gap; + struct wol_config wol_conf; } __attribute__ ((packed)); + + struct cmd_ds_802_11_key_material { struct cmd_header hdr; diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index b54e2ea8346bf26ae5071ed39bbfe450830a980d..4519d7314f47c37677df87ca51fc4b53bfeac2fe 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -26,6 +26,7 @@ * if_sdio_card_to_host() to pad the data. */ +#include #include #include #include @@ -581,7 +582,7 @@ static int if_sdio_prog_real(struct if_sdio_card *card) chunk_size, (chunk_size + 31) / 32 * 32); */ ret = sdio_writesb(card->func, card->ioport, - chunk_buffer, (chunk_size + 31) / 32 * 32); + chunk_buffer, roundup(chunk_size, 32)); if (ret) goto release; diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index cafbccb7414322e5013a3be370a5f656b8f7a8f9..2fc637ad85c741b84b94ba1a7f230f30077a4b8a 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -59,7 +59,7 @@ static int if_usb_reset_device(struct if_usb_card *cardp); static ssize_t if_usb_firmware_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); struct if_usb_card *cardp = priv->card; char fwname[FIRMWARE_NAME_MAX]; int ret; @@ -86,7 +86,7 @@ static DEVICE_ATTR(lbs_flash_fw, 0200, NULL, if_usb_firmware_set); static ssize_t if_usb_boot2_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); struct if_usb_card *cardp = priv->card; char fwname[FIRMWARE_NAME_MAX]; int ret; @@ -178,7 +178,8 @@ static void if_usb_setup_firmware(struct lbs_private *priv) priv->wol_gpio = 2; /* Wake via GPIO2... */ priv->wol_gap = 20; /* ... after 20ms */ - lbs_host_sleep_cfg(priv, EHS_WAKE_ON_UNICAST_DATA); + lbs_host_sleep_cfg(priv, EHS_WAKE_ON_UNICAST_DATA, + (struct wol_config *) NULL); wake_method.hdr.size = cpu_to_le16(sizeof(wake_method)); wake_method.action = cpu_to_le16(CMD_ACT_GET); diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 73dc8c72402a93fbfa85d1477869d370454c4cd2..3dba836794443b9cc39879df2462c1123d5156d1 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -12,9 +12,8 @@ #include #include #include - +#include #include -#include #include "host.h" #include "decl.h" @@ -223,7 +222,7 @@ u8 lbs_data_rate_to_fw_index(u32 rate) static ssize_t lbs_anycast_get(struct device *dev, struct device_attribute *attr, char * buf) { - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); struct cmd_ds_mesh_access mesh_access; int ret; @@ -242,7 +241,7 @@ static ssize_t lbs_anycast_get(struct device *dev, static ssize_t lbs_anycast_set(struct device *dev, struct device_attribute *attr, const char * buf, size_t count) { - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); struct cmd_ds_mesh_access mesh_access; uint32_t datum; int ret; @@ -258,6 +257,58 @@ static ssize_t lbs_anycast_set(struct device *dev, return strlen(buf); } +/** + * @brief Get function for sysfs attribute prb_rsp_limit + */ +static ssize_t lbs_prb_rsp_limit_get(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); + struct cmd_ds_mesh_access mesh_access; + int ret; + u32 retry_limit; + + memset(&mesh_access, 0, sizeof(mesh_access)); + mesh_access.data[0] = cpu_to_le32(CMD_ACT_GET); + + ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT, + &mesh_access); + if (ret) + return ret; + + retry_limit = le32_to_cpu(mesh_access.data[1]); + return snprintf(buf, 10, "%d\n", retry_limit); +} + +/** + * @brief Set function for sysfs attribute prb_rsp_limit + */ +static ssize_t lbs_prb_rsp_limit_set(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); + struct cmd_ds_mesh_access mesh_access; + int ret; + unsigned long retry_limit; + + memset(&mesh_access, 0, sizeof(mesh_access)); + mesh_access.data[0] = cpu_to_le32(CMD_ACT_SET); + + if (!strict_strtoul(buf, 10, &retry_limit)) + return -ENOTSUPP; + if (retry_limit > 15) + return -ENOTSUPP; + + mesh_access.data[1] = cpu_to_le32(retry_limit); + + ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT, + &mesh_access); + if (ret) + return ret; + + return strlen(buf); +} + static int lbs_add_rtap(struct lbs_private *priv); static void lbs_remove_rtap(struct lbs_private *priv); static int lbs_add_mesh(struct lbs_private *priv); @@ -270,7 +321,7 @@ static void lbs_remove_mesh(struct lbs_private *priv); static ssize_t lbs_rtap_get(struct device *dev, struct device_attribute *attr, char * buf) { - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); return snprintf(buf, 5, "0x%X\n", priv->monitormode); } @@ -281,7 +332,7 @@ static ssize_t lbs_rtap_set(struct device *dev, struct device_attribute *attr, const char * buf, size_t count) { int monitor_mode; - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); sscanf(buf, "%x", &monitor_mode); if (monitor_mode) { @@ -332,7 +383,7 @@ static DEVICE_ATTR(lbs_rtap, 0644, lbs_rtap_get, lbs_rtap_set ); static ssize_t lbs_mesh_get(struct device *dev, struct device_attribute *attr, char * buf) { - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); return snprintf(buf, 5, "0x%X\n", !!priv->mesh_dev); } @@ -342,7 +393,7 @@ static ssize_t lbs_mesh_get(struct device *dev, static ssize_t lbs_mesh_set(struct device *dev, struct device_attribute *attr, const char * buf, size_t count) { - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); int enable; int ret, action = CMD_ACT_MESH_CONFIG_STOP; @@ -376,8 +427,16 @@ static DEVICE_ATTR(lbs_mesh, 0644, lbs_mesh_get, lbs_mesh_set); */ static DEVICE_ATTR(anycast_mask, 0644, lbs_anycast_get, lbs_anycast_set); +/** + * prb_rsp_limit attribute to be exported per mshX interface + * through sysfs (/sys/class/net/mshX/prb_rsp_limit) + */ +static DEVICE_ATTR(prb_rsp_limit, 0644, lbs_prb_rsp_limit_get, + lbs_prb_rsp_limit_set); + static struct attribute *lbs_mesh_sysfs_entries[] = { &dev_attr_anycast_mask.attr, + &dev_attr_prb_rsp_limit.attr, NULL, }; @@ -393,7 +452,7 @@ static struct attribute_group lbs_mesh_attr_group = { */ static int lbs_dev_open(struct net_device *dev) { - struct lbs_private *priv = (struct lbs_private *) dev->priv ; + struct lbs_private *priv = netdev_priv(dev) ; int ret = 0; lbs_deb_enter(LBS_DEB_NET); @@ -435,7 +494,7 @@ static int lbs_dev_open(struct net_device *dev) */ static int lbs_mesh_stop(struct net_device *dev) { - struct lbs_private *priv = (struct lbs_private *) (dev->priv); + struct lbs_private *priv = dev->ml_priv; lbs_deb_enter(LBS_DEB_MESH); spin_lock_irq(&priv->driver_lock); @@ -462,7 +521,7 @@ static int lbs_mesh_stop(struct net_device *dev) */ static int lbs_eth_stop(struct net_device *dev) { - struct lbs_private *priv = (struct lbs_private *) dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_NET); @@ -479,7 +538,7 @@ static int lbs_eth_stop(struct net_device *dev) static void lbs_tx_timeout(struct net_device *dev) { - struct lbs_private *priv = (struct lbs_private *) dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_TX); @@ -531,7 +590,7 @@ EXPORT_SYMBOL_GPL(lbs_host_to_card_done); */ static struct net_device_stats *lbs_get_stats(struct net_device *dev) { - struct lbs_private *priv = (struct lbs_private *) dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_NET); return &priv->stats; @@ -540,7 +599,7 @@ static struct net_device_stats *lbs_get_stats(struct net_device *dev) static int lbs_set_mac_address(struct net_device *dev, void *addr) { int ret = 0; - struct lbs_private *priv = (struct lbs_private *) dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct sockaddr *phwaddr = addr; struct cmd_ds_802_11_mac_address cmd; @@ -588,7 +647,6 @@ static int lbs_add_mcast_addrs(struct cmd_ds_mac_multicast_adr *cmd, { int i = nr_addrs; struct dev_mc_list *mc_list; - DECLARE_MAC_BUF(mac); if ((dev->flags & (IFF_UP|IFF_MULTICAST)) != (IFF_UP|IFF_MULTICAST)) return nr_addrs; @@ -596,16 +654,16 @@ static int lbs_add_mcast_addrs(struct cmd_ds_mac_multicast_adr *cmd, netif_addr_lock_bh(dev); for (mc_list = dev->mc_list; mc_list; mc_list = mc_list->next) { if (mac_in_list(cmd->maclist, nr_addrs, mc_list->dmi_addr)) { - lbs_deb_net("mcast address %s:%s skipped\n", dev->name, - print_mac(mac, mc_list->dmi_addr)); + lbs_deb_net("mcast address %s:%pM skipped\n", dev->name, + mc_list->dmi_addr); continue; } if (i == MRVDRV_MAX_MULTICAST_LIST_SIZE) break; memcpy(&cmd->maclist[6*i], mc_list->dmi_addr, ETH_ALEN); - lbs_deb_net("mcast address %s:%s added to filter\n", dev->name, - print_mac(mac, mc_list->dmi_addr)); + lbs_deb_net("mcast address %s:%pM added to filter\n", dev->name, + mc_list->dmi_addr); i++; } netif_addr_unlock_bh(dev); @@ -674,7 +732,7 @@ static void lbs_set_mcast_worker(struct work_struct *work) static void lbs_set_multicast_list(struct net_device *dev) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); schedule_work(&priv->mcast_work); } @@ -690,7 +748,7 @@ static void lbs_set_multicast_list(struct net_device *dev) static int lbs_thread(void *data) { struct net_device *dev = data; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); wait_queue_t wait; lbs_deb_enter(LBS_DEB_THREAD); @@ -1125,7 +1183,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) lbs_pr_err("init ethX device failed\n"); goto done; } - priv = dev->priv; + priv = netdev_priv(dev); if (lbs_init_adapter(priv)) { lbs_pr_err("failed to initialize adapter structure.\n"); @@ -1378,7 +1436,7 @@ static int lbs_add_mesh(struct lbs_private *priv) ret = -ENOMEM; goto done; } - mesh_dev->priv = priv; + mesh_dev->ml_priv = priv; priv->mesh_dev = mesh_dev; mesh_dev->open = lbs_dev_open; @@ -1591,7 +1649,7 @@ static int lbs_rtap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) static struct net_device_stats *lbs_rtap_get_stats(struct net_device *dev) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = dev->ml_priv; lbs_deb_enter(LBS_DEB_NET); return &priv->stats; } @@ -1632,7 +1690,7 @@ static int lbs_add_rtap(struct lbs_private *priv) rtap_dev->stop = lbs_rtap_stop; rtap_dev->get_stats = lbs_rtap_get_stats; rtap_dev->hard_start_xmit = lbs_rtap_hard_start_xmit; - rtap_dev->priv = priv; + rtap_dev->ml_priv = priv; SET_NETDEV_DEV(rtap_dev, priv->dev->dev.parent); ret = register_netdev(rtap_dev); @@ -1647,33 +1705,6 @@ static int lbs_add_rtap(struct lbs_private *priv) return ret; } -#ifndef CONFIG_IEEE80211 -const char *escape_essid(const char *essid, u8 essid_len) -{ - static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; - const char *s = essid; - char *d = escaped; - - if (ieee80211_is_empty_essid(essid, essid_len)) { - memcpy(escaped, "", sizeof("")); - return escaped; - } - - essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE); - while (essid_len--) { - if (*s == '\0') { - *d++ = '\\'; - *d++ = '0'; - s++; - } else { - *d++ = *s++; - } - } - *d = '\0'; - return escaped; -} -#endif - module_init(lbs_init_module); module_exit(lbs_exit_module); diff --git a/drivers/net/wireless/libertas/persistcfg.c b/drivers/net/wireless/libertas/persistcfg.c index 3309a9c3cfef3f66c84f5f1cb67388dda176c5e6..d42b7a5a1b3f32a564579771e19149429348db5b 100644 --- a/drivers/net/wireless/libertas/persistcfg.c +++ b/drivers/net/wireless/libertas/persistcfg.c @@ -18,7 +18,7 @@ static int mesh_get_default_parameters(struct device *dev, struct mrvl_mesh_defaults *defs) { - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); struct cmd_ds_mesh_config cmd; int ret; @@ -57,7 +57,7 @@ static ssize_t bootflag_get(struct device *dev, static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); struct cmd_ds_mesh_config cmd; uint32_t datum; int ret; @@ -100,7 +100,7 @@ static ssize_t boottime_get(struct device *dev, static ssize_t boottime_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); struct cmd_ds_mesh_config cmd; uint32_t datum; int ret; @@ -152,7 +152,7 @@ static ssize_t channel_get(struct device *dev, static ssize_t channel_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); struct cmd_ds_mesh_config cmd; uint32_t datum; int ret; @@ -210,7 +210,7 @@ static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr, struct cmd_ds_mesh_config cmd; struct mrvl_mesh_defaults defs; struct mrvl_meshie *ie; - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); int len; int ret; @@ -233,7 +233,7 @@ static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr, /* SSID len */ ie->val.mesh_id_len = len; /* IE len */ - ie->hdr.len = sizeof(struct mrvl_meshie_val) - IW_ESSID_MAX_SIZE + len; + ie->len = sizeof(struct mrvl_meshie_val) - IW_ESSID_MAX_SIZE + len; ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, CMD_TYPE_MESH_SET_MESH_IE); @@ -269,7 +269,7 @@ static ssize_t protocol_id_set(struct device *dev, struct cmd_ds_mesh_config cmd; struct mrvl_mesh_defaults defs; struct mrvl_meshie *ie; - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); uint32_t datum; int ret; @@ -323,7 +323,7 @@ static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr, struct cmd_ds_mesh_config cmd; struct mrvl_mesh_defaults defs; struct mrvl_meshie *ie; - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); uint32_t datum; int ret; @@ -377,7 +377,7 @@ static ssize_t capability_set(struct device *dev, struct device_attribute *attr, struct cmd_ds_mesh_config cmd; struct mrvl_mesh_defaults defs; struct mrvl_meshie *ie; - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); uint32_t datum; int ret; diff --git a/drivers/net/wireless/libertas/radiotap.h b/drivers/net/wireless/libertas/radiotap.h index 5d118f40cfbc43206369ec77082e220822318f11..f8eb9097ff0a013b06aa61d76033c622488f6a1b 100644 --- a/drivers/net/wireless/libertas/radiotap.h +++ b/drivers/net/wireless/libertas/radiotap.h @@ -6,9 +6,6 @@ struct tx_radiotap_hdr { u8 txpower; u8 rts_retries; u8 data_retries; -#if 0 - u8 pad[IEEE80211_RADIOTAP_HDRLEN - 12]; -#endif } __attribute__ ((packed)); #define TX_RADIOTAP_PRESENT ( \ diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 22c4c611052147ef3c2e1b3d01f1d64026ad9bec..57f6c12cda2085a902a8fae4e1e950c138f34475 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -4,8 +4,11 @@ * IOCTL handlers as well as command preperation and response routines * for sending scan commands to the firmware. */ +#include #include +#include #include +#include #include "host.h" #include "decl.h" @@ -52,6 +55,8 @@ //! Scan time specified in the channel TLV for each channel for active scans #define MRVDRV_ACTIVE_SCAN_CHAN_TIME 100 +#define DEFAULT_MAX_SCAN_AGE (15 * HZ) + static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy, struct cmd_header *resp); @@ -359,7 +364,7 @@ int lbs_scan_networks(struct lbs_private *priv, int full_scan) #ifdef CONFIG_LIBERTAS_DEBUG struct bss_descriptor *iter; int i = 0; - DECLARE_MAC_BUF(mac); + DECLARE_SSID_BUF(ssid); #endif lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d", full_scan); @@ -451,9 +456,9 @@ int lbs_scan_networks(struct lbs_private *priv, int full_scan) mutex_lock(&priv->lock); lbs_deb_scan("scan table:\n"); list_for_each_entry(iter, &priv->network_list, list) - lbs_deb_scan("%02d: BSSID %s, RSSI %d, SSID '%s'\n", - i++, print_mac(mac, iter->bssid), iter->rssi, - escape_essid(iter->ssid, iter->ssid_len)); + lbs_deb_scan("%02d: BSSID %pM, RSSI %d, SSID '%s'\n", + i++, iter->bssid, iter->rssi, + print_ssid(ssid, iter->ssid, iter->ssid_len)); mutex_unlock(&priv->lock); #endif @@ -512,7 +517,7 @@ static int lbs_process_bss(struct bss_descriptor *bss, struct ieeetypes_dsparamset *pDS; struct ieeetypes_cfparamset *pCF; struct ieeetypes_ibssparamset *pibss; - DECLARE_MAC_BUF(mac); + DECLARE_SSID_BUF(ssid); struct ieeetypes_countryinfoset *pcountryinfo; uint8_t *pos, *end, *p; uint8_t n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0; @@ -544,7 +549,7 @@ static int lbs_process_bss(struct bss_descriptor *bss, *bytesleft -= beaconsize; memcpy(bss->bssid, pos, ETH_ALEN); - lbs_deb_scan("process_bss: BSSID %s\n", print_mac(mac, bss->bssid)); + lbs_deb_scan("process_bss: BSSID %pM\n", bss->bssid); pos += ETH_ALEN; if ((end - pos) < 12) { @@ -588,38 +593,36 @@ static int lbs_process_bss(struct bss_descriptor *bss, /* process variable IE */ while (pos <= end - 2) { - struct ieee80211_info_element * elem = (void *)pos; - - if (pos + elem->len > end) { + if (pos + pos[1] > end) { lbs_deb_scan("process_bss: error in processing IE, " "bytes left < IE length\n"); break; } - switch (elem->id) { - case MFIE_TYPE_SSID: - bss->ssid_len = min_t(int, 32, elem->len); - memcpy(bss->ssid, elem->data, bss->ssid_len); + switch (pos[0]) { + case WLAN_EID_SSID: + bss->ssid_len = min_t(int, IEEE80211_MAX_SSID_LEN, pos[1]); + memcpy(bss->ssid, pos + 2, bss->ssid_len); lbs_deb_scan("got SSID IE: '%s', len %u\n", - escape_essid(bss->ssid, bss->ssid_len), + print_ssid(ssid, bss->ssid, bss->ssid_len), bss->ssid_len); break; - case MFIE_TYPE_RATES: - n_basic_rates = min_t(uint8_t, MAX_RATES, elem->len); - memcpy(bss->rates, elem->data, n_basic_rates); + case WLAN_EID_SUPP_RATES: + n_basic_rates = min_t(uint8_t, MAX_RATES, pos[1]); + memcpy(bss->rates, pos + 2, n_basic_rates); got_basic_rates = 1; lbs_deb_scan("got RATES IE\n"); break; - case MFIE_TYPE_FH_SET: + case WLAN_EID_FH_PARAMS: pFH = (struct ieeetypes_fhparamset *) pos; memmove(&bss->phyparamset.fhparamset, pFH, sizeof(struct ieeetypes_fhparamset)); lbs_deb_scan("got FH IE\n"); break; - case MFIE_TYPE_DS_SET: + case WLAN_EID_DS_PARAMS: pDS = (struct ieeetypes_dsparamset *) pos; bss->channel = pDS->currentchan; memcpy(&bss->phyparamset.dsparamset, pDS, @@ -627,14 +630,14 @@ static int lbs_process_bss(struct bss_descriptor *bss, lbs_deb_scan("got DS IE, channel %d\n", bss->channel); break; - case MFIE_TYPE_CF_SET: + case WLAN_EID_CF_PARAMS: pCF = (struct ieeetypes_cfparamset *) pos; memcpy(&bss->ssparamset.cfparamset, pCF, sizeof(struct ieeetypes_cfparamset)); lbs_deb_scan("got CF IE\n"); break; - case MFIE_TYPE_IBSS_SET: + case WLAN_EID_IBSS_PARAMS: pibss = (struct ieeetypes_ibssparamset *) pos; bss->atimwindow = le16_to_cpu(pibss->atimwindow); memmove(&bss->ssparamset.ibssparamset, pibss, @@ -642,7 +645,7 @@ static int lbs_process_bss(struct bss_descriptor *bss, lbs_deb_scan("got IBSS IE\n"); break; - case MFIE_TYPE_COUNTRY: + case WLAN_EID_COUNTRY: pcountryinfo = (struct ieeetypes_countryinfoset *) pos; lbs_deb_scan("got COUNTRY IE\n"); if (pcountryinfo->len < sizeof(pcountryinfo->countrycode) @@ -659,7 +662,7 @@ static int lbs_process_bss(struct bss_descriptor *bss, (int) (pcountryinfo->len + 2)); break; - case MFIE_TYPE_RATES_EX: + case WLAN_EID_EXT_SUPP_RATES: /* only process extended supported rate if data rate is * already found. Data rate IE should come before * extended supported rate IE @@ -670,50 +673,51 @@ static int lbs_process_bss(struct bss_descriptor *bss, break; } - n_ex_rates = elem->len; + n_ex_rates = pos[1]; if (n_basic_rates + n_ex_rates > MAX_RATES) n_ex_rates = MAX_RATES - n_basic_rates; p = bss->rates + n_basic_rates; - memcpy(p, elem->data, n_ex_rates); + memcpy(p, pos + 2, n_ex_rates); break; - case MFIE_TYPE_GENERIC: - if (elem->len >= 4 && - elem->data[0] == 0x00 && elem->data[1] == 0x50 && - elem->data[2] == 0xf2 && elem->data[3] == 0x01) { - bss->wpa_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN); - memcpy(bss->wpa_ie, elem, bss->wpa_ie_len); + case WLAN_EID_GENERIC: + if (pos[1] >= 4 && + pos[2] == 0x00 && pos[3] == 0x50 && + pos[4] == 0xf2 && pos[5] == 0x01) { + bss->wpa_ie_len = min(pos[1] + 2, MAX_WPA_IE_LEN); + memcpy(bss->wpa_ie, pos, bss->wpa_ie_len); lbs_deb_scan("got WPA IE\n"); - lbs_deb_hex(LBS_DEB_SCAN, "WPA IE", bss->wpa_ie, elem->len); - } else if (elem->len >= MARVELL_MESH_IE_LENGTH && - elem->data[0] == 0x00 && elem->data[1] == 0x50 && - elem->data[2] == 0x43 && elem->data[3] == 0x04) { + lbs_deb_hex(LBS_DEB_SCAN, "WPA IE", bss->wpa_ie, + bss->wpa_ie_len); + } else if (pos[1] >= MARVELL_MESH_IE_LENGTH && + pos[2] == 0x00 && pos[3] == 0x50 && + pos[4] == 0x43 && pos[4] == 0x04) { lbs_deb_scan("got mesh IE\n"); bss->mesh = 1; } else { lbs_deb_scan("got generic IE: %02x:%02x:%02x:%02x, len %d\n", - elem->data[0], elem->data[1], - elem->data[2], elem->data[3], - elem->len); + pos[2], pos[3], + pos[4], pos[5], + pos[1]); } break; - case MFIE_TYPE_RSN: + case WLAN_EID_RSN: lbs_deb_scan("got RSN IE\n"); - bss->rsn_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN); - memcpy(bss->rsn_ie, elem, bss->rsn_ie_len); + bss->rsn_ie_len = min(pos[1] + 2, MAX_WPA_IE_LEN); + memcpy(bss->rsn_ie, pos, bss->rsn_ie_len); lbs_deb_hex(LBS_DEB_SCAN, "process_bss: RSN_IE", - bss->rsn_ie, elem->len); + bss->rsn_ie, bss->rsn_ie_len); break; default: lbs_deb_scan("got IE 0x%04x, len %d\n", - elem->id, elem->len); + pos[0], pos[1]); break; } - pos += elem->len + 2; + pos += pos[1] + 2; } /* Timestamp */ @@ -741,10 +745,11 @@ static int lbs_process_bss(struct bss_descriptor *bss, int lbs_send_specific_ssid_scan(struct lbs_private *priv, uint8_t *ssid, uint8_t ssid_len) { + DECLARE_SSID_BUF(ssid_buf); int ret = 0; lbs_deb_enter_args(LBS_DEB_SCAN, "SSID '%s'\n", - escape_essid(ssid, ssid_len)); + print_ssid(ssid_buf, ssid, ssid_len)); if (!ssid_len) goto out; @@ -939,7 +944,8 @@ static inline char *lbs_translate_scan(struct lbs_private *priv, int lbs_set_scan(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct lbs_private *priv = dev->priv; + DECLARE_SSID_BUF(ssid); + struct lbs_private *priv = netdev_priv(dev); int ret = 0; lbs_deb_enter(LBS_DEB_WEXT); @@ -968,7 +974,7 @@ int lbs_set_scan(struct net_device *dev, struct iw_request_info *info, priv->scan_ssid_len = req->essid_len; memcpy(priv->scan_ssid, req->essid, priv->scan_ssid_len); lbs_deb_wext("set_scan, essid '%s'\n", - escape_essid(priv->scan_ssid, priv->scan_ssid_len)); + print_ssid(ssid, priv->scan_ssid, priv->scan_ssid_len)); } else { priv->scan_ssid_len = 0; } @@ -1002,7 +1008,7 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { #define SCAN_ITEM_SIZE 128 - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); int err = 0; char *ev = extra; char *stop = ev + dwrq->length; @@ -1151,7 +1157,6 @@ static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy, struct bss_descriptor new; struct bss_descriptor *found = NULL; struct bss_descriptor *oldest = NULL; - DECLARE_MAC_BUF(mac); /* Process the data fields and IEs returned for this BSS */ memset(&new, 0, sizeof (struct bss_descriptor)); @@ -1190,7 +1195,7 @@ static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy, continue; } - lbs_deb_scan("SCAN_RESP: BSSID %s\n", print_mac(mac, new.bssid)); + lbs_deb_scan("SCAN_RESP: BSSID %pM\n", new.bssid); /* Copy the locally created newbssentry to the scan table */ memcpy(found, &new, offsetof(struct bss_descriptor, list)); diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h index 9e07b0464a8e1e432d82cb787f9e34ec95afe68f..fab7d5d097fc73f5241117e35b4adc32b30a6c1c 100644 --- a/drivers/net/wireless/libertas/scan.h +++ b/drivers/net/wireless/libertas/scan.h @@ -7,6 +7,10 @@ #ifndef _LBS_SCAN_H #define _LBS_SCAN_H +#include + +#define MAX_NETWORK_COUNT 128 + /** * @brief Maximum number of channels that can be sent in a setuserscan ioctl */ diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c index a4972fed294171dfacf99135e4de9cf7bd206371..dac462641170e6193da4f04cfd44e39222520ba3 100644 --- a/drivers/net/wireless/libertas/tx.c +++ b/drivers/net/wireless/libertas/tx.c @@ -60,7 +60,7 @@ static u32 convert_radiotap_rate_to_mv(u8 rate) int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { unsigned long flags; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct txpd *txpd; char *p802x_hdr; uint16_t pkt_len; diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h index e0c2599da92f182c2e3a31b616d04fd9c2ac4323..fb7a2d1a2525e5efae1d78c9dcf0edec7ab1a76c 100644 --- a/drivers/net/wireless/libertas/types.h +++ b/drivers/net/wireless/libertas/types.h @@ -7,7 +7,6 @@ #include #include #include -#include struct ieeetypes_cfparamset { u8 elementid; @@ -258,7 +257,7 @@ struct mrvlietypes_ledbhv { * Note that the len member of the ieee80211_info_element varies depending on * the mesh_id_len */ struct mrvl_meshie_val { - uint8_t oui[P80211_OUI_LEN]; + uint8_t oui[3]; uint8_t type; uint8_t subtype; uint8_t version; @@ -270,7 +269,7 @@ struct mrvl_meshie_val { } __attribute__ ((packed)); struct mrvl_meshie { - struct ieee80211_info_element hdr; + u8 id, len; struct mrvl_meshie_val val; } __attribute__ ((packed)); diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 82c3e5a50ea695602fa844b7cc5ce93493f1b0d3..c6102e08179e6ba7d9fcc09d7fb8a26da721024b 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include "host.h" @@ -163,7 +163,7 @@ static int lbs_get_name(struct net_device *dev, struct iw_request_info *info, static int lbs_get_freq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *fwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct chan_freq_power *cfp; lbs_deb_enter(LBS_DEB_WEXT); @@ -189,7 +189,7 @@ static int lbs_get_freq(struct net_device *dev, struct iw_request_info *info, static int lbs_get_wap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *awrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_WEXT); @@ -207,7 +207,7 @@ static int lbs_get_wap(struct net_device *dev, struct iw_request_info *info, static int lbs_set_nick(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_WEXT); @@ -231,7 +231,7 @@ static int lbs_set_nick(struct net_device *dev, struct iw_request_info *info, static int lbs_get_nick(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_WEXT); @@ -248,7 +248,7 @@ static int lbs_get_nick(struct net_device *dev, struct iw_request_info *info, static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_WEXT); @@ -273,7 +273,7 @@ static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { int ret = 0; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); u32 val = vwrq->value; lbs_deb_enter(LBS_DEB_WEXT); @@ -293,7 +293,7 @@ static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info, static int lbs_get_rts(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); int ret = 0; u16 val = 0; @@ -315,7 +315,7 @@ static int lbs_get_rts(struct net_device *dev, struct iw_request_info *info, static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); int ret = 0; u32 val = vwrq->value; @@ -336,7 +336,7 @@ static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info, static int lbs_get_frag(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); int ret = 0; u16 val = 0; @@ -359,7 +359,7 @@ static int lbs_get_frag(struct net_device *dev, struct iw_request_info *info, static int lbs_get_mode(struct net_device *dev, struct iw_request_info *info, u32 * uwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_WEXT); @@ -385,7 +385,7 @@ static int lbs_get_txpow(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); s16 curlevel = 0; int ret = 0; @@ -418,7 +418,7 @@ static int lbs_get_txpow(struct net_device *dev, static int lbs_set_retry(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); int ret = 0; u16 slimit = 0, llimit = 0; @@ -466,7 +466,7 @@ static int lbs_set_retry(struct net_device *dev, struct iw_request_info *info, static int lbs_get_retry(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); int ret = 0; u16 val = 0; @@ -542,7 +542,7 @@ static int lbs_get_range(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { int i, j; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct iw_range *range = (struct iw_range *)extra; struct chan_freq_power *cfp; u8 rates[MAX_RATES + 1]; @@ -708,7 +708,7 @@ static int lbs_get_range(struct net_device *dev, struct iw_request_info *info, static int lbs_set_power(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_WEXT); @@ -758,7 +758,7 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info, static int lbs_get_power(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_WEXT); @@ -781,7 +781,7 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev) EXCELLENT = 95, PERFECT = 100 }; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); u32 rssi_qual; u32 tx_qual; u32 quality = 0; @@ -886,7 +886,7 @@ static int lbs_set_freq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *fwrq, char *extra) { int ret = -EINVAL; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct chan_freq_power *cfp; struct assoc_request * assoc_req; @@ -943,7 +943,7 @@ static int lbs_mesh_set_freq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *fwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct chan_freq_power *cfp; int ret = -EINVAL; @@ -994,7 +994,7 @@ static int lbs_mesh_set_freq(struct net_device *dev, static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); u8 new_rate = 0; int ret = -EINVAL; u8 rates[MAX_RATES + 1]; @@ -1054,7 +1054,7 @@ static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info, static int lbs_get_rate(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_WEXT); @@ -1079,7 +1079,7 @@ static int lbs_set_mode(struct net_device *dev, struct iw_request_info *info, u32 * uwrq, char *extra) { int ret = 0; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct assoc_request * assoc_req; lbs_deb_enter(LBS_DEB_WEXT); @@ -1124,7 +1124,7 @@ static int lbs_get_encode(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, u8 * extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; lbs_deb_enter(LBS_DEB_WEXT); @@ -1319,7 +1319,7 @@ static int lbs_set_encode(struct net_device *dev, struct iw_point *dwrq, char *extra) { int ret = 0; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct assoc_request * assoc_req; u16 is_default = 0, index = 0, set_tx_key = 0; @@ -1395,7 +1395,7 @@ static int lbs_get_encodeext(struct net_device *dev, char *extra) { int ret = -EINVAL; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; int index, max_key_len; @@ -1501,7 +1501,7 @@ static int lbs_set_encodeext(struct net_device *dev, char *extra) { int ret = 0; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; int alg = ext->alg; struct assoc_request * assoc_req; @@ -1639,7 +1639,7 @@ static int lbs_set_genie(struct net_device *dev, struct iw_point *dwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); int ret = 0; struct assoc_request * assoc_req; @@ -1685,7 +1685,7 @@ static int lbs_get_genie(struct net_device *dev, char *extra) { int ret = 0; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_WEXT); @@ -1713,7 +1713,7 @@ static int lbs_set_auth(struct net_device *dev, struct iw_param *dwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct assoc_request * assoc_req; int ret = 0; int updated = 0; @@ -1816,7 +1816,7 @@ static int lbs_get_auth(struct net_device *dev, char *extra) { int ret = 0; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_WEXT); @@ -1857,7 +1857,7 @@ static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { int ret = 0; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); s16 dbm = (s16) vwrq->value; lbs_deb_enter(LBS_DEB_WEXT); @@ -1936,7 +1936,7 @@ static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info, static int lbs_get_essid(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_WEXT); @@ -1971,12 +1971,13 @@ static int lbs_get_essid(struct net_device *dev, struct iw_request_info *info, static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); int ret = 0; u8 ssid[IW_ESSID_MAX_SIZE]; u8 ssid_len = 0; struct assoc_request * assoc_req; int in_ssid_len = dwrq->length; + DECLARE_SSID_BUF(ssid_buf); lbs_deb_enter(LBS_DEB_WEXT); @@ -2005,7 +2006,7 @@ static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info, lbs_deb_wext("requested any SSID\n"); } else { lbs_deb_wext("requested SSID '%s'\n", - escape_essid(ssid, ssid_len)); + print_ssid(ssid_buf, ssid, ssid_len)); } out: @@ -2039,7 +2040,7 @@ static int lbs_mesh_get_essid(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_WEXT); @@ -2057,7 +2058,7 @@ static int lbs_mesh_set_essid(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); int ret = 0; lbs_deb_enter(LBS_DEB_WEXT); @@ -2101,10 +2102,9 @@ static int lbs_mesh_set_essid(struct net_device *dev, static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *awrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct assoc_request * assoc_req; int ret = 0; - DECLARE_MAC_BUF(mac); lbs_deb_enter(LBS_DEB_WEXT); @@ -2114,7 +2114,7 @@ static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info, if (awrq->sa_family != ARPHRD_ETHER) return -EINVAL; - lbs_deb_wext("ASSOC: WAP: sa_data %s\n", print_mac(mac, awrq->sa_data)); + lbs_deb_wext("ASSOC: WAP: sa_data %pM\n", awrq->sa_data); mutex_lock(&priv->lock); diff --git a/drivers/net/wireless/libertas_tf/cmd.c b/drivers/net/wireless/libertas_tf/cmd.c index fdbcf8ba3e8a0c6bc02036c05d7c9bd7d9c19dc2..3d3914c83b145388c6d2afc6c6c6fc124f8b2469 100644 --- a/drivers/net/wireless/libertas_tf/cmd.c +++ b/drivers/net/wireless/libertas_tf/cmd.c @@ -79,7 +79,6 @@ int lbtf_update_hw_spec(struct lbtf_private *priv) struct cmd_ds_get_hw_spec cmd; int ret = -1; u32 i; - DECLARE_MAC_BUF(mac); memset(&cmd, 0, sizeof(cmd)); cmd.hdr.size = cpu_to_le16(sizeof(cmd)); @@ -96,8 +95,8 @@ int lbtf_update_hw_spec(struct lbtf_private *priv) priv->fwrelease = (priv->fwrelease << 8) | (priv->fwrelease >> 24 & 0xff); - printk(KERN_INFO "libertastf: %s, fw %u.%u.%up%u, cap 0x%08x\n", - print_mac(mac, cmd.permanentaddr), + printk(KERN_INFO "libertastf: %pM, fw %u.%u.%up%u, cap 0x%08x\n", + cmd.permanentaddr, priv->fwrelease >> 24 & 0xff, priv->fwrelease >> 16 & 0xff, priv->fwrelease >> 8 & 0xff, diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c index feff945ad856368e737eac8a344352b947ad73c5..d1fc305de5fe03c755368b70690d3f81d5fe54ba 100644 --- a/drivers/net/wireless/libertas_tf/main.c +++ b/drivers/net/wireless/libertas_tf/main.c @@ -354,9 +354,11 @@ static void lbtf_op_remove_interface(struct ieee80211_hw *hw, priv->vif = NULL; } -static int lbtf_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +static int lbtf_op_config(struct ieee80211_hw *hw, u32 changed) { struct lbtf_private *priv = hw->priv; + struct ieee80211_conf *conf = &hw->conf; + if (conf->channel->center_freq != priv->cur_freq) { priv->cur_freq = conf->channel->center_freq; lbtf_set_channel(priv, conf->channel->hw_value); @@ -590,14 +592,14 @@ EXPORT_SYMBOL_GPL(lbtf_remove_card); void lbtf_send_tx_feedback(struct lbtf_private *priv, u8 retrycnt, u8 fail) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(priv->tx_skb); - memset(&info->status, 0, sizeof(info->status)); + + ieee80211_tx_info_clear_status(info); /* * Commented out, otherwise we never go beyond 1Mbit/s using mac80211 * default pid rc algorithm. * * info->status.retry_count = MRVL_DEFAULT_RETRIES - retrycnt; */ - info->status.excessive_retries = fail ? 1 : 0; if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && !fail) info->flags |= IEEE80211_TX_STAT_ACK; skb_pull(priv->tx_skb, sizeof(struct txpd)); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 1a019e98dac3ee8ef0b7be504a6cee8af6a36369..f83d69e813d3a23cf46c8aefd94833147ab05d9f 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -21,6 +21,7 @@ #include #include #include +#include MODULE_AUTHOR("Jouni Malinen"); MODULE_DESCRIPTION("Software simulator of 802.11 radio(s) for mac80211"); @@ -32,6 +33,9 @@ MODULE_PARM_DESC(radios, "Number of simulated radios"); struct hwsim_vif_priv { u32 magic; + u8 bssid[ETH_ALEN]; + bool assoc; + u16 aid; }; #define HWSIM_VIF_MAGIC 0x69537748 @@ -63,13 +67,13 @@ struct hwsim_sta_priv { static inline void hwsim_check_sta_magic(struct ieee80211_sta *sta) { struct hwsim_sta_priv *sp = (void *)sta->drv_priv; - WARN_ON(sp->magic != HWSIM_VIF_MAGIC); + WARN_ON(sp->magic != HWSIM_STA_MAGIC); } static inline void hwsim_set_sta_magic(struct ieee80211_sta *sta) { struct hwsim_sta_priv *sp = (void *)sta->drv_priv; - sp->magic = HWSIM_VIF_MAGIC; + sp->magic = HWSIM_STA_MAGIC; } static inline void hwsim_clear_sta_magic(struct ieee80211_sta *sta) @@ -132,6 +136,12 @@ struct mac80211_hwsim_data { unsigned int rx_filter; int started; struct timer_list beacon_timer; + enum ps_mode { + PS_DISABLED, PS_ENABLED, PS_AUTO_POLL, PS_MANUAL_POLL + } ps; + bool ps_poll_pending; + struct dentry *debugfs; + struct dentry *debugfs_ps; }; @@ -196,6 +206,34 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw, } +static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data, + struct sk_buff *skb) +{ + switch (data->ps) { + case PS_DISABLED: + return true; + case PS_ENABLED: + return false; + case PS_AUTO_POLL: + /* TODO: accept (some) Beacons by default and other frames only + * if pending PS-Poll has been sent */ + return true; + case PS_MANUAL_POLL: + /* Allow unicast frames to own address if there is a pending + * PS-Poll */ + if (data->ps_poll_pending && + memcmp(data->hw->wiphy->perm_addr, skb->data + 4, + ETH_ALEN) == 0) { + data->ps_poll_pending = false; + return true; + } + return false; + } + + return true; +} + + static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, struct sk_buff *skb) { @@ -209,9 +247,12 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, /* TODO: set mactime */ rx_status.freq = data->channel->center_freq; rx_status.band = data->channel->band; - rx_status.rate_idx = info->tx_rate_idx; + rx_status.rate_idx = info->control.rates[0].idx; /* TODO: simulate signal strength (and optional packet drop) */ + if (data->ps != PS_DISABLED) + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); + /* Copy skb to all enabled radios that are on the current frequency */ spin_lock(&hwsim_radio_lock); list_for_each_entry(data2, &hwsim_radios, list) { @@ -221,6 +262,7 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, continue; if (!data2->started || !data2->radio_enabled || + !hwsim_ps_rx_ok(data2, skb) || data->channel->center_freq != data2->channel->center_freq) continue; @@ -269,13 +311,9 @@ static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) if (txi->control.sta) hwsim_check_sta_magic(txi->control.sta); - memset(&txi->status, 0, sizeof(txi->status)); - if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK)) { - if (ack) - txi->flags |= IEEE80211_TX_STAT_ACK; - else - txi->status.excessive_retries = 1; - } + ieee80211_tx_info_clear_status(txi); + if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK) && ack) + txi->flags |= IEEE80211_TX_STAT_ACK; ieee80211_tx_status_irqsafe(hw, skb); return NETDEV_TX_OK; } @@ -294,6 +332,7 @@ static void mac80211_hwsim_stop(struct ieee80211_hw *hw) { struct mac80211_hwsim_data *data = hw->priv; data->started = 0; + del_timer(&data->beacon_timer); printk(KERN_DEBUG "%s:%s\n", wiphy_name(hw->wiphy), __func__); } @@ -301,10 +340,9 @@ static void mac80211_hwsim_stop(struct ieee80211_hw *hw) static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { - DECLARE_MAC_BUF(mac); - printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%s)\n", + printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n", wiphy_name(hw->wiphy), __func__, conf->type, - print_mac(mac, conf->mac_addr)); + conf->mac_addr); hwsim_set_magic(conf->vif); return 0; } @@ -313,10 +351,9 @@ static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw, static void mac80211_hwsim_remove_interface( struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { - DECLARE_MAC_BUF(mac); - printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%s)\n", + printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n", wiphy_name(hw->wiphy), __func__, conf->type, - print_mac(mac, conf->mac_addr)); + conf->mac_addr); hwsim_check_magic(conf->vif); hwsim_clear_magic(conf->vif); } @@ -331,7 +368,8 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, hwsim_check_magic(vif); - if (vif->type != NL80211_IFTYPE_AP) + if (vif->type != NL80211_IFTYPE_AP && + vif->type != NL80211_IFTYPE_MESH_POINT) return; skb = ieee80211_beacon_get(hw, vif); @@ -361,10 +399,10 @@ static void mac80211_hwsim_beacon(unsigned long arg) } -static int mac80211_hwsim_config(struct ieee80211_hw *hw, - struct ieee80211_conf *conf) +static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) { struct mac80211_hwsim_data *data = hw->priv; + struct ieee80211_conf *conf = &hw->conf; printk(KERN_DEBUG "%s:%s (freq=%d radio_enabled=%d beacon_int=%d)\n", wiphy_name(hw->wiphy), __func__, @@ -409,7 +447,16 @@ static int mac80211_hwsim_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_if_conf *conf) { + struct hwsim_vif_priv *vp = (void *)vif->drv_priv; + hwsim_check_magic(vif); + if (conf->changed & IEEE80211_IFCC_BSSID) { + DECLARE_MAC_BUF(mac); + printk(KERN_DEBUG "%s:%s: BSSID changed: %pM\n", + wiphy_name(hw->wiphy), __func__, + conf->bssid); + memcpy(vp->bssid, conf->bssid, ETH_ALEN); + } return 0; } @@ -418,7 +465,46 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_bss_conf *info, u32 changed) { + struct hwsim_vif_priv *vp = (void *)vif->drv_priv; + hwsim_check_magic(vif); + + printk(KERN_DEBUG "%s:%s(changed=0x%x)\n", + wiphy_name(hw->wiphy), __func__, changed); + + if (changed & BSS_CHANGED_ASSOC) { + printk(KERN_DEBUG " %s: ASSOC: assoc=%d aid=%d\n", + wiphy_name(hw->wiphy), info->assoc, info->aid); + vp->assoc = info->assoc; + vp->aid = info->aid; + } + + if (changed & BSS_CHANGED_ERP_CTS_PROT) { + printk(KERN_DEBUG " %s: ERP_CTS_PROT: %d\n", + wiphy_name(hw->wiphy), info->use_cts_prot); + } + + if (changed & BSS_CHANGED_ERP_PREAMBLE) { + printk(KERN_DEBUG " %s: ERP_PREAMBLE: %d\n", + wiphy_name(hw->wiphy), info->use_short_preamble); + } + + if (changed & BSS_CHANGED_ERP_SLOT) { + printk(KERN_DEBUG " %s: ERP_SLOT: %d\n", + wiphy_name(hw->wiphy), info->use_short_slot); + } + + if (changed & BSS_CHANGED_HT) { + printk(KERN_DEBUG " %s: HT: op_mode=0x%x\n", + wiphy_name(hw->wiphy), + info->ht.operation_mode); + } + + if (changed & BSS_CHANGED_BASIC_RATES) { + printk(KERN_DEBUG " %s: BASIC_RATES: 0x%llx\n", + wiphy_name(hw->wiphy), + (unsigned long long) info->basic_rates); + } } static void mac80211_hwsim_sta_notify(struct ieee80211_hw *hw, @@ -434,6 +520,10 @@ static void mac80211_hwsim_sta_notify(struct ieee80211_hw *hw, case STA_NOTIFY_REMOVE: hwsim_clear_sta_magic(sta); break; + case STA_NOTIFY_SLEEP: + case STA_NOTIFY_AWAKE: + /* TODO: make good use of these flags */ + break; } } @@ -445,6 +535,17 @@ static int mac80211_hwsim_set_tim(struct ieee80211_hw *hw, return 0; } +static int mac80211_hwsim_conf_tx( + struct ieee80211_hw *hw, u16 queue, + const struct ieee80211_tx_queue_params *params) +{ + printk(KERN_DEBUG "%s:%s (queue=%d txop=%d cw_min=%d cw_max=%d " + "aifs=%d)\n", + wiphy_name(hw->wiphy), __func__, queue, + params->txop, params->cw_min, params->cw_max, params->aifs); + return 0; +} + static const struct ieee80211_ops mac80211_hwsim_ops = { .tx = mac80211_hwsim_tx, @@ -458,6 +559,7 @@ static const struct ieee80211_ops mac80211_hwsim_ops = .bss_info_changed = mac80211_hwsim_bss_info_changed, .sta_notify = mac80211_hwsim_sta_notify, .set_tim = mac80211_hwsim_set_tim, + .conf_tx = mac80211_hwsim_conf_tx, }; @@ -474,6 +576,8 @@ static void mac80211_hwsim_free(void) spin_unlock_bh(&hwsim_radio_lock); list_for_each_entry(data, &tmplist, list) { + debugfs_remove(data->debugfs_ps); + debugfs_remove(data->debugfs); ieee80211_unregister_hw(data->hw); device_unregister(data->dev); ieee80211_free_hw(data->hw); @@ -499,13 +603,131 @@ static void hwsim_mon_setup(struct net_device *dev) } +static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) +{ + struct mac80211_hwsim_data *data = dat; + struct hwsim_vif_priv *vp = (void *)vif->drv_priv; + DECLARE_MAC_BUF(buf); + struct sk_buff *skb; + struct ieee80211_pspoll *pspoll; + + if (!vp->assoc) + return; + + printk(KERN_DEBUG "%s:%s: send PS-Poll to %pM for aid %d\n", + wiphy_name(data->hw->wiphy), __func__, vp->bssid, vp->aid); + + skb = dev_alloc_skb(sizeof(*pspoll)); + if (!skb) + return; + pspoll = (void *) skb_put(skb, sizeof(*pspoll)); + pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | + IEEE80211_STYPE_PSPOLL | + IEEE80211_FCTL_PM); + pspoll->aid = cpu_to_le16(0xc000 | vp->aid); + memcpy(pspoll->bssid, vp->bssid, ETH_ALEN); + memcpy(pspoll->ta, mac, ETH_ALEN); + if (data->radio_enabled && + !mac80211_hwsim_tx_frame(data->hw, skb)) + printk(KERN_DEBUG "%s: PS-Poll frame not ack'ed\n", __func__); + dev_kfree_skb(skb); +} + + +static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, + struct ieee80211_vif *vif, int ps) +{ + struct hwsim_vif_priv *vp = (void *)vif->drv_priv; + DECLARE_MAC_BUF(buf); + struct sk_buff *skb; + struct ieee80211_hdr *hdr; + + if (!vp->assoc) + return; + + printk(KERN_DEBUG "%s:%s: send data::nullfunc to %pM ps=%d\n", + wiphy_name(data->hw->wiphy), __func__, vp->bssid, ps); + + skb = dev_alloc_skb(sizeof(*hdr)); + if (!skb) + return; + hdr = (void *) skb_put(skb, sizeof(*hdr) - ETH_ALEN); + hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | + IEEE80211_STYPE_NULLFUNC | + (ps ? IEEE80211_FCTL_PM : 0)); + hdr->duration_id = cpu_to_le16(0); + memcpy(hdr->addr1, vp->bssid, ETH_ALEN); + memcpy(hdr->addr2, mac, ETH_ALEN); + memcpy(hdr->addr3, vp->bssid, ETH_ALEN); + if (data->radio_enabled && + !mac80211_hwsim_tx_frame(data->hw, skb)) + printk(KERN_DEBUG "%s: nullfunc frame not ack'ed\n", __func__); + dev_kfree_skb(skb); +} + + +static void hwsim_send_nullfunc_ps(void *dat, u8 *mac, + struct ieee80211_vif *vif) +{ + struct mac80211_hwsim_data *data = dat; + hwsim_send_nullfunc(data, mac, vif, 1); +} + + +static void hwsim_send_nullfunc_no_ps(void *dat, u8 *mac, + struct ieee80211_vif *vif) +{ + struct mac80211_hwsim_data *data = dat; + hwsim_send_nullfunc(data, mac, vif, 0); +} + + +static int hwsim_fops_ps_read(void *dat, u64 *val) +{ + struct mac80211_hwsim_data *data = dat; + *val = data->ps; + return 0; +} + +static int hwsim_fops_ps_write(void *dat, u64 val) +{ + struct mac80211_hwsim_data *data = dat; + enum ps_mode old_ps; + + if (val != PS_DISABLED && val != PS_ENABLED && val != PS_AUTO_POLL && + val != PS_MANUAL_POLL) + return -EINVAL; + + old_ps = data->ps; + data->ps = val; + + if (val == PS_MANUAL_POLL) { + ieee80211_iterate_active_interfaces(data->hw, + hwsim_send_ps_poll, data); + data->ps_poll_pending = true; + } else if (old_ps == PS_DISABLED && val != PS_DISABLED) { + ieee80211_iterate_active_interfaces(data->hw, + hwsim_send_nullfunc_ps, + data); + } else if (old_ps != PS_DISABLED && val == PS_DISABLED) { + ieee80211_iterate_active_interfaces(data->hw, + hwsim_send_nullfunc_no_ps, + data); + } + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_ps, hwsim_fops_ps_read, hwsim_fops_ps_write, + "%llu\n"); + + static int __init init_mac80211_hwsim(void) { int i, err = 0; u8 addr[ETH_ALEN]; struct mac80211_hwsim_data *data; struct ieee80211_hw *hw; - DECLARE_MAC_BUF(mac); if (radios < 1 || radios > 100) return -EINVAL; @@ -553,7 +775,8 @@ static int __init init_mac80211_hwsim(void) hw->queues = 4; hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_AP); + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_MESH_POINT); hw->ampdu_queues = 1; /* ask mac80211 to reserve space for magic */ @@ -566,19 +789,18 @@ static int __init init_mac80211_hwsim(void) data->band.n_channels = ARRAY_SIZE(hwsim_channels); data->band.bitrates = data->rates; data->band.n_bitrates = ARRAY_SIZE(hwsim_rates); - data->band.ht_info.ht_supported = 1; - data->band.ht_info.cap = IEEE80211_HT_CAP_SUP_WIDTH | + data->band.ht_cap.ht_supported = true; + data->band.ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_DSSSCCK40; - data->band.ht_info.ampdu_factor = 0x3; - data->band.ht_info.ampdu_density = 0x6; - memset(data->band.ht_info.supp_mcs_set, 0, - sizeof(data->band.ht_info.supp_mcs_set)); - data->band.ht_info.supp_mcs_set[0] = 0xff; - data->band.ht_info.supp_mcs_set[1] = 0xff; - data->band.ht_info.supp_mcs_set[12] = - IEEE80211_HT_CAP_MCS_TX_DEFINED; + data->band.ht_cap.ampdu_factor = 0x3; + data->band.ht_cap.ampdu_density = 0x6; + memset(&data->band.ht_cap.mcs, 0, + sizeof(data->band.ht_cap.mcs)); + data->band.ht_cap.mcs.rx_mask[0] = 0xff; + data->band.ht_cap.mcs.rx_mask[1] = 0xff; + data->band.ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &data->band; err = ieee80211_register_hw(hw); @@ -588,9 +810,15 @@ static int __init init_mac80211_hwsim(void) goto failed_hw; } - printk(KERN_DEBUG "%s: hwaddr %s registered\n", + printk(KERN_DEBUG "%s: hwaddr %pM registered\n", wiphy_name(hw->wiphy), - print_mac(mac, hw->wiphy->perm_addr)); + hw->wiphy->perm_addr); + + data->debugfs = debugfs_create_dir("hwsim", + hw->wiphy->debugfsdir); + data->debugfs_ps = debugfs_create_file("ps", 0666, + data->debugfs, data, + &hwsim_fops_ps); setup_timer(&data->beacon_timer, mac80211_hwsim_beacon, (unsigned long) hw); diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index a670f36b5f3f3c1e3222d0e45c27491132caed7d..24caec6caf1fc0f98cdbffb1141ee6c57dd123aa 100644 --- a/drivers/net/wireless/netwave_cs.c +++ b/drivers/net/wireless/netwave_cs.c @@ -737,7 +737,6 @@ static int netwave_pcmcia_config(struct pcmcia_device *link) { win_req_t req; memreq_t mem; u_char __iomem *ramBase = NULL; - DECLARE_MAC_BUF(mac); DEBUG(0, "netwave_pcmcia_config(0x%p)\n", link); @@ -808,12 +807,12 @@ static int netwave_pcmcia_config(struct pcmcia_device *link) { dev->dev_addr[i] = readb(ramBase + NETWAVE_EREG_PA + i); printk(KERN_INFO "%s: Netwave: port %#3lx, irq %d, mem %lx, " - "id %c%c, hw_addr %s\n", + "id %c%c, hw_addr %pM\n", dev->name, dev->base_addr, dev->irq, (u_long) ramBase, (int) readb(ramBase+NETWAVE_EREG_NI), (int) readb(ramBase+NETWAVE_EREG_NI+1), - print_mac(mac, dev->dev_addr)); + dev->dev_addr); /* get revision words */ printk(KERN_DEBUG "Netwave_reset: revision %04x %04x\n", @@ -1308,7 +1307,6 @@ static int netwave_rx(struct net_device *dev) /* Queue packet for network layer */ netif_rx(skb); - dev->last_rx = jiffies; priv->stats.rx_packets++; priv->stats.rx_bytes += rcvLen; diff --git a/drivers/net/wireless/orinoco/Makefile b/drivers/net/wireless/orinoco/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..791366e08c501dac79c1becf88e056d8afa5c7df --- /dev/null +++ b/drivers/net/wireless/orinoco/Makefile @@ -0,0 +1,12 @@ +# +# Makefile for the orinoco wireless device drivers. +# + +obj-$(CONFIG_HERMES) += orinoco.o hermes.o hermes_dld.o +obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o +obj-$(CONFIG_APPLE_AIRPORT) += airport.o +obj-$(CONFIG_PLX_HERMES) += orinoco_plx.o +obj-$(CONFIG_PCI_HERMES) += orinoco_pci.o +obj-$(CONFIG_TMD_HERMES) += orinoco_tmd.o +obj-$(CONFIG_NORTEL_HERMES) += orinoco_nortel.o +obj-$(CONFIG_PCMCIA_SPECTRUM) += spectrum_cs.o diff --git a/drivers/net/wireless/airport.c b/drivers/net/wireless/orinoco/airport.c similarity index 99% rename from drivers/net/wireless/airport.c rename to drivers/net/wireless/orinoco/airport.c index ce03a2e865fabafbc6b04b0eee3022a4a6b1a20d..28f1cae48439ec787b13fdd424c2e4f065455fd1 100644 --- a/drivers/net/wireless/airport.c +++ b/drivers/net/wireless/orinoco/airport.c @@ -279,7 +279,7 @@ init_airport(void) static void __exit exit_airport(void) { - return macio_unregister_driver(&airport_driver); + macio_unregister_driver(&airport_driver); } module_init(init_airport); diff --git a/drivers/net/wireless/hermes.c b/drivers/net/wireless/orinoco/hermes.c similarity index 100% rename from drivers/net/wireless/hermes.c rename to drivers/net/wireless/orinoco/hermes.c diff --git a/drivers/net/wireless/hermes.h b/drivers/net/wireless/orinoco/hermes.h similarity index 100% rename from drivers/net/wireless/hermes.h rename to drivers/net/wireless/orinoco/hermes.h diff --git a/drivers/net/wireless/hermes_dld.c b/drivers/net/wireless/orinoco/hermes_dld.c similarity index 100% rename from drivers/net/wireless/hermes_dld.c rename to drivers/net/wireless/orinoco/hermes_dld.c diff --git a/drivers/net/wireless/hermes_dld.h b/drivers/net/wireless/orinoco/hermes_dld.h similarity index 100% rename from drivers/net/wireless/hermes_dld.h rename to drivers/net/wireless/orinoco/hermes_dld.h diff --git a/drivers/net/wireless/hermes_rid.h b/drivers/net/wireless/orinoco/hermes_rid.h similarity index 100% rename from drivers/net/wireless/hermes_rid.h rename to drivers/net/wireless/orinoco/hermes_rid.h diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco/orinoco.c similarity index 96% rename from drivers/net/wireless/orinoco.c rename to drivers/net/wireless/orinoco/orinoco.c index e0512e49d6d374052af6401c020d30ad22ca122b..bc84e2792f8a887838f42c02bbe5ed4f68c500af 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco/orinoco.c @@ -84,10 +84,11 @@ #include #include #include +#include #include #include +#include #include -#include #include #include @@ -143,7 +144,7 @@ static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; #define ENCAPS_OVERHEAD (sizeof(encaps_hdr) + 2) #define ORINOCO_MIN_MTU 256 -#define ORINOCO_MAX_MTU (IEEE80211_DATA_LEN - ENCAPS_OVERHEAD) +#define ORINOCO_MAX_MTU (IEEE80211_MAX_DATA_LEN - ENCAPS_OVERHEAD) #define SYMBOL_MAX_VER_LEN (14) #define USER_BAP 0 @@ -392,7 +393,7 @@ static void orinoco_bss_data_init(struct orinoco_private *priv) } static inline u8 *orinoco_get_ie(u8 *data, size_t len, - enum ieee80211_mfie eid) + enum ieee80211_eid eid) { u8 *p = data; while ((p + 2) < (data + len)) { @@ -409,7 +410,7 @@ static inline u8 *orinoco_get_wpa_ie(u8 *data, size_t len) { u8 *p = data; while ((p + 2 + WPA_SELECTOR_LEN) < (data + len)) { - if ((p[0] == MFIE_TYPE_GENERIC) && + if ((p[0] == WLAN_EID_GENERIC) && (memcmp(&p[2], WPA_OUI_TYPE, WPA_SELECTOR_LEN) == 0)) return p; p += p[1] + 2; @@ -431,9 +432,9 @@ struct fw_info { }; const static struct fw_info orinoco_fw[] = { - { "", "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 }, - { "", "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 }, - { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", "", 0x00003100, 512 } + { NULL, "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 }, + { NULL, "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 }, + { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", NULL, 0x00003100, 512 } }; /* Structure used to access fields in FW @@ -487,13 +488,17 @@ orinoco_dl_firmware(struct orinoco_private *priv, if (err) goto free; - err = request_firmware(&fw_entry, firmware, priv->dev); - if (err) { - printk(KERN_ERR "%s: Cannot find firmware %s\n", - dev->name, firmware); - err = -ENOENT; - goto free; - } + if (!priv->cached_fw) { + err = request_firmware(&fw_entry, firmware, priv->dev); + + if (err) { + printk(KERN_ERR "%s: Cannot find firmware %s\n", + dev->name, firmware); + err = -ENOENT; + goto free; + } + } else + fw_entry = priv->cached_fw; hdr = (const struct orinoco_fw_header *) fw_entry->data; @@ -535,7 +540,9 @@ orinoco_dl_firmware(struct orinoco_private *priv, dev->name, hermes_present(hw)); abort: - release_firmware(fw_entry); + /* If we requested the firmware, release it. */ + if (!priv->cached_fw) + release_firmware(fw_entry); free: kfree(pda); @@ -639,34 +646,41 @@ symbol_dl_firmware(struct orinoco_private *priv, int ret; const struct firmware *fw_entry; - if (request_firmware(&fw_entry, fw->pri_fw, - priv->dev) != 0) { - printk(KERN_ERR "%s: Cannot find firmware: %s\n", - dev->name, fw->pri_fw); - return -ENOENT; - } + if (!priv->cached_pri_fw) { + if (request_firmware(&fw_entry, fw->pri_fw, priv->dev) != 0) { + printk(KERN_ERR "%s: Cannot find firmware: %s\n", + dev->name, fw->pri_fw); + return -ENOENT; + } + } else + fw_entry = priv->cached_pri_fw; /* Load primary firmware */ ret = symbol_dl_image(priv, fw, fw_entry->data, fw_entry->data + fw_entry->size, 0); - release_firmware(fw_entry); + + if (!priv->cached_pri_fw) + release_firmware(fw_entry); if (ret) { printk(KERN_ERR "%s: Primary firmware download failed\n", dev->name); return ret; } - if (request_firmware(&fw_entry, fw->sta_fw, - priv->dev) != 0) { - printk(KERN_ERR "%s: Cannot find firmware: %s\n", - dev->name, fw->sta_fw); - return -ENOENT; - } + if (!priv->cached_fw) { + if (request_firmware(&fw_entry, fw->sta_fw, priv->dev) != 0) { + printk(KERN_ERR "%s: Cannot find firmware: %s\n", + dev->name, fw->sta_fw); + return -ENOENT; + } + } else + fw_entry = priv->cached_fw; /* Load secondary firmware */ ret = symbol_dl_image(priv, fw, fw_entry->data, fw_entry->data + fw_entry->size, 1); - release_firmware(fw_entry); + if (!priv->cached_fw) + release_firmware(fw_entry); if (ret) { printk(KERN_ERR "%s: Secondary firmware download failed\n", dev->name); @@ -699,6 +713,45 @@ static int orinoco_download(struct orinoco_private *priv) return err; } +#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP) +static void orinoco_cache_fw(struct orinoco_private *priv, int ap) +{ + const struct firmware *fw_entry = NULL; + const char *pri_fw; + const char *fw; + + pri_fw = orinoco_fw[priv->firmware_type].pri_fw; + if (ap) + fw = orinoco_fw[priv->firmware_type].ap_fw; + else + fw = orinoco_fw[priv->firmware_type].sta_fw; + + if (pri_fw) { + if (request_firmware(&fw_entry, pri_fw, priv->dev) == 0) + priv->cached_pri_fw = fw_entry; + } + + if (fw) { + if (request_firmware(&fw_entry, fw, priv->dev) == 0) + priv->cached_fw = fw_entry; + } +} + +static void orinoco_uncache_fw(struct orinoco_private *priv) +{ + if (priv->cached_pri_fw) + release_firmware(priv->cached_pri_fw); + if (priv->cached_fw) + release_firmware(priv->cached_fw); + + priv->cached_pri_fw = NULL; + priv->cached_fw = NULL; +} +#else +#define orinoco_cache_fw(priv, ap) +#define orinoco_uncache_fw(priv) +#endif + /********************************************************************/ /* Device methods */ /********************************************************************/ @@ -800,7 +853,7 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev) wstats->qual.qual = (int)le16_to_cpu(cq.qual); wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95; wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95; - wstats->qual.updated = 7; + wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; } } @@ -830,7 +883,8 @@ static int orinoco_change_mtu(struct net_device *dev, int new_mtu) if ( (new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU) ) return -EINVAL; - if ( (new_mtu + ENCAPS_OVERHEAD + IEEE80211_HLEN) > + /* MTU + encapsulation + header length */ + if ( (new_mtu + ENCAPS_OVERHEAD + sizeof(struct ieee80211_hdr)) > (priv->nicbuf_size - ETH_HLEN) ) return -EINVAL; @@ -1158,7 +1212,7 @@ static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac, wstats.level = level - 0x95; wstats.noise = noise - 0x95; wstats.qual = (level > noise) ? (level - noise) : 0; - wstats.updated = 7; + wstats.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; /* Update spy records */ wireless_spy_update(dev, mac, &wstats); } @@ -1245,7 +1299,7 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid, } /* sanity check the length */ - if (datalen > IEEE80211_DATA_LEN + 12) { + if (datalen > IEEE80211_MAX_DATA_LEN + 12) { printk(KERN_DEBUG "%s: oversized monitor frame, " "data length = %d\n", dev->name, datalen); stats->rx_length_errors++; @@ -1280,7 +1334,6 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid, skb->pkt_type = PACKET_OTHERHOST; skb->protocol = __constant_htons(ETH_P_802_2); - dev->last_rx = jiffies; stats->rx_packets++; stats->rx_bytes += skb->len; @@ -1374,7 +1427,7 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) data. */ goto out; } - if (length > IEEE80211_DATA_LEN) { + if (length > IEEE80211_MAX_DATA_LEN) { printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n", dev->name, length); stats->rx_length_errors++; @@ -1477,12 +1530,11 @@ static void orinoco_rx(struct net_device *dev, MICHAEL_MIC_LEN)) { union iwreq_data wrqu; struct iw_michaelmicfailure wxmic; - DECLARE_MAC_BUF(mac); printk(KERN_WARNING "%s: " - "Invalid Michael MIC in data frame from %s, " + "Invalid Michael MIC in data frame from %pM, " "using key %i\n", - dev->name, print_mac(mac, src), key_id); + dev->name, src, key_id); /* TODO: update stats */ @@ -1530,7 +1582,6 @@ static void orinoco_rx(struct net_device *dev, else memcpy(hdr->h_source, desc->addr2, ETH_ALEN); - dev->last_rx = jiffies; skb->protocol = eth_type_trans(skb, dev); skb->ip_summed = CHECKSUM_NONE; if (fc & IEEE80211_FCTL_TODS) @@ -1699,7 +1750,7 @@ static void orinoco_send_bssid_wevent(struct orinoco_private *priv) union iwreq_data wrqu; int err; - err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENTBSSID, + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID, ETH_ALEN, NULL, wrqu.ap_addr.sa_data); if (err != 0) return; @@ -1722,7 +1773,7 @@ static void orinoco_send_assocreqie_wevent(struct orinoco_private *priv) if (!priv->has_wpa) return; - err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENT_ASSOC_REQ_INFO, + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_ASSOC_REQ_INFO, sizeof(buf), NULL, &buf); if (err != 0) return; @@ -1752,7 +1803,7 @@ static void orinoco_send_assocrespie_wevent(struct orinoco_private *priv) if (!priv->has_wpa) return; - err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENT_ASSOC_RESP_INFO, + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_ASSOC_RESP_INFO, sizeof(buf), NULL, &buf); if (err != 0) return; @@ -2301,6 +2352,11 @@ int orinoco_reinit_firmware(struct net_device *dev) int err; err = hermes_init(hw); + if (priv->do_fw_download && !err) { + err = orinoco_download(priv); + if (err) + priv->do_fw_download = 0; + } if (!err) err = orinoco_allocate_fid(dev); @@ -2926,12 +2982,6 @@ static void orinoco_reset(struct work_struct *work) } } - if (priv->do_fw_download) { - err = orinoco_download(priv); - if (err) - priv->do_fw_download = 0; - } - err = orinoco_reinit_firmware(dev); if (err) { printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n", @@ -3055,6 +3105,50 @@ irqreturn_t orinoco_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +/********************************************************************/ +/* Power management */ +/********************************************************************/ +#if defined(CONFIG_PM_SLEEP) && !defined(CONFIG_HERMES_CACHE_FW_ON_INIT) +static int orinoco_pm_notifier(struct notifier_block *notifier, + unsigned long pm_event, + void *unused) +{ + struct orinoco_private *priv = container_of(notifier, + struct orinoco_private, + pm_notifier); + + /* All we need to do is cache the firmware before suspend, and + * release it when we come out. + * + * Only need to do this if we're downloading firmware. */ + if (!priv->do_fw_download) + return NOTIFY_DONE; + + switch (pm_event) { + case PM_HIBERNATION_PREPARE: + case PM_SUSPEND_PREPARE: + orinoco_cache_fw(priv, 0); + break; + + case PM_POST_RESTORE: + /* Restore from hibernation failed. We need to clean + * up in exactly the same way, so fall through. */ + case PM_POST_HIBERNATION: + case PM_POST_SUSPEND: + orinoco_uncache_fw(priv); + break; + + case PM_RESTORE_PREPARE: + default: + break; + } + + return NOTIFY_DONE; +} +#else /* !PM_SLEEP || HERMES_CACHE_FW_ON_INIT */ +#define orinoco_pm_notifier NULL +#endif + /********************************************************************/ /* Initialization */ /********************************************************************/ @@ -3277,11 +3371,10 @@ static int orinoco_init(struct net_device *dev) struct hermes_idstring nickbuf; u16 reclen; int len; - DECLARE_MAC_BUF(mac); /* No need to lock, the hw_unavailable flag is already set in * alloc_orinocodev() */ - priv->nicbuf_size = IEEE80211_FRAME_LEN + ETH_HLEN; + priv->nicbuf_size = IEEE80211_MAX_FRAME_LEN + ETH_HLEN; /* Initialize the firmware */ err = hermes_init(hw); @@ -3299,6 +3392,10 @@ static int orinoco_init(struct net_device *dev) } if (priv->do_fw_download) { +#ifdef CONFIG_HERMES_CACHE_FW_ON_INIT + orinoco_cache_fw(priv, 0); +#endif + err = orinoco_download(priv); if (err) priv->do_fw_download = 0; @@ -3348,8 +3445,8 @@ static int orinoco_init(struct net_device *dev) goto out; } - printk(KERN_DEBUG "%s: MAC address %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk(KERN_DEBUG "%s: MAC address %pM\n", + dev->name, dev->dev_addr); /* Get the station name */ err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, @@ -3535,6 +3632,13 @@ struct net_device netif_carrier_off(dev); priv->last_linkstatus = 0xffff; + priv->cached_pri_fw = NULL; + priv->cached_fw = NULL; + + /* Register PM notifiers */ + priv->pm_notifier.notifier_call = orinoco_pm_notifier; + register_pm_notifier(&priv->pm_notifier); + return dev; } @@ -3546,6 +3650,10 @@ void free_orinocodev(struct net_device *dev) * when we call tasklet_kill it will run one final time, * emptying the list */ tasklet_kill(&priv->rx_tasklet); + + unregister_pm_notifier(&priv->pm_notifier); + orinoco_uncache_fw(priv); + priv->wpa_ie_len = 0; kfree(priv->wpa_ie); orinoco_mic_free(priv); @@ -4672,7 +4780,7 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev, /* Determine and validate the key index */ idx = encoding->flags & IW_ENCODE_INDEX; if (idx) { - if ((idx < 1) || (idx > WEP_KEYS)) + if ((idx < 1) || (idx > 4)) goto out; idx--; } else @@ -4777,7 +4885,7 @@ static int orinoco_ioctl_get_encodeext(struct net_device *dev, idx = encoding->flags & IW_ENCODE_INDEX; if (idx) { - if ((idx < 1) || (idx > WEP_KEYS)) + if ((idx < 1) || (idx > 4)) goto out; idx--; } else @@ -4940,7 +5048,8 @@ static int orinoco_ioctl_set_genie(struct net_device *dev, unsigned long flags; int err = 0; - if ((wrqu->data.length > MAX_WPA_IE_LEN) || + /* cut off at IEEE80211_MAX_DATA_LEN */ + if ((wrqu->data.length > IEEE80211_MAX_DATA_LEN) || (wrqu->data.length && (extra == NULL))) return -EINVAL; @@ -5433,7 +5542,7 @@ static inline char *orinoco_translate_scan(struct net_device *dev, char *current_ev, char *end_buf, union hermes_scan_info *bss, - unsigned int last_scanned) + unsigned long last_scanned) { struct orinoco_private *priv = netdev_priv(dev); u16 capabilities; @@ -5580,7 +5689,7 @@ static inline char *orinoco_translate_ext_scan(struct net_device *dev, char *current_ev, char *end_buf, struct agere_ext_scan_info *bss, - unsigned int last_scanned) + unsigned long last_scanned) { u16 capabilities; u16 channel; @@ -5623,7 +5732,7 @@ static inline char *orinoco_translate_ext_scan(struct net_device *dev, &iwe, IW_EV_UINT_LEN); } - ie = orinoco_get_ie(bss->data, sizeof(bss->data), MFIE_TYPE_DS_SET); + ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_DS_PARAMS); channel = ie ? ie[2] : 0; if ((channel >= 1) && (channel <= NUM_CHANNELS)) { /* Add channel and frequency */ @@ -5673,7 +5782,7 @@ static inline char *orinoco_translate_ext_scan(struct net_device *dev, } /* RSN IE */ - ie = orinoco_get_ie(bss->data, sizeof(bss->data), MFIE_TYPE_RSN); + ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_RSN); if (ie) { iwe.cmd = IWEVGENIE; iwe.u.data.length = ie[1] + 2; @@ -5681,7 +5790,7 @@ static inline char *orinoco_translate_ext_scan(struct net_device *dev, &iwe, ie); } - ie = orinoco_get_ie(bss->data, sizeof(bss->data), MFIE_TYPE_RATES); + ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_SUPP_RATES); if (ie) { char *p = current_ev + iwe_stream_lcp_len(info); int i; @@ -5976,7 +6085,7 @@ static void orinoco_get_drvinfo(struct net_device *dev, strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1); strncpy(info->fw_version, priv->fw_name, sizeof(info->fw_version) - 1); if (dev->dev.parent) - strncpy(info->bus_info, dev->dev.parent->bus_id, + strncpy(info->bus_info, dev_name(dev->dev.parent), sizeof(info->bus_info) - 1); else snprintf(info->bus_info, sizeof(info->bus_info) - 1, diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h similarity index 96% rename from drivers/net/wireless/orinoco.h rename to drivers/net/wireless/orinoco/orinoco.h index 981570bd3b9d660b6c403840a09a1b98d4eb67c7..00750c8ba7db4019a5ea36a6c46632cbd1aad1db 100644 --- a/drivers/net/wireless/orinoco.h +++ b/drivers/net/wireless/orinoco/orinoco.h @@ -10,6 +10,7 @@ #define DRIVER_VERSION "0.15" #include +#include #include #include #include @@ -66,6 +67,8 @@ struct orinoco_rx_data { struct list_head list; }; +struct firmware; + struct orinoco_private { void *card; /* Pointer to card dependent structure */ struct device *dev; @@ -164,6 +167,12 @@ struct orinoco_private { unsigned int wpa_enabled:1; unsigned int tkip_cm_active:1; unsigned int key_mgmt:3; + + /* Cached in memory firmware to use during ->resume. */ + const struct firmware *cached_pri_fw; + const struct firmware *cached_fw; + + struct notifier_block pm_notifier; }; #ifdef ORINOCO_DEBUG diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c similarity index 98% rename from drivers/net/wireless/orinoco_cs.c rename to drivers/net/wireless/orinoco/orinoco_cs.c index 6fcf2bda7cdfbe5e0e356ab5adfee8982a2f6b27..f127602670ece436e88b80345cde5917ee729082 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco/orinoco_cs.c @@ -178,13 +178,17 @@ static int orinoco_cs_config_check(struct pcmcia_device *p_dev, /* Note that the CIS values need to be rescaled */ if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n", vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); + DEBUG(2, "%s: Vcc mismatch (vcc = %d, CIS = %d)\n", + __func__, vcc, + cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); if (!ignore_cis_vcc) goto next_entry; } } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) { if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n", vcc, dflt->vcc.param[CISTPL_POWER_VNOM] / 10000); + DEBUG(2, "%s: Vcc mismatch (vcc = %d, CIS = %d)\n", + __func__, vcc, + dflt->vcc.param[CISTPL_POWER_VNOM] / 10000); if (!ignore_cis_vcc) goto next_entry; } @@ -308,7 +312,7 @@ orinoco_cs_config(struct pcmcia_device *link) /* Finally, report what we've done */ printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io " - "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id, + "0x%04x-0x%04x\n", dev->name, dev_name(dev->dev.parent), link->irq.AssignedIRQ, link->io.BasePort1, link->io.BasePort1 + link->io.NumPorts1 - 1); return 0; diff --git a/drivers/net/wireless/orinoco_nortel.c b/drivers/net/wireless/orinoco/orinoco_nortel.c similarity index 100% rename from drivers/net/wireless/orinoco_nortel.c rename to drivers/net/wireless/orinoco/orinoco_nortel.c diff --git a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco/orinoco_pci.c similarity index 100% rename from drivers/net/wireless/orinoco_pci.c rename to drivers/net/wireless/orinoco/orinoco_pci.c diff --git a/drivers/net/wireless/orinoco_pci.h b/drivers/net/wireless/orinoco/orinoco_pci.h similarity index 100% rename from drivers/net/wireless/orinoco_pci.h rename to drivers/net/wireless/orinoco/orinoco_pci.h diff --git a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco/orinoco_plx.c similarity index 100% rename from drivers/net/wireless/orinoco_plx.c rename to drivers/net/wireless/orinoco/orinoco_plx.c diff --git a/drivers/net/wireless/orinoco_tmd.c b/drivers/net/wireless/orinoco/orinoco_tmd.c similarity index 100% rename from drivers/net/wireless/orinoco_tmd.c rename to drivers/net/wireless/orinoco/orinoco_tmd.c diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c similarity index 95% rename from drivers/net/wireless/spectrum_cs.c rename to drivers/net/wireless/orinoco/spectrum_cs.c index 852789ad34b3e33e0094bbc2bce4496096e00209..b2ca2e39c2cbd41943ca878895f7e55001cd4b13 100644 --- a/drivers/net/wireless/spectrum_cs.c +++ b/drivers/net/wireless/orinoco/spectrum_cs.c @@ -248,13 +248,17 @@ static int spectrum_cs_config_check(struct pcmcia_device *p_dev, /* Note that the CIS values need to be rescaled */ if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n", vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); + DEBUG(2, "%s: Vcc mismatch (vcc = %d, CIS = %d)\n", + __func__, vcc, + cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); if (!ignore_cis_vcc) goto next_entry; } } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) { if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n", vcc, dflt->vcc.param[CISTPL_POWER_VNOM] / 10000); + DEBUG(2, "%s: Vcc mismatch (vcc = %d, CIS = %d)\n", + __func__, vcc, + dflt->vcc.param[CISTPL_POWER_VNOM] / 10000); if (!ignore_cis_vcc) goto next_entry; } @@ -383,7 +387,7 @@ spectrum_cs_config(struct pcmcia_device *link) /* Finally, report what we've done */ printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io " - "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id, + "0x%04x-0x%04x\n", dev->name, dev_name(dev->dev.parent), link->irq.AssignedIRQ, link->io.BasePort1, link->io.BasePort1 + link->io.NumPorts1 - 1); @@ -450,10 +454,29 @@ spectrum_cs_resume(struct pcmcia_device *link) { struct net_device *dev = link->priv; struct orinoco_private *priv = netdev_priv(dev); + unsigned long flags; + int err; + + err = orinoco_reinit_firmware(dev); + if (err) { + printk(KERN_ERR "%s: Error %d re-initializing firmware\n", + dev->name, err); + return -EIO; + } + + spin_lock_irqsave(&priv->lock, flags); netif_device_attach(dev); priv->hw_unavailable--; - schedule_work(&priv->reset_work); + + if (priv->open && !priv->hw_unavailable) { + err = __orinoco_up(dev); + if (err) + printk(KERN_ERR "%s: Error %d restarting card\n", + dev->name, err); + } + + spin_unlock_irqrestore(&priv->lock, flags); return 0; } diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 1d0704fe146fb72ed0691271a7bd8491096481b2..ab79e32f0b27c495c3c20eb43310882ff1aaa8b9 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -14,17 +14,17 @@ * published by the Free Software Foundation. */ -enum control_frame_types { - P54_CONTROL_TYPE_FILTER_SET = 0, - P54_CONTROL_TYPE_CHANNEL_CHANGE, - P54_CONTROL_TYPE_FREQDONE, +enum p54_control_frame_types { + P54_CONTROL_TYPE_SETUP = 0, + P54_CONTROL_TYPE_SCAN, + P54_CONTROL_TYPE_TRAP, P54_CONTROL_TYPE_DCFINIT, - P54_CONTROL_TYPE_ENCRYPTION, + P54_CONTROL_TYPE_RX_KEYCACHE, P54_CONTROL_TYPE_TIM, - P54_CONTROL_TYPE_POWERMGT, - P54_CONTROL_TYPE_FREEQUEUE, + P54_CONTROL_TYPE_PSM, + P54_CONTROL_TYPE_TXCANCEL, P54_CONTROL_TYPE_TXDONE, - P54_CONTROL_TYPE_PING, + P54_CONTROL_TYPE_BURST, P54_CONTROL_TYPE_STAT_READBACK, P54_CONTROL_TYPE_BBP, P54_CONTROL_TYPE_EEPROM_READBACK, @@ -37,18 +37,44 @@ enum control_frame_types { P54_CONTROL_TYPE_XBOW_SYNTH_CFG, P54_CONTROL_TYPE_CCE_QUIET, P54_CONTROL_TYPE_PSM_STA_UNLOCK, + P54_CONTROL_TYPE_PCS, + P54_CONTROL_TYPE_BT_BALANCER = 28, + P54_CONTROL_TYPE_GROUP_ADDRESS_TABLE = 30, + P54_CONTROL_TYPE_ARPTABLE = 31, + P54_CONTROL_TYPE_BT_OPTIONS = 35 }; -struct p54_control_hdr { - __le16 magic1; +#define P54_HDR_FLAG_CONTROL BIT(15) +#define P54_HDR_FLAG_CONTROL_OPSET (BIT(15) + BIT(0)) + +struct p54_hdr { + __le16 flags; __le16 len; __le32 req_id; - __le16 type; /* enum control_frame_types */ - u8 retry1; - u8 retry2; + __le16 type; /* enum p54_control_frame_types */ + u8 rts_tries; + u8 tries; u8 data[0]; } __attribute__ ((packed)); +#define FREE_AFTER_TX(skb) \ + ((((struct p54_hdr *) ((struct sk_buff *) skb)->data)-> \ + flags) == cpu_to_le16(P54_HDR_FLAG_CONTROL_OPSET)) + +struct p54_edcf_queue_param { + __le16 aifs; + __le16 cwmin; + __le16 cwmax; + __le16 txop; +} __attribute__ ((packed)); + +struct p54_rssi_linear_approximation { + s16 mul; + s16 add; + s16 longbow_unkn; + s16 longbow_unk2; +}; + #define EEPROM_READBACK_LEN 0x3fc #define ISL38XX_DEV_FIRMWARE_ADDR 0x20000 @@ -59,49 +85,53 @@ struct p54_control_hdr { #define FW_LM20 0x4c4d3230 struct p54_common { + struct ieee80211_hw *hw; u32 rx_start; u32 rx_end; struct sk_buff_head tx_queue; - void (*tx)(struct ieee80211_hw *dev, struct p54_control_hdr *data, - size_t len, int free_on_tx); + void (*tx)(struct ieee80211_hw *dev, struct sk_buff *skb); int (*open)(struct ieee80211_hw *dev); void (*stop)(struct ieee80211_hw *dev); int mode; - u16 seqno; u16 rx_mtu; u8 headroom; u8 tailroom; struct mutex conf_mutex; u8 mac_addr[ETH_ALEN]; u8 bssid[ETH_ALEN]; - __le16 filter_type; struct pda_iq_autocal_entry *iq_autocal; unsigned int iq_autocal_len; struct pda_channel_output_limit *output_limit; unsigned int output_limit_len; struct pda_pa_curve_data *curve_data; + struct p54_rssi_linear_approximation rssical_db[IEEE80211_NUM_BANDS]; unsigned int filter_flags; + bool use_short_slot; u16 rxhw; u8 version; - u8 rx_antenna; unsigned int tx_hdr_len; - void *cached_vdcf; unsigned int fw_var; unsigned int fw_interface; unsigned int output_power; u32 tsf_low32; u32 tsf_high32; + u64 basic_rate_mask; + u16 wakeup_timer; + u16 aid; struct ieee80211_tx_queue_stats tx_stats[8]; + struct p54_edcf_queue_param qos_params[8]; struct ieee80211_low_level_stats stats; - struct timer_list stats_timer; - struct completion stats_comp; - void *cached_stats; + struct delayed_work work; + struct sk_buff *cached_beacon; int noise; void *eeprom; struct completion eeprom_comp; + u8 privacy_caps; + u8 rx_keycache_size; }; int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb); +void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb); int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw); int p54_read_eeprom(struct ieee80211_hw *dev); struct ieee80211_hw *p54_init_common(size_t priv_data_len); diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 827ca0384a4ca220151a048528964ffcbf172ee3..82354b974a04773e752307f45f393bed8a89763c 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -1,12 +1,15 @@ - /* * Common code for mac80211 Prism54 drivers * * Copyright (c) 2006, Michael Wu * Copyright (c) 2007, Christian Lamparter + * Copyright 2008, Johannes Berg * - * Based on the islsm (softmac prism54) driver, which is: - * Copyright 2004-2006 Jean-Baptiste Note , et al. + * Based on: + * - the islsm (softmac prism54) driver, which is: + * Copyright 2004-2006 Jean-Baptiste Note , et al. + * - stlc45xx driver + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). * * 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 @@ -22,6 +25,9 @@ #include "p54.h" #include "p54common.h" +static int modparam_nohwcrypt; +module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); +MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); MODULE_AUTHOR("Michael Wu "); MODULE_DESCRIPTION("Softmac Prism54 common code"); MODULE_LICENSE("GPL"); @@ -152,21 +158,21 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) priv->fw_interface = be32_to_cpup((__be32 *) bootrec->data); switch (priv->fw_interface) { - case FW_FMAC: - printk(KERN_INFO "p54: FreeMAC firmware\n"); - break; - case FW_LM20: - printk(KERN_INFO "p54: LM20 firmware\n"); - break; case FW_LM86: - printk(KERN_INFO "p54: LM86 firmware\n"); - break; - case FW_LM87: - printk(KERN_INFO "p54: LM87 firmware\n"); + case FW_LM20: + case FW_LM87: { + char *iftype = (char *)bootrec->data; + printk(KERN_INFO "%s: p54 detected a LM%c%c " + "firmware\n", + wiphy_name(dev->wiphy), + iftype[2], iftype[3]); break; + } + case FW_FMAC: default: - printk(KERN_INFO "p54: unknown firmware\n"); - break; + printk(KERN_ERR "%s: unsupported firmware\n", + wiphy_name(dev->wiphy)); + return -ENODEV; } break; case BR_CODE_COMPONENT_VERSION: @@ -182,8 +188,10 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) priv->rx_end = le32_to_cpu(desc->rx_end) - 0x3500; priv->headroom = desc->headroom; priv->tailroom = desc->tailroom; + priv->privacy_caps = desc->privacy_caps; + priv->rx_keycache_size = desc->rx_keycache_size; if (le32_to_cpu(bootrec->len) == 11) - priv->rx_mtu = le16_to_cpu(bootrec->rx_mtu); + priv->rx_mtu = le16_to_cpu(desc->rx_mtu); else priv->rx_mtu = (size_t) 0x620 - priv->tx_hdr_len; @@ -208,18 +216,35 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) } if (fw_version) - printk(KERN_INFO "p54: FW rev %s - Softmac protocol %x.%x\n", - fw_version, priv->fw_var >> 8, priv->fw_var & 0xff); + printk(KERN_INFO "%s: FW rev %s - Softmac protocol %x.%x\n", + wiphy_name(dev->wiphy), fw_version, + priv->fw_var >> 8, priv->fw_var & 0xff); + + if (priv->fw_var < 0x500) + printk(KERN_INFO "%s: you are using an obsolete firmware. " + "visit http://wireless.kernel.org/en/users/Drivers/p54 " + "and grab one for \"kernel >= 2.6.28\"!\n", + wiphy_name(dev->wiphy)); if (priv->fw_var >= 0x300) { /* Firmware supports QoS, use it! */ - priv->tx_stats[4].limit = 3; - priv->tx_stats[5].limit = 4; - priv->tx_stats[6].limit = 3; - priv->tx_stats[7].limit = 1; + priv->tx_stats[4].limit = 3; /* AC_VO */ + priv->tx_stats[5].limit = 4; /* AC_VI */ + priv->tx_stats[6].limit = 3; /* AC_BE */ + priv->tx_stats[7].limit = 2; /* AC_BK */ dev->queues = 4; } + if (!modparam_nohwcrypt) + printk(KERN_INFO "%s: cryptographic accelerator " + "WEP:%s, TKIP:%s, CCMP:%s\n", + wiphy_name(dev->wiphy), + (priv->privacy_caps & BR_DESC_PRIV_CAP_WEP) ? "YES" : + "no", (priv->privacy_caps & (BR_DESC_PRIV_CAP_TKIP | + BR_DESC_PRIV_CAP_MICHAEL)) ? "YES" : "no", + (priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP) ? + "YES" : "no"); + return 0; } EXPORT_SYMBOL_GPL(p54_parse_firmware); @@ -310,6 +335,36 @@ static const char *p54_rf_chips[] = { "NULL", "Duette3", "Duette2", "Frisbee", "Xbow", "Longbow", "NULL", "NULL" }; static int p54_init_xbow_synth(struct ieee80211_hw *dev); +static void p54_parse_rssical(struct ieee80211_hw *dev, void *data, int len, + u16 type) +{ + struct p54_common *priv = dev->priv; + int offset = (type == PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) ? 2 : 0; + int entry_size = sizeof(struct pda_rssi_cal_entry) + offset; + int num_entries = (type == PDR_RSSI_LINEAR_APPROXIMATION) ? 1 : 2; + int i; + + if (len != (entry_size * num_entries)) { + printk(KERN_ERR "%s: unknown rssi calibration data packing " + " type:(%x) len:%d.\n", + wiphy_name(dev->wiphy), type, len); + + print_hex_dump_bytes("rssical:", DUMP_PREFIX_NONE, + data, len); + + printk(KERN_ERR "%s: please report this issue.\n", + wiphy_name(dev->wiphy)); + return; + } + + for (i = 0; i < num_entries; i++) { + struct pda_rssi_cal_entry *cal = data + + (offset + i * entry_size); + priv->rssical_db[i].mul = (s16) le16_to_cpu(cal->mul); + priv->rssical_db[i].add = (s16) le16_to_cpu(cal->add); + } +} + static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) { struct p54_common *priv = dev->priv; @@ -320,7 +375,6 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) int err; u8 *end = (u8 *)eeprom + len; u16 synth = 0; - DECLARE_MAC_BUF(mac); wrap = (struct eeprom_pda_wrap *) eeprom; entry = (void *)wrap->data + le16_to_cpu(wrap->len); @@ -377,8 +431,9 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) err = p54_convert_rev1(dev, curve_data); break; default: - printk(KERN_ERR "p54: unknown curve data " + printk(KERN_ERR "%s: unknown curve data " "revision %d\n", + wiphy_name(dev->wiphy), curve_data->cal_method_rev); err = -ENODEV; break; @@ -409,12 +464,40 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) case PDR_HARDWARE_PLATFORM_COMPONENT_ID: priv->version = *(u8 *)(entry->data + 1); break; + case PDR_RSSI_LINEAR_APPROXIMATION: + case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND: + case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED: + p54_parse_rssical(dev, entry->data, data_len, + le16_to_cpu(entry->code)); + break; case PDR_END: /* make it overrun */ entry_len = len; break; + case PDR_MANUFACTURING_PART_NUMBER: + case PDR_PDA_VERSION: + case PDR_NIC_SERIAL_NUMBER: + case PDR_REGULATORY_DOMAIN_LIST: + case PDR_TEMPERATURE_TYPE: + case PDR_PRISM_PCI_IDENTIFIER: + case PDR_COUNTRY_INFORMATION: + case PDR_OEM_NAME: + case PDR_PRODUCT_NAME: + case PDR_UTF8_OEM_NAME: + case PDR_UTF8_PRODUCT_NAME: + case PDR_COUNTRY_LIST: + case PDR_DEFAULT_COUNTRY: + case PDR_ANTENNA_GAIN: + case PDR_PRISM_INDIGO_PA_CALIBRATION_DATA: + case PDR_REGULATORY_POWER_LIMITS: + case PDR_RADIATED_TRANSMISSION_CORRECTION: + case PDR_PRISM_TX_IQ_CALIBRATION: + case PDR_BASEBAND_REGISTERS: + case PDR_PER_CHANNEL_BASEBAND_REGISTERS: + break; default: - printk(KERN_INFO "p54: unknown eeprom code : 0x%x\n", + printk(KERN_INFO "%s: unknown eeprom code : 0x%x\n", + wiphy_name(dev->wiphy), le16_to_cpu(entry->code)); break; } @@ -424,17 +507,18 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) if (!synth || !priv->iq_autocal || !priv->output_limit || !priv->curve_data) { - printk(KERN_ERR "p54: not all required entries found in eeprom!\n"); + printk(KERN_ERR "%s: not all required entries found in eeprom!\n", + wiphy_name(dev->wiphy)); err = -EINVAL; goto err; } - priv->rxhw = synth & 0x07; + priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK; if (priv->rxhw == 4) p54_init_xbow_synth(dev); - if (!(synth & 0x40)) + if (!(synth & PDR_SYNTH_24_GHZ_DISABLED)) dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz; - if (!(synth & 0x80)) + if (!(synth & PDR_SYNTH_5_GHZ_DISABLED)) dev->wiphy->bands[IEEE80211_BAND_5GHZ] = &band_5GHz; if (!is_valid_ether_addr(dev->wiphy->perm_addr)) { @@ -446,9 +530,9 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) SET_IEEE80211_PERM_ADDR(dev, perm_addr); } - printk(KERN_INFO "%s: hwaddr %s, MAC:isl38%02x RF:%s\n", + printk(KERN_INFO "%s: hwaddr %pM, MAC:isl38%02x RF:%s\n", wiphy_name(dev->wiphy), - print_mac(mac, dev->wiphy->perm_addr), + dev->wiphy->perm_addr, priv->version, p54_rf_chips[priv->rxhw]); return 0; @@ -469,36 +553,56 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) priv->curve_data = NULL; } - printk(KERN_ERR "p54: eeprom parse failed!\n"); + printk(KERN_ERR "%s: eeprom parse failed!\n", + wiphy_name(dev->wiphy)); return err; } static int p54_rssi_to_dbm(struct ieee80211_hw *dev, int rssi) { - /* TODO: get the rssi_add & rssi_mul data from the eeprom */ - return ((rssi * 0x83) / 64 - 400) / 4; + struct p54_common *priv = dev->priv; + int band = dev->conf.channel->band; + + return ((rssi * priv->rssical_db[band].mul) / 64 + + priv->rssical_db[band].add) / 4; } static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54_common *priv = dev->priv; - struct p54_rx_hdr *hdr = (struct p54_rx_hdr *) skb->data; + struct p54_rx_data *hdr = (struct p54_rx_data *) skb->data; struct ieee80211_rx_status rx_status = {0}; u16 freq = le16_to_cpu(hdr->freq); size_t header_len = sizeof(*hdr); u32 tsf32; - if (!(hdr->magic & cpu_to_le16(0x0001))) { + /* + * If the device is in a unspecified state we have to + * ignore all data frames. Else we could end up with a + * nasty crash. + */ + if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) + return 0; + + if (!(hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_IN_FCS_GOOD))) { if (priv->filter_flags & FIF_FCSFAIL) rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; else return 0; } + if (hdr->decrypt_status == P54_DECRYPT_OK) + rx_status.flag |= RX_FLAG_DECRYPTED; + if ((hdr->decrypt_status == P54_DECRYPT_FAIL_MICHAEL) || + (hdr->decrypt_status == P54_DECRYPT_FAIL_TKIP)) + rx_status.flag |= RX_FLAG_MMIC_ERROR; + rx_status.signal = p54_rssi_to_dbm(dev, hdr->rssi); rx_status.noise = priv->noise; /* XX correct? */ rx_status.qual = (100 * hdr->rssi) / 127; + if (hdr->rate & 0x10) + rx_status.flag |= RX_FLAG_SHORTPRE; rx_status.rate_idx = (dev->conf.channel->band == IEEE80211_BAND_2GHZ ? hdr->rate : (hdr->rate - 4)) & 0xf; rx_status.freq = freq; @@ -513,7 +617,7 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) rx_status.flag |= RX_FLAG_TSFT; - if (hdr->magic & cpu_to_le16(0x4000)) + if (hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN)) header_len += hdr->align[0]; skb_pull(skb, header_len); @@ -521,6 +625,9 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) ieee80211_rx_irqsafe(dev, skb, &rx_status); + queue_delayed_work(dev->workqueue, &priv->work, + msecs_to_jiffies(P54_STATISTICS_UPDATE)); + return -1; } @@ -529,88 +636,197 @@ static void inline p54_wake_free_queues(struct ieee80211_hw *dev) struct p54_common *priv = dev->priv; int i; + if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) + return ; + for (i = 0; i < dev->queues; i++) if (priv->tx_stats[i + 4].len < priv->tx_stats[i + 4].limit) ieee80211_wake_queue(dev, i); } +void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb) +{ + struct p54_common *priv = dev->priv; + struct ieee80211_tx_info *info; + struct memrecord *range; + unsigned long flags; + u32 freed = 0, last_addr = priv->rx_start; + + if (unlikely(!skb || !dev || !skb_queue_len(&priv->tx_queue))) + return; + + /* + * don't try to free an already unlinked skb + */ + if (unlikely((!skb->next) || (!skb->prev))) + return; + + spin_lock_irqsave(&priv->tx_queue.lock, flags); + info = IEEE80211_SKB_CB(skb); + range = (void *)info->rate_driver_data; + if (skb->prev != (struct sk_buff *)&priv->tx_queue) { + struct ieee80211_tx_info *ni; + struct memrecord *mr; + + ni = IEEE80211_SKB_CB(skb->prev); + mr = (struct memrecord *)ni->rate_driver_data; + last_addr = mr->end_addr; + } + if (skb->next != (struct sk_buff *)&priv->tx_queue) { + struct ieee80211_tx_info *ni; + struct memrecord *mr; + + ni = IEEE80211_SKB_CB(skb->next); + mr = (struct memrecord *)ni->rate_driver_data; + freed = mr->start_addr - last_addr; + } else + freed = priv->rx_end - last_addr; + __skb_unlink(skb, &priv->tx_queue); + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + dev_kfree_skb_any(skb); + + if (freed >= priv->headroom + sizeof(struct p54_hdr) + 48 + + IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom) + p54_wake_free_queues(dev); +} +EXPORT_SYMBOL_GPL(p54_free_skb); + +static struct sk_buff *p54_find_tx_entry(struct ieee80211_hw *dev, + __le32 req_id) +{ + struct p54_common *priv = dev->priv; + struct sk_buff *entry = priv->tx_queue.next; + unsigned long flags; + + spin_lock_irqsave(&priv->tx_queue.lock, flags); + while (entry != (struct sk_buff *)&priv->tx_queue) { + struct p54_hdr *hdr = (struct p54_hdr *) entry->data; + + if (hdr->req_id == req_id) { + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + return entry; + } + entry = entry->next; + } + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + return NULL; +} + static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data; - struct p54_frame_sent_hdr *payload = (struct p54_frame_sent_hdr *) hdr->data; + struct p54_hdr *hdr = (struct p54_hdr *) skb->data; + struct p54_frame_sent *payload = (struct p54_frame_sent *) hdr->data; struct sk_buff *entry = (struct sk_buff *) priv->tx_queue.next; u32 addr = le32_to_cpu(hdr->req_id) - priv->headroom; struct memrecord *range = NULL; u32 freed = 0; u32 last_addr = priv->rx_start; unsigned long flags; + int count, idx; spin_lock_irqsave(&priv->tx_queue.lock, flags); while (entry != (struct sk_buff *)&priv->tx_queue) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry); - range = (void *)info->driver_data; - if (range->start_addr == addr) { - struct p54_control_hdr *entry_hdr; - struct p54_tx_control_allocdata *entry_data; - int pad = 0; - - if (entry->next != (struct sk_buff *)&priv->tx_queue) { - struct ieee80211_tx_info *ni; - struct memrecord *mr; - - ni = IEEE80211_SKB_CB(entry->next); - mr = (struct memrecord *)ni->driver_data; - freed = mr->start_addr - last_addr; - } else - freed = priv->rx_end - last_addr; + struct p54_hdr *entry_hdr; + struct p54_tx_data *entry_data; + int pad = 0; + range = (void *)info->rate_driver_data; + if (range->start_addr != addr) { last_addr = range->end_addr; - __skb_unlink(entry, &priv->tx_queue); - spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + entry = entry->next; + continue; + } - memset(&info->status, 0, sizeof(info->status)); - entry_hdr = (struct p54_control_hdr *) entry->data; - entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data; - if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0) - pad = entry_data->align[0]; - - priv->tx_stats[entry_data->hw_queue].len--; - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { - if (!(payload->status & 0x01)) - info->flags |= IEEE80211_TX_STAT_ACK; - else - info->status.excessive_retries = 1; - } - info->status.retry_count = payload->retries - 1; - info->status.ack_signal = p54_rssi_to_dbm(dev, - le16_to_cpu(payload->ack_rssi)); - skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data)); - ieee80211_tx_status_irqsafe(dev, entry); - goto out; + if (entry->next != (struct sk_buff *)&priv->tx_queue) { + struct ieee80211_tx_info *ni; + struct memrecord *mr; + + ni = IEEE80211_SKB_CB(entry->next); + mr = (struct memrecord *)ni->rate_driver_data; + freed = mr->start_addr - last_addr; } else - last_addr = range->end_addr; - entry = entry->next; + freed = priv->rx_end - last_addr; + + last_addr = range->end_addr; + __skb_unlink(entry, &priv->tx_queue); + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + + entry_hdr = (struct p54_hdr *) entry->data; + entry_data = (struct p54_tx_data *) entry_hdr->data; + priv->tx_stats[entry_data->hw_queue].len--; + priv->stats.dot11ACKFailureCount += payload->tries - 1; + + if (unlikely(entry == priv->cached_beacon)) { + kfree_skb(entry); + priv->cached_beacon = NULL; + goto out; + } + + /* + * Clear manually, ieee80211_tx_info_clear_status would + * clear the counts too and we need them. + */ + memset(&info->status.ampdu_ack_len, 0, + sizeof(struct ieee80211_tx_info) - + offsetof(struct ieee80211_tx_info, status.ampdu_ack_len)); + BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, + status.ampdu_ack_len) != 23); + + if (entry_hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN)) + pad = entry_data->align[0]; + + /* walk through the rates array and adjust the counts */ + count = payload->tries; + for (idx = 0; idx < 4; idx++) { + if (count >= info->status.rates[idx].count) { + count -= info->status.rates[idx].count; + } else if (count > 0) { + info->status.rates[idx].count = count; + count = 0; + } else { + info->status.rates[idx].idx = -1; + info->status.rates[idx].count = 0; + } + } + + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && + (!payload->status)) + info->flags |= IEEE80211_TX_STAT_ACK; + if (payload->status & P54_TX_PSM_CANCELLED) + info->flags |= IEEE80211_TX_STAT_TX_FILTERED; + info->status.ack_signal = p54_rssi_to_dbm(dev, + (int)payload->ack_rssi); + skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data)); + ieee80211_tx_status_irqsafe(dev, entry); + goto out; } spin_unlock_irqrestore(&priv->tx_queue.lock, flags); out: - if (freed >= IEEE80211_MAX_RTS_THRESHOLD + 0x170 + - sizeof(struct p54_control_hdr)) + if (freed >= priv->headroom + sizeof(struct p54_hdr) + 48 + + IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom) p54_wake_free_queues(dev); } static void p54_rx_eeprom_readback(struct ieee80211_hw *dev, struct sk_buff *skb) { - struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data; + struct p54_hdr *hdr = (struct p54_hdr *) skb->data; struct p54_eeprom_lm86 *eeprom = (struct p54_eeprom_lm86 *) hdr->data; struct p54_common *priv = dev->priv; if (!priv->eeprom) return ; - memcpy(priv->eeprom, eeprom->data, le16_to_cpu(eeprom->len)); + if (priv->fw_var >= 0x509) { + memcpy(priv->eeprom, eeprom->v2.data, + le16_to_cpu(eeprom->v2.len)); + } else { + memcpy(priv->eeprom, eeprom->v1.data, + le16_to_cpu(eeprom->v1.len)); + } complete(&priv->eeprom_comp); } @@ -618,10 +834,14 @@ static void p54_rx_eeprom_readback(struct ieee80211_hw *dev, static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data; + struct p54_hdr *hdr = (struct p54_hdr *) skb->data; struct p54_statistics *stats = (struct p54_statistics *) hdr->data; - u32 tsf32 = le32_to_cpu(stats->tsf32); + u32 tsf32; + + if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) + return ; + tsf32 = le32_to_cpu(stats->tsf32); if (tsf32 < priv->tsf_low32) priv->tsf_high32++; priv->tsf_low32 = tsf32; @@ -631,19 +851,50 @@ static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb) priv->stats.dot11FCSErrorCount = le32_to_cpu(stats->rx_bad_fcs); priv->noise = p54_rssi_to_dbm(dev, le32_to_cpu(stats->noise)); - complete(&priv->stats_comp); - mod_timer(&priv->stats_timer, jiffies + 5 * HZ); + p54_free_skb(dev, p54_find_tx_entry(dev, hdr->req_id)); +} + +static void p54_rx_trap(struct ieee80211_hw *dev, struct sk_buff *skb) +{ + struct p54_hdr *hdr = (struct p54_hdr *) skb->data; + struct p54_trap *trap = (struct p54_trap *) hdr->data; + u16 event = le16_to_cpu(trap->event); + u16 freq = le16_to_cpu(trap->frequency); + + switch (event) { + case P54_TRAP_BEACON_TX: + break; + case P54_TRAP_RADAR: + printk(KERN_INFO "%s: radar (freq:%d MHz)\n", + wiphy_name(dev->wiphy), freq); + break; + case P54_TRAP_NO_BEACON: + break; + case P54_TRAP_SCAN: + break; + case P54_TRAP_TBTT: + break; + case P54_TRAP_TIMER: + break; + default: + printk(KERN_INFO "%s: received event:%x freq:%d\n", + wiphy_name(dev->wiphy), event, freq); + break; + } } static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb) { - struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data; + struct p54_hdr *hdr = (struct p54_hdr *) skb->data; switch (le16_to_cpu(hdr->type)) { case P54_CONTROL_TYPE_TXDONE: p54_rx_frame_sent(dev, skb); break; + case P54_CONTROL_TYPE_TRAP: + p54_rx_trap(dev, skb); + break; case P54_CONTROL_TYPE_BBP: break; case P54_CONTROL_TYPE_STAT_READBACK: @@ -664,9 +915,9 @@ static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb) /* returns zero if skb can be reused */ int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb) { - u8 type = le16_to_cpu(*((__le16 *)skb->data)) >> 8; + u16 type = le16_to_cpu(*((__le16 *)skb->data)); - if (type == 0x80) + if (type & P54_HDR_FLAG_CONTROL) return p54_rx_control(dev, skb); else return p54_rx_data(dev, skb); @@ -682,12 +933,14 @@ EXPORT_SYMBOL_GPL(p54_rx); * marks allocated areas as reserved if necessary. p54_rx_frame_sent frees * allocated areas. */ -static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, - struct p54_control_hdr *data, u32 len) +static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, + struct p54_hdr *data, u32 len) { struct p54_common *priv = dev->priv; struct sk_buff *entry = priv->tx_queue.next; struct sk_buff *target_skb = NULL; + struct ieee80211_tx_info *info; + struct memrecord *range; u32 last_addr = priv->rx_start; u32 largest_hole = 0; u32 target_addr = priv->rx_start; @@ -695,12 +948,37 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, unsigned int left; len = (len + priv->headroom + priv->tailroom + 3) & ~0x3; + if (!skb) + return -EINVAL; + spin_lock_irqsave(&priv->tx_queue.lock, flags); + left = skb_queue_len(&priv->tx_queue); + if (unlikely(left >= 28)) { + /* + * The tx_queue is nearly full! + * We have throttle normal data traffic, because we must + * have a few spare slots for control frames left. + */ + ieee80211_stop_queues(dev); + queue_delayed_work(dev->workqueue, &priv->work, + msecs_to_jiffies(P54_TX_TIMEOUT)); + + if (unlikely(left == 32)) { + /* + * The tx_queue is now really full. + * + * TODO: check if the device has crashed and reset it. + */ + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + return -ENOSPC; + } + } + while (left--) { u32 hole_size; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry); - struct memrecord *range = (void *)info->driver_data; + info = IEEE80211_SKB_CB(entry); + range = (void *)info->rate_driver_data; hole_size = range->start_addr - last_addr; if (!target_skb && hole_size >= len) { target_skb = entry->prev; @@ -715,64 +993,102 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, target_skb = priv->tx_queue.prev; largest_hole = max(largest_hole, priv->rx_end - last_addr - len); if (!skb_queue_empty(&priv->tx_queue)) { - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(target_skb); - struct memrecord *range = (void *)info->driver_data; + info = IEEE80211_SKB_CB(target_skb); + range = (void *)info->rate_driver_data; target_addr = range->end_addr; } } else largest_hole = max(largest_hole, priv->rx_end - last_addr); - if (skb) { - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct memrecord *range = (void *)info->driver_data; - range->start_addr = target_addr; - range->end_addr = target_addr + len; - __skb_queue_after(&priv->tx_queue, target_skb, skb); - if (largest_hole < priv->rx_mtu + priv->headroom + - priv->tailroom + - sizeof(struct p54_control_hdr)) - ieee80211_stop_queues(dev); + if (!target_skb) { + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + ieee80211_stop_queues(dev); + return -ENOSPC; } + + info = IEEE80211_SKB_CB(skb); + range = (void *)info->rate_driver_data; + range->start_addr = target_addr; + range->end_addr = target_addr + len; + __skb_queue_after(&priv->tx_queue, target_skb, skb); spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + if (largest_hole < priv->headroom + sizeof(struct p54_hdr) + + 48 + IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom) + ieee80211_stop_queues(dev); + data->req_id = cpu_to_le32(target_addr + priv->headroom); + return 0; +} + +static struct sk_buff *p54_alloc_skb(struct ieee80211_hw *dev, + u16 hdr_flags, u16 len, u16 type, gfp_t memflags) +{ + struct p54_common *priv = dev->priv; + struct p54_hdr *hdr; + struct sk_buff *skb; + + skb = __dev_alloc_skb(len + priv->tx_hdr_len, memflags); + if (!skb) + return NULL; + skb_reserve(skb, priv->tx_hdr_len); + + hdr = (struct p54_hdr *) skb_put(skb, sizeof(*hdr)); + hdr->flags = cpu_to_le16(hdr_flags); + hdr->len = cpu_to_le16(len - sizeof(*hdr)); + hdr->type = cpu_to_le16(type); + hdr->tries = hdr->rts_tries = 0; + + if (unlikely(p54_assign_address(dev, skb, hdr, len))) { + kfree_skb(skb); + return NULL; + } + return skb; } int p54_read_eeprom(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr = NULL; + struct p54_hdr *hdr = NULL; struct p54_eeprom_lm86 *eeprom_hdr; - size_t eeprom_size = 0x2020, offset = 0, blocksize; + struct sk_buff *skb; + size_t eeprom_size = 0x2020, offset = 0, blocksize, maxblocksize; int ret = -ENOMEM; void *eeprom = NULL; - hdr = (struct p54_control_hdr *)kzalloc(sizeof(*hdr) + - sizeof(*eeprom_hdr) + EEPROM_READBACK_LEN, GFP_KERNEL); - if (!hdr) - goto free; + maxblocksize = EEPROM_READBACK_LEN; + if (priv->fw_var >= 0x509) + maxblocksize -= 0xc; + else + maxblocksize -= 0x4; + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL, sizeof(*hdr) + + sizeof(*eeprom_hdr) + maxblocksize, + P54_CONTROL_TYPE_EEPROM_READBACK, GFP_KERNEL); + if (!skb) + goto free; priv->eeprom = kzalloc(EEPROM_READBACK_LEN, GFP_KERNEL); if (!priv->eeprom) goto free; - eeprom = kzalloc(eeprom_size, GFP_KERNEL); if (!eeprom) goto free; - hdr->magic1 = cpu_to_le16(0x8000); - hdr->type = cpu_to_le16(P54_CONTROL_TYPE_EEPROM_READBACK); - hdr->retry1 = hdr->retry2 = 0; - eeprom_hdr = (struct p54_eeprom_lm86 *) hdr->data; + eeprom_hdr = (struct p54_eeprom_lm86 *) skb_put(skb, + sizeof(*eeprom_hdr) + maxblocksize); while (eeprom_size) { - blocksize = min(eeprom_size, (size_t)EEPROM_READBACK_LEN); - hdr->len = cpu_to_le16(blocksize + sizeof(*eeprom_hdr)); - eeprom_hdr->offset = cpu_to_le16(offset); - eeprom_hdr->len = cpu_to_le16(blocksize); - p54_assign_address(dev, NULL, hdr, le16_to_cpu(hdr->len) + - sizeof(*hdr)); - priv->tx(dev, hdr, le16_to_cpu(hdr->len) + sizeof(*hdr), 0); + blocksize = min(eeprom_size, maxblocksize); + if (priv->fw_var < 0x509) { + eeprom_hdr->v1.offset = cpu_to_le16(offset); + eeprom_hdr->v1.len = cpu_to_le16(blocksize); + } else { + eeprom_hdr->v2.offset = cpu_to_le32(offset); + eeprom_hdr->v2.len = cpu_to_le16(blocksize); + eeprom_hdr->v2.magic2 = 0xf; + memcpy(eeprom_hdr->v2.magic, (const char *)"LOCK", 4); + } + priv->tx(dev, skb); if (!wait_for_completion_interruptible_timeout(&priv->eeprom_comp, HZ)) { printk(KERN_ERR "%s: device does not respond!\n", @@ -790,166 +1106,422 @@ int p54_read_eeprom(struct ieee80211_hw *dev) free: kfree(priv->eeprom); priv->eeprom = NULL; - kfree(hdr); + p54_free_skb(dev, skb); kfree(eeprom); return ret; } EXPORT_SYMBOL_GPL(p54_read_eeprom); +static int p54_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta, + bool set) +{ + struct p54_common *priv = dev->priv; + struct sk_buff *skb; + struct p54_tim *tim; + + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, + sizeof(struct p54_hdr) + sizeof(*tim), + P54_CONTROL_TYPE_TIM, GFP_KERNEL); + if (!skb) + return -ENOMEM; + + tim = (struct p54_tim *) skb_put(skb, sizeof(*tim)); + tim->count = 1; + tim->entry[0] = cpu_to_le16(set ? (sta->aid | 0x8000) : sta->aid); + priv->tx(dev, skb); + return 0; +} + +static int p54_sta_unlock(struct ieee80211_hw *dev, u8 *addr) +{ + struct p54_common *priv = dev->priv; + struct sk_buff *skb; + struct p54_sta_unlock *sta; + + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, + sizeof(struct p54_hdr) + sizeof(*sta), + P54_CONTROL_TYPE_PSM_STA_UNLOCK, GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + sta = (struct p54_sta_unlock *)skb_put(skb, sizeof(*sta)); + memcpy(sta->addr, addr, ETH_ALEN); + priv->tx(dev, skb); + return 0; +} + +static void p54_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif, + enum sta_notify_cmd notify_cmd, + struct ieee80211_sta *sta) +{ + switch (notify_cmd) { + case STA_NOTIFY_ADD: + case STA_NOTIFY_REMOVE: + /* + * Notify the firmware that we don't want or we don't + * need to buffer frames for this station anymore. + */ + + p54_sta_unlock(dev, sta->addr); + break; + case STA_NOTIFY_AWAKE: + /* update the firmware's filter table */ + p54_sta_unlock(dev, sta->addr); + break; + default: + break; + } +} + +static int p54_tx_cancel(struct ieee80211_hw *dev, struct sk_buff *entry) +{ + struct p54_common *priv = dev->priv; + struct sk_buff *skb; + struct p54_hdr *hdr; + struct p54_txcancel *cancel; + + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, + sizeof(struct p54_hdr) + sizeof(*cancel), + P54_CONTROL_TYPE_TXCANCEL, GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + hdr = (void *)entry->data; + cancel = (struct p54_txcancel *)skb_put(skb, sizeof(*cancel)); + cancel->req_id = hdr->req_id; + priv->tx(dev, skb); + return 0; +} + +static int p54_tx_fill(struct ieee80211_hw *dev, struct sk_buff *skb, + struct ieee80211_tx_info *info, u8 *queue, size_t *extra_len, + u16 *flags, u16 *aid) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct p54_common *priv = dev->priv; + int ret = 0; + + if (unlikely(ieee80211_is_mgmt(hdr->frame_control))) { + if (ieee80211_is_beacon(hdr->frame_control)) { + *aid = 0; + *queue = 0; + *extra_len = IEEE80211_MAX_TIM_LEN; + *flags = P54_HDR_FLAG_DATA_OUT_TIMESTAMP; + return 0; + } else if (ieee80211_is_probe_resp(hdr->frame_control)) { + *aid = 0; + *queue = 2; + *flags = P54_HDR_FLAG_DATA_OUT_TIMESTAMP | + P54_HDR_FLAG_DATA_OUT_NOCANCEL; + return 0; + } else { + *queue = 2; + ret = 0; + } + } else { + *queue += 4; + ret = 1; + } + + switch (priv->mode) { + case NL80211_IFTYPE_STATION: + *aid = 1; + break; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: + if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { + *aid = 0; + *queue = 3; + return 0; + } + if (info->control.sta) + *aid = info->control.sta->aid; + else + *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL; + } + return ret; +} + +static u8 p54_convert_algo(enum ieee80211_key_alg alg) +{ + switch (alg) { + case ALG_WEP: + return P54_CRYPTO_WEP; + case ALG_TKIP: + return P54_CRYPTO_TKIPMICHAEL; + case ALG_CCMP: + return P54_CRYPTO_AESCCMP; + default: + return 0; + } +} + static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_tx_queue_stats *current_queue; + struct ieee80211_tx_queue_stats *current_queue = NULL; struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; - struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; - struct p54_tx_control_allocdata *txhdr; - size_t padding, len; - u8 rate; + struct p54_hdr *hdr; + struct p54_tx_data *txhdr; + size_t padding, len, tim_len = 0; + int i, j, ridx, ret; + u16 hdr_flags = 0, aid = 0; + u8 rate, queue, crypt_offset = 0; u8 cts_rate = 0x20; + u8 rc_flags; + u8 calculated_tries[4]; + u8 nrates = 0, nremaining = 8; - current_queue = &priv->tx_stats[skb_get_queue_mapping(skb) + 4]; - if (unlikely(current_queue->len > current_queue->limit)) + queue = skb_get_queue_mapping(skb); + + ret = p54_tx_fill(dev, skb, info, &queue, &tim_len, &hdr_flags, &aid); + current_queue = &priv->tx_stats[queue]; + if (unlikely((current_queue->len > current_queue->limit) && ret)) return NETDEV_TX_BUSY; current_queue->len++; current_queue->count++; - if (current_queue->len == current_queue->limit) + if ((current_queue->len == current_queue->limit) && ret) ieee80211_stop_queue(dev, skb_get_queue_mapping(skb)); padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3; len = skb->len; - txhdr = (struct p54_tx_control_allocdata *) - skb_push(skb, sizeof(*txhdr) + padding); - hdr = (struct p54_control_hdr *) skb_push(skb, sizeof(*hdr)); + if (info->control.hw_key) { + crypt_offset = ieee80211_get_hdrlen_from_skb(skb); + if (info->control.hw_key->alg == ALG_TKIP) { + u8 *iv = (u8 *)(skb->data + crypt_offset); + /* + * The firmware excepts that the IV has to have + * this special format + */ + iv[1] = iv[0]; + iv[0] = iv[2]; + iv[2] = 0; + } + } + + txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding); + hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr)); if (padding) - hdr->magic1 = cpu_to_le16(0x4010); - else - hdr->magic1 = cpu_to_le16(0x0010); - hdr->len = cpu_to_le16(len); - hdr->type = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? 0 : cpu_to_le16(1); - hdr->retry1 = hdr->retry2 = info->control.retry_limit; - - /* TODO: add support for alternate retry TX rates */ - rate = ieee80211_get_tx_rate(dev, info)->hw_value; - if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE) { - rate |= 0x10; - cts_rate |= 0x10; + hdr_flags |= P54_HDR_FLAG_DATA_ALIGN; + hdr->type = cpu_to_le16(aid); + hdr->rts_tries = info->control.rates[0].count; + + /* + * we register the rates in perfect order, and + * RTS/CTS won't happen on 5 GHz + */ + cts_rate = info->control.rts_cts_rate_idx; + + memset(&txhdr->rateset, 0, sizeof(txhdr->rateset)); + + /* see how many rates got used */ + for (i = 0; i < 4; i++) { + if (info->control.rates[i].idx < 0) + break; + nrates++; + } + + /* limit tries to 8/nrates per rate */ + for (i = 0; i < nrates; i++) { + /* + * The magic expression here is equivalent to 8/nrates for + * all values that matter, but avoids division and jumps. + * Note that nrates can only take the values 1 through 4. + */ + calculated_tries[i] = min_t(int, ((15 >> nrates) | 1) + 1, + info->control.rates[i].count); + nremaining -= calculated_tries[i]; } - if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { - rate |= 0x40; - cts_rate |= ieee80211_get_rts_cts_rate(dev, info)->hw_value; - } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { - rate |= 0x20; - cts_rate |= ieee80211_get_rts_cts_rate(dev, info)->hw_value; + + /* if there are tries left, distribute from back to front */ + for (i = nrates - 1; nremaining > 0 && i >= 0; i--) { + int tmp = info->control.rates[i].count - calculated_tries[i]; + + if (tmp <= 0) + continue; + /* RC requested more tries at this rate */ + + tmp = min_t(int, tmp, nremaining); + calculated_tries[i] += tmp; + nremaining -= tmp; + } + + ridx = 0; + for (i = 0; i < nrates && ridx < 8; i++) { + /* we register the rates in perfect order */ + rate = info->control.rates[i].idx; + if (info->band == IEEE80211_BAND_5GHZ) + rate += 4; + + /* store the count we actually calculated for TX status */ + info->control.rates[i].count = calculated_tries[i]; + + rc_flags = info->control.rates[i].flags; + if (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) { + rate |= 0x10; + cts_rate |= 0x10; + } + if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) + rate |= 0x40; + else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) + rate |= 0x20; + for (j = 0; j < calculated_tries[i] && ridx < 8; j++) { + txhdr->rateset[ridx] = rate; + ridx++; + } + } + + if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) + hdr_flags |= P54_HDR_FLAG_DATA_OUT_SEQNR; + + /* TODO: enable bursting */ + hdr->flags = cpu_to_le16(hdr_flags); + hdr->tries = ridx; + txhdr->rts_rate_idx = 0; + if (info->control.hw_key) { + crypt_offset += info->control.hw_key->iv_len; + txhdr->key_type = p54_convert_algo(info->control.hw_key->alg); + txhdr->key_len = min((u8)16, info->control.hw_key->keylen); + memcpy(txhdr->key, info->control.hw_key->key, txhdr->key_len); + if (info->control.hw_key->alg == ALG_TKIP) { + if (unlikely(skb_tailroom(skb) < 12)) + goto err; + /* reserve space for the MIC key */ + len += 8; + memcpy(skb_put(skb, 8), &(info->control.hw_key->key + [NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY]), 8); + } + /* reserve some space for ICV */ + len += info->control.hw_key->icv_len; + } else { + txhdr->key_type = 0; + txhdr->key_len = 0; } - memset(txhdr->rateset, rate, 8); - txhdr->key_type = 0; - txhdr->key_len = 0; - txhdr->hw_queue = skb_get_queue_mapping(skb) + 4; + txhdr->crypt_offset = crypt_offset; + txhdr->hw_queue = queue; + if (current_queue) + txhdr->backlog = current_queue->len; + else + txhdr->backlog = 0; + memset(txhdr->durations, 0, sizeof(txhdr->durations)); txhdr->tx_antenna = (info->antenna_sel_tx == 0) ? 2 : info->antenna_sel_tx - 1; txhdr->output_power = priv->output_power; - txhdr->cts_rate = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? - 0 : cts_rate; + txhdr->cts_rate = cts_rate; if (padding) txhdr->align[0] = padding; - /* FIXME: The sequence that follows is needed for this driver to - * work with mac80211 since "mac80211: fix TX sequence numbers". - * As with the temporary code in rt2x00, changes will be needed - * to get proper sequence numbers on beacons. In addition, this - * patch places the sequence number in the hardware state, which - * limits us to a single virtual state. - */ - if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { - if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) - priv->seqno += 0x10; - ieee80211hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); - ieee80211hdr->seq_ctrl |= cpu_to_le16(priv->seqno); - } + hdr->len = cpu_to_le16(len); /* modifies skb->cb and with it info, so must be last! */ - p54_assign_address(dev, skb, hdr, skb->len); + if (unlikely(p54_assign_address(dev, skb, hdr, skb->len + tim_len))) + goto err; + priv->tx(dev, skb); + + queue_delayed_work(dev->workqueue, &priv->work, + msecs_to_jiffies(P54_TX_FRAME_LIFETIME)); - priv->tx(dev, hdr, skb->len, 0); return 0; + + err: + skb_pull(skb, sizeof(*hdr) + sizeof(*txhdr) + padding); + if (current_queue) { + current_queue->len--; + current_queue->count--; + } + return NETDEV_TX_BUSY; } -static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type, - const u8 *bssid) +static int p54_setup_mac(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; - struct p54_tx_control_filter *filter; - size_t data_len; + struct sk_buff *skb; + struct p54_setup_mac *setup; + u16 mode; - hdr = kzalloc(sizeof(*hdr) + sizeof(*filter) + - priv->tx_hdr_len, GFP_ATOMIC); - if (!hdr) + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*setup) + + sizeof(struct p54_hdr), P54_CONTROL_TYPE_SETUP, + GFP_ATOMIC); + if (!skb) return -ENOMEM; - hdr = (void *)hdr + priv->tx_hdr_len; - - filter = (struct p54_tx_control_filter *) hdr->data; - hdr->magic1 = cpu_to_le16(0x8001); - hdr->type = cpu_to_le16(P54_CONTROL_TYPE_FILTER_SET); - - priv->filter_type = filter->filter_type = cpu_to_le16(filter_type); - memcpy(filter->mac_addr, priv->mac_addr, ETH_ALEN); - if (!bssid) - memset(filter->bssid, ~0, ETH_ALEN); - else - memcpy(filter->bssid, bssid, ETH_ALEN); - - filter->rx_antenna = priv->rx_antenna; + setup = (struct p54_setup_mac *) skb_put(skb, sizeof(*setup)); + if (dev->conf.radio_enabled) { + switch (priv->mode) { + case NL80211_IFTYPE_STATION: + mode = P54_FILTER_TYPE_STATION; + break; + case NL80211_IFTYPE_AP: + mode = P54_FILTER_TYPE_AP; + break; + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: + mode = P54_FILTER_TYPE_IBSS; + break; + default: + mode = P54_FILTER_TYPE_NONE; + break; + } + if (priv->filter_flags & FIF_PROMISC_IN_BSS) + mode |= P54_FILTER_TYPE_TRANSPARENT; + } else + mode = P54_FILTER_TYPE_RX_DISABLED; + setup->mac_mode = cpu_to_le16(mode); + memcpy(setup->mac_addr, priv->mac_addr, ETH_ALEN); + memcpy(setup->bssid, priv->bssid, ETH_ALEN); + setup->rx_antenna = 2; /* automatic */ + setup->rx_align = 0; if (priv->fw_var < 0x500) { - data_len = P54_TX_CONTROL_FILTER_V1_LEN; - filter->v1.basic_rate_mask = cpu_to_le32(0x15F); - filter->v1.rx_addr = cpu_to_le32(priv->rx_end); - filter->v1.max_rx = cpu_to_le16(priv->rx_mtu); - filter->v1.rxhw = cpu_to_le16(priv->rxhw); - filter->v1.wakeup_timer = cpu_to_le16(500); + setup->v1.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); + memset(setup->v1.rts_rates, 0, 8); + setup->v1.rx_addr = cpu_to_le32(priv->rx_end); + setup->v1.max_rx = cpu_to_le16(priv->rx_mtu); + setup->v1.rxhw = cpu_to_le16(priv->rxhw); + setup->v1.wakeup_timer = cpu_to_le16(priv->wakeup_timer); + setup->v1.unalloc0 = cpu_to_le16(0); } else { - data_len = P54_TX_CONTROL_FILTER_V2_LEN; - filter->v2.rx_addr = cpu_to_le32(priv->rx_end); - filter->v2.max_rx = cpu_to_le16(priv->rx_mtu); - filter->v2.rxhw = cpu_to_le16(priv->rxhw); - filter->v2.timer = cpu_to_le16(1000); + setup->v2.rx_addr = cpu_to_le32(priv->rx_end); + setup->v2.max_rx = cpu_to_le16(priv->rx_mtu); + setup->v2.rxhw = cpu_to_le16(priv->rxhw); + setup->v2.timer = cpu_to_le16(priv->wakeup_timer); + setup->v2.truncate = cpu_to_le16(48896); + setup->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); + setup->v2.sbss_offset = 0; + setup->v2.mcast_window = 0; + setup->v2.rx_rssi_threshold = 0; + setup->v2.rx_ed_threshold = 0; + setup->v2.ref_clock = cpu_to_le32(644245094); + setup->v2.lpf_bandwidth = cpu_to_le16(65535); + setup->v2.osc_start_delay = cpu_to_le16(65535); } - - hdr->len = cpu_to_le16(data_len); - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + data_len); - priv->tx(dev, hdr, sizeof(*hdr) + data_len, 1); + priv->tx(dev, skb); return 0; } -static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq) +static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; - struct p54_tx_control_channel *chan; + struct sk_buff *skb; + struct p54_scan *chan; unsigned int i; - size_t data_len; void *entry; + __le16 freq = cpu_to_le16(dev->conf.channel->center_freq); + int band = dev->conf.channel->band; - hdr = kzalloc(sizeof(*hdr) + sizeof(*chan) + - priv->tx_hdr_len, GFP_KERNEL); - if (!hdr) + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*chan) + + sizeof(struct p54_hdr), P54_CONTROL_TYPE_SCAN, + GFP_ATOMIC); + if (!skb) return -ENOMEM; - hdr = (void *)hdr + priv->tx_hdr_len; - - chan = (struct p54_tx_control_channel *) hdr->data; - - hdr->magic1 = cpu_to_le16(0x8001); - - hdr->type = cpu_to_le16(P54_CONTROL_TYPE_CHANNEL_CHANGE); - - chan->flags = cpu_to_le16(0x1); - chan->dwell = cpu_to_le16(0x0); + chan = (struct p54_scan *) skb_put(skb, sizeof(*chan)); + memset(chan->padding1, 0, sizeof(chan->padding1)); + chan->mode = cpu_to_le16(mode); + chan->dwell = cpu_to_le16(dwell); for (i = 0; i < priv->iq_autocal_len; i++) { if (priv->iq_autocal[i].freq != freq) @@ -990,61 +1562,50 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq) } entry += sizeof(__le16); - chan->pa_points_per_curve = - min(priv->curve_data->points_per_channel, (u8) 8); - - memcpy(chan->curve_data, entry, sizeof(*chan->curve_data) * - chan->pa_points_per_curve); + chan->pa_points_per_curve = 8; + memset(chan->curve_data, 0, sizeof(*chan->curve_data)); + memcpy(chan->curve_data, entry, + sizeof(struct p54_pa_curve_data_sample) * + min((u8)8, priv->curve_data->points_per_channel)); break; } if (priv->fw_var < 0x500) { - data_len = P54_TX_CONTROL_CHANNEL_V1_LEN; - chan->v1.rssical_mul = cpu_to_le16(130); - chan->v1.rssical_add = cpu_to_le16(0xfe70); + chan->v1_rssi.mul = cpu_to_le16(priv->rssical_db[band].mul); + chan->v1_rssi.add = cpu_to_le16(priv->rssical_db[band].add); } else { - data_len = P54_TX_CONTROL_CHANNEL_V2_LEN; - chan->v2.rssical_mul = cpu_to_le16(130); - chan->v2.rssical_add = cpu_to_le16(0xfe70); - chan->v2.basic_rate_mask = cpu_to_le32(0x15f); + chan->v2.rssi.mul = cpu_to_le16(priv->rssical_db[band].mul); + chan->v2.rssi.add = cpu_to_le16(priv->rssical_db[band].add); + chan->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); + memset(chan->v2.rts_rates, 0, 8); } - - hdr->len = cpu_to_le16(data_len); - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + data_len); - priv->tx(dev, hdr, sizeof(*hdr) + data_len, 1); + priv->tx(dev, skb); return 0; err: printk(KERN_ERR "%s: frequency change failed\n", wiphy_name(dev->wiphy)); - kfree(hdr); + kfree_skb(skb); return -EINVAL; } static int p54_set_leds(struct ieee80211_hw *dev, int mode, int link, int act) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; - struct p54_tx_control_led *led; + struct sk_buff *skb; + struct p54_led *led; - hdr = kzalloc(sizeof(*hdr) + sizeof(*led) + - priv->tx_hdr_len, GFP_KERNEL); - if (!hdr) + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*led) + + sizeof(struct p54_hdr), P54_CONTROL_TYPE_LED, + GFP_ATOMIC); + if (!skb) return -ENOMEM; - hdr = (void *)hdr + priv->tx_hdr_len; - hdr->magic1 = cpu_to_le16(0x8001); - hdr->len = cpu_to_le16(sizeof(*led)); - hdr->type = cpu_to_le16(P54_CONTROL_TYPE_LED); - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*led)); - - led = (struct p54_tx_control_led *) hdr->data; + led = (struct p54_led *)skb_put(skb, sizeof(*led)); led->mode = cpu_to_le16(mode); led->led_permanent = cpu_to_le16(link); led->led_temporary = cpu_to_le16(act); led->duration = cpu_to_le16(1000); - - priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*led), 1); - + priv->tx(dev, skb); return 0; } @@ -1056,88 +1617,144 @@ do { \ queue.txop = cpu_to_le16(_txop); \ } while(0) -static void p54_init_vdcf(struct ieee80211_hw *dev) +static int p54_set_edcf(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; - struct p54_tx_control_vdcf *vdcf; - - /* all USB V1 adapters need a extra headroom */ - hdr = (void *)priv->cached_vdcf + priv->tx_hdr_len; - hdr->magic1 = cpu_to_le16(0x8001); - hdr->len = cpu_to_le16(sizeof(*vdcf)); - hdr->type = cpu_to_le16(P54_CONTROL_TYPE_DCFINIT); - hdr->req_id = cpu_to_le32(priv->rx_start); - - vdcf = (struct p54_tx_control_vdcf *) hdr->data; - - P54_SET_QUEUE(vdcf->queue[0], 0x0002, 0x0003, 0x0007, 47); - P54_SET_QUEUE(vdcf->queue[1], 0x0002, 0x0007, 0x000f, 94); - P54_SET_QUEUE(vdcf->queue[2], 0x0003, 0x000f, 0x03ff, 0); - P54_SET_QUEUE(vdcf->queue[3], 0x0007, 0x000f, 0x03ff, 0); + struct sk_buff *skb; + struct p54_edcf *edcf; + + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*edcf) + + sizeof(struct p54_hdr), P54_CONTROL_TYPE_DCFINIT, + GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + edcf = (struct p54_edcf *)skb_put(skb, sizeof(*edcf)); + if (priv->use_short_slot) { + edcf->slottime = 9; + edcf->sifs = 0x10; + edcf->eofpad = 0x00; + } else { + edcf->slottime = 20; + edcf->sifs = 0x0a; + edcf->eofpad = 0x06; + } + /* (see prism54/isl_oid.h for further details) */ + edcf->frameburst = cpu_to_le16(0); + edcf->round_trip_delay = cpu_to_le16(0); + edcf->flags = 0; + memset(edcf->mapping, 0, sizeof(edcf->mapping)); + memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue)); + priv->tx(dev, skb); + return 0; } -static void p54_set_vdcf(struct ieee80211_hw *dev) +static int p54_beacon_tim(struct sk_buff *skb) { - struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; - struct p54_tx_control_vdcf *vdcf; + /* + * the good excuse for this mess is ... the firmware. + * The dummy TIM MUST be at the end of the beacon frame, + * because it'll be overwritten! + */ - hdr = (void *)priv->cached_vdcf + priv->tx_hdr_len; + struct ieee80211_mgmt *mgmt = (void *)skb->data; + u8 *pos, *end; - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*vdcf)); + if (skb->len <= sizeof(mgmt)) + return -EINVAL; - vdcf = (struct p54_tx_control_vdcf *) hdr->data; + pos = (u8 *)mgmt->u.beacon.variable; + end = skb->data + skb->len; + while (pos < end) { + if (pos + 2 + pos[1] > end) + return -EINVAL; - if (dev->conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME) { - vdcf->slottime = 9; - vdcf->magic1 = 0x10; - vdcf->magic2 = 0x00; - } else { - vdcf->slottime = 20; - vdcf->magic1 = 0x0a; - vdcf->magic2 = 0x06; - } + if (pos[0] == WLAN_EID_TIM) { + u8 dtim_len = pos[1]; + u8 dtim_period = pos[3]; + u8 *next = pos + 2 + dtim_len; - /* (see prism54/isl_oid.h for further details) */ - vdcf->frameburst = cpu_to_le16(0); + if (dtim_len < 3) + return -EINVAL; + + memmove(pos, next, end - next); - priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*vdcf), 0); + if (dtim_len > 3) + skb_trim(skb, skb->len - (dtim_len - 3)); + + pos = end - (dtim_len + 2); + + /* add the dummy at the end */ + pos[0] = WLAN_EID_TIM; + pos[1] = 3; + pos[2] = 0; + pos[3] = dtim_period; + pos[4] = 0; + return 0; + } + pos += 2 + pos[1]; + } + return 0; } -static int p54_start(struct ieee80211_hw *dev) +static int p54_beacon_update(struct ieee80211_hw *dev, + struct ieee80211_vif *vif) { struct p54_common *priv = dev->priv; - int err; - - if (!priv->cached_vdcf) { - priv->cached_vdcf = kzalloc(sizeof(struct p54_tx_control_vdcf)+ - priv->tx_hdr_len + sizeof(struct p54_control_hdr), - GFP_KERNEL); + struct sk_buff *beacon; + int ret; - if (!priv->cached_vdcf) - return -ENOMEM; + if (priv->cached_beacon) { + p54_tx_cancel(dev, priv->cached_beacon); + /* wait for the last beacon the be freed */ + msleep(10); } - if (!priv->cached_stats) { - priv->cached_stats = kzalloc(sizeof(struct p54_statistics) + - priv->tx_hdr_len + sizeof(struct p54_control_hdr), - GFP_KERNEL); + beacon = ieee80211_beacon_get(dev, vif); + if (!beacon) + return -ENOMEM; + ret = p54_beacon_tim(beacon); + if (ret) + return ret; + ret = p54_tx(dev, beacon); + if (ret) + return ret; + priv->cached_beacon = beacon; + priv->tsf_high32 = 0; + priv->tsf_low32 = 0; - if (!priv->cached_stats) { - kfree(priv->cached_vdcf); - priv->cached_vdcf = NULL; - return -ENOMEM; - } - } + return 0; +} +static int p54_start(struct ieee80211_hw *dev) +{ + struct p54_common *priv = dev->priv; + int err; + + mutex_lock(&priv->conf_mutex); err = priv->open(dev); - if (!err) - priv->mode = NL80211_IFTYPE_MONITOR; + if (err) + goto out; + P54_SET_QUEUE(priv->qos_params[0], 0x0002, 0x0003, 0x0007, 47); + P54_SET_QUEUE(priv->qos_params[1], 0x0002, 0x0007, 0x000f, 94); + P54_SET_QUEUE(priv->qos_params[2], 0x0003, 0x000f, 0x03ff, 0); + P54_SET_QUEUE(priv->qos_params[3], 0x0007, 0x000f, 0x03ff, 0); + err = p54_set_edcf(dev); + if (err) + goto out; + + memset(priv->bssid, ~0, ETH_ALEN); + priv->mode = NL80211_IFTYPE_MONITOR; + err = p54_setup_mac(dev); + if (err) { + priv->mode = NL80211_IFTYPE_UNSPECIFIED; + goto out; + } - p54_init_vdcf(dev); + queue_delayed_work(dev->workqueue, &priv->work, 0); - mod_timer(&priv->stats_timer, jiffies + HZ); +out: + mutex_unlock(&priv->conf_mutex); return err; } @@ -1146,12 +1763,18 @@ static void p54_stop(struct ieee80211_hw *dev) struct p54_common *priv = dev->priv; struct sk_buff *skb; - del_timer(&priv->stats_timer); + mutex_lock(&priv->conf_mutex); + priv->mode = NL80211_IFTYPE_UNSPECIFIED; + cancel_delayed_work_sync(&priv->work); + if (priv->cached_beacon) + p54_tx_cancel(dev, priv->cached_beacon); + + priv->stop(dev); while ((skb = skb_dequeue(&priv->tx_queue))) kfree_skb(skb); - priv->stop(dev); + priv->cached_beacon = NULL; priv->tsf_high32 = priv->tsf_low32 = 0; - priv->mode = NL80211_IFTYPE_UNSPECIFIED; + mutex_unlock(&priv->conf_mutex); } static int p54_add_interface(struct ieee80211_hw *dev, @@ -1159,32 +1782,28 @@ static int p54_add_interface(struct ieee80211_hw *dev, { struct p54_common *priv = dev->priv; - if (priv->mode != NL80211_IFTYPE_MONITOR) + mutex_lock(&priv->conf_mutex); + if (priv->mode != NL80211_IFTYPE_MONITOR) { + mutex_unlock(&priv->conf_mutex); return -EOPNOTSUPP; + } switch (conf->type) { case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_MESH_POINT: priv->mode = conf->type; break; default: + mutex_unlock(&priv->conf_mutex); return -EOPNOTSUPP; } memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); - - p54_set_filter(dev, 0, NULL); - - switch (conf->type) { - case NL80211_IFTYPE_STATION: - p54_set_filter(dev, 1, NULL); - break; - default: - BUG(); /* impossible */ - break; - } - + p54_setup_mac(dev); p54_set_leds(dev, 1, 0, 0); - + mutex_unlock(&priv->conf_mutex); return 0; } @@ -1192,22 +1811,38 @@ static void p54_remove_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf) { struct p54_common *priv = dev->priv; + + mutex_lock(&priv->conf_mutex); + if (priv->cached_beacon) + p54_tx_cancel(dev, priv->cached_beacon); priv->mode = NL80211_IFTYPE_MONITOR; memset(priv->mac_addr, 0, ETH_ALEN); - p54_set_filter(dev, 0, NULL); + memset(priv->bssid, 0, ETH_ALEN); + p54_setup_mac(dev); + mutex_unlock(&priv->conf_mutex); } -static int p54_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) +static int p54_config(struct ieee80211_hw *dev, u32 changed) { int ret; struct p54_common *priv = dev->priv; + struct ieee80211_conf *conf = &dev->conf; mutex_lock(&priv->conf_mutex); - priv->rx_antenna = (conf->antenna_sel_rx == 0) ? - 2 : conf->antenna_sel_tx - 1; - priv->output_power = conf->power_level << 2; - ret = p54_set_freq(dev, cpu_to_le16(conf->channel->center_freq)); - p54_set_vdcf(dev); + if (changed & IEEE80211_CONF_CHANGE_POWER) + priv->output_power = conf->power_level << 2; + if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) { + ret = p54_setup_mac(dev); + if (ret) + goto out; + } + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + ret = p54_scan(dev, P54_SCAN_EXIT, 0); + if (ret) + goto out; + } + +out: mutex_unlock(&priv->conf_mutex); return ret; } @@ -1217,13 +1852,36 @@ static int p54_config_interface(struct ieee80211_hw *dev, struct ieee80211_if_conf *conf) { struct p54_common *priv = dev->priv; + int ret = 0; mutex_lock(&priv->conf_mutex); - p54_set_filter(dev, 0, conf->bssid); - p54_set_leds(dev, 1, !is_multicast_ether_addr(conf->bssid), 0); - memcpy(priv->bssid, conf->bssid, ETH_ALEN); + if (conf->changed & IEEE80211_IFCC_BSSID) { + memcpy(priv->bssid, conf->bssid, ETH_ALEN); + ret = p54_setup_mac(dev); + if (ret) + goto out; + } + + if (conf->changed & IEEE80211_IFCC_BEACON) { + ret = p54_scan(dev, P54_SCAN_EXIT, 0); + if (ret) + goto out; + ret = p54_setup_mac(dev); + if (ret) + goto out; + ret = p54_beacon_update(dev, vif); + if (ret) + goto out; + ret = p54_set_edcf(dev); + if (ret) + goto out; + } + + ret = p54_set_leds(dev, 1, !is_multicast_ether_addr(priv->bssid), 0); + +out: mutex_unlock(&priv->conf_mutex); - return 0; + return ret; } static void p54_configure_filter(struct ieee80211_hw *dev, @@ -1233,94 +1891,78 @@ static void p54_configure_filter(struct ieee80211_hw *dev, { struct p54_common *priv = dev->priv; - *total_flags &= FIF_BCN_PRBRESP_PROMISC | - FIF_PROMISC_IN_BSS | - FIF_FCSFAIL; + *total_flags &= FIF_PROMISC_IN_BSS | + (*total_flags & FIF_PROMISC_IN_BSS) ? + FIF_FCSFAIL : 0; priv->filter_flags = *total_flags; - if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { - if (*total_flags & FIF_BCN_PRBRESP_PROMISC) - p54_set_filter(dev, le16_to_cpu(priv->filter_type), - NULL); - else - p54_set_filter(dev, le16_to_cpu(priv->filter_type), - priv->bssid); - } - - if (changed_flags & FIF_PROMISC_IN_BSS) { - if (*total_flags & FIF_PROMISC_IN_BSS) - p54_set_filter(dev, le16_to_cpu(priv->filter_type) | - 0x8, NULL); - else - p54_set_filter(dev, le16_to_cpu(priv->filter_type) & - ~0x8, priv->bssid); - } + if (changed_flags & FIF_PROMISC_IN_BSS) + p54_setup_mac(dev); } static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue, const struct ieee80211_tx_queue_params *params) { struct p54_common *priv = dev->priv; - struct p54_tx_control_vdcf *vdcf; - - vdcf = (struct p54_tx_control_vdcf *)(((struct p54_control_hdr *) - ((void *)priv->cached_vdcf + priv->tx_hdr_len))->data); + int ret; + mutex_lock(&priv->conf_mutex); if ((params) && !(queue > 4)) { - P54_SET_QUEUE(vdcf->queue[queue], params->aifs, + P54_SET_QUEUE(priv->qos_params[queue], params->aifs, params->cw_min, params->cw_max, params->txop); + ret = p54_set_edcf(dev); } else - return -EINVAL; - - p54_set_vdcf(dev); - - return 0; + ret = -EINVAL; + mutex_unlock(&priv->conf_mutex); + return ret; } static int p54_init_xbow_synth(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; - struct p54_tx_control_xbow_synth *xbow; + struct sk_buff *skb; + struct p54_xbow_synth *xbow; - hdr = kzalloc(sizeof(*hdr) + sizeof(*xbow) + - priv->tx_hdr_len, GFP_KERNEL); - if (!hdr) + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*xbow) + + sizeof(struct p54_hdr), + P54_CONTROL_TYPE_XBOW_SYNTH_CFG, + GFP_KERNEL); + if (!skb) return -ENOMEM; - hdr = (void *)hdr + priv->tx_hdr_len; - hdr->magic1 = cpu_to_le16(0x8001); - hdr->len = cpu_to_le16(sizeof(*xbow)); - hdr->type = cpu_to_le16(P54_CONTROL_TYPE_XBOW_SYNTH_CFG); - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*xbow)); - - xbow = (struct p54_tx_control_xbow_synth *) hdr->data; + xbow = (struct p54_xbow_synth *)skb_put(skb, sizeof(*xbow)); xbow->magic1 = cpu_to_le16(0x1); xbow->magic2 = cpu_to_le16(0x2); xbow->freq = cpu_to_le16(5390); - - priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*xbow), 1); - + memset(xbow->padding, 0, sizeof(xbow->padding)); + priv->tx(dev, skb); return 0; } -static void p54_statistics_timer(unsigned long data) +static void p54_work(struct work_struct *work) { - struct ieee80211_hw *dev = (struct ieee80211_hw *) data; - struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; - struct p54_statistics *stats; + struct p54_common *priv = container_of(work, struct p54_common, + work.work); + struct ieee80211_hw *dev = priv->hw; + struct sk_buff *skb; - BUG_ON(!priv->cached_stats); + if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) + return ; - hdr = (void *)priv->cached_stats + priv->tx_hdr_len; - hdr->magic1 = cpu_to_le16(0x8000); - hdr->len = cpu_to_le16(sizeof(*stats)); - hdr->type = cpu_to_le16(P54_CONTROL_TYPE_STAT_READBACK); - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*stats)); + /* + * TODO: walk through tx_queue and do the following tasks + * 1. initiate bursts. + * 2. cancel stuck frames / reset the device if necessary. + */ + + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL, sizeof(struct p54_hdr) + + sizeof(struct p54_statistics), + P54_CONTROL_TYPE_STAT_READBACK, GFP_KERNEL); + if (!skb) + return ; - priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*stats), 0); + priv->tx(dev, skb); } static int p54_get_stats(struct ieee80211_hw *dev, @@ -1328,17 +1970,7 @@ static int p54_get_stats(struct ieee80211_hw *dev, { struct p54_common *priv = dev->priv; - del_timer(&priv->stats_timer); - p54_statistics_timer((unsigned long)dev); - - if (!wait_for_completion_interruptible_timeout(&priv->stats_comp, HZ)) { - printk(KERN_ERR "%s: device does not respond!\n", - wiphy_name(dev->wiphy)); - return -EBUSY; - } - memcpy(stats, &priv->stats, sizeof(*stats)); - return 0; } @@ -1352,14 +1984,133 @@ static int p54_get_tx_stats(struct ieee80211_hw *dev, return 0; } +static void p54_bss_info_changed(struct ieee80211_hw *dev, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u32 changed) +{ + struct p54_common *priv = dev->priv; + + if (changed & BSS_CHANGED_ERP_SLOT) { + priv->use_short_slot = info->use_short_slot; + p54_set_edcf(dev); + } + if (changed & BSS_CHANGED_BASIC_RATES) { + if (dev->conf.channel->band == IEEE80211_BAND_5GHZ) + priv->basic_rate_mask = (info->basic_rates << 4); + else + priv->basic_rate_mask = info->basic_rates; + p54_setup_mac(dev); + if (priv->fw_var >= 0x500) + p54_scan(dev, P54_SCAN_EXIT, 0); + } + if (changed & BSS_CHANGED_ASSOC) { + if (info->assoc) { + priv->aid = info->aid; + priv->wakeup_timer = info->beacon_int * + info->dtim_period * 5; + p54_setup_mac(dev); + } + } + +} + +static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, + const u8 *local_address, const u8 *address, + struct ieee80211_key_conf *key) +{ + struct p54_common *priv = dev->priv; + struct sk_buff *skb; + struct p54_keycache *rxkey; + u8 algo = 0; + + if (modparam_nohwcrypt) + return -EOPNOTSUPP; + + if (cmd == DISABLE_KEY) + algo = 0; + else { + switch (key->alg) { + case ALG_TKIP: + if (!(priv->privacy_caps & (BR_DESC_PRIV_CAP_MICHAEL | + BR_DESC_PRIV_CAP_TKIP))) + return -EOPNOTSUPP; + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + algo = P54_CRYPTO_TKIPMICHAEL; + break; + case ALG_WEP: + if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP)) + return -EOPNOTSUPP; + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + algo = P54_CRYPTO_WEP; + break; + case ALG_CCMP: + if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)) + return -EOPNOTSUPP; + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + algo = P54_CRYPTO_AESCCMP; + break; + default: + return -EINVAL; + } + } + + if (key->keyidx > priv->rx_keycache_size) { + /* + * The device supports the choosen algorithm, but the firmware + * does not provide enough key slots to store all of them. + * So, incoming frames have to be decoded by the mac80211 stack, + * but we can still offload encryption for outgoing frames. + */ + + return 0; + } + + mutex_lock(&priv->conf_mutex); + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*rxkey) + + sizeof(struct p54_hdr), P54_CONTROL_TYPE_RX_KEYCACHE, + GFP_ATOMIC); + if (!skb) { + mutex_unlock(&priv->conf_mutex); + return -ENOMEM; + } + + /* TODO: some devices have 4 more free slots for rx keys */ + rxkey = (struct p54_keycache *)skb_put(skb, sizeof(*rxkey)); + rxkey->entry = key->keyidx; + rxkey->key_id = key->keyidx; + rxkey->key_type = algo; + if (address) + memcpy(rxkey->mac, address, ETH_ALEN); + else + memset(rxkey->mac, ~0, ETH_ALEN); + if (key->alg != ALG_TKIP) { + rxkey->key_len = min((u8)16, key->keylen); + memcpy(rxkey->key, key->key, rxkey->key_len); + } else { + rxkey->key_len = 24; + memcpy(rxkey->key, key->key, 16); + memcpy(&(rxkey->key[16]), &(key->key + [NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]), 8); + } + + priv->tx(dev, skb); + mutex_unlock(&priv->conf_mutex); + return 0; +} + static const struct ieee80211_ops p54_ops = { .tx = p54_tx, .start = p54_start, .stop = p54_stop, .add_interface = p54_add_interface, .remove_interface = p54_remove_interface, + .set_tim = p54_set_tim, + .sta_notify = p54_sta_notify, + .set_key = p54_set_key, .config = p54_config, .config_interface = p54_config_interface, + .bss_info_changed = p54_bss_info_changed, .configure_filter = p54_configure_filter, .conf_tx = p54_conf_tx, .get_stats = p54_get_stats, @@ -1376,32 +2127,43 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) return NULL; priv = dev->priv; + priv->hw = dev; priv->mode = NL80211_IFTYPE_UNSPECIFIED; + priv->basic_rate_mask = 0x15f; skb_queue_head_init(&priv->tx_queue); - dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */ - IEEE80211_HW_RX_INCLUDES_FCS | + dev->flags = IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; - dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_MESH_POINT); dev->channel_change_time = 1000; /* TODO: find actual value */ - - priv->tx_stats[0].limit = 1; - priv->tx_stats[1].limit = 1; - priv->tx_stats[2].limit = 1; - priv->tx_stats[3].limit = 1; - priv->tx_stats[4].limit = 5; + priv->tx_stats[0].limit = 1; /* Beacon queue */ + priv->tx_stats[1].limit = 1; /* Probe queue for HW scan */ + priv->tx_stats[2].limit = 3; /* queue for MLMEs */ + priv->tx_stats[3].limit = 3; /* Broadcast / MC queue */ + priv->tx_stats[4].limit = 5; /* Data */ dev->queues = 1; priv->noise = -94; - dev->extra_tx_headroom = sizeof(struct p54_control_hdr) + 4 + - sizeof(struct p54_tx_control_allocdata); + /* + * We support at most 8 tries no matter which rate they're at, + * we cannot support max_rates * max_rate_tries as we set it + * here, but setting it correctly to 4/2 or so would limit us + * artificially if the RC algorithm wants just two rates, so + * let's say 4/7, we'll redistribute it at TX time, see the + * comments there. + */ + dev->max_rates = 4; + dev->max_rate_tries = 7; + dev->extra_tx_headroom = sizeof(struct p54_hdr) + 4 + + sizeof(struct p54_tx_data); mutex_init(&priv->conf_mutex); init_completion(&priv->eeprom_comp); - init_completion(&priv->stats_comp); - setup_timer(&priv->stats_timer, p54_statistics_timer, - (unsigned long)dev); + INIT_DELAYED_WORK(&priv->work, p54_work); return dev; } @@ -1410,11 +2172,9 @@ EXPORT_SYMBOL_GPL(p54_init_common); void p54_free_common(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; - kfree(priv->cached_stats); kfree(priv->iq_autocal); kfree(priv->output_limit); kfree(priv->curve_data); - kfree(priv->cached_vdcf); } EXPORT_SYMBOL_GPL(p54_free_common); diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index 2fa994cfcfed413cfdf08f9d6c043cec89b7536a..f5729de83fe118eaeb36ea55c9f9cecdacd2c40b 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -7,8 +7,12 @@ * Copyright (c) 2006, Michael Wu * Copyright (c) 2007, Christian Lamparter * - * Based on the islsm (softmac prism54) driver, which is: - * Copyright 2004-2006 Jean-Baptiste Note , et al. + * Based on: + * - the islsm (softmac prism54) driver, which is: + * Copyright 2004-2006 Jean-Baptiste Note , et al. + * + * - LMAC API interface header file for STLC4560 (lmac_longbow.h) + * Copyright (C) 2007 Conexant Systems, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -19,9 +23,24 @@ struct bootrec { __le32 code; __le32 len; u32 data[10]; - __le16 rx_mtu; } __attribute__((packed)); +#define PDR_SYNTH_FRONTEND_MASK 0x0007 +#define PDR_SYNTH_IQ_CAL_MASK 0x0018 +#define PDR_SYNTH_IQ_CAL_PA_DETECTOR 0x0000 +#define PDR_SYNTH_IQ_CAL_DISABLED 0x0008 +#define PDR_SYNTH_IQ_CAL_ZIF 0x0010 +#define PDR_SYNTH_FAA_SWITCH_MASK 0x0020 +#define PDR_SYNTH_FAA_SWITCH_ENABLED 0x0001 +#define PDR_SYNTH_24_GHZ_MASK 0x0040 +#define PDR_SYNTH_24_GHZ_DISABLED 0x0040 +#define PDR_SYNTH_5_GHZ_MASK 0x0080 +#define PDR_SYNTH_5_GHZ_DISABLED 0x0080 +#define PDR_SYNTH_RX_DIV_MASK 0x0100 +#define PDR_SYNTH_RX_DIV_SUPPORTED 0x0100 +#define PDR_SYNTH_TX_DIV_MASK 0x0200 +#define PDR_SYNTH_TX_DIV_SUPPORTED 0x0200 + struct bootrec_exp_if { __le16 role; __le16 if_id; @@ -30,6 +49,13 @@ struct bootrec_exp_if { __le16 top_compat; } __attribute__((packed)); +#define BR_DESC_PRIV_CAP_WEP BIT(0) +#define BR_DESC_PRIV_CAP_TKIP BIT(1) +#define BR_DESC_PRIV_CAP_MICHAEL BIT(2) +#define BR_DESC_PRIV_CAP_CCX_CP BIT(3) +#define BR_DESC_PRIV_CAP_CCX_MIC BIT(4) +#define BR_DESC_PRIV_CAP_AESCCMP BIT(5) + struct bootrec_desc { __le16 modes; __le16 flags; @@ -37,8 +63,15 @@ struct bootrec_desc { __le32 rx_end; u8 headroom; u8 tailroom; - u8 unimportant[6]; + u8 tx_queues; + u8 tx_depth; + u8 privacy_caps; + u8 rx_keycache_size; + u8 time_size; + u8 padding; u8 rates[16]; + u8 padding2[4]; + __le16 rx_mtu; } __attribute__((packed)); #define BR_CODE_MIN 0x80000000 @@ -51,6 +84,31 @@ struct bootrec_desc { #define BR_CODE_END_OF_BRA 0xFF0000FF #define LEGACY_BR_CODE_END_OF_BRA 0xFFFFFFFF +#define P54_HDR_FLAG_DATA_ALIGN BIT(14) +#define P54_HDR_FLAG_DATA_OUT_PROMISC BIT(0) +#define P54_HDR_FLAG_DATA_OUT_TIMESTAMP BIT(1) +#define P54_HDR_FLAG_DATA_OUT_SEQNR BIT(2) +#define P54_HDR_FLAG_DATA_OUT_BIT3 BIT(3) +#define P54_HDR_FLAG_DATA_OUT_BURST BIT(4) +#define P54_HDR_FLAG_DATA_OUT_NOCANCEL BIT(5) +#define P54_HDR_FLAG_DATA_OUT_CLEARTIM BIT(6) +#define P54_HDR_FLAG_DATA_OUT_HITCHHIKE BIT(7) +#define P54_HDR_FLAG_DATA_OUT_COMPRESS BIT(8) +#define P54_HDR_FLAG_DATA_OUT_CONCAT BIT(9) +#define P54_HDR_FLAG_DATA_OUT_PCS_ACCEPT BIT(10) +#define P54_HDR_FLAG_DATA_OUT_WAITEOSP BIT(11) + +#define P54_HDR_FLAG_DATA_IN_FCS_GOOD BIT(0) +#define P54_HDR_FLAG_DATA_IN_MATCH_MAC BIT(1) +#define P54_HDR_FLAG_DATA_IN_MCBC BIT(2) +#define P54_HDR_FLAG_DATA_IN_BEACON BIT(3) +#define P54_HDR_FLAG_DATA_IN_MATCH_BSS BIT(4) +#define P54_HDR_FLAG_DATA_IN_BCAST_BSS BIT(5) +#define P54_HDR_FLAG_DATA_IN_DATA BIT(6) +#define P54_HDR_FLAG_DATA_IN_TRUNCATED BIT(7) +#define P54_HDR_FLAG_DATA_IN_BIT8 BIT(8) +#define P54_HDR_FLAG_DATA_IN_TRANSPARENT BIT(9) + /* PDA defines are Copyright (C) 2005 Nokia Corporation (taken from islsm_pda.h) */ struct pda_entry { @@ -117,6 +175,11 @@ struct pda_pa_curve_data { u8 data[0]; } __attribute__ ((packed)); +struct pda_rssi_cal_entry { + __le16 mul; + __le16 add; +} __attribute__ ((packed)); + /* * this defines the PDR codes used to build PDAs as defined in document * number 553155. The current implementation mirrors version 1.1 of the @@ -165,6 +228,19 @@ struct pda_pa_curve_data { #define PDR_BASEBAND_REGISTERS 0x8000 #define PDR_PER_CHANNEL_BASEBAND_REGISTERS 0x8001 +/* PDR definitions for default country & country list */ +#define PDR_COUNTRY_CERT_CODE 0x80 +#define PDR_COUNTRY_CERT_CODE_REAL 0x00 +#define PDR_COUNTRY_CERT_CODE_PSEUDO 0x80 +#define PDR_COUNTRY_CERT_BAND 0x40 +#define PDR_COUNTRY_CERT_BAND_2GHZ 0x00 +#define PDR_COUNTRY_CERT_BAND_5GHZ 0x40 +#define PDR_COUNTRY_CERT_IODOOR 0x30 +#define PDR_COUNTRY_CERT_IODOOR_BOTH 0x00 +#define PDR_COUNTRY_CERT_IODOOR_INDOOR 0x20 +#define PDR_COUNTRY_CERT_IODOOR_OUTDOOR 0x30 +#define PDR_COUNTRY_CERT_INDEX 0x0F + /* stored in skb->cb */ struct memrecord { u32 start_addr; @@ -172,41 +248,108 @@ struct memrecord { }; struct p54_eeprom_lm86 { - __le16 offset; - __le16 len; - u8 data[0]; + union { + struct { + __le16 offset; + __le16 len; + u8 data[0]; + } v1; + struct { + __le32 offset; + __le16 len; + u8 magic2; + u8 pad; + u8 magic[4]; + u8 data[0]; + } v2; + } __attribute__ ((packed)); } __attribute__ ((packed)); -struct p54_rx_hdr { - __le16 magic; +enum p54_rx_decrypt_status { + P54_DECRYPT_NONE = 0, + P54_DECRYPT_OK, + P54_DECRYPT_NOKEY, + P54_DECRYPT_NOMICHAEL, + P54_DECRYPT_NOCKIPMIC, + P54_DECRYPT_FAIL_WEP, + P54_DECRYPT_FAIL_TKIP, + P54_DECRYPT_FAIL_MICHAEL, + P54_DECRYPT_FAIL_CKIPKP, + P54_DECRYPT_FAIL_CKIPMIC, + P54_DECRYPT_FAIL_AESCCMP +}; + +struct p54_rx_data { + __le16 flags; __le16 len; __le16 freq; u8 antenna; u8 rate; u8 rssi; u8 quality; - u16 unknown2; + u8 decrypt_status; + u8 rssi_raw; __le32 tsf32; __le32 unalloc0; u8 align[0]; } __attribute__ ((packed)); -struct p54_frame_sent_hdr { +enum p54_trap_type { + P54_TRAP_SCAN = 0, + P54_TRAP_TIMER, + P54_TRAP_BEACON_TX, + P54_TRAP_FAA_RADIO_ON, + P54_TRAP_FAA_RADIO_OFF, + P54_TRAP_RADAR, + P54_TRAP_NO_BEACON, + P54_TRAP_TBTT, + P54_TRAP_SCO_ENTER, + P54_TRAP_SCO_EXIT +}; + +struct p54_trap { + __le16 event; + __le16 frequency; +} __attribute__ ((packed)); + +enum p54_frame_sent_status { + P54_TX_OK = 0, + P54_TX_FAILED, + P54_TX_PSM, + P54_TX_PSM_CANCELLED = 4 +}; + +struct p54_frame_sent { u8 status; - u8 retries; - __le16 ack_rssi; + u8 tries; + u8 ack_rssi; + u8 quality; __le16 seq; - u16 rate; + u8 antenna; + u8 padding; } __attribute__ ((packed)); -struct p54_tx_control_allocdata { +enum p54_tx_data_crypt { + P54_CRYPTO_NONE = 0, + P54_CRYPTO_WEP, + P54_CRYPTO_TKIP, + P54_CRYPTO_TKIPMICHAEL, + P54_CRYPTO_CCX_WEPMIC, + P54_CRYPTO_CCX_KPMIC, + P54_CRYPTO_CCX_KP, + P54_CRYPTO_AESCCMP +}; + +struct p54_tx_data { u8 rateset[8]; - u8 unalloc0[2]; + u8 rts_rate_idx; + u8 crypt_offset; u8 key_type; u8 key_len; u8 key[16]; u8 hw_queue; - u8 unalloc1[9]; + u8 backlog; + __le16 durations[4]; u8 tx_antenna; u8 output_power; u8 cts_rate; @@ -214,8 +357,23 @@ struct p54_tx_control_allocdata { u8 align[0]; } __attribute__ ((packed)); -struct p54_tx_control_filter { - __le16 filter_type; +/* unit is ms */ +#define P54_TX_FRAME_LIFETIME 2000 +#define P54_TX_TIMEOUT 4000 +#define P54_STATISTICS_UPDATE 5000 + +#define P54_FILTER_TYPE_NONE 0 +#define P54_FILTER_TYPE_STATION BIT(0) +#define P54_FILTER_TYPE_IBSS BIT(1) +#define P54_FILTER_TYPE_AP BIT(2) +#define P54_FILTER_TYPE_TRANSPARENT BIT(3) +#define P54_FILTER_TYPE_PROMISCUOUS BIT(4) +#define P54_FILTER_TYPE_HIBERNATE BIT(5) +#define P54_FILTER_TYPE_NOACK BIT(6) +#define P54_FILTER_TYPE_RX_DISABLED BIT(7) + +struct p54_setup_mac { + __le16 mac_mode; u8 mac_addr[ETH_ALEN]; u8 bssid[ETH_ALEN]; u8 rx_antenna; @@ -235,17 +393,29 @@ struct p54_tx_control_filter { __le16 max_rx; __le16 rxhw; __le16 timer; - __le16 unalloc0; - __le32 unalloc1; + __le16 truncate; + __le32 basic_rate_mask; + u8 sbss_offset; + u8 mcast_window; + u8 rx_rssi_threshold; + u8 rx_ed_threshold; + __le32 ref_clock; + __le16 lpf_bandwidth; + __le16 osc_start_delay; } v2 __attribute__ ((packed)); } __attribute__ ((packed)); } __attribute__ ((packed)); -#define P54_TX_CONTROL_FILTER_V1_LEN (sizeof(struct p54_tx_control_filter)) -#define P54_TX_CONTROL_FILTER_V2_LEN (sizeof(struct p54_tx_control_filter)-8) +#define P54_SETUP_V1_LEN 40 +#define P54_SETUP_V2_LEN (sizeof(struct p54_setup_mac)) -struct p54_tx_control_channel { - __le16 flags; +#define P54_SCAN_EXIT BIT(0) +#define P54_SCAN_TRAP BIT(1) +#define P54_SCAN_ACTIVE BIT(2) +#define P54_SCAN_FILTER BIT(3) + +struct p54_scan { + __le16 mode; __le16 dwell; u8 padding1[20]; struct pda_iq_autocal_entry iq_autocal; @@ -261,45 +431,35 @@ struct p54_tx_control_channel { u8 dup_16qam; u8 dup_64qam; union { - struct { - __le16 rssical_mul; - __le16 rssical_add; - } v1 __attribute__ ((packed)); + struct pda_rssi_cal_entry v1_rssi; struct { __le32 basic_rate_mask; - u8 rts_rates[8]; - __le16 rssical_mul; - __le16 rssical_add; + u8 rts_rates[8]; + struct pda_rssi_cal_entry rssi; } v2 __attribute__ ((packed)); } __attribute__ ((packed)); } __attribute__ ((packed)); -#define P54_TX_CONTROL_CHANNEL_V1_LEN (sizeof(struct p54_tx_control_channel)-12) -#define P54_TX_CONTROL_CHANNEL_V2_LEN (sizeof(struct p54_tx_control_channel)) +#define P54_SCAN_V1_LEN 0x70 +#define P54_SCAN_V2_LEN 0x7c -struct p54_tx_control_led { +struct p54_led { __le16 mode; __le16 led_temporary; __le16 led_permanent; __le16 duration; } __attribute__ ((packed)); -struct p54_tx_vdcf_queues { - __le16 aifs; - __le16 cwmin; - __le16 cwmax; - __le16 txop; -} __attribute__ ((packed)); - -struct p54_tx_control_vdcf { - u8 padding; +struct p54_edcf { + u8 flags; u8 slottime; - u8 magic1; - u8 magic2; - struct p54_tx_vdcf_queues queue[8]; - u8 pad2[4]; + u8 sifs; + u8 eofpad; + struct p54_edcf_queue_param queue[8]; + u8 mapping[4]; __le16 frameburst; + __le16 round_trip_delay; } __attribute__ ((packed)); struct p54_statistics { @@ -312,14 +472,103 @@ struct p54_statistics { __le32 tsf32; __le32 airtime; __le32 noise; - __le32 unkn[10]; /* CCE / CCA / RADAR */ + __le32 sample_noise[8]; + __le32 sample_cca; + __le32 sample_tx; } __attribute__ ((packed)); -struct p54_tx_control_xbow_synth { +struct p54_xbow_synth { __le16 magic1; __le16 magic2; __le16 freq; u32 padding[5]; } __attribute__ ((packed)); +struct p54_timer { + __le32 interval; +} __attribute__ ((packed)); + +struct p54_keycache { + u8 entry; + u8 key_id; + u8 mac[ETH_ALEN]; + u8 padding[2]; + u8 key_type; + u8 key_len; + u8 key[24]; +} __attribute__ ((packed)); + +struct p54_burst { + u8 flags; + u8 queue; + u8 backlog; + u8 pad; + __le16 durations[32]; +} __attribute__ ((packed)); + +struct p54_psm_interval { + __le16 interval; + __le16 periods; +} __attribute__ ((packed)); + +#define P54_PSM BIT(0) +#define P54_PSM_DTIM BIT(1) +#define P54_PSM_MCBC BIT(2) +#define P54_PSM_CHECKSUM BIT(3) +#define P54_PSM_SKIP_MORE_DATA BIT(4) +#define P54_PSM_BEACON_TIMEOUT BIT(5) +#define P54_PSM_HFOSLEEP BIT(6) +#define P54_PSM_AUTOSWITCH_SLEEP BIT(7) +#define P54_PSM_LPIT BIT(8) +#define P54_PSM_BF_UCAST_SKIP BIT(9) +#define P54_PSM_BF_MCAST_SKIP BIT(10) + +struct p54_psm { + __le16 mode; + __le16 aid; + struct p54_psm_interval intervals[4]; + u8 beacon_rssi_skip_max; + u8 rssi_delta_threshold; + u8 nr; + u8 exclude[1]; +} __attribute__ ((packed)); + +#define MC_FILTER_ADDRESS_NUM 4 + +struct p54_group_address_table { + __le16 filter_enable; + __le16 num_address; + u8 mac_list[MC_FILTER_ADDRESS_NUM][ETH_ALEN]; +} __attribute__ ((packed)); + +struct p54_txcancel { + __le32 req_id; +} __attribute__ ((packed)); + +struct p54_sta_unlock { + u8 addr[ETH_ALEN]; + u16 padding; +} __attribute__ ((packed)); + +#define P54_TIM_CLEAR BIT(15) +struct p54_tim { + u8 count; + u8 padding[3]; + __le16 entry[8]; +} __attribute__ ((packed)); + +struct p54_cce_quiet { + __le32 period; +} __attribute__ ((packed)); + +struct p54_bt_balancer { + __le16 prio_thresh; + __le16 acl_thresh; +} __attribute__ ((packed)); + +struct p54_arp_table { + __le16 filter_enable; + u8 ipv4_addr[4]; +} __attribute__ ((packed)); + #endif /* P54COMMON_H */ diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index 88b3cad8b65e0c72b18bcde9d02c2dc11f2f0b97..aa367a0ddc49139ac51a097730a0f464d97c24e0 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -28,6 +28,7 @@ MODULE_AUTHOR("Michael Wu "); MODULE_DESCRIPTION("Prism54 PCI wireless driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("prism54pci"); +MODULE_FIRMWARE("isl3886pci"); static struct pci_device_id p54p_table[] __devinitdata = { /* Intersil PRISM Duette/Prism GT Wireless LAN adapter */ @@ -46,7 +47,6 @@ MODULE_DEVICE_TABLE(pci, p54p_table); static int p54p_upload_firmware(struct ieee80211_hw *dev) { struct p54p_priv *priv = dev->priv; - const struct firmware *fw_entry = NULL; __le32 reg; int err; __le32 *data; @@ -72,21 +72,15 @@ static int p54p_upload_firmware(struct ieee80211_hw *dev) P54P_WRITE(ctrl_stat, reg); wmb(); - err = request_firmware(&fw_entry, "isl3886", &priv->pdev->dev); - if (err) { - printk(KERN_ERR "%s (p54pci): cannot find firmware " - "(isl3886)\n", pci_name(priv->pdev)); - return err; - } + /* wait for the firmware to reset properly */ + mdelay(10); - err = p54_parse_firmware(dev, fw_entry); - if (err) { - release_firmware(fw_entry); + err = p54_parse_firmware(dev, priv->firmware); + if (err) return err; - } - data = (__le32 *) fw_entry->data; - remains = fw_entry->size; + data = (__le32 *) priv->firmware->data; + remains = priv->firmware->size; device_addr = ISL38XX_DEV_FIRMWARE_ADDR; while (remains) { u32 i = 0; @@ -104,8 +98,6 @@ static int p54p_upload_firmware(struct ieee80211_hw *dev) P54P_READ(int_enable); } - release_firmware(fw_entry); - reg = P54P_READ(ctrl_stat); reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN); reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET); @@ -235,7 +227,9 @@ static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index, while (i != idx) { desc = &ring[i]; - kfree(tx_buf[i]); + if (tx_buf[i]) + if (FREE_AFTER_TX((struct sk_buff *) tx_buf[i])) + p54_free_skb(dev, tx_buf[i]); tx_buf[i] = NULL; pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), @@ -306,8 +300,7 @@ static irqreturn_t p54p_interrupt(int irq, void *dev_id) return reg ? IRQ_HANDLED : IRQ_NONE; } -static void p54p_tx(struct ieee80211_hw *dev, struct p54_control_hdr *data, - size_t len, int free_on_tx) +static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54p_priv *priv = dev->priv; struct p54p_ring_control *ring_control = priv->ring_control; @@ -322,28 +315,21 @@ static void p54p_tx(struct ieee80211_hw *dev, struct p54_control_hdr *data, idx = le32_to_cpu(ring_control->host_idx[1]); i = idx % ARRAY_SIZE(ring_control->tx_data); - mapping = pci_map_single(priv->pdev, data, len, PCI_DMA_TODEVICE); + priv->tx_buf_data[i] = skb; + mapping = pci_map_single(priv->pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); desc = &ring_control->tx_data[i]; desc->host_addr = cpu_to_le32(mapping); - desc->device_addr = data->req_id; - desc->len = cpu_to_le16(len); + desc->device_addr = ((struct p54_hdr *)skb->data)->req_id; + desc->len = cpu_to_le16(skb->len); desc->flags = 0; wmb(); ring_control->host_idx[1] = cpu_to_le32(idx + 1); - - if (free_on_tx) - priv->tx_buf_data[i] = data; - spin_unlock_irqrestore(&priv->lock, flags); P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE)); P54P_READ(dev_int); - - /* FIXME: unlikely to happen because the device usually runs out of - memory before we fill the ring up, but we can make it impossible */ - if (idx - device_idx > ARRAY_SIZE(ring_control->tx_data) - 2) - printk(KERN_INFO "%s: tx overflow.\n", wiphy_name(dev->wiphy)); } static void p54p_stop(struct ieee80211_hw *dev) @@ -393,7 +379,7 @@ static void p54p_stop(struct ieee80211_hw *dev) le16_to_cpu(desc->len), PCI_DMA_TODEVICE); - kfree(priv->tx_buf_data[i]); + p54_free_skb(dev, priv->tx_buf_data[i]); priv->tx_buf_data[i] = NULL; } @@ -405,7 +391,7 @@ static void p54p_stop(struct ieee80211_hw *dev) le16_to_cpu(desc->len), PCI_DMA_TODEVICE); - kfree(priv->tx_buf_mgmt[i]); + p54_free_skb(dev, priv->tx_buf_mgmt[i]); priv->tx_buf_mgmt[i] = NULL; } @@ -481,7 +467,6 @@ static int __devinit p54p_probe(struct pci_dev *pdev, struct ieee80211_hw *dev; unsigned long mem_addr, mem_len; int err; - DECLARE_MAC_BUF(mac); err = pci_enable_device(pdev); if (err) { @@ -495,15 +480,14 @@ static int __devinit p54p_probe(struct pci_dev *pdev, if (mem_len < sizeof(struct p54p_csr)) { printk(KERN_ERR "%s (p54pci): Too short PCI resources\n", pci_name(pdev)); - pci_disable_device(pdev); - return err; + goto err_disable_dev; } err = pci_request_regions(pdev, "p54pci"); if (err) { printk(KERN_ERR "%s (p54pci): Cannot obtain PCI resources\n", pci_name(pdev)); - return err; + goto err_disable_dev; } if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) || @@ -556,6 +540,17 @@ static int __devinit p54p_probe(struct pci_dev *pdev, spin_lock_init(&priv->lock); tasklet_init(&priv->rx_tasklet, p54p_rx_tasklet, (unsigned long)dev); + err = request_firmware(&priv->firmware, "isl3886pci", + &priv->pdev->dev); + if (err) { + printk(KERN_ERR "%s (p54pci): cannot find firmware " + "(isl3886pci)\n", pci_name(priv->pdev)); + err = request_firmware(&priv->firmware, "isl3886", + &priv->pdev->dev); + if (err) + goto err_free_common; + } + err = p54p_open(dev); if (err) goto err_free_common; @@ -574,6 +569,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev, return 0; err_free_common: + release_firmware(priv->firmware); p54_free_common(dev); pci_free_consistent(pdev, sizeof(*priv->ring_control), priv->ring_control, priv->ring_control_dma); @@ -587,6 +583,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev, err_free_reg: pci_release_regions(pdev); + err_disable_dev: pci_disable_device(pdev); return err; } @@ -601,6 +598,7 @@ static void __devexit p54p_remove(struct pci_dev *pdev) ieee80211_unregister_hw(dev); priv = dev->priv; + release_firmware(priv->firmware); pci_free_consistent(pdev, sizeof(*priv->ring_control), priv->ring_control, priv->ring_control_dma); p54_free_common(dev); diff --git a/drivers/net/wireless/p54/p54pci.h b/drivers/net/wireless/p54/p54pci.h index 4a6778070afc1fc3da1a2cbc9c9d598db9d07e75..fbb683953fb258b8949627398fff499fd21355fd 100644 --- a/drivers/net/wireless/p54/p54pci.h +++ b/drivers/net/wireless/p54/p54pci.h @@ -93,7 +93,7 @@ struct p54p_priv { struct pci_dev *pdev; struct p54p_csr __iomem *map; struct tasklet_struct rx_tasklet; - + const struct firmware *firmware; spinlock_t lock; struct p54p_ring_control *ring_control; dma_addr_t ring_control_dma; diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 75d749bccb0d13e17104b67e348c3723bbb1032b..c44a200059d21c4ce0aae4a6f66b2e61af73984e 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -28,6 +28,8 @@ MODULE_AUTHOR("Michael Wu "); MODULE_DESCRIPTION("Prism54 USB wireless driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("prism54usb"); +MODULE_FIRMWARE("isl3886usb"); +MODULE_FIRMWARE("isl3887usb"); static struct usb_device_id p54u_table[] __devinitdata = { /* Version 1 devices (pci chip + net2280) */ @@ -84,13 +86,13 @@ static void p54u_rx_cb(struct urb *urb) struct ieee80211_hw *dev = info->dev; struct p54u_priv *priv = dev->priv; + skb_unlink(skb, &priv->rx_queue); + if (unlikely(urb->status)) { - info->urb = NULL; - usb_free_urb(urb); + dev_kfree_skb_irq(skb); return; } - skb_unlink(skb, &priv->rx_queue); skb_put(skb, urb->actual_length); if (priv->hw_type == P54U_NET2280) @@ -103,7 +105,6 @@ static void p54u_rx_cb(struct urb *urb) if (p54_rx(dev, skb)) { skb = dev_alloc_skb(priv->common.rx_mtu + 32); if (unlikely(!skb)) { - usb_free_urb(urb); /* TODO check rx queue length and refill *somewhere* */ return; } @@ -113,7 +114,6 @@ static void p54u_rx_cb(struct urb *urb) info->dev = dev; urb->transfer_buffer = skb_tail_pointer(skb); urb->context = skb; - skb_queue_tail(&priv->rx_queue, skb); } else { if (priv->hw_type == P54U_NET2280) skb_push(skb, priv->common.tx_hdr_len); @@ -128,40 +128,56 @@ static void p54u_rx_cb(struct urb *urb) WARN_ON(1); urb->transfer_buffer = skb_tail_pointer(skb); } - - skb_queue_tail(&priv->rx_queue, skb); } - - usb_submit_urb(urb, GFP_ATOMIC); + skb_queue_tail(&priv->rx_queue, skb); + usb_anchor_urb(urb, &priv->submitted); + if (usb_submit_urb(urb, GFP_ATOMIC)) { + skb_unlink(skb, &priv->rx_queue); + usb_unanchor_urb(urb); + dev_kfree_skb_irq(skb); + } } static void p54u_tx_cb(struct urb *urb) { - usb_free_urb(urb); + struct sk_buff *skb = urb->context; + struct ieee80211_hw *dev = (struct ieee80211_hw *) + usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); + struct p54u_priv *priv = dev->priv; + + skb_pull(skb, priv->common.tx_hdr_len); + if (FREE_AFTER_TX(skb)) + p54_free_skb(dev, skb); } -static void p54u_tx_free_cb(struct urb *urb) +static void p54u_tx_dummy_cb(struct urb *urb) { } + +static void p54u_free_urbs(struct ieee80211_hw *dev) { - kfree(urb->transfer_buffer); - usb_free_urb(urb); + struct p54u_priv *priv = dev->priv; + usb_kill_anchored_urbs(&priv->submitted); } static int p54u_init_urbs(struct ieee80211_hw *dev) { struct p54u_priv *priv = dev->priv; - struct urb *entry; + struct urb *entry = NULL; struct sk_buff *skb; struct p54u_rx_info *info; + int ret = 0; while (skb_queue_len(&priv->rx_queue) < 32) { skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL); - if (!skb) - break; + if (!skb) { + ret = -ENOMEM; + goto err; + } entry = usb_alloc_urb(0, GFP_KERNEL); if (!entry) { - kfree_skb(skb); - break; + ret = -ENOMEM; + goto err; } + usb_fill_bulk_urb(entry, priv->udev, usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), skb_tail_pointer(skb), @@ -170,33 +186,32 @@ static int p54u_init_urbs(struct ieee80211_hw *dev) info->urb = entry; info->dev = dev; skb_queue_tail(&priv->rx_queue, skb); - usb_submit_urb(entry, GFP_KERNEL); + + usb_anchor_urb(entry, &priv->submitted); + ret = usb_submit_urb(entry, GFP_KERNEL); + if (ret) { + skb_unlink(skb, &priv->rx_queue); + usb_unanchor_urb(entry); + goto err; + } + usb_free_urb(entry); + entry = NULL; } return 0; -} - -static void p54u_free_urbs(struct ieee80211_hw *dev) -{ - struct p54u_priv *priv = dev->priv; - struct p54u_rx_info *info; - struct sk_buff *skb; - while ((skb = skb_dequeue(&priv->rx_queue))) { - info = (struct p54u_rx_info *) skb->cb; - if (!info->urb) - continue; - - usb_kill_urb(info->urb); - kfree_skb(skb); - } + err: + usb_free_urb(entry); + kfree_skb(skb); + p54u_free_urbs(dev); + return ret; } -static void p54u_tx_3887(struct ieee80211_hw *dev, struct p54_control_hdr *data, - size_t len, int free_on_tx) +static void p54u_tx_3887(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54u_priv *priv = dev->priv; struct urb *addr_urb, *data_urb; + int err = 0; addr_urb = usb_alloc_urb(0, GFP_ATOMIC); if (!addr_urb) @@ -209,59 +224,85 @@ static void p54u_tx_3887(struct ieee80211_hw *dev, struct p54_control_hdr *data, } usb_fill_bulk_urb(addr_urb, priv->udev, - usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), &data->req_id, - sizeof(data->req_id), p54u_tx_cb, dev); + usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), + &((struct p54_hdr *)skb->data)->req_id, 4, + p54u_tx_dummy_cb, dev); usb_fill_bulk_urb(data_urb, priv->udev, - usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), data, len, - free_on_tx ? p54u_tx_free_cb : p54u_tx_cb, dev); + usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), + skb->data, skb->len, p54u_tx_cb, skb); + + usb_anchor_urb(addr_urb, &priv->submitted); + err = usb_submit_urb(addr_urb, GFP_ATOMIC); + if (err) { + usb_unanchor_urb(addr_urb); + goto out; + } - usb_submit_urb(addr_urb, GFP_ATOMIC); - usb_submit_urb(data_urb, GFP_ATOMIC); + usb_anchor_urb(addr_urb, &priv->submitted); + err = usb_submit_urb(data_urb, GFP_ATOMIC); + if (err) + usb_unanchor_urb(data_urb); + + out: + usb_free_urb(addr_urb); + usb_free_urb(data_urb); + + if (err) + p54_free_skb(dev, skb); } -static __le32 p54u_lm87_chksum(const u32 *data, size_t length) +static __le32 p54u_lm87_chksum(const __le32 *data, size_t length) { u32 chk = 0; length >>= 2; while (length--) { - chk ^= *data++; + chk ^= le32_to_cpu(*data++); chk = (chk >> 5) ^ (chk << 3); } return cpu_to_le32(chk); } -static void p54u_tx_lm87(struct ieee80211_hw *dev, - struct p54_control_hdr *data, - size_t len, int free_on_tx) +static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54u_priv *priv = dev->priv; struct urb *data_urb; - struct lm87_tx_hdr *hdr = (void *)data - sizeof(*hdr); + struct lm87_tx_hdr *hdr; + __le32 checksum; + __le32 addr = ((struct p54_hdr *)skb->data)->req_id; data_urb = usb_alloc_urb(0, GFP_ATOMIC); if (!data_urb) return; - hdr->chksum = p54u_lm87_chksum((u32 *)data, len); - hdr->device_addr = data->req_id; + checksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len); + hdr = (struct lm87_tx_hdr *)skb_push(skb, sizeof(*hdr)); + hdr->chksum = checksum; + hdr->device_addr = addr; usb_fill_bulk_urb(data_urb, priv->udev, - usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), hdr, - len + sizeof(*hdr), free_on_tx ? p54u_tx_free_cb : p54u_tx_cb, - dev); - - usb_submit_urb(data_urb, GFP_ATOMIC); + usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), + skb->data, skb->len, p54u_tx_cb, skb); + + usb_anchor_urb(data_urb, &priv->submitted); + if (usb_submit_urb(data_urb, GFP_ATOMIC)) { + usb_unanchor_urb(data_urb); + skb_pull(skb, sizeof(*hdr)); + p54_free_skb(dev, skb); + } + usb_free_urb(data_urb); } -static void p54u_tx_net2280(struct ieee80211_hw *dev, struct p54_control_hdr *data, - size_t len, int free_on_tx) +static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54u_priv *priv = dev->priv; struct urb *int_urb, *data_urb; struct net2280_tx_hdr *hdr; struct net2280_reg_write *reg; + int err = 0; + __le32 addr = ((struct p54_hdr *) skb->data)->req_id; + __le16 len = cpu_to_le16(skb->len); reg = kmalloc(sizeof(*reg), GFP_ATOMIC); if (!reg) @@ -284,21 +325,47 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct p54_control_hdr *da reg->addr = cpu_to_le32(P54U_DEV_BASE); reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA); - len += sizeof(*data); - hdr = (void *)data - sizeof(*hdr); + hdr = (void *)skb_push(skb, sizeof(*hdr)); memset(hdr, 0, sizeof(*hdr)); - hdr->device_addr = data->req_id; - hdr->len = cpu_to_le16(len); + hdr->len = len; + hdr->device_addr = addr; usb_fill_bulk_urb(int_urb, priv->udev, usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg), - p54u_tx_free_cb, dev); - usb_submit_urb(int_urb, GFP_ATOMIC); + p54u_tx_dummy_cb, dev); + + /* + * This flag triggers a code path in the USB subsystem that will + * free what's inside the transfer_buffer after the callback routine + * has completed. + */ + int_urb->transfer_flags |= URB_FREE_BUFFER; usb_fill_bulk_urb(data_urb, priv->udev, - usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), hdr, len + sizeof(*hdr), - free_on_tx ? p54u_tx_free_cb : p54u_tx_cb, dev); - usb_submit_urb(data_urb, GFP_ATOMIC); + usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), + skb->data, skb->len, p54u_tx_cb, skb); + + usb_anchor_urb(int_urb, &priv->submitted); + err = usb_submit_urb(int_urb, GFP_ATOMIC); + if (err) { + usb_unanchor_urb(int_urb); + goto out; + } + + usb_anchor_urb(data_urb, &priv->submitted); + err = usb_submit_urb(data_urb, GFP_ATOMIC); + if (err) { + usb_unanchor_urb(data_urb); + goto out; + } + out: + usb_free_urb(int_urb); + usb_free_urb(data_urb); + + if (err) { + skb_pull(skb, sizeof(*hdr)); + p54_free_skb(dev, skb); + } } static int p54u_write(struct p54u_priv *priv, @@ -375,7 +442,8 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL); if (!buf) { - printk(KERN_ERR "p54usb: cannot allocate firmware upload buffer!\n"); + dev_err(&priv->udev->dev, "(p54usb) cannot allocate firmware" + "upload buffer!\n"); err = -ENOMEM; goto err_bufalloc; } @@ -383,14 +451,18 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) memcpy(buf, start_string, 4); err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 4); if (err) { - printk(KERN_ERR "p54usb: reset failed! (%d)\n", err); + dev_err(&priv->udev->dev, "(p54usb) reset failed! (%d)\n", err); goto err_reset; } - err = request_firmware(&fw_entry, "isl3887usb_bare", &priv->udev->dev); + err = request_firmware(&fw_entry, "isl3887usb", &priv->udev->dev); if (err) { - printk(KERN_ERR "p54usb: cannot find firmware (isl3887usb_bare)!\n"); - goto err_req_fw_failed; + dev_err(&priv->udev->dev, "p54usb: cannot find firmware " + "(isl3887usb)\n"); + err = request_firmware(&fw_entry, "isl3887usb_bare", + &priv->udev->dev); + if (err) + goto err_req_fw_failed; } err = p54_parse_firmware(dev, fw_entry); @@ -441,7 +513,8 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size); if (err) { - printk(KERN_ERR "p54usb: firmware upload failed!\n"); + dev_err(&priv->udev->dev, "(p54usb) firmware " + "upload failed!\n"); goto err_upload_failed; } @@ -452,10 +525,9 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, fw_entry->data, fw_entry->size)); err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32)); if (err) { - printk(KERN_ERR "p54usb: firmware upload failed!\n"); + dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n"); goto err_upload_failed; } - timeout = jiffies + msecs_to_jiffies(1000); while (!(err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) { @@ -463,25 +535,27 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) break; if (alen > 5 && !memcmp(buf, "ERROR", 5)) { - printk(KERN_INFO "p54usb: firmware upload failed!\n"); err = -EINVAL; break; } if (time_after(jiffies, timeout)) { - printk(KERN_ERR "p54usb: firmware boot timed out!\n"); + dev_err(&priv->udev->dev, "(p54usb) firmware boot " + "timed out!\n"); err = -ETIMEDOUT; break; } } - if (err) + if (err) { + dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n"); goto err_upload_failed; + } buf[0] = 'g'; buf[1] = '\r'; err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2); if (err) { - printk(KERN_ERR "p54usb: firmware boot failed!\n"); + dev_err(&priv->udev->dev, "(p54usb) firmware boot failed!\n"); goto err_upload_failed; } @@ -521,15 +595,21 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) buf = kmalloc(512, GFP_KERNEL); if (!buf) { - printk(KERN_ERR "p54usb: firmware buffer alloc failed!\n"); + dev_err(&priv->udev->dev, "(p54usb) firmware buffer " + "alloc failed!\n"); return -ENOMEM; } - err = request_firmware(&fw_entry, "isl3890usb", &priv->udev->dev); + err = request_firmware(&fw_entry, "isl3886usb", &priv->udev->dev); if (err) { - printk(KERN_ERR "p54usb: cannot find firmware (isl3890usb)!\n"); - kfree(buf); - return err; + dev_err(&priv->udev->dev, "(p54usb) cannot find firmware " + "(isl3886usb)\n"); + err = request_firmware(&fw_entry, "isl3890usb", + &priv->udev->dev); + if (err) { + kfree(buf); + return err; + } } err = p54_parse_firmware(dev, fw_entry); @@ -648,8 +728,8 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len); if (err) { - printk(KERN_ERR "p54usb: firmware block upload " - "failed\n"); + dev_err(&priv->udev->dev, "(p54usb) firmware block " + "upload failed\n"); goto fail; } @@ -682,8 +762,8 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) 0x002C | (unsigned long)&devreg->direct_mem_win); if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) || !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) { - printk(KERN_ERR "p54usb: firmware DMA transfer " - "failed\n"); + dev_err(&priv->udev->dev, "(p54usb) firmware DMA " + "transfer failed\n"); goto fail; } @@ -786,11 +866,11 @@ static int __devinit p54u_probe(struct usb_interface *intf, struct p54u_priv *priv; int err; unsigned int i, recognized_pipes; - DECLARE_MAC_BUF(mac); dev = p54_init_common(sizeof(*priv)); + if (!dev) { - printk(KERN_ERR "p54usb: ieee80211 alloc failed\n"); + dev_err(&udev->dev, "(p54usb) ieee80211 alloc failed\n"); return -ENOMEM; } @@ -842,6 +922,7 @@ static int __devinit p54u_probe(struct usb_interface *intf, goto err_free_dev; skb_queue_head_init(&priv->rx_queue); + init_usb_anchor(&priv->submitted); p54u_open(dev); err = p54_read_eeprom(dev); @@ -851,7 +932,7 @@ static int __devinit p54u_probe(struct usb_interface *intf, err = ieee80211_register_hw(dev); if (err) { - printk(KERN_ERR "p54usb: Cannot register netdevice\n"); + dev_err(&udev->dev, "(p54usb) Cannot register netdevice\n"); goto err_free_dev; } diff --git a/drivers/net/wireless/p54/p54usb.h b/drivers/net/wireless/p54/p54usb.h index 5b8fe91379c36e947ad3ff23bc8b2bfddaf512c5..54ee738bf2af66c8503ea549d21ff1797b0de4b7 100644 --- a/drivers/net/wireless/p54/p54usb.h +++ b/drivers/net/wireless/p54/p54usb.h @@ -133,6 +133,7 @@ struct p54u_priv { spinlock_t lock; struct sk_buff_head rx_queue; + struct usb_anchor submitted; }; #endif /* P54USB_H */ diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c index 16e68f4b654a94370433cd928c23405f4a5be950..57a150a22de5c6544bee00f7799e5b2caf9164e6 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.c +++ b/drivers/net/wireless/prism54/isl_ioctl.c @@ -2028,12 +2028,11 @@ static void format_event(islpci_private *priv, char *dest, const char *str, const struct obj_mlme *mlme, u16 *length, int error) { - DECLARE_MAC_BUF(mac); int n = snprintf(dest, IW_CUSTOM_MAX, - "%s %s %s %s (%2.2X)", + "%s %s %pM %s (%2.2X)", str, ((priv->iw_mode == IW_MODE_MASTER) ? "from" : "to"), - print_mac(mac, mlme->address), + mlme->address, (error ? (mlme->code ? " : REJECTED " : " : ACCEPTED ") : ""), mlme->code); BUG_ON(n > IW_CUSTOM_MAX); @@ -2113,7 +2112,6 @@ prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid, { struct list_head *ptr; struct islpci_bss_wpa_ie *bss = NULL; - DECLARE_MAC_BUF(mac); if (wpa_ie_len > MAX_WPA_IE_LEN) wpa_ie_len = MAX_WPA_IE_LEN; @@ -2154,7 +2152,7 @@ prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid, bss->last_update = jiffies; } else { printk(KERN_DEBUG "Failed to add BSS WPA entry for " - "%s\n", print_mac(mac, bssid)); + "%pM\n", bssid); } /* expire old entries from WPA list */ @@ -2219,7 +2217,6 @@ prism54_process_bss_data(islpci_private *priv, u32 oid, u8 *addr, { struct ieee80211_beacon_phdr *hdr; u8 *pos, *end; - DECLARE_MAC_BUF(mac); if (!priv->wpa) return; @@ -2230,7 +2227,7 @@ prism54_process_bss_data(islpci_private *priv, u32 oid, u8 *addr, while (pos < end) { if (pos + 2 + pos[1] > end) { printk(KERN_DEBUG "Parsing Beacon/ProbeResp failed " - "for %s\n", print_mac(mac, addr)); + "for %pM\n", addr); return; } if (pos[0] == WLAN_EID_GENERIC && pos[1] >= 4 && @@ -2269,7 +2266,6 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid, size_t len = 0; /* u16, better? */ u8 *payload = NULL, *pos = NULL; int ret; - DECLARE_MAC_BUF(mac); /* I think all trapable objects are listed here. * Some oids have a EX version. The difference is that they are emitted @@ -2358,8 +2354,8 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid, break; memcpy(&confirm->address, mlmeex->address, ETH_ALEN); - printk(KERN_DEBUG "Authenticate from: address:\t%s\n", - print_mac(mac, mlmeex->address)); + printk(KERN_DEBUG "Authenticate from: address:\t%pM\n", + mlmeex->address); confirm->id = -1; /* or mlmeex->id ? */ confirm->state = 0; /* not used */ confirm->code = 0; @@ -2404,8 +2400,8 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid, wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie); if (!wpa_ie_len) { - printk(KERN_DEBUG "No WPA IE found from address:\t%s\n", - print_mac(mac, mlmeex->address)); + printk(KERN_DEBUG "No WPA IE found from address:\t%pM\n", + mlmeex->address); kfree(confirm); break; } @@ -2441,8 +2437,8 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid, wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie); if (!wpa_ie_len) { - printk(KERN_DEBUG "No WPA IE found from address:\t%s\n", - print_mac(mac, mlmeex->address)); + printk(KERN_DEBUG "No WPA IE found from address:\t%pM\n", + mlmeex->address); kfree(confirm); break; } diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c index af2e4f2405f2577ae0f047d37827c6eb532054f8..9a72b1e3e163bb597a075a11c65e9a66a3958312 100644 --- a/drivers/net/wireless/prism54/islpci_hotplug.c +++ b/drivers/net/wireless/prism54/islpci_hotplug.c @@ -93,7 +93,7 @@ static struct pci_driver prism54_driver = { Module initialization functions ******************************************************************************/ -int +static int prism54_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct net_device *ndev; @@ -216,7 +216,7 @@ prism54_probe(struct pci_dev *pdev, const struct pci_device_id *id) static volatile int __in_cleanup_module = 0; /* this one removes one(!!) instance only */ -void +static void prism54_remove(struct pci_dev *pdev) { struct net_device *ndev = pci_get_drvdata(pdev); @@ -259,7 +259,7 @@ prism54_remove(struct pci_dev *pdev) pci_disable_device(pdev); } -int +static int prism54_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *ndev = pci_get_drvdata(pdev); @@ -282,7 +282,7 @@ prism54_suspend(struct pci_dev *pdev, pm_message_t state) return 0; } -int +static int prism54_resume(struct pci_dev *pdev) { struct net_device *ndev = pci_get_drvdata(pdev); diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 1404a57175207f71d39ac28b12ad78651610d0c1..99ec7d62251813e95caf0c72bac8c1c0439fe3fe 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -414,7 +414,6 @@ static int ray_config(struct pcmcia_device *link) memreq_t mem; struct net_device *dev = (struct net_device *)link->priv; ray_dev_t *local = netdev_priv(dev); - DECLARE_MAC_BUF(mac); DEBUG(1, "ray_config(0x%p)\n", link); @@ -485,8 +484,8 @@ static int ray_config(struct pcmcia_device *link) strcpy(local->node.dev_name, dev->name); link->dev_node = &local->node; - printk(KERN_INFO "%s: RayLink, irq %d, hw_addr %s\n", - dev->name, dev->irq, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: RayLink, irq %d, hw_addr %pM\n", + dev->name, dev->irq, dev->dev_addr); return 0; @@ -829,7 +828,7 @@ static int ray_resume(struct pcmcia_device *link) } /*===========================================================================*/ -int ray_dev_init(struct net_device *dev) +static int ray_dev_init(struct net_device *dev) { #ifdef RAY_IMMEDIATE_INIT int i; @@ -2285,7 +2284,6 @@ static void rx_data(struct net_device *dev, struct rcs __iomem *prcs, unsigned i skb->protocol = eth_type_trans(skb,dev); netif_rx(skb); - dev->last_rx = jiffies; local->stats.rx_packets++; local->stats.rx_bytes += total_len; @@ -2595,7 +2593,6 @@ static int ray_cs_proc_show(struct seq_file *m, void *v) UCHAR *p; struct freq_hop_element *pfh; UCHAR c[33]; - DECLARE_MAC_BUF(mac); link = this_device; if (!link) @@ -2623,8 +2620,7 @@ static int ray_cs_proc_show(struct seq_file *m, void *v) nettype[local->sparm.b5.a_network_type], c); p = local->bss_id; - seq_printf(m, "BSSID = %s\n", - print_mac(mac, p)); + seq_printf(m, "BSSID = %pM\n", p); seq_printf(m, "Country code = %d\n", local->sparm.b5.a_curr_country_code); diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 2b414899dfa08107f8c2faba4be42e0aa2ffde79..607ce9f61b5400fa0e43d0bd675bfd0674dec406 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -37,11 +37,11 @@ #include #include #include +#include #include #include #include #include -#include #include #include @@ -1104,7 +1104,7 @@ static int rndis_iw_get_range(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct iw_range *range = (struct iw_range *)extra; - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); int len, ret, i, j, num, has_80211g_rates; u8 rates[8]; @@ -1210,7 +1210,7 @@ static int rndis_iw_get_range(struct net_device *dev, static int rndis_iw_get_name(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); strcpy(wrqu->name, priv->name); @@ -1223,7 +1223,7 @@ static int rndis_iw_set_essid(struct net_device *dev, { struct ndis_80211_ssid ssid; int length = wrqu->essid.length; - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); devdbg(usbdev, "SIOCSIWESSID: [flags:%d,len:%d] '%.32s'", wrqu->essid.flags, wrqu->essid.length, essid); @@ -1250,7 +1250,7 @@ static int rndis_iw_get_essid(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *essid) { struct ndis_80211_ssid ssid; - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); int ret; ret = get_essid(usbdev, &ssid); @@ -1273,15 +1273,14 @@ static int rndis_iw_get_essid(struct net_device *dev, static int rndis_iw_get_bssid(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); unsigned char bssid[ETH_ALEN]; int ret; - DECLARE_MAC_BUF(mac); ret = get_bssid(usbdev, bssid); if (ret == 0) - devdbg(usbdev, "SIOCGIWAP: %s", print_mac(mac, bssid)); + devdbg(usbdev, "SIOCGIWAP: %pM", bssid); else devdbg(usbdev, "SIOCGIWAP: "); @@ -1295,12 +1294,11 @@ static int rndis_iw_get_bssid(struct net_device *dev, static int rndis_iw_set_bssid(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); u8 *bssid = (u8 *)wrqu->ap_addr.sa_data; - DECLARE_MAC_BUF(mac); int ret; - devdbg(usbdev, "SIOCSIWAP: %s", print_mac(mac, bssid)); + devdbg(usbdev, "SIOCSIWAP: %pM", bssid); ret = rndis_set_oid(usbdev, OID_802_11_BSSID, bssid, ETH_ALEN); @@ -1318,7 +1316,7 @@ static int rndis_iw_set_auth(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct iw_param *p = &wrqu->param; - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); int ret = -ENOTSUPP; @@ -1399,7 +1397,7 @@ static int rndis_iw_get_auth(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct iw_param *p = &wrqu->param; - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); switch (p->flags & IW_AUTH_INDEX) { @@ -1431,7 +1429,7 @@ static int rndis_iw_get_mode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); switch (priv->infra_mode) { @@ -1454,7 +1452,7 @@ static int rndis_iw_get_mode(struct net_device *dev, static int rndis_iw_set_mode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); int mode; devdbg(usbdev, "SIOCSIWMODE: %08x", wrqu->mode); @@ -1479,7 +1477,7 @@ static int rndis_iw_set_mode(struct net_device *dev, static int rndis_iw_set_encode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); int ret, index, key_len; u8 *key; @@ -1542,7 +1540,7 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); struct ndis_80211_key ndis_key; int keyidx, ret; @@ -1627,7 +1625,7 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, static int rndis_iw_set_scan(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); union iwreq_data evt; int ret = -EINVAL; __le32 tmp; @@ -1652,19 +1650,18 @@ static char *rndis_translate_scan(struct net_device *dev, struct ndis_80211_bssid_ex *bssid) { #ifdef DEBUG - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); #endif - struct ieee80211_info_element *ie; + u8 *ie; char *current_val; int bssid_len, ie_len, i; u32 beacon, atim; struct iw_event iwe; unsigned char sbuf[32]; - DECLARE_MAC_BUF(mac); bssid_len = le32_to_cpu(bssid->length); - devdbg(usbdev, "BSSID %s", print_mac(mac, bssid->mac)); + devdbg(usbdev, "BSSID %pM", bssid->mac); iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; memcpy(iwe.u.ap_addr.sa_data, bssid->mac, ETH_ALEN); @@ -1753,20 +1750,20 @@ static char *rndis_translate_scan(struct net_device *dev, ie_len = min(bssid_len - (int)sizeof(*bssid), (int)le32_to_cpu(bssid->ie_length)); ie_len -= sizeof(struct ndis_80211_fixed_ies); - while (ie_len >= sizeof(*ie) && sizeof(*ie) + ie->len <= ie_len) { - if ((ie->id == MFIE_TYPE_GENERIC && ie->len >= 4 && - memcmp(ie->data, "\x00\x50\xf2\x01", 4) == 0) || - ie->id == MFIE_TYPE_RSN) { + while (ie_len >= 2 && 2 + ie[1] <= ie_len) { + if ((ie[0] == WLAN_EID_GENERIC && ie[1] >= 4 && + memcmp(ie + 2, "\x00\x50\xf2\x01", 4) == 0) || + ie[0] == WLAN_EID_RSN) { devdbg(usbdev, "IE: WPA%d", - (ie->id == MFIE_TYPE_RSN) ? 2 : 1); + (ie[0] == WLAN_EID_RSN) ? 2 : 1); iwe.cmd = IWEVGENIE; - iwe.u.data.length = min(ie->len + 2, MAX_WPA_IE_LEN); - cev = iwe_stream_add_point(info, cev, end_buf, &iwe, - (u8 *)ie); + /* arbitrary cut-off at 64 */ + iwe.u.data.length = min(ie[1] + 2, 64); + cev = iwe_stream_add_point(info, cev, end_buf, &iwe, ie); } - ie_len -= sizeof(*ie) + ie->len; - ie = (struct ieee80211_info_element *)&ie->data[ie->len]; + ie_len -= 2 + ie[1]; + ie += 2 + ie[1]; } return cev; @@ -1776,7 +1773,7 @@ static char *rndis_translate_scan(struct net_device *dev, static int rndis_iw_get_scan(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); void *buf = NULL; char *cev = extra; struct ndis_80211_bssid_list_ex *bssid_list; @@ -1822,7 +1819,7 @@ static int rndis_iw_get_scan(struct net_device *dev, static int rndis_iw_set_genie(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); int ret = 0; @@ -1856,7 +1853,7 @@ static int rndis_iw_set_genie(struct net_device *dev, static int rndis_iw_get_genie(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); devdbg(usbdev, "SIOCGIWGENIE"); @@ -1879,7 +1876,7 @@ static int rndis_iw_get_genie(struct net_device *dev, static int rndis_iw_set_rts(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); __le32 tmp; devdbg(usbdev, "SIOCSIWRTS"); @@ -1892,7 +1889,7 @@ static int rndis_iw_set_rts(struct net_device *dev, static int rndis_iw_get_rts(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); __le32 tmp; int len, ret; @@ -1913,7 +1910,7 @@ static int rndis_iw_get_rts(struct net_device *dev, static int rndis_iw_set_frag(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); __le32 tmp; devdbg(usbdev, "SIOCSIWFRAG"); @@ -1927,7 +1924,7 @@ static int rndis_iw_set_frag(struct net_device *dev, static int rndis_iw_get_frag(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); __le32 tmp; int len, ret; @@ -1947,7 +1944,7 @@ static int rndis_iw_get_frag(struct net_device *dev, static int rndis_iw_set_nick(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); devdbg(usbdev, "SIOCSIWNICK"); @@ -1964,7 +1961,7 @@ static int rndis_iw_set_nick(struct net_device *dev, static int rndis_iw_get_nick(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); wrqu->data.flags = 1; @@ -1980,7 +1977,7 @@ static int rndis_iw_get_nick(struct net_device *dev, static int rndis_iw_set_freq(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct ndis_80211_conf config; unsigned int dsconfig; int len, ret; @@ -2011,7 +2008,7 @@ static int rndis_iw_set_freq(struct net_device *dev, static int rndis_iw_get_freq(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct ndis_80211_conf config; int len, ret; @@ -2028,7 +2025,7 @@ static int rndis_iw_get_freq(struct net_device *dev, static int rndis_iw_get_txpower(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); __le32 tx_power; int ret = 0, len; @@ -2062,7 +2059,7 @@ static int rndis_iw_get_txpower(struct net_device *dev, static int rndis_iw_set_txpower(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); __le32 tx_power = 0; int ret = 0; @@ -2114,7 +2111,7 @@ static int rndis_iw_set_txpower(struct net_device *dev, static int rndis_iw_get_rate(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); __le32 tmp; int ret, len; @@ -2132,7 +2129,7 @@ static int rndis_iw_get_rate(struct net_device *dev, static int rndis_iw_set_mlme(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); struct iw_mlme *mlme = (struct iw_mlme *)extra; unsigned char bssid[ETH_ALEN]; @@ -2157,7 +2154,7 @@ static int rndis_iw_set_mlme(struct net_device *dev, static struct iw_statistics *rndis_get_wireless_stats(struct net_device *dev) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); unsigned long flags; @@ -2287,7 +2284,7 @@ static void rndis_wext_worker(struct work_struct *work) static void rndis_wext_set_multicast_list(struct net_device *dev) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); if (test_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending)) diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index 95511ac2247054de571fa2aeb896ba10936681eb..178b313293b4537a45d3f00f7e6a9b6078802439 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -57,6 +57,7 @@ config RT2500USB tristate "Ralink rt2500 (USB) support" depends on USB select RT2X00_LIB_USB + select RT2X00_LIB_CRYPTO ---help--- This adds support for rt2500 wireless chipset family. Supported chips: RT2571 & RT2572. diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 08cb9eec16a6bca16c3e5dc30c467db1e600a3af..6a977679124d549a954eb78a27b89b9cf7c304c3 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -49,45 +49,33 @@ * the access attempt is considered to have failed, * and we will print an error. */ -static u32 rt2400pci_bbp_check(struct rt2x00_dev *rt2x00dev) -{ - u32 reg; - unsigned int i; - - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00pci_register_read(rt2x00dev, BBPCSR, ®); - if (!rt2x00_get_field32(reg, BBPCSR_BUSY)) - break; - udelay(REGISTER_BUSY_DELAY); - } - - return reg; -} +#define WAIT_FOR_BBP(__dev, __reg) \ + rt2x00pci_regbusy_read((__dev), BBPCSR, BBPCSR_BUSY, (__reg)) +#define WAIT_FOR_RF(__dev, __reg) \ + rt2x00pci_regbusy_read((__dev), RFCSR, RFCSR_BUSY, (__reg)) static void rt2400pci_bbp_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u8 value) { u32 reg; - /* - * Wait until the BBP becomes ready. - */ - reg = rt2400pci_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, BBPCSR_BUSY)) { - ERROR(rt2x00dev, "BBPCSR register busy. Write failed.\n"); - return; - } + mutex_lock(&rt2x00dev->csr_mutex); /* - * Write the data into the BBP. + * Wait until the BBP becomes available, afterwards we + * can safely write the new data into the register. */ - reg = 0; - rt2x00_set_field32(®, BBPCSR_VALUE, value); - rt2x00_set_field32(®, BBPCSR_REGNUM, word); - rt2x00_set_field32(®, BBPCSR_BUSY, 1); - rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 1); + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, BBPCSR_VALUE, value); + rt2x00_set_field32(®, BBPCSR_REGNUM, word); + rt2x00_set_field32(®, BBPCSR_BUSY, 1); + rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 1); + + rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); + } - rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); + mutex_unlock(&rt2x00dev->csr_mutex); } static void rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev, @@ -95,66 +83,58 @@ static void rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev, { u32 reg; - /* - * Wait until the BBP becomes ready. - */ - reg = rt2400pci_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, BBPCSR_BUSY)) { - ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n"); - return; - } + mutex_lock(&rt2x00dev->csr_mutex); /* - * Write the request into the BBP. + * Wait until the BBP becomes available, afterwards we + * can safely write the read request into the register. + * After the data has been written, we wait until hardware + * returns the correct value, if at any time the register + * doesn't become available in time, reg will be 0xffffffff + * which means we return 0xff to the caller. */ - reg = 0; - rt2x00_set_field32(®, BBPCSR_REGNUM, word); - rt2x00_set_field32(®, BBPCSR_BUSY, 1); - rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 0); + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, BBPCSR_REGNUM, word); + rt2x00_set_field32(®, BBPCSR_BUSY, 1); + rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 0); - rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); + rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); - /* - * Wait until the BBP becomes ready. - */ - reg = rt2400pci_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, BBPCSR_BUSY)) { - ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n"); - *value = 0xff; - return; + WAIT_FOR_BBP(rt2x00dev, ®); } *value = rt2x00_get_field32(reg, BBPCSR_VALUE); + + mutex_unlock(&rt2x00dev->csr_mutex); } static void rt2400pci_rf_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u32 value) { u32 reg; - unsigned int i; if (!word) return; - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00pci_register_read(rt2x00dev, RFCSR, ®); - if (!rt2x00_get_field32(reg, RFCSR_BUSY)) - goto rf_write; - udelay(REGISTER_BUSY_DELAY); - } - - ERROR(rt2x00dev, "RFCSR register busy. Write failed.\n"); - return; + mutex_lock(&rt2x00dev->csr_mutex); -rf_write: - reg = 0; - rt2x00_set_field32(®, RFCSR_VALUE, value); - rt2x00_set_field32(®, RFCSR_NUMBER_OF_BITS, 20); - rt2x00_set_field32(®, RFCSR_IF_SELECT, 0); - rt2x00_set_field32(®, RFCSR_BUSY, 1); + /* + * Wait until the RF becomes available, afterwards we + * can safely write the new data into the register. + */ + if (WAIT_FOR_RF(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, RFCSR_VALUE, value); + rt2x00_set_field32(®, RFCSR_NUMBER_OF_BITS, 20); + rt2x00_set_field32(®, RFCSR_IF_SELECT, 0); + rt2x00_set_field32(®, RFCSR_BUSY, 1); + + rt2x00pci_register_write(rt2x00dev, RFCSR, reg); + rt2x00_rf_write(rt2x00dev, word, value); + } - rt2x00pci_register_write(rt2x00dev, RFCSR, reg); - rt2x00_rf_write(rt2x00dev, word, value); + mutex_unlock(&rt2x00dev->csr_mutex); } static void rt2400pci_eepromregister_read(struct eeprom_93cx6 *eeprom) @@ -188,43 +168,34 @@ static void rt2400pci_eepromregister_write(struct eeprom_93cx6 *eeprom) } #ifdef CONFIG_RT2X00_LIB_DEBUGFS -#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u32)) ) - -static void rt2400pci_read_csr(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u32 *data) -{ - rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data); -} - -static void rt2400pci_write_csr(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u32 data) -{ - rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data); -} - static const struct rt2x00debug rt2400pci_rt2x00debug = { .owner = THIS_MODULE, .csr = { - .read = rt2400pci_read_csr, - .write = rt2400pci_write_csr, + .read = rt2x00pci_register_read, + .write = rt2x00pci_register_write, + .flags = RT2X00DEBUGFS_OFFSET, + .word_base = CSR_REG_BASE, .word_size = sizeof(u32), .word_count = CSR_REG_SIZE / sizeof(u32), }, .eeprom = { .read = rt2x00_eeprom_read, .write = rt2x00_eeprom_write, + .word_base = EEPROM_BASE, .word_size = sizeof(u16), .word_count = EEPROM_SIZE / sizeof(u16), }, .bbp = { .read = rt2400pci_bbp_read, .write = rt2400pci_bbp_write, + .word_base = BBP_BASE, .word_size = sizeof(u8), .word_count = BBP_SIZE / sizeof(u8), }, .rf = { .read = rt2x00_rf_read, .write = rt2400pci_rf_write, + .word_base = RF_BASE, .word_size = sizeof(u32), .word_count = RF_SIZE / sizeof(u32), }, @@ -331,7 +302,7 @@ static void rt2400pci_config_intf(struct rt2x00_dev *rt2x00dev, /* * Enable beacon config */ - bcn_preload = PREAMBLE + get_duration(IEEE80211_HEADER, 20); + bcn_preload = PREAMBLE + GET_DURATION(IEEE80211_HEADER, 20); rt2x00pci_register_read(rt2x00dev, BCNCSR1, ®); rt2x00_set_field32(®, BCNCSR1_PRELOAD, bcn_preload); rt2x00pci_register_write(rt2x00dev, BCNCSR1, reg); @@ -376,32 +347,94 @@ static void rt2400pci_config_erp(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_read(rt2x00dev, ARCSR2, ®); rt2x00_set_field32(®, ARCSR2_SIGNAL, 0x00); rt2x00_set_field32(®, ARCSR2_SERVICE, 0x04); - rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 10)); + rt2x00_set_field32(®, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 10)); rt2x00pci_register_write(rt2x00dev, ARCSR2, reg); rt2x00pci_register_read(rt2x00dev, ARCSR3, ®); rt2x00_set_field32(®, ARCSR3_SIGNAL, 0x01 | preamble_mask); rt2x00_set_field32(®, ARCSR3_SERVICE, 0x04); - rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 20)); + rt2x00_set_field32(®, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 20)); rt2x00pci_register_write(rt2x00dev, ARCSR3, reg); rt2x00pci_register_read(rt2x00dev, ARCSR4, ®); rt2x00_set_field32(®, ARCSR4_SIGNAL, 0x02 | preamble_mask); rt2x00_set_field32(®, ARCSR4_SERVICE, 0x04); - rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 55)); + rt2x00_set_field32(®, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 55)); rt2x00pci_register_write(rt2x00dev, ARCSR4, reg); rt2x00pci_register_read(rt2x00dev, ARCSR5, ®); rt2x00_set_field32(®, ARCSR5_SIGNAL, 0x03 | preamble_mask); rt2x00_set_field32(®, ARCSR5_SERVICE, 0x84); - rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110)); + rt2x00_set_field32(®, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 110)); rt2x00pci_register_write(rt2x00dev, ARCSR5, reg); + + rt2x00pci_register_write(rt2x00dev, ARCSR1, erp->basic_rates); + + rt2x00pci_register_read(rt2x00dev, CSR11, ®); + rt2x00_set_field32(®, CSR11_SLOT_TIME, erp->slot_time); + rt2x00pci_register_write(rt2x00dev, CSR11, reg); + + rt2x00pci_register_read(rt2x00dev, CSR18, ®); + rt2x00_set_field32(®, CSR18_SIFS, erp->sifs); + rt2x00_set_field32(®, CSR18_PIFS, erp->pifs); + rt2x00pci_register_write(rt2x00dev, CSR18, reg); + + rt2x00pci_register_read(rt2x00dev, CSR19, ®); + rt2x00_set_field32(®, CSR19_DIFS, erp->difs); + rt2x00_set_field32(®, CSR19_EIFS, erp->eifs); + rt2x00pci_register_write(rt2x00dev, CSR19, reg); } -static void rt2400pci_config_phymode(struct rt2x00_dev *rt2x00dev, - const int basic_rate_mask) +static void rt2400pci_config_ant(struct rt2x00_dev *rt2x00dev, + struct antenna_setup *ant) { - rt2x00pci_register_write(rt2x00dev, ARCSR1, basic_rate_mask); + u8 r1; + u8 r4; + + /* + * We should never come here because rt2x00lib is supposed + * to catch this and send us the correct antenna explicitely. + */ + BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY || + ant->tx == ANTENNA_SW_DIVERSITY); + + rt2400pci_bbp_read(rt2x00dev, 4, &r4); + rt2400pci_bbp_read(rt2x00dev, 1, &r1); + + /* + * Configure the TX antenna. + */ + switch (ant->tx) { + case ANTENNA_HW_DIVERSITY: + rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 1); + break; + case ANTENNA_A: + rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 0); + break; + case ANTENNA_B: + default: + rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 2); + break; + } + + /* + * Configure the RX antenna. + */ + switch (ant->rx) { + case ANTENNA_HW_DIVERSITY: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); + break; + case ANTENNA_A: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 0); + break; + case ANTENNA_B: + default: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2); + break; + } + + rt2400pci_bbp_write(rt2x00dev, 4, r4); + rt2400pci_bbp_write(rt2x00dev, 1, r1); } static void rt2400pci_config_channel(struct rt2x00_dev *rt2x00dev, @@ -460,56 +493,17 @@ static void rt2400pci_config_txpower(struct rt2x00_dev *rt2x00dev, int txpower) rt2400pci_bbp_write(rt2x00dev, 3, TXPOWER_TO_DEV(txpower)); } -static void rt2400pci_config_antenna(struct rt2x00_dev *rt2x00dev, - struct antenna_setup *ant) +static void rt2400pci_config_retry_limit(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf) { - u8 r1; - u8 r4; - - /* - * We should never come here because rt2x00lib is supposed - * to catch this and send us the correct antenna explicitely. - */ - BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY || - ant->tx == ANTENNA_SW_DIVERSITY); - - rt2400pci_bbp_read(rt2x00dev, 4, &r4); - rt2400pci_bbp_read(rt2x00dev, 1, &r1); - - /* - * Configure the TX antenna. - */ - switch (ant->tx) { - case ANTENNA_HW_DIVERSITY: - rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 1); - break; - case ANTENNA_A: - rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 0); - break; - case ANTENNA_B: - default: - rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 2); - break; - } - - /* - * Configure the RX antenna. - */ - switch (ant->rx) { - case ANTENNA_HW_DIVERSITY: - rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); - break; - case ANTENNA_A: - rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 0); - break; - case ANTENNA_B: - default: - rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2); - break; - } + u32 reg; - rt2400pci_bbp_write(rt2x00dev, 4, r4); - rt2400pci_bbp_write(rt2x00dev, 1, r1); + rt2x00pci_register_read(rt2x00dev, CSR11, ®); + rt2x00_set_field32(®, CSR11_LONG_RETRY, + libconf->conf->long_frame_max_tx_count); + rt2x00_set_field32(®, CSR11_SHORT_RETRY, + libconf->conf->short_frame_max_tx_count); + rt2x00pci_register_write(rt2x00dev, CSR11, reg); } static void rt2400pci_config_duration(struct rt2x00_dev *rt2x00dev, @@ -517,20 +511,6 @@ static void rt2400pci_config_duration(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt2x00pci_register_read(rt2x00dev, CSR11, ®); - rt2x00_set_field32(®, CSR11_SLOT_TIME, libconf->slot_time); - rt2x00pci_register_write(rt2x00dev, CSR11, reg); - - rt2x00pci_register_read(rt2x00dev, CSR18, ®); - rt2x00_set_field32(®, CSR18_SIFS, libconf->sifs); - rt2x00_set_field32(®, CSR18_PIFS, libconf->pifs); - rt2x00pci_register_write(rt2x00dev, CSR18, reg); - - rt2x00pci_register_read(rt2x00dev, CSR19, ®); - rt2x00_set_field32(®, CSR19_DIFS, libconf->difs); - rt2x00_set_field32(®, CSR19_EIFS, libconf->eifs); - rt2x00pci_register_write(rt2x00dev, CSR19, reg); - rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); rt2x00_set_field32(®, TXCSR1_TSF_OFFSET, IEEE80211_HEADER); rt2x00_set_field32(®, TXCSR1_AUTORESPONDER, 1); @@ -548,16 +528,14 @@ static void rt2400pci_config(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf, const unsigned int flags) { - if (flags & CONFIG_UPDATE_PHYMODE) - rt2400pci_config_phymode(rt2x00dev, libconf->basic_rates); - if (flags & CONFIG_UPDATE_CHANNEL) + if (flags & IEEE80211_CONF_CHANGE_CHANNEL) rt2400pci_config_channel(rt2x00dev, &libconf->rf); - if (flags & CONFIG_UPDATE_TXPOWER) + if (flags & IEEE80211_CONF_CHANGE_POWER) rt2400pci_config_txpower(rt2x00dev, libconf->conf->power_level); - if (flags & CONFIG_UPDATE_ANTENNA) - rt2400pci_config_antenna(rt2x00dev, &libconf->ant); - if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) + if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) + rt2400pci_config_retry_limit(rt2x00dev, libconf); + if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) rt2400pci_config_duration(rt2x00dev, libconf); } @@ -628,36 +606,47 @@ static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev) /* * Initialization functions. */ -static void rt2400pci_init_rxentry(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry) +static bool rt2400pci_get_entry_state(struct queue_entry *entry) { struct queue_entry_priv_pci *entry_priv = entry->priv_data; - struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); u32 word; - rt2x00_desc_read(entry_priv->desc, 2, &word); - rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH, entry->skb->len); - rt2x00_desc_write(entry_priv->desc, 2, word); + if (entry->queue->qid == QID_RX) { + rt2x00_desc_read(entry_priv->desc, 0, &word); - rt2x00_desc_read(entry_priv->desc, 1, &word); - rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma); - rt2x00_desc_write(entry_priv->desc, 1, word); + return rt2x00_get_field32(word, RXD_W0_OWNER_NIC); + } else { + rt2x00_desc_read(entry_priv->desc, 0, &word); - rt2x00_desc_read(entry_priv->desc, 0, &word); - rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); - rt2x00_desc_write(entry_priv->desc, 0, word); + return (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || + rt2x00_get_field32(word, TXD_W0_VALID)); + } } -static void rt2400pci_init_txentry(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry) +static void rt2400pci_clear_entry(struct queue_entry *entry) { struct queue_entry_priv_pci *entry_priv = entry->priv_data; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); u32 word; - rt2x00_desc_read(entry_priv->desc, 0, &word); - rt2x00_set_field32(&word, TXD_W0_VALID, 0); - rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); - rt2x00_desc_write(entry_priv->desc, 0, word); + if (entry->queue->qid == QID_RX) { + rt2x00_desc_read(entry_priv->desc, 2, &word); + rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH, entry->skb->len); + rt2x00_desc_write(entry_priv->desc, 2, word); + + rt2x00_desc_read(entry_priv->desc, 1, &word); + rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma); + rt2x00_desc_write(entry_priv->desc, 1, word); + + rt2x00_desc_read(entry_priv->desc, 0, &word); + rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); + rt2x00_desc_write(entry_priv->desc, 0, word); + } else { + rt2x00_desc_read(entry_priv->desc, 0, &word); + rt2x00_set_field32(&word, TXD_W0_VALID, 0); + rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); + rt2x00_desc_write(entry_priv->desc, 0, word); + } } static int rt2400pci_init_queues(struct rt2x00_dev *rt2x00dev) @@ -1313,10 +1302,8 @@ static int rt2400pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) */ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); if (!is_valid_ether_addr(mac)) { - DECLARE_MAC_BUF(macbuf); - random_ether_addr(mac); - EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac)); + EEPROM(rt2x00dev, "MAC: %pM\n", mac); } rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); @@ -1504,20 +1491,6 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ -static int rt2400pci_set_retry_limit(struct ieee80211_hw *hw, - u32 short_retry, u32 long_retry) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - u32 reg; - - rt2x00pci_register_read(rt2x00dev, CSR11, ®); - rt2x00_set_field32(®, CSR11_LONG_RETRY, long_retry); - rt2x00_set_field32(®, CSR11_SHORT_RETRY, short_retry); - rt2x00pci_register_write(rt2x00dev, CSR11, reg); - - return 0; -} - static int rt2400pci_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params) { @@ -1576,7 +1549,6 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = { .config_interface = rt2x00mac_config_interface, .configure_filter = rt2x00mac_configure_filter, .get_stats = rt2x00mac_get_stats, - .set_retry_limit = rt2400pci_set_retry_limit, .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt2400pci_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, @@ -1589,8 +1561,8 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { .probe_hw = rt2400pci_probe_hw, .initialize = rt2x00pci_initialize, .uninitialize = rt2x00pci_uninitialize, - .init_rxentry = rt2400pci_init_rxentry, - .init_txentry = rt2400pci_init_txentry, + .get_entry_state = rt2400pci_get_entry_state, + .clear_entry = rt2400pci_clear_entry, .set_device_state = rt2400pci_set_device_state, .rfkill_poll = rt2400pci_rfkill_poll, .link_stats = rt2400pci_link_stats, @@ -1604,6 +1576,7 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { .config_filter = rt2400pci_config_filter, .config_intf = rt2400pci_config_intf, .config_erp = rt2400pci_config_erp, + .config_ant = rt2400pci_config_ant, .config = rt2400pci_config, }; diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h index bbff381ce3963d11e28b9b261c5c44ab88d3da5b..9aefda4ab3c263c4163543fff32a7853b8139ec8 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.h +++ b/drivers/net/wireless/rt2x00/rt2400pci.h @@ -46,7 +46,9 @@ #define CSR_REG_SIZE 0x014c #define EEPROM_BASE 0x0000 #define EEPROM_SIZE 0x0100 +#define BBP_BASE 0x0000 #define BBP_SIZE 0x0020 +#define RF_BASE 0x0000 #define RF_SIZE 0x0010 /* diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index ef42cc04a2d736428d112bdc28caa4af58aeeca4..d3bc218ec85cc2debcd5dfd52e8c00fcdf4124bf 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -49,45 +49,33 @@ * the access attempt is considered to have failed, * and we will print an error. */ -static u32 rt2500pci_bbp_check(struct rt2x00_dev *rt2x00dev) -{ - u32 reg; - unsigned int i; - - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00pci_register_read(rt2x00dev, BBPCSR, ®); - if (!rt2x00_get_field32(reg, BBPCSR_BUSY)) - break; - udelay(REGISTER_BUSY_DELAY); - } - - return reg; -} +#define WAIT_FOR_BBP(__dev, __reg) \ + rt2x00pci_regbusy_read((__dev), BBPCSR, BBPCSR_BUSY, (__reg)) +#define WAIT_FOR_RF(__dev, __reg) \ + rt2x00pci_regbusy_read((__dev), RFCSR, RFCSR_BUSY, (__reg)) static void rt2500pci_bbp_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u8 value) { u32 reg; - /* - * Wait until the BBP becomes ready. - */ - reg = rt2500pci_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, BBPCSR_BUSY)) { - ERROR(rt2x00dev, "BBPCSR register busy. Write failed.\n"); - return; - } + mutex_lock(&rt2x00dev->csr_mutex); /* - * Write the data into the BBP. + * Wait until the BBP becomes available, afterwards we + * can safely write the new data into the register. */ - reg = 0; - rt2x00_set_field32(®, BBPCSR_VALUE, value); - rt2x00_set_field32(®, BBPCSR_REGNUM, word); - rt2x00_set_field32(®, BBPCSR_BUSY, 1); - rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 1); + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, BBPCSR_VALUE, value); + rt2x00_set_field32(®, BBPCSR_REGNUM, word); + rt2x00_set_field32(®, BBPCSR_BUSY, 1); + rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 1); + + rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); + } - rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); + mutex_unlock(&rt2x00dev->csr_mutex); } static void rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev, @@ -95,66 +83,58 @@ static void rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev, { u32 reg; - /* - * Wait until the BBP becomes ready. - */ - reg = rt2500pci_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, BBPCSR_BUSY)) { - ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n"); - return; - } + mutex_lock(&rt2x00dev->csr_mutex); /* - * Write the request into the BBP. + * Wait until the BBP becomes available, afterwards we + * can safely write the read request into the register. + * After the data has been written, we wait until hardware + * returns the correct value, if at any time the register + * doesn't become available in time, reg will be 0xffffffff + * which means we return 0xff to the caller. */ - reg = 0; - rt2x00_set_field32(®, BBPCSR_REGNUM, word); - rt2x00_set_field32(®, BBPCSR_BUSY, 1); - rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 0); + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, BBPCSR_REGNUM, word); + rt2x00_set_field32(®, BBPCSR_BUSY, 1); + rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 0); - rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); + rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); - /* - * Wait until the BBP becomes ready. - */ - reg = rt2500pci_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, BBPCSR_BUSY)) { - ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n"); - *value = 0xff; - return; + WAIT_FOR_BBP(rt2x00dev, ®); } *value = rt2x00_get_field32(reg, BBPCSR_VALUE); + + mutex_unlock(&rt2x00dev->csr_mutex); } static void rt2500pci_rf_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u32 value) { u32 reg; - unsigned int i; if (!word) return; - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00pci_register_read(rt2x00dev, RFCSR, ®); - if (!rt2x00_get_field32(reg, RFCSR_BUSY)) - goto rf_write; - udelay(REGISTER_BUSY_DELAY); - } - - ERROR(rt2x00dev, "RFCSR register busy. Write failed.\n"); - return; + mutex_lock(&rt2x00dev->csr_mutex); -rf_write: - reg = 0; - rt2x00_set_field32(®, RFCSR_VALUE, value); - rt2x00_set_field32(®, RFCSR_NUMBER_OF_BITS, 20); - rt2x00_set_field32(®, RFCSR_IF_SELECT, 0); - rt2x00_set_field32(®, RFCSR_BUSY, 1); + /* + * Wait until the RF becomes available, afterwards we + * can safely write the new data into the register. + */ + if (WAIT_FOR_RF(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, RFCSR_VALUE, value); + rt2x00_set_field32(®, RFCSR_NUMBER_OF_BITS, 20); + rt2x00_set_field32(®, RFCSR_IF_SELECT, 0); + rt2x00_set_field32(®, RFCSR_BUSY, 1); + + rt2x00pci_register_write(rt2x00dev, RFCSR, reg); + rt2x00_rf_write(rt2x00dev, word, value); + } - rt2x00pci_register_write(rt2x00dev, RFCSR, reg); - rt2x00_rf_write(rt2x00dev, word, value); + mutex_unlock(&rt2x00dev->csr_mutex); } static void rt2500pci_eepromregister_read(struct eeprom_93cx6 *eeprom) @@ -188,43 +168,34 @@ static void rt2500pci_eepromregister_write(struct eeprom_93cx6 *eeprom) } #ifdef CONFIG_RT2X00_LIB_DEBUGFS -#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u32)) ) - -static void rt2500pci_read_csr(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u32 *data) -{ - rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data); -} - -static void rt2500pci_write_csr(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u32 data) -{ - rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data); -} - static const struct rt2x00debug rt2500pci_rt2x00debug = { .owner = THIS_MODULE, .csr = { - .read = rt2500pci_read_csr, - .write = rt2500pci_write_csr, + .read = rt2x00pci_register_read, + .write = rt2x00pci_register_write, + .flags = RT2X00DEBUGFS_OFFSET, + .word_base = CSR_REG_BASE, .word_size = sizeof(u32), .word_count = CSR_REG_SIZE / sizeof(u32), }, .eeprom = { .read = rt2x00_eeprom_read, .write = rt2x00_eeprom_write, + .word_base = EEPROM_BASE, .word_size = sizeof(u16), .word_count = EEPROM_SIZE / sizeof(u16), }, .bbp = { .read = rt2500pci_bbp_read, .write = rt2500pci_bbp_write, + .word_base = BBP_BASE, .word_size = sizeof(u8), .word_count = BBP_SIZE / sizeof(u8), }, .rf = { .read = rt2x00_rf_read, .write = rt2500pci_rf_write, + .word_base = RF_BASE, .word_size = sizeof(u32), .word_count = RF_SIZE / sizeof(u32), }, @@ -336,7 +307,7 @@ static void rt2500pci_config_intf(struct rt2x00_dev *rt2x00dev, /* * Enable beacon config */ - bcn_preload = PREAMBLE + get_duration(IEEE80211_HEADER, 20); + bcn_preload = PREAMBLE + GET_DURATION(IEEE80211_HEADER, 20); rt2x00pci_register_read(rt2x00dev, BCNCSR1, ®); rt2x00_set_field32(®, BCNCSR1_PRELOAD, bcn_preload); rt2x00_set_field32(®, BCNCSR1_BEACON_CWMIN, queue->cw_min); @@ -382,32 +353,114 @@ static void rt2500pci_config_erp(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_read(rt2x00dev, ARCSR2, ®); rt2x00_set_field32(®, ARCSR2_SIGNAL, 0x00); rt2x00_set_field32(®, ARCSR2_SERVICE, 0x04); - rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 10)); + rt2x00_set_field32(®, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 10)); rt2x00pci_register_write(rt2x00dev, ARCSR2, reg); rt2x00pci_register_read(rt2x00dev, ARCSR3, ®); rt2x00_set_field32(®, ARCSR3_SIGNAL, 0x01 | preamble_mask); rt2x00_set_field32(®, ARCSR3_SERVICE, 0x04); - rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 20)); + rt2x00_set_field32(®, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 20)); rt2x00pci_register_write(rt2x00dev, ARCSR3, reg); rt2x00pci_register_read(rt2x00dev, ARCSR4, ®); rt2x00_set_field32(®, ARCSR4_SIGNAL, 0x02 | preamble_mask); rt2x00_set_field32(®, ARCSR4_SERVICE, 0x04); - rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 55)); + rt2x00_set_field32(®, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 55)); rt2x00pci_register_write(rt2x00dev, ARCSR4, reg); rt2x00pci_register_read(rt2x00dev, ARCSR5, ®); rt2x00_set_field32(®, ARCSR5_SIGNAL, 0x03 | preamble_mask); rt2x00_set_field32(®, ARCSR5_SERVICE, 0x84); - rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110)); + rt2x00_set_field32(®, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 110)); rt2x00pci_register_write(rt2x00dev, ARCSR5, reg); + + rt2x00pci_register_write(rt2x00dev, ARCSR1, erp->basic_rates); + + rt2x00pci_register_read(rt2x00dev, CSR11, ®); + rt2x00_set_field32(®, CSR11_SLOT_TIME, erp->slot_time); + rt2x00pci_register_write(rt2x00dev, CSR11, reg); + + rt2x00pci_register_read(rt2x00dev, CSR18, ®); + rt2x00_set_field32(®, CSR18_SIFS, erp->sifs); + rt2x00_set_field32(®, CSR18_PIFS, erp->pifs); + rt2x00pci_register_write(rt2x00dev, CSR18, reg); + + rt2x00pci_register_read(rt2x00dev, CSR19, ®); + rt2x00_set_field32(®, CSR19_DIFS, erp->difs); + rt2x00_set_field32(®, CSR19_EIFS, erp->eifs); + rt2x00pci_register_write(rt2x00dev, CSR19, reg); } -static void rt2500pci_config_phymode(struct rt2x00_dev *rt2x00dev, - const int basic_rate_mask) +static void rt2500pci_config_ant(struct rt2x00_dev *rt2x00dev, + struct antenna_setup *ant) { - rt2x00pci_register_write(rt2x00dev, ARCSR1, basic_rate_mask); + u32 reg; + u8 r14; + u8 r2; + + /* + * We should never come here because rt2x00lib is supposed + * to catch this and send us the correct antenna explicitely. + */ + BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY || + ant->tx == ANTENNA_SW_DIVERSITY); + + rt2x00pci_register_read(rt2x00dev, BBPCSR1, ®); + rt2500pci_bbp_read(rt2x00dev, 14, &r14); + rt2500pci_bbp_read(rt2x00dev, 2, &r2); + + /* + * Configure the TX antenna. + */ + switch (ant->tx) { + case ANTENNA_A: + rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 0); + rt2x00_set_field32(®, BBPCSR1_CCK, 0); + rt2x00_set_field32(®, BBPCSR1_OFDM, 0); + break; + case ANTENNA_B: + default: + rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2); + rt2x00_set_field32(®, BBPCSR1_CCK, 2); + rt2x00_set_field32(®, BBPCSR1_OFDM, 2); + break; + } + + /* + * Configure the RX antenna. + */ + switch (ant->rx) { + case ANTENNA_A: + rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 0); + break; + case ANTENNA_B: + default: + rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2); + break; + } + + /* + * RT2525E and RT5222 need to flip TX I/Q + */ + if (rt2x00_rf(&rt2x00dev->chip, RF2525E) || + rt2x00_rf(&rt2x00dev->chip, RF5222)) { + rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1); + rt2x00_set_field32(®, BBPCSR1_CCK_FLIP, 1); + rt2x00_set_field32(®, BBPCSR1_OFDM_FLIP, 1); + + /* + * RT2525E does not need RX I/Q Flip. + */ + if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) + rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0); + } else { + rt2x00_set_field32(®, BBPCSR1_CCK_FLIP, 0); + rt2x00_set_field32(®, BBPCSR1_OFDM_FLIP, 0); + } + + rt2x00pci_register_write(rt2x00dev, BBPCSR1, reg); + rt2500pci_bbp_write(rt2x00dev, 14, r14); + rt2500pci_bbp_write(rt2x00dev, 2, r2); } static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev, @@ -489,76 +542,17 @@ static void rt2500pci_config_txpower(struct rt2x00_dev *rt2x00dev, rt2500pci_rf_write(rt2x00dev, 3, rf3); } -static void rt2500pci_config_antenna(struct rt2x00_dev *rt2x00dev, - struct antenna_setup *ant) +static void rt2500pci_config_retry_limit(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf) { u32 reg; - u8 r14; - u8 r2; - - /* - * We should never come here because rt2x00lib is supposed - * to catch this and send us the correct antenna explicitely. - */ - BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY || - ant->tx == ANTENNA_SW_DIVERSITY); - - rt2x00pci_register_read(rt2x00dev, BBPCSR1, ®); - rt2500pci_bbp_read(rt2x00dev, 14, &r14); - rt2500pci_bbp_read(rt2x00dev, 2, &r2); - - /* - * Configure the TX antenna. - */ - switch (ant->tx) { - case ANTENNA_A: - rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 0); - rt2x00_set_field32(®, BBPCSR1_CCK, 0); - rt2x00_set_field32(®, BBPCSR1_OFDM, 0); - break; - case ANTENNA_B: - default: - rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2); - rt2x00_set_field32(®, BBPCSR1_CCK, 2); - rt2x00_set_field32(®, BBPCSR1_OFDM, 2); - break; - } - - /* - * Configure the RX antenna. - */ - switch (ant->rx) { - case ANTENNA_A: - rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 0); - break; - case ANTENNA_B: - default: - rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2); - break; - } - - /* - * RT2525E and RT5222 need to flip TX I/Q - */ - if (rt2x00_rf(&rt2x00dev->chip, RF2525E) || - rt2x00_rf(&rt2x00dev->chip, RF5222)) { - rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1); - rt2x00_set_field32(®, BBPCSR1_CCK_FLIP, 1); - rt2x00_set_field32(®, BBPCSR1_OFDM_FLIP, 1); - /* - * RT2525E does not need RX I/Q Flip. - */ - if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) - rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0); - } else { - rt2x00_set_field32(®, BBPCSR1_CCK_FLIP, 0); - rt2x00_set_field32(®, BBPCSR1_OFDM_FLIP, 0); - } - - rt2x00pci_register_write(rt2x00dev, BBPCSR1, reg); - rt2500pci_bbp_write(rt2x00dev, 14, r14); - rt2500pci_bbp_write(rt2x00dev, 2, r2); + rt2x00pci_register_read(rt2x00dev, CSR11, ®); + rt2x00_set_field32(®, CSR11_LONG_RETRY, + libconf->conf->long_frame_max_tx_count); + rt2x00_set_field32(®, CSR11_SHORT_RETRY, + libconf->conf->short_frame_max_tx_count); + rt2x00pci_register_write(rt2x00dev, CSR11, reg); } static void rt2500pci_config_duration(struct rt2x00_dev *rt2x00dev, @@ -566,20 +560,6 @@ static void rt2500pci_config_duration(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt2x00pci_register_read(rt2x00dev, CSR11, ®); - rt2x00_set_field32(®, CSR11_SLOT_TIME, libconf->slot_time); - rt2x00pci_register_write(rt2x00dev, CSR11, reg); - - rt2x00pci_register_read(rt2x00dev, CSR18, ®); - rt2x00_set_field32(®, CSR18_SIFS, libconf->sifs); - rt2x00_set_field32(®, CSR18_PIFS, libconf->pifs); - rt2x00pci_register_write(rt2x00dev, CSR18, reg); - - rt2x00pci_register_read(rt2x00dev, CSR19, ®); - rt2x00_set_field32(®, CSR19_DIFS, libconf->difs); - rt2x00_set_field32(®, CSR19_EIFS, libconf->eifs); - rt2x00pci_register_write(rt2x00dev, CSR19, reg); - rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); rt2x00_set_field32(®, TXCSR1_TSF_OFFSET, IEEE80211_HEADER); rt2x00_set_field32(®, TXCSR1_AUTORESPONDER, 1); @@ -597,17 +577,16 @@ static void rt2500pci_config(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf, const unsigned int flags) { - if (flags & CONFIG_UPDATE_PHYMODE) - rt2500pci_config_phymode(rt2x00dev, libconf->basic_rates); - if (flags & CONFIG_UPDATE_CHANNEL) + if (flags & IEEE80211_CONF_CHANGE_CHANNEL) rt2500pci_config_channel(rt2x00dev, &libconf->rf, libconf->conf->power_level); - if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL)) + if ((flags & IEEE80211_CONF_CHANGE_POWER) && + !(flags & IEEE80211_CONF_CHANGE_CHANNEL)) rt2500pci_config_txpower(rt2x00dev, libconf->conf->power_level); - if (flags & CONFIG_UPDATE_ANTENNA) - rt2500pci_config_antenna(rt2x00dev, &libconf->ant); - if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) + if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) + rt2500pci_config_retry_limit(rt2x00dev, libconf); + if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) rt2500pci_config_duration(rt2x00dev, libconf); } @@ -723,32 +702,43 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev) /* * Initialization functions. */ -static void rt2500pci_init_rxentry(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry) +static bool rt2500pci_get_entry_state(struct queue_entry *entry) { struct queue_entry_priv_pci *entry_priv = entry->priv_data; - struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); u32 word; - rt2x00_desc_read(entry_priv->desc, 1, &word); - rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma); - rt2x00_desc_write(entry_priv->desc, 1, word); + if (entry->queue->qid == QID_RX) { + rt2x00_desc_read(entry_priv->desc, 0, &word); + + return rt2x00_get_field32(word, RXD_W0_OWNER_NIC); + } else { + rt2x00_desc_read(entry_priv->desc, 0, &word); - rt2x00_desc_read(entry_priv->desc, 0, &word); - rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); - rt2x00_desc_write(entry_priv->desc, 0, word); + return (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || + rt2x00_get_field32(word, TXD_W0_VALID)); + } } -static void rt2500pci_init_txentry(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry) +static void rt2500pci_clear_entry(struct queue_entry *entry) { struct queue_entry_priv_pci *entry_priv = entry->priv_data; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); u32 word; - rt2x00_desc_read(entry_priv->desc, 0, &word); - rt2x00_set_field32(&word, TXD_W0_VALID, 0); - rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); - rt2x00_desc_write(entry_priv->desc, 0, word); + if (entry->queue->qid == QID_RX) { + rt2x00_desc_read(entry_priv->desc, 1, &word); + rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma); + rt2x00_desc_write(entry_priv->desc, 1, word); + + rt2x00_desc_read(entry_priv->desc, 0, &word); + rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); + rt2x00_desc_write(entry_priv->desc, 0, word); + } else { + rt2x00_desc_read(entry_priv->desc, 0, &word); + rt2x00_set_field32(&word, TXD_W0_VALID, 0); + rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); + rt2x00_desc_write(entry_priv->desc, 0, word); + } } static int rt2500pci_init_queues(struct rt2x00_dev *rt2x00dev) @@ -1451,11 +1441,8 @@ static int rt2500pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) */ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); if (!is_valid_ether_addr(mac)) { - DECLARE_MAC_BUF(macbuf); - random_ether_addr(mac); - EEPROM(rt2x00dev, "MAC: %s\n", - print_mac(macbuf, mac)); + EEPROM(rt2x00dev, "MAC: %pM\n", mac); } rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); @@ -1830,20 +1817,6 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ -static int rt2500pci_set_retry_limit(struct ieee80211_hw *hw, - u32 short_retry, u32 long_retry) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - u32 reg; - - rt2x00pci_register_read(rt2x00dev, CSR11, ®); - rt2x00_set_field32(®, CSR11_LONG_RETRY, long_retry); - rt2x00_set_field32(®, CSR11_SHORT_RETRY, short_retry); - rt2x00pci_register_write(rt2x00dev, CSR11, reg); - - return 0; -} - static u64 rt2500pci_get_tsf(struct ieee80211_hw *hw) { struct rt2x00_dev *rt2x00dev = hw->priv; @@ -1877,7 +1850,6 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = { .config_interface = rt2x00mac_config_interface, .configure_filter = rt2x00mac_configure_filter, .get_stats = rt2x00mac_get_stats, - .set_retry_limit = rt2500pci_set_retry_limit, .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt2x00mac_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, @@ -1890,8 +1862,8 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { .probe_hw = rt2500pci_probe_hw, .initialize = rt2x00pci_initialize, .uninitialize = rt2x00pci_uninitialize, - .init_rxentry = rt2500pci_init_rxentry, - .init_txentry = rt2500pci_init_txentry, + .get_entry_state = rt2500pci_get_entry_state, + .clear_entry = rt2500pci_clear_entry, .set_device_state = rt2500pci_set_device_state, .rfkill_poll = rt2500pci_rfkill_poll, .link_stats = rt2500pci_link_stats, @@ -1905,6 +1877,7 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { .config_filter = rt2500pci_config_filter, .config_intf = rt2500pci_config_intf, .config_erp = rt2500pci_config_erp, + .config_ant = rt2500pci_config_ant, .config = rt2500pci_config, }; diff --git a/drivers/net/wireless/rt2x00/rt2500pci.h b/drivers/net/wireless/rt2x00/rt2500pci.h index 8c26bef6cf49cc23d0eecafe635e20f93b89f052..e135247f7f89d6aae25fefc4bdb7673e54bfc706 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.h +++ b/drivers/net/wireless/rt2x00/rt2500pci.h @@ -57,7 +57,9 @@ #define CSR_REG_SIZE 0x0174 #define EEPROM_BASE 0x0000 #define EEPROM_SIZE 0x0200 +#define BBP_BASE 0x0000 #define BBP_SIZE 0x0040 +#define RF_BASE 0x0000 #define RF_SIZE 0x0014 /* diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index d3bf7bba611ac02111b05df14a523148648796e5..30028e2422fcfde7706b285042b7a4b9b12863c9 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -35,6 +35,13 @@ #include "rt2x00usb.h" #include "rt2500usb.h" +/* + * Allow hardware encryption to be disabled. + */ +static int modparam_nohwcrypt = 1; +module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); +MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); + /* * Register access. * All access to the CSR registers will go through the methods @@ -47,7 +54,7 @@ * between each attampt. When the busy bit is still set at that time, * the access attempt is considered to have failed, * and we will print an error. - * If the usb_cache_mutex is already held then the _lock variants must + * If the csr_mutex is already held then the _lock variants must * be used instead. */ static inline void rt2500usb_register_read(struct rt2x00_dev *rt2x00dev, @@ -57,7 +64,7 @@ static inline void rt2500usb_register_read(struct rt2x00_dev *rt2x00dev, __le16 reg; rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ, USB_VENDOR_REQUEST_IN, offset, - ®, sizeof(u16), REGISTER_TIMEOUT); + ®, sizeof(reg), REGISTER_TIMEOUT); *value = le16_to_cpu(reg); } @@ -68,7 +75,7 @@ static inline void rt2500usb_register_read_lock(struct rt2x00_dev *rt2x00dev, __le16 reg; rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ, USB_VENDOR_REQUEST_IN, offset, - ®, sizeof(u16), REGISTER_TIMEOUT); + ®, sizeof(reg), REGISTER_TIMEOUT); *value = le16_to_cpu(reg); } @@ -89,7 +96,7 @@ static inline void rt2500usb_register_write(struct rt2x00_dev *rt2x00dev, __le16 reg = cpu_to_le16(value); rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE, USB_VENDOR_REQUEST_OUT, offset, - ®, sizeof(u16), REGISTER_TIMEOUT); + ®, sizeof(reg), REGISTER_TIMEOUT); } static inline void rt2500usb_register_write_lock(struct rt2x00_dev *rt2x00dev, @@ -99,7 +106,7 @@ static inline void rt2500usb_register_write_lock(struct rt2x00_dev *rt2x00dev, __le16 reg = cpu_to_le16(value); rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_WRITE, USB_VENDOR_REQUEST_OUT, offset, - ®, sizeof(u16), REGISTER_TIMEOUT); + ®, sizeof(reg), REGISTER_TIMEOUT); } static inline void rt2500usb_register_multiwrite(struct rt2x00_dev *rt2x00dev, @@ -112,53 +119,53 @@ static inline void rt2500usb_register_multiwrite(struct rt2x00_dev *rt2x00dev, REGISTER_TIMEOUT16(length)); } -static u16 rt2500usb_bbp_check(struct rt2x00_dev *rt2x00dev) +static int rt2500usb_regbusy_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + struct rt2x00_field16 field, + u16 *reg) { - u16 reg; unsigned int i; for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2500usb_register_read_lock(rt2x00dev, PHY_CSR8, ®); - if (!rt2x00_get_field16(reg, PHY_CSR8_BUSY)) - break; + rt2500usb_register_read_lock(rt2x00dev, offset, reg); + if (!rt2x00_get_field16(*reg, field)) + return 1; udelay(REGISTER_BUSY_DELAY); } - return reg; + ERROR(rt2x00dev, "Indirect register access failed: " + "offset=0x%.08x, value=0x%.08x\n", offset, *reg); + *reg = ~0; + + return 0; } +#define WAIT_FOR_BBP(__dev, __reg) \ + rt2500usb_regbusy_read((__dev), PHY_CSR8, PHY_CSR8_BUSY, (__reg)) +#define WAIT_FOR_RF(__dev, __reg) \ + rt2500usb_regbusy_read((__dev), PHY_CSR10, PHY_CSR10_RF_BUSY, (__reg)) + static void rt2500usb_bbp_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u8 value) { u16 reg; - mutex_lock(&rt2x00dev->usb_cache_mutex); + mutex_lock(&rt2x00dev->csr_mutex); /* - * Wait until the BBP becomes ready. + * Wait until the BBP becomes available, afterwards we + * can safely write the new data into the register. */ - reg = rt2500usb_bbp_check(rt2x00dev); - if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) - goto exit_fail; - - /* - * Write the data into the BBP. - */ - reg = 0; - rt2x00_set_field16(®, PHY_CSR7_DATA, value); - rt2x00_set_field16(®, PHY_CSR7_REG_ID, word); - rt2x00_set_field16(®, PHY_CSR7_READ_CONTROL, 0); - - rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg); - - mutex_unlock(&rt2x00dev->usb_cache_mutex); - - return; + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field16(®, PHY_CSR7_DATA, value); + rt2x00_set_field16(®, PHY_CSR7_REG_ID, word); + rt2x00_set_field16(®, PHY_CSR7_READ_CONTROL, 0); -exit_fail: - mutex_unlock(&rt2x00dev->usb_cache_mutex); + rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg); + } - ERROR(rt2x00dev, "PHY_CSR8 register busy. Write failed.\n"); + mutex_unlock(&rt2x00dev->csr_mutex); } static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev, @@ -166,122 +173,107 @@ static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev, { u16 reg; - mutex_lock(&rt2x00dev->usb_cache_mutex); + mutex_lock(&rt2x00dev->csr_mutex); /* - * Wait until the BBP becomes ready. + * Wait until the BBP becomes available, afterwards we + * can safely write the read request into the register. + * After the data has been written, we wait until hardware + * returns the correct value, if at any time the register + * doesn't become available in time, reg will be 0xffffffff + * which means we return 0xff to the caller. */ - reg = rt2500usb_bbp_check(rt2x00dev); - if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) - goto exit_fail; - - /* - * Write the request into the BBP. - */ - reg = 0; - rt2x00_set_field16(®, PHY_CSR7_REG_ID, word); - rt2x00_set_field16(®, PHY_CSR7_READ_CONTROL, 1); + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field16(®, PHY_CSR7_REG_ID, word); + rt2x00_set_field16(®, PHY_CSR7_READ_CONTROL, 1); - rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg); + rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg); - /* - * Wait until the BBP becomes ready. - */ - reg = rt2500usb_bbp_check(rt2x00dev); - if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) - goto exit_fail; + if (WAIT_FOR_BBP(rt2x00dev, ®)) + rt2500usb_register_read_lock(rt2x00dev, PHY_CSR7, ®); + } - rt2500usb_register_read_lock(rt2x00dev, PHY_CSR7, ®); *value = rt2x00_get_field16(reg, PHY_CSR7_DATA); - mutex_unlock(&rt2x00dev->usb_cache_mutex); - - return; - -exit_fail: - mutex_unlock(&rt2x00dev->usb_cache_mutex); - - ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n"); - *value = 0xff; + mutex_unlock(&rt2x00dev->csr_mutex); } static void rt2500usb_rf_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u32 value) { u16 reg; - unsigned int i; if (!word) return; - mutex_lock(&rt2x00dev->usb_cache_mutex); - - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2500usb_register_read_lock(rt2x00dev, PHY_CSR10, ®); - if (!rt2x00_get_field16(reg, PHY_CSR10_RF_BUSY)) - goto rf_write; - udelay(REGISTER_BUSY_DELAY); - } + mutex_lock(&rt2x00dev->csr_mutex); - mutex_unlock(&rt2x00dev->usb_cache_mutex); - ERROR(rt2x00dev, "PHY_CSR10 register busy. Write failed.\n"); - return; - -rf_write: - reg = 0; - rt2x00_set_field16(®, PHY_CSR9_RF_VALUE, value); - rt2500usb_register_write_lock(rt2x00dev, PHY_CSR9, reg); + /* + * Wait until the RF becomes available, afterwards we + * can safely write the new data into the register. + */ + if (WAIT_FOR_RF(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field16(®, PHY_CSR9_RF_VALUE, value); + rt2500usb_register_write_lock(rt2x00dev, PHY_CSR9, reg); - reg = 0; - rt2x00_set_field16(®, PHY_CSR10_RF_VALUE, value >> 16); - rt2x00_set_field16(®, PHY_CSR10_RF_NUMBER_OF_BITS, 20); - rt2x00_set_field16(®, PHY_CSR10_RF_IF_SELECT, 0); - rt2x00_set_field16(®, PHY_CSR10_RF_BUSY, 1); + reg = 0; + rt2x00_set_field16(®, PHY_CSR10_RF_VALUE, value >> 16); + rt2x00_set_field16(®, PHY_CSR10_RF_NUMBER_OF_BITS, 20); + rt2x00_set_field16(®, PHY_CSR10_RF_IF_SELECT, 0); + rt2x00_set_field16(®, PHY_CSR10_RF_BUSY, 1); - rt2500usb_register_write_lock(rt2x00dev, PHY_CSR10, reg); - rt2x00_rf_write(rt2x00dev, word, value); + rt2500usb_register_write_lock(rt2x00dev, PHY_CSR10, reg); + rt2x00_rf_write(rt2x00dev, word, value); + } - mutex_unlock(&rt2x00dev->usb_cache_mutex); + mutex_unlock(&rt2x00dev->csr_mutex); } #ifdef CONFIG_RT2X00_LIB_DEBUGFS -#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u16)) ) - -static void rt2500usb_read_csr(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u32 *data) +static void _rt2500usb_register_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + u32 *value) { - rt2500usb_register_read(rt2x00dev, CSR_OFFSET(word), (u16 *) data); + rt2500usb_register_read(rt2x00dev, offset, (u16 *)value); } -static void rt2500usb_write_csr(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u32 data) +static void _rt2500usb_register_write(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + u32 value) { - rt2500usb_register_write(rt2x00dev, CSR_OFFSET(word), data); + rt2500usb_register_write(rt2x00dev, offset, value); } static const struct rt2x00debug rt2500usb_rt2x00debug = { .owner = THIS_MODULE, .csr = { - .read = rt2500usb_read_csr, - .write = rt2500usb_write_csr, + .read = _rt2500usb_register_read, + .write = _rt2500usb_register_write, + .flags = RT2X00DEBUGFS_OFFSET, + .word_base = CSR_REG_BASE, .word_size = sizeof(u16), .word_count = CSR_REG_SIZE / sizeof(u16), }, .eeprom = { .read = rt2x00_eeprom_read, .write = rt2x00_eeprom_write, + .word_base = EEPROM_BASE, .word_size = sizeof(u16), .word_count = EEPROM_SIZE / sizeof(u16), }, .bbp = { .read = rt2500usb_bbp_read, .write = rt2500usb_bbp_write, + .word_base = BBP_BASE, .word_size = sizeof(u8), .word_count = BBP_SIZE / sizeof(u8), }, .rf = { .read = rt2x00_rf_read, .write = rt2500usb_rf_write, + .word_base = RF_BASE, .word_size = sizeof(u32), .word_count = RF_SIZE / sizeof(u32), }, @@ -338,6 +330,82 @@ static void rt2500usb_init_led(struct rt2x00_dev *rt2x00dev, /* * Configuration handlers. */ + +/* + * rt2500usb does not differentiate between shared and pairwise + * keys, so we should use the same function for both key types. + */ +static int rt2500usb_config_key(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_crypto *crypto, + struct ieee80211_key_conf *key) +{ + int timeout; + u32 mask; + u16 reg; + + if (crypto->cmd == SET_KEY) { + /* + * Pairwise key will always be entry 0, but this + * could collide with a shared key on the same + * position... + */ + mask = TXRX_CSR0_KEY_ID.bit_mask; + + rt2500usb_register_read(rt2x00dev, TXRX_CSR0, ®); + reg &= mask; + + if (reg && reg == mask) + return -ENOSPC; + + reg = rt2x00_get_field16(reg, TXRX_CSR0_KEY_ID); + + key->hw_key_idx += reg ? ffz(reg) : 0; + + /* + * The encryption key doesn't fit within the CSR cache, + * this means we should allocate it seperately and use + * rt2x00usb_vendor_request() to send the key to the hardware. + */ + reg = KEY_ENTRY(key->hw_key_idx); + timeout = REGISTER_TIMEOUT32(sizeof(crypto->key)); + rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, reg, + crypto->key, + sizeof(crypto->key), + timeout); + + /* + * The driver does not support the IV/EIV generation + * in hardware. However it doesn't support the IV/EIV + * inside the ieee80211 frame either, but requires it + * to be provided seperately for the descriptor. + * rt2x00lib will cut the IV/EIV data out of all frames + * given to us by mac80211, but we must tell mac80211 + * to generate the IV/EIV data. + */ + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; + } + + /* + * TXRX_CSR0_KEY_ID contains only single-bit fields to indicate + * a particular key is valid. + */ + rt2500usb_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00_set_field16(®, TXRX_CSR0_ALGORITHM, crypto->cipher); + rt2x00_set_field16(®, TXRX_CSR0_IV_OFFSET, IEEE80211_HEADER); + + mask = rt2x00_get_field16(reg, TXRX_CSR0_KEY_ID); + if (crypto->cmd == SET_KEY) + mask |= 1 << key->hw_key_idx; + else if (crypto->cmd == DISABLE_KEY) + mask &= ~(1 << key->hw_key_idx); + rt2x00_set_field16(®, TXRX_CSR0_KEY_ID, mask); + rt2500usb_register_write(rt2x00dev, TXRX_CSR0, reg); + + return 0; +} + static void rt2500usb_config_filter(struct rt2x00_dev *rt2x00dev, const unsigned int filter_flags) { @@ -380,7 +448,7 @@ static void rt2500usb_config_intf(struct rt2x00_dev *rt2x00dev, /* * Enable beacon config */ - bcn_preload = PREAMBLE + get_duration(IEEE80211_HEADER, 20); + bcn_preload = PREAMBLE + GET_DURATION(IEEE80211_HEADER, 20); rt2500usb_register_read(rt2x00dev, TXRX_CSR20, ®); rt2x00_set_field16(®, TXRX_CSR20_OFFSET, bcn_preload >> 6); rt2x00_set_field16(®, TXRX_CSR20_BCN_EXPECT_WINDOW, @@ -423,57 +491,16 @@ static void rt2500usb_config_erp(struct rt2x00_dev *rt2x00dev, rt2x00_set_field16(®, TXRX_CSR10_AUTORESPOND_PREAMBLE, !!erp->short_preamble); rt2500usb_register_write(rt2x00dev, TXRX_CSR10, reg); -} - -static void rt2500usb_config_phymode(struct rt2x00_dev *rt2x00dev, - const int basic_rate_mask) -{ - rt2500usb_register_write(rt2x00dev, TXRX_CSR11, basic_rate_mask); -} - -static void rt2500usb_config_channel(struct rt2x00_dev *rt2x00dev, - struct rf_channel *rf, const int txpower) -{ - /* - * Set TXpower. - */ - rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); - - /* - * For RT2525E we should first set the channel to half band higher. - */ - if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) { - static const u32 vals[] = { - 0x000008aa, 0x000008ae, 0x000008ae, 0x000008b2, - 0x000008b2, 0x000008b6, 0x000008b6, 0x000008ba, - 0x000008ba, 0x000008be, 0x000008b7, 0x00000902, - 0x00000902, 0x00000906 - }; - - rt2500usb_rf_write(rt2x00dev, 2, vals[rf->channel - 1]); - if (rf->rf4) - rt2500usb_rf_write(rt2x00dev, 4, rf->rf4); - } - - rt2500usb_rf_write(rt2x00dev, 1, rf->rf1); - rt2500usb_rf_write(rt2x00dev, 2, rf->rf2); - rt2500usb_rf_write(rt2x00dev, 3, rf->rf3); - if (rf->rf4) - rt2500usb_rf_write(rt2x00dev, 4, rf->rf4); -} -static void rt2500usb_config_txpower(struct rt2x00_dev *rt2x00dev, - const int txpower) -{ - u32 rf3; + rt2500usb_register_write(rt2x00dev, TXRX_CSR11, erp->basic_rates); - rt2x00_rf_read(rt2x00dev, 3, &rf3); - rt2x00_set_field32(&rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); - rt2500usb_rf_write(rt2x00dev, 3, rf3); + rt2500usb_register_write(rt2x00dev, MAC_CSR10, erp->slot_time); + rt2500usb_register_write(rt2x00dev, MAC_CSR11, erp->sifs); + rt2500usb_register_write(rt2x00dev, MAC_CSR12, erp->eifs); } -static void rt2500usb_config_antenna(struct rt2x00_dev *rt2x00dev, - struct antenna_setup *ant) +static void rt2500usb_config_ant(struct rt2x00_dev *rt2x00dev, + struct antenna_setup *ant) { u8 r2; u8 r14; @@ -555,15 +582,52 @@ static void rt2500usb_config_antenna(struct rt2x00_dev *rt2x00dev, rt2500usb_register_write(rt2x00dev, PHY_CSR6, csr6); } +static void rt2500usb_config_channel(struct rt2x00_dev *rt2x00dev, + struct rf_channel *rf, const int txpower) +{ + /* + * Set TXpower. + */ + rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); + + /* + * For RT2525E we should first set the channel to half band higher. + */ + if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) { + static const u32 vals[] = { + 0x000008aa, 0x000008ae, 0x000008ae, 0x000008b2, + 0x000008b2, 0x000008b6, 0x000008b6, 0x000008ba, + 0x000008ba, 0x000008be, 0x000008b7, 0x00000902, + 0x00000902, 0x00000906 + }; + + rt2500usb_rf_write(rt2x00dev, 2, vals[rf->channel - 1]); + if (rf->rf4) + rt2500usb_rf_write(rt2x00dev, 4, rf->rf4); + } + + rt2500usb_rf_write(rt2x00dev, 1, rf->rf1); + rt2500usb_rf_write(rt2x00dev, 2, rf->rf2); + rt2500usb_rf_write(rt2x00dev, 3, rf->rf3); + if (rf->rf4) + rt2500usb_rf_write(rt2x00dev, 4, rf->rf4); +} + +static void rt2500usb_config_txpower(struct rt2x00_dev *rt2x00dev, + const int txpower) +{ + u32 rf3; + + rt2x00_rf_read(rt2x00dev, 3, &rf3); + rt2x00_set_field32(&rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); + rt2500usb_rf_write(rt2x00dev, 3, rf3); +} + static void rt2500usb_config_duration(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf) { u16 reg; - rt2500usb_register_write(rt2x00dev, MAC_CSR10, libconf->slot_time); - rt2500usb_register_write(rt2x00dev, MAC_CSR11, libconf->sifs); - rt2500usb_register_write(rt2x00dev, MAC_CSR12, libconf->eifs); - rt2500usb_register_read(rt2x00dev, TXRX_CSR18, ®); rt2x00_set_field16(®, TXRX_CSR18_INTERVAL, libconf->conf->beacon_int * 4); @@ -574,17 +638,14 @@ static void rt2500usb_config(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf, const unsigned int flags) { - if (flags & CONFIG_UPDATE_PHYMODE) - rt2500usb_config_phymode(rt2x00dev, libconf->basic_rates); - if (flags & CONFIG_UPDATE_CHANNEL) + if (flags & IEEE80211_CONF_CHANGE_CHANNEL) rt2500usb_config_channel(rt2x00dev, &libconf->rf, libconf->conf->power_level); - if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL)) + if ((flags & IEEE80211_CONF_CHANGE_POWER) && + !(flags & IEEE80211_CONF_CHANGE_CHANNEL)) rt2500usb_config_txpower(rt2x00dev, libconf->conf->power_level); - if (flags & CONFIG_UPDATE_ANTENNA) - rt2500usb_config_antenna(rt2x00dev, &libconf->ant); - if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) + if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) rt2500usb_config_duration(rt2x00dev, libconf); } @@ -866,7 +927,7 @@ static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2500usb_register_read(rt2x00dev, TXRX_CSR0, ®); rt2x00_set_field16(®, TXRX_CSR0_IV_OFFSET, IEEE80211_HEADER); - rt2x00_set_field16(®, TXRX_CSR0_KEY_ID, 0xff); + rt2x00_set_field16(®, TXRX_CSR0_KEY_ID, 0); rt2500usb_register_write(rt2x00dev, TXRX_CSR0, reg); rt2500usb_register_read(rt2x00dev, MAC_CSR18, ®); @@ -1088,7 +1149,7 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, * Start writing the descriptor words. */ rt2x00_desc_read(txd, 1, &word); - rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER); + rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, txdesc->iv_offset); rt2x00_set_field32(&word, TXD_W1_AIFS, txdesc->aifs); rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min); rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max); @@ -1101,6 +1162,11 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, txdesc->length_high); rt2x00_desc_write(txd, 2, word); + if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags)) { + _rt2x00_desc_write(txd, 3, skbdesc->iv[0]); + _rt2x00_desc_write(txd, 4, skbdesc->iv[1]); + } + rt2x00_desc_read(txd, 0, &word); rt2x00_set_field32(&word, TXD_W0_RETRY_LIMIT, txdesc->retry_limit); rt2x00_set_field32(&word, TXD_W0_MORE_FRAG, @@ -1115,7 +1181,8 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skb->len); - rt2x00_set_field32(&word, TXD_W0_CIPHER, CIPHER_NONE); + rt2x00_set_field32(&word, TXD_W0_CIPHER, txdesc->cipher); + rt2x00_set_field32(&word, TXD_W0_KEY_ID, txdesc->key_idx); rt2x00_desc_write(txd, 0, word); } @@ -1130,7 +1197,7 @@ static void rt2500usb_write_beacon(struct queue_entry *entry) struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data; struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); - int pipe = usb_sndbulkpipe(usb_dev, 1); + int pipe = usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint); int length; u16 reg; @@ -1156,7 +1223,7 @@ static void rt2500usb_write_beacon(struct queue_entry *entry) * length of the data to usb_fill_bulk_urb. Pass the skb * to the driver to determine what the length should be. */ - length = rt2x00dev->ops->lib->get_tx_data_len(rt2x00dev, entry->skb); + length = rt2x00dev->ops->lib->get_tx_data_len(entry); usb_fill_bulk_urb(bcn_priv->urb, usb_dev, pipe, entry->skb->data, length, rt2500usb_beacondone, @@ -1178,8 +1245,7 @@ static void rt2500usb_write_beacon(struct queue_entry *entry) usb_submit_urb(bcn_priv->guardian_urb, GFP_ATOMIC); } -static int rt2500usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb) +static int rt2500usb_get_tx_data_len(struct queue_entry *entry) { int length; @@ -1187,8 +1253,8 @@ static int rt2500usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev, * The length _must_ be a multiple of 2, * but it must _not_ be a multiple of the USB packet size. */ - length = roundup(skb->len, 2); - length += (2 * !(length % rt2x00dev->usb_maxpacket)); + length = roundup(entry->skb->len, 2); + length += (2 * !(length % entry->queue->usb_maxpacket)); return length; } @@ -1227,6 +1293,7 @@ static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, static void rt2500usb_fill_rxdone(struct queue_entry *entry, struct rxdone_entry_desc *rxdesc) { + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct queue_entry_priv_usb *entry_priv = entry->priv_data; struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); __le32 *rxd = @@ -1254,6 +1321,33 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry, if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_PLCP_CRC; + if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) { + rxdesc->cipher = rt2x00_get_field32(word0, RXD_W0_CIPHER); + if (rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR)) + rxdesc->cipher_status = RX_CRYPTO_FAIL_KEY; + } + + if (rxdesc->cipher != CIPHER_NONE) { + _rt2x00_desc_read(rxd, 2, &rxdesc->iv[0]); + _rt2x00_desc_read(rxd, 3, &rxdesc->iv[1]); + rxdesc->dev_flags |= RXDONE_CRYPTO_IV; + + /* ICV is located at the end of frame */ + + /* + * Hardware has stripped IV/EIV data from 802.11 frame during + * decryption. It has provided the data seperately but rt2x00lib + * should decide if it should be reinserted. + */ + rxdesc->flags |= RX_FLAG_IV_STRIPPED; + if (rxdesc->cipher != CIPHER_TKIP) + rxdesc->flags |= RX_FLAG_MMIC_STRIPPED; + if (rxdesc->cipher_status == RX_CRYPTO_SUCCESS) + rxdesc->flags |= RX_FLAG_DECRYPTED; + else if (rxdesc->cipher_status == RX_CRYPTO_FAIL_MIC) + rxdesc->flags |= RX_FLAG_MMIC_ERROR; + } + /* * Obtain the status about this packet. * When frame was received with an OFDM bitrate, @@ -1261,8 +1355,8 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry, * a CCK bitrate the signal is the rate in 100kbit/s. */ rxdesc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); - rxdesc->rssi = rt2x00_get_field32(word1, RXD_W1_RSSI) - - entry->queue->rt2x00dev->rssi_offset; + rxdesc->rssi = + rt2x00_get_field32(word1, RXD_W1_RSSI) - rt2x00dev->rssi_offset; rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); if (rt2x00_get_field32(word0, RXD_W0_OFDM)) @@ -1319,10 +1413,8 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) */ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); if (!is_valid_ether_addr(mac)) { - DECLARE_MAC_BUF(macbuf); - random_ether_addr(mac); - EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac)); + EEPROM(rt2x00dev, "MAC: %pM\n", mac); } rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); @@ -1752,6 +1844,10 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) __set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags); + if (!modparam_nohwcrypt) { + __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); + __set_bit(CONFIG_CRYPTO_COPY_IV, &rt2x00dev->flags); + } __set_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags); /* @@ -1771,6 +1867,7 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = { .config = rt2x00mac_config, .config_interface = rt2x00mac_config_interface, .configure_filter = rt2x00mac_configure_filter, + .set_key = rt2x00mac_set_key, .get_stats = rt2x00mac_get_stats, .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt2x00mac_conf_tx, @@ -1781,8 +1878,7 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = { .probe_hw = rt2500usb_probe_hw, .initialize = rt2x00usb_initialize, .uninitialize = rt2x00usb_uninitialize, - .init_rxentry = rt2x00usb_init_rxentry, - .init_txentry = rt2x00usb_init_txentry, + .clear_entry = rt2x00usb_clear_entry, .set_device_state = rt2500usb_set_device_state, .link_stats = rt2500usb_link_stats, .reset_tuner = rt2500usb_reset_tuner, @@ -1793,9 +1889,12 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = { .get_tx_data_len = rt2500usb_get_tx_data_len, .kick_tx_queue = rt2500usb_kick_tx_queue, .fill_rxdone = rt2500usb_fill_rxdone, + .config_shared_key = rt2500usb_config_key, + .config_pairwise_key = rt2500usb_config_key, .config_filter = rt2500usb_config_filter, .config_intf = rt2500usb_config_intf, .config_erp = rt2500usb_config_erp, + .config_ant = rt2500usb_config_ant, .config = rt2500usb_config, }; diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h index 89e5ed24e4f7906a95ae0feaacc992e022840e34..4347dfdabcd4f0525a1e9f2cbed5457848cf1d2b 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.h +++ b/drivers/net/wireless/rt2x00/rt2500usb.h @@ -57,7 +57,9 @@ #define CSR_REG_SIZE 0x0100 #define EEPROM_BASE 0x0000 #define EEPROM_SIZE 0x006a +#define BBP_BASE 0x0000 #define BBP_SIZE 0x0060 +#define RF_BASE 0x0000 #define RF_SIZE 0x0014 /* @@ -445,6 +447,9 @@ #define SEC_CSR30 0x04bc #define SEC_CSR31 0x04be +#define KEY_ENTRY(__idx) \ + ( SEC_CSR0 + ((__idx) * 16) ) + /* * PHY control registers. */ diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 1359a3768404b89b70e3908f2f297a46d9f30745..39ecf3b82ca1ca0b6895be3eb266c883b9e2e42f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -44,7 +44,7 @@ /* * Module information. */ -#define DRV_VERSION "2.2.1" +#define DRV_VERSION "2.2.3" #define DRV_PROJECT "http://rt2x00.serialmonkey.com" /* @@ -91,6 +91,16 @@ #define EEPROM(__dev, __msg, __args...) \ DEBUG_PRINTK(__dev, KERN_DEBUG, "EEPROM recovery", __msg, ##__args) +/* + * Duration calculations + * The rate variable passed is: 100kbs. + * To convert from bytes to bits we multiply size with 8, + * then the size is multiplied with 10 to make the + * real rate -> rate argument correction. + */ +#define GET_DURATION(__size, __rate) (((__size) * 8 * 10) / (__rate)) +#define GET_DURATION_RES(__size, __rate)(((__size) * 8 * 10) % (__rate)) + /* * Standard timing and size defines. * These values should follow the ieee80211 specifications. @@ -109,9 +119,9 @@ #define DIFS ( PIFS + SLOT_TIME ) #define SHORT_DIFS ( SHORT_PIFS + SHORT_SLOT_TIME ) #define EIFS ( SIFS + DIFS + \ - (8 * (IEEE80211_HEADER + ACK_SIZE)) ) + GET_DURATION(IEEE80211_HEADER + ACK_SIZE, 10) ) #define SHORT_EIFS ( SIFS + SHORT_DIFS + \ - (8 * (IEEE80211_HEADER + ACK_SIZE)) ) + GET_DURATION(IEEE80211_HEADER + ACK_SIZE, 10) ) /* * Chipset identification @@ -347,13 +357,6 @@ struct rt2x00_intf { */ spinlock_t lock; - /* - * BSS configuration. Copied from the structure - * passed to us through the bss_info_changed() - * callback funtion. - */ - struct ieee80211_bss_conf conf; - /* * MAC of the device. */ @@ -433,18 +436,6 @@ struct rt2x00lib_conf { struct rf_channel rf; struct channel_info channel; - - struct antenna_setup ant; - - enum ieee80211_band band; - - u32 basic_rates; - u32 slot_time; - - short sifs; - short pifs; - short difs; - short eifs; }; /* @@ -456,6 +447,15 @@ struct rt2x00lib_erp { int ack_timeout; int ack_consume_time; + + u64 basic_rates; + + int slot_time; + + short sifs; + short pifs; + short difs; + short eifs; }; /* @@ -533,10 +533,8 @@ struct rt2x00lib_ops { /* * queue initialization handlers */ - void (*init_rxentry) (struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry); - void (*init_txentry) (struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry); + bool (*get_entry_state) (struct queue_entry *entry); + void (*clear_entry) (struct queue_entry *entry); /* * Radio control handlers. @@ -557,8 +555,7 @@ struct rt2x00lib_ops { struct txentry_desc *txdesc); int (*write_tx_data) (struct queue_entry *entry); void (*write_beacon) (struct queue_entry *entry); - int (*get_tx_data_len) (struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb); + int (*get_tx_data_len) (struct queue_entry *entry); void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev, const enum data_queue_qid queue); @@ -589,16 +586,11 @@ struct rt2x00lib_ops { void (*config_erp) (struct rt2x00_dev *rt2x00dev, struct rt2x00lib_erp *erp); + void (*config_ant) (struct rt2x00_dev *rt2x00dev, + struct antenna_setup *ant); void (*config) (struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf, - const unsigned int flags); -#define CONFIG_UPDATE_PHYMODE ( 1 << 1 ) -#define CONFIG_UPDATE_CHANNEL ( 1 << 2 ) -#define CONFIG_UPDATE_TXPOWER ( 1 << 3 ) -#define CONFIG_UPDATE_ANTENNA ( 1 << 4 ) -#define CONFIG_UPDATE_SLOT_TIME ( 1 << 5 ) -#define CONFIG_UPDATE_BEACON_INT ( 1 << 6 ) -#define CONFIG_UPDATE_ALL 0xffff + const unsigned int changed_flags); }; /* @@ -661,6 +653,7 @@ enum rt2x00_flags { CONFIG_EXTERNAL_LNA_BG, CONFIG_DOUBLE_ANTENNA, CONFIG_DISABLE_LINK_TUNING, + CONFIG_CRYPTO_COPY_IV, }; /* @@ -738,8 +731,7 @@ struct rt2x00_dev { /* * This is the default TX/RX antenna setup as indicated - * by the device's EEPROM. When mac80211 sets its - * antenna value to 0 we should be using these values. + * by the device's EEPROM. */ struct antenna_setup default_ant; @@ -754,16 +746,15 @@ struct rt2x00_dev { } csr; /* - * Mutex to protect register accesses on USB devices. - * There are 2 reasons this is needed, one is to ensure - * use of the csr_cache (for USB devices) by one thread - * isn't corrupted by another thread trying to access it. - * The other is that access to BBP and RF registers - * require multiple BUS transactions and if another thread - * attempted to access one of those registers at the same - * time one of the writes could silently fail. + * Mutex to protect register accesses. + * For PCI and USB devices it protects against concurrent indirect + * register access (BBP, RF, MCU) since accessing those + * registers require multiple calls to the CSR registers. + * For USB devices it also protects the csr_cache since that + * field is used for normal CSR access and it cannot support + * multiple callers simultaneously. */ - struct mutex usb_cache_mutex; + struct mutex csr_mutex; /* * Current packet filter configuration for the device. @@ -808,14 +799,15 @@ struct rt2x00_dev { short lna_gain; /* - * USB Max frame size (for rt2500usb & rt73usb). + * Current TX power value. */ - u16 usb_maxpacket; + u16 tx_power; /* - * Current TX power value. + * Current retry values. */ - u16 tx_power; + u8 short_retry; + u8 long_retry; /* * Rssi <-> Dbm offset @@ -938,23 +930,6 @@ static inline u16 rt2x00_check_rev(const struct rt2x00_chip *chipset, !!(chipset->rev & 0x0000f)); } -/* - * Duration calculations - * The rate variable passed is: 100kbs. - * To convert from bytes to bits we multiply size with 8, - * then the size is multiplied with 10 to make the - * real rate -> rate argument correction. - */ -static inline u16 get_duration(const unsigned int size, const u8 rate) -{ - return ((size * 8 * 10) / rate); -} - -static inline u16 get_duration_res(const unsigned int size, const u8 rate) -{ - return ((size * 8 * 10) % rate); -} - /** * rt2x00queue_map_txskb - Map a skb into DMA for TX purposes. * @rt2x00dev: Pointer to &struct rt2x00_dev. @@ -997,7 +972,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); void rt2x00mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); -int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf); +int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed); int rt2x00mac_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_if_conf *conf); diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 4d5e87b015a079f065acd0f4215ec91a94f37d0e..e66fb316cd61fda7fae8add82217d06e01213628 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -86,13 +86,14 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, erp.short_preamble = bss_conf->use_short_preamble; erp.cts_protection = bss_conf->use_cts_prot; - erp.ack_timeout = PLCP + get_duration(ACK_SIZE, 10); - erp.ack_consume_time = SIFS + PLCP + get_duration(ACK_SIZE, 10); + erp.slot_time = bss_conf->use_short_slot ? SHORT_SLOT_TIME : SLOT_TIME; + erp.sifs = SIFS; + erp.pifs = bss_conf->use_short_slot ? SHORT_PIFS : PIFS; + erp.difs = bss_conf->use_short_slot ? SHORT_DIFS : DIFS; + erp.eifs = bss_conf->use_short_slot ? SHORT_EIFS : EIFS; - if (rt2x00dev->hw->conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME) - erp.ack_timeout += SHORT_DIFS; - else - erp.ack_timeout += DIFS; + erp.ack_timeout = PLCP + erp.difs + GET_DURATION(ACK_SIZE, 10); + erp.ack_consume_time = SIFS + PLCP + GET_DURATION(ACK_SIZE, 10); if (bss_conf->use_short_preamble) { erp.ack_timeout += SHORT_PREAMBLE; @@ -102,19 +103,39 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, erp.ack_consume_time += PREAMBLE; } + erp.basic_rates = bss_conf->basic_rates; + rt2x00dev->ops->lib->config_erp(rt2x00dev, &erp); } +static inline +enum antenna rt2x00lib_config_antenna_check(enum antenna current_ant, + enum antenna default_ant) +{ + if (current_ant != ANTENNA_SW_DIVERSITY) + return current_ant; + return (default_ant != ANTENNA_SW_DIVERSITY) ? default_ant : ANTENNA_B; +} + void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, - enum antenna rx, enum antenna tx) + struct antenna_setup *ant) { - struct rt2x00lib_conf libconf; + struct antenna_setup *def = &rt2x00dev->default_ant; + struct antenna_setup *active = &rt2x00dev->link.ant.active; - libconf.ant.rx = rx; - libconf.ant.tx = tx; + /* + * Failsafe: Make sure we are not sending the + * ANTENNA_SW_DIVERSITY state to the driver. + * If that happes fallback to hardware default, + * or our own default. + * The calls to rt2x00lib_config_antenna_check() + * might have caused that we restore back to the already + * active setting. If that has happened we can quit. + */ + ant->rx = rt2x00lib_config_antenna_check(ant->rx, def->rx); + ant->tx = rt2x00lib_config_antenna_check(ant->tx, def->tx); - if (rx == rt2x00dev->link.ant.active.rx && - tx == rt2x00dev->link.ant.active.tx) + if (ant->rx == active->rx && ant->tx == active->tx) return; /* @@ -129,119 +150,28 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, * The latter is required since we need to recalibrate the * noise-sensitivity ratio for the new setup. */ - rt2x00dev->ops->lib->config(rt2x00dev, &libconf, CONFIG_UPDATE_ANTENNA); + rt2x00dev->ops->lib->config_ant(rt2x00dev, ant); + rt2x00lib_reset_link_tuner(rt2x00dev); rt2x00_reset_link_ant_rssi(&rt2x00dev->link); - rt2x00dev->link.ant.active.rx = libconf.ant.rx; - rt2x00dev->link.ant.active.tx = libconf.ant.tx; + memcpy(active, ant, sizeof(*ant)); if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK); } -static u32 rt2x00lib_get_basic_rates(struct ieee80211_supported_band *band) -{ - const struct rt2x00_rate *rate; - unsigned int i; - u32 mask = 0; - - for (i = 0; i < band->n_bitrates; i++) { - rate = rt2x00_get_rate(band->bitrates[i].hw_value); - if (rate->flags & DEV_RATE_BASIC) - mask |= rate->ratemask; - } - - return mask; -} - void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, - struct ieee80211_conf *conf, const int force_config) + struct ieee80211_conf *conf, + unsigned int ieee80211_flags) { struct rt2x00lib_conf libconf; - struct ieee80211_supported_band *band; - struct antenna_setup *default_ant = &rt2x00dev->default_ant; - struct antenna_setup *active_ant = &rt2x00dev->link.ant.active; - int flags = 0; - int short_slot_time; - - /* - * In some situations we want to force all configurations - * to be reloaded (When resuming for instance). - */ - if (force_config) { - flags = CONFIG_UPDATE_ALL; - goto config; - } - /* - * Check which configuration options have been - * updated and should be send to the device. - */ - if (rt2x00dev->rx_status.band != conf->channel->band) - flags |= CONFIG_UPDATE_PHYMODE; - if (rt2x00dev->rx_status.freq != conf->channel->center_freq) - flags |= CONFIG_UPDATE_CHANNEL; - if (rt2x00dev->tx_power != conf->power_level) - flags |= CONFIG_UPDATE_TXPOWER; - - /* - * Determining changes in the antenna setups request several checks: - * antenna_sel_{r,t}x = 0 - * -> Does active_{r,t}x match default_{r,t}x - * -> Is default_{r,t}x SW_DIVERSITY - * antenna_sel_{r,t}x = 1/2 - * -> Does active_{r,t}x match antenna_sel_{r,t}x - * The reason for not updating the antenna while SW diversity - * should be used is simple: Software diversity means that - * we should switch between the antenna's based on the - * quality. This means that the current antenna is good enough - * to work with untill the link tuner decides that an antenna - * switch should be performed. - */ - if (!conf->antenna_sel_rx && - default_ant->rx != ANTENNA_SW_DIVERSITY && - default_ant->rx != active_ant->rx) - flags |= CONFIG_UPDATE_ANTENNA; - else if (conf->antenna_sel_rx && - conf->antenna_sel_rx != active_ant->rx) - flags |= CONFIG_UPDATE_ANTENNA; - else if (active_ant->rx == ANTENNA_SW_DIVERSITY) - flags |= CONFIG_UPDATE_ANTENNA; - - if (!conf->antenna_sel_tx && - default_ant->tx != ANTENNA_SW_DIVERSITY && - default_ant->tx != active_ant->tx) - flags |= CONFIG_UPDATE_ANTENNA; - else if (conf->antenna_sel_tx && - conf->antenna_sel_tx != active_ant->tx) - flags |= CONFIG_UPDATE_ANTENNA; - else if (active_ant->tx == ANTENNA_SW_DIVERSITY) - flags |= CONFIG_UPDATE_ANTENNA; - - /* - * The following configuration options are never - * stored anywhere and will always be updated. - */ - flags |= CONFIG_UPDATE_SLOT_TIME; - flags |= CONFIG_UPDATE_BEACON_INT; - - /* - * We have determined what options should be updated, - * now precalculate device configuration values depending - * on what configuration options need to be updated. - */ -config: memset(&libconf, 0, sizeof(libconf)); - if (flags & CONFIG_UPDATE_PHYMODE) { - band = &rt2x00dev->bands[conf->channel->band]; - - libconf.band = conf->channel->band; - libconf.basic_rates = rt2x00lib_get_basic_rates(band); - } + libconf.conf = conf; - if (flags & CONFIG_UPDATE_CHANNEL) { + if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) { memcpy(&libconf.rf, &rt2x00dev->spec.channels[conf->channel->hw_value], sizeof(libconf.rf)); @@ -251,61 +181,23 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, sizeof(libconf.channel)); } - if (flags & CONFIG_UPDATE_ANTENNA) { - if (conf->antenna_sel_rx) - libconf.ant.rx = conf->antenna_sel_rx; - else if (default_ant->rx != ANTENNA_SW_DIVERSITY) - libconf.ant.rx = default_ant->rx; - else if (active_ant->rx == ANTENNA_SW_DIVERSITY) - libconf.ant.rx = ANTENNA_B; - else - libconf.ant.rx = active_ant->rx; - - if (conf->antenna_sel_tx) - libconf.ant.tx = conf->antenna_sel_tx; - else if (default_ant->tx != ANTENNA_SW_DIVERSITY) - libconf.ant.tx = default_ant->tx; - else if (active_ant->tx == ANTENNA_SW_DIVERSITY) - libconf.ant.tx = ANTENNA_B; - else - libconf.ant.tx = active_ant->tx; - } - - if (flags & CONFIG_UPDATE_SLOT_TIME) { - short_slot_time = conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME; - - libconf.slot_time = - short_slot_time ? SHORT_SLOT_TIME : SLOT_TIME; - libconf.sifs = SIFS; - libconf.pifs = short_slot_time ? SHORT_PIFS : PIFS; - libconf.difs = short_slot_time ? SHORT_DIFS : DIFS; - libconf.eifs = short_slot_time ? SHORT_EIFS : EIFS; - } - - libconf.conf = conf; - /* * Start configuration. */ - rt2x00dev->ops->lib->config(rt2x00dev, &libconf, flags); + rt2x00dev->ops->lib->config(rt2x00dev, &libconf, ieee80211_flags); /* * Some configuration changes affect the link quality * which means we need to reset the link tuner. */ - if (flags & (CONFIG_UPDATE_CHANNEL | CONFIG_UPDATE_ANTENNA)) + if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) rt2x00lib_reset_link_tuner(rt2x00dev); - if (flags & CONFIG_UPDATE_PHYMODE) { - rt2x00dev->curr_band = conf->channel->band; - rt2x00dev->rx_status.band = conf->channel->band; - } - - rt2x00dev->rx_status.freq = conf->channel->center_freq; + rt2x00dev->curr_band = conf->channel->band; rt2x00dev->tx_power = conf->power_level; + rt2x00dev->short_retry = conf->short_frame_max_tx_count; + rt2x00dev->long_retry = conf->long_frame_max_tx_count; - if (flags & CONFIG_UPDATE_ANTENNA) { - rt2x00dev->link.ant.active.rx = libconf.ant.rx; - rt2x00dev->link.ant.active.tx = libconf.ant.tx; - } + rt2x00dev->rx_status.band = conf->channel->band; + rt2x00dev->rx_status.freq = conf->channel->center_freq; } diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c index 5a858e5106c4c618969080242cf524b345923d0e..37ad0d2fb64c46c0210d17ee5f8fb4462187ad60 100644 --- a/drivers/net/wireless/rt2x00/rt2x00crypto.c +++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c @@ -46,6 +46,29 @@ enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key) } } +void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry, + struct txentry_desc *txdesc) +{ + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); + struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; + + __set_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags); + + txdesc->cipher = rt2x00crypto_key_to_cipher(hw_key); + + if (hw_key->flags & IEEE80211_KEY_FLAG_PAIRWISE) + __set_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags); + + txdesc->key_idx = hw_key->hw_key_idx; + txdesc->iv_offset = ieee80211_get_hdrlen_from_skb(entry->skb); + + if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) + __set_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags); + + if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) + __set_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags); +} + unsigned int rt2x00crypto_tx_overhead(struct ieee80211_tx_info *tx_info) { struct ieee80211_key_conf *key = tx_info->control.hw_key; @@ -69,6 +92,18 @@ unsigned int rt2x00crypto_tx_overhead(struct ieee80211_tx_info *tx_info) return overhead; } +void rt2x00crypto_tx_copy_iv(struct sk_buff *skb, unsigned int iv_len) +{ + struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); + unsigned int header_length = ieee80211_get_hdrlen_from_skb(skb); + + if (unlikely(!iv_len)) + return; + + /* Copy IV/EIV data */ + memcpy(skbdesc->iv, skb->data + header_length, iv_len); +} + void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, unsigned int iv_len) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); @@ -78,10 +113,7 @@ void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, unsigned int iv_len) return; /* Copy IV/EIV data */ - if (iv_len >= 4) - memcpy(&skbdesc->iv, skb->data + header_length, 4); - if (iv_len >= 8) - memcpy(&skbdesc->eiv, skb->data + header_length + 4, 4); + memcpy(skbdesc->iv, skb->data + header_length, iv_len); /* Move ieee80211 header */ memmove(skb->data + iv_len, skb->data, header_length); @@ -98,7 +130,7 @@ void rt2x00crypto_tx_insert_iv(struct sk_buff *skb) struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); unsigned int header_length = ieee80211_get_hdrlen_from_skb(skb); const unsigned int iv_len = - ((!!(skbdesc->iv)) * 4) + ((!!(skbdesc->eiv)) * 4); + ((!!(skbdesc->iv[0])) * 4) + ((!!(skbdesc->iv[1])) * 4); if (!(skbdesc->flags & FRAME_DESC_IV_STRIPPED)) return; @@ -109,10 +141,7 @@ void rt2x00crypto_tx_insert_iv(struct sk_buff *skb) memmove(skb->data, skb->data + iv_len, header_length); /* Copy IV/EIV data */ - if (iv_len >= 4) - memcpy(skb->data + header_length, &skbdesc->iv, 4); - if (iv_len >= 8) - memcpy(skb->data + header_length + 4, &skbdesc->eiv, 4); + memcpy(skb->data + header_length, skbdesc->iv, iv_len); /* IV/EIV data has returned into the frame */ skbdesc->flags &= ~FRAME_DESC_IV_STRIPPED; @@ -172,17 +201,9 @@ void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, unsigned int align, header_length); transfer += header_length; - /* Copy IV data */ - if (iv_len >= 4) { - memcpy(skb->data + transfer, &rxdesc->iv, 4); - transfer += 4; - } - - /* Copy EIV data */ - if (iv_len >= 8) { - memcpy(skb->data + transfer, &rxdesc->eiv, 4); - transfer += 4; - } + /* Copy IV/EIV data */ + memcpy(skb->data + transfer, rxdesc->iv, iv_len); + transfer += iv_len; /* Move payload */ if (align) { @@ -198,16 +219,14 @@ void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, unsigned int align, */ transfer += payload_len; - /* Copy ICV data */ - if (icv_len >= 4) { - memcpy(skb->data + transfer, &rxdesc->icv, 4); - /* - * AES appends 8 bytes, we can't fill the upper - * 4 bytes, but mac80211 doesn't care about what - * we provide here anyway and strips it immediately. - */ - transfer += icv_len; - } + /* + * Copy ICV data + * AES appends 8 bytes, we can't fill the upper + * 4 bytes, but mac80211 doesn't care about what + * we provide here anyway and strips it immediately. + */ + memcpy(skb->data + transfer, &rxdesc->icv, 4); + transfer += icv_len; /* IV/EIV/ICV has been inserted into frame */ rxdesc->size = transfer; diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index 5cf4c859e39d741ec6dfe4595523065ee25e5125..54dd10060bf1a56a8b318ee5e135463b796cc358 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c @@ -285,7 +285,7 @@ static ssize_t rt2x00debug_read_queue_dump(struct file *file, } static unsigned int rt2x00debug_poll_queue_dump(struct file *file, - poll_table *wait) + poll_table *wait) { struct rt2x00debug_intf *intf = file->private_data; @@ -377,7 +377,7 @@ static ssize_t rt2x00debug_read_crypto_stats(struct file *file, if (*offset) return 0; - data = kzalloc((1 + CIPHER_MAX)* MAX_LINE_LENGTH, GFP_KERNEL); + data = kzalloc((1 + CIPHER_MAX) * MAX_LINE_LENGTH, GFP_KERNEL); if (!data) return -ENOMEM; @@ -424,16 +424,21 @@ static ssize_t rt2x00debug_read_##__name(struct file *file, \ const struct rt2x00debug *debug = intf->debug; \ char line[16]; \ size_t size; \ + unsigned int index = intf->offset_##__name; \ __type value; \ \ if (*offset) \ return 0; \ \ - if (intf->offset_##__name >= debug->__name.word_count) \ + if (index >= debug->__name.word_count) \ return -EINVAL; \ \ - debug->__name.read(intf->rt2x00dev, \ - intf->offset_##__name, &value); \ + if (debug->__name.flags & RT2X00DEBUGFS_OFFSET) \ + index *= debug->__name.word_size; \ + \ + index += debug->__name.word_base; \ + \ + debug->__name.read(intf->rt2x00dev, index, &value); \ \ size = sprintf(line, __format, value); \ \ @@ -454,12 +459,13 @@ static ssize_t rt2x00debug_write_##__name(struct file *file, \ const struct rt2x00debug *debug = intf->debug; \ char line[16]; \ size_t size; \ + unsigned int index = intf->offset_##__name; \ __type value; \ \ if (*offset) \ return 0; \ \ - if (intf->offset_##__name >= debug->__name.word_count) \ + if (index >= debug->__name.word_count) \ return -EINVAL; \ \ if (copy_from_user(line, buf, length)) \ @@ -468,8 +474,12 @@ static ssize_t rt2x00debug_write_##__name(struct file *file, \ size = strlen(line); \ value = simple_strtoul(line, NULL, 0); \ \ - debug->__name.write(intf->rt2x00dev, \ - intf->offset_##__name, value); \ + if (debug->__name.flags & RT2X00DEBUGFS_OFFSET) \ + index *= debug->__name.word_size; \ + \ + index += debug->__name.word_base; \ + \ + debug->__name.write(intf->rt2x00dev, index, value); \ \ *offset += size; \ return size; \ @@ -587,29 +597,29 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) intf->driver_folder = debugfs_create_dir(intf->rt2x00dev->ops->name, rt2x00dev->hw->wiphy->debugfsdir); - if (IS_ERR(intf->driver_folder)) + if (IS_ERR(intf->driver_folder) || !intf->driver_folder) goto exit; intf->driver_entry = rt2x00debug_create_file_driver("driver", intf, &intf->driver_blob); - if (IS_ERR(intf->driver_entry)) + if (IS_ERR(intf->driver_entry) || !intf->driver_entry) goto exit; intf->chipset_entry = rt2x00debug_create_file_chipset("chipset", intf, &intf->chipset_blob); - if (IS_ERR(intf->chipset_entry)) + if (IS_ERR(intf->chipset_entry) || !intf->chipset_entry) goto exit; intf->dev_flags = debugfs_create_file("dev_flags", S_IRUSR, intf->driver_folder, intf, &rt2x00debug_fop_dev_flags); - if (IS_ERR(intf->dev_flags)) + if (IS_ERR(intf->dev_flags) || !intf->dev_flags) goto exit; intf->register_folder = debugfs_create_dir("register", intf->driver_folder); - if (IS_ERR(intf->register_folder)) + if (IS_ERR(intf->register_folder) || !intf->register_folder) goto exit; #define RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(__intf, __name) \ @@ -619,7 +629,8 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) S_IRUSR | S_IWUSR, \ (__intf)->register_folder, \ &(__intf)->offset_##__name); \ - if (IS_ERR((__intf)->__name##_off_entry)) \ + if (IS_ERR((__intf)->__name##_off_entry) \ + || !(__intf)->__name##_off_entry) \ goto exit; \ \ (__intf)->__name##_val_entry = \ @@ -627,7 +638,8 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) S_IRUSR | S_IWUSR, \ (__intf)->register_folder, \ (__intf), &rt2x00debug_fop_##__name);\ - if (IS_ERR((__intf)->__name##_val_entry)) \ + if (IS_ERR((__intf)->__name##_val_entry) \ + || !(__intf)->__name##_val_entry) \ goto exit; \ }) @@ -640,13 +652,14 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) intf->queue_folder = debugfs_create_dir("queue", intf->driver_folder); - if (IS_ERR(intf->queue_folder)) + if (IS_ERR(intf->queue_folder) || !intf->queue_folder) goto exit; intf->queue_frame_dump_entry = debugfs_create_file("dump", S_IRUSR, intf->queue_folder, intf, &rt2x00debug_fop_queue_dump); - if (IS_ERR(intf->queue_frame_dump_entry)) + if (IS_ERR(intf->queue_frame_dump_entry) + || !intf->queue_frame_dump_entry) goto exit; skb_queue_head_init(&intf->frame_dump_skbqueue); diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.h b/drivers/net/wireless/rt2x00/rt2x00debug.h index c4ce895aa1c70776100b66536fe54064d2368125..a92104dfee9a6836d90b7ee2270b3c407fc873e8 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.h +++ b/drivers/net/wireless/rt2x00/rt2x00debug.h @@ -28,6 +28,16 @@ struct rt2x00_dev; +/** + * enum rt2x00debugfs_entry_flags: Flags for debugfs registry entry + * + * @RT2X00DEBUGFS_OFFSET: rt2x00lib should pass the register offset + * as argument when using the callback function read()/write() + */ +enum rt2x00debugfs_entry_flags { + RT2X00DEBUGFS_OFFSET = (1 << 0), +}; + #define RT2X00DEBUGFS_REGISTER_ENTRY(__name, __type) \ struct reg##__name { \ void (*read)(struct rt2x00_dev *rt2x00dev, \ @@ -35,6 +45,9 @@ struct reg##__name { \ void (*write)(struct rt2x00_dev *rt2x00dev, \ const unsigned int word, __type data); \ \ + unsigned int flags; \ + \ + unsigned int word_base; \ unsigned int word_size; \ unsigned int word_count; \ } __name diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 86840e3585e82e7825072641f112a679434e4c0a..6d92542fcf0da8c509846726e230b0a40d839d84 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -101,8 +101,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) /* * Initialize all data queues. */ - rt2x00queue_init_rx(rt2x00dev); - rt2x00queue_init_tx(rt2x00dev); + rt2x00queue_init_queues(rt2x00dev); /* * Enable radio. @@ -176,13 +175,14 @@ void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, enum dev_state state) static void rt2x00lib_evaluate_antenna_sample(struct rt2x00_dev *rt2x00dev) { - enum antenna rx = rt2x00dev->link.ant.active.rx; - enum antenna tx = rt2x00dev->link.ant.active.tx; + struct antenna_setup ant; int sample_a = rt2x00_get_link_ant_rssi_history(&rt2x00dev->link, ANTENNA_A); int sample_b = rt2x00_get_link_ant_rssi_history(&rt2x00dev->link, ANTENNA_B); + memcpy(&ant, &rt2x00dev->link.ant.active, sizeof(ant)); + /* * We are done sampling. Now we should evaluate the results. */ @@ -200,21 +200,22 @@ static void rt2x00lib_evaluate_antenna_sample(struct rt2x00_dev *rt2x00dev) return; if (rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY) - rx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B; + ant.rx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B; if (rt2x00dev->link.ant.flags & ANTENNA_TX_DIVERSITY) - tx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B; + ant.tx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B; - rt2x00lib_config_antenna(rt2x00dev, rx, tx); + rt2x00lib_config_antenna(rt2x00dev, &ant); } static void rt2x00lib_evaluate_antenna_eval(struct rt2x00_dev *rt2x00dev) { - enum antenna rx = rt2x00dev->link.ant.active.rx; - enum antenna tx = rt2x00dev->link.ant.active.tx; + struct antenna_setup ant; int rssi_curr = rt2x00_get_link_ant_rssi(&rt2x00dev->link); int rssi_old = rt2x00_update_ant_rssi(&rt2x00dev->link, rssi_curr); + memcpy(&ant, &rt2x00dev->link.ant.active, sizeof(ant)); + /* * Legacy driver indicates that we should swap antenna's * when the difference in RSSI is greater that 5. This @@ -230,12 +231,12 @@ static void rt2x00lib_evaluate_antenna_eval(struct rt2x00_dev *rt2x00dev) rt2x00dev->link.ant.flags |= ANTENNA_MODE_SAMPLE; if (rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY) - rx = (rx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A; + ant.rx = (ant.rx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A; if (rt2x00dev->link.ant.flags & ANTENNA_TX_DIVERSITY) - tx = (tx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A; + ant.tx = (ant.tx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A; - rt2x00lib_config_antenna(rt2x00dev, rx, tx); + rt2x00lib_config_antenna(rt2x00dev, &ant); } static void rt2x00lib_evaluate_antenna(struct rt2x00_dev *rt2x00dev) @@ -249,11 +250,9 @@ static void rt2x00lib_evaluate_antenna(struct rt2x00_dev *rt2x00dev) rt2x00dev->link.ant.flags &= ~ANTENNA_RX_DIVERSITY; rt2x00dev->link.ant.flags &= ~ANTENNA_TX_DIVERSITY; - if (rt2x00dev->hw->conf.antenna_sel_rx == 0 && - rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY) + if (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY) rt2x00dev->link.ant.flags |= ANTENNA_RX_DIVERSITY; - if (rt2x00dev->hw->conf.antenna_sel_tx == 0 && - rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY) + if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY) rt2x00dev->link.ant.flags |= ANTENNA_TX_DIVERSITY; if (!(rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY) && @@ -419,7 +418,7 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac, */ spin_lock(&intf->lock); - memcpy(&conf, &intf->conf, sizeof(conf)); + memcpy(&conf, &vif->bss_conf, sizeof(conf)); delayed_flags = intf->delayed_flags; intf->delayed_flags = 0; @@ -500,7 +499,9 @@ void rt2x00lib_txdone(struct queue_entry *entry, { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); enum data_queue_qid qid = skb_get_queue_mapping(entry->skb); + u8 rate_idx, rate_flags; /* * Unmap the skb. @@ -530,14 +531,18 @@ void rt2x00lib_txdone(struct queue_entry *entry, rt2x00dev->link.qual.tx_failed += test_bit(TXDONE_FAILURE, &txdesc->flags); + rate_idx = skbdesc->tx_rate_idx; + rate_flags = skbdesc->tx_rate_flags; + /* * Initialize TX status */ memset(&tx_info->status, 0, sizeof(tx_info->status)); tx_info->status.ack_signal = 0; - tx_info->status.excessive_retries = - test_bit(TXDONE_EXCESSIVE_RETRY, &txdesc->flags); - tx_info->status.retry_count = txdesc->retry; + tx_info->status.rates[0].idx = rate_idx; + tx_info->status.rates[0].flags = rate_flags; + tx_info->status.rates[0].count = txdesc->retry + 1; + tx_info->status.rates[1].idx = -1; /* terminate */ if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) { if (test_bit(TXDONE_SUCCESS, &txdesc->flags)) @@ -546,7 +551,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, rt2x00dev->low_level_stats.dot11ACKFailureCount++; } - if (tx_info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { + if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) { if (test_bit(TXDONE_SUCCESS, &txdesc->flags)) rt2x00dev->low_level_stats.dot11RTSSuccessCount++; else if (test_bit(TXDONE_FAILURE, &txdesc->flags)) @@ -570,7 +575,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, entry->skb = NULL; entry->flags = 0; - rt2x00dev->ops->lib->init_txentry(rt2x00dev, entry); + rt2x00dev->ops->lib->clear_entry(entry); clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE); @@ -631,7 +636,8 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, * provided seperately (through hardware descriptor) * in which case we should reinsert the data into the frame. */ - if ((rxdesc.flags & RX_FLAG_IV_STRIPPED)) { + if ((rxdesc.dev_flags & RXDONE_CRYPTO_IV) && + (rxdesc.flags & RX_FLAG_IV_STRIPPED)) { rt2x00crypto_rx_insert_iv(entry->skb, align, header_length, &rxdesc); } else if (align) { @@ -702,7 +708,7 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, entry->skb = skb; entry->flags = 0; - rt2x00dev->ops->lib->init_rxentry(rt2x00dev, entry); + rt2x00dev->ops->lib->clear_entry(entry); rt2x00queue_index_inc(entry->queue, Q_INDEX); } @@ -713,31 +719,31 @@ EXPORT_SYMBOL_GPL(rt2x00lib_rxdone); */ const struct rt2x00_rate rt2x00_supported_rates[12] = { { - .flags = DEV_RATE_CCK | DEV_RATE_BASIC, + .flags = DEV_RATE_CCK, .bitrate = 10, .ratemask = BIT(0), .plcp = 0x00, }, { - .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE | DEV_RATE_BASIC, + .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE, .bitrate = 20, .ratemask = BIT(1), .plcp = 0x01, }, { - .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE | DEV_RATE_BASIC, + .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE, .bitrate = 55, .ratemask = BIT(2), .plcp = 0x02, }, { - .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE | DEV_RATE_BASIC, + .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE, .bitrate = 110, .ratemask = BIT(3), .plcp = 0x03, }, { - .flags = DEV_RATE_OFDM | DEV_RATE_BASIC, + .flags = DEV_RATE_OFDM, .bitrate = 60, .ratemask = BIT(4), .plcp = 0x0b, @@ -749,7 +755,7 @@ const struct rt2x00_rate rt2x00_supported_rates[12] = { .plcp = 0x0f, }, { - .flags = DEV_RATE_OFDM | DEV_RATE_BASIC, + .flags = DEV_RATE_OFDM, .bitrate = 120, .ratemask = BIT(6), .plcp = 0x0a, @@ -761,7 +767,7 @@ const struct rt2x00_rate rt2x00_supported_rates[12] = { .plcp = 0x0e, }, { - .flags = DEV_RATE_OFDM | DEV_RATE_BASIC, + .flags = DEV_RATE_OFDM, .bitrate = 240, .ratemask = BIT(8), .plcp = 0x09, @@ -1046,16 +1052,24 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) { int retval = -ENOMEM; + mutex_init(&rt2x00dev->csr_mutex); + /* * Make room for rt2x00_intf inside the per-interface * structure ieee80211_vif. */ rt2x00dev->hw->vif_data_size = sizeof(struct rt2x00_intf); - rt2x00dev->hw->wiphy->interface_modes = - BIT(NL80211_IFTYPE_AP) | - BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC); + /* + * Determine which operating modes are supported, all modes + * which require beaconing, depend on the availability of + * beacon entries. + */ + rt2x00dev->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + if (rt2x00dev->ops->bcn->entry_num > 0) + rt2x00dev->hw->wiphy->interface_modes |= + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_AP); /* * Let the driver probe the device to detect the capabilities. @@ -1247,7 +1261,7 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) /* * Reconfigure device. */ - retval = rt2x00mac_config(rt2x00dev->hw, &rt2x00dev->hw->conf); + retval = rt2x00mac_config(rt2x00dev->hw, ~0); if (retval) goto exit; diff --git a/drivers/net/wireless/rt2x00/rt2x00leds.c b/drivers/net/wireless/rt2x00/rt2x00leds.c index b362a1cf3f8dcac64d0de1e34b4cb956a73c0312..68f4e0fc35b9e057043b8423a5e752c4e3eb2441 100644 --- a/drivers/net/wireless/rt2x00/rt2x00leds.c +++ b/drivers/net/wireless/rt2x00/rt2x00leds.c @@ -72,49 +72,33 @@ void rt2x00leds_led_quality(struct rt2x00_dev *rt2x00dev, int rssi) } } -void rt2x00led_led_activity(struct rt2x00_dev *rt2x00dev, bool enabled) +static void rt2x00led_led_simple(struct rt2x00_led *led, bool enabled) { - struct rt2x00_led *led = &rt2x00dev->led_qual; - unsigned int brightness; + unsigned int brightness = enabled ? LED_FULL : LED_OFF; - if ((led->type != LED_TYPE_ACTIVITY) || !(led->flags & LED_REGISTERED)) + if (!(led->flags & LED_REGISTERED)) return; - brightness = enabled ? LED_FULL : LED_OFF; - if (brightness != led->led_dev.brightness) { - led->led_dev.brightness_set(&led->led_dev, brightness); - led->led_dev.brightness = brightness; - } + led->led_dev.brightness_set(&led->led_dev, brightness); + led->led_dev.brightness = brightness; } -void rt2x00leds_led_assoc(struct rt2x00_dev *rt2x00dev, bool enabled) +void rt2x00led_led_activity(struct rt2x00_dev *rt2x00dev, bool enabled) { - struct rt2x00_led *led = &rt2x00dev->led_assoc; - unsigned int brightness; - - if ((led->type != LED_TYPE_ASSOC) || !(led->flags & LED_REGISTERED)) - return; + if (rt2x00dev->led_qual.type == LED_TYPE_ACTIVITY) + rt2x00led_led_simple(&rt2x00dev->led_qual, enabled); +} - brightness = enabled ? LED_FULL : LED_OFF; - if (brightness != led->led_dev.brightness) { - led->led_dev.brightness_set(&led->led_dev, brightness); - led->led_dev.brightness = brightness; - } +void rt2x00leds_led_assoc(struct rt2x00_dev *rt2x00dev, bool enabled) +{ + if (rt2x00dev->led_assoc.type == LED_TYPE_ASSOC) + rt2x00led_led_simple(&rt2x00dev->led_assoc, enabled); } void rt2x00leds_led_radio(struct rt2x00_dev *rt2x00dev, bool enabled) { - struct rt2x00_led *led = &rt2x00dev->led_radio; - unsigned int brightness; - - if ((led->type != LED_TYPE_RADIO) || !(led->flags & LED_REGISTERED)) - return; - - brightness = enabled ? LED_FULL : LED_OFF; - if (brightness != led->led_dev.brightness) { - led->led_dev.brightness_set(&led->led_dev, brightness); - led->led_dev.brightness = brightness; - } + if (rt2x00dev->led_radio.type == LED_TYPE_ASSOC) + rt2x00led_led_simple(&rt2x00dev->led_radio, enabled); } static int rt2x00leds_register_led(struct rt2x00_dev *rt2x00dev, @@ -125,6 +109,7 @@ static int rt2x00leds_register_led(struct rt2x00_dev *rt2x00dev, int retval; led->led_dev.name = name; + led->led_dev.brightness = LED_OFF; retval = led_classdev_register(device, &led->led_dev); if (retval) { @@ -199,7 +184,16 @@ void rt2x00leds_register(struct rt2x00_dev *rt2x00dev) static void rt2x00leds_unregister_led(struct rt2x00_led *led) { led_classdev_unregister(&led->led_dev); - led->led_dev.brightness_set(&led->led_dev, LED_OFF); + + /* + * This might look weird, but when we are unregistering while + * suspended the led is already off, and since we haven't + * fully resumed yet, access to the device might not be + * possible yet. + */ + if (!(led->led_dev.flags & LED_SUSPENDED)) + led->led_dev.brightness_set(&led->led_dev, LED_OFF); + led->flags &= ~LED_REGISTERED; } @@ -213,22 +207,40 @@ void rt2x00leds_unregister(struct rt2x00_dev *rt2x00dev) rt2x00leds_unregister_led(&rt2x00dev->led_radio); } +static inline void rt2x00leds_suspend_led(struct rt2x00_led *led) +{ + led_classdev_suspend(&led->led_dev); + + /* This shouldn't be needed, but just to be safe */ + led->led_dev.brightness_set(&led->led_dev, LED_OFF); + led->led_dev.brightness = LED_OFF; +} + void rt2x00leds_suspend(struct rt2x00_dev *rt2x00dev) { if (rt2x00dev->led_qual.flags & LED_REGISTERED) - led_classdev_suspend(&rt2x00dev->led_qual.led_dev); + rt2x00leds_suspend_led(&rt2x00dev->led_qual); if (rt2x00dev->led_assoc.flags & LED_REGISTERED) - led_classdev_suspend(&rt2x00dev->led_assoc.led_dev); + rt2x00leds_suspend_led(&rt2x00dev->led_assoc); if (rt2x00dev->led_radio.flags & LED_REGISTERED) - led_classdev_suspend(&rt2x00dev->led_radio.led_dev); + rt2x00leds_suspend_led(&rt2x00dev->led_radio); +} + +static inline void rt2x00leds_resume_led(struct rt2x00_led *led) +{ + led_classdev_resume(&led->led_dev); + + /* Device might have enabled the LEDS during resume */ + led->led_dev.brightness_set(&led->led_dev, LED_OFF); + led->led_dev.brightness = LED_OFF; } void rt2x00leds_resume(struct rt2x00_dev *rt2x00dev) { if (rt2x00dev->led_radio.flags & LED_REGISTERED) - led_classdev_resume(&rt2x00dev->led_radio.led_dev); + rt2x00leds_resume_led(&rt2x00dev->led_radio); if (rt2x00dev->led_assoc.flags & LED_REGISTERED) - led_classdev_resume(&rt2x00dev->led_assoc.led_dev); + rt2x00leds_resume_led(&rt2x00dev->led_assoc); if (rt2x00dev->led_qual.flags & LED_REGISTERED) - led_classdev_resume(&rt2x00dev->led_qual.led_dev); + rt2x00leds_resume_led(&rt2x00dev->led_qual); } diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 797eb619aa0af918d9591fc56a9b4281448720b0..03024327767be6c83f23343914bed7e208840377 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -43,7 +43,6 @@ struct rt2x00_rate { #define DEV_RATE_CCK 0x0001 #define DEV_RATE_OFDM 0x0002 #define DEV_RATE_SHORT_PREAMBLE 0x0004 -#define DEV_RATE_BASIC 0x0008 unsigned short bitrate; /* In 100kbit/s */ unsigned short ratemask; @@ -94,9 +93,10 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, struct ieee80211_bss_conf *conf); void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, - enum antenna rx, enum antenna tx); + struct antenna_setup *ant); void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, - struct ieee80211_conf *conf, const int force_config); + struct ieee80211_conf *conf, + const unsigned int changed_flags); /** * DOC: Queue handlers @@ -150,8 +150,16 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, */ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index); -void rt2x00queue_init_rx(struct rt2x00_dev *rt2x00dev); -void rt2x00queue_init_tx(struct rt2x00_dev *rt2x00dev); +/** + * rt2x00queue_init_queues - Initialize all data queues + * @rt2x00dev: Pointer to &struct rt2x00_dev. + * + * This function will loop through all available queues to clear all + * index numbers and set the queue entry to the correct initialization + * state. + */ +void rt2x00queue_init_queues(struct rt2x00_dev *rt2x00dev); + int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev); void rt2x00queue_uninitialize(struct rt2x00_dev *rt2x00dev); int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev); @@ -210,7 +218,10 @@ static inline void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev, */ #ifdef CONFIG_RT2X00_LIB_CRYPTO enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key); +void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry, + struct txentry_desc *txdesc); unsigned int rt2x00crypto_tx_overhead(struct ieee80211_tx_info *tx_info); +void rt2x00crypto_tx_copy_iv(struct sk_buff *skb, unsigned int iv_len); void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, unsigned int iv_len); void rt2x00crypto_tx_insert_iv(struct sk_buff *skb); void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, unsigned int align, @@ -222,11 +233,21 @@ static inline enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf * return CIPHER_NONE; } +static inline void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry, + struct txentry_desc *txdesc) +{ +} + static inline unsigned int rt2x00crypto_tx_overhead(struct ieee80211_tx_info *tx_info) { return 0; } +static inline void rt2x00crypto_tx_copy_iv(struct sk_buff *skb, + unsigned int iv_len) +{ +} + static inline void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, unsigned int iv_len) { @@ -242,7 +263,7 @@ static inline void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, struct rxdone_entry_desc *rxdesc) { } -#endif +#endif /* CONFIG_RT2X00_LIB_CRYPTO */ /* * RFkill handlers. diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 2c6cc5c374ff3be765b681e07d17fede815a3d22..38edee5fe1683c1022e3739efa808e0292f61eea 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -39,7 +39,7 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, unsigned int data_length; int retval = 0; - if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) + if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) data_length = sizeof(struct ieee80211_cts); else data_length = sizeof(struct ieee80211_rts); @@ -64,11 +64,11 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, */ memcpy(skb->cb, frag_skb->cb, sizeof(skb->cb)); rts_info = IEEE80211_SKB_CB(skb); - rts_info->flags &= ~IEEE80211_TX_CTL_USE_RTS_CTS; - rts_info->flags &= ~IEEE80211_TX_CTL_USE_CTS_PROTECT; + rts_info->control.rates[0].flags &= ~IEEE80211_TX_RC_USE_RTS_CTS; + rts_info->control.rates[0].flags &= ~IEEE80211_TX_RC_USE_CTS_PROTECT; rts_info->flags &= ~IEEE80211_TX_CTL_REQ_TX_STATUS; - if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) + if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) rts_info->flags |= IEEE80211_TX_CTL_NO_ACK; else rts_info->flags &= ~IEEE80211_TX_CTL_NO_ACK; @@ -79,12 +79,10 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, * RTS/CTS frame should use the length of the frame plus any * encryption overhead that will be added by the hardware. */ -#ifdef CONFIG_RT2X00_LIB_CRYPTO if (!frag_skb->do_not_encrypt) data_length += rt2x00crypto_tx_overhead(tx_info); -#endif /* CONFIG_RT2X00_LIB_CRYPTO */ - if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) + if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) ieee80211_ctstoself_get(rt2x00dev->hw, tx_info->control.vif, frag_skb->data, data_length, tx_info, (struct ieee80211_cts *)(skb->data)); @@ -132,8 +130,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) ERROR(rt2x00dev, "Attempt to send packet over invalid queue %d.\n" "Please file bug report to %s.\n", qid, DRV_PROJECT); - dev_kfree_skb_any(skb); - return NETDEV_TX_OK; + goto exit_fail; } /* @@ -146,8 +143,8 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) * inside the hardware. */ frame_control = le16_to_cpu(ieee80211hdr->frame_control); - if ((tx_info->flags & (IEEE80211_TX_CTL_USE_RTS_CTS | - IEEE80211_TX_CTL_USE_CTS_PROTECT)) && + if ((tx_info->control.rates[0].flags & (IEEE80211_TX_RC_USE_RTS_CTS | + IEEE80211_TX_RC_USE_CTS_PROTECT)) && !rt2x00dev->ops->hw->set_rts_threshold) { if (rt2x00queue_available(queue) <= 1) goto exit_fail; @@ -335,10 +332,10 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw, } EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface); -int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed) { struct rt2x00_dev *rt2x00dev = hw->priv; - int radio_on; + struct ieee80211_conf *conf = &hw->conf; int status; /* @@ -355,7 +352,6 @@ int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) * some configuration parameters (e.g. channel and antenna values) can * only be set when the radio is enabled. */ - radio_on = test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags); if (conf->radio_enabled) { /* For programming the values, we have to turn RX off */ rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF); @@ -369,7 +365,18 @@ int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) * When we've just turned on the radio, we want to reprogram * everything to ensure a consistent state */ - rt2x00lib_config(rt2x00dev, conf, !radio_on); + rt2x00lib_config(rt2x00dev, conf, changed); + + /* + * The radio was enabled, configure the antenna to the + * default settings, the link tuner will later start + * continue configuring the antenna based on the software + * diversity. But for non-diversity configurations, we need + * to have configured the correct state now. + */ + if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) + rt2x00lib_config_antenna(rt2x00dev, + &rt2x00dev->default_ant); /* Turn RX back on */ rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON); @@ -480,12 +487,15 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_key_conf *key) { struct rt2x00_dev *rt2x00dev = hw->priv; + struct ieee80211_sta *sta; int (*set_key) (struct rt2x00_dev *rt2x00dev, struct rt2x00lib_crypto *crypto, struct ieee80211_key_conf *key); struct rt2x00lib_crypto crypto; - if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) + return 0; + else if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) return -EOPNOTSUPP; else if (key->keylen > 32) return -ENOSPC; @@ -527,6 +537,17 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, } else memcpy(&crypto.key, &key->key[0], key->keylen); + /* + * Discover the Association ID from mac80211. + * Some drivers need this information when updating the + * hardware key (either adding or removing). + */ + rcu_read_lock(); + sta = ieee80211_find_sta(hw, address); + if (sta) + crypto.aid = sta->aid; + rcu_read_unlock(); + /* * Each BSS has a maximum of 4 shared keys. * Shared key index values: @@ -625,7 +646,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, * When the erp information has changed, we should perform * additional configuration steps. For all other changes we are done. */ - if (changes & (BSS_CHANGED_ERP_PREAMBLE | BSS_CHANGED_ERP_CTS_PROT)) { + if (changes & ~(BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) { if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags)) rt2x00lib_config_erp(rt2x00dev, intf, bss_conf); else @@ -633,7 +654,6 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, } spin_lock(&intf->lock); - memcpy(&intf->conf, bss_conf, sizeof(*bss_conf)); if (delayed) { intf->delayed_flags |= delayed; schedule_work(&rt2x00dev->intf_work); diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index adf2876ed8ab77de00d5c3676b781d4c62edeabf..d52b22b82d1fb4662184b653efe50f99b43fec13 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -31,25 +31,47 @@ #include "rt2x00.h" #include "rt2x00pci.h" +/* + * Register access. + */ +int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + const struct rt2x00_field32 field, + u32 *reg) +{ + unsigned int i; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00pci_register_read(rt2x00dev, offset, reg); + if (!rt2x00_get_field32(*reg, field)) + return 1; + udelay(REGISTER_BUSY_DELAY); + } + + ERROR(rt2x00dev, "Indirect register access failed: " + "offset=0x%.08x, value=0x%.08x\n", offset, *reg); + *reg = ~0; + + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00pci_regbusy_read); + /* * TX data handlers. */ int rt2x00pci_write_tx_data(struct queue_entry *entry) { + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct queue_entry_priv_pci *entry_priv = entry->priv_data; struct skb_frame_desc *skbdesc; - u32 word; - - rt2x00_desc_read(entry_priv->desc, 0, &word); /* * This should not happen, we already checked the entry * was ours. When the hardware disagrees there has been * a queue corruption! */ - if (unlikely(rt2x00_get_field32(word, TXD_ENTRY_OWNER_NIC) || - rt2x00_get_field32(word, TXD_ENTRY_VALID))) { - ERROR(entry->queue->rt2x00dev, + if (unlikely(rt2x00dev->ops->lib->get_entry_state(entry))) { + ERROR(rt2x00dev, "Corrupt queue %d, accessing entry which is not ours.\n" "Please file bug report to %s.\n", entry->queue->qid, DRV_PROJECT); @@ -76,14 +98,12 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) struct queue_entry *entry; struct queue_entry_priv_pci *entry_priv; struct skb_frame_desc *skbdesc; - u32 word; while (1) { entry = rt2x00queue_get_entry(queue, Q_INDEX); entry_priv = entry->priv_data; - rt2x00_desc_read(entry_priv->desc, 0, &word); - if (rt2x00_get_field32(word, RXD_ENTRY_OWNER_NIC)) + if (rt2x00dev->ops->lib->get_entry_state(entry)) break; /* @@ -222,8 +242,7 @@ static int rt2x00pci_alloc_reg(struct rt2x00_dev *rt2x00dev) { struct pci_dev *pci_dev = to_pci_dev(rt2x00dev->dev); - rt2x00dev->csr.base = ioremap(pci_resource_start(pci_dev, 0), - pci_resource_len(pci_dev, 0)); + rt2x00dev->csr.base = pci_ioremap_bar(pci_dev, 0); if (!rt2x00dev->csr.base) goto exit; diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h index 80bf97c03e2d159395f46d9933db3be0275948c8..9c0a4d77bc1be1e16ab79940c3c2cb0aa65859c2 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.h +++ b/drivers/net/wireless/rt2x00/rt2x00pci.h @@ -43,22 +43,11 @@ #define REGISTER_BUSY_COUNT 5 #define REGISTER_BUSY_DELAY 100 -/* - * Descriptor availability flags. - * All PCI device descriptors have these 2 flags - * with the exact same definition. - * By storing them here we can use them inside rt2x00pci - * for some simple entry availability checking. - */ -#define TXD_ENTRY_OWNER_NIC FIELD32(0x00000001) -#define TXD_ENTRY_VALID FIELD32(0x00000002) -#define RXD_ENTRY_OWNER_NIC FIELD32(0x00000001) - /* * Register access. */ static inline void rt2x00pci_register_read(struct rt2x00_dev *rt2x00dev, - const unsigned long offset, + const unsigned int offset, u32 *value) { *value = readl(rt2x00dev->csr.base + offset); @@ -66,14 +55,14 @@ static inline void rt2x00pci_register_read(struct rt2x00_dev *rt2x00dev, static inline void rt2x00pci_register_multiread(struct rt2x00_dev *rt2x00dev, - const unsigned long offset, + const unsigned int offset, void *value, const u16 length) { memcpy_fromio(value, rt2x00dev->csr.base + offset, length); } static inline void rt2x00pci_register_write(struct rt2x00_dev *rt2x00dev, - const unsigned long offset, + const unsigned int offset, u32 value) { writel(value, rt2x00dev->csr.base + offset); @@ -81,12 +70,30 @@ static inline void rt2x00pci_register_write(struct rt2x00_dev *rt2x00dev, static inline void rt2x00pci_register_multiwrite(struct rt2x00_dev *rt2x00dev, - const unsigned long offset, + const unsigned int offset, const void *value, const u16 length) { memcpy_toio(rt2x00dev->csr.base + offset, value, length); } +/** + * rt2x00pci_regbusy_read - Read from register with busy check + * @rt2x00dev: Device pointer, see &struct rt2x00_dev. + * @offset: Register offset + * @field: Field to check if register is busy + * @reg: Pointer to where register contents should be stored + * + * This function will read the given register, and checks if the + * register is busy. If it is, it will sleep for a couple of + * microseconds before reading the register again. If the register + * is not read after a certain timeout, this function will return + * FALSE. + */ +int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + const struct rt2x00_field32 field, + u32 *reg); + /** * rt2x00pci_write_tx_data - Initialize data for TX operation * @entry: The entry where the frame is located diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 451d410ecdae4fae126ab835bdadd5647a4f13b8..eaec6bd93ed5e0adc3f5a0911a8d9dac72356db1 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -55,14 +55,12 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev, /* * For IV/EIV/ICV assembly we must make sure there is * at least 8 bytes bytes available in headroom for IV/EIV - * and 4 bytes for ICV data as tailroon. + * and 8 bytes for ICV data as tailroon. */ -#ifdef CONFIG_RT2X00_LIB_CRYPTO if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) { head_size += 8; - tail_size += 4; + tail_size += 8; } -#endif /* CONFIG_RT2X00_LIB_CRYPTO */ /* * Allocate skbuffer. @@ -174,7 +172,7 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, txdesc->cw_max = entry->queue->cw_max; txdesc->aifs = entry->queue->aifs; - /* Data length + CRC + IV/EIV/ICV/MMIC (when using encryption) */ + /* Data length + CRC */ data_length = entry->skb->len + 4; /* @@ -183,34 +181,17 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) __set_bit(ENTRY_TXD_ACK, &txdesc->flags); -#ifdef CONFIG_RT2X00_LIB_CRYPTO if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) && !entry->skb->do_not_encrypt) { - struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; - - __set_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags); - - txdesc->cipher = rt2x00crypto_key_to_cipher(hw_key); - - if (hw_key->flags & IEEE80211_KEY_FLAG_PAIRWISE) - __set_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags); - - txdesc->key_idx = hw_key->hw_key_idx; - txdesc->iv_offset = ieee80211_get_hdrlen_from_skb(entry->skb); + /* Apply crypto specific descriptor information */ + rt2x00crypto_create_tx_descriptor(entry, txdesc); /* * Extend frame length to include all encryption overhead * that will be added by the hardware. */ data_length += rt2x00crypto_tx_overhead(tx_info); - - if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) - __set_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags); - - if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) - __set_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags); } -#endif /* CONFIG_RT2X00_LIB_CRYPTO */ /* * Check if this is a RTS/CTS frame @@ -230,8 +211,8 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, /* * Determine retry information. */ - txdesc->retry_limit = tx_info->control.retry_limit; - if (tx_info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT) + txdesc->retry_limit = tx_info->control.rates[0].count - 1; + if (txdesc->retry_limit >= rt2x00dev->long_retry) __set_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags); /* @@ -312,8 +293,8 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, /* * Convert length to microseconds. */ - residual = get_duration_res(data_length, hwrate->bitrate); - duration = get_duration(data_length, hwrate->bitrate); + residual = GET_DURATION_RES(data_length, hwrate->bitrate); + duration = GET_DURATION(data_length, hwrate->bitrate); if (residual != 0) { duration++; @@ -371,13 +352,15 @@ static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry, int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) { + struct ieee80211_tx_info *tx_info; struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); struct txentry_desc txdesc; struct skb_frame_desc *skbdesc; unsigned int iv_len = 0; + u8 rate_idx, rate_flags; if (unlikely(rt2x00queue_full(queue))) - return -EINVAL; + return -ENOBUFS; if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) { ERROR(queue->rt2x00dev, @@ -399,13 +382,18 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) iv_len = IEEE80211_SKB_CB(skb)->control.hw_key->iv_len; /* - * All information is retreived from the skb->cb array, + * All information is retrieved from the skb->cb array, * now we should claim ownership of the driver part of that - * array. + * array, preserving the bitrate index and flags. */ - skbdesc = get_skb_frame_desc(entry->skb); + tx_info = IEEE80211_SKB_CB(skb); + rate_idx = tx_info->control.rates[0].idx; + rate_flags = tx_info->control.rates[0].flags; + skbdesc = get_skb_frame_desc(skb); memset(skbdesc, 0, sizeof(*skbdesc)); skbdesc->entry = entry; + skbdesc->tx_rate_idx = rate_idx; + skbdesc->tx_rate_flags = rate_flags; /* * When hardware encryption is supported, and this frame @@ -414,19 +402,21 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) */ if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc.flags) && !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags)) { - rt2x00crypto_tx_remove_iv(skb, iv_len); + if (test_bit(CONFIG_CRYPTO_COPY_IV, &queue->rt2x00dev->flags)) + rt2x00crypto_tx_copy_iv(skb, iv_len); + else + rt2x00crypto_tx_remove_iv(skb, iv_len); } /* * It could be possible that the queue was corrupted and this - * call failed. Just drop the frame, we cannot rollback and pass - * the frame to mac80211 because the skb->cb has now been tainted. + * call failed. Since we always return NETDEV_TX_OK to mac80211, + * this frame will simply be dropped. */ if (unlikely(queue->rt2x00dev->ops->lib->write_tx_data(entry))) { clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); - dev_kfree_skb_any(entry->skb); entry->skb = NULL; - return 0; + return -EIO; } if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags)) @@ -556,7 +546,7 @@ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index) queue->length++; } else if (index == Q_INDEX_DONE) { queue->length--; - queue->count ++; + queue->count++; } spin_unlock_irqrestore(&queue->lock, irqflags); @@ -575,40 +565,18 @@ static void rt2x00queue_reset(struct data_queue *queue) spin_unlock_irqrestore(&queue->lock, irqflags); } -void rt2x00queue_init_rx(struct rt2x00_dev *rt2x00dev) -{ - struct data_queue *queue = rt2x00dev->rx; - unsigned int i; - - rt2x00queue_reset(queue); - - if (!rt2x00dev->ops->lib->init_rxentry) - return; - - for (i = 0; i < queue->limit; i++) { - queue->entries[i].flags = 0; - - rt2x00dev->ops->lib->init_rxentry(rt2x00dev, - &queue->entries[i]); - } -} - -void rt2x00queue_init_tx(struct rt2x00_dev *rt2x00dev) +void rt2x00queue_init_queues(struct rt2x00_dev *rt2x00dev) { struct data_queue *queue; unsigned int i; - txall_queue_for_each(rt2x00dev, queue) { + queue_for_each(rt2x00dev, queue) { rt2x00queue_reset(queue); - if (!rt2x00dev->ops->lib->init_txentry) - continue; - for (i = 0; i < queue->limit; i++) { queue->entries[i].flags = 0; - rt2x00dev->ops->lib->init_txentry(rt2x00dev, - &queue->entries[i]); + rt2x00dev->ops->lib->clear_entry(&queue->entries[i]); } } } diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 9dbf04f0f04c1ceeae6ac10f0789aec9eb649a95..28293715340849363aa98eeb480f18f593fae7ec 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -104,22 +104,25 @@ enum skb_frame_desc_flags { * * @flags: Frame flags, see &enum skb_frame_desc_flags. * @desc_len: Length of the frame descriptor. + * @tx_rate_idx: the index of the TX rate, used for TX status reporting + * @tx_rate_flags: the TX rate flags, used for TX status reporting * @desc: Pointer to descriptor part of the frame. * Note that this pointer could point to something outside * of the scope of the skb->data pointer. - * @iv: IV data used during encryption/decryption. - * @eiv: EIV data used during encryption/decryption. + * @iv: IV/EIV data used during encryption/decryption. * @skb_dma: (PCI-only) the DMA address associated with the sk buffer. * @entry: The entry to which this sk buffer belongs. */ struct skb_frame_desc { - unsigned int flags; + u8 flags; + + u8 desc_len; + u8 tx_rate_idx; + u8 tx_rate_flags; - unsigned int desc_len; void *desc; - __le32 iv; - __le32 eiv; + __le32 iv[2]; dma_addr_t skb_dma; @@ -143,11 +146,15 @@ static inline struct skb_frame_desc* get_skb_frame_desc(struct sk_buff *skb) * @RXDONE_SIGNAL_PLCP: Signal field contains the plcp value. * @RXDONE_SIGNAL_BITRATE: Signal field contains the bitrate value. * @RXDONE_MY_BSS: Does this frame originate from device's BSS. + * @RXDONE_CRYPTO_IV: Driver provided IV/EIV data. + * @RXDONE_CRYPTO_ICV: Driver provided ICV data. */ enum rxdone_entry_desc_flags { RXDONE_SIGNAL_PLCP = 1 << 0, RXDONE_SIGNAL_BITRATE = 1 << 1, RXDONE_MY_BSS = 1 << 2, + RXDONE_CRYPTO_IV = 1 << 3, + RXDONE_CRYPTO_ICV = 1 << 4, }; /** @@ -163,8 +170,7 @@ enum rxdone_entry_desc_flags { * @dev_flags: Ralink receive flags (See &enum rxdone_entry_desc_flags). * @cipher: Cipher type used during decryption. * @cipher_status: Decryption status. - * @iv: IV data used during decryption. - * @eiv: EIV data used during decryption. + * @iv: IV/EIV data used during decryption. * @icv: ICV data used during decryption. */ struct rxdone_entry_desc { @@ -177,8 +183,7 @@ struct rxdone_entry_desc { u8 cipher; u8 cipher_status; - __le32 iv; - __le32 eiv; + __le32 iv[2]; __le32 icv; }; @@ -375,6 +380,8 @@ enum queue_index { * @cw_max: The cw max value for outgoing frames (field ignored in RX queue). * @data_size: Maximum data size for the frames in this queue. * @desc_size: Hardware descriptor size for the data in this queue. + * @usb_endpoint: Device endpoint used for communication (USB only) + * @usb_maxpacket: Max packet size for given endpoint (USB only) */ struct data_queue { struct rt2x00_dev *rt2x00dev; @@ -396,6 +403,9 @@ struct data_queue { unsigned short data_size; unsigned short desc_size; + + unsigned short usb_endpoint; + unsigned short usb_maxpacket; }; /** @@ -438,6 +448,19 @@ struct data_queue_desc { #define tx_queue_end(__dev) \ &(__dev)->tx[(__dev)->ops->tx_queues] +/** + * queue_next - Return pointer to next queue in list (HELPER MACRO). + * @__queue: Current queue for which we need the next queue + * + * Using the current queue address we take the address directly + * after the queue to take the next queue. Note that this macro + * should be used carefully since it does not protect against + * moving past the end of the list. (See macros &queue_end and + * &tx_queue_end for determining the end of the queue). + */ +#define queue_next(__queue) \ + &(__queue)[1] + /** * queue_loop - Loop through the queues within a specific range (HELPER MACRO). * @__entry: Pointer where the current queue entry will be stored in. @@ -448,8 +471,8 @@ struct data_queue_desc { */ #define queue_loop(__entry, __start, __end) \ for ((__entry) = (__start); \ - prefetch(&(__entry)[1]), (__entry) != (__end); \ - (__entry) = &(__entry)[1]) + prefetch(queue_next(__entry)), (__entry) != (__end);\ + (__entry) = queue_next(__entry)) /** * queue_for_each - Loop through all queues diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index b73a7e0aeed4c54221435bbb3050326450dc093a..83df312ac56fe02b3b833022c8f432d674e0215e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -79,7 +79,7 @@ int rt2x00usb_vendor_req_buff_lock(struct rt2x00_dev *rt2x00dev, { int status; - BUG_ON(!mutex_is_locked(&rt2x00dev->usb_cache_mutex)); + BUG_ON(!mutex_is_locked(&rt2x00dev->csr_mutex)); /* * Check for Cache availability. @@ -110,13 +110,13 @@ int rt2x00usb_vendor_request_buff(struct rt2x00_dev *rt2x00dev, { int status; - mutex_lock(&rt2x00dev->usb_cache_mutex); + mutex_lock(&rt2x00dev->csr_mutex); status = rt2x00usb_vendor_req_buff_lock(rt2x00dev, request, requesttype, offset, buffer, buffer_length, timeout); - mutex_unlock(&rt2x00dev->usb_cache_mutex); + mutex_unlock(&rt2x00dev->csr_mutex); return status; } @@ -132,7 +132,7 @@ int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev, unsigned char *tb; u16 off, len, bsize; - mutex_lock(&rt2x00dev->usb_cache_mutex); + mutex_lock(&rt2x00dev->csr_mutex); tb = (char *)buffer; off = offset; @@ -148,12 +148,34 @@ int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev, off += bsize; } - mutex_unlock(&rt2x00dev->usb_cache_mutex); + mutex_unlock(&rt2x00dev->csr_mutex); return status; } EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_large_buff); +int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + struct rt2x00_field32 field, + u32 *reg) +{ + unsigned int i; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00usb_register_read_lock(rt2x00dev, offset, reg); + if (!rt2x00_get_field32(*reg, field)) + return 1; + udelay(REGISTER_BUSY_DELAY); + } + + ERROR(rt2x00dev, "Indirect register access failed: " + "offset=0x%.08x, value=0x%.08x\n", offset, *reg); + *reg = ~0; + + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00usb_regbusy_read); + /* * TX data handlers. */ @@ -212,10 +234,10 @@ int rt2x00usb_write_tx_data(struct queue_entry *entry) * length of the data to usb_fill_bulk_urb. Pass the skb * to the driver to determine what the length should be. */ - length = rt2x00dev->ops->lib->get_tx_data_len(rt2x00dev, entry->skb); + length = rt2x00dev->ops->lib->get_tx_data_len(entry); usb_fill_bulk_urb(entry_priv->urb, usb_dev, - usb_sndbulkpipe(usb_dev, 1), + usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint), entry->skb->data, length, rt2x00usb_interrupt_txdone, entry); @@ -351,28 +373,96 @@ EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio); /* * Device initialization handlers. */ -void rt2x00usb_init_rxentry(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry) +void rt2x00usb_clear_entry(struct queue_entry *entry) { - struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); + struct usb_device *usb_dev = + to_usb_device_intf(entry->queue->rt2x00dev->dev); struct queue_entry_priv_usb *entry_priv = entry->priv_data; + int pipe; - usb_fill_bulk_urb(entry_priv->urb, usb_dev, - usb_rcvbulkpipe(usb_dev, 1), - entry->skb->data, entry->skb->len, - rt2x00usb_interrupt_rxdone, entry); + if (entry->queue->qid == QID_RX) { + pipe = usb_rcvbulkpipe(usb_dev, entry->queue->usb_endpoint); + usb_fill_bulk_urb(entry_priv->urb, usb_dev, pipe, + entry->skb->data, entry->skb->len, + rt2x00usb_interrupt_rxdone, entry); - set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); - usb_submit_urb(entry_priv->urb, GFP_ATOMIC); + set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); + usb_submit_urb(entry_priv->urb, GFP_ATOMIC); + } else { + entry->flags = 0; + } } -EXPORT_SYMBOL_GPL(rt2x00usb_init_rxentry); +EXPORT_SYMBOL_GPL(rt2x00usb_clear_entry); -void rt2x00usb_init_txentry(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry) +static void rt2x00usb_assign_endpoint(struct data_queue *queue, + struct usb_endpoint_descriptor *ep_desc) { - entry->flags = 0; + struct usb_device *usb_dev = to_usb_device_intf(queue->rt2x00dev->dev); + int pipe; + + queue->usb_endpoint = usb_endpoint_num(ep_desc); + + if (queue->qid == QID_RX) { + pipe = usb_rcvbulkpipe(usb_dev, queue->usb_endpoint); + queue->usb_maxpacket = usb_maxpacket(usb_dev, pipe, 0); + } else { + pipe = usb_sndbulkpipe(usb_dev, queue->usb_endpoint); + queue->usb_maxpacket = usb_maxpacket(usb_dev, pipe, 1); + } + + if (!queue->usb_maxpacket) + queue->usb_maxpacket = 1; +} + +static int rt2x00usb_find_endpoints(struct rt2x00_dev *rt2x00dev) +{ + struct usb_interface *intf = to_usb_interface(rt2x00dev->dev); + struct usb_host_interface *intf_desc = intf->cur_altsetting; + struct usb_endpoint_descriptor *ep_desc; + struct data_queue *queue = rt2x00dev->tx; + struct usb_endpoint_descriptor *tx_ep_desc = NULL; + unsigned int i; + + /* + * Walk through all available endpoints to search for "bulk in" + * and "bulk out" endpoints. When we find such endpoints collect + * the information we need from the descriptor and assign it + * to the queue. + */ + for (i = 0; i < intf_desc->desc.bNumEndpoints; i++) { + ep_desc = &intf_desc->endpoint[i].desc; + + if (usb_endpoint_is_bulk_in(ep_desc)) { + rt2x00usb_assign_endpoint(rt2x00dev->rx, ep_desc); + } else if (usb_endpoint_is_bulk_out(ep_desc)) { + rt2x00usb_assign_endpoint(queue, ep_desc); + + if (queue != queue_end(rt2x00dev)) + queue = queue_next(queue); + tx_ep_desc = ep_desc; + } + } + + /* + * At least 1 endpoint for RX and 1 endpoint for TX must be available. + */ + if (!rt2x00dev->rx->usb_endpoint || !rt2x00dev->tx->usb_endpoint) { + ERROR(rt2x00dev, "Bulk-in/Bulk-out endpoints not found\n"); + return -EPIPE; + } + + /* + * It might be possible not all queues have a dedicated endpoint. + * Loop through all TX queues and copy the endpoint information + * which we have gathered from already assigned endpoints. + */ + txall_queue_for_each(rt2x00dev, queue) { + if (!queue->usb_endpoint) + rt2x00usb_assign_endpoint(queue, tx_ep_desc); + } + + return 0; } -EXPORT_SYMBOL_GPL(rt2x00usb_init_txentry); static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev, struct data_queue *queue) @@ -444,6 +534,13 @@ int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev) struct data_queue *queue; int status; + /* + * Find endpoints for each queue + */ + status = rt2x00usb_find_endpoints(rt2x00dev); + if (status) + goto exit; + /* * Allocate DMA */ @@ -534,12 +631,6 @@ int rt2x00usb_probe(struct usb_interface *usb_intf, rt2x00dev->dev = &usb_intf->dev; rt2x00dev->ops = ops; rt2x00dev->hw = hw; - mutex_init(&rt2x00dev->usb_cache_mutex); - - rt2x00dev->usb_maxpacket = - usb_maxpacket(usb_dev, usb_sndbulkpipe(usb_dev, 1), 1); - if (!rt2x00dev->usb_maxpacket) - rt2x00dev->usb_maxpacket = 1; retval = rt2x00usb_alloc_reg(rt2x00dev); if (retval) diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index 3b4a67417f956625c55da3b88568ed08f140e3e5..2bd4ac855f528db67f60879ee2166a7b280b037f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -231,6 +231,142 @@ static inline int rt2x00usb_eeprom_read(struct rt2x00_dev *rt2x00dev, REGISTER_TIMEOUT16(length)); } +/** + * rt2x00usb_regbusy_read - Read 32bit register word + * @rt2x00dev: Device pointer, see &struct rt2x00_dev. + * @offset: Register offset + * @value: Pointer to where register contents should be stored + * + * This function is a simple wrapper for 32bit register access + * through rt2x00usb_vendor_request_buff(). + */ +static inline void rt2x00usb_register_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + u32 *value) +{ + __le32 reg; + rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ, + USB_VENDOR_REQUEST_IN, offset, + ®, sizeof(reg), REGISTER_TIMEOUT); + *value = le32_to_cpu(reg); +} + +/** + * rt2x00usb_register_read_lock - Read 32bit register word + * @rt2x00dev: Device pointer, see &struct rt2x00_dev. + * @offset: Register offset + * @value: Pointer to where register contents should be stored + * + * This function is a simple wrapper for 32bit register access + * through rt2x00usb_vendor_req_buff_lock(). + */ +static inline void rt2x00usb_register_read_lock(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + u32 *value) +{ + __le32 reg; + rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ, + USB_VENDOR_REQUEST_IN, offset, + ®, sizeof(reg), REGISTER_TIMEOUT); + *value = le32_to_cpu(reg); +} + +/** + * rt2x00usb_register_multiread - Read 32bit register words + * @rt2x00dev: Device pointer, see &struct rt2x00_dev. + * @offset: Register offset + * @value: Pointer to where register contents should be stored + * @length: Length of the data + * + * This function is a simple wrapper for 32bit register access + * through rt2x00usb_vendor_request_buff(). + */ +static inline void rt2x00usb_register_multiread(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + void *value, const u32 length) +{ + rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ, + USB_VENDOR_REQUEST_IN, offset, + value, length, + REGISTER_TIMEOUT32(length)); +} + +/** + * rt2x00usb_register_write - Write 32bit register word + * @rt2x00dev: Device pointer, see &struct rt2x00_dev. + * @offset: Register offset + * @value: Data which should be written + * + * This function is a simple wrapper for 32bit register access + * through rt2x00usb_vendor_request_buff(). + */ +static inline void rt2x00usb_register_write(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + u32 value) +{ + __le32 reg = cpu_to_le32(value); + rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, offset, + ®, sizeof(reg), REGISTER_TIMEOUT); +} + +/** + * rt2x00usb_register_write_lock - Write 32bit register word + * @rt2x00dev: Device pointer, see &struct rt2x00_dev. + * @offset: Register offset + * @value: Data which should be written + * + * This function is a simple wrapper for 32bit register access + * through rt2x00usb_vendor_req_buff_lock(). + */ +static inline void rt2x00usb_register_write_lock(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + u32 value) +{ + __le32 reg = cpu_to_le32(value); + rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, offset, + ®, sizeof(reg), REGISTER_TIMEOUT); +} + +/** + * rt2x00usb_register_multiwrite - Write 32bit register words + * @rt2x00dev: Device pointer, see &struct rt2x00_dev. + * @offset: Register offset + * @value: Data which should be written + * @length: Length of the data + * + * This function is a simple wrapper for 32bit register access + * through rt2x00usb_vendor_request_buff(). + */ +static inline void rt2x00usb_register_multiwrite(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + void *value, const u32 length) +{ + rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, offset, + value, length, + REGISTER_TIMEOUT32(length)); +} + +/** + * rt2x00usb_regbusy_read - Read from register with busy check + * @rt2x00dev: Device pointer, see &struct rt2x00_dev. + * @offset: Register offset + * @field: Field to check if register is busy + * @reg: Pointer to where register contents should be stored + * + * This function will read the given register, and checks if the + * register is busy. If it is, it will sleep for a couple of + * microseconds before reading the register again. If the register + * is not read after a certain timeout, this function will return + * FALSE. + */ +int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + struct rt2x00_field32 field, + u32 *reg); + /* * Radio handlers */ @@ -286,10 +422,7 @@ void rt2x00usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, /* * Device initialization handlers. */ -void rt2x00usb_init_rxentry(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry); -void rt2x00usb_init_txentry(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry); +void rt2x00usb_clear_entry(struct queue_entry *entry); int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev); void rt2x00usb_uninitialize(struct rt2x00_dev *rt2x00dev); diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index a461620b489f0350536bb06148e2813c609ea77f..987e89009f74ed36debc32498783d57812b68916 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -55,45 +55,36 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); * the access attempt is considered to have failed, * and we will print an error. */ -static u32 rt61pci_bbp_check(struct rt2x00_dev *rt2x00dev) -{ - u32 reg; - unsigned int i; - - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00pci_register_read(rt2x00dev, PHY_CSR3, ®); - if (!rt2x00_get_field32(reg, PHY_CSR3_BUSY)) - break; - udelay(REGISTER_BUSY_DELAY); - } - - return reg; -} +#define WAIT_FOR_BBP(__dev, __reg) \ + rt2x00pci_regbusy_read((__dev), PHY_CSR3, PHY_CSR3_BUSY, (__reg)) +#define WAIT_FOR_RF(__dev, __reg) \ + rt2x00pci_regbusy_read((__dev), PHY_CSR4, PHY_CSR4_BUSY, (__reg)) +#define WAIT_FOR_MCU(__dev, __reg) \ + rt2x00pci_regbusy_read((__dev), H2M_MAILBOX_CSR, \ + H2M_MAILBOX_CSR_OWNER, (__reg)) static void rt61pci_bbp_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u8 value) { u32 reg; - /* - * Wait until the BBP becomes ready. - */ - reg = rt61pci_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) { - ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n"); - return; - } + mutex_lock(&rt2x00dev->csr_mutex); /* - * Write the data into the BBP. + * Wait until the BBP becomes available, afterwards we + * can safely write the new data into the register. */ - reg = 0; - rt2x00_set_field32(®, PHY_CSR3_VALUE, value); - rt2x00_set_field32(®, PHY_CSR3_REGNUM, word); - rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); - rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 0); + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, PHY_CSR3_VALUE, value); + rt2x00_set_field32(®, PHY_CSR3_REGNUM, word); + rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); + rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 0); + + rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg); + } - rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg); + mutex_unlock(&rt2x00dev->csr_mutex); } static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev, @@ -101,66 +92,58 @@ static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev, { u32 reg; - /* - * Wait until the BBP becomes ready. - */ - reg = rt61pci_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) { - ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n"); - return; - } + mutex_lock(&rt2x00dev->csr_mutex); /* - * Write the request into the BBP. + * Wait until the BBP becomes available, afterwards we + * can safely write the read request into the register. + * After the data has been written, we wait until hardware + * returns the correct value, if at any time the register + * doesn't become available in time, reg will be 0xffffffff + * which means we return 0xff to the caller. */ - reg = 0; - rt2x00_set_field32(®, PHY_CSR3_REGNUM, word); - rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); - rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 1); + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, PHY_CSR3_REGNUM, word); + rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); + rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 1); - rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg); + rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg); - /* - * Wait until the BBP becomes ready. - */ - reg = rt61pci_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) { - ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n"); - *value = 0xff; - return; + WAIT_FOR_BBP(rt2x00dev, ®); } *value = rt2x00_get_field32(reg, PHY_CSR3_VALUE); + + mutex_unlock(&rt2x00dev->csr_mutex); } static void rt61pci_rf_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u32 value) { u32 reg; - unsigned int i; if (!word) return; - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00pci_register_read(rt2x00dev, PHY_CSR4, ®); - if (!rt2x00_get_field32(reg, PHY_CSR4_BUSY)) - goto rf_write; - udelay(REGISTER_BUSY_DELAY); - } + mutex_lock(&rt2x00dev->csr_mutex); - ERROR(rt2x00dev, "PHY_CSR4 register busy. Write failed.\n"); - return; + /* + * Wait until the RF becomes available, afterwards we + * can safely write the new data into the register. + */ + if (WAIT_FOR_RF(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, PHY_CSR4_VALUE, value); + rt2x00_set_field32(®, PHY_CSR4_NUMBER_OF_BITS, 21); + rt2x00_set_field32(®, PHY_CSR4_IF_SELECT, 0); + rt2x00_set_field32(®, PHY_CSR4_BUSY, 1); -rf_write: - reg = 0; - rt2x00_set_field32(®, PHY_CSR4_VALUE, value); - rt2x00_set_field32(®, PHY_CSR4_NUMBER_OF_BITS, 21); - rt2x00_set_field32(®, PHY_CSR4_IF_SELECT, 0); - rt2x00_set_field32(®, PHY_CSR4_BUSY, 1); + rt2x00pci_register_write(rt2x00dev, PHY_CSR4, reg); + rt2x00_rf_write(rt2x00dev, word, value); + } - rt2x00pci_register_write(rt2x00dev, PHY_CSR4, reg); - rt2x00_rf_write(rt2x00dev, word, value); + mutex_unlock(&rt2x00dev->csr_mutex); } #ifdef CONFIG_RT2X00_LIB_LEDS @@ -175,25 +158,27 @@ static void rt61pci_mcu_request(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt2x00pci_register_read(rt2x00dev, H2M_MAILBOX_CSR, ®); + mutex_lock(&rt2x00dev->csr_mutex); - if (rt2x00_get_field32(reg, H2M_MAILBOX_CSR_OWNER)) { - ERROR(rt2x00dev, "mcu request error. " - "Request 0x%02x failed for token 0x%02x.\n", - command, token); - return; + /* + * Wait until the MCU becomes available, afterwards we + * can safely write the new data into the register. + */ + if (WAIT_FOR_MCU(rt2x00dev, ®)) { + rt2x00_set_field32(®, H2M_MAILBOX_CSR_OWNER, 1); + rt2x00_set_field32(®, H2M_MAILBOX_CSR_CMD_TOKEN, token); + rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG0, arg0); + rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG1, arg1); + rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, reg); + + rt2x00pci_register_read(rt2x00dev, HOST_CMD_CSR, ®); + rt2x00_set_field32(®, HOST_CMD_CSR_HOST_COMMAND, command); + rt2x00_set_field32(®, HOST_CMD_CSR_INTERRUPT_MCU, 1); + rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, reg); } - rt2x00_set_field32(®, H2M_MAILBOX_CSR_OWNER, 1); - rt2x00_set_field32(®, H2M_MAILBOX_CSR_CMD_TOKEN, token); - rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG0, arg0); - rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG1, arg1); - rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, reg); + mutex_unlock(&rt2x00dev->csr_mutex); - rt2x00pci_register_read(rt2x00dev, HOST_CMD_CSR, ®); - rt2x00_set_field32(®, HOST_CMD_CSR_HOST_COMMAND, command); - rt2x00_set_field32(®, HOST_CMD_CSR_INTERRUPT_MCU, 1); - rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, reg); } #endif /* CONFIG_RT2X00_LIB_LEDS */ @@ -228,43 +213,34 @@ static void rt61pci_eepromregister_write(struct eeprom_93cx6 *eeprom) } #ifdef CONFIG_RT2X00_LIB_DEBUGFS -#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u32)) ) - -static void rt61pci_read_csr(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u32 *data) -{ - rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data); -} - -static void rt61pci_write_csr(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u32 data) -{ - rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data); -} - static const struct rt2x00debug rt61pci_rt2x00debug = { .owner = THIS_MODULE, .csr = { - .read = rt61pci_read_csr, - .write = rt61pci_write_csr, + .read = rt2x00pci_register_read, + .write = rt2x00pci_register_write, + .flags = RT2X00DEBUGFS_OFFSET, + .word_base = CSR_REG_BASE, .word_size = sizeof(u32), .word_count = CSR_REG_SIZE / sizeof(u32), }, .eeprom = { .read = rt2x00_eeprom_read, .write = rt2x00_eeprom_write, + .word_base = EEPROM_BASE, .word_size = sizeof(u16), .word_count = EEPROM_SIZE / sizeof(u16), }, .bbp = { .read = rt61pci_bbp_read, .write = rt61pci_bbp_write, + .word_base = BBP_BASE, .word_size = sizeof(u8), .word_count = BBP_SIZE / sizeof(u8), }, .rf = { .read = rt2x00_rf_read, .write = rt61pci_rf_write, + .word_base = RF_BASE, .word_size = sizeof(u32), .word_count = RF_SIZE / sizeof(u32), }, @@ -643,95 +619,18 @@ static void rt61pci_config_erp(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, !!erp->short_preamble); rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg); -} - - -static void rt61pci_config_lna_gain(struct rt2x00_dev *rt2x00dev, - struct rt2x00lib_conf *libconf) -{ - u16 eeprom; - short lna_gain = 0; - - if (libconf->band == IEEE80211_BAND_2GHZ) { - if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) - lna_gain += 14; - - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom); - lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1); - } else { - if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) - lna_gain += 14; - - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom); - lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1); - } - - rt2x00dev->lna_gain = lna_gain; -} - -static void rt61pci_config_phymode(struct rt2x00_dev *rt2x00dev, - const int basic_rate_mask) -{ - rt2x00pci_register_write(rt2x00dev, TXRX_CSR5, basic_rate_mask); -} - -static void rt61pci_config_channel(struct rt2x00_dev *rt2x00dev, - struct rf_channel *rf, const int txpower) -{ - u8 r3; - u8 r94; - u8 smart; - rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); - rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset); - - smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) || - rt2x00_rf(&rt2x00dev->chip, RF2527)); - - rt61pci_bbp_read(rt2x00dev, 3, &r3); - rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart); - rt61pci_bbp_write(rt2x00dev, 3, r3); - - r94 = 6; - if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94)) - r94 += txpower - MAX_TXPOWER; - else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94)) - r94 += txpower; - rt61pci_bbp_write(rt2x00dev, 94, r94); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR5, erp->basic_rates); - rt61pci_rf_write(rt2x00dev, 1, rf->rf1); - rt61pci_rf_write(rt2x00dev, 2, rf->rf2); - rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); - rt61pci_rf_write(rt2x00dev, 4, rf->rf4); - - udelay(200); - - rt61pci_rf_write(rt2x00dev, 1, rf->rf1); - rt61pci_rf_write(rt2x00dev, 2, rf->rf2); - rt61pci_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004); - rt61pci_rf_write(rt2x00dev, 4, rf->rf4); - - udelay(200); - - rt61pci_rf_write(rt2x00dev, 1, rf->rf1); - rt61pci_rf_write(rt2x00dev, 2, rf->rf2); - rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); - rt61pci_rf_write(rt2x00dev, 4, rf->rf4); - - msleep(1); -} - -static void rt61pci_config_txpower(struct rt2x00_dev *rt2x00dev, - const int txpower) -{ - struct rf_channel rf; - - rt2x00_rf_read(rt2x00dev, 1, &rf.rf1); - rt2x00_rf_read(rt2x00dev, 2, &rf.rf2); - rt2x00_rf_read(rt2x00dev, 3, &rf.rf3); - rt2x00_rf_read(rt2x00dev, 4, &rf.rf4); + rt2x00pci_register_read(rt2x00dev, MAC_CSR9, ®); + rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, erp->slot_time); + rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg); - rt61pci_config_channel(rt2x00dev, &rf, txpower); + rt2x00pci_register_read(rt2x00dev, MAC_CSR8, ®); + rt2x00_set_field32(®, MAC_CSR8_SIFS, erp->sifs); + rt2x00_set_field32(®, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3); + rt2x00_set_field32(®, MAC_CSR8_EIFS, erp->eifs); + rt2x00pci_register_write(rt2x00dev, MAC_CSR8, reg); } static void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev, @@ -906,8 +805,8 @@ static const struct antenna_sel antenna_sel_bg[] = { { 98, { 0x48, 0x48 } }, }; -static void rt61pci_config_antenna(struct rt2x00_dev *rt2x00dev, - struct antenna_setup *ant) +static void rt61pci_config_ant(struct rt2x00_dev *rt2x00dev, + struct antenna_setup *ant) { const struct antenna_sel *sel; unsigned int lna; @@ -954,20 +853,105 @@ static void rt61pci_config_antenna(struct rt2x00_dev *rt2x00dev, } } -static void rt61pci_config_duration(struct rt2x00_dev *rt2x00dev, +static void rt61pci_config_lna_gain(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf) +{ + u16 eeprom; + short lna_gain = 0; + + if (libconf->conf->channel->band == IEEE80211_BAND_2GHZ) { + if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) + lna_gain += 14; + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom); + lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1); + } else { + if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) + lna_gain += 14; + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom); + lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1); + } + + rt2x00dev->lna_gain = lna_gain; +} + +static void rt61pci_config_channel(struct rt2x00_dev *rt2x00dev, + struct rf_channel *rf, const int txpower) +{ + u8 r3; + u8 r94; + u8 smart; + + rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); + rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset); + + smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) || + rt2x00_rf(&rt2x00dev->chip, RF2527)); + + rt61pci_bbp_read(rt2x00dev, 3, &r3); + rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart); + rt61pci_bbp_write(rt2x00dev, 3, r3); + + r94 = 6; + if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94)) + r94 += txpower - MAX_TXPOWER; + else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94)) + r94 += txpower; + rt61pci_bbp_write(rt2x00dev, 94, r94); + + rt61pci_rf_write(rt2x00dev, 1, rf->rf1); + rt61pci_rf_write(rt2x00dev, 2, rf->rf2); + rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); + rt61pci_rf_write(rt2x00dev, 4, rf->rf4); + + udelay(200); + + rt61pci_rf_write(rt2x00dev, 1, rf->rf1); + rt61pci_rf_write(rt2x00dev, 2, rf->rf2); + rt61pci_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004); + rt61pci_rf_write(rt2x00dev, 4, rf->rf4); + + udelay(200); + + rt61pci_rf_write(rt2x00dev, 1, rf->rf1); + rt61pci_rf_write(rt2x00dev, 2, rf->rf2); + rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); + rt61pci_rf_write(rt2x00dev, 4, rf->rf4); + + msleep(1); +} + +static void rt61pci_config_txpower(struct rt2x00_dev *rt2x00dev, + const int txpower) +{ + struct rf_channel rf; + + rt2x00_rf_read(rt2x00dev, 1, &rf.rf1); + rt2x00_rf_read(rt2x00dev, 2, &rf.rf2); + rt2x00_rf_read(rt2x00dev, 3, &rf.rf3); + rt2x00_rf_read(rt2x00dev, 4, &rf.rf4); + + rt61pci_config_channel(rt2x00dev, &rf, txpower); +} + +static void rt61pci_config_retry_limit(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf) { u32 reg; - rt2x00pci_register_read(rt2x00dev, MAC_CSR9, ®); - rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, libconf->slot_time); - rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg); + rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, ®); + rt2x00_set_field32(®, TXRX_CSR4_LONG_RETRY_LIMIT, + libconf->conf->long_frame_max_tx_count); + rt2x00_set_field32(®, TXRX_CSR4_SHORT_RETRY_LIMIT, + libconf->conf->short_frame_max_tx_count); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg); +} - rt2x00pci_register_read(rt2x00dev, MAC_CSR8, ®); - rt2x00_set_field32(®, MAC_CSR8_SIFS, libconf->sifs); - rt2x00_set_field32(®, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3); - rt2x00_set_field32(®, MAC_CSR8_EIFS, libconf->eifs); - rt2x00pci_register_write(rt2x00dev, MAC_CSR8, reg); +static void rt61pci_config_duration(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf) +{ + u32 reg; rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); @@ -990,16 +974,15 @@ static void rt61pci_config(struct rt2x00_dev *rt2x00dev, /* Always recalculate LNA gain before changing configuration */ rt61pci_config_lna_gain(rt2x00dev, libconf); - if (flags & CONFIG_UPDATE_PHYMODE) - rt61pci_config_phymode(rt2x00dev, libconf->basic_rates); - if (flags & CONFIG_UPDATE_CHANNEL) + if (flags & IEEE80211_CONF_CHANGE_CHANNEL) rt61pci_config_channel(rt2x00dev, &libconf->rf, libconf->conf->power_level); - if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL)) + if ((flags & IEEE80211_CONF_CHANGE_POWER) && + !(flags & IEEE80211_CONF_CHANGE_CHANNEL)) rt61pci_config_txpower(rt2x00dev, libconf->conf->power_level); - if (flags & CONFIG_UPDATE_ANTENNA) - rt61pci_config_antenna(rt2x00dev, &libconf->ant); - if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) + if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) + rt61pci_config_retry_limit(rt2x00dev, libconf); + if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) rt61pci_config_duration(rt2x00dev, libconf); } @@ -1263,33 +1246,44 @@ static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev, const void *data, /* * Initialization functions. */ -static void rt61pci_init_rxentry(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry) +static bool rt61pci_get_entry_state(struct queue_entry *entry) { struct queue_entry_priv_pci *entry_priv = entry->priv_data; - struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); u32 word; - rt2x00_desc_read(entry_priv->desc, 5, &word); - rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS, - skbdesc->skb_dma); - rt2x00_desc_write(entry_priv->desc, 5, word); + if (entry->queue->qid == QID_RX) { + rt2x00_desc_read(entry_priv->desc, 0, &word); + + return rt2x00_get_field32(word, RXD_W0_OWNER_NIC); + } else { + rt2x00_desc_read(entry_priv->desc, 0, &word); - rt2x00_desc_read(entry_priv->desc, 0, &word); - rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); - rt2x00_desc_write(entry_priv->desc, 0, word); + return (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || + rt2x00_get_field32(word, TXD_W0_VALID)); + } } -static void rt61pci_init_txentry(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry) +static void rt61pci_clear_entry(struct queue_entry *entry) { struct queue_entry_priv_pci *entry_priv = entry->priv_data; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); u32 word; - rt2x00_desc_read(entry_priv->desc, 0, &word); - rt2x00_set_field32(&word, TXD_W0_VALID, 0); - rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); - rt2x00_desc_write(entry_priv->desc, 0, word); + if (entry->queue->qid == QID_RX) { + rt2x00_desc_read(entry_priv->desc, 5, &word); + rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS, + skbdesc->skb_dma); + rt2x00_desc_write(entry_priv->desc, 5, word); + + rt2x00_desc_read(entry_priv->desc, 0, &word); + rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); + rt2x00_desc_write(entry_priv->desc, 0, word); + } else { + rt2x00_desc_read(entry_priv->desc, 0, &word); + rt2x00_set_field32(&word, TXD_W0_VALID, 0); + rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); + rt2x00_desc_write(entry_priv->desc, 0, word); + } } static int rt61pci_init_queues(struct rt2x00_dev *rt2x00dev) @@ -1784,8 +1778,8 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_desc_write(txd, 2, word); if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags)) { - _rt2x00_desc_write(txd, 3, skbdesc->iv); - _rt2x00_desc_write(txd, 4, skbdesc->eiv); + _rt2x00_desc_write(txd, 3, skbdesc->iv[0]); + _rt2x00_desc_write(txd, 4, skbdesc->iv[1]); } rt2x00_desc_read(txd, 5, &word); @@ -1934,7 +1928,7 @@ static int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) } static void rt61pci_fill_rxdone(struct queue_entry *entry, - struct rxdone_entry_desc *rxdesc) + struct rxdone_entry_desc *rxdesc) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct queue_entry_priv_pci *entry_priv = entry->priv_data; @@ -1955,9 +1949,12 @@ static void rt61pci_fill_rxdone(struct queue_entry *entry, } if (rxdesc->cipher != CIPHER_NONE) { - _rt2x00_desc_read(entry_priv->desc, 2, &rxdesc->iv); - _rt2x00_desc_read(entry_priv->desc, 3, &rxdesc->eiv); + _rt2x00_desc_read(entry_priv->desc, 2, &rxdesc->iv[0]); + _rt2x00_desc_read(entry_priv->desc, 3, &rxdesc->iv[1]); + rxdesc->dev_flags |= RXDONE_CRYPTO_IV; + _rt2x00_desc_read(entry_priv->desc, 4, &rxdesc->icv); + rxdesc->dev_flags |= RXDONE_CRYPTO_ICV; /* * Hardware has stripped IV/EIV data from 802.11 frame during @@ -2175,10 +2172,8 @@ static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) */ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); if (!is_valid_ether_addr(mac)) { - DECLARE_MAC_BUF(macbuf); - random_ether_addr(mac); - EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac)); + EEPROM(rt2x00dev, "MAC: %pM\n", mac); } rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); @@ -2630,20 +2625,6 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ -static int rt61pci_set_retry_limit(struct ieee80211_hw *hw, - u32 short_retry, u32 long_retry) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - u32 reg; - - rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, ®); - rt2x00_set_field32(®, TXRX_CSR4_LONG_RETRY_LIMIT, long_retry); - rt2x00_set_field32(®, TXRX_CSR4_SHORT_RETRY_LIMIT, short_retry); - rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg); - - return 0; -} - static int rt61pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, const struct ieee80211_tx_queue_params *params) { @@ -2726,7 +2707,6 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = { .configure_filter = rt2x00mac_configure_filter, .set_key = rt2x00mac_set_key, .get_stats = rt2x00mac_get_stats, - .set_retry_limit = rt61pci_set_retry_limit, .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt61pci_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, @@ -2741,8 +2721,8 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { .load_firmware = rt61pci_load_firmware, .initialize = rt2x00pci_initialize, .uninitialize = rt2x00pci_uninitialize, - .init_rxentry = rt61pci_init_rxentry, - .init_txentry = rt61pci_init_txentry, + .get_entry_state = rt61pci_get_entry_state, + .clear_entry = rt61pci_clear_entry, .set_device_state = rt61pci_set_device_state, .rfkill_poll = rt61pci_rfkill_poll, .link_stats = rt61pci_link_stats, @@ -2758,6 +2738,7 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { .config_filter = rt61pci_config_filter, .config_intf = rt61pci_config_intf, .config_erp = rt61pci_config_erp, + .config_ant = rt61pci_config_ant, .config = rt61pci_config, }; diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h index 8ec1451308ccea2700ce05e03f0be2229a3c2779..65fe3332364aa8cb414793ec0f0a057e40038252 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.h +++ b/drivers/net/wireless/rt2x00/rt61pci.h @@ -48,7 +48,9 @@ #define CSR_REG_SIZE 0x04b0 #define EEPROM_BASE 0x0000 #define EEPROM_SIZE 0x0100 +#define BBP_BASE 0x0000 #define BBP_SIZE 0x0080 +#define RF_BASE 0x0000 #define RF_SIZE 0x0014 /* diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 934f8e03c5aae99fa9f6175d0c509d48fc245a48..d638a8a593705384f58a2cbf6a6e95fd4dd7d0db 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -46,7 +46,7 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); /* * Register access. * All access to the CSR registers will go through the methods - * rt73usb_register_read and rt73usb_register_write. + * rt2x00usb_register_read and rt2x00usb_register_write. * BBP and RF register require indirect register access, * and use the CSR registers BBPCSR and RFCSR to achieve this. * These indirect registers work with busy bits, @@ -55,113 +55,35 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); * between each attampt. When the busy bit is still set at that time, * the access attempt is considered to have failed, * and we will print an error. - * The _lock versions must be used if you already hold the usb_cache_mutex + * The _lock versions must be used if you already hold the csr_mutex */ -static inline void rt73usb_register_read(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, u32 *value) -{ - __le32 reg; - rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ, - USB_VENDOR_REQUEST_IN, offset, - ®, sizeof(u32), REGISTER_TIMEOUT); - *value = le32_to_cpu(reg); -} - -static inline void rt73usb_register_read_lock(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, u32 *value) -{ - __le32 reg; - rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ, - USB_VENDOR_REQUEST_IN, offset, - ®, sizeof(u32), REGISTER_TIMEOUT); - *value = le32_to_cpu(reg); -} - -static inline void rt73usb_register_multiread(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - void *value, const u32 length) -{ - rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ, - USB_VENDOR_REQUEST_IN, offset, - value, length, - REGISTER_TIMEOUT32(length)); -} - -static inline void rt73usb_register_write(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, u32 value) -{ - __le32 reg = cpu_to_le32(value); - rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE, - USB_VENDOR_REQUEST_OUT, offset, - ®, sizeof(u32), REGISTER_TIMEOUT); -} - -static inline void rt73usb_register_write_lock(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, u32 value) -{ - __le32 reg = cpu_to_le32(value); - rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_WRITE, - USB_VENDOR_REQUEST_OUT, offset, - ®, sizeof(u32), REGISTER_TIMEOUT); -} - -static inline void rt73usb_register_multiwrite(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - void *value, const u32 length) -{ - rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE, - USB_VENDOR_REQUEST_OUT, offset, - value, length, - REGISTER_TIMEOUT32(length)); -} - -static u32 rt73usb_bbp_check(struct rt2x00_dev *rt2x00dev) -{ - u32 reg; - unsigned int i; - - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt73usb_register_read_lock(rt2x00dev, PHY_CSR3, ®); - if (!rt2x00_get_field32(reg, PHY_CSR3_BUSY)) - break; - udelay(REGISTER_BUSY_DELAY); - } - - return reg; -} +#define WAIT_FOR_BBP(__dev, __reg) \ + rt2x00usb_regbusy_read((__dev), PHY_CSR3, PHY_CSR3_BUSY, (__reg)) +#define WAIT_FOR_RF(__dev, __reg) \ + rt2x00usb_regbusy_read((__dev), PHY_CSR4, PHY_CSR4_BUSY, (__reg)) static void rt73usb_bbp_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u8 value) { u32 reg; - mutex_lock(&rt2x00dev->usb_cache_mutex); + mutex_lock(&rt2x00dev->csr_mutex); /* - * Wait until the BBP becomes ready. + * Wait until the BBP becomes available, afterwards we + * can safely write the new data into the register. */ - reg = rt73usb_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) - goto exit_fail; - - /* - * Write the data into the BBP. - */ - reg = 0; - rt2x00_set_field32(®, PHY_CSR3_VALUE, value); - rt2x00_set_field32(®, PHY_CSR3_REGNUM, word); - rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); - rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 0); - - rt73usb_register_write_lock(rt2x00dev, PHY_CSR3, reg); - mutex_unlock(&rt2x00dev->usb_cache_mutex); - - return; - -exit_fail: - mutex_unlock(&rt2x00dev->usb_cache_mutex); + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, PHY_CSR3_VALUE, value); + rt2x00_set_field32(®, PHY_CSR3_REGNUM, word); + rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); + rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 0); + + rt2x00usb_register_write_lock(rt2x00dev, PHY_CSR3, reg); + } - ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n"); + mutex_unlock(&rt2x00dev->csr_mutex); } static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev, @@ -169,123 +91,95 @@ static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev, { u32 reg; - mutex_lock(&rt2x00dev->usb_cache_mutex); - - /* - * Wait until the BBP becomes ready. - */ - reg = rt73usb_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) - goto exit_fail; + mutex_lock(&rt2x00dev->csr_mutex); /* - * Write the request into the BBP. + * Wait until the BBP becomes available, afterwards we + * can safely write the read request into the register. + * After the data has been written, we wait until hardware + * returns the correct value, if at any time the register + * doesn't become available in time, reg will be 0xffffffff + * which means we return 0xff to the caller. */ - reg = 0; - rt2x00_set_field32(®, PHY_CSR3_REGNUM, word); - rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); - rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 1); + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, PHY_CSR3_REGNUM, word); + rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); + rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 1); - rt73usb_register_write_lock(rt2x00dev, PHY_CSR3, reg); + rt2x00usb_register_write_lock(rt2x00dev, PHY_CSR3, reg); - /* - * Wait until the BBP becomes ready. - */ - reg = rt73usb_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) - goto exit_fail; + WAIT_FOR_BBP(rt2x00dev, ®); + } *value = rt2x00_get_field32(reg, PHY_CSR3_VALUE); - mutex_unlock(&rt2x00dev->usb_cache_mutex); - - return; - -exit_fail: - mutex_unlock(&rt2x00dev->usb_cache_mutex); - ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n"); - *value = 0xff; + mutex_unlock(&rt2x00dev->csr_mutex); } static void rt73usb_rf_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u32 value) { u32 reg; - unsigned int i; if (!word) return; - mutex_lock(&rt2x00dev->usb_cache_mutex); - - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt73usb_register_read_lock(rt2x00dev, PHY_CSR4, ®); - if (!rt2x00_get_field32(reg, PHY_CSR4_BUSY)) - goto rf_write; - udelay(REGISTER_BUSY_DELAY); - } - - mutex_unlock(&rt2x00dev->usb_cache_mutex); - ERROR(rt2x00dev, "PHY_CSR4 register busy. Write failed.\n"); - return; - -rf_write: - reg = 0; - rt2x00_set_field32(®, PHY_CSR4_VALUE, value); + mutex_lock(&rt2x00dev->csr_mutex); /* - * RF5225 and RF2527 contain 21 bits per RF register value, - * all others contain 20 bits. + * Wait until the RF becomes available, afterwards we + * can safely write the new data into the register. */ - rt2x00_set_field32(®, PHY_CSR4_NUMBER_OF_BITS, - 20 + (rt2x00_rf(&rt2x00dev->chip, RF5225) || - rt2x00_rf(&rt2x00dev->chip, RF2527))); - rt2x00_set_field32(®, PHY_CSR4_IF_SELECT, 0); - rt2x00_set_field32(®, PHY_CSR4_BUSY, 1); - - rt73usb_register_write_lock(rt2x00dev, PHY_CSR4, reg); - rt2x00_rf_write(rt2x00dev, word, value); - mutex_unlock(&rt2x00dev->usb_cache_mutex); -} - -#ifdef CONFIG_RT2X00_LIB_DEBUGFS -#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u32)) ) - -static void rt73usb_read_csr(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u32 *data) -{ - rt73usb_register_read(rt2x00dev, CSR_OFFSET(word), data); -} + if (WAIT_FOR_RF(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, PHY_CSR4_VALUE, value); + /* + * RF5225 and RF2527 contain 21 bits per RF register value, + * all others contain 20 bits. + */ + rt2x00_set_field32(®, PHY_CSR4_NUMBER_OF_BITS, + 20 + (rt2x00_rf(&rt2x00dev->chip, RF5225) || + rt2x00_rf(&rt2x00dev->chip, RF2527))); + rt2x00_set_field32(®, PHY_CSR4_IF_SELECT, 0); + rt2x00_set_field32(®, PHY_CSR4_BUSY, 1); + + rt2x00usb_register_write_lock(rt2x00dev, PHY_CSR4, reg); + rt2x00_rf_write(rt2x00dev, word, value); + } -static void rt73usb_write_csr(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u32 data) -{ - rt73usb_register_write(rt2x00dev, CSR_OFFSET(word), data); + mutex_unlock(&rt2x00dev->csr_mutex); } +#ifdef CONFIG_RT2X00_LIB_DEBUGFS static const struct rt2x00debug rt73usb_rt2x00debug = { .owner = THIS_MODULE, .csr = { - .read = rt73usb_read_csr, - .write = rt73usb_write_csr, + .read = rt2x00usb_register_read, + .write = rt2x00usb_register_write, + .flags = RT2X00DEBUGFS_OFFSET, + .word_base = CSR_REG_BASE, .word_size = sizeof(u32), .word_count = CSR_REG_SIZE / sizeof(u32), }, .eeprom = { .read = rt2x00_eeprom_read, .write = rt2x00_eeprom_write, + .word_base = EEPROM_BASE, .word_size = sizeof(u16), .word_count = EEPROM_SIZE / sizeof(u16), }, .bbp = { .read = rt73usb_bbp_read, .write = rt73usb_bbp_write, + .word_base = BBP_BASE, .word_size = sizeof(u8), .word_count = BBP_SIZE / sizeof(u8), }, .rf = { .read = rt2x00_rf_read, .write = rt73usb_rf_write, + .word_base = RF_BASE, .word_size = sizeof(u32), .word_count = RF_SIZE / sizeof(u32), }, @@ -341,10 +235,10 @@ static int rt73usb_blink_set(struct led_classdev *led_cdev, container_of(led_cdev, struct rt2x00_led, led_dev); u32 reg; - rt73usb_register_read(led->rt2x00dev, MAC_CSR14, ®); + rt2x00usb_register_read(led->rt2x00dev, MAC_CSR14, ®); rt2x00_set_field32(®, MAC_CSR14_ON_PERIOD, *delay_on); rt2x00_set_field32(®, MAC_CSR14_OFF_PERIOD, *delay_off); - rt73usb_register_write(led->rt2x00dev, MAC_CSR14, reg); + rt2x00usb_register_write(led->rt2x00dev, MAC_CSR14, reg); return 0; } @@ -387,7 +281,7 @@ static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev, */ mask = (0xf << crypto->bssidx); - rt73usb_register_read(rt2x00dev, SEC_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, SEC_CSR0, ®); reg &= mask; if (reg && reg == mask) @@ -424,16 +318,16 @@ static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev, field.bit_offset = (3 * key->hw_key_idx); field.bit_mask = 0x7 << field.bit_offset; - rt73usb_register_read(rt2x00dev, SEC_CSR1, ®); + rt2x00usb_register_read(rt2x00dev, SEC_CSR1, ®); rt2x00_set_field32(®, field, crypto->cipher); - rt73usb_register_write(rt2x00dev, SEC_CSR1, reg); + rt2x00usb_register_write(rt2x00dev, SEC_CSR1, reg); } else { field.bit_offset = (3 * (key->hw_key_idx - 8)); field.bit_mask = 0x7 << field.bit_offset; - rt73usb_register_read(rt2x00dev, SEC_CSR5, ®); + rt2x00usb_register_read(rt2x00dev, SEC_CSR5, ®); rt2x00_set_field32(®, field, crypto->cipher); - rt73usb_register_write(rt2x00dev, SEC_CSR5, reg); + rt2x00usb_register_write(rt2x00dev, SEC_CSR5, reg); } /* @@ -456,12 +350,12 @@ static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev, */ mask = 1 << key->hw_key_idx; - rt73usb_register_read(rt2x00dev, SEC_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, SEC_CSR0, ®); if (crypto->cmd == SET_KEY) reg |= mask; else if (crypto->cmd == DISABLE_KEY) reg &= ~mask; - rt73usb_register_write(rt2x00dev, SEC_CSR0, reg); + rt2x00usb_register_write(rt2x00dev, SEC_CSR0, reg); return 0; } @@ -486,10 +380,10 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev, * When both registers are full, we drop the key, * otherwise we use the first invalid entry. */ - rt73usb_register_read(rt2x00dev, SEC_CSR2, ®); + rt2x00usb_register_read(rt2x00dev, SEC_CSR2, ®); if (reg && reg == ~0) { key->hw_key_idx = 32; - rt73usb_register_read(rt2x00dev, SEC_CSR3, ®); + rt2x00usb_register_read(rt2x00dev, SEC_CSR3, ®); if (reg && reg == ~0) return -ENOSPC; } @@ -517,14 +411,14 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev, /* * Send the address and cipher type to the hardware register. * This data fits within the CSR cache size, so we can use - * rt73usb_register_multiwrite() directly. + * rt2x00usb_register_multiwrite() directly. */ memset(&addr_entry, 0, sizeof(addr_entry)); memcpy(&addr_entry, crypto->address, ETH_ALEN); addr_entry.cipher = crypto->cipher; reg = PAIRWISE_TA_ENTRY(key->hw_key_idx); - rt73usb_register_multiwrite(rt2x00dev, reg, + rt2x00usb_register_multiwrite(rt2x00dev, reg, &addr_entry, sizeof(addr_entry)); /* @@ -532,9 +426,9 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev, * without this received frames will not be decrypted * by the hardware. */ - rt73usb_register_read(rt2x00dev, SEC_CSR4, ®); + rt2x00usb_register_read(rt2x00dev, SEC_CSR4, ®); reg |= (1 << crypto->bssidx); - rt73usb_register_write(rt2x00dev, SEC_CSR4, reg); + rt2x00usb_register_write(rt2x00dev, SEC_CSR4, reg); /* * The driver does not support the IV/EIV generation @@ -557,21 +451,21 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev, if (key->hw_key_idx < 32) { mask = 1 << key->hw_key_idx; - rt73usb_register_read(rt2x00dev, SEC_CSR2, ®); + rt2x00usb_register_read(rt2x00dev, SEC_CSR2, ®); if (crypto->cmd == SET_KEY) reg |= mask; else if (crypto->cmd == DISABLE_KEY) reg &= ~mask; - rt73usb_register_write(rt2x00dev, SEC_CSR2, reg); + rt2x00usb_register_write(rt2x00dev, SEC_CSR2, reg); } else { mask = 1 << (key->hw_key_idx - 32); - rt73usb_register_read(rt2x00dev, SEC_CSR3, ®); + rt2x00usb_register_read(rt2x00dev, SEC_CSR3, ®); if (crypto->cmd == SET_KEY) reg |= mask; else if (crypto->cmd == DISABLE_KEY) reg &= ~mask; - rt73usb_register_write(rt2x00dev, SEC_CSR3, reg); + rt2x00usb_register_write(rt2x00dev, SEC_CSR3, reg); } return 0; @@ -588,7 +482,7 @@ static void rt73usb_config_filter(struct rt2x00_dev *rt2x00dev, * and broadcast frames will always be accepted since * there is no filter for it at this time. */ - rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, !(filter_flags & FIF_FCSFAIL)); rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, @@ -606,7 +500,7 @@ static void rt73usb_config_filter(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, TXRX_CSR0_DROP_BROADCAST, 0); rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, !(filter_flags & FIF_CONTROL)); - rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg); } static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev, @@ -625,16 +519,16 @@ static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev, * bits which (when set to 0) will invalidate the entire beacon. */ beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx); - rt73usb_register_write(rt2x00dev, beacon_base, 0); + rt2x00usb_register_write(rt2x00dev, beacon_base, 0); /* * Enable synchronisation. */ - rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, conf->sync); rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); - rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); } if (flags & CONFIG_UPDATE_MAC) { @@ -642,7 +536,7 @@ static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, MAC_CSR3_UNICAST_TO_ME_MASK, 0xff); conf->mac[1] = cpu_to_le32(reg); - rt73usb_register_multiwrite(rt2x00dev, MAC_CSR2, + rt2x00usb_register_multiwrite(rt2x00dev, MAC_CSR2, conf->mac, sizeof(conf->mac)); } @@ -651,7 +545,7 @@ static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, MAC_CSR5_BSS_ID_MASK, 3); conf->bssid[1] = cpu_to_le32(reg); - rt73usb_register_multiwrite(rt2x00dev, MAC_CSR4, + rt2x00usb_register_multiwrite(rt2x00dev, MAC_CSR4, conf->bssid, sizeof(conf->bssid)); } } @@ -661,95 +555,26 @@ static void rt73usb_config_erp(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, erp->ack_timeout); - rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg); - rt73usb_register_read(rt2x00dev, TXRX_CSR4, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR4, ®); rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, !!erp->short_preamble); - rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg); -} - -static void rt73usb_config_lna_gain(struct rt2x00_dev *rt2x00dev, - struct rt2x00lib_conf *libconf) -{ - u16 eeprom; - short lna_gain = 0; - - if (libconf->band == IEEE80211_BAND_2GHZ) { - if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) - lna_gain += 14; - - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom); - lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1); - } else { - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom); - lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1); - } - - rt2x00dev->lna_gain = lna_gain; -} - -static void rt73usb_config_phymode(struct rt2x00_dev *rt2x00dev, - const int basic_rate_mask) -{ - rt73usb_register_write(rt2x00dev, TXRX_CSR5, basic_rate_mask); -} - -static void rt73usb_config_channel(struct rt2x00_dev *rt2x00dev, - struct rf_channel *rf, const int txpower) -{ - u8 r3; - u8 r94; - u8 smart; - - rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); - rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset); - - smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) || - rt2x00_rf(&rt2x00dev->chip, RF2527)); - - rt73usb_bbp_read(rt2x00dev, 3, &r3); - rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart); - rt73usb_bbp_write(rt2x00dev, 3, r3); - - r94 = 6; - if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94)) - r94 += txpower - MAX_TXPOWER; - else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94)) - r94 += txpower; - rt73usb_bbp_write(rt2x00dev, 94, r94); - - rt73usb_rf_write(rt2x00dev, 1, rf->rf1); - rt73usb_rf_write(rt2x00dev, 2, rf->rf2); - rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); - rt73usb_rf_write(rt2x00dev, 4, rf->rf4); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg); - rt73usb_rf_write(rt2x00dev, 1, rf->rf1); - rt73usb_rf_write(rt2x00dev, 2, rf->rf2); - rt73usb_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004); - rt73usb_rf_write(rt2x00dev, 4, rf->rf4); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR5, erp->basic_rates); - rt73usb_rf_write(rt2x00dev, 1, rf->rf1); - rt73usb_rf_write(rt2x00dev, 2, rf->rf2); - rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); - rt73usb_rf_write(rt2x00dev, 4, rf->rf4); + rt2x00usb_register_read(rt2x00dev, MAC_CSR9, ®); + rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, erp->slot_time); + rt2x00usb_register_write(rt2x00dev, MAC_CSR9, reg); - udelay(10); -} - -static void rt73usb_config_txpower(struct rt2x00_dev *rt2x00dev, - const int txpower) -{ - struct rf_channel rf; - - rt2x00_rf_read(rt2x00dev, 1, &rf.rf1); - rt2x00_rf_read(rt2x00dev, 2, &rf.rf2); - rt2x00_rf_read(rt2x00dev, 3, &rf.rf3); - rt2x00_rf_read(rt2x00dev, 4, &rf.rf4); - - rt73usb_config_channel(rt2x00dev, &rf, txpower); + rt2x00usb_register_read(rt2x00dev, MAC_CSR8, ®); + rt2x00_set_field32(®, MAC_CSR8_SIFS, erp->sifs); + rt2x00_set_field32(®, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3); + rt2x00_set_field32(®, MAC_CSR8_EIFS, erp->eifs); + rt2x00usb_register_write(rt2x00dev, MAC_CSR8, reg); } static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev, @@ -869,8 +694,8 @@ static const struct antenna_sel antenna_sel_bg[] = { { 98, { 0x48, 0x48 } }, }; -static void rt73usb_config_antenna(struct rt2x00_dev *rt2x00dev, - struct antenna_setup *ant) +static void rt73usb_config_ant(struct rt2x00_dev *rt2x00dev, + struct antenna_setup *ant) { const struct antenna_sel *sel; unsigned int lna; @@ -895,14 +720,14 @@ static void rt73usb_config_antenna(struct rt2x00_dev *rt2x00dev, for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++) rt73usb_bbp_write(rt2x00dev, sel[i].word, sel[i].value[lna]); - rt73usb_register_read(rt2x00dev, PHY_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, PHY_CSR0, ®); rt2x00_set_field32(®, PHY_CSR0_PA_PE_BG, (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ)); rt2x00_set_field32(®, PHY_CSR0_PA_PE_A, (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ)); - rt73usb_register_write(rt2x00dev, PHY_CSR0, reg); + rt2x00usb_register_write(rt2x00dev, PHY_CSR0, reg); if (rt2x00_rf(&rt2x00dev->chip, RF5226) || rt2x00_rf(&rt2x00dev->chip, RF5225)) @@ -912,33 +737,111 @@ static void rt73usb_config_antenna(struct rt2x00_dev *rt2x00dev, rt73usb_config_antenna_2x(rt2x00dev, ant); } -static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev, +static void rt73usb_config_lna_gain(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf) +{ + u16 eeprom; + short lna_gain = 0; + + if (libconf->conf->channel->band == IEEE80211_BAND_2GHZ) { + if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) + lna_gain += 14; + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom); + lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1); + } else { + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom); + lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1); + } + + rt2x00dev->lna_gain = lna_gain; +} + +static void rt73usb_config_channel(struct rt2x00_dev *rt2x00dev, + struct rf_channel *rf, const int txpower) +{ + u8 r3; + u8 r94; + u8 smart; + + rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); + rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset); + + smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) || + rt2x00_rf(&rt2x00dev->chip, RF2527)); + + rt73usb_bbp_read(rt2x00dev, 3, &r3); + rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart); + rt73usb_bbp_write(rt2x00dev, 3, r3); + + r94 = 6; + if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94)) + r94 += txpower - MAX_TXPOWER; + else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94)) + r94 += txpower; + rt73usb_bbp_write(rt2x00dev, 94, r94); + + rt73usb_rf_write(rt2x00dev, 1, rf->rf1); + rt73usb_rf_write(rt2x00dev, 2, rf->rf2); + rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); + rt73usb_rf_write(rt2x00dev, 4, rf->rf4); + + rt73usb_rf_write(rt2x00dev, 1, rf->rf1); + rt73usb_rf_write(rt2x00dev, 2, rf->rf2); + rt73usb_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004); + rt73usb_rf_write(rt2x00dev, 4, rf->rf4); + + rt73usb_rf_write(rt2x00dev, 1, rf->rf1); + rt73usb_rf_write(rt2x00dev, 2, rf->rf2); + rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); + rt73usb_rf_write(rt2x00dev, 4, rf->rf4); + + udelay(10); +} + +static void rt73usb_config_txpower(struct rt2x00_dev *rt2x00dev, + const int txpower) +{ + struct rf_channel rf; + + rt2x00_rf_read(rt2x00dev, 1, &rf.rf1); + rt2x00_rf_read(rt2x00dev, 2, &rf.rf2); + rt2x00_rf_read(rt2x00dev, 3, &rf.rf3); + rt2x00_rf_read(rt2x00dev, 4, &rf.rf4); + + rt73usb_config_channel(rt2x00dev, &rf, txpower); +} + +static void rt73usb_config_retry_limit(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf) { u32 reg; - rt73usb_register_read(rt2x00dev, MAC_CSR9, ®); - rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, libconf->slot_time); - rt73usb_register_write(rt2x00dev, MAC_CSR9, reg); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR4, ®); + rt2x00_set_field32(®, TXRX_CSR4_LONG_RETRY_LIMIT, + libconf->conf->long_frame_max_tx_count); + rt2x00_set_field32(®, TXRX_CSR4_SHORT_RETRY_LIMIT, + libconf->conf->short_frame_max_tx_count); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg); +} - rt73usb_register_read(rt2x00dev, MAC_CSR8, ®); - rt2x00_set_field32(®, MAC_CSR8_SIFS, libconf->sifs); - rt2x00_set_field32(®, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3); - rt2x00_set_field32(®, MAC_CSR8_EIFS, libconf->eifs); - rt73usb_register_write(rt2x00dev, MAC_CSR8, reg); +static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf) +{ + u32 reg; - rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); - rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg); - rt73usb_register_read(rt2x00dev, TXRX_CSR4, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR4, ®); rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_ENABLE, 1); - rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg); - rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, libconf->conf->beacon_int * 16); - rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); } static void rt73usb_config(struct rt2x00_dev *rt2x00dev, @@ -948,16 +851,15 @@ static void rt73usb_config(struct rt2x00_dev *rt2x00dev, /* Always recalculate LNA gain before changing configuration */ rt73usb_config_lna_gain(rt2x00dev, libconf); - if (flags & CONFIG_UPDATE_PHYMODE) - rt73usb_config_phymode(rt2x00dev, libconf->basic_rates); - if (flags & CONFIG_UPDATE_CHANNEL) + if (flags & IEEE80211_CONF_CHANGE_CHANNEL) rt73usb_config_channel(rt2x00dev, &libconf->rf, libconf->conf->power_level); - if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL)) + if ((flags & IEEE80211_CONF_CHANGE_POWER) && + !(flags & IEEE80211_CONF_CHANGE_CHANNEL)) rt73usb_config_txpower(rt2x00dev, libconf->conf->power_level); - if (flags & CONFIG_UPDATE_ANTENNA) - rt73usb_config_antenna(rt2x00dev, &libconf->ant); - if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) + if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) + rt73usb_config_retry_limit(rt2x00dev, libconf); + if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) rt73usb_config_duration(rt2x00dev, libconf); } @@ -972,13 +874,13 @@ static void rt73usb_link_stats(struct rt2x00_dev *rt2x00dev, /* * Update FCS error count from register. */ - rt73usb_register_read(rt2x00dev, STA_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, STA_CSR0, ®); qual->rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR); /* * Update False CCA count from register. */ - rt73usb_register_read(rt2x00dev, STA_CSR1, ®); + rt2x00usb_register_read(rt2x00dev, STA_CSR1, ®); qual->false_cca = rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR); } @@ -1138,7 +1040,7 @@ static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, const void *data, * Wait for stable hardware. */ for (i = 0; i < 100; i++) { - rt73usb_register_read(rt2x00dev, MAC_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, MAC_CSR0, ®); if (reg) break; msleep(1); @@ -1180,13 +1082,13 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) { u32 reg; - rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); rt2x00_set_field32(®, TXRX_CSR0_AUTO_TX_SEQ, 1); rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, 0); rt2x00_set_field32(®, TXRX_CSR0_TX_WITHOUT_WAITING, 0); - rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg); - rt73usb_register_read(rt2x00dev, TXRX_CSR1, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR1, ®); rt2x00_set_field32(®, TXRX_CSR1_BBP_ID0, 47); /* CCK Signal */ rt2x00_set_field32(®, TXRX_CSR1_BBP_ID0_VALID, 1); rt2x00_set_field32(®, TXRX_CSR1_BBP_ID1, 30); /* Rssi */ @@ -1195,12 +1097,12 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, TXRX_CSR1_BBP_ID2_VALID, 1); rt2x00_set_field32(®, TXRX_CSR1_BBP_ID3, 30); /* Rssi */ rt2x00_set_field32(®, TXRX_CSR1_BBP_ID3_VALID, 1); - rt73usb_register_write(rt2x00dev, TXRX_CSR1, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR1, reg); /* * CCK TXD BBP registers */ - rt73usb_register_read(rt2x00dev, TXRX_CSR2, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR2, ®); rt2x00_set_field32(®, TXRX_CSR2_BBP_ID0, 13); rt2x00_set_field32(®, TXRX_CSR2_BBP_ID0_VALID, 1); rt2x00_set_field32(®, TXRX_CSR2_BBP_ID1, 12); @@ -1209,77 +1111,77 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, TXRX_CSR2_BBP_ID2_VALID, 1); rt2x00_set_field32(®, TXRX_CSR2_BBP_ID3, 10); rt2x00_set_field32(®, TXRX_CSR2_BBP_ID3_VALID, 1); - rt73usb_register_write(rt2x00dev, TXRX_CSR2, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR2, reg); /* * OFDM TXD BBP registers */ - rt73usb_register_read(rt2x00dev, TXRX_CSR3, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR3, ®); rt2x00_set_field32(®, TXRX_CSR3_BBP_ID0, 7); rt2x00_set_field32(®, TXRX_CSR3_BBP_ID0_VALID, 1); rt2x00_set_field32(®, TXRX_CSR3_BBP_ID1, 6); rt2x00_set_field32(®, TXRX_CSR3_BBP_ID1_VALID, 1); rt2x00_set_field32(®, TXRX_CSR3_BBP_ID2, 5); rt2x00_set_field32(®, TXRX_CSR3_BBP_ID2_VALID, 1); - rt73usb_register_write(rt2x00dev, TXRX_CSR3, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR3, reg); - rt73usb_register_read(rt2x00dev, TXRX_CSR7, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR7, ®); rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_6MBS, 59); rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_9MBS, 53); rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_12MBS, 49); rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_18MBS, 46); - rt73usb_register_write(rt2x00dev, TXRX_CSR7, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR7, reg); - rt73usb_register_read(rt2x00dev, TXRX_CSR8, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR8, ®); rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_24MBS, 44); rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_36MBS, 42); rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_48MBS, 42); rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_54MBS, 42); - rt73usb_register_write(rt2x00dev, TXRX_CSR8, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR8, reg); - rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, 0); rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0); rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 0); rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); rt2x00_set_field32(®, TXRX_CSR9_TIMESTAMP_COMPENSATE, 0); - rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); - rt73usb_register_write(rt2x00dev, TXRX_CSR15, 0x0000000f); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR15, 0x0000000f); - rt73usb_register_read(rt2x00dev, MAC_CSR6, ®); + rt2x00usb_register_read(rt2x00dev, MAC_CSR6, ®); rt2x00_set_field32(®, MAC_CSR6_MAX_FRAME_UNIT, 0xfff); - rt73usb_register_write(rt2x00dev, MAC_CSR6, reg); + rt2x00usb_register_write(rt2x00dev, MAC_CSR6, reg); - rt73usb_register_write(rt2x00dev, MAC_CSR10, 0x00000718); + rt2x00usb_register_write(rt2x00dev, MAC_CSR10, 0x00000718); if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE)) return -EBUSY; - rt73usb_register_write(rt2x00dev, MAC_CSR13, 0x00007f00); + rt2x00usb_register_write(rt2x00dev, MAC_CSR13, 0x00007f00); /* * Invalidate all Shared Keys (SEC_CSR0), * and clear the Shared key Cipher algorithms (SEC_CSR1 & SEC_CSR5) */ - rt73usb_register_write(rt2x00dev, SEC_CSR0, 0x00000000); - rt73usb_register_write(rt2x00dev, SEC_CSR1, 0x00000000); - rt73usb_register_write(rt2x00dev, SEC_CSR5, 0x00000000); + rt2x00usb_register_write(rt2x00dev, SEC_CSR0, 0x00000000); + rt2x00usb_register_write(rt2x00dev, SEC_CSR1, 0x00000000); + rt2x00usb_register_write(rt2x00dev, SEC_CSR5, 0x00000000); reg = 0x000023b0; if (rt2x00_rf(&rt2x00dev->chip, RF5225) || rt2x00_rf(&rt2x00dev->chip, RF2527)) rt2x00_set_field32(®, PHY_CSR1_RF_RPI, 1); - rt73usb_register_write(rt2x00dev, PHY_CSR1, reg); + rt2x00usb_register_write(rt2x00dev, PHY_CSR1, reg); - rt73usb_register_write(rt2x00dev, PHY_CSR5, 0x00040a06); - rt73usb_register_write(rt2x00dev, PHY_CSR6, 0x00080606); - rt73usb_register_write(rt2x00dev, PHY_CSR7, 0x00000408); + rt2x00usb_register_write(rt2x00dev, PHY_CSR5, 0x00040a06); + rt2x00usb_register_write(rt2x00dev, PHY_CSR6, 0x00080606); + rt2x00usb_register_write(rt2x00dev, PHY_CSR7, 0x00000408); - rt73usb_register_read(rt2x00dev, MAC_CSR9, ®); + rt2x00usb_register_read(rt2x00dev, MAC_CSR9, ®); rt2x00_set_field32(®, MAC_CSR9_CW_SELECT, 0); - rt73usb_register_write(rt2x00dev, MAC_CSR9, reg); + rt2x00usb_register_write(rt2x00dev, MAC_CSR9, reg); /* * Clear all beacons @@ -1287,36 +1189,36 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) * the first byte since that byte contains the VALID and OWNER * bits which (when set to 0) will invalidate the entire beacon. */ - rt73usb_register_write(rt2x00dev, HW_BEACON_BASE0, 0); - rt73usb_register_write(rt2x00dev, HW_BEACON_BASE1, 0); - rt73usb_register_write(rt2x00dev, HW_BEACON_BASE2, 0); - rt73usb_register_write(rt2x00dev, HW_BEACON_BASE3, 0); + rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE0, 0); + rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE1, 0); + rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE2, 0); + rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE3, 0); /* * We must clear the error counters. * These registers are cleared on read, * so we may pass a useless variable to store the value. */ - rt73usb_register_read(rt2x00dev, STA_CSR0, ®); - rt73usb_register_read(rt2x00dev, STA_CSR1, ®); - rt73usb_register_read(rt2x00dev, STA_CSR2, ®); + rt2x00usb_register_read(rt2x00dev, STA_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, STA_CSR1, ®); + rt2x00usb_register_read(rt2x00dev, STA_CSR2, ®); /* * Reset MAC and BBP registers. */ - rt73usb_register_read(rt2x00dev, MAC_CSR1, ®); + rt2x00usb_register_read(rt2x00dev, MAC_CSR1, ®); rt2x00_set_field32(®, MAC_CSR1_SOFT_RESET, 1); rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 1); - rt73usb_register_write(rt2x00dev, MAC_CSR1, reg); + rt2x00usb_register_write(rt2x00dev, MAC_CSR1, reg); - rt73usb_register_read(rt2x00dev, MAC_CSR1, ®); + rt2x00usb_register_read(rt2x00dev, MAC_CSR1, ®); rt2x00_set_field32(®, MAC_CSR1_SOFT_RESET, 0); rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 0); - rt73usb_register_write(rt2x00dev, MAC_CSR1, reg); + rt2x00usb_register_write(rt2x00dev, MAC_CSR1, reg); - rt73usb_register_read(rt2x00dev, MAC_CSR1, ®); + rt2x00usb_register_read(rt2x00dev, MAC_CSR1, ®); rt2x00_set_field32(®, MAC_CSR1_HOST_READY, 1); - rt73usb_register_write(rt2x00dev, MAC_CSR1, reg); + rt2x00usb_register_write(rt2x00dev, MAC_CSR1, reg); return 0; } @@ -1394,11 +1296,11 @@ static void rt73usb_toggle_rx(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, (state == STATE_RADIO_RX_OFF) || (state == STATE_RADIO_RX_OFF_LINK)); - rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg); } static int rt73usb_enable_radio(struct rt2x00_dev *rt2x00dev) @@ -1415,12 +1317,12 @@ static int rt73usb_enable_radio(struct rt2x00_dev *rt2x00dev) static void rt73usb_disable_radio(struct rt2x00_dev *rt2x00dev) { - rt73usb_register_write(rt2x00dev, MAC_CSR10, 0x00001818); + rt2x00usb_register_write(rt2x00dev, MAC_CSR10, 0x00001818); /* * Disable synchronisation. */ - rt73usb_register_write(rt2x00dev, TXRX_CSR9, 0); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, 0); rt2x00usb_disable_radio(rt2x00dev); } @@ -1433,10 +1335,10 @@ static int rt73usb_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) put_to_sleep = (state != STATE_AWAKE); - rt73usb_register_read(rt2x00dev, MAC_CSR12, ®); + rt2x00usb_register_read(rt2x00dev, MAC_CSR12, ®); rt2x00_set_field32(®, MAC_CSR12_FORCE_WAKEUP, !put_to_sleep); rt2x00_set_field32(®, MAC_CSR12_PUT_TO_SLEEP, put_to_sleep); - rt73usb_register_write(rt2x00dev, MAC_CSR12, reg); + rt2x00usb_register_write(rt2x00dev, MAC_CSR12, reg); /* * Device is not guaranteed to be in the requested state yet. @@ -1444,7 +1346,7 @@ static int rt73usb_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) * device has entered the correct state. */ for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt73usb_register_read(rt2x00dev, MAC_CSR12, ®); + rt2x00usb_register_read(rt2x00dev, MAC_CSR12, ®); state = rt2x00_get_field32(reg, MAC_CSR12_BBP_CURRENT_STATE); if (state == !put_to_sleep) return 0; @@ -1526,8 +1428,8 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_desc_write(txd, 2, word); if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags)) { - _rt2x00_desc_write(txd, 3, skbdesc->iv); - _rt2x00_desc_write(txd, 4, skbdesc->eiv); + _rt2x00_desc_write(txd, 3, skbdesc->iv[0]); + _rt2x00_desc_write(txd, 4, skbdesc->iv[1]); } rt2x00_desc_read(txd, 5, &word); @@ -1584,11 +1486,11 @@ static void rt73usb_write_beacon(struct queue_entry *entry) * Disable beaconing while we are reloading the beacon data, * otherwise we might be sending out invalid data. */ - rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0); rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); - rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); /* * Write entire beacon with descriptor to register. @@ -1606,8 +1508,7 @@ static void rt73usb_write_beacon(struct queue_entry *entry) entry->skb = NULL; } -static int rt73usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb) +static int rt73usb_get_tx_data_len(struct queue_entry *entry) { int length; @@ -1615,8 +1516,8 @@ static int rt73usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev, * The length _must_ be a multiple of 4, * but it must _not_ be a multiple of the USB packet size. */ - length = roundup(skb->len, 4); - length += (4 * !(length % rt2x00dev->usb_maxpacket)); + length = roundup(entry->skb->len, 4); + length += (4 * !(length % entry->queue->usb_maxpacket)); return length; } @@ -1635,14 +1536,14 @@ static void rt73usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, * For Wi-Fi faily generated beacons between participating stations. * Set TBTT phase adaptive adjustment step to 8us (default 16us) */ - rt73usb_register_write(rt2x00dev, TXRX_CSR10, 0x00001008); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR10, 0x00001008); - rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); if (!rt2x00_get_field32(reg, TXRX_CSR9_BEACON_GEN)) { rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 1); - rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); } } @@ -1685,7 +1586,7 @@ static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) } static void rt73usb_fill_rxdone(struct queue_entry *entry, - struct rxdone_entry_desc *rxdesc) + struct rxdone_entry_desc *rxdesc) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); @@ -1717,9 +1618,12 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry, } if (rxdesc->cipher != CIPHER_NONE) { - _rt2x00_desc_read(rxd, 2, &rxdesc->iv); - _rt2x00_desc_read(rxd, 3, &rxdesc->eiv); + _rt2x00_desc_read(rxd, 2, &rxdesc->iv[0]); + _rt2x00_desc_read(rxd, 3, &rxdesc->iv[1]); + rxdesc->dev_flags |= RXDONE_CRYPTO_IV; + _rt2x00_desc_read(rxd, 4, &rxdesc->icv); + rxdesc->dev_flags |= RXDONE_CRYPTO_ICV; /* * Hardware has stripped IV/EIV data from 802.11 frame during @@ -1781,10 +1685,8 @@ static int rt73usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) */ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); if (!is_valid_ether_addr(mac)) { - DECLARE_MAC_BUF(macbuf); - random_ether_addr(mac); - EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac)); + EEPROM(rt2x00dev, "MAC: %pM\n", mac); } rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); @@ -1883,7 +1785,7 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) * Identify RF chipset. */ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); - rt73usb_register_read(rt2x00dev, MAC_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, MAC_CSR0, ®); rt2x00_set_chip(rt2x00dev, RT2571, value, reg); if (!rt2x00_check_rev(&rt2x00dev->chip, 0x25730)) { @@ -2211,20 +2113,6 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ -static int rt73usb_set_retry_limit(struct ieee80211_hw *hw, - u32 short_retry, u32 long_retry) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - u32 reg; - - rt73usb_register_read(rt2x00dev, TXRX_CSR4, ®); - rt2x00_set_field32(®, TXRX_CSR4_LONG_RETRY_LIMIT, long_retry); - rt2x00_set_field32(®, TXRX_CSR4_SHORT_RETRY_LIMIT, short_retry); - rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg); - - return 0; -} - static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, const struct ieee80211_tx_queue_params *params) { @@ -2251,33 +2139,33 @@ static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, field.bit_offset = queue_idx * 16; field.bit_mask = 0xffff << field.bit_offset; - rt73usb_register_read(rt2x00dev, AC_TXOP_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, AC_TXOP_CSR0, ®); rt2x00_set_field32(®, field, queue->txop); - rt73usb_register_write(rt2x00dev, AC_TXOP_CSR0, reg); + rt2x00usb_register_write(rt2x00dev, AC_TXOP_CSR0, reg); } else if (queue_idx < 4) { field.bit_offset = (queue_idx - 2) * 16; field.bit_mask = 0xffff << field.bit_offset; - rt73usb_register_read(rt2x00dev, AC_TXOP_CSR1, ®); + rt2x00usb_register_read(rt2x00dev, AC_TXOP_CSR1, ®); rt2x00_set_field32(®, field, queue->txop); - rt73usb_register_write(rt2x00dev, AC_TXOP_CSR1, reg); + rt2x00usb_register_write(rt2x00dev, AC_TXOP_CSR1, reg); } /* Update WMM registers */ field.bit_offset = queue_idx * 4; field.bit_mask = 0xf << field.bit_offset; - rt73usb_register_read(rt2x00dev, AIFSN_CSR, ®); + rt2x00usb_register_read(rt2x00dev, AIFSN_CSR, ®); rt2x00_set_field32(®, field, queue->aifs); - rt73usb_register_write(rt2x00dev, AIFSN_CSR, reg); + rt2x00usb_register_write(rt2x00dev, AIFSN_CSR, reg); - rt73usb_register_read(rt2x00dev, CWMIN_CSR, ®); + rt2x00usb_register_read(rt2x00dev, CWMIN_CSR, ®); rt2x00_set_field32(®, field, queue->cw_min); - rt73usb_register_write(rt2x00dev, CWMIN_CSR, reg); + rt2x00usb_register_write(rt2x00dev, CWMIN_CSR, reg); - rt73usb_register_read(rt2x00dev, CWMAX_CSR, ®); + rt2x00usb_register_read(rt2x00dev, CWMAX_CSR, ®); rt2x00_set_field32(®, field, queue->cw_max); - rt73usb_register_write(rt2x00dev, CWMAX_CSR, reg); + rt2x00usb_register_write(rt2x00dev, CWMAX_CSR, reg); return 0; } @@ -2295,9 +2183,9 @@ static u64 rt73usb_get_tsf(struct ieee80211_hw *hw) u64 tsf; u32 reg; - rt73usb_register_read(rt2x00dev, TXRX_CSR13, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR13, ®); tsf = (u64) rt2x00_get_field32(reg, TXRX_CSR13_HIGH_TSFTIMER) << 32; - rt73usb_register_read(rt2x00dev, TXRX_CSR12, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR12, ®); tsf |= rt2x00_get_field32(reg, TXRX_CSR12_LOW_TSFTIMER); return tsf; @@ -2317,7 +2205,6 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = { .configure_filter = rt2x00mac_configure_filter, .set_key = rt2x00mac_set_key, .get_stats = rt2x00mac_get_stats, - .set_retry_limit = rt73usb_set_retry_limit, .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt73usb_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, @@ -2331,8 +2218,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { .load_firmware = rt73usb_load_firmware, .initialize = rt2x00usb_initialize, .uninitialize = rt2x00usb_uninitialize, - .init_rxentry = rt2x00usb_init_rxentry, - .init_txentry = rt2x00usb_init_txentry, + .clear_entry = rt2x00usb_clear_entry, .set_device_state = rt73usb_set_device_state, .link_stats = rt73usb_link_stats, .reset_tuner = rt73usb_reset_tuner, @@ -2348,6 +2234,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { .config_filter = rt73usb_config_filter, .config_intf = rt73usb_config_intf, .config_erp = rt73usb_config_erp, + .config_ant = rt73usb_config_ant, .config = rt73usb_config, }; diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h index 868386c457f65c39c4e15d11ef92cefbebb534a4..46e1405eb0e21ae7d643e5b6d17a011101199d30 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.h +++ b/drivers/net/wireless/rt2x00/rt73usb.h @@ -48,7 +48,9 @@ #define CSR_REG_SIZE 0x04b0 #define EEPROM_BASE 0x0000 #define EEPROM_SIZE 0x0100 +#define BBP_BASE 0x0000 #define BBP_SIZE 0x0080 +#define RF_BASE 0x0000 #define RF_SIZE 0x0014 /* diff --git a/drivers/net/wireless/rtl818x/Makefile b/drivers/net/wireless/rtl818x/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c113b3e690467fccfa266f92ab42da8a0e3275fb --- /dev/null +++ b/drivers/net/wireless/rtl818x/Makefile @@ -0,0 +1,7 @@ +rtl8180-objs := rtl8180_dev.o rtl8180_rtl8225.o rtl8180_sa2400.o rtl8180_max2820.o rtl8180_grf5101.o +rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o + +obj-$(CONFIG_RTL8180) += rtl8180.o +obj-$(CONFIG_RTL8187) += rtl8187.o + + diff --git a/drivers/net/wireless/rtl8180.h b/drivers/net/wireless/rtl818x/rtl8180.h similarity index 100% rename from drivers/net/wireless/rtl8180.h rename to drivers/net/wireless/rtl818x/rtl8180.h diff --git a/drivers/net/wireless/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c similarity index 96% rename from drivers/net/wireless/rtl8180_dev.c rename to drivers/net/wireless/rtl818x/rtl8180_dev.c index df7e78ee8a88451cfe6a00111e93327bcd8f996c..5f887fb137a9c0d4e95b2fd926e517fb479b4dae 100644 --- a/drivers/net/wireless/rtl8180_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c @@ -182,15 +182,13 @@ static void rtl8180_handle_tx(struct ieee80211_hw *dev, unsigned int prio) skb->len, PCI_DMA_TODEVICE); info = IEEE80211_SKB_CB(skb); - memset(&info->status, 0, sizeof(info->status)); + ieee80211_tx_info_clear_status(info); - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { - if (flags & RTL818X_TX_DESC_FLAG_TX_OK) - info->flags |= IEEE80211_TX_STAT_ACK; - else - info->status.excessive_retries = 1; - } - info->status.retry_count = flags & 0xFF; + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && + (flags & RTL818X_TX_DESC_FLAG_TX_OK)) + info->flags |= IEEE80211_TX_STAT_ACK; + + info->status.rates[0].count = (flags & 0xFF) + 1; ieee80211_tx_status_irqsafe(dev, skb); if (ring->entries - skb_queue_len(&ring->queue) == 2) @@ -243,6 +241,7 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb) unsigned int idx, prio; dma_addr_t mapping; u32 tx_flags; + u8 rc_flags; u16 plcp_len = 0; __le16 rts_duration = 0; @@ -261,15 +260,16 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb) tx_flags |= RTL818X_TX_DESC_FLAG_DMA | RTL818X_TX_DESC_FLAG_NO_ENC; - if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { + rc_flags = info->control.rates[0].flags; + if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) { tx_flags |= RTL818X_TX_DESC_FLAG_RTS; tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; - } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { + } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { tx_flags |= RTL818X_TX_DESC_FLAG_CTS; tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; } - if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) + if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) rts_duration = ieee80211_rts_duration(dev, priv->vif, skb->len, info); @@ -292,9 +292,9 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb) entry->plcp_len = cpu_to_le16(plcp_len); entry->tx_buf = cpu_to_le32(mapping); entry->frame_len = cpu_to_le32(skb->len); - entry->flags2 = info->control.retries[0].rate_idx >= 0 ? + entry->flags2 = info->control.rates[1].idx >= 0 ? ieee80211_get_alt_retry_rate(dev, info, 0)->bitrate << 4 : 0; - entry->retry_limit = info->control.retry_limit; + entry->retry_limit = info->control.rates[0].count; entry->flags = cpu_to_le32(tx_flags); __skb_queue_tail(&ring->queue, skb); if (ring->entries - skb_queue_len(&ring->queue) < 2) @@ -692,9 +692,10 @@ static void rtl8180_remove_interface(struct ieee80211_hw *dev, priv->vif = NULL; } -static int rtl8180_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) +static int rtl8180_config(struct ieee80211_hw *dev, u32 changed) { struct rtl8180_priv *priv = dev->priv; + struct ieee80211_conf *conf = &dev->conf; priv->rf->set_chan(dev, conf); @@ -719,6 +720,17 @@ static int rtl8180_config_interface(struct ieee80211_hw *dev, return 0; } +static void rtl8180_bss_info_changed(struct ieee80211_hw *dev, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u32 changed) +{ + struct rtl8180_priv *priv = dev->priv; + + if (changed & BSS_CHANGED_ERP_SLOT && priv->rf->conf_erp) + priv->rf->conf_erp(dev, info); +} + static void rtl8180_configure_filter(struct ieee80211_hw *dev, unsigned int changed_flags, unsigned int *total_flags, @@ -759,6 +771,7 @@ static const struct ieee80211_ops rtl8180_ops = { .remove_interface = rtl8180_remove_interface, .config = rtl8180_config, .config_interface = rtl8180_config_interface, + .bss_info_changed = rtl8180_bss_info_changed, .configure_filter = rtl8180_configure_filter, }; @@ -806,7 +819,6 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev, const char *chip_name, *rf_name = NULL; u32 reg; u16 eeprom_val; - DECLARE_MAC_BUF(mac); err = pci_enable_device(pdev); if (err) { @@ -855,7 +867,7 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev, priv = dev->priv; priv->pdev = pdev; - dev->max_altrates = 1; + dev->max_rates = 2; SET_IEEE80211_DEV(dev, &pdev->dev); pci_set_drvdata(pdev, dev); @@ -1002,8 +1014,8 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev, goto err_iounmap; } - printk(KERN_INFO "%s: hwaddr %s, %s + %s\n", - wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr), + printk(KERN_INFO "%s: hwaddr %pM, %s + %s\n", + wiphy_name(dev->wiphy), dev->wiphy->perm_addr, chip_name, priv->rf->name); return 0; diff --git a/drivers/net/wireless/rtl8180_grf5101.c b/drivers/net/wireless/rtl818x/rtl8180_grf5101.c similarity index 100% rename from drivers/net/wireless/rtl8180_grf5101.c rename to drivers/net/wireless/rtl818x/rtl8180_grf5101.c diff --git a/drivers/net/wireless/rtl8180_grf5101.h b/drivers/net/wireless/rtl818x/rtl8180_grf5101.h similarity index 100% rename from drivers/net/wireless/rtl8180_grf5101.h rename to drivers/net/wireless/rtl818x/rtl8180_grf5101.h diff --git a/drivers/net/wireless/rtl8180_max2820.c b/drivers/net/wireless/rtl818x/rtl8180_max2820.c similarity index 100% rename from drivers/net/wireless/rtl8180_max2820.c rename to drivers/net/wireless/rtl818x/rtl8180_max2820.c diff --git a/drivers/net/wireless/rtl8180_max2820.h b/drivers/net/wireless/rtl818x/rtl8180_max2820.h similarity index 100% rename from drivers/net/wireless/rtl8180_max2820.h rename to drivers/net/wireless/rtl818x/rtl8180_max2820.h diff --git a/drivers/net/wireless/rtl8180_rtl8225.c b/drivers/net/wireless/rtl818x/rtl8180_rtl8225.c similarity index 98% rename from drivers/net/wireless/rtl8180_rtl8225.c rename to drivers/net/wireless/rtl818x/rtl8180_rtl8225.c index cd22781728a945713a86c70488bbcb2197a9a4ab..4d2be0d9672b58b529ab6570f5c940a6bb78c9ad 100644 --- a/drivers/net/wireless/rtl8180_rtl8225.c +++ b/drivers/net/wireless/rtl818x/rtl8180_rtl8225.c @@ -725,8 +725,14 @@ static void rtl8225_rf_set_channel(struct ieee80211_hw *dev, rtl8225_write(dev, 0x7, rtl8225_chan[chan - 1]); msleep(10); +} + +static void rtl8225_rf_conf_erp(struct ieee80211_hw *dev, + struct ieee80211_bss_conf *info) +{ + struct rtl8180_priv *priv = dev->priv; - if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) { + if (info->use_short_slot) { rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9); rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22); rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14); @@ -745,14 +751,16 @@ static const struct rtl818x_rf_ops rtl8225_ops = { .name = "rtl8225", .init = rtl8225_rf_init, .stop = rtl8225_rf_stop, - .set_chan = rtl8225_rf_set_channel + .set_chan = rtl8225_rf_set_channel, + .conf_erp = rtl8225_rf_conf_erp, }; static const struct rtl818x_rf_ops rtl8225z2_ops = { .name = "rtl8225z2", .init = rtl8225z2_rf_init, .stop = rtl8225_rf_stop, - .set_chan = rtl8225_rf_set_channel + .set_chan = rtl8225_rf_set_channel, + .conf_erp = rtl8225_rf_conf_erp, }; const struct rtl818x_rf_ops * rtl8180_detect_rf(struct ieee80211_hw *dev) diff --git a/drivers/net/wireless/rtl8180_rtl8225.h b/drivers/net/wireless/rtl818x/rtl8180_rtl8225.h similarity index 100% rename from drivers/net/wireless/rtl8180_rtl8225.h rename to drivers/net/wireless/rtl818x/rtl8180_rtl8225.h diff --git a/drivers/net/wireless/rtl8180_sa2400.c b/drivers/net/wireless/rtl818x/rtl8180_sa2400.c similarity index 100% rename from drivers/net/wireless/rtl8180_sa2400.c rename to drivers/net/wireless/rtl818x/rtl8180_sa2400.c diff --git a/drivers/net/wireless/rtl8180_sa2400.h b/drivers/net/wireless/rtl818x/rtl8180_sa2400.h similarity index 100% rename from drivers/net/wireless/rtl8180_sa2400.h rename to drivers/net/wireless/rtl818x/rtl8180_sa2400.h diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl818x/rtl8187.h similarity index 97% rename from drivers/net/wireless/rtl8187.h rename to drivers/net/wireless/rtl818x/rtl8187.h index e82bb4d289e834e2a2117a463d1a96697534a47d..3b1e1c2aad26cb35e18167eb7da16e5e354b98b4 100644 --- a/drivers/net/wireless/rtl8187.h +++ b/drivers/net/wireless/rtl818x/rtl8187.h @@ -99,8 +99,8 @@ struct rtl8187_priv { struct ieee80211_supported_band band; struct usb_device *udev; u32 rx_conf; + struct usb_anchor anchored; u16 txpwr_base; - u16 seqno; u8 asic_rev; u8 is_rtl8187b; enum { @@ -112,6 +112,12 @@ struct rtl8187_priv { u8 signal; u8 quality; u8 noise; + u8 slot_time; + u8 aifsn[4]; + struct { + __le64 buf; + struct sk_buff_head queue; + } b_tx_status; }; void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data); diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c similarity index 79% rename from drivers/net/wireless/rtl8187_dev.c rename to drivers/net/wireless/rtl818x/rtl8187_dev.c index 69eb0132593b72cc2a5d995788a28d2744fcecce..00ce3ef39abe6e496de43fa10edaf3e3dd97858a 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -7,6 +7,11 @@ * Based on the r8187 driver, which is: * Copyright 2005 Andrea Merello , et al. * + * The driver was extended to the RTL8187B in 2008 by: + * Herton Ronaldo Krzesinski + * Hin-Tak Leung + * Larry Finger + * * Magic delays and register offsets below are taken from the original * r8187 driver sources. Thanks to Realtek for their support! * @@ -27,6 +32,9 @@ MODULE_AUTHOR("Michael Wu "); MODULE_AUTHOR("Andrea Merello "); +MODULE_AUTHOR("Herton Ronaldo Krzesinski "); +MODULE_AUTHOR("Hin-Tak Leung "); +MODULE_AUTHOR("Larry Finger "); MODULE_DESCRIPTION("RTL8187/RTL8187B USB wireless driver"); MODULE_LICENSE("GPL"); @@ -91,7 +99,6 @@ static const struct ieee80211_channel rtl818x_channels[] = { static void rtl8187_iowrite_async_cb(struct urb *urb) { kfree(urb->context); - usb_free_urb(urb); } static void rtl8187_iowrite_async(struct rtl8187_priv *priv, __le16 addr, @@ -128,11 +135,13 @@ static void rtl8187_iowrite_async(struct rtl8187_priv *priv, __le16 addr, usb_fill_control_urb(urb, priv->udev, usb_sndctrlpipe(priv->udev, 0), (unsigned char *)dr, buf, len, rtl8187_iowrite_async_cb, buf); + usb_anchor_urb(urb, &priv->anchored); rc = usb_submit_urb(urb, GFP_ATOMIC); if (rc < 0) { kfree(buf); - usb_free_urb(urb); + usb_unanchor_urb(urb); } + usb_free_urb(urb); } static inline void rtl818x_iowrite32_async(struct rtl8187_priv *priv, @@ -155,30 +164,45 @@ void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data) rtl818x_iowrite8(priv, &priv->map->PHY[2], (data >> 16) & 0xFF); rtl818x_iowrite8(priv, &priv->map->PHY[1], (data >> 8) & 0xFF); rtl818x_iowrite8(priv, &priv->map->PHY[0], data & 0xFF); - - msleep(1); } static void rtl8187_tx_cb(struct urb *urb) { struct sk_buff *skb = (struct sk_buff *)urb->context; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_hw *hw = info->driver_data[0]; + struct ieee80211_hw *hw = info->rate_driver_data[0]; struct rtl8187_priv *priv = hw->priv; - usb_free_urb(info->driver_data[1]); skb_pull(skb, priv->is_rtl8187b ? sizeof(struct rtl8187b_tx_hdr) : sizeof(struct rtl8187_tx_hdr)); - memset(&info->status, 0, sizeof(info->status)); - info->flags |= IEEE80211_TX_STAT_ACK; - ieee80211_tx_status_irqsafe(hw, skb); + ieee80211_tx_info_clear_status(info); + + if (!urb->status && + !(info->flags & IEEE80211_TX_CTL_NO_ACK) && + priv->is_rtl8187b) { + skb_queue_tail(&priv->b_tx_status.queue, skb); + + /* queue is "full", discard last items */ + while (skb_queue_len(&priv->b_tx_status.queue) > 5) { + struct sk_buff *old_skb; + + dev_dbg(&priv->udev->dev, + "transmit status queue full\n"); + + old_skb = skb_dequeue(&priv->b_tx_status.queue); + ieee80211_tx_status_irqsafe(hw, old_skb); + } + } else { + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && !urb->status) + info->flags |= IEEE80211_TX_STAT_ACK; + ieee80211_tx_status_irqsafe(hw, skb); + } } static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) { struct rtl8187_priv *priv = dev->priv; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; unsigned int ep; void *buf; struct urb *urb; @@ -189,7 +213,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) { kfree_skb(skb); - return 0; + return -ENOMEM; } flags = skb->len; @@ -198,12 +222,12 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) flags |= ieee80211_get_tx_rate(dev, info)->hw_value << 24; if (ieee80211_has_morefrags(((struct ieee80211_hdr *)skb->data)->frame_control)) flags |= RTL818X_TX_DESC_FLAG_MOREFRAG; - if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) { flags |= RTL818X_TX_DESC_FLAG_RTS; flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; rts_dur = ieee80211_rts_duration(dev, priv->vif, skb->len, info); - } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { + } else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { flags |= RTL818X_TX_DESC_FLAG_CTS; flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; } @@ -214,7 +238,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) hdr->flags = cpu_to_le32(flags); hdr->len = 0; hdr->rts_duration = rts_dur; - hdr->retry = cpu_to_le32(info->control.retry_limit << 8); + hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8); buf = hdr; ep = 2; @@ -232,7 +256,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) memset(hdr, 0, sizeof(*hdr)); hdr->flags = cpu_to_le32(flags); hdr->rts_duration = rts_dur; - hdr->retry = cpu_to_le32(info->control.retry_limit << 8); + hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8); hdr->tx_duration = ieee80211_generic_frame_duration(dev, priv->vif, skb->len, txrate); @@ -244,32 +268,20 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) ep = epmap[skb_get_queue_mapping(skb)]; } - /* FIXME: The sequence that follows is needed for this driver to - * work with mac80211 since "mac80211: fix TX sequence numbers". - * As with the temporary code in rt2x00, changes will be needed - * to get proper sequence numbers on beacons. In addition, this - * patch places the sequence number in the hardware state, which - * limits us to a single virtual state. - */ - if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { - if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) - priv->seqno += 0x10; - ieee80211hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); - ieee80211hdr->seq_ctrl |= cpu_to_le16(priv->seqno); - } - - info->driver_data[0] = dev; - info->driver_data[1] = urb; + info->rate_driver_data[0] = dev; + info->rate_driver_data[1] = urb; usb_fill_bulk_urb(urb, priv->udev, usb_sndbulkpipe(priv->udev, ep), buf, skb->len, rtl8187_tx_cb, skb); + usb_anchor_urb(urb, &priv->anchored); rc = usb_submit_urb(urb, GFP_ATOMIC); if (rc < 0) { - usb_free_urb(urb); + usb_unanchor_urb(urb); kfree_skb(skb); } + usb_free_urb(urb); - return 0; + return rc; } static void rtl8187_rx_cb(struct urb *urb) @@ -282,50 +294,35 @@ static void rtl8187_rx_cb(struct urb *urb) int rate, signal; u32 flags; u32 quality; + unsigned long f; - spin_lock(&priv->rx_queue.lock); + spin_lock_irqsave(&priv->rx_queue.lock, f); if (skb->next) __skb_unlink(skb, &priv->rx_queue); else { - spin_unlock(&priv->rx_queue.lock); + spin_unlock_irqrestore(&priv->rx_queue.lock, f); return; } - spin_unlock(&priv->rx_queue.lock); + spin_unlock_irqrestore(&priv->rx_queue.lock, f); + skb_put(skb, urb->actual_length); if (unlikely(urb->status)) { - usb_free_urb(urb); dev_kfree_skb_irq(skb); return; } - skb_put(skb, urb->actual_length); if (!priv->is_rtl8187b) { struct rtl8187_rx_hdr *hdr = (typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr)); flags = le32_to_cpu(hdr->flags); - signal = hdr->signal & 0x7f; + /* As with the RTL8187B below, the AGC is used to calculate + * signal strength and quality. In this case, the scaling + * constants are derived from the output of p54usb. + */ + quality = 130 - ((41 * hdr->agc) >> 6); + signal = -4 - ((27 * hdr->agc) >> 6); rx_status.antenna = (hdr->signal >> 7) & 1; - rx_status.noise = hdr->noise; rx_status.mactime = le64_to_cpu(hdr->mac_time); - priv->quality = signal; - rx_status.qual = priv->quality; - priv->noise = hdr->noise; - rate = (flags >> 20) & 0xF; - if (rate > 3) { /* OFDM rate */ - if (signal > 90) - signal = 90; - else if (signal < 25) - signal = 25; - signal = 90 - signal; - } else { /* CCK rate */ - if (signal > 95) - signal = 95; - else if (signal < 30) - signal = 30; - signal = 95 - signal; - } - rx_status.signal = signal; - priv->signal = signal; } else { struct rtl8187b_rx_hdr *hdr = (typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr)); @@ -343,18 +340,18 @@ static void rtl8187_rx_cb(struct urb *urb) */ flags = le32_to_cpu(hdr->flags); quality = 170 - hdr->agc; - if (quality > 100) - quality = 100; signal = 14 - hdr->agc / 2; - rx_status.qual = quality; - priv->quality = quality; - rx_status.signal = signal; - priv->signal = signal; rx_status.antenna = (hdr->rssi >> 7) & 1; rx_status.mactime = le64_to_cpu(hdr->mac_time); - rate = (flags >> 20) & 0xF; } + if (quality > 100) + quality = 100; + rx_status.qual = quality; + priv->quality = quality; + rx_status.signal = signal; + priv->signal = signal; + rate = (flags >> 20) & 0xF; skb_trim(skb, flags & 0x0FFF); rx_status.rate_idx = rate; rx_status.freq = dev->conf.channel->center_freq; @@ -366,7 +363,6 @@ static void rtl8187_rx_cb(struct urb *urb) skb = dev_alloc_skb(RTL8187_MAX_RX); if (unlikely(!skb)) { - usb_free_urb(urb); /* TODO check rx queue length and refill *somewhere* */ return; } @@ -378,24 +374,32 @@ static void rtl8187_rx_cb(struct urb *urb) urb->context = skb; skb_queue_tail(&priv->rx_queue, skb); - usb_submit_urb(urb, GFP_ATOMIC); + usb_anchor_urb(urb, &priv->anchored); + if (usb_submit_urb(urb, GFP_ATOMIC)) { + usb_unanchor_urb(urb); + skb_unlink(skb, &priv->rx_queue); + dev_kfree_skb_irq(skb); + } } static int rtl8187_init_urbs(struct ieee80211_hw *dev) { struct rtl8187_priv *priv = dev->priv; - struct urb *entry; + struct urb *entry = NULL; struct sk_buff *skb; struct rtl8187_rx_info *info; + int ret = 0; while (skb_queue_len(&priv->rx_queue) < 8) { skb = __dev_alloc_skb(RTL8187_MAX_RX, GFP_KERNEL); - if (!skb) - break; + if (!skb) { + ret = -ENOMEM; + goto err; + } entry = usb_alloc_urb(0, GFP_KERNEL); if (!entry) { - kfree_skb(skb); - break; + ret = -ENOMEM; + goto err; } usb_fill_bulk_urb(entry, priv->udev, usb_rcvbulkpipe(priv->udev, @@ -406,10 +410,129 @@ static int rtl8187_init_urbs(struct ieee80211_hw *dev) info->urb = entry; info->dev = dev; skb_queue_tail(&priv->rx_queue, skb); - usb_submit_urb(entry, GFP_KERNEL); + usb_anchor_urb(entry, &priv->anchored); + ret = usb_submit_urb(entry, GFP_KERNEL); + if (ret) { + skb_unlink(skb, &priv->rx_queue); + usb_unanchor_urb(entry); + goto err; + } + usb_free_urb(entry); } + return ret; - return 0; +err: + usb_free_urb(entry); + kfree_skb(skb); + usb_kill_anchored_urbs(&priv->anchored); + return ret; +} + +static void rtl8187b_status_cb(struct urb *urb) +{ + struct ieee80211_hw *hw = (struct ieee80211_hw *)urb->context; + struct rtl8187_priv *priv = hw->priv; + u64 val; + unsigned int cmd_type; + + if (unlikely(urb->status)) + return; + + /* + * Read from status buffer: + * + * bits [30:31] = cmd type: + * - 0 indicates tx beacon interrupt + * - 1 indicates tx close descriptor + * + * In the case of tx beacon interrupt: + * [0:9] = Last Beacon CW + * [10:29] = reserved + * [30:31] = 00b + * [32:63] = Last Beacon TSF + * + * If it's tx close descriptor: + * [0:7] = Packet Retry Count + * [8:14] = RTS Retry Count + * [15] = TOK + * [16:27] = Sequence No + * [28] = LS + * [29] = FS + * [30:31] = 01b + * [32:47] = unused (reserved?) + * [48:63] = MAC Used Time + */ + val = le64_to_cpu(priv->b_tx_status.buf); + + cmd_type = (val >> 30) & 0x3; + if (cmd_type == 1) { + unsigned int pkt_rc, seq_no; + bool tok; + struct sk_buff *skb; + struct ieee80211_hdr *ieee80211hdr; + unsigned long flags; + + pkt_rc = val & 0xFF; + tok = val & (1 << 15); + seq_no = (val >> 16) & 0xFFF; + + spin_lock_irqsave(&priv->b_tx_status.queue.lock, flags); + skb_queue_reverse_walk(&priv->b_tx_status.queue, skb) { + ieee80211hdr = (struct ieee80211_hdr *)skb->data; + + /* + * While testing, it was discovered that the seq_no + * doesn't actually contains the sequence number. + * Instead of returning just the 12 bits of sequence + * number, hardware is returning entire sequence control + * (fragment number plus sequence number) in a 12 bit + * only field overflowing after some time. As a + * workaround, just consider the lower bits, and expect + * it's unlikely we wrongly ack some sent data + */ + if ((le16_to_cpu(ieee80211hdr->seq_ctrl) + & 0xFFF) == seq_no) + break; + } + if (skb != (struct sk_buff *) &priv->b_tx_status.queue) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + __skb_unlink(skb, &priv->b_tx_status.queue); + if (tok) + info->flags |= IEEE80211_TX_STAT_ACK; + info->status.rates[0].count = pkt_rc + 1; + + ieee80211_tx_status_irqsafe(hw, skb); + } + spin_unlock_irqrestore(&priv->b_tx_status.queue.lock, flags); + } + + usb_anchor_urb(urb, &priv->anchored); + if (usb_submit_urb(urb, GFP_ATOMIC)) + usb_unanchor_urb(urb); +} + +static int rtl8187b_init_status_urb(struct ieee80211_hw *dev) +{ + struct rtl8187_priv *priv = dev->priv; + struct urb *entry; + int ret = 0; + + entry = usb_alloc_urb(0, GFP_KERNEL); + if (!entry) + return -ENOMEM; + + usb_fill_bulk_urb(entry, priv->udev, usb_rcvbulkpipe(priv->udev, 9), + &priv->b_tx_status.buf, sizeof(priv->b_tx_status.buf), + rtl8187b_status_cb, dev); + + usb_anchor_urb(entry, &priv->anchored); + ret = usb_submit_urb(entry, GFP_KERNEL); + if (ret) + usb_unanchor_urb(entry); + usb_free_urb(entry); + + return ret; } static int rtl8187_cmd_reset(struct ieee80211_hw *dev) @@ -687,7 +810,7 @@ static int rtl8187b_init_hw(struct ieee80211_hw *dev) rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480); rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x2488); rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); - msleep(1100); + msleep(100); priv->rf->init(dev); @@ -721,6 +844,13 @@ static int rtl8187b_init_hw(struct ieee80211_hw *dev) rtl818x_iowrite16_idx(priv, (__le16 *)0xFFEC, 0x0800, 1); + priv->slot_time = 0x9; + priv->aifsn[0] = 2; /* AIFSN[AC_VO] */ + priv->aifsn[1] = 2; /* AIFSN[AC_VI] */ + priv->aifsn[2] = 7; /* AIFSN[AC_BK] */ + priv->aifsn[3] = 3; /* AIFSN[AC_BE] */ + rtl818x_iowrite8(priv, &priv->map->ACM_CONTROL, 0); + return 0; } @@ -736,6 +866,9 @@ static int rtl8187_start(struct ieee80211_hw *dev) return ret; mutex_lock(&priv->conf_mutex); + + init_usb_anchor(&priv->anchored); + if (priv->is_rtl8187b) { reg = RTL818X_RX_CONF_MGMT | RTL818X_RX_CONF_DATA | @@ -757,6 +890,7 @@ static int rtl8187_start(struct ieee80211_hw *dev) (7 << 0 /* long retry limit */) | (7 << 21 /* MAX TX DMA */)); rtl8187_init_urbs(dev); + rtl8187b_init_status_urb(dev); mutex_unlock(&priv->conf_mutex); return 0; } @@ -809,7 +943,6 @@ static int rtl8187_start(struct ieee80211_hw *dev) static void rtl8187_stop(struct ieee80211_hw *dev) { struct rtl8187_priv *priv = dev->priv; - struct rtl8187_rx_info *info; struct sk_buff *skb; u32 reg; @@ -828,11 +961,10 @@ static void rtl8187_stop(struct ieee80211_hw *dev) rtl818x_iowrite8(priv, &priv->map->CONFIG4, reg | RTL818X_CONFIG4_VCOOFF); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); - while ((skb = skb_dequeue(&priv->rx_queue))) { - info = (struct rtl8187_rx_info *)skb->cb; - usb_kill_urb(info->urb); - kfree_skb(skb); - } + while ((skb = skb_dequeue(&priv->b_tx_status.queue))) + dev_kfree_skb_any(skb); + + usb_kill_anchored_urbs(&priv->anchored); mutex_unlock(&priv->conf_mutex); } @@ -876,9 +1008,10 @@ static void rtl8187_remove_interface(struct ieee80211_hw *dev, mutex_unlock(&priv->conf_mutex); } -static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) +static int rtl8187_config(struct ieee80211_hw *dev, u32 changed) { struct rtl8187_priv *priv = dev->priv; + struct ieee80211_conf *conf = &dev->conf; u32 reg; mutex_lock(&priv->conf_mutex); @@ -889,27 +1022,10 @@ static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) */ rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg | RTL818X_TX_CONF_LOOPBACK_MAC); - msleep(10); priv->rf->set_chan(dev, conf); msleep(10); rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg); - if (!priv->is_rtl8187b) { - rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22); - - if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) { - rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9); - rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14); - rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x14); - rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0x73); - } else { - rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14); - rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24); - rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x24); - rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0xa5); - } - } - rtl818x_iowrite16(priv, &priv->map->ATIM_WND, 2); rtl818x_iowrite16(priv, &priv->map->ATIMTR_INTERVAL, 100); rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL, 100); @@ -944,6 +1060,89 @@ static int rtl8187_config_interface(struct ieee80211_hw *dev, return 0; } +/* + * With 8187B, AC_*_PARAM clashes with FEMR definition in struct rtl818x_csr for + * example. Thus we have to use raw values for AC_*_PARAM register addresses. + */ +static __le32 *rtl8187b_ac_addr[4] = { + (__le32 *) 0xFFF0, /* AC_VO */ + (__le32 *) 0xFFF4, /* AC_VI */ + (__le32 *) 0xFFFC, /* AC_BK */ + (__le32 *) 0xFFF8, /* AC_BE */ +}; + +#define SIFS_TIME 0xa + +static void rtl8187_conf_erp(struct rtl8187_priv *priv, bool use_short_slot, + bool use_short_preamble) +{ + if (priv->is_rtl8187b) { + u8 difs, eifs; + u16 ack_timeout; + int queue; + + if (use_short_slot) { + priv->slot_time = 0x9; + difs = 0x1c; + eifs = 0x53; + } else { + priv->slot_time = 0x14; + difs = 0x32; + eifs = 0x5b; + } + rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22); + rtl818x_iowrite8(priv, &priv->map->SLOT, priv->slot_time); + rtl818x_iowrite8(priv, &priv->map->DIFS, difs); + + /* + * BRSR+1 on 8187B is in fact EIFS register + * Value in units of 4 us + */ + rtl818x_iowrite8(priv, (u8 *)&priv->map->BRSR + 1, eifs); + + /* + * For 8187B, CARRIER_SENSE_COUNTER is in fact ack timeout + * register. In units of 4 us like eifs register + * ack_timeout = ack duration + plcp + difs + preamble + */ + ack_timeout = 112 + 48 + difs; + if (use_short_preamble) + ack_timeout += 72; + else + ack_timeout += 144; + rtl818x_iowrite8(priv, &priv->map->CARRIER_SENSE_COUNTER, + DIV_ROUND_UP(ack_timeout, 4)); + + for (queue = 0; queue < 4; queue++) + rtl818x_iowrite8(priv, (u8 *) rtl8187b_ac_addr[queue], + priv->aifsn[queue] * priv->slot_time + + SIFS_TIME); + } else { + rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22); + if (use_short_slot) { + rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9); + rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14); + rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x14); + } else { + rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14); + rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24); + rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x24); + } + } +} + +static void rtl8187_bss_info_changed(struct ieee80211_hw *dev, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u32 changed) +{ + struct rtl8187_priv *priv = dev->priv; + + if (changed & (BSS_CHANGED_ERP_SLOT | BSS_CHANGED_ERP_PREAMBLE)) + rtl8187_conf_erp(priv, info->use_short_slot, + info->use_short_preamble); +} + static void rtl8187_configure_filter(struct ieee80211_hw *dev, unsigned int changed_flags, unsigned int *total_flags, @@ -976,6 +1175,42 @@ static void rtl8187_configure_filter(struct ieee80211_hw *dev, rtl818x_iowrite32_async(priv, &priv->map->RX_CONF, priv->rx_conf); } +static int rtl8187_conf_tx(struct ieee80211_hw *dev, u16 queue, + const struct ieee80211_tx_queue_params *params) +{ + struct rtl8187_priv *priv = dev->priv; + u8 cw_min, cw_max; + + if (queue > 3) + return -EINVAL; + + cw_min = fls(params->cw_min); + cw_max = fls(params->cw_max); + + if (priv->is_rtl8187b) { + priv->aifsn[queue] = params->aifs; + + /* + * This is the structure of AC_*_PARAM registers in 8187B: + * - TXOP limit field, bit offset = 16 + * - ECWmax, bit offset = 12 + * - ECWmin, bit offset = 8 + * - AIFS, bit offset = 0 + */ + rtl818x_iowrite32(priv, rtl8187b_ac_addr[queue], + (params->txop << 16) | (cw_max << 12) | + (cw_min << 8) | (params->aifs * + priv->slot_time + SIFS_TIME)); + } else { + if (queue != 0) + return -EINVAL; + + rtl818x_iowrite8(priv, &priv->map->CW_VAL, + cw_min | (cw_max << 4)); + } + return 0; +} + static const struct ieee80211_ops rtl8187_ops = { .tx = rtl8187_tx, .start = rtl8187_start, @@ -984,7 +1219,9 @@ static const struct ieee80211_ops rtl8187_ops = { .remove_interface = rtl8187_remove_interface, .config = rtl8187_config, .config_interface = rtl8187_config_interface, + .bss_info_changed = rtl8187_bss_info_changed, .configure_filter = rtl8187_configure_filter, + .conf_tx = rtl8187_conf_tx }; static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom) @@ -1029,7 +1266,6 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, const char *chip_name; u16 txpwr, reg; int err, i; - DECLARE_MAC_BUF(mac); dev = ieee80211_alloc_hw(sizeof(*priv), &rtl8187_ops); if (!dev) { @@ -1065,6 +1301,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, priv->mode = NL80211_IFTYPE_MONITOR; dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_RX_INCLUDES_FCS; eeprom.data = dev; @@ -1180,16 +1417,13 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, (*channel++).hw_value = txpwr >> 8; } - if (priv->is_rtl8187b) { - printk(KERN_WARNING "rtl8187: 8187B chip detected. Support " - "is EXPERIMENTAL, and could damage your\n" - " hardware, use at your own risk\n"); - dev->flags |= IEEE80211_HW_SIGNAL_DBM; - } else { - dev->flags |= IEEE80211_HW_SIGNAL_UNSPEC; - dev->max_signal = 65; - } + if (priv->is_rtl8187b) + printk(KERN_WARNING "rtl8187: 8187B chip detected.\n"); + /* + * XXX: Once this driver supports anything that requires + * beacons it must implement IEEE80211_TX_CTL_ASSIGN_SEQ. + */ dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); if ((id->driver_info == DEVICE_RTL8187) && priv->is_rtl8187b) @@ -1211,9 +1445,10 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, goto err_free_dev; } mutex_init(&priv->conf_mutex); + skb_queue_head_init(&priv->b_tx_status.queue); - printk(KERN_INFO "%s: hwaddr %s, %s V%d + %s\n", - wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr), + printk(KERN_INFO "%s: hwaddr %pM, %s V%d + %s\n", + wiphy_name(dev->wiphy), dev->wiphy->perm_addr, chip_name, priv->asic_rev, priv->rf->name); return 0; diff --git a/drivers/net/wireless/rtl8187_rtl8225.c b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c similarity index 69% rename from drivers/net/wireless/rtl8187_rtl8225.c rename to drivers/net/wireless/rtl818x/rtl8187_rtl8225.c index 1bae8990341096913c6800c19df076ac4f7e208a..4e75e8e7fa909036e89fca107f8acbad06e4d70c 100644 --- a/drivers/net/wireless/rtl8187_rtl8225.c +++ b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c @@ -64,7 +64,6 @@ static void rtl8225_write_bitbang(struct ieee80211_hw *dev, u8 addr, u16 data) rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84); - msleep(2); } static void rtl8225_write_8051(struct ieee80211_hw *dev, u8 addr, __le16 data) @@ -98,7 +97,6 @@ static void rtl8225_write_8051(struct ieee80211_hw *dev, u8 addr, __le16 data) rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84); - msleep(2); } static void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data) @@ -333,21 +331,21 @@ static void rtl8225_rf_init(struct ieee80211_hw *dev) struct rtl8187_priv *priv = dev->priv; int i; - rtl8225_write(dev, 0x0, 0x067); msleep(1); - rtl8225_write(dev, 0x1, 0xFE0); msleep(1); - rtl8225_write(dev, 0x2, 0x44D); msleep(1); - rtl8225_write(dev, 0x3, 0x441); msleep(1); - rtl8225_write(dev, 0x4, 0x486); msleep(1); - rtl8225_write(dev, 0x5, 0xBC0); msleep(1); - rtl8225_write(dev, 0x6, 0xAE6); msleep(1); - rtl8225_write(dev, 0x7, 0x82A); msleep(1); - rtl8225_write(dev, 0x8, 0x01F); msleep(1); - rtl8225_write(dev, 0x9, 0x334); msleep(1); - rtl8225_write(dev, 0xA, 0xFD4); msleep(1); - rtl8225_write(dev, 0xB, 0x391); msleep(1); - rtl8225_write(dev, 0xC, 0x050); msleep(1); - rtl8225_write(dev, 0xD, 0x6DB); msleep(1); - rtl8225_write(dev, 0xE, 0x029); msleep(1); + rtl8225_write(dev, 0x0, 0x067); + rtl8225_write(dev, 0x1, 0xFE0); + rtl8225_write(dev, 0x2, 0x44D); + rtl8225_write(dev, 0x3, 0x441); + rtl8225_write(dev, 0x4, 0x486); + rtl8225_write(dev, 0x5, 0xBC0); + rtl8225_write(dev, 0x6, 0xAE6); + rtl8225_write(dev, 0x7, 0x82A); + rtl8225_write(dev, 0x8, 0x01F); + rtl8225_write(dev, 0x9, 0x334); + rtl8225_write(dev, 0xA, 0xFD4); + rtl8225_write(dev, 0xB, 0x391); + rtl8225_write(dev, 0xC, 0x050); + rtl8225_write(dev, 0xD, 0x6DB); + rtl8225_write(dev, 0xE, 0x029); rtl8225_write(dev, 0xF, 0x914); msleep(100); rtl8225_write(dev, 0x2, 0xC4D); msleep(200); @@ -375,91 +373,89 @@ static void rtl8225_rf_init(struct ieee80211_hw *dev) for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) { rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]); - msleep(1); rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i); - msleep(1); } msleep(1); - rtl8225_write_phy_ofdm(dev, 0x00, 0x01); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x01, 0x02); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x02, 0x42); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x03, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x04, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x05, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x06, 0x40); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x08, 0x40); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x0a, 0x09); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x10, 0x84); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x11, 0x06); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x12, 0x20); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x13, 0x20); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x14, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x15, 0x40); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x16, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x17, 0x40); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x19, 0x19); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1b, 0x76); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x21, 0x27); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x22, 0x16); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x24, 0x46); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x25, 0x20); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x27, 0x88); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x00, 0x01); + rtl8225_write_phy_ofdm(dev, 0x01, 0x02); + rtl8225_write_phy_ofdm(dev, 0x02, 0x42); + rtl8225_write_phy_ofdm(dev, 0x03, 0x00); + rtl8225_write_phy_ofdm(dev, 0x04, 0x00); + rtl8225_write_phy_ofdm(dev, 0x05, 0x00); + rtl8225_write_phy_ofdm(dev, 0x06, 0x40); + rtl8225_write_phy_ofdm(dev, 0x07, 0x00); + rtl8225_write_phy_ofdm(dev, 0x08, 0x40); + rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); + rtl8225_write_phy_ofdm(dev, 0x0a, 0x09); + rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); + rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); + rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); + rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); + rtl8225_write_phy_ofdm(dev, 0x10, 0x84); + rtl8225_write_phy_ofdm(dev, 0x11, 0x06); + rtl8225_write_phy_ofdm(dev, 0x12, 0x20); + rtl8225_write_phy_ofdm(dev, 0x13, 0x20); + rtl8225_write_phy_ofdm(dev, 0x14, 0x00); + rtl8225_write_phy_ofdm(dev, 0x15, 0x40); + rtl8225_write_phy_ofdm(dev, 0x16, 0x00); + rtl8225_write_phy_ofdm(dev, 0x17, 0x40); + rtl8225_write_phy_ofdm(dev, 0x18, 0xef); + rtl8225_write_phy_ofdm(dev, 0x19, 0x19); + rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); + rtl8225_write_phy_ofdm(dev, 0x1b, 0x76); + rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); + rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); + rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); + rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); + rtl8225_write_phy_ofdm(dev, 0x21, 0x27); + rtl8225_write_phy_ofdm(dev, 0x22, 0x16); + rtl8225_write_phy_ofdm(dev, 0x24, 0x46); + rtl8225_write_phy_ofdm(dev, 0x25, 0x20); + rtl8225_write_phy_ofdm(dev, 0x26, 0x90); + rtl8225_write_phy_ofdm(dev, 0x27, 0x88); rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[2 * 4]); rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[2 * 4 + 2]); rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[2 * 4 + 3]); rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[2 * 4 + 1]); - rtl8225_write_phy_cck(dev, 0x00, 0x98); msleep(1); - rtl8225_write_phy_cck(dev, 0x03, 0x20); msleep(1); - rtl8225_write_phy_cck(dev, 0x04, 0x7e); msleep(1); - rtl8225_write_phy_cck(dev, 0x05, 0x12); msleep(1); - rtl8225_write_phy_cck(dev, 0x06, 0xfc); msleep(1); - rtl8225_write_phy_cck(dev, 0x07, 0x78); msleep(1); - rtl8225_write_phy_cck(dev, 0x08, 0x2e); msleep(1); - rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1); - rtl8225_write_phy_cck(dev, 0x11, 0x88); msleep(1); - rtl8225_write_phy_cck(dev, 0x12, 0x47); msleep(1); + rtl8225_write_phy_cck(dev, 0x00, 0x98); + rtl8225_write_phy_cck(dev, 0x03, 0x20); + rtl8225_write_phy_cck(dev, 0x04, 0x7e); + rtl8225_write_phy_cck(dev, 0x05, 0x12); + rtl8225_write_phy_cck(dev, 0x06, 0xfc); + rtl8225_write_phy_cck(dev, 0x07, 0x78); + rtl8225_write_phy_cck(dev, 0x08, 0x2e); + rtl8225_write_phy_cck(dev, 0x10, 0x9b); + rtl8225_write_phy_cck(dev, 0x11, 0x88); + rtl8225_write_phy_cck(dev, 0x12, 0x47); rtl8225_write_phy_cck(dev, 0x13, 0xd0); rtl8225_write_phy_cck(dev, 0x19, 0x00); rtl8225_write_phy_cck(dev, 0x1a, 0xa0); rtl8225_write_phy_cck(dev, 0x1b, 0x08); rtl8225_write_phy_cck(dev, 0x40, 0x86); - rtl8225_write_phy_cck(dev, 0x41, 0x8d); msleep(1); - rtl8225_write_phy_cck(dev, 0x42, 0x15); msleep(1); - rtl8225_write_phy_cck(dev, 0x43, 0x18); msleep(1); - rtl8225_write_phy_cck(dev, 0x44, 0x1f); msleep(1); - rtl8225_write_phy_cck(dev, 0x45, 0x1e); msleep(1); - rtl8225_write_phy_cck(dev, 0x46, 0x1a); msleep(1); - rtl8225_write_phy_cck(dev, 0x47, 0x15); msleep(1); - rtl8225_write_phy_cck(dev, 0x48, 0x10); msleep(1); - rtl8225_write_phy_cck(dev, 0x49, 0x0a); msleep(1); - rtl8225_write_phy_cck(dev, 0x4a, 0x05); msleep(1); - rtl8225_write_phy_cck(dev, 0x4b, 0x02); msleep(1); - rtl8225_write_phy_cck(dev, 0x4c, 0x05); msleep(1); + rtl8225_write_phy_cck(dev, 0x41, 0x8d); + rtl8225_write_phy_cck(dev, 0x42, 0x15); + rtl8225_write_phy_cck(dev, 0x43, 0x18); + rtl8225_write_phy_cck(dev, 0x44, 0x1f); + rtl8225_write_phy_cck(dev, 0x45, 0x1e); + rtl8225_write_phy_cck(dev, 0x46, 0x1a); + rtl8225_write_phy_cck(dev, 0x47, 0x15); + rtl8225_write_phy_cck(dev, 0x48, 0x10); + rtl8225_write_phy_cck(dev, 0x49, 0x0a); + rtl8225_write_phy_cck(dev, 0x4a, 0x05); + rtl8225_write_phy_cck(dev, 0x4b, 0x02); + rtl8225_write_phy_cck(dev, 0x4c, 0x05); rtl818x_iowrite8(priv, &priv->map->TESTR, 0x0D); rtl8225_rf_set_tx_power(dev, 1); /* RX antenna default to A */ - rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1); /* B: 0xDB */ - rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); /* B: 0x10 */ + rtl8225_write_phy_cck(dev, 0x10, 0x9b); /* B: 0xDB */ + rtl8225_write_phy_ofdm(dev, 0x26, 0x90); /* B: 0x10 */ rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */ msleep(1); @@ -629,7 +625,7 @@ static void rtl8225z2_b_rf_set_tx_power(struct ieee80211_hw *dev, int channel) rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++); rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, - rtl8225z2_tx_gain_cck_ofdm[cck_power]); + rtl8225z2_tx_gain_cck_ofdm[cck_power] << 1); msleep(1); rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, @@ -687,22 +683,23 @@ static void rtl8225z2_rf_init(struct ieee80211_hw *dev) struct rtl8187_priv *priv = dev->priv; int i; - rtl8225_write(dev, 0x0, 0x2BF); msleep(1); - rtl8225_write(dev, 0x1, 0xEE0); msleep(1); - rtl8225_write(dev, 0x2, 0x44D); msleep(1); - rtl8225_write(dev, 0x3, 0x441); msleep(1); - rtl8225_write(dev, 0x4, 0x8C3); msleep(1); - rtl8225_write(dev, 0x5, 0xC72); msleep(1); - rtl8225_write(dev, 0x6, 0x0E6); msleep(1); - rtl8225_write(dev, 0x7, 0x82A); msleep(1); - rtl8225_write(dev, 0x8, 0x03F); msleep(1); - rtl8225_write(dev, 0x9, 0x335); msleep(1); - rtl8225_write(dev, 0xa, 0x9D4); msleep(1); - rtl8225_write(dev, 0xb, 0x7BB); msleep(1); - rtl8225_write(dev, 0xc, 0x850); msleep(1); - rtl8225_write(dev, 0xd, 0xCDF); msleep(1); - rtl8225_write(dev, 0xe, 0x02B); msleep(1); - rtl8225_write(dev, 0xf, 0x114); msleep(100); + rtl8225_write(dev, 0x0, 0x2BF); + rtl8225_write(dev, 0x1, 0xEE0); + rtl8225_write(dev, 0x2, 0x44D); + rtl8225_write(dev, 0x3, 0x441); + rtl8225_write(dev, 0x4, 0x8C3); + rtl8225_write(dev, 0x5, 0xC72); + rtl8225_write(dev, 0x6, 0x0E6); + rtl8225_write(dev, 0x7, 0x82A); + rtl8225_write(dev, 0x8, 0x03F); + rtl8225_write(dev, 0x9, 0x335); + rtl8225_write(dev, 0xa, 0x9D4); + rtl8225_write(dev, 0xb, 0x7BB); + rtl8225_write(dev, 0xc, 0x850); + rtl8225_write(dev, 0xd, 0xCDF); + rtl8225_write(dev, 0xe, 0x02B); + rtl8225_write(dev, 0xf, 0x114); + msleep(100); rtl8225_write(dev, 0x0, 0x1B7); @@ -736,94 +733,92 @@ static void rtl8225z2_rf_init(struct ieee80211_hw *dev) for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) { rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]); - msleep(1); rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i); - msleep(1); } msleep(1); - rtl8225_write_phy_ofdm(dev, 0x00, 0x01); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x01, 0x02); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x02, 0x42); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x03, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x04, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x05, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x06, 0x40); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x08, 0x40); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x0a, 0x08); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x00, 0x01); + rtl8225_write_phy_ofdm(dev, 0x01, 0x02); + rtl8225_write_phy_ofdm(dev, 0x02, 0x42); + rtl8225_write_phy_ofdm(dev, 0x03, 0x00); + rtl8225_write_phy_ofdm(dev, 0x04, 0x00); + rtl8225_write_phy_ofdm(dev, 0x05, 0x00); + rtl8225_write_phy_ofdm(dev, 0x06, 0x40); + rtl8225_write_phy_ofdm(dev, 0x07, 0x00); + rtl8225_write_phy_ofdm(dev, 0x08, 0x40); + rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); + rtl8225_write_phy_ofdm(dev, 0x0a, 0x08); + rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); + rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); rtl8225_write_phy_ofdm(dev, 0x0d, 0x43); - rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x10, 0x84); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x11, 0x07); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x12, 0x20); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x13, 0x20); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x14, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x15, 0x40); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x16, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x17, 0x40); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x19, 0x19); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1b, 0x15); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1d, 0xc5); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x21, 0x17); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x22, 0x16); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x23, 0x80); msleep(1); //FIXME: not needed? - rtl8225_write_phy_ofdm(dev, 0x24, 0x46); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x25, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x27, 0x88); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); + rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); + rtl8225_write_phy_ofdm(dev, 0x10, 0x84); + rtl8225_write_phy_ofdm(dev, 0x11, 0x07); + rtl8225_write_phy_ofdm(dev, 0x12, 0x20); + rtl8225_write_phy_ofdm(dev, 0x13, 0x20); + rtl8225_write_phy_ofdm(dev, 0x14, 0x00); + rtl8225_write_phy_ofdm(dev, 0x15, 0x40); + rtl8225_write_phy_ofdm(dev, 0x16, 0x00); + rtl8225_write_phy_ofdm(dev, 0x17, 0x40); + rtl8225_write_phy_ofdm(dev, 0x18, 0xef); + rtl8225_write_phy_ofdm(dev, 0x19, 0x19); + rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); + rtl8225_write_phy_ofdm(dev, 0x1b, 0x15); + rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); + rtl8225_write_phy_ofdm(dev, 0x1d, 0xc5); + rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); + rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); + rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); + rtl8225_write_phy_ofdm(dev, 0x21, 0x17); + rtl8225_write_phy_ofdm(dev, 0x22, 0x16); + rtl8225_write_phy_ofdm(dev, 0x23, 0x80); + rtl8225_write_phy_ofdm(dev, 0x24, 0x46); + rtl8225_write_phy_ofdm(dev, 0x25, 0x00); + rtl8225_write_phy_ofdm(dev, 0x26, 0x90); + rtl8225_write_phy_ofdm(dev, 0x27, 0x88); rtl8225_write_phy_ofdm(dev, 0x0b, rtl8225z2_gain_bg[4 * 3]); rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225z2_gain_bg[4 * 3 + 1]); rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225z2_gain_bg[4 * 3 + 2]); rtl8225_write_phy_ofdm(dev, 0x21, 0x37); - rtl8225_write_phy_cck(dev, 0x00, 0x98); msleep(1); - rtl8225_write_phy_cck(dev, 0x03, 0x20); msleep(1); - rtl8225_write_phy_cck(dev, 0x04, 0x7e); msleep(1); - rtl8225_write_phy_cck(dev, 0x05, 0x12); msleep(1); - rtl8225_write_phy_cck(dev, 0x06, 0xfc); msleep(1); - rtl8225_write_phy_cck(dev, 0x07, 0x78); msleep(1); - rtl8225_write_phy_cck(dev, 0x08, 0x2e); msleep(1); - rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1); - rtl8225_write_phy_cck(dev, 0x11, 0x88); msleep(1); - rtl8225_write_phy_cck(dev, 0x12, 0x47); msleep(1); + rtl8225_write_phy_cck(dev, 0x00, 0x98); + rtl8225_write_phy_cck(dev, 0x03, 0x20); + rtl8225_write_phy_cck(dev, 0x04, 0x7e); + rtl8225_write_phy_cck(dev, 0x05, 0x12); + rtl8225_write_phy_cck(dev, 0x06, 0xfc); + rtl8225_write_phy_cck(dev, 0x07, 0x78); + rtl8225_write_phy_cck(dev, 0x08, 0x2e); + rtl8225_write_phy_cck(dev, 0x10, 0x9b); + rtl8225_write_phy_cck(dev, 0x11, 0x88); + rtl8225_write_phy_cck(dev, 0x12, 0x47); rtl8225_write_phy_cck(dev, 0x13, 0xd0); rtl8225_write_phy_cck(dev, 0x19, 0x00); rtl8225_write_phy_cck(dev, 0x1a, 0xa0); rtl8225_write_phy_cck(dev, 0x1b, 0x08); rtl8225_write_phy_cck(dev, 0x40, 0x86); - rtl8225_write_phy_cck(dev, 0x41, 0x8d); msleep(1); - rtl8225_write_phy_cck(dev, 0x42, 0x15); msleep(1); - rtl8225_write_phy_cck(dev, 0x43, 0x18); msleep(1); - rtl8225_write_phy_cck(dev, 0x44, 0x36); msleep(1); - rtl8225_write_phy_cck(dev, 0x45, 0x35); msleep(1); - rtl8225_write_phy_cck(dev, 0x46, 0x2e); msleep(1); - rtl8225_write_phy_cck(dev, 0x47, 0x25); msleep(1); - rtl8225_write_phy_cck(dev, 0x48, 0x1c); msleep(1); - rtl8225_write_phy_cck(dev, 0x49, 0x12); msleep(1); - rtl8225_write_phy_cck(dev, 0x4a, 0x09); msleep(1); - rtl8225_write_phy_cck(dev, 0x4b, 0x04); msleep(1); - rtl8225_write_phy_cck(dev, 0x4c, 0x05); msleep(1); + rtl8225_write_phy_cck(dev, 0x41, 0x8d); + rtl8225_write_phy_cck(dev, 0x42, 0x15); + rtl8225_write_phy_cck(dev, 0x43, 0x18); + rtl8225_write_phy_cck(dev, 0x44, 0x36); + rtl8225_write_phy_cck(dev, 0x45, 0x35); + rtl8225_write_phy_cck(dev, 0x46, 0x2e); + rtl8225_write_phy_cck(dev, 0x47, 0x25); + rtl8225_write_phy_cck(dev, 0x48, 0x1c); + rtl8225_write_phy_cck(dev, 0x49, 0x12); + rtl8225_write_phy_cck(dev, 0x4a, 0x09); + rtl8225_write_phy_cck(dev, 0x4b, 0x04); + rtl8225_write_phy_cck(dev, 0x4c, 0x05); rtl818x_iowrite8(priv, (u8 *)0xFF5B, 0x0D); msleep(1); rtl8225z2_rf_set_tx_power(dev, 1); /* RX antenna default to A */ - rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1); /* B: 0xDB */ - rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); /* B: 0x10 */ + rtl8225_write_phy_cck(dev, 0x10, 0x9b); /* B: 0xDB */ + rtl8225_write_phy_ofdm(dev, 0x26, 0x90); /* B: 0x10 */ rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */ msleep(1); @@ -835,40 +830,38 @@ static void rtl8225z2_b_rf_init(struct ieee80211_hw *dev) struct rtl8187_priv *priv = dev->priv; int i; - rtl8225_write(dev, 0x0, 0x0B7); msleep(1); - rtl8225_write(dev, 0x1, 0xEE0); msleep(1); - rtl8225_write(dev, 0x2, 0x44D); msleep(1); - rtl8225_write(dev, 0x3, 0x441); msleep(1); - rtl8225_write(dev, 0x4, 0x8C3); msleep(1); - rtl8225_write(dev, 0x5, 0xC72); msleep(1); - rtl8225_write(dev, 0x6, 0x0E6); msleep(1); - rtl8225_write(dev, 0x7, 0x82A); msleep(1); - rtl8225_write(dev, 0x8, 0x03F); msleep(1); - rtl8225_write(dev, 0x9, 0x335); msleep(1); - rtl8225_write(dev, 0xa, 0x9D4); msleep(1); - rtl8225_write(dev, 0xb, 0x7BB); msleep(1); - rtl8225_write(dev, 0xc, 0x850); msleep(1); - rtl8225_write(dev, 0xd, 0xCDF); msleep(1); - rtl8225_write(dev, 0xe, 0x02B); msleep(1); - rtl8225_write(dev, 0xf, 0x114); msleep(1); - - rtl8225_write(dev, 0x0, 0x1B7); msleep(1); + rtl8225_write(dev, 0x0, 0x0B7); + rtl8225_write(dev, 0x1, 0xEE0); + rtl8225_write(dev, 0x2, 0x44D); + rtl8225_write(dev, 0x3, 0x441); + rtl8225_write(dev, 0x4, 0x8C3); + rtl8225_write(dev, 0x5, 0xC72); + rtl8225_write(dev, 0x6, 0x0E6); + rtl8225_write(dev, 0x7, 0x82A); + rtl8225_write(dev, 0x8, 0x03F); + rtl8225_write(dev, 0x9, 0x335); + rtl8225_write(dev, 0xa, 0x9D4); + rtl8225_write(dev, 0xb, 0x7BB); + rtl8225_write(dev, 0xc, 0x850); + rtl8225_write(dev, 0xd, 0xCDF); + rtl8225_write(dev, 0xe, 0x02B); + rtl8225_write(dev, 0xf, 0x114); + + rtl8225_write(dev, 0x0, 0x1B7); for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) { - rtl8225_write(dev, 0x1, i + 1); msleep(1); - rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]); msleep(1); + rtl8225_write(dev, 0x1, i + 1); + rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]); } - rtl8225_write(dev, 0x3, 0x080); msleep(1); - rtl8225_write(dev, 0x5, 0x004); msleep(1); - rtl8225_write(dev, 0x0, 0x0B7); msleep(1); - msleep(3000); + rtl8225_write(dev, 0x3, 0x080); + rtl8225_write(dev, 0x5, 0x004); + rtl8225_write(dev, 0x0, 0x0B7); - rtl8225_write(dev, 0x2, 0xC4D); msleep(1); - msleep(2000); + rtl8225_write(dev, 0x2, 0xC4D); - rtl8225_write(dev, 0x2, 0x44D); msleep(1); - rtl8225_write(dev, 0x0, 0x2BF); msleep(1); + rtl8225_write(dev, 0x2, 0x44D); + rtl8225_write(dev, 0x0, 0x2BF); rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, 0x03); rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, 0x07); @@ -885,24 +878,10 @@ static void rtl8225z2_b_rf_init(struct ieee80211_hw *dev) for (i = 0; i < ARRAY_SIZE(rtl8225z2_ofdm); i++) rtl8225_write_phy_ofdm(dev, i, rtl8225z2_ofdm[i]); - rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22); - rtl818x_iowrite8(priv, &priv->map->SLOT, 9); - rtl818x_iowrite8(priv, (u8 *)0xFFF0, 28); - rtl818x_iowrite8(priv, (u8 *)0xFFF4, 28); - rtl818x_iowrite8(priv, (u8 *)0xFFF8, 28); - rtl818x_iowrite8(priv, (u8 *)0xFFFC, 28); - rtl818x_iowrite8(priv, (u8 *)0xFF2D, 0x5B); - rtl818x_iowrite8(priv, (u8 *)0xFF79, 0x5B); - rtl818x_iowrite32(priv, (__le32 *)0xFFF0, (7 << 12) | (3 << 8) | 28); - rtl818x_iowrite32(priv, (__le32 *)0xFFF4, (7 << 12) | (3 << 8) | 28); - rtl818x_iowrite32(priv, (__le32 *)0xFFF8, (7 << 12) | (3 << 8) | 28); - rtl818x_iowrite32(priv, (__le32 *)0xFFFC, (7 << 12) | (3 << 8) | 28); - rtl818x_iowrite8(priv, &priv->map->ACM_CONTROL, 0); - - rtl8225_write_phy_ofdm(dev, 0x97, 0x46); msleep(1); - rtl8225_write_phy_ofdm(dev, 0xa4, 0xb6); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x85, 0xfc); msleep(1); - rtl8225_write_phy_cck(dev, 0xc1, 0x88); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x97, 0x46); + rtl8225_write_phy_ofdm(dev, 0xa4, 0xb6); + rtl8225_write_phy_ofdm(dev, 0x85, 0xfc); + rtl8225_write_phy_cck(dev, 0xc1, 0x88); } static void rtl8225_rf_stop(struct ieee80211_hw *dev) @@ -910,7 +889,7 @@ static void rtl8225_rf_stop(struct ieee80211_hw *dev) u8 reg; struct rtl8187_priv *priv = dev->priv; - rtl8225_write(dev, 0x4, 0x1f); msleep(1); + rtl8225_write(dev, 0x4, 0x1f); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); diff --git a/drivers/net/wireless/rtl8187_rtl8225.h b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.h similarity index 100% rename from drivers/net/wireless/rtl8187_rtl8225.h rename to drivers/net/wireless/rtl818x/rtl8187_rtl8225.h diff --git a/drivers/net/wireless/rtl818x.h b/drivers/net/wireless/rtl818x/rtl818x.h similarity index 98% rename from drivers/net/wireless/rtl818x.h rename to drivers/net/wireless/rtl818x/rtl818x.h index 3538b15211b190bd2cf07d96ecd6caf79c527232..34a5555cc19c04fe3162f634e34c7937ac570018 100644 --- a/drivers/net/wireless/rtl818x.h +++ b/drivers/net/wireless/rtl818x/rtl818x.h @@ -191,6 +191,7 @@ struct rtl818x_rf_ops { void (*init)(struct ieee80211_hw *); void (*stop)(struct ieee80211_hw *); void (*set_chan)(struct ieee80211_hw *, struct ieee80211_conf *); + void (*conf_erp)(struct ieee80211_hw *, struct ieee80211_bss_conf *); }; /* Tx/Rx flags are common between RTL818X chips */ diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index 417e9e675facceab098ca13f594419572a0a0d6d..dd0de3a9ed4eef2f479b5a36aead3d580ba50d81 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -1234,7 +1234,7 @@ static void ResetRadio(struct strip *strip_info) static void strip_write_some_more(struct tty_struct *tty) { - struct strip *strip_info = (struct strip *) tty->disc_data; + struct strip *strip_info = tty->disc_data; /* First make sure we're connected. */ if (!strip_info || strip_info->magic != STRIP_MAGIC || @@ -1252,7 +1252,7 @@ static void strip_write_some_more(struct tty_struct *tty) #endif } else { /* Else start transmission of another packet */ - tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); strip_unlock(strip_info); } } @@ -1455,8 +1455,7 @@ static void strip_send(struct strip *strip_info, struct sk_buff *skb) */ strip_info->tx_head = strip_info->tx_buff; strip_info->tx_left = ptr - strip_info->tx_buff; - strip_info->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); - + set_bit(TTY_DO_WRITE_WAKEUP, &strip_info->tty->flags); /* * 4. Debugging check to make sure we're not overflowing the buffer. */ @@ -1997,7 +1996,6 @@ static void deliver_packet(struct strip *strip_info, STRIP_Header * header, #ifdef EXT_COUNTERS strip_info->rx_bytes += packetlen; #endif - skb->dev->last_rx = jiffies; netif_rx(skb); } } @@ -2261,7 +2259,7 @@ static void process_message(struct strip *strip_info) static void strip_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) { - struct strip *strip_info = (struct strip *) tty->disc_data; + struct strip *strip_info = tty->disc_data; const unsigned char *end = cp + count; if (!strip_info || strip_info->magic != STRIP_MAGIC @@ -2455,8 +2453,7 @@ static int strip_close_low(struct net_device *dev) if (strip_info->tty == NULL) return -EBUSY; - strip_info->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); - + clear_bit(TTY_DO_WRITE_WAKEUP, &strip_info->tty->flags); netif_stop_queue(dev); /* @@ -2490,7 +2487,6 @@ static void strip_dev_setup(struct net_device *dev) */ dev->trans_start = 0; - dev->last_rx = 0; dev->tx_queue_len = 30; /* Drop after 30 frames queued */ dev->flags = 0; @@ -2498,7 +2494,7 @@ static void strip_dev_setup(struct net_device *dev) dev->type = ARPHRD_METRICOM; /* dtang */ dev->hard_header_len = sizeof(STRIP_Header); /* - * dev->priv Already holds a pointer to our struct strip + * netdev_priv(dev) Already holds a pointer to our struct strip */ *(MetricomAddress *) & dev->broadcast = broadcast_address; @@ -2598,7 +2594,7 @@ static struct strip *strip_alloc(void) static int strip_open(struct tty_struct *tty) { - struct strip *strip_info = (struct strip *) tty->disc_data; + struct strip *strip_info = tty->disc_data; /* * First make sure we're not already connected. @@ -2669,7 +2665,7 @@ static int strip_open(struct tty_struct *tty) static void strip_close(struct tty_struct *tty) { - struct strip *strip_info = (struct strip *) tty->disc_data; + struct strip *strip_info = tty->disc_data; /* * First make sure we're connected. @@ -2695,7 +2691,7 @@ static void strip_close(struct tty_struct *tty) static int strip_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { - struct strip *strip_info = (struct strip *) tty->disc_data; + struct strip *strip_info = tty->disc_data; /* * First make sure we're connected. diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c index e939a73ff794a731583292d5e41e7e8a23f64d8e..832679396b6cbc14a23124d35abd2ae389de83b6 100644 --- a/drivers/net/wireless/wavelan.c +++ b/drivers/net/wireless/wavelan.c @@ -134,7 +134,7 @@ static inline void wv_16_on(unsigned long ioaddr, u16 hacr) */ static inline void wv_ints_off(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; lp->hacr &= ~HACR_INTRON; @@ -148,7 +148,7 @@ static inline void wv_ints_off(struct net_device * dev) */ static inline void wv_ints_on(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; lp->hacr |= HACR_INTRON; @@ -526,7 +526,7 @@ static inline void obram_write(unsigned long ioaddr, u16 o, u8 * b, int n) */ static void wv_ack(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; u16 scb_cs; int i; @@ -568,7 +568,7 @@ static void wv_ack(struct net_device * dev) */ static int wv_synchronous_cmd(struct net_device * dev, const char *str) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; u16 scb_cmd; ach_t cb; @@ -824,7 +824,7 @@ if (lp->tx_n_in_use > 0) */ static void wv_82586_reconfig(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long flags; /* Arm the flag, will be cleard in wv_82586_config() */ @@ -859,8 +859,6 @@ static void wv_82586_reconfig(struct net_device * dev) */ static void wv_psa_show(psa_t * p) { - DECLARE_MAC_BUF(mac); - printk(KERN_DEBUG "##### WaveLAN PSA contents: #####\n"); printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n", p->psa_io_base_addr_1, @@ -872,13 +870,10 @@ static void wv_psa_show(psa_t * p) printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params); printk("psa_int_req_no: %d\n", p->psa_int_req_no); #ifdef DEBUG_SHOW_UNUSED - printk(KERN_DEBUG "psa_unused0[]: %s\n", - print_mac(mac, p->psa_unused0)); + printk(KERN_DEBUG "psa_unused0[]: %pM\n", p->psa_unused0); #endif /* DEBUG_SHOW_UNUSED */ - printk(KERN_DEBUG "psa_univ_mac_addr[]: %s\n", - print_mac(mac, p->psa_univ_mac_addr)); - printk(KERN_DEBUG "psa_local_mac_addr[]: %s\n", - print_mac(mac, p->psa_local_mac_addr)); + printk(KERN_DEBUG "psa_univ_mac_addr[]: %pM\n", p->psa_univ_mac_addr); + printk(KERN_DEBUG "psa_local_mac_addr[]: %pM\n", p->psa_local_mac_addr); printk(KERN_DEBUG "psa_univ_local_sel: %d, ", p->psa_univ_local_sel); printk("psa_comp_number: %d, ", p->psa_comp_number); @@ -927,7 +922,7 @@ static void wv_psa_show(psa_t * p) static void wv_mmc_show(struct net_device * dev) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); mmr_t m; /* Basic check */ @@ -1107,8 +1102,6 @@ static void wv_scb_show(unsigned long ioaddr) */ static void wv_ru_show(struct net_device * dev) { - /* net_local *lp = (net_local *) dev->priv; */ - printk(KERN_DEBUG "##### WaveLAN i82586 receiver unit status: #####\n"); printk(KERN_DEBUG "ru:"); @@ -1153,7 +1146,7 @@ static void wv_cu_show_one(struct net_device * dev, net_local * lp, int i, u16 p */ static void wv_cu_show(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned int i; u16 p; @@ -1195,7 +1188,7 @@ static void wv_local_show(struct net_device * dev) { net_local *lp; - lp = (net_local *) dev->priv; + lp = netdev_priv(dev); printk(KERN_DEBUG "local:"); printk(" tx_n_in_use=%d,", lp->tx_n_in_use); @@ -1220,14 +1213,13 @@ static inline void wv_packet_info(u8 * p, /* Packet to dump */ { /* Name of the function */ int i; int maxi; - DECLARE_MAC_BUF(mac); printk(KERN_DEBUG - "%s: %s(): dest %s, length %d\n", - msg1, msg2, print_mac(mac, p), length); + "%s: %s(): dest %pM, length %d\n", + msg1, msg2, p, length); printk(KERN_DEBUG - "%s: %s(): src %s, type 0x%02X%02X\n", - msg1, msg2, print_mac(mac, &p[6]), p[12], p[13]); + "%s: %s(): src %pM, type 0x%02X%02X\n", + msg1, msg2, &p[6], p[12], p[13]); #ifdef DEBUG_PACKET_DUMP @@ -1256,11 +1248,8 @@ static inline void wv_packet_info(u8 * p, /* Packet to dump */ static void wv_init_info(struct net_device * dev) { short ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); psa_t psa; -#ifdef DEBUG_BASIC_SHOW - DECLARE_MAC_BUF(mac); -#endif /* Read the parameter storage area */ psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa)); @@ -1277,8 +1266,8 @@ static void wv_init_info(struct net_device * dev) #ifdef DEBUG_BASIC_SHOW /* Now, let's go for the basic stuff. */ - printk(KERN_NOTICE "%s: WaveLAN at %#x, %s, IRQ %d", - dev->name, ioaddr, print_mac(mac, dev->dev_addr), dev->irq); + printk(KERN_NOTICE "%s: WaveLAN at %#x, %pM, IRQ %d", + dev->name, ioaddr, dev->dev_addr, dev->irq); /* Print current network ID. */ if (psa.psa_nwid_select) @@ -1369,7 +1358,7 @@ static en_stats *wavelan_get_stats(struct net_device * dev) printk(KERN_DEBUG "%s: <>wavelan_get_stats()\n", dev->name); #endif - return (&((net_local *) dev->priv)->stats); + return &((net_local *)netdev_priv(dev))->stats; } /*------------------------------------------------------------------*/ @@ -1382,7 +1371,7 @@ static en_stats *wavelan_get_stats(struct net_device * dev) */ static void wavelan_set_multicast_list(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); #ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: ->wavelan_set_multicast_list()\n", @@ -1716,7 +1705,7 @@ static inline void wl_spy_gather(struct net_device * dev, */ static inline void wl_his_gather(struct net_device * dev, u8 * stats) { /* Statistics to gather */ - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); u8 level = stats[0] & MMR_SIGNAL_LVL; int i; @@ -1753,7 +1742,7 @@ static int wavelan_set_nwid(struct net_device *dev, char *extra) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ psa_t psa; mm_t m; unsigned long flags; @@ -1812,7 +1801,7 @@ static int wavelan_get_nwid(struct net_device *dev, char *extra) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ psa_t psa; unsigned long flags; int ret = 0; @@ -1844,7 +1833,7 @@ static int wavelan_set_freq(struct net_device *dev, char *extra) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ unsigned long flags; int ret; @@ -1874,7 +1863,7 @@ static int wavelan_get_freq(struct net_device *dev, char *extra) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ psa_t psa; unsigned long flags; int ret = 0; @@ -1920,7 +1909,7 @@ static int wavelan_set_sens(struct net_device *dev, char *extra) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ psa_t psa; unsigned long flags; int ret = 0; @@ -1956,7 +1945,7 @@ static int wavelan_get_sens(struct net_device *dev, char *extra) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ psa_t psa; unsigned long flags; int ret = 0; @@ -1987,7 +1976,7 @@ static int wavelan_set_encode(struct net_device *dev, char *extra) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ unsigned long flags; psa_t psa; int ret = 0; @@ -2057,7 +2046,7 @@ static int wavelan_get_encode(struct net_device *dev, char *extra) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ psa_t psa; unsigned long flags; int ret = 0; @@ -2104,7 +2093,7 @@ static int wavelan_get_range(struct net_device *dev, char *extra) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ struct iw_range *range = (struct iw_range *) extra; unsigned long flags; int ret = 0; @@ -2179,7 +2168,7 @@ static int wavelan_set_qthr(struct net_device *dev, char *extra) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ psa_t psa; unsigned long flags; @@ -2211,7 +2200,7 @@ static int wavelan_get_qthr(struct net_device *dev, char *extra) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ psa_t psa; unsigned long flags; @@ -2239,7 +2228,7 @@ static int wavelan_set_histo(struct net_device *dev, union iwreq_data *wrqu, char *extra) { - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ /* Check the number of intervals. */ if (wrqu->data.length > 16) { @@ -2282,7 +2271,7 @@ static int wavelan_get_histo(struct net_device *dev, union iwreq_data *wrqu, char *extra) { - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ /* Set the number of intervals. */ wrqu->data.length = lp->his_number; @@ -2386,7 +2375,7 @@ static const struct iw_handler_def wavelan_handler_def = static iw_stats *wavelan_get_wireless_stats(struct net_device * dev) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); mmr_t m; iw_stats *wstats; unsigned long flags; @@ -2461,7 +2450,7 @@ static iw_stats *wavelan_get_wireless_stats(struct net_device * dev) static void wv_packet_read(struct net_device * dev, u16 buf_off, int sksize) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; struct sk_buff *skb; @@ -2537,7 +2526,6 @@ wv_packet_read(struct net_device * dev, u16 buf_off, int sksize) netif_rx(skb); /* Keep statistics up to date */ - dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes += sksize; @@ -2556,7 +2544,7 @@ wv_packet_read(struct net_device * dev, u16 buf_off, int sksize) static void wv_receive(struct net_device * dev) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); fd_t fd; rbd_t rbd; int nreaped = 0; @@ -2738,7 +2726,7 @@ static void wv_receive(struct net_device * dev) */ static int wv_packet_write(struct net_device * dev, void *buf, short length) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; unsigned short txblock; unsigned short txpred; @@ -2869,7 +2857,7 @@ static int wv_packet_write(struct net_device * dev, void *buf, short length) */ static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long flags; char data[ETH_ZLEN]; @@ -2937,7 +2925,7 @@ static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev) static int wv_mmc_init(struct net_device * dev) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); psa_t psa; mmw_t m; int configured; @@ -3108,7 +3096,7 @@ static int wv_mmc_init(struct net_device * dev) */ static int wv_ru_start(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; u16 scb_cs; fd_t fd; @@ -3200,7 +3188,7 @@ static int wv_ru_start(struct net_device * dev) */ static int wv_cu_start(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; int i; u16 txblock; @@ -3301,7 +3289,7 @@ static int wv_cu_start(struct net_device * dev) */ static int wv_82586_start(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; scp_t scp; /* system configuration pointer */ iscp_t iscp; /* intermediate scp */ @@ -3433,7 +3421,7 @@ static int wv_82586_start(struct net_device * dev) */ static void wv_82586_config(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; unsigned short txblock; unsigned short txpred; @@ -3565,15 +3553,11 @@ static void wv_82586_config(struct net_device * dev) WAVELAN_ADDR_SIZE >> 1); #ifdef DEBUG_CONFIG_INFO - { - DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "%s: wv_82586_config(): set %d multicast addresses:\n", dev->name, lp->mc_count); for (dmi = dev->mc_list; dmi; dmi = dmi->next) - printk(KERN_DEBUG " %s\n", - print_mac(mac, dmi->dmi_addr)); - } + printk(KERN_DEBUG " %pM\n", dmi->dmi_addr); #endif } @@ -3613,7 +3597,7 @@ static void wv_82586_config(struct net_device * dev) */ static void wv_82586_stop(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; u16 scb_cmd; @@ -3650,7 +3634,7 @@ static void wv_82586_stop(struct net_device * dev) */ static int wv_hw_reset(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; #ifdef DEBUG_CONFIG_TRACE @@ -3751,7 +3735,7 @@ static irqreturn_t wavelan_interrupt(int irq, void *dev_id) printk(KERN_DEBUG "%s: ->wavelan_interrupt()\n", dev->name); #endif - lp = (net_local *) dev->priv; + lp = netdev_priv(dev); ioaddr = dev->base_addr; #ifdef DEBUG_INTERRUPT_INFO @@ -3894,7 +3878,7 @@ static irqreturn_t wavelan_interrupt(int irq, void *dev_id) */ static void wavelan_watchdog(struct net_device * dev) { - net_local * lp = (net_local *)dev->priv; + net_local *lp = netdev_priv(dev); u_long ioaddr = dev->base_addr; unsigned long flags; unsigned int nreaped; @@ -3974,7 +3958,7 @@ static void wavelan_watchdog(struct net_device * dev) */ static int wavelan_open(struct net_device * dev) { - net_local * lp = (net_local *)dev->priv; + net_local *lp = netdev_priv(dev); unsigned long flags; #ifdef DEBUG_CALLBACK_TRACE @@ -4029,7 +4013,7 @@ static int wavelan_open(struct net_device * dev) */ static int wavelan_close(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long flags; #ifdef DEBUG_CALLBACK_TRACE @@ -4128,8 +4112,8 @@ static int __init wavelan_config(struct net_device *dev, unsigned short ioaddr) dev->if_port = 0; /* Initialize device structures */ - memset(dev->priv, 0, sizeof(net_local)); - lp = (net_local *) dev->priv; + memset(netdev_priv(dev), 0, sizeof(net_local)); + lp = netdev_priv(dev); /* Back link to the device structure. */ lp->dev = dev; diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index e124b1d6267afa03cc5e3c149d8ab77080159b2c..de717f8ffd61061a5caccfa92cb62d70403b1087 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -1020,7 +1020,6 @@ wv_82593_reconfig(struct net_device * dev) static void wv_psa_show(psa_t * p) { - DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "##### wavelan psa contents: #####\n"); printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n", p->psa_io_base_addr_1, @@ -1034,13 +1033,10 @@ wv_psa_show(psa_t * p) printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params); printk("psa_int_req_no: %d\n", p->psa_int_req_no); #ifdef DEBUG_SHOW_UNUSED - printk(KERN_DEBUG "psa_unused0[]: %s\n", - print_mac(mac, p->psa_unused0)); + printk(KERN_DEBUG "psa_unused0[]: %pM\n", p->psa_unused0); #endif /* DEBUG_SHOW_UNUSED */ - printk(KERN_DEBUG "psa_univ_mac_addr[]: %s\n", - print_mac(mac, p->psa_univ_mac_addr)); - printk(KERN_DEBUG "psa_local_mac_addr[]: %s\n", - print_mac(mac, p->psa_local_mac_addr)); + printk(KERN_DEBUG "psa_univ_mac_addr[]: %pM\n", p->psa_univ_mac_addr); + printk(KERN_DEBUG "psa_local_mac_addr[]: %pM\n", p->psa_local_mac_addr); printk(KERN_DEBUG "psa_univ_local_sel: %d, ", p->psa_univ_local_sel); printk("psa_comp_number: %d, ", p->psa_comp_number); printk("psa_thr_pre_set: 0x%02x\n", p->psa_thr_pre_set); @@ -1238,12 +1234,11 @@ wv_packet_info(u_char * p, /* Packet to dump */ { int i; int maxi; - DECLARE_MAC_BUF(mac); - printk(KERN_DEBUG "%s: %s(): dest %s, length %d\n", - msg1, msg2, print_mac(mac, p), length); - printk(KERN_DEBUG "%s: %s(): src %s, type 0x%02X%02X\n", - msg1, msg2, print_mac(mac, &p[6]), p[12], p[13]); + printk(KERN_DEBUG "%s: %s(): dest %pM, length %d\n", + msg1, msg2, p, length); + printk(KERN_DEBUG "%s: %s(): src %pM, type 0x%02X%02X\n", + msg1, msg2, &p[6], p[12], p[13]); #ifdef DEBUG_PACKET_DUMP @@ -1274,7 +1269,6 @@ wv_init_info(struct net_device * dev) { unsigned int base = dev->base_addr; psa_t psa; - DECLARE_MAC_BUF(mac); /* Read the parameter storage area */ psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); @@ -1291,10 +1285,8 @@ wv_init_info(struct net_device * dev) #ifdef DEBUG_BASIC_SHOW /* Now, let's go for the basic stuff */ - printk(KERN_NOTICE "%s: WaveLAN: port %#x, irq %d, " - "hw_addr %s", - dev->name, base, dev->irq, - print_mac(mac, dev->dev_addr)); + printk(KERN_NOTICE "%s: WaveLAN: port %#x, irq %d, hw_addr %pM", + dev->name, base, dev->irq, dev->dev_addr); /* Print current network id */ if(psa.psa_nwid_select) @@ -2243,13 +2235,7 @@ static int wavelan_set_wap(struct net_device *dev, char *extra) { #ifdef DEBUG_IOCTL_INFO - printk(KERN_DEBUG "Set AP to : %02X:%02X:%02X:%02X:%02X:%02X\n", - wrqu->ap_addr.sa_data[0], - wrqu->ap_addr.sa_data[1], - wrqu->ap_addr.sa_data[2], - wrqu->ap_addr.sa_data[3], - wrqu->ap_addr.sa_data[4], - wrqu->ap_addr.sa_data[5]); + printk(KERN_DEBUG "Set AP to : %pM\n", wrqu->ap_addr.sa_data); #endif /* DEBUG_IOCTL_INFO */ return -EOPNOTSUPP; @@ -2892,7 +2878,6 @@ wv_packet_read(struct net_device * dev, netif_rx(skb); /* Keep stats up to date */ - dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes += sksize; @@ -3647,12 +3632,10 @@ wv_82593_config(struct net_device * dev) int addrs_len = WAVELAN_ADDR_SIZE * lp->mc_count; #ifdef DEBUG_CONFIG_INFO - DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "%s: wv_hw_config(): set %d multicast addresses:\n", dev->name, lp->mc_count); for(dmi=dev->mc_list; dmi; dmi=dmi->next) - printk(KERN_DEBUG " %s\n", - print_mac(mac, dmi->dmi_addr)); + printk(KERN_DEBUG " %pM\n", dmi->dmi_addr); #endif /* Initialize adapter's ethernet multicast addresses */ diff --git a/drivers/net/wireless/wl3501.h b/drivers/net/wireless/wl3501.h index 65ceb088f7000c9e06b371605857302d59beeeff..59bb3a55ab48c82838da43c1545d9863560bf572 100644 --- a/drivers/net/wireless/wl3501.h +++ b/drivers/net/wireless/wl3501.h @@ -2,7 +2,7 @@ #define __WL3501_H__ #include -#include +#include /* define for WLA 2.0 */ #define WL3501_BLKSZ 256 @@ -548,7 +548,7 @@ struct wl3501_80211_tx_plcp_hdr { struct wl3501_80211_tx_hdr { struct wl3501_80211_tx_plcp_hdr pclp_hdr; - struct ieee80211_hdr_4addr mac_hdr; + struct ieee80211_hdr mac_hdr; } __attribute__ ((packed)); /* diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index 68789c6e1ce9ac96cb180b7c8a6d798719764294..c99a1b6b948fca668dfbf31b82ace895bb005de7 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -860,10 +860,9 @@ static int wl3501_esbq_confirm(struct wl3501_card *this) static void wl3501_online(struct net_device *dev) { struct wl3501_card *this = netdev_priv(dev); - DECLARE_MAC_BUF(mac); - printk(KERN_INFO "%s: Wireless LAN online. BSSID: %s\n", - dev->name, print_mac(mac, this->bssid)); + printk(KERN_INFO "%s: Wireless LAN online. BSSID: %pM\n", + dev->name, this->bssid); netif_wake_queue(dev); } @@ -1014,7 +1013,6 @@ static inline void wl3501_md_ind_interrupt(struct net_device *dev, wl3501_receive(this, skb->data, pkt_len); skb_put(skb, pkt_len); skb->protocol = eth_type_trans(skb, dev); - dev->last_rx = jiffies; this->stats.rx_packets++; this->stats.rx_bytes += skb->len; netif_rx(skb); @@ -1965,7 +1963,6 @@ static int wl3501_config(struct pcmcia_device *link) struct net_device *dev = link->priv; int i = 0, j, last_fn, last_ret; struct wl3501_card *this; - DECLARE_MAC_BUF(mac); /* Try allocating IO ports. This tries a few fixed addresses. If you * want, you can also read the card's config table to pick addresses -- @@ -2024,9 +2021,9 @@ static int wl3501_config(struct pcmcia_device *link) /* print probe information */ printk(KERN_INFO "%s: wl3501 @ 0x%3.3x, IRQ %d, " - "MAC addr in flash ROM:%s\n", + "MAC addr in flash ROM:%pM\n", dev->name, this->base_addr, (int)dev->irq, - print_mac(mac, dev->dev_addr)); + dev->dev_addr); /* * Initialize card parameters - added by jss */ diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c index b16ec6e5f0e3913115fe6a40b15ae9a9e0bde4ca..b45c27d42fd83f98ac6a5f3479b0251f40443e7b 100644 --- a/drivers/net/wireless/zd1201.c +++ b/drivers/net/wireless/zd1201.c @@ -17,11 +17,11 @@ #include #include #include +#include #include #include #include #include -#include #include "zd1201.h" static struct usb_device_id zd1201_table[] = { @@ -328,7 +328,6 @@ static void zd1201_usbrx(struct urb *urb) memcpy(skb_put(skb, 2), &data[datalen-24], 2); memcpy(skb_put(skb, len), data, len); skb->protocol = eth_type_trans(skb, zd->dev); - skb->dev->last_rx = jiffies; zd->stats.rx_packets++; zd->stats.rx_bytes += skb->len; netif_rx(skb); @@ -346,7 +345,7 @@ static void zd1201_usbrx(struct urb *urb) frag = kmalloc(sizeof(*frag), GFP_ATOMIC); if (!frag) goto resubmit; - skb = dev_alloc_skb(IEEE80211_DATA_LEN +14+2); + skb = dev_alloc_skb(IEEE80211_MAX_DATA_LEN +14+2); if (!skb) { kfree(frag); goto resubmit; @@ -385,7 +384,6 @@ static void zd1201_usbrx(struct urb *urb) memcpy(skb_put(skb, len), data+8, len); } skb->protocol = eth_type_trans(skb, zd->dev); - skb->dev->last_rx = jiffies; zd->stats.rx_packets++; zd->stats.rx_bytes += skb->len; netif_rx(skb); @@ -745,7 +743,7 @@ static int zd1201_join(struct zd1201 *zd, char *essid, int essidlen) static int zd1201_net_open(struct net_device *dev) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); /* Start MAC with wildcard if no essid set */ if (!zd->mac_enabled) @@ -783,7 +781,7 @@ static int zd1201_net_stop(struct net_device *dev) */ static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); unsigned char *txbuf = zd->txdata; int txbuflen, pad = 0, err; struct urb *urb = zd->tx_urb; @@ -833,7 +831,7 @@ static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) static void zd1201_tx_timeout(struct net_device *dev) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); if (!zd) return; @@ -848,7 +846,7 @@ static void zd1201_tx_timeout(struct net_device *dev) static int zd1201_set_mac_address(struct net_device *dev, void *p) { struct sockaddr *addr = p; - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); int err; if (!zd) @@ -865,21 +863,21 @@ static int zd1201_set_mac_address(struct net_device *dev, void *p) static struct net_device_stats *zd1201_get_stats(struct net_device *dev) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); return &zd->stats; } static struct iw_statistics *zd1201_get_wireless_stats(struct net_device *dev) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); return &zd->iwstats; } static void zd1201_set_multicast(struct net_device *dev) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); struct dev_mc_list *mc = dev->mc_list; unsigned char reqbuf[ETH_ALEN*ZD1201_MAXMULTI]; int i; @@ -899,7 +897,7 @@ static void zd1201_set_multicast(struct net_device *dev) static int zd1201_config_commit(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *essid) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); return zd1201_mac_reset(zd); } @@ -914,7 +912,7 @@ static int zd1201_get_name(struct net_device *dev, static int zd1201_set_freq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *freq, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short channel = 0; int err; @@ -939,7 +937,7 @@ static int zd1201_set_freq(struct net_device *dev, static int zd1201_get_freq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *freq, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short channel; int err; @@ -955,7 +953,7 @@ static int zd1201_get_freq(struct net_device *dev, static int zd1201_set_mode(struct net_device *dev, struct iw_request_info *info, __u32 *mode, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short porttype, monitor = 0; unsigned char buffer[IW_ESSID_MAX_SIZE+2]; int err; @@ -1017,7 +1015,7 @@ static int zd1201_set_mode(struct net_device *dev, static int zd1201_get_mode(struct net_device *dev, struct iw_request_info *info, __u32 *mode, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short porttype; int err; @@ -1093,7 +1091,7 @@ static int zd1201_get_range(struct net_device *dev, static int zd1201_get_wap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *ap_addr, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); unsigned char buffer[6]; if (!zd1201_getconfig(zd, ZD1201_RID_COMMSQUALITY, buffer, 6)) { @@ -1121,7 +1119,7 @@ static int zd1201_set_scan(struct net_device *dev, static int zd1201_get_scan(struct net_device *dev, struct iw_request_info *info, struct iw_point *srq, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); int err, i, j, enabled_save; struct iw_event iwe; char *cev = extra; @@ -1213,7 +1211,7 @@ static int zd1201_get_scan(struct net_device *dev, static int zd1201_set_essid(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *essid) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); if (data->length > IW_ESSID_MAX_SIZE) return -EINVAL; @@ -1228,7 +1226,7 @@ static int zd1201_set_essid(struct net_device *dev, static int zd1201_get_essid(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *essid) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); memcpy(essid, zd->essid, zd->essidlen); data->flags = 1; @@ -1249,7 +1247,7 @@ static int zd1201_get_nick(struct net_device *dev, struct iw_request_info *info, static int zd1201_set_rate(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short rate; int err; @@ -1282,7 +1280,7 @@ static int zd1201_set_rate(struct net_device *dev, static int zd1201_get_rate(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short rate; int err; @@ -1315,7 +1313,7 @@ static int zd1201_get_rate(struct net_device *dev, static int zd1201_set_rts(struct net_device *dev, struct iw_request_info *info, struct iw_param *rts, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); int err; short val = rts->value; @@ -1335,7 +1333,7 @@ static int zd1201_set_rts(struct net_device *dev, struct iw_request_info *info, static int zd1201_get_rts(struct net_device *dev, struct iw_request_info *info, struct iw_param *rts, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short rtst; int err; @@ -1352,7 +1350,7 @@ static int zd1201_get_rts(struct net_device *dev, struct iw_request_info *info, static int zd1201_set_frag(struct net_device *dev, struct iw_request_info *info, struct iw_param *frag, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); int err; short val = frag->value; @@ -1373,7 +1371,7 @@ static int zd1201_set_frag(struct net_device *dev, struct iw_request_info *info, static int zd1201_get_frag(struct net_device *dev, struct iw_request_info *info, struct iw_param *frag, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short fragt; int err; @@ -1402,7 +1400,7 @@ static int zd1201_get_retry(struct net_device *dev, static int zd1201_set_encode(struct net_device *dev, struct iw_request_info *info, struct iw_point *erq, char *key) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short i; int err, rid; @@ -1459,7 +1457,7 @@ static int zd1201_set_encode(struct net_device *dev, static int zd1201_get_encode(struct net_device *dev, struct iw_request_info *info, struct iw_point *erq, char *key) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short i; int err; @@ -1492,7 +1490,7 @@ static int zd1201_get_encode(struct net_device *dev, static int zd1201_set_power(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short enabled, duration, level; int err; @@ -1531,7 +1529,7 @@ static int zd1201_set_power(struct net_device *dev, static int zd1201_get_power(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short enabled, level, duration; int err; @@ -1618,7 +1616,7 @@ static const iw_handler zd1201_iw_handler[] = static int zd1201_set_hostauth(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); if (!zd->ap) return -EOPNOTSUPP; @@ -1629,7 +1627,7 @@ static int zd1201_set_hostauth(struct net_device *dev, static int zd1201_get_hostauth(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short hostauth; int err; @@ -1648,7 +1646,7 @@ static int zd1201_get_hostauth(struct net_device *dev, static int zd1201_auth_sta(struct net_device *dev, struct iw_request_info *info, struct sockaddr *sta, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); unsigned char buffer[10]; if (!zd->ap) @@ -1664,7 +1662,7 @@ static int zd1201_auth_sta(struct net_device *dev, static int zd1201_set_maxassoc(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); int err; if (!zd->ap) @@ -1679,7 +1677,7 @@ static int zd1201_set_maxassoc(struct net_device *dev, static int zd1201_get_maxassoc(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short maxassoc; int err; @@ -1731,6 +1729,7 @@ static int zd1201_probe(struct usb_interface *interface, const struct usb_device_id *id) { struct zd1201 *zd; + struct net_device *dev; struct usb_device *usb; int err; short porttype; @@ -1738,9 +1737,12 @@ static int zd1201_probe(struct usb_interface *interface, usb = interface_to_usbdev(interface); - zd = kzalloc(sizeof(struct zd1201), GFP_KERNEL); - if (!zd) + dev = alloc_etherdev(sizeof(*zd)); + if (!dev) return -ENOMEM; + zd = netdev_priv(dev); + zd->dev = dev; + zd->ap = ap; zd->usb = usb; zd->removed = 0; @@ -1775,34 +1777,29 @@ static int zd1201_probe(struct usb_interface *interface, if (err) goto err_start; - zd->dev = alloc_etherdev(0); - if (!zd->dev) - goto err_start; - - zd->dev->priv = zd; - zd->dev->open = zd1201_net_open; - zd->dev->stop = zd1201_net_stop; - zd->dev->get_stats = zd1201_get_stats; - zd->dev->wireless_handlers = + dev->open = zd1201_net_open; + dev->stop = zd1201_net_stop; + dev->get_stats = zd1201_get_stats; + dev->wireless_handlers = (struct iw_handler_def *)&zd1201_iw_handlers; - zd->dev->hard_start_xmit = zd1201_hard_start_xmit; - zd->dev->watchdog_timeo = ZD1201_TX_TIMEOUT; - zd->dev->tx_timeout = zd1201_tx_timeout; - zd->dev->set_multicast_list = zd1201_set_multicast; - zd->dev->set_mac_address = zd1201_set_mac_address; - strcpy(zd->dev->name, "wlan%d"); + dev->hard_start_xmit = zd1201_hard_start_xmit; + dev->watchdog_timeo = ZD1201_TX_TIMEOUT; + dev->tx_timeout = zd1201_tx_timeout; + dev->set_multicast_list = zd1201_set_multicast; + dev->set_mac_address = zd1201_set_mac_address; + strcpy(dev->name, "wlan%d"); err = zd1201_getconfig(zd, ZD1201_RID_CNFOWNMACADDR, - zd->dev->dev_addr, zd->dev->addr_len); + dev->dev_addr, dev->addr_len); if (err) - goto err_net; + goto err_start; /* Set wildcard essid to match zd->essid */ *(__le16 *)buf = cpu_to_le16(0); err = zd1201_setconfig(zd, ZD1201_RID_CNFDESIREDSSID, buf, IW_ESSID_MAX_SIZE+2, 1); if (err) - goto err_net; + goto err_start; if (zd->ap) porttype = ZD1201_PORTTYPE_AP; @@ -1810,30 +1807,28 @@ static int zd1201_probe(struct usb_interface *interface, porttype = ZD1201_PORTTYPE_BSS; err = zd1201_setconfig16(zd, ZD1201_RID_CNFPORTTYPE, porttype); if (err) - goto err_net; + goto err_start; - SET_NETDEV_DEV(zd->dev, &usb->dev); + SET_NETDEV_DEV(dev, &usb->dev); - err = register_netdev(zd->dev); + err = register_netdev(dev); if (err) - goto err_net; + goto err_start; dev_info(&usb->dev, "%s: ZD1201 USB Wireless interface\n", - zd->dev->name); + dev->name); usb_set_intfdata(interface, zd); zd1201_enable(zd); /* zd1201 likes to startup enabled, */ zd1201_disable(zd); /* interfering with all the wifis in range */ return 0; -err_net: - free_netdev(zd->dev); err_start: /* Leave the device in reset state */ zd1201_docmd(zd, ZD1201_CMDCODE_INIT, 0, 0, 0); err_zd: usb_free_urb(zd->tx_urb); usb_free_urb(zd->rx_urb); - kfree(zd); + free_netdev(dev); return err; } @@ -1846,10 +1841,6 @@ static void zd1201_disconnect(struct usb_interface *interface) if (!zd) return; usb_set_intfdata(interface, NULL); - if (zd->dev) { - unregister_netdev(zd->dev); - free_netdev(zd->dev); - } hlist_for_each_entry_safe(frag, node, node2, &zd->fraglist, fnode) { hlist_del_init(&frag->fnode); @@ -1865,7 +1856,11 @@ static void zd1201_disconnect(struct usb_interface *interface) usb_kill_urb(zd->rx_urb); usb_free_urb(zd->rx_urb); } - kfree(zd); + + if (zd->dev) { + unregister_netdev(zd->dev); + free_netdev(zd->dev); + } } #ifdef CONFIG_PM diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index e0ac58b8ff1fafe3e57a042f8e2a2ddfafeacc30..f1519143f8a65e80fca00501be81e5fd456cec73 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c @@ -378,7 +378,6 @@ int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr) [0] = { .addr = CR_MAC_ADDR_P1 }, [1] = { .addr = CR_MAC_ADDR_P2 }, }; - DECLARE_MAC_BUF(mac); if (mac_addr) { reqs[0].value = (mac_addr[3] << 24) @@ -387,8 +386,7 @@ int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr) | mac_addr[0]; reqs[1].value = (mac_addr[5] << 8) | mac_addr[4]; - dev_dbg_f(zd_chip_dev(chip), - "mac addr %s\n", print_mac(mac, mac_addr)); + dev_dbg_f(zd_chip_dev(chip), "mac addr %pM\n", mac_addr); } else { dev_dbg_f(zd_chip_dev(chip), "set NULL mac\n"); } diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index cac732f4047f524b3b575a1e86dbee1d7fd68644..9caa96a135866c8c79cbc240d63ebfadc9c5e699 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -171,7 +171,7 @@ int zd_mac_init_hw(struct ieee80211_hw *hw) r = zd_reg2alpha2(mac->regdomain, alpha2); if (!r) - regulatory_hint(hw->wiphy, alpha2, NULL); + regulatory_hint(hw->wiphy, alpha2); r = 0; disable_int: @@ -296,15 +296,14 @@ static void zd_op_stop(struct ieee80211_hw *hw) * If no status information has been requested, the skb is freed. */ static void tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, - u32 flags, int ackssi, bool success) + int ackssi, bool success) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - memset(&info->status, 0, sizeof(info->status)); + ieee80211_tx_info_clear_status(info); - if (!success) - info->status.excessive_retries = 1; - info->flags |= flags; + if (success) + info->flags |= IEEE80211_TX_STAT_ACK; info->status.ack_signal = ackssi; ieee80211_tx_status_irqsafe(hw, skb); } @@ -326,7 +325,7 @@ void zd_mac_tx_failed(struct ieee80211_hw *hw) if (skb == NULL) return; - tx_status(hw, skb, 0, 0, 0); + tx_status(hw, skb, 0, 0); } /** @@ -342,12 +341,12 @@ void zd_mac_tx_failed(struct ieee80211_hw *hw) void zd_mac_tx_to_dev(struct sk_buff *skb, int error) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_hw *hw = info->driver_data[0]; + struct ieee80211_hw *hw = info->rate_driver_data[0]; skb_pull(skb, sizeof(struct zd_ctrlset)); if (unlikely(error || (info->flags & IEEE80211_TX_CTL_NO_ACK))) { - tx_status(hw, skb, 0, 0, !error); + tx_status(hw, skb, 0, !error); } else { struct sk_buff_head *q = &zd_hw_mac(hw)->ack_wait_queue; @@ -406,7 +405,8 @@ static int zd_calc_tx_length_us(u8 *service, u8 zd_rate, u16 tx_length) } static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, - struct ieee80211_hdr *header, u32 flags) + struct ieee80211_hdr *header, + struct ieee80211_tx_info *info) { /* * CONTROL TODO: @@ -417,7 +417,7 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, cs->control = 0; /* First fragment */ - if (flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) + if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) cs->control |= ZD_CS_NEED_RANDOM_BACKOFF; /* Multicast */ @@ -428,10 +428,10 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, if (ieee80211_is_pspoll(header->frame_control)) cs->control |= ZD_CS_PS_POLL_FRAME; - if (flags & IEEE80211_TX_CTL_USE_RTS_CTS) + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) cs->control |= ZD_CS_RTS; - if (flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) cs->control |= ZD_CS_SELF_CTS; /* FIXME: Management frame? */ @@ -517,12 +517,12 @@ static int fill_ctrlset(struct zd_mac *mac, txrate = ieee80211_get_tx_rate(mac->hw, info); cs->modulation = txrate->hw_value; - if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE) + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) cs->modulation = txrate->hw_value_short; cs->tx_length = cpu_to_le16(frag_len); - cs_set_control(mac, cs, hdr, info->flags); + cs_set_control(mac, cs, hdr, info); packet_length = frag_len + sizeof(struct zd_ctrlset) + 10; ZD_ASSERT(packet_length <= 0xffff); @@ -577,7 +577,7 @@ static int zd_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) if (r) return r; - info->driver_data[0] = hw; + info->rate_driver_data[0] = hw; r = zd_usb_tx(&mac->chip.usb, skb); if (r) @@ -618,7 +618,7 @@ static int filter_ack(struct ieee80211_hw *hw, struct ieee80211_hdr *rx_hdr, if (likely(!memcmp(tx_hdr->addr2, rx_hdr->addr1, ETH_ALEN))) { __skb_unlink(skb, q); - tx_status(hw, skb, IEEE80211_TX_STAT_ACK, stats->signal, 1); + tx_status(hw, skb, stats->signal, 1); goto out; } } @@ -743,9 +743,11 @@ static void zd_op_remove_interface(struct ieee80211_hw *hw, zd_write_mac_addr(&mac->chip, NULL); } -static int zd_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +static int zd_op_config(struct ieee80211_hw *hw, u32 changed) { struct zd_mac *mac = zd_hw_mac(hw); + struct ieee80211_conf *conf = &hw->conf; + return zd_chip_set_channel(&mac->chip, conf->channel->hw_value); } @@ -852,14 +854,12 @@ static void zd_op_configure_filter(struct ieee80211_hw *hw, if (*new_flags & (FIF_PROMISC_IN_BSS | FIF_ALLMULTI)) { zd_mc_add_all(&hash); } else { - DECLARE_MAC_BUF(macbuf); - zd_mc_clear(&hash); for (i = 0; i < mc_count; i++) { if (!mclist) break; - dev_dbg_f(zd_mac_dev(mac), "mc addr %s\n", - print_mac(macbuf, mclist->dmi_addr)); + dev_dbg_f(zd_mac_dev(mac), "mc addr %pM\n", + mclist->dmi_addr); zd_mc_add_addr(&hash, mclist->dmi_addr); mclist = mclist->next; } diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index a3ccd8c1c716957bd669ec678681bc2fcfe1f806..04c1396669656261d87cf6dbc53a6bc1c4b748ff 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -909,7 +909,7 @@ static void tx_urb_complete(struct urb *urb) * it might be freed by zd_mac_tx_to_dev or mac80211) */ info = IEEE80211_SKB_CB(skb); - usb = &zd_hw_mac(info->driver_data[0])->chip.usb; + usb = &zd_hw_mac(info->rate_driver_data[0])->chip.usb; zd_mac_tx_to_dev(skb, urb->status); free_tx_urb(usb, urb); tx_dec_submitted_urbs(usb); diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 6d017adc914ac18c5389fb550b53ed5aa09b3246..761635be9104f155af6978a72a8283ebec2cde9e 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -196,7 +196,7 @@ static void rx_refill_timeout(unsigned long data) { struct net_device *dev = (struct net_device *)data; struct netfront_info *np = netdev_priv(dev); - netif_rx_schedule(dev, &np->napi); + netif_rx_schedule(&np->napi); } static int netfront_tx_slot_available(struct netfront_info *np) @@ -328,7 +328,7 @@ static int xennet_open(struct net_device *dev) xennet_alloc_rx_buffers(dev); np->rx.sring->rsp_event = np->rx.rsp_cons + 1; if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx)) - netif_rx_schedule(dev, &np->napi); + netif_rx_schedule(&np->napi); } spin_unlock_bh(&np->rx_lock); @@ -841,7 +841,6 @@ static int handle_incoming_queue(struct net_device *dev, /* Pass it up. */ netif_receive_skb(skb); - dev->last_rx = jiffies; } return packets_dropped; @@ -980,7 +979,7 @@ static int xennet_poll(struct napi_struct *napi, int budget) RING_FINAL_CHECK_FOR_RESPONSES(&np->rx, more_to_do); if (!more_to_do) - __netif_rx_complete(dev, napi); + __netif_rx_complete(napi); local_irq_restore(flags); } @@ -1311,7 +1310,7 @@ static irqreturn_t xennet_interrupt(int irq, void *dev_id) xennet_tx_buf_gc(dev); /* Under tx_lock: protects access to rx shared-ring indexes. */ if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx)) - netif_rx_schedule(dev, &np->napi); + netif_rx_schedule(&np->napi); } spin_unlock_irqrestore(&np->tx_lock, flags); diff --git a/drivers/net/xtsonic.c b/drivers/net/xtsonic.c index da42aa06a3babc7982b37f820ebd9172cab0ffd6..03a3f34e90393c43202db9731caac53cd25ed40a 100644 --- a/drivers/net/xtsonic.c +++ b/drivers/net/xtsonic.c @@ -239,8 +239,6 @@ int __init xtsonic_probe(struct platform_device *pdev) struct resource *resmem, *resirq; int err = 0; - DECLARE_MAC_BUF(mac); - if ((resmem = platform_get_resource(pdev, IORESOURCE_MEM, 0)) == NULL) return -ENODEV; @@ -263,8 +261,8 @@ int __init xtsonic_probe(struct platform_device *pdev) if ((err = register_netdev(dev))) goto out1; - printk("%s: SONIC ethernet @%08lx, MAC %s, IRQ %d\n", dev->name, - dev->base_addr, print_mac(mac, dev->dev_addr), dev->irq); + printk("%s: SONIC ethernet @%08lx, MAC %pM, IRQ %d\n", dev->name, + dev->base_addr, dev->dev_addr, dev->irq); return 0; diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index 57e1f495b9fc0456db009a9540ec0f7111295b51..cf97129227780ee2f8d2427f687c6e5c1f4128ca 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -355,6 +355,16 @@ static int yellowfin_close(struct net_device *dev); static void set_rx_mode(struct net_device *dev); static const struct ethtool_ops ethtool_ops; +static const struct net_device_ops netdev_ops = { + .ndo_open = yellowfin_open, + .ndo_stop = yellowfin_close, + .ndo_start_xmit = yellowfin_start_xmit, + .ndo_set_multicast_list = set_rx_mode, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_do_ioctl = netdev_ioctl, + .ndo_tx_timeout = yellowfin_tx_timeout, +}; static int __devinit yellowfin_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -374,7 +384,6 @@ static int __devinit yellowfin_init_one(struct pci_dev *pdev, #else int bar = 1; #endif - DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -465,13 +474,8 @@ static int __devinit yellowfin_init_one(struct pci_dev *pdev, np->duplex_lock = 1; /* The Yellowfin-specific entries in the device structure. */ - dev->open = &yellowfin_open; - dev->hard_start_xmit = &yellowfin_start_xmit; - dev->stop = &yellowfin_close; - dev->set_multicast_list = &set_rx_mode; - dev->do_ioctl = &netdev_ioctl; + dev->netdev_ops = &netdev_ops; SET_ETHTOOL_OPS(dev, ðtool_ops); - dev->tx_timeout = yellowfin_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; if (mtu) @@ -481,10 +485,10 @@ static int __devinit yellowfin_init_one(struct pci_dev *pdev, if (i) goto err_out_unmap_status; - printk(KERN_INFO "%s: %s type %8x at %p, %s, IRQ %d.\n", + printk(KERN_INFO "%s: %s type %8x at %p, %pM, IRQ %d.\n", dev->name, pci_id_tbl[chip_idx].name, ioread32(ioaddr + ChipRev), ioaddr, - print_mac(mac, dev->dev_addr), irq); + dev->dev_addr, irq); if (np->drv_flags & HasMII) { int phy, phy_idx = 0; @@ -1100,11 +1104,9 @@ static int yellowfin_rx(struct net_device *dev) memcmp(le32_to_cpu(yp->rx_ring_dma + entry*sizeof(struct yellowfin_desc)), "\377\377\377\377\377\377", 6) != 0) { - if (bogus_rx++ == 0) { - DECLARE_MAC_BUF(mac); - printk(KERN_WARNING "%s: Bad frame to %s\n", - dev->name, print_mac(mac, buf_addr)); - } + if (bogus_rx++ == 0) + printk(KERN_WARNING "%s: Bad frame to %pM\n", + dev->name, buf_addr); #endif } else { struct sk_buff *skb; @@ -1141,7 +1143,6 @@ static int yellowfin_rx(struct net_device *dev) } skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } @@ -1423,14 +1424,3 @@ static void __exit yellowfin_cleanup (void) module_init(yellowfin_init); module_exit(yellowfin_cleanup); - -/* - * Local variables: - * compile-command: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c yellowfin.c" - * compile-command-alphaLX: "gcc -DMODULE -Wall -Wstrict-prototypes -O2 -c yellowfin.c -fomit-frame-pointer -fno-strength-reduce -mno-fp-regs -Wa,-m21164a -DBWX_USABLE -DBWIO_ENABLED" - * simple-compile-command: "gcc -DMODULE -O6 -c yellowfin.c" - * c-indent-level: 4 - * c-basic-offset: 4 - * tab-width: 4 - * End: - */ diff --git a/drivers/net/znet.c b/drivers/net/znet.c index a86c022d6a9494e4f96822095b06366d7531054b..f0b15c9347d0dae517497544ef629b9e0f8d80c1 100644 --- a/drivers/net/znet.c +++ b/drivers/net/znet.c @@ -167,7 +167,7 @@ static void znet_tx_timeout (struct net_device *dev); /* Request needed resources */ static int znet_request_resources (struct net_device *dev) { - struct znet_private *znet = dev->priv; + struct znet_private *znet = netdev_priv(dev); unsigned long flags; if (request_irq (dev->irq, &znet_interrupt, 0, "ZNet", dev)) @@ -201,7 +201,7 @@ static int znet_request_resources (struct net_device *dev) static void znet_release_resources (struct net_device *dev) { - struct znet_private *znet = dev->priv; + struct znet_private *znet = netdev_priv(dev); unsigned long flags; release_region (znet->sia_base, znet->sia_size); @@ -216,7 +216,7 @@ static void znet_release_resources (struct net_device *dev) /* Keep the magical SIA stuff in a single function... */ static void znet_transceiver_power (struct net_device *dev, int on) { - struct znet_private *znet = dev->priv; + struct znet_private *znet = netdev_priv(dev); unsigned char v; /* Turn on/off the 82501 SIA, using zenith-specific magic. */ @@ -235,7 +235,7 @@ static void znet_transceiver_power (struct net_device *dev, int on) Also used from hardware_init. */ static void znet_set_multicast_list (struct net_device *dev) { - struct znet_private *znet = dev->priv; + struct znet_private *znet = netdev_priv(dev); short ioaddr = dev->base_addr; struct i82593_conf_block *cfblk = &znet->i593_init; @@ -370,7 +370,6 @@ static int __init znet_probe (void) struct net_device *dev; char *p; int err = -ENOMEM; - DECLARE_MAC_BUF(mac); /* This code scans the region 0xf0000 to 0xfffff for a "NETIDBLK". */ for(p = (char *)phys_to_virt(0xf0000); p < (char *)phys_to_virt(0x100000); p++) @@ -387,7 +386,7 @@ static int __init znet_probe (void) if (!dev) return -ENOMEM; - znet = dev->priv; + znet = netdev_priv(dev); netinfo = (struct netidblk *)p; dev->base_addr = netinfo->iobase1; @@ -397,9 +396,9 @@ static int __init znet_probe (void) for (i = 0; i < 6; i++) dev->dev_addr[i] = netinfo->netid[i]; - printk(KERN_INFO "%s: ZNET at %#3lx, %s" + printk(KERN_INFO "%s: ZNET at %#3lx, %pM" ", using IRQ %d DMA %d and %d.\n", - dev->name, dev->base_addr, print_mac(mac, dev->dev_addr), + dev->name, dev->base_addr, dev->dev_addr, dev->irq, netinfo->dma1, netinfo->dma2); if (znet_debug > 1) { @@ -531,7 +530,7 @@ static void znet_tx_timeout (struct net_device *dev) static int znet_send_packet(struct sk_buff *skb, struct net_device *dev) { int ioaddr = dev->base_addr; - struct znet_private *znet = dev->priv; + struct znet_private *znet = netdev_priv(dev); unsigned long flags; short length = skb->len; @@ -601,7 +600,7 @@ static int znet_send_packet(struct sk_buff *skb, struct net_device *dev) static irqreturn_t znet_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; - struct znet_private *znet = dev->priv; + struct znet_private *znet = netdev_priv(dev); int ioaddr; int boguscnt = 20; int handled = 0; @@ -679,7 +678,7 @@ static irqreturn_t znet_interrupt(int irq, void *dev_id) static void znet_rx(struct net_device *dev) { - struct znet_private *znet = dev->priv; + struct znet_private *znet = netdev_priv(dev); int ioaddr = dev->base_addr; int boguscount = 1; short next_frame_end_offset = 0; /* Offset of next frame start. */ @@ -786,7 +785,6 @@ static void znet_rx(struct net_device *dev) } skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } @@ -829,7 +827,7 @@ static void show_dma(struct net_device *dev) { short ioaddr = dev->base_addr; unsigned char stat = inb (ioaddr); - struct znet_private *znet = dev->priv; + struct znet_private *znet = netdev_priv(dev); unsigned long flags; short dma_port = ((znet->tx_dma&3)<<2) + IO_DMA2_BASE; unsigned addr = inb(dma_port); @@ -852,7 +850,7 @@ static void hardware_init(struct net_device *dev) { unsigned long flags; short ioaddr = dev->base_addr; - struct znet_private *znet = dev->priv; + struct znet_private *znet = netdev_priv(dev); znet->rx_cur = znet->rx_start; znet->tx_cur = znet->tx_start; @@ -914,7 +912,7 @@ static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset) static __exit void znet_cleanup (void) { if (znet_dev) { - struct znet_private *znet = znet_dev->priv; + struct znet_private *znet = netdev_priv(znet_dev); unregister_netdev (znet_dev); kfree (znet->rx_start); diff --git a/drivers/net/zorro8390.c b/drivers/net/zorro8390.c index 3926b2aa9cca4c7aaa761fbc486e65d727bf762b..affd904deafc6c885f3a4e5c0908561ffa654f23 100644 --- a/drivers/net/zorro8390.c +++ b/drivers/net/zorro8390.c @@ -122,7 +122,7 @@ static int __devinit zorro8390_init_one(struct zorro_dev *z, break; board = z->resource.start; ioaddr = board+cards[i].offset; - dev = ____alloc_ei_netdev(0); + dev = alloc_ei_netdev(); if (!dev) return -ENOMEM; if (!request_mem_region(ioaddr, NE_IO_EXTENT*2, DRV_NAME)) { @@ -139,6 +139,20 @@ static int __devinit zorro8390_init_one(struct zorro_dev *z, return 0; } +static const struct net_device_ops zorro8390_netdev_ops = { + .ndo_open = zorro8390_open, + .ndo_stop = zorro8390_close, + .ndo_start_xmit = ei_start_xmit, + .ndo_tx_timeout = ei_tx_timeout, + .ndo_get_stats = ei_get_stats, + .ndo_set_multicast_list = ei_set_multicast_list, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = ei_poll, +#endif +}; + static int __devinit zorro8390_init(struct net_device *dev, unsigned long board, const char *name, unsigned long ioaddr) @@ -151,7 +165,6 @@ static int __devinit zorro8390_init(struct net_device *dev, 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, }; - DECLARE_MAC_BUF(mac); /* Reset card. Who knows what dain-bramaged state it was left in. */ { @@ -216,7 +229,7 @@ static int __devinit zorro8390_init(struct net_device *dev, dev->dev_addr[i] = SA_prom[i]; #ifdef DEBUG - printk("%s", print_mac(mac, dev->dev_addr)); + printk("%pM", dev->dev_addr); #endif ei_status.name = name; @@ -231,12 +244,8 @@ static int __devinit zorro8390_init(struct net_device *dev, ei_status.block_output = &zorro8390_block_output; ei_status.get_8390_hdr = &zorro8390_get_8390_hdr; ei_status.reg_offset = zorro8390_offsets; - dev->open = &zorro8390_open; - dev->stop = &zorro8390_close; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = __ei_poll; -#endif + dev->netdev_ops = &zorro8390_netdev_ops; __NS8390_init(dev, 0); err = register_netdev(dev); if (err) { @@ -244,8 +253,8 @@ static int __devinit zorro8390_init(struct net_device *dev, return err; } - printk(KERN_INFO "%s: %s at 0x%08lx, Ethernet Address %s\n", - dev->name, name, board, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: %s at 0x%08lx, Ethernet Address %pM\n", + dev->name, name, board, dev->dev_addr); return 0; } diff --git a/drivers/of/base.c b/drivers/of/base.c index 7c79e94a35eac932a165367a11439a8af1d35cc0..cd17092b82bd4bbfa93e760e994046861d8f9902 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -328,6 +328,41 @@ struct device_node *of_find_compatible_node(struct device_node *from, } EXPORT_SYMBOL(of_find_compatible_node); +/** + * of_find_node_with_property - Find a node which has a property with + * the given name. + * @from: The node to start searching from or NULL, the node + * you pass will not be searched, only the next one + * will; typically, you pass what the previous call + * returned. of_node_put() will be called on it + * @prop_name: The name of the property to look for. + * + * Returns a node pointer with refcount incremented, use + * of_node_put() on it when done. + */ +struct device_node *of_find_node_with_property(struct device_node *from, + const char *prop_name) +{ + struct device_node *np; + struct property *pp; + + read_lock(&devtree_lock); + np = from ? from->allnext : allnodes; + for (; np; np = np->allnext) { + for (pp = np->properties; pp != 0; pp = pp->next) { + if (of_prop_cmp(pp->name, prop_name) == 0) { + of_node_get(np); + goto out; + } + } + } +out: + of_node_put(from); + read_unlock(&devtree_lock); + return np; +} +EXPORT_SYMBOL(of_find_node_with_property); + /** * of_match_node - Tell if an device_node has a matching of_match structure * @matches: array of of device match structures to search in @@ -464,8 +499,8 @@ EXPORT_SYMBOL_GPL(of_modalias_node); * @list_name: property name that contains a list * @cells_name: property name that specifies phandles' arguments count * @index: index of a phandle to parse out - * @out_node: pointer to device_node struct pointer (will be filled) - * @out_args: pointer to arguments pointer (will be filled) + * @out_node: optional pointer to device_node struct pointer (will be filled) + * @out_args: optional pointer to arguments pointer (will be filled) * * This function is useful to parse lists of phandles and their arguments. * Returns 0 on success and fills out_node and out_args, on error returns @@ -499,7 +534,7 @@ int of_parse_phandles_with_args(struct device_node *np, const char *list_name, int size; int cur_index = 0; struct device_node *node = NULL; - const void *args; + const void *args = NULL; list = of_get_property(np, list_name, &size); if (!list) { @@ -512,14 +547,12 @@ int of_parse_phandles_with_args(struct device_node *np, const char *list_name, const u32 *cells; const phandle *phandle; - phandle = list; - args = list + 1; + phandle = list++; + args = list; /* one cell hole in the list = <>; */ - if (!*phandle) { - list++; + if (!*phandle) goto next; - } node = of_find_node_by_phandle(*phandle); if (!node) { @@ -535,8 +568,7 @@ int of_parse_phandles_with_args(struct device_node *np, const char *list_name, goto err1; } - /* Next phandle is at offset of one phandle cell + #cells */ - list += 1 + *cells; + list += *cells; if (list > list_end) { pr_debug("%s: insufficient arguments length\n", np->full_name); @@ -548,16 +580,26 @@ int of_parse_phandles_with_args(struct device_node *np, const char *list_name, of_node_put(node); node = NULL; + args = NULL; cur_index++; } if (!node) { - ret = -ENOENT; + /* + * args w/o node indicates that the loop above has stopped at + * the 'hole' cell. Report this differently. + */ + if (args) + ret = -EEXIST; + else + ret = -ENOENT; goto err0; } - *out_node = node; - *out_args = args; + if (out_node) + *out_node = node; + if (out_args) + *out_args = args; return 0; err1: diff --git a/drivers/of/gpio.c b/drivers/of/gpio.c index 7cd7301b583992683391215816bd6bd277785691..6eea601a92043b69f3c95c86aa06ae077327c03a 100644 --- a/drivers/of/gpio.c +++ b/drivers/of/gpio.c @@ -19,14 +19,17 @@ #include /** - * of_get_gpio - Get a GPIO number from the device tree to use with GPIO API + * of_get_gpio_flags - Get a GPIO number and flags to use with GPIO API * @np: device node to get GPIO from * @index: index of the GPIO + * @flags: a flags pointer to fill in * * Returns GPIO number to use with Linux generic GPIO API, or one of the errno - * value on the error condition. + * value on the error condition. If @flags is not NULL the function also fills + * in flags for the GPIO. */ -int of_get_gpio(struct device_node *np, int index) +int of_get_gpio_flags(struct device_node *np, int index, + enum of_gpio_flags *flags) { int ret; struct device_node *gc; @@ -59,7 +62,11 @@ int of_get_gpio(struct device_node *np, int index) goto err1; } - ret = of_gc->xlate(of_gc, np, gpio_spec); + /* .xlate might decide to not fill in the flags, so clear it. */ + if (flags) + *flags = 0; + + ret = of_gc->xlate(of_gc, np, gpio_spec, flags); if (ret < 0) goto err1; @@ -70,26 +77,75 @@ int of_get_gpio(struct device_node *np, int index) pr_debug("%s exited with status %d\n", __func__, ret); return ret; } -EXPORT_SYMBOL(of_get_gpio); +EXPORT_SYMBOL(of_get_gpio_flags); /** - * of_gpio_simple_xlate - translate gpio_spec to the GPIO number + * of_gpio_count - Count GPIOs for a device + * @np: device node to count GPIOs for + * + * The function returns the count of GPIOs specified for a node. + * + * Note that the empty GPIO specifiers counts too. For example, + * + * gpios = <0 + * &pio1 1 2 + * 0 + * &pio2 3 4>; + * + * defines four GPIOs (so this function will return 4), two of which + * are not specified. + */ +unsigned int of_gpio_count(struct device_node *np) +{ + unsigned int cnt = 0; + + do { + int ret; + + ret = of_parse_phandles_with_args(np, "gpios", "#gpio-cells", + cnt, NULL, NULL); + /* A hole in the gpios = <> counts anyway. */ + if (ret < 0 && ret != -EEXIST) + break; + } while (++cnt); + + return cnt; +} +EXPORT_SYMBOL(of_gpio_count); + +/** + * of_gpio_simple_xlate - translate gpio_spec to the GPIO number and flags * @of_gc: pointer to the of_gpio_chip structure * @np: device node of the GPIO chip * @gpio_spec: gpio specifier as found in the device tree + * @flags: a flags pointer to fill in * * This is simple translation function, suitable for the most 1:1 mapped * gpio chips. This function performs only one sanity check: whether gpio * is less than ngpios (that is specified in the gpio_chip). */ int of_gpio_simple_xlate(struct of_gpio_chip *of_gc, struct device_node *np, - const void *gpio_spec) + const void *gpio_spec, enum of_gpio_flags *flags) { const u32 *gpio = gpio_spec; + /* + * We're discouraging gpio_cells < 2, since that way you'll have to + * write your own xlate function (that will have to retrive the GPIO + * number and the flags from a single gpio cell -- this is possible, + * but not recommended). + */ + if (of_gc->gpio_cells < 2) { + WARN_ON(1); + return -EINVAL; + } + if (*gpio > of_gc->gc.ngpio) return -EINVAL; + if (flags) + *flags = gpio[1]; + return *gpio; } EXPORT_SYMBOL(of_gpio_simple_xlate); diff --git a/drivers/of/of_i2c.c b/drivers/of/of_i2c.c index 24bbef777c1914cfb7096cec8f198fdbc7512618..e1b0ad6e918f0bec0a843888e4de826d1cccf825 100644 --- a/drivers/of/of_i2c.c +++ b/drivers/of/of_i2c.c @@ -24,6 +24,7 @@ void of_register_i2c_devices(struct i2c_adapter *adap, for_each_child_of_node(adap_node, node) { struct i2c_board_info info = {}; + struct dev_archdata dev_ad = {}; const u32 *addr; int len; @@ -41,6 +42,9 @@ void of_register_i2c_devices(struct i2c_adapter *adap, info.addr = *addr; + dev_archdata_set_node(&dev_ad, node); + info.archdata = &dev_ad; + request_module("%s", info.type); result = i2c_new_device(adap, &info); @@ -51,6 +55,13 @@ void of_register_i2c_devices(struct i2c_adapter *adap, irq_dispose_mapping(info.irq); continue; } + + /* + * Get the node to not lose the dev_archdata->of_node. + * Currently there is no way to put it back, as well as no + * of_unregister_i2c_devices() call. + */ + of_node_get(node); } } EXPORT_SYMBOL(of_register_i2c_devices); diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c index f9b12664f9fb90c24e07ce2cc6f49cd8769a81cd..454b6532e40998cce76aa3eeb7ed8fdaa901748a 100644 --- a/drivers/parisc/led.c +++ b/drivers/parisc/led.c @@ -360,13 +360,13 @@ static __inline__ int led_get_net_activity(void) read_lock(&dev_base_lock); rcu_read_lock(); for_each_netdev(&init_net, dev) { - struct net_device_stats *stats; + const struct net_device_stats *stats; struct in_device *in_dev = __in_dev_get_rcu(dev); if (!in_dev || !in_dev->ifa_list) continue; if (ipv4_is_loopback(in_dev->ifa_list->ifa_local)) continue; - stats = dev->get_stats(dev); + stats = dev_get_stats(dev); rx_total += stats->rx_packets; tx_total += stats->tx_packets; } diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c index 9c2a22fed18b2b3a6d37e83278f8583d963f1bb5..4e3e0382c16e2a954c55aaa42e8ebb44bc7493b1 100644 --- a/drivers/pci/hotplug/rpadlpar_core.c +++ b/drivers/pci/hotplug/rpadlpar_core.c @@ -14,6 +14,9 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ + +#undef DEBUG + #include #include #include @@ -151,20 +154,20 @@ static void dlpar_pci_add_bus(struct device_node *dn) return; } + /* Scan below the new bridge */ if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) of_scan_pci_bridge(dn, dev); - pcibios_fixup_new_pci_devices(dev->subordinate); - - /* Claim new bus resources */ - pcibios_claim_one_bus(dev->bus); - /* Map IO space for child bus, which may or may not succeed */ pcibios_map_io_space(dev->subordinate); - /* Add new devices to global lists. Register in proc, sysfs. */ - pci_bus_add_devices(phb->bus); + /* Finish adding it : resource allocation, adding devices, etc... + * Note that we need to perform the finish pass on the -parent- + * bus of the EADS bridge so the bridge device itself gets + * properly added + */ + pcibios_finish_adding_to_bus(phb->bus); } static int dlpar_add_pci_slot(char *drc_name, struct device_node *dn) @@ -203,27 +206,6 @@ static int dlpar_add_pci_slot(char *drc_name, struct device_node *dn) return 0; } -static int dlpar_remove_root_bus(struct pci_controller *phb) -{ - struct pci_bus *phb_bus; - int rc; - - phb_bus = phb->bus; - if (!(list_empty(&phb_bus->children) && - list_empty(&phb_bus->devices))) { - return -EBUSY; - } - - rc = pcibios_remove_root_bus(phb); - if (rc) - return -EIO; - - device_unregister(phb_bus->bridge); - pci_remove_bus(phb_bus); - - return 0; -} - static int dlpar_remove_phb(char *drc_name, struct device_node *dn) { struct slot *slot; @@ -235,18 +217,15 @@ static int dlpar_remove_phb(char *drc_name, struct device_node *dn) /* If pci slot is hotplugable, use hotplug to remove it */ slot = find_php_slot(dn); - if (slot) { - if (rpaphp_deregister_slot(slot)) { - printk(KERN_ERR - "%s: unable to remove hotplug slot %s\n", - __func__, drc_name); - return -EIO; - } + if (slot && rpaphp_deregister_slot(slot)) { + printk(KERN_ERR "%s: unable to remove hotplug slot %s\n", + __func__, drc_name); + return -EIO; } pdn = dn->data; BUG_ON(!pdn || !pdn->phb); - rc = dlpar_remove_root_bus(pdn->phb); + rc = remove_phb_dynamic(pdn->phb); if (rc < 0) return rc; @@ -378,26 +357,38 @@ int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn) if (!bus) return -EINVAL; - /* If pci slot is hotplugable, use hotplug to remove it */ + pr_debug("PCI: Removing PCI slot below EADS bridge %s\n", + bus->self ? pci_name(bus->self) : ""); + slot = find_php_slot(dn); if (slot) { + pr_debug("PCI: Removing hotplug slot for %04x:%02x...\n", + pci_domain_nr(bus), bus->number); + if (rpaphp_deregister_slot(slot)) { printk(KERN_ERR "%s: unable to remove hotplug slot %s\n", __func__, drc_name); return -EIO; } - } else - pcibios_remove_pci_devices(bus); + } + + /* Remove all devices below slot */ + pcibios_remove_pci_devices(bus); + /* Unmap PCI IO space */ if (pcibios_unmap_io_space(bus)) { printk(KERN_ERR "%s: failed to unmap bus range\n", __func__); return -ERANGE; } + /* Remove the EADS bridge device itself */ BUG_ON(!bus->self); + pr_debug("PCI: Now removing bridge device %s\n", pci_name(bus->self)); + eeh_remove_bus_device(bus->self); pci_remove_bus_device(bus->self); + return 0; } diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 5f4f85f56cb7c7b592f4583f61f7a0d0657ea9d7..ce0985615133df0da3b84f71b370e0e1fb6f6988 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -606,27 +606,6 @@ static void __init quirk_ioapic_rmw(struct pci_dev *dev) sis_apic_bug = 1; } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_ANY_ID, quirk_ioapic_rmw); - -#define AMD8131_revA0 0x01 -#define AMD8131_revB0 0x11 -#define AMD8131_MISC 0x40 -#define AMD8131_NIOAMODE_BIT 0 -static void quirk_amd_8131_ioapic(struct pci_dev *dev) -{ - unsigned char tmp; - - if (nr_ioapics == 0) - return; - - if (dev->revision == AMD8131_revA0 || dev->revision == AMD8131_revB0) { - dev_info(&dev->dev, "Fixing up AMD8131 IOAPIC mode\n"); - pci_read_config_byte( dev, AMD8131_MISC, &tmp); - tmp &= ~(1 << AMD8131_NIOAMODE_BIT); - pci_write_config_byte( dev, AMD8131_MISC, tmp); - } -} -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_amd_8131_ioapic); -DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_amd_8131_ioapic); #endif /* CONFIG_X86_IO_APIC */ /* @@ -1423,6 +1402,155 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2609, quirk_intel_pcie_pm); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x260a, quirk_intel_pcie_pm); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x260b, quirk_intel_pcie_pm); +#ifdef CONFIG_X86_IO_APIC +/* + * Boot interrupts on some chipsets cannot be turned off. For these chipsets, + * remap the original interrupt in the linux kernel to the boot interrupt, so + * that a PCI device's interrupt handler is installed on the boot interrupt + * line instead. + */ +static void quirk_reroute_to_boot_interrupts_intel(struct pci_dev *dev) +{ + if (noioapicquirk || noioapicreroute) + return; + + dev->irq_reroute_variant = INTEL_IRQ_REROUTE_VARIANT; + + printk(KERN_INFO "PCI quirk: reroute interrupts for 0x%04x:0x%04x\n", + dev->vendor, dev->device); + return; +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80333_0, quirk_reroute_to_boot_interrupts_intel); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80333_1, quirk_reroute_to_boot_interrupts_intel); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_0, quirk_reroute_to_boot_interrupts_intel); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXH_0, quirk_reroute_to_boot_interrupts_intel); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXH_1, quirk_reroute_to_boot_interrupts_intel); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXHV, quirk_reroute_to_boot_interrupts_intel); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80332_0, quirk_reroute_to_boot_interrupts_intel); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80332_1, quirk_reroute_to_boot_interrupts_intel); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80333_0, quirk_reroute_to_boot_interrupts_intel); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80333_1, quirk_reroute_to_boot_interrupts_intel); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_0, quirk_reroute_to_boot_interrupts_intel); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXH_0, quirk_reroute_to_boot_interrupts_intel); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXH_1, quirk_reroute_to_boot_interrupts_intel); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXHV, quirk_reroute_to_boot_interrupts_intel); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80332_0, quirk_reroute_to_boot_interrupts_intel); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80332_1, quirk_reroute_to_boot_interrupts_intel); + +/* + * On some chipsets we can disable the generation of legacy INTx boot + * interrupts. + */ + +/* + * IO-APIC1 on 6300ESB generates boot interrupts, see intel order no + * 300641-004US, section 5.7.3. + */ +#define INTEL_6300_IOAPIC_ABAR 0x40 +#define INTEL_6300_DISABLE_BOOT_IRQ (1<<14) + +static void quirk_disable_intel_boot_interrupt(struct pci_dev *dev) +{ + u16 pci_config_word; + + if (noioapicquirk) + return; + + pci_read_config_word(dev, INTEL_6300_IOAPIC_ABAR, &pci_config_word); + pci_config_word |= INTEL_6300_DISABLE_BOOT_IRQ; + pci_write_config_word(dev, INTEL_6300_IOAPIC_ABAR, pci_config_word); + + printk(KERN_INFO "disabled boot interrupt on device 0x%04x:0x%04x\n", + dev->vendor, dev->device); +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_10, quirk_disable_intel_boot_interrupt); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_10, quirk_disable_intel_boot_interrupt); + +/* + * disable boot interrupts on HT-1000 + */ +#define BC_HT1000_FEATURE_REG 0x64 +#define BC_HT1000_PIC_REGS_ENABLE (1<<0) +#define BC_HT1000_MAP_IDX 0xC00 +#define BC_HT1000_MAP_DATA 0xC01 + +static void quirk_disable_broadcom_boot_interrupt(struct pci_dev *dev) +{ + u32 pci_config_dword; + u8 irq; + + if (noioapicquirk) + return; + + pci_read_config_dword(dev, BC_HT1000_FEATURE_REG, &pci_config_dword); + pci_write_config_dword(dev, BC_HT1000_FEATURE_REG, pci_config_dword | + BC_HT1000_PIC_REGS_ENABLE); + + for (irq = 0x10; irq < 0x10 + 32; irq++) { + outb(irq, BC_HT1000_MAP_IDX); + outb(0x00, BC_HT1000_MAP_DATA); + } + + pci_write_config_dword(dev, BC_HT1000_FEATURE_REG, pci_config_dword); + + printk(KERN_INFO "disabled boot interrupts on PCI device" + "0x%04x:0x%04x\n", dev->vendor, dev->device); +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000SB, quirk_disable_broadcom_boot_interrupt); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000SB, quirk_disable_broadcom_boot_interrupt); + +/* + * disable boot interrupts on AMD and ATI chipsets + */ +/* + * NOIOAMODE needs to be disabled to disable "boot interrupts". For AMD 8131 + * rev. A0 and B0, NOIOAMODE needs to be disabled anyway to fix IO-APIC mode + * (due to an erratum). + */ +#define AMD_813X_MISC 0x40 +#define AMD_813X_NOIOAMODE (1<<0) + +static void quirk_disable_amd_813x_boot_interrupt(struct pci_dev *dev) +{ + u32 pci_config_dword; + + if (noioapicquirk) + return; + + pci_read_config_dword(dev, AMD_813X_MISC, &pci_config_dword); + pci_config_dword &= ~AMD_813X_NOIOAMODE; + pci_write_config_dword(dev, AMD_813X_MISC, pci_config_dword); + + printk(KERN_INFO "disabled boot interrupts on PCI device " + "0x%04x:0x%04x\n", dev->vendor, dev->device); +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_disable_amd_813x_boot_interrupt); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8132_BRIDGE, quirk_disable_amd_813x_boot_interrupt); + +#define AMD_8111_PCI_IRQ_ROUTING 0x56 + +static void quirk_disable_amd_8111_boot_interrupt(struct pci_dev *dev) +{ + u16 pci_config_word; + + if (noioapicquirk) + return; + + pci_read_config_word(dev, AMD_8111_PCI_IRQ_ROUTING, &pci_config_word); + if (!pci_config_word) { + printk(KERN_INFO "boot interrupts on PCI device 0x%04x:0x%04x " + "already disabled\n", + dev->vendor, dev->device); + return; + } + pci_write_config_word(dev, AMD_8111_PCI_IRQ_ROUTING, 0); + printk(KERN_INFO "disabled boot interrupts on PCI device " + "0x%04x:0x%04x\n", dev->vendor, dev->device); +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS, quirk_disable_amd_8111_boot_interrupt); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS, quirk_disable_amd_8111_boot_interrupt); +#endif /* CONFIG_X86_IO_APIC */ + /* * Toshiba TC86C001 IDE controller reports the standard 8-byte BAR0 size * but the PIO transfers won't work if BAR0 falls at the odd 8 bytes. diff --git a/drivers/ps3/ps3av.c b/drivers/ps3/ps3av.c index 06848b254d5752d3a5d40ad2a68b8c4bb686b01e..5324978b73fba2d8aeee419d0debd31c0428ee38 100644 --- a/drivers/ps3/ps3av.c +++ b/drivers/ps3/ps3av.c @@ -59,8 +59,6 @@ static struct ps3av { struct ps3av_reply_hdr reply_hdr; u8 raw[PS3AV_BUF_SIZE]; } recv_buf; - void (*flip_ctl)(int on, void *data); - void *flip_data; } *ps3av; /* color space */ @@ -939,24 +937,6 @@ int ps3av_audio_mute(int mute) EXPORT_SYMBOL_GPL(ps3av_audio_mute); -void ps3av_register_flip_ctl(void (*flip_ctl)(int on, void *data), - void *flip_data) -{ - mutex_lock(&ps3av->mutex); - ps3av->flip_ctl = flip_ctl; - ps3av->flip_data = flip_data; - mutex_unlock(&ps3av->mutex); -} -EXPORT_SYMBOL_GPL(ps3av_register_flip_ctl); - -void ps3av_flip_ctl(int on) -{ - mutex_lock(&ps3av->mutex); - if (ps3av->flip_ctl) - ps3av->flip_ctl(on, ps3av->flip_data); - mutex_unlock(&ps3av->mutex); -} - static int ps3av_probe(struct ps3_system_bus_device *dev) { int res; diff --git a/drivers/ps3/ps3av_cmd.c b/drivers/ps3/ps3av_cmd.c index 11eb50318fec9ce093e6b9ef99e6fd858c4ead20..716596e8e5b0acdc26d92d607af85516897f932d 100644 --- a/drivers/ps3/ps3av_cmd.c +++ b/drivers/ps3/ps3av_cmd.c @@ -864,7 +864,7 @@ int ps3av_cmd_avb_param(struct ps3av_pkt_avb_param *avb, u32 send_len) { int res; - ps3av_flip_ctl(0); /* flip off */ + mutex_lock(&ps3_gpu_mutex); /* avb packet */ res = ps3av_do_pkt(PS3AV_CID_AVB_PARAM, send_len, sizeof(*avb), @@ -878,7 +878,7 @@ int ps3av_cmd_avb_param(struct ps3av_pkt_avb_param *avb, u32 send_len) res); out: - ps3av_flip_ctl(1); /* flip on */ + mutex_unlock(&ps3_gpu_mutex); return res; } diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c index 643a6b98462b67062487fec8e37e505fe9c50cd1..5c13f61bfb1b5003f67ea3142275444f776242e4 100644 --- a/drivers/rapidio/rio-scan.c +++ b/drivers/rapidio/rio-scan.c @@ -365,15 +365,15 @@ static struct rio_dev *rio_setup_device(struct rio_net *net, rdid++) rswitch->route_table[rdid] = RIO_INVALID_ROUTE; rdev->rswitch = rswitch; - sprintf(rio_name(rdev), "%02x:s:%04x", rdev->net->id, - rdev->rswitch->switchid); + dev_set_name(&rdev->dev, "%02x:s:%04x", rdev->net->id, + rdev->rswitch->switchid); rio_route_set_ops(rdev); list_add_tail(&rswitch->node, &rio_switches); } else - sprintf(rio_name(rdev), "%02x:e:%04x", rdev->net->id, - rdev->destid); + dev_set_name(&rdev->dev, "%02x:e:%04x", rdev->net->id, + rdev->destid); rdev->dev.bus = &rio_bus_type; diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c index 2cd77ab8fc66b06e43d3b908884a9f4fe8603ca1..054e05294af8566e30d3834fc23c793b615239f9 100644 --- a/drivers/rtc/rtc-isl1208.c +++ b/drivers/rtc/rtc-isl1208.c @@ -328,6 +328,13 @@ isl1208_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm) int sr; u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, }; + /* The clock has an 8 bit wide bcd-coded register (they never learn) + * for the year. tm_year is an offset from 1900 and we are interested + * in the 2000-2099 range, so any value less than 100 is invalid. + */ + if (tm->tm_year < 100) + return -EINVAL; + regs[ISL1208_REG_SC] = bin2bcd(tm->tm_sec); regs[ISL1208_REG_MN] = bin2bcd(tm->tm_min); regs[ISL1208_REG_HR] = bin2bcd(tm->tm_hour) | ISL1208_REG_HR_MIL; diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 363bd1303d217aa4904ea088549e8f0bb9f23618..570ae59c1d5eb5aa0841c1ee661134d93922ea4c 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -1898,15 +1898,19 @@ static int dasd_flush_block_queue(struct dasd_block *block) wait_event(dasd_flush_wq, (cqr->status < DASD_CQR_QUEUED)); /* Process finished ERP request. */ if (cqr->refers) { + spin_lock_bh(&block->queue_lock); __dasd_block_process_erp(block, cqr); + spin_unlock_bh(&block->queue_lock); /* restart list_for_xx loop since dasd_process_erp * might remove multiple elements */ goto restart_cb; } /* call the callback function */ + spin_lock_irq(&block->request_queue_lock); cqr->endclk = get_clock(); list_del_init(&cqr->blocklist); __dasd_cleanup_cqr(cqr); + spin_unlock_irq(&block->request_queue_lock); } return rc; } diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 921443b01d163165bcf20b50e81d9baceb785f34..2ef25731d197ed0f6a9ce2fdfdc1fc4358b9e460 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -23,6 +23,7 @@ /* This is ugly... */ #define PRINTK_HEADER "dasd_devmap:" +#define DASD_BUS_ID_SIZE 20 #include "dasd_int.h" @@ -41,7 +42,7 @@ EXPORT_SYMBOL_GPL(dasd_page_cache); */ struct dasd_devmap { struct list_head list; - char bus_id[BUS_ID_SIZE]; + char bus_id[DASD_BUS_ID_SIZE]; unsigned int devindex; unsigned short features; struct dasd_device *device; @@ -94,7 +95,7 @@ dasd_hash_busid(const char *bus_id) int hash, i; hash = 0; - for (i = 0; (i < BUS_ID_SIZE) && *bus_id; i++, bus_id++) + for (i = 0; (i < DASD_BUS_ID_SIZE) && *bus_id; i++, bus_id++) hash += *bus_id; return hash & 0xff; } @@ -301,7 +302,7 @@ dasd_parse_range( char *parsestring ) { int from, from_id0, from_id1; int to, to_id0, to_id1; int features, rc; - char bus_id[BUS_ID_SIZE+1], *str; + char bus_id[DASD_BUS_ID_SIZE+1], *str; str = parsestring; rc = dasd_busid(&str, &from_id0, &from_id1, &from); @@ -407,14 +408,14 @@ dasd_add_busid(const char *bus_id, int features) devmap = NULL; hash = dasd_hash_busid(bus_id); list_for_each_entry(tmp, &dasd_hashlists[hash], list) - if (strncmp(tmp->bus_id, bus_id, BUS_ID_SIZE) == 0) { + if (strncmp(tmp->bus_id, bus_id, DASD_BUS_ID_SIZE) == 0) { devmap = tmp; break; } if (!devmap) { /* This bus_id is new. */ new->devindex = dasd_max_devindex++; - strncpy(new->bus_id, bus_id, BUS_ID_SIZE); + strncpy(new->bus_id, bus_id, DASD_BUS_ID_SIZE); new->features = features; new->device = NULL; list_add(&new->list, &dasd_hashlists[hash]); @@ -439,7 +440,7 @@ dasd_find_busid(const char *bus_id) devmap = ERR_PTR(-ENODEV); hash = dasd_hash_busid(bus_id); list_for_each_entry(tmp, &dasd_hashlists[hash], list) { - if (strncmp(tmp->bus_id, bus_id, BUS_ID_SIZE) == 0) { + if (strncmp(tmp->bus_id, bus_id, DASD_BUS_ID_SIZE) == 0) { devmap = tmp; break; } @@ -561,7 +562,7 @@ dasd_create_device(struct ccw_device *cdev) } spin_lock_irqsave(get_ccwdev_lock(cdev), flags); - cdev->dev.driver_data = device; + dev_set_drvdata(&cdev->dev, device); spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); return device; @@ -597,7 +598,7 @@ dasd_delete_device(struct dasd_device *device) /* Disconnect dasd_device structure from ccw_device structure. */ spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); - device->cdev->dev.driver_data = NULL; + dev_set_drvdata(&device->cdev->dev, NULL); spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); /* @@ -638,7 +639,7 @@ dasd_put_device_wake(struct dasd_device *device) struct dasd_device * dasd_device_from_cdev_locked(struct ccw_device *cdev) { - struct dasd_device *device = cdev->dev.driver_data; + struct dasd_device *device = dev_get_drvdata(&cdev->dev); if (!device) return ERR_PTR(-ENODEV); diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 2e60d5f968c84d81b9dd63bafb7a670b88170c4e..bd2c52e20762e3593cb531be9b77552db0a2089a 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -1496,7 +1496,7 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device, /* service information message SIM */ - if (irb->esw.esw0.erw.cons && (irb->ecw[27] & DASD_SENSE_BIT_0) && + if (irb->esw.esw0.erw.cons && !(irb->ecw[27] & DASD_SENSE_BIT_0) && ((irb->ecw[6] & DASD_SIM_SENSE) == DASD_SIM_SENSE)) { dasd_3990_erp_handle_sim(device, irb->ecw); dasd_schedule_device_bh(device); diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c index 9088de84b45de867fd845478ac97b3b5c18bf543..bf6fd348f20e5b97849fb44f75b5210e1853871f 100644 --- a/drivers/s390/block/dasd_proc.c +++ b/drivers/s390/block/dasd_proc.c @@ -180,12 +180,12 @@ dasd_calc_metrics(char *page, char **start, off_t off, #ifdef CONFIG_DASD_PROFILE static char * -dasd_statistics_array(char *str, unsigned int *array, int shift) +dasd_statistics_array(char *str, unsigned int *array, int factor) { int i; for (i = 0; i < 32; i++) { - str += sprintf(str, "%7d ", array[i] >> shift); + str += sprintf(str, "%7d ", array[i] / factor); if (i == 15) str += sprintf(str, "\n"); } @@ -202,7 +202,7 @@ dasd_statistics_read(char *page, char **start, off_t off, #ifdef CONFIG_DASD_PROFILE struct dasd_profile_info_t *prof; char *str; - int shift; + int factor; /* check for active profiling */ if (dasd_profile_level == DASD_PROFILE_OFF) { @@ -214,12 +214,14 @@ dasd_statistics_read(char *page, char **start, off_t off, prof = &dasd_global_profile; /* prevent couter 'overflow' on output */ - for (shift = 0; (prof->dasd_io_reqs >> shift) > 9999999; shift++); + for (factor = 1; (prof->dasd_io_reqs / factor) > 9999999; + factor *= 10); str = page; str += sprintf(str, "%d dasd I/O requests\n", prof->dasd_io_reqs); - str += sprintf(str, "with %d sectors(512B each)\n", + str += sprintf(str, "with %u sectors(512B each)\n", prof->dasd_io_sects); + str += sprintf(str, "Scale Factor is %d\n", factor); str += sprintf(str, " __<4 ___8 __16 __32 __64 _128 " " _256 _512 __1k __2k __4k __8k " @@ -230,22 +232,22 @@ dasd_statistics_read(char *page, char **start, off_t off, " __1G __2G __4G " " _>4G\n"); str += sprintf(str, "Histogram of sizes (512B secs)\n"); - str = dasd_statistics_array(str, prof->dasd_io_secs, shift); + str = dasd_statistics_array(str, prof->dasd_io_secs, factor); str += sprintf(str, "Histogram of I/O times (microseconds)\n"); - str = dasd_statistics_array(str, prof->dasd_io_times, shift); + str = dasd_statistics_array(str, prof->dasd_io_times, factor); str += sprintf(str, "Histogram of I/O times per sector\n"); - str = dasd_statistics_array(str, prof->dasd_io_timps, shift); + str = dasd_statistics_array(str, prof->dasd_io_timps, factor); str += sprintf(str, "Histogram of I/O time till ssch\n"); - str = dasd_statistics_array(str, prof->dasd_io_time1, shift); + str = dasd_statistics_array(str, prof->dasd_io_time1, factor); str += sprintf(str, "Histogram of I/O time between ssch and irq\n"); - str = dasd_statistics_array(str, prof->dasd_io_time2, shift); + str = dasd_statistics_array(str, prof->dasd_io_time2, factor); str += sprintf(str, "Histogram of I/O time between ssch " "and irq per sector\n"); - str = dasd_statistics_array(str, prof->dasd_io_time2ps, shift); + str = dasd_statistics_array(str, prof->dasd_io_time2ps, factor); str += sprintf(str, "Histogram of I/O time between irq and end\n"); - str = dasd_statistics_array(str, prof->dasd_io_time3, shift); + str = dasd_statistics_array(str, prof->dasd_io_time3, factor); str += sprintf(str, "# of req in chanq at enqueuing (1..32) \n"); - str = dasd_statistics_array(str, prof->dasd_io_nr_req, shift); + str = dasd_statistics_array(str, prof->dasd_io_nr_req, factor); len = str - page; #else len = sprintf(page, "Statistics are not activated in this kernel\n"); diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 63f26a135fe5ae9764a26eda10cd5cae64aa4c49..26ffc6ab441d95ab6ed21ec79a820a34db41245a 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -4,6 +4,9 @@ * Authors: Carsten Otte, Stefan Weinhuber, Gerald Schaefer */ +#define KMSG_COMPONENT "dcssblk" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include @@ -17,19 +20,10 @@ #include #include -//#define DCSSBLK_DEBUG /* Debug messages on/off */ #define DCSSBLK_NAME "dcssblk" #define DCSSBLK_MINORS_PER_DISK 1 #define DCSSBLK_PARM_LEN 400 - -#ifdef DCSSBLK_DEBUG -#define PRINT_DEBUG(x...) printk(KERN_DEBUG DCSSBLK_NAME " debug: " x) -#else -#define PRINT_DEBUG(x...) do {} while (0) -#endif -#define PRINT_INFO(x...) printk(KERN_INFO DCSSBLK_NAME " info: " x) -#define PRINT_WARN(x...) printk(KERN_WARNING DCSSBLK_NAME " warning: " x) -#define PRINT_ERR(x...) printk(KERN_ERR DCSSBLK_NAME " error: " x) +#define DCSS_BUS_ID_SIZE 20 static int dcssblk_open(struct block_device *bdev, fmode_t mode); static int dcssblk_release(struct gendisk *disk, fmode_t mode); @@ -50,7 +44,7 @@ static struct block_device_operations dcssblk_devops = { struct dcssblk_dev_info { struct list_head lh; struct device dev; - char segment_name[BUS_ID_SIZE]; + char segment_name[DCSS_BUS_ID_SIZE]; atomic_t use_count; struct gendisk *gd; unsigned long start; @@ -65,7 +59,7 @@ struct dcssblk_dev_info { struct segment_info { struct list_head lh; - char segment_name[BUS_ID_SIZE]; + char segment_name[DCSS_BUS_ID_SIZE]; unsigned long start; unsigned long end; int segment_type; @@ -261,10 +255,9 @@ dcssblk_is_continuous(struct dcssblk_dev_info *dev_info) /* check continuity */ for (i = 0; i < dev_info->num_of_segments - 1; i++) { if ((sort_list[i].end + 1) != sort_list[i+1].start) { - PRINT_ERR("Segment %s is not contiguous with " - "segment %s\n", - sort_list[i].segment_name, - sort_list[i+1].segment_name); + pr_err("Adjacent DCSSs %s and %s are not " + "contiguous\n", sort_list[i].segment_name, + sort_list[i+1].segment_name); rc = -EINVAL; goto out; } @@ -275,10 +268,10 @@ dcssblk_is_continuous(struct dcssblk_dev_info *dev_info) !(sort_list[i+1].segment_type & SEGMENT_EXCLUSIVE) || (sort_list[i+1].segment_type == SEG_TYPE_ER)) { - PRINT_ERR("Segment %s has different type from " - "segment %s\n", - sort_list[i].segment_name, - sort_list[i+1].segment_name); + pr_err("DCSS %s and DCSS %s have " + "incompatible types\n", + sort_list[i].segment_name, + sort_list[i+1].segment_name); rc = -EINVAL; goto out; } @@ -380,8 +373,9 @@ dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const ch } else if (inbuf[0] == '0') { /* reload segments in exclusive mode */ if (dev_info->segment_type == SEG_TYPE_SC) { - PRINT_ERR("Segment type SC (%s) cannot be loaded in " - "non-shared mode\n", dev_info->segment_name); + pr_err("DCSS %s is of type SC and cannot be " + "loaded as exclusive-writable\n", + dev_info->segment_name); rc = -EINVAL; goto out; } @@ -404,9 +398,8 @@ dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const ch goto out; removeseg: - PRINT_ERR("Could not reload segment(s) of the device %s, removing " - "segment(s) now!\n", - dev_info->segment_name); + pr_err("DCSS device %s is removed after a failed access mode " + "change\n", dev_info->segment_name); temp = entry; list_for_each_entry(entry, &dev_info->seg_list, lh) { if (entry != temp) @@ -454,17 +447,17 @@ dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char if (inbuf[0] == '1') { if (atomic_read(&dev_info->use_count) == 0) { // device is idle => we save immediately - PRINT_INFO("Saving segment(s) of the device %s\n", - dev_info->segment_name); + pr_info("All DCSSs that map to device %s are " + "saved\n", dev_info->segment_name); list_for_each_entry(entry, &dev_info->seg_list, lh) { segment_save(entry->segment_name); } } else { // device is busy => we save it when it becomes // idle in dcssblk_release - PRINT_INFO("Device %s is currently busy, segment(s) " - "will be saved when it becomes idle...\n", - dev_info->segment_name); + pr_info("Device %s is in use, its DCSSs will be " + "saved when it becomes idle\n", + dev_info->segment_name); dev_info->save_pending = 1; } } else if (inbuf[0] == '0') { @@ -472,9 +465,9 @@ dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char // device is busy & the user wants to undo his save // request dev_info->save_pending = 0; - PRINT_INFO("Pending save for segment(s) of the device " - "%s deactivated\n", - dev_info->segment_name); + pr_info("A pending save request for device %s " + "has been canceled\n", + dev_info->segment_name); } } else { up_write(&dcssblk_devices_sem); @@ -614,9 +607,8 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char seg_byte_size = (dev_info->end - dev_info->start + 1); set_capacity(dev_info->gd, seg_byte_size >> 9); // size in sectors - PRINT_INFO("Loaded segment(s) %s, size = %lu Byte, " - "capacity = %lu (512 Byte) sectors\n", local_buf, - seg_byte_size, seg_byte_size >> 9); + pr_info("Loaded %s with total size %lu bytes and capacity %lu " + "sectors\n", local_buf, seg_byte_size, seg_byte_size >> 9); dev_info->save_pending = 0; dev_info->is_shared = 1; @@ -744,13 +736,15 @@ dcssblk_remove_store(struct device *dev, struct device_attribute *attr, const ch dev_info = dcssblk_get_device_by_name(local_buf); if (dev_info == NULL) { up_write(&dcssblk_devices_sem); - PRINT_WARN("Device %s is not loaded!\n", local_buf); + pr_warning("Device %s cannot be removed because it is not a " + "known device\n", local_buf); rc = -ENODEV; goto out_buf; } if (atomic_read(&dev_info->use_count) != 0) { up_write(&dcssblk_devices_sem); - PRINT_WARN("Device %s is in use!\n", local_buf); + pr_warning("Device %s cannot be removed while it is in " + "use\n", local_buf); rc = -EBUSY; goto out_buf; } @@ -807,8 +801,8 @@ dcssblk_release(struct gendisk *disk, fmode_t mode) down_write(&dcssblk_devices_sem); if (atomic_dec_and_test(&dev_info->use_count) && (dev_info->save_pending)) { - PRINT_INFO("Device %s became idle and is being saved now\n", - dev_info->segment_name); + pr_info("Device %s has become idle and is being saved " + "now\n", dev_info->segment_name); list_for_each_entry(entry, &dev_info->seg_list, lh) { segment_save(entry->segment_name); } @@ -851,7 +845,8 @@ dcssblk_make_request(struct request_queue *q, struct bio *bio) case SEG_TYPE_SC: /* cannot write to these segments */ if (bio_data_dir(bio) == WRITE) { - PRINT_WARN("rejecting write to ro device %s\n", + pr_warning("Writing to %s failed because it " + "is a read-only device\n", dev_name(&dev_info->dev)); goto fail; } diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index 03916989ed2d63ec7a45966353c8350e260640ad..76814f3e898a9c444dca70b4ddfc0cd7d885847c 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -25,6 +25,9 @@ * generic hard disk support to replace ad-hoc partitioning */ +#define KMSG_COMPONENT "xpram" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include /* isdigit, isxdigit */ @@ -42,12 +45,6 @@ #define XPRAM_DEVS 1 /* one partition */ #define XPRAM_MAX_DEVS 32 /* maximal number of devices (partitions) */ -#define PRINT_DEBUG(x...) printk(KERN_DEBUG XPRAM_NAME " debug:" x) -#define PRINT_INFO(x...) printk(KERN_INFO XPRAM_NAME " info:" x) -#define PRINT_WARN(x...) printk(KERN_WARNING XPRAM_NAME " warning:" x) -#define PRINT_ERR(x...) printk(KERN_ERR XPRAM_NAME " error:" x) - - typedef struct { unsigned int size; /* size of xpram segment in pages */ unsigned int offset; /* start page of xpram segment */ @@ -264,7 +261,7 @@ static int __init xpram_setup_sizes(unsigned long pages) /* Check number of devices. */ if (devs <= 0 || devs > XPRAM_MAX_DEVS) { - PRINT_ERR("invalid number %d of devices\n",devs); + pr_err("%d is not a valid number of XPRAM devices\n",devs); return -EINVAL; } xpram_devs = devs; @@ -295,22 +292,22 @@ static int __init xpram_setup_sizes(unsigned long pages) mem_auto_no++; } - PRINT_INFO(" number of devices (partitions): %d \n", xpram_devs); + pr_info(" number of devices (partitions): %d \n", xpram_devs); for (i = 0; i < xpram_devs; i++) { if (xpram_sizes[i]) - PRINT_INFO(" size of partition %d: %u kB\n", - i, xpram_sizes[i]); + pr_info(" size of partition %d: %u kB\n", + i, xpram_sizes[i]); else - PRINT_INFO(" size of partition %d to be set " - "automatically\n",i); + pr_info(" size of partition %d to be set " + "automatically\n",i); } - PRINT_DEBUG(" memory needed (for sized partitions): %lu kB\n", - mem_needed); - PRINT_DEBUG(" partitions to be sized automatically: %d\n", - mem_auto_no); + pr_info(" memory needed (for sized partitions): %lu kB\n", + mem_needed); + pr_info(" partitions to be sized automatically: %d\n", + mem_auto_no); if (mem_needed > pages * 4) { - PRINT_ERR("Not enough expanded memory available\n"); + pr_err("Not enough expanded memory available\n"); return -EINVAL; } @@ -322,8 +319,8 @@ static int __init xpram_setup_sizes(unsigned long pages) */ if (mem_auto_no) { mem_auto = ((pages - mem_needed / 4) / mem_auto_no) * 4; - PRINT_INFO(" automatically determined " - "partition size: %lu kB\n", mem_auto); + pr_info(" automatically determined " + "partition size: %lu kB\n", mem_auto); for (i = 0; i < xpram_devs; i++) if (xpram_sizes[i] == 0) xpram_sizes[i] = mem_auto; @@ -405,12 +402,12 @@ static int __init xpram_init(void) /* Find out size of expanded memory. */ if (xpram_present() != 0) { - PRINT_WARN("No expanded memory available\n"); + pr_err("No expanded memory available\n"); return -ENODEV; } xpram_pages = xpram_highest_page_index() + 1; - PRINT_INFO(" %u pages expanded memory found (%lu KB).\n", - xpram_pages, (unsigned long) xpram_pages*4); + pr_info(" %u pages expanded memory found (%lu KB).\n", + xpram_pages, (unsigned long) xpram_pages*4); rc = xpram_setup_sizes(xpram_pages); if (rc) return rc; diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c index 35fd8dfcaaa6d22d2083304ccdd9ebb4137d3af7..97e63cf469443ab594e231a288b856c0cc5d9562 100644 --- a/drivers/s390/char/monreader.c +++ b/drivers/s390/char/monreader.c @@ -7,6 +7,9 @@ * Author: Gerald Schaefer */ +#define KMSG_COMPONENT "monreader" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include @@ -24,19 +27,6 @@ #include #include -//#define MON_DEBUG /* Debug messages on/off */ - -#define MON_NAME "monreader" - -#define P_INFO(x...) printk(KERN_INFO MON_NAME " info: " x) -#define P_ERROR(x...) printk(KERN_ERR MON_NAME " error: " x) -#define P_WARNING(x...) printk(KERN_WARNING MON_NAME " warning: " x) - -#ifdef MON_DEBUG -#define P_DEBUG(x...) printk(KERN_DEBUG MON_NAME " debug: " x) -#else -#define P_DEBUG(x...) do {} while (0) -#endif #define MON_COLLECT_SAMPLE 0x80 #define MON_COLLECT_EVENT 0x40 @@ -172,7 +162,7 @@ static int mon_send_reply(struct mon_msg *monmsg, } else monmsg->replied_msglim = 1; if (rc) { - P_ERROR("read, IUCV reply failed with rc = %i\n\n", rc); + pr_err("Reading monitor data failed with rc=%i\n", rc); return -EIO; } return 0; @@ -251,7 +241,8 @@ static void mon_iucv_path_severed(struct iucv_path *path, u8 ipuser[16]) { struct mon_private *monpriv = path->private; - P_ERROR("IUCV connection severed with rc = 0x%X\n", ipuser[0]); + pr_err("z/VM *MONITOR system service disconnected with rc=%i\n", + ipuser[0]); iucv_path_sever(path, NULL); atomic_set(&monpriv->iucv_severed, 1); wake_up(&mon_conn_wait_queue); @@ -266,8 +257,7 @@ static void mon_iucv_message_pending(struct iucv_path *path, memcpy(&monpriv->msg_array[monpriv->write_index]->msg, msg, sizeof(*msg)); if (atomic_inc_return(&monpriv->msglim_count) == MON_MSGLIM) { - P_WARNING("IUCV message pending, message limit (%i) reached\n", - MON_MSGLIM); + pr_warning("The read queue for monitor data is full\n"); monpriv->msg_array[monpriv->write_index]->msglim_reached = 1; } monpriv->write_index = (monpriv->write_index + 1) % MON_MSGLIM; @@ -311,8 +301,8 @@ static int mon_open(struct inode *inode, struct file *filp) rc = iucv_path_connect(monpriv->path, &monreader_iucv_handler, MON_SERVICE, NULL, user_data_connect, monpriv); if (rc) { - P_ERROR("iucv connection to *MONITOR failed with " - "IPUSER SEVER code = %i\n", rc); + pr_err("Connecting to the z/VM *MONITOR system service " + "failed with rc=%i\n", rc); rc = -EIO; goto out_path; } @@ -353,7 +343,8 @@ static int mon_close(struct inode *inode, struct file *filp) */ rc = iucv_path_sever(monpriv->path, user_data_sever); if (rc) - P_ERROR("close, iucv_sever failed with rc = %i\n", rc); + pr_warning("Disconnecting the z/VM *MONITOR system service " + "failed with rc=%i\n", rc); atomic_set(&monpriv->iucv_severed, 0); atomic_set(&monpriv->iucv_connected, 0); @@ -469,7 +460,8 @@ static int __init mon_init(void) int rc; if (!MACHINE_IS_VM) { - P_ERROR("not running under z/VM, driver not loaded\n"); + pr_err("The z/VM *MONITOR record device driver cannot be " + "loaded without z/VM\n"); return -ENODEV; } @@ -478,7 +470,8 @@ static int __init mon_init(void) */ rc = iucv_register(&monreader_iucv_handler, 1); if (rc) { - P_ERROR("failed to register with iucv driver\n"); + pr_err("The z/VM *MONITOR record device driver failed to " + "register with IUCV\n"); return rc; } @@ -488,8 +481,8 @@ static int __init mon_init(void) goto out_iucv; } if (rc != SEG_TYPE_SC) { - P_ERROR("segment %s has unsupported type, should be SC\n", - mon_dcss_name); + pr_err("The specified *MONITOR DCSS %s does not have the " + "required type SC\n", mon_dcss_name); rc = -EINVAL; goto out_iucv; } diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c index 4d71aa8c1a7956928e1354cd82f56a70d145c1e2..c7d7483bab9ae010fef8e225d3138242aa9a00c7 100644 --- a/drivers/s390/char/monwriter.c +++ b/drivers/s390/char/monwriter.c @@ -8,6 +8,9 @@ * Author(s): Melissa Howland */ +#define KMSG_COMPONENT "monwriter" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include @@ -64,9 +67,9 @@ static int monwrite_diag(struct monwrite_hdr *myhdr, char *buffer, int fcn) rc = appldata_asm(&id, fcn, (void *) buffer, myhdr->datalen); if (rc <= 0) return rc; + pr_err("Writing monitor data failed with rc=%i\n", rc); if (rc == 5) return -EPERM; - printk("DIAG X'DC' error with return code: %i\n", rc); return -EINVAL; } diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c index ec9c0bcf66eeefd8ee9029675cc193d0af328b0f..506390496416ea1163d12919042a6f0d0d34df34 100644 --- a/drivers/s390/char/sclp_cmd.c +++ b/drivers/s390/char/sclp_cmd.c @@ -6,6 +6,9 @@ * Peter Oberparleiter */ +#define KMSG_COMPONENT "sclp_cmd" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include @@ -16,9 +19,8 @@ #include #include #include -#include "sclp.h" -#define TAG "sclp_cmd: " +#include "sclp.h" #define SCLP_CMDW_READ_SCP_INFO 0x00020001 #define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001 @@ -169,8 +171,8 @@ static int do_sync_request(sclp_cmdw_t cmd, void *sccb) /* Check response. */ if (request->status != SCLP_REQ_DONE) { - printk(KERN_WARNING TAG "sync request failed " - "(cmd=0x%08x, status=0x%02x)\n", cmd, request->status); + pr_warning("sync request failed (cmd=0x%08x, " + "status=0x%02x)\n", cmd, request->status); rc = -EIO; } out: @@ -224,8 +226,8 @@ int sclp_get_cpu_info(struct sclp_cpu_info *info) if (rc) goto out; if (sccb->header.response_code != 0x0010) { - printk(KERN_WARNING TAG "readcpuinfo failed " - "(response=0x%04x)\n", sccb->header.response_code); + pr_warning("readcpuinfo failed (response=0x%04x)\n", + sccb->header.response_code); rc = -EIO; goto out; } @@ -262,8 +264,9 @@ static int do_cpu_configure(sclp_cmdw_t cmd) case 0x0120: break; default: - printk(KERN_WARNING TAG "configure cpu failed (cmd=0x%08x, " - "response=0x%04x)\n", cmd, sccb->header.response_code); + pr_warning("configure cpu failed (cmd=0x%08x, " + "response=0x%04x)\n", cmd, + sccb->header.response_code); rc = -EIO; break; } @@ -626,9 +629,9 @@ static int do_chp_configure(sclp_cmdw_t cmd) case 0x0450: break; default: - printk(KERN_WARNING TAG "configure channel-path failed " - "(cmd=0x%08x, response=0x%04x)\n", cmd, - sccb->header.response_code); + pr_warning("configure channel-path failed " + "(cmd=0x%08x, response=0x%04x)\n", cmd, + sccb->header.response_code); rc = -EIO; break; } @@ -695,8 +698,8 @@ int sclp_chp_read_info(struct sclp_chp_info *info) if (rc) goto out; if (sccb->header.response_code != 0x0010) { - printk(KERN_WARNING TAG "read channel-path info failed " - "(response=0x%04x)\n", sccb->header.response_code); + pr_warning("read channel-path info failed " + "(response=0x%04x)\n", sccb->header.response_code); rc = -EIO; goto out; } diff --git a/drivers/s390/char/sclp_config.c b/drivers/s390/char/sclp_config.c index 4cebd6ee6d27e79b33bf037e74754743a947f9fd..b497afe061cc4f0731fd625ca317386d5af0c85f 100644 --- a/drivers/s390/char/sclp_config.c +++ b/drivers/s390/char/sclp_config.c @@ -5,15 +5,17 @@ * Author(s): Heiko Carstens */ +#define KMSG_COMPONENT "sclp_config" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include #include #include #include -#include "sclp.h" -#define TAG "sclp_config: " +#include "sclp.h" struct conf_mgm_data { u8 reserved; @@ -31,7 +33,7 @@ static void sclp_cpu_capability_notify(struct work_struct *work) int cpu; struct sys_device *sysdev; - printk(KERN_WARNING TAG "cpu capability changed.\n"); + pr_warning("cpu capability changed.\n"); get_online_cpus(); for_each_online_cpu(cpu) { sysdev = get_cpu_sysdev(cpu); @@ -78,7 +80,7 @@ static int __init sclp_conf_init(void) return rc; if (!(sclp_conf_register.sclp_send_mask & EVTYP_CONFMGMDATA_MASK)) { - printk(KERN_WARNING TAG "no configuration management.\n"); + pr_warning("no configuration management.\n"); sclp_unregister(&sclp_conf_register); rc = -ENOSYS; } diff --git a/drivers/s390/char/sclp_cpi_sys.c b/drivers/s390/char/sclp_cpi_sys.c index d887bd261d28e2029847213d1f6e017ed41dd06f..62c2647f37f4b60300911326f039d78615de38ed 100644 --- a/drivers/s390/char/sclp_cpi_sys.c +++ b/drivers/s390/char/sclp_cpi_sys.c @@ -7,6 +7,9 @@ * Michael Ernst */ +#define KMSG_COMPONENT "sclp_cpi" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include @@ -20,6 +23,7 @@ #include #include #include + #include "sclp.h" #include "sclp_rw.h" #include "sclp_cpi_sys.h" @@ -150,16 +154,16 @@ static int cpi_req(void) wait_for_completion(&completion); if (req->status != SCLP_REQ_DONE) { - printk(KERN_WARNING "cpi: request failed (status=0x%02x)\n", - req->status); + pr_warning("request failed (status=0x%02x)\n", + req->status); rc = -EIO; goto out_free_req; } response = ((struct cpi_sccb *) req->sccb)->header.response_code; if (response != 0x0020) { - printk(KERN_WARNING "cpi: failed with " - "response code 0x%x\n", response); + pr_warning("request failed with response code 0x%x\n", + response); rc = -EIO; } diff --git a/drivers/s390/char/sclp_sdias.c b/drivers/s390/char/sclp_sdias.c index 8b854857ba0733eb5a8a56a9451318a8d383603c..6a1c58dc61a78e920c4e626ab61b04f1747c3418 100644 --- a/drivers/s390/char/sclp_sdias.c +++ b/drivers/s390/char/sclp_sdias.c @@ -5,15 +5,18 @@ * Author(s): Michael Holzheu */ +#define KMSG_COMPONENT "sclp_sdias" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include #include + #include "sclp.h" #include "sclp_rw.h" #define TRACE(x...) debug_sprintf_event(sdias_dbf, 1, x) -#define ERROR_MSG(x...) printk ( KERN_ALERT "SDIAS: " x ) #define SDIAS_RETRIES 300 #define SDIAS_SLEEP_TICKS 50 @@ -131,7 +134,7 @@ int sclp_sdias_blk_count(void) rc = sdias_sclp_send(&request); if (rc) { - ERROR_MSG("sclp_send failed for get_nr_blocks\n"); + pr_err("sclp_send failed for get_nr_blocks\n"); goto out; } if (sccb.hdr.response_code != 0x0020) { @@ -145,7 +148,8 @@ int sclp_sdias_blk_count(void) rc = sccb.evbuf.blk_cnt; break; default: - ERROR_MSG("SCLP error: %x\n", sccb.evbuf.event_status); + pr_err("SCLP error: %x\n", + sccb.evbuf.event_status); rc = -EIO; goto out; } @@ -201,7 +205,7 @@ int sclp_sdias_copy(void *dest, int start_blk, int nr_blks) rc = sdias_sclp_send(&request); if (rc) { - ERROR_MSG("sclp_send failed: %x\n", rc); + pr_err("sclp_send failed: %x\n", rc); goto out; } if (sccb.hdr.response_code != 0x0020) { @@ -219,9 +223,9 @@ int sclp_sdias_copy(void *dest, int start_blk, int nr_blks) case EVSTATE_NO_DATA: TRACE("no data\n"); default: - ERROR_MSG("Error from SCLP while copying hsa. " - "Event status = %x\n", - sccb.evbuf.event_status); + pr_err("Error from SCLP while copying hsa. " + "Event status = %x\n", + sccb.evbuf.event_status); rc = -EIO; } out: diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index 9854f19f5e624532a754d7b7654c286d9601f75e..a839aa531d7c0f011cbe6e135ce3bac897333d7e 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c @@ -583,23 +583,6 @@ sclp_vt220_chars_in_buffer(struct tty_struct *tty) return count; } -static void -__sclp_vt220_flush_buffer(void) -{ - unsigned long flags; - - sclp_vt220_emit_current(); - spin_lock_irqsave(&sclp_vt220_lock, flags); - if (timer_pending(&sclp_vt220_timer)) - del_timer(&sclp_vt220_timer); - while (sclp_vt220_outqueue_count > 0) { - spin_unlock_irqrestore(&sclp_vt220_lock, flags); - sclp_sync_wait(); - spin_lock_irqsave(&sclp_vt220_lock, flags); - } - spin_unlock_irqrestore(&sclp_vt220_lock, flags); -} - /* * Pass on all buffers to the hardware. Return only when there are no more * buffers pending. @@ -745,6 +728,22 @@ sclp_vt220_con_device(struct console *c, int *index) return sclp_vt220_driver; } +static void __sclp_vt220_flush_buffer(void) +{ + unsigned long flags; + + sclp_vt220_emit_current(); + spin_lock_irqsave(&sclp_vt220_lock, flags); + if (timer_pending(&sclp_vt220_timer)) + del_timer(&sclp_vt220_timer); + while (sclp_vt220_outqueue_count > 0) { + spin_unlock_irqrestore(&sclp_vt220_lock, flags); + sclp_sync_wait(); + spin_lock_irqsave(&sclp_vt220_lock, flags); + } + spin_unlock_irqrestore(&sclp_vt220_lock, flags); +} + static int sclp_vt220_notify(struct notifier_block *self, unsigned long event, void *data) diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c index 09e7d9bf438b0e18b1dc5d49acd9f540000dfb06..a6087cec55b463fc0237e1fe1774d010a69d038e 100644 --- a/drivers/s390/char/vmcp.c +++ b/drivers/s390/char/vmcp.c @@ -11,12 +11,14 @@ * The idea of this driver is based on cpint from Neale Ferguson and #CP in CMS */ +#define KMSG_COMPONENT "vmcp" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include #include #include -#include #include #include #include @@ -26,8 +28,6 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Christian Borntraeger "); MODULE_DESCRIPTION("z/VM CP interface"); -#define PRINTK_HEADER "vmcp: " - static debug_info_t *vmcp_debug; static int vmcp_open(struct inode *inode, struct file *file) @@ -41,13 +41,11 @@ static int vmcp_open(struct inode *inode, struct file *file) if (!session) return -ENOMEM; - lock_kernel(); session->bufsize = PAGE_SIZE; session->response = NULL; session->resp_size = 0; mutex_init(&session->mutex); file->private_data = session; - unlock_kernel(); return nonseekable_open(inode, file); } @@ -193,7 +191,8 @@ static int __init vmcp_init(void) int ret; if (!MACHINE_IS_VM) { - PRINT_WARN("z/VM CP interface is only available under z/VM\n"); + pr_warning("The z/VM CP interface device driver cannot be " + "loaded without z/VM\n"); return -ENODEV; } diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index 24762727bc27ff80243951dd47a984128af3ed61..aabbeb909cc6d4f2f18ba6b960073ee59b921145 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c @@ -10,6 +10,10 @@ * Stefan Weinhuber * */ + +#define KMSG_COMPONENT "vmlogrdr" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include @@ -28,8 +32,6 @@ #include #include - - MODULE_AUTHOR ("(C) 2004 IBM Corporation by Xenia Tkatschow (xenia@us.ibm.com)\n" " Stefan Weinhuber (wein@de.ibm.com)"); @@ -174,8 +176,7 @@ static void vmlogrdr_iucv_path_severed(struct iucv_path *path, u8 ipuser[16]) struct vmlogrdr_priv_t * logptr = path->private; u8 reason = (u8) ipuser[8]; - printk (KERN_ERR "vmlogrdr: connection severed with" - " reason %i\n", reason); + pr_err("vmlogrdr: connection severed with reason %i\n", reason); iucv_path_sever(path, NULL); kfree(path); @@ -333,8 +334,8 @@ static int vmlogrdr_open (struct inode *inode, struct file *filp) if (logptr->autorecording) { ret = vmlogrdr_recording(logptr,1,logptr->autopurge); if (ret) - printk (KERN_WARNING "vmlogrdr: failed to start " - "recording automatically\n"); + pr_warning("vmlogrdr: failed to start " + "recording automatically\n"); } /* create connection to the system service */ @@ -345,9 +346,9 @@ static int vmlogrdr_open (struct inode *inode, struct file *filp) logptr->system_service, NULL, NULL, logptr); if (connect_rc) { - printk (KERN_ERR "vmlogrdr: iucv connection to %s " - "failed with rc %i \n", logptr->system_service, - connect_rc); + pr_err("vmlogrdr: iucv connection to %s " + "failed with rc %i \n", + logptr->system_service, connect_rc); goto out_path; } @@ -388,8 +389,8 @@ static int vmlogrdr_release (struct inode *inode, struct file *filp) if (logptr->autorecording) { ret = vmlogrdr_recording(logptr,0,logptr->autopurge); if (ret) - printk (KERN_WARNING "vmlogrdr: failed to stop " - "recording automatically\n"); + pr_warning("vmlogrdr: failed to stop " + "recording automatically\n"); } logptr->dev_in_use = 0; @@ -823,8 +824,7 @@ static int __init vmlogrdr_init(void) dev_t dev; if (! MACHINE_IS_VM) { - printk (KERN_ERR "vmlogrdr: not running under VM, " - "driver not loaded.\n"); + pr_err("not running under VM, driver not loaded.\n"); return -ENODEV; } diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c index 9020eba620eee22fe8ae36bd0716596c38ae9a7f..5dcef81fc9d927a0bf5672a0f979e564dac32953 100644 --- a/drivers/s390/char/vmur.c +++ b/drivers/s390/char/vmur.c @@ -8,6 +8,9 @@ * Frank Munzert */ +#define KMSG_COMPONENT "vmur" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include @@ -40,8 +43,6 @@ MODULE_AUTHOR("IBM Corporation"); MODULE_DESCRIPTION("s390 z/VM virtual unit record device driver"); MODULE_LICENSE("GPL"); -#define PRINTK_HEADER "vmur: " - static dev_t ur_first_dev_maj_min; static struct class *vmur_class; static struct debug_info *vmur_dbf; @@ -987,7 +988,8 @@ static int __init ur_init(void) dev_t dev; if (!MACHINE_IS_VM) { - PRINT_ERR("%s is only available under z/VM.\n", ur_banner); + pr_err("The %s cannot be loaded without z/VM\n", + ur_banner); return -ENODEV; } @@ -1006,7 +1008,8 @@ static int __init ur_init(void) rc = alloc_chrdev_region(&dev, 0, NUM_MINORS, "vmur"); if (rc) { - PRINT_ERR("alloc_chrdev_region failed: err = %d\n", rc); + pr_err("Kernel function alloc_chrdev_region failed with " + "error code %d\n", rc); goto fail_unregister_driver; } ur_first_dev_maj_min = MKDEV(MAJOR(dev), 0); @@ -1016,7 +1019,7 @@ static int __init ur_init(void) rc = PTR_ERR(vmur_class); goto fail_unregister_region; } - PRINT_INFO("%s loaded.\n", ur_banner); + pr_info("%s loaded.\n", ur_banner); return 0; fail_unregister_region: @@ -1034,7 +1037,7 @@ static void __exit ur_exit(void) unregister_chrdev_region(ur_first_dev_maj_min, NUM_MINORS); ccw_driver_unregister(&ur_driver); debug_unregister(vmur_dbf); - PRINT_INFO("%s unloaded.\n", ur_banner); + pr_info("%s unloaded.\n", ur_banner); } module_init(ur_init); diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index 7fd84be1193132f53163a272eba02c3791775116..eefc6611412e120fd3b5ad896ca3c0a426f9d4b0 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c @@ -9,6 +9,9 @@ * Author(s): Michael Holzheu */ +#define KMSG_COMPONENT "zdump" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include @@ -24,8 +27,6 @@ #include "sclp.h" #define TRACE(x...) debug_sprintf_event(zcore_dbf, 1, x) -#define MSG(x...) printk( KERN_ALERT x ) -#define ERROR_MSG(x...) printk ( KERN_ALERT "DUMP: " x ) #define TO_USER 0 #define TO_KERNEL 1 @@ -563,19 +564,19 @@ static int __init sys_info_init(enum arch_id arch) switch (arch) { case ARCH_S390X: - MSG("DETECTED 'S390X (64 bit) OS'\n"); + pr_alert("DETECTED 'S390X (64 bit) OS'\n"); sys_info.sa_base = SAVE_AREA_BASE_S390X; sys_info.sa_size = sizeof(struct save_area_s390x); set_s390x_lc_mask(&sys_info.lc_mask); break; case ARCH_S390: - MSG("DETECTED 'S390 (32 bit) OS'\n"); + pr_alert("DETECTED 'S390 (32 bit) OS'\n"); sys_info.sa_base = SAVE_AREA_BASE_S390; sys_info.sa_size = sizeof(struct save_area_s390); set_s390_lc_mask(&sys_info.lc_mask); break; default: - ERROR_MSG("unknown architecture 0x%x.\n",arch); + pr_alert("0x%x is an unknown architecture.\n",arch); return -EINVAL; } sys_info.arch = arch; @@ -674,7 +675,8 @@ static int __init zcore_init(void) #ifndef __s390x__ if (arch == ARCH_S390X) { - ERROR_MSG("32 bit dumper can't dump 64 bit system!\n"); + pr_alert("The 32-bit dump tool cannot be used for a " + "64-bit system\n"); rc = -EINVAL; goto fail; } diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c index 2f547b840ef011f70fef2e559bd571d5b66d616e..fe00be3675cd6757c7a84d6aec6f58e99947485c 100644 --- a/drivers/s390/cio/blacklist.c +++ b/drivers/s390/cio/blacklist.c @@ -9,6 +9,9 @@ * Arnd Bergmann (arndb@de.ibm.com) */ +#define KMSG_COMPONENT "cio" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include @@ -50,9 +53,10 @@ static int blacklist_range(range_action action, unsigned int from_ssid, { if ((from_ssid > to_ssid) || ((from_ssid == to_ssid) && (from > to))) { if (msgtrigger) - printk(KERN_WARNING "cio: Invalid cio_ignore range " - "0.%x.%04x-0.%x.%04x\n", from_ssid, from, - to_ssid, to); + pr_warning("0.%x.%04x to 0.%x.%04x is not a valid " + "range for cio_ignore\n", from_ssid, from, + to_ssid, to); + return 1; } @@ -140,8 +144,8 @@ static int parse_busid(char *str, unsigned int *cssid, unsigned int *ssid, rc = 0; out: if (rc && msgtrigger) - printk(KERN_WARNING "cio: Invalid cio_ignore device '%s'\n", - str); + pr_warning("%s is not a valid device for the cio_ignore " + "kernel parameter\n", str); return rc; } diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 3ac2c2019f5e28ffae89e7c0d07f965be297f500..918e6fce2573fcd9fe18e61a41c6d26fd3872c56 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -19,6 +19,8 @@ #include #include +#define CCW_BUS_ID_SIZE 20 + /* In Linux 2.4, we had a channel device layer called "chandev" * that did all sorts of obscure stuff for networking devices. * This is another driver that serves as a replacement for just @@ -89,15 +91,23 @@ ccwgroup_ungroup_store(struct device *dev, struct device_attribute *attr, const gdev = to_ccwgroupdev(dev); - if (gdev->state != CCWGROUP_OFFLINE) - return -EINVAL; - + /* Prevent concurrent online/offline processing and ungrouping. */ + if (atomic_cmpxchg(&gdev->onoff, 0, 1) != 0) + return -EAGAIN; + if (gdev->state != CCWGROUP_OFFLINE) { + rc = -EINVAL; + goto out; + } /* Note that we cannot unregister the device from one of its * attribute methods, so we have to use this roundabout approach. */ rc = device_schedule_callback(dev, ccwgroup_ungroup_callback); - if (rc) - count = rc; +out: + if (rc) { + /* Release onoff "lock" when ungrouping failed. */ + atomic_set(&gdev->onoff, 0); + return rc; + } return count; } @@ -172,7 +182,7 @@ static int __get_next_bus_id(const char **buf, char *bus_id) len = end - start + 1; end++; } - if (len < BUS_ID_SIZE) { + if (len < CCW_BUS_ID_SIZE) { strlcpy(bus_id, start, len); rc = 0; } else @@ -181,7 +191,7 @@ static int __get_next_bus_id(const char **buf, char *bus_id) return rc; } -static int __is_valid_bus_id(char bus_id[BUS_ID_SIZE]) +static int __is_valid_bus_id(char bus_id[CCW_BUS_ID_SIZE]) { int cssid, ssid, devno; @@ -213,7 +223,7 @@ int ccwgroup_create_from_string(struct device *root, unsigned int creator_id, { struct ccwgroup_device *gdev; int rc, i; - char tmp_bus_id[BUS_ID_SIZE]; + char tmp_bus_id[CCW_BUS_ID_SIZE]; const char *curr_buf; gdev = kzalloc(sizeof(*gdev) + num_devices * sizeof(gdev->cdev[0]), diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 29826fdd47b84e658916241c3897386582d04ac9..ebab6ea4659b783ed37e8b87d1332c8fed864517 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -8,6 +8,9 @@ * Arnd Bergmann (arndb@de.ibm.com) */ +#define KMSG_COMPONENT "cio" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include @@ -333,6 +336,7 @@ static void chsc_process_sei_chp_config(struct chsc_sei_area *sei_area) struct chp_config_data *data; struct chp_id chpid; int num; + char *events[3] = {"configure", "deconfigure", "cancel deconfigure"}; CIO_CRW_EVENT(4, "chsc: channel-path-configuration notification\n"); if (sei_area->rs != 0) @@ -343,8 +347,8 @@ static void chsc_process_sei_chp_config(struct chsc_sei_area *sei_area) if (!chp_test_bit(data->map, num)) continue; chpid.id = num; - printk(KERN_WARNING "cio: processing configure event %d for " - "chpid %x.%02x\n", data->op, chpid.cssid, chpid.id); + pr_notice("Processing %s for channel path %x.%02x\n", + events[data->op], chpid.cssid, chpid.id); switch (data->op) { case 0: chp_cfg_schedule(chpid, 1); diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c index f49f0e502b8dfb7f144801db8aa57d975a2dc7b7..0a2f2edafc03ea17bd54dcb7ef758002c021146c 100644 --- a/drivers/s390/cio/chsc_sch.c +++ b/drivers/s390/cio/chsc_sch.c @@ -61,7 +61,7 @@ static void chsc_subchannel_irq(struct subchannel *sch) } private->request = NULL; memcpy(&request->irb, irb, sizeof(*irb)); - stsch(sch->schid, &sch->schib); + cio_update_schib(sch); complete(&request->completion); put_device(&sch->dev); } diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 3db2c386546f13733f122b6e0d6ef7410416548c..8a8df7552969d15ad0d2532b4cf94aef3bdf3f89 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -9,6 +9,9 @@ * Martin Schwidefsky (schwidefsky@de.ibm.com) */ +#define KMSG_COMPONENT "cio" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include @@ -104,44 +107,6 @@ cio_get_options (struct subchannel *sch) return flags; } -/* - * Use tpi to get a pending interrupt, call the interrupt handler and - * return a pointer to the subchannel structure. - */ -static int -cio_tpi(void) -{ - struct tpi_info *tpi_info; - struct subchannel *sch; - struct irb *irb; - int irq_context; - - tpi_info = (struct tpi_info *) __LC_SUBCHANNEL_ID; - if (tpi (NULL) != 1) - return 0; - irb = (struct irb *) __LC_IRB; - /* Store interrupt response block to lowcore. */ - if (tsch (tpi_info->schid, irb) != 0) - /* Not status pending or not operational. */ - return 1; - sch = (struct subchannel *)(unsigned long)tpi_info->intparm; - if (!sch) - return 1; - irq_context = in_interrupt(); - if (!irq_context) - local_bh_disable(); - irq_enter (); - spin_lock(sch->lock); - memcpy(&sch->schib.scsw, &irb->scsw, sizeof(union scsw)); - if (sch->driver && sch->driver->irq) - sch->driver->irq(sch); - spin_unlock(sch->lock); - irq_exit (); - if (!irq_context) - _local_bh_enable(); - return 1; -} - static int cio_start_handle_notoper(struct subchannel *sch, __u8 lpm) { @@ -152,11 +117,13 @@ cio_start_handle_notoper(struct subchannel *sch, __u8 lpm) else sch->lpm = 0; - stsch (sch->schid, &sch->schib); - CIO_MSG_EVENT(2, "cio_start: 'not oper' status for " "subchannel 0.%x.%04x!\n", sch->schid.ssid, sch->schid.sch_no); + + if (cio_update_schib(sch)) + return -ENODEV; + sprintf(dbf_text, "no%s", dev_name(&sch->dev)); CIO_TRACE_EVENT(0, dbf_text); CIO_HEX_EVENT(0, &sch->schib, sizeof (struct schib)); @@ -354,7 +321,8 @@ cio_cancel (struct subchannel *sch) switch (ccode) { case 0: /* success */ /* Update information in scsw. */ - stsch (sch->schid, &sch->schib); + if (cio_update_schib(sch)) + return -ENODEV; return 0; case 1: /* status pending */ return -EBUSY; @@ -365,36 +333,93 @@ cio_cancel (struct subchannel *sch) } } + +static void cio_apply_config(struct subchannel *sch, struct schib *schib) +{ + schib->pmcw.intparm = sch->config.intparm; + schib->pmcw.mbi = sch->config.mbi; + schib->pmcw.isc = sch->config.isc; + schib->pmcw.ena = sch->config.ena; + schib->pmcw.mme = sch->config.mme; + schib->pmcw.mp = sch->config.mp; + schib->pmcw.csense = sch->config.csense; + schib->pmcw.mbfc = sch->config.mbfc; + if (sch->config.mbfc) + schib->mba = sch->config.mba; +} + +static int cio_check_config(struct subchannel *sch, struct schib *schib) +{ + return (schib->pmcw.intparm == sch->config.intparm) && + (schib->pmcw.mbi == sch->config.mbi) && + (schib->pmcw.isc == sch->config.isc) && + (schib->pmcw.ena == sch->config.ena) && + (schib->pmcw.mme == sch->config.mme) && + (schib->pmcw.mp == sch->config.mp) && + (schib->pmcw.csense == sch->config.csense) && + (schib->pmcw.mbfc == sch->config.mbfc) && + (!sch->config.mbfc || (schib->mba == sch->config.mba)); +} + /* - * Function: cio_modify - * Issues a "Modify Subchannel" on the specified subchannel + * cio_commit_config - apply configuration to the subchannel */ -int -cio_modify (struct subchannel *sch) +int cio_commit_config(struct subchannel *sch) { - int ccode, retry, ret; + struct schib schib; + int ccode, retry, ret = 0; + + if (stsch(sch->schid, &schib) || !css_sch_is_valid(&schib)) + return -ENODEV; - ret = 0; for (retry = 0; retry < 5; retry++) { - ccode = msch_err (sch->schid, &sch->schib); - if (ccode < 0) /* -EIO if msch gets a program check. */ + /* copy desired changes to local schib */ + cio_apply_config(sch, &schib); + ccode = msch_err(sch->schid, &schib); + if (ccode < 0) /* -EIO if msch gets a program check. */ return ccode; switch (ccode) { case 0: /* successfull */ - return 0; - case 1: /* status pending */ + if (stsch(sch->schid, &schib) || + !css_sch_is_valid(&schib)) + return -ENODEV; + if (cio_check_config(sch, &schib)) { + /* commit changes from local schib */ + memcpy(&sch->schib, &schib, sizeof(schib)); + return 0; + } + ret = -EAGAIN; + break; + case 1: /* status pending */ return -EBUSY; - case 2: /* busy */ - udelay (100); /* allow for recovery */ + case 2: /* busy */ + udelay(100); /* allow for recovery */ ret = -EBUSY; break; - case 3: /* not operational */ + case 3: /* not operational */ return -ENODEV; } } return ret; } +/** + * cio_update_schib - Perform stsch and update schib if subchannel is valid. + * @sch: subchannel on which to perform stsch + * Return zero on success, -ENODEV otherwise. + */ +int cio_update_schib(struct subchannel *sch) +{ + struct schib schib; + + if (stsch(sch->schid, &schib) || !css_sch_is_valid(&schib)) + return -ENODEV; + + memcpy(&sch->schib, &schib, sizeof(schib)); + return 0; +} +EXPORT_SYMBOL_GPL(cio_update_schib); + /** * cio_enable_subchannel - enable a subchannel. * @sch: subchannel to be enabled @@ -403,7 +428,6 @@ cio_modify (struct subchannel *sch) int cio_enable_subchannel(struct subchannel *sch, u32 intparm) { char dbf_txt[15]; - int ccode; int retry; int ret; @@ -412,33 +436,27 @@ int cio_enable_subchannel(struct subchannel *sch, u32 intparm) if (sch_is_pseudo_sch(sch)) return -EINVAL; - ccode = stsch (sch->schid, &sch->schib); - if (ccode) + if (cio_update_schib(sch)) return -ENODEV; - for (retry = 5, ret = 0; retry > 0; retry--) { - sch->schib.pmcw.ena = 1; - sch->schib.pmcw.isc = sch->isc; - sch->schib.pmcw.intparm = intparm; - ret = cio_modify(sch); - if (ret == -ENODEV) - break; - if (ret == -EIO) + sch->config.ena = 1; + sch->config.isc = sch->isc; + sch->config.intparm = intparm; + + for (retry = 0; retry < 3; retry++) { + ret = cio_commit_config(sch); + if (ret == -EIO) { /* - * Got a program check in cio_modify. Try without + * Got a program check in msch. Try without * the concurrent sense bit the next time. */ - sch->schib.pmcw.csense = 0; - if (ret == 0) { - stsch (sch->schid, &sch->schib); - if (sch->schib.pmcw.ena) - break; - } - if (ret == -EBUSY) { + sch->config.csense = 0; + } else if (ret == -EBUSY) { struct irb irb; if (tsch(sch->schid, &irb) != 0) break; - } + } else + break; } sprintf (dbf_txt, "ret:%d", ret); CIO_TRACE_EVENT (2, dbf_txt); @@ -453,8 +471,6 @@ EXPORT_SYMBOL_GPL(cio_enable_subchannel); int cio_disable_subchannel(struct subchannel *sch) { char dbf_txt[15]; - int ccode; - int retry; int ret; CIO_TRACE_EVENT (2, "dissch"); @@ -462,8 +478,7 @@ int cio_disable_subchannel(struct subchannel *sch) if (sch_is_pseudo_sch(sch)) return 0; - ccode = stsch (sch->schid, &sch->schib); - if (ccode == 3) /* Not operational. */ + if (cio_update_schib(sch)) return -ENODEV; if (scsw_actl(&sch->schib.scsw) != 0) @@ -473,24 +488,9 @@ int cio_disable_subchannel(struct subchannel *sch) */ return -EBUSY; - for (retry = 5, ret = 0; retry > 0; retry--) { - sch->schib.pmcw.ena = 0; - ret = cio_modify(sch); - if (ret == -ENODEV) - break; - if (ret == -EBUSY) - /* - * The subchannel is busy or status pending. - * We'll disable when the next interrupt was delivered - * via the state machine. - */ - break; - if (ret == 0) { - stsch (sch->schid, &sch->schib); - if (!sch->schib.pmcw.ena) - break; - } - } + sch->config.ena = 0; + ret = cio_commit_config(sch); + sprintf (dbf_txt, "ret:%d", ret); CIO_TRACE_EVENT (2, dbf_txt); return ret; @@ -687,6 +687,43 @@ static char console_sch_name[10] = "0.x.xxxx"; static struct io_subchannel_private console_priv; static int console_subchannel_in_use; +/* + * Use tpi to get a pending interrupt, call the interrupt handler and + * return a pointer to the subchannel structure. + */ +static int cio_tpi(void) +{ + struct tpi_info *tpi_info; + struct subchannel *sch; + struct irb *irb; + int irq_context; + + tpi_info = (struct tpi_info *) __LC_SUBCHANNEL_ID; + if (tpi(NULL) != 1) + return 0; + irb = (struct irb *) __LC_IRB; + /* Store interrupt response block to lowcore. */ + if (tsch(tpi_info->schid, irb) != 0) + /* Not status pending or not operational. */ + return 1; + sch = (struct subchannel *)(unsigned long)tpi_info->intparm; + if (!sch) + return 1; + irq_context = in_interrupt(); + if (!irq_context) + local_bh_disable(); + irq_enter(); + spin_lock(sch->lock); + memcpy(&sch->schib.scsw, &irb->scsw, sizeof(union scsw)); + if (sch->driver && sch->driver->irq) + sch->driver->irq(sch); + spin_unlock(sch->lock); + irq_exit(); + if (!irq_context) + _local_bh_enable(); + return 1; +} + void *cio_get_console_priv(void) { return &console_priv; @@ -780,7 +817,7 @@ cio_probe_console(void) sch_no = cio_get_console_sch_no(); if (sch_no == -1) { console_subchannel_in_use = 0; - printk(KERN_WARNING "cio: No ccw console found!\n"); + pr_warning("No CCW console was found\n"); return ERR_PTR(-ENODEV); } memset(&console_subchannel, 0, sizeof(struct subchannel)); @@ -796,10 +833,9 @@ cio_probe_console(void) * enable console I/O-interrupt subclass */ isc_register(CONSOLE_ISC); - console_subchannel.schib.pmcw.isc = CONSOLE_ISC; - console_subchannel.schib.pmcw.intparm = - (u32)(addr_t)&console_subchannel; - ret = cio_modify(&console_subchannel); + console_subchannel.config.isc = CONSOLE_ISC; + console_subchannel.config.intparm = (u32)(addr_t)&console_subchannel; + ret = cio_commit_config(&console_subchannel); if (ret) { isc_unregister(CONSOLE_ISC); console_subchannel_in_use = 0; @@ -811,8 +847,8 @@ cio_probe_console(void) void cio_release_console(void) { - console_subchannel.schib.pmcw.intparm = 0; - cio_modify(&console_subchannel); + console_subchannel.config.intparm = 0; + cio_commit_config(&console_subchannel); isc_unregister(CONSOLE_ISC); console_subchannel_in_use = 0; } @@ -852,7 +888,8 @@ __disable_subchannel_easy(struct subchannel_id schid, struct schib *schib) cc = msch(schid, schib); if (cc) return (cc==3?-ENODEV:-EBUSY); - stsch(schid, schib); + if (stsch(schid, schib) || !css_sch_is_valid(schib)) + return -ENODEV; if (!schib->pmcw.ena) return 0; } diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h index 0fb24784e9254fb00641974b1f67b0a95f0861f1..5150fba742ac24f3569d1199b0d1567cd1588522 100644 --- a/drivers/s390/cio/cio.h +++ b/drivers/s390/cio/cio.h @@ -45,6 +45,19 @@ struct pmcw { /* ... in an operand exception. */ } __attribute__ ((packed)); +/* Target SCHIB configuration. */ +struct schib_config { + u64 mba; + u32 intparm; + u16 mbi; + u32 isc:3; + u32 ena:1; + u32 mme:2; + u32 mp:1; + u32 csense:1; + u32 mbfc:1; +} __attribute__ ((packed)); + /* * subchannel information block */ @@ -82,6 +95,8 @@ struct subchannel { struct device dev; /* entry in device tree */ struct css_driver *driver; void *private; /* private per subchannel type data */ + struct work_struct work; + struct schib_config config; } __attribute__ ((aligned(8))); #define IO_INTERRUPT_TYPE 0 /* I/O interrupt type */ @@ -100,7 +115,8 @@ extern int cio_start_key (struct subchannel *, struct ccw1 *, __u8, __u8); extern int cio_cancel (struct subchannel *); extern int cio_set_options (struct subchannel *, int); extern int cio_get_options (struct subchannel *); -extern int cio_modify (struct subchannel *); +extern int cio_update_schib(struct subchannel *sch); +extern int cio_commit_config(struct subchannel *sch); int cio_tm_start_key(struct subchannel *sch, struct tcw *tcw, u8 lpm, u8 key); int cio_tm_intrg(struct subchannel *sch); diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index a90b28c0be5707f64bdd6a058ac416272756265c..dc98b2c638628bf8a3174db78c53ec5823506a1e 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c @@ -25,6 +25,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define KMSG_COMPONENT "cio" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include @@ -185,56 +188,19 @@ static inline void cmf_activate(void *area, unsigned int onoff) static int set_schib(struct ccw_device *cdev, u32 mme, int mbfc, unsigned long address) { - int ret; - int retry; struct subchannel *sch; - struct schib *schib; sch = to_subchannel(cdev->dev.parent); - schib = &sch->schib; - /* msch can silently fail, so do it again if necessary */ - for (retry = 0; retry < 3; retry++) { - /* prepare schib */ - stsch(sch->schid, schib); - schib->pmcw.mme = mme; - schib->pmcw.mbfc = mbfc; - /* address can be either a block address or a block index */ - if (mbfc) - schib->mba = address; - else - schib->pmcw.mbi = address; - - /* try to submit it */ - switch(ret = msch_err(sch->schid, schib)) { - case 0: - break; - case 1: - case 2: /* in I/O or status pending */ - ret = -EBUSY; - break; - case 3: /* subchannel is no longer valid */ - ret = -ENODEV; - break; - default: /* msch caught an exception */ - ret = -EINVAL; - break; - } - stsch(sch->schid, schib); /* restore the schib */ - - if (ret) - break; - /* check if it worked */ - if (schib->pmcw.mme == mme && - schib->pmcw.mbfc == mbfc && - (mbfc ? (schib->mba == address) - : (schib->pmcw.mbi == address))) - return 0; + sch->config.mme = mme; + sch->config.mbfc = mbfc; + /* address can be either a block address or a block index */ + if (mbfc) + sch->config.mba = address; + else + sch->config.mbi = address; - ret = -EINVAL; - } - - return ret; + return cio_commit_config(sch); } struct set_schib_struct { @@ -338,7 +304,7 @@ static int cmf_copy_block(struct ccw_device *cdev) sch = to_subchannel(cdev->dev.parent); - if (stsch(sch->schid, &sch->schib)) + if (cio_update_schib(sch)) return -ENODEV; if (scsw_fctl(&sch->schib.scsw) & SCSW_FCTL_START_FUNC) { @@ -1359,9 +1325,8 @@ static int __init init_cmf(void) default: return 1; } - - printk(KERN_INFO "cio: Channel measurement facility using %s " - "format (%s)\n", format_string, detect_string); + pr_info("Channel measurement facility initialized using format " + "%s (mode %s)\n", format_string, detect_string); return 0; } diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 76bbb1e74c2988c025d695c3927fc690ca067ba6..8019288bc6dee0a730f79b6a4ed86228a3a052f3 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -6,6 +6,10 @@ * Author(s): Arnd Bergmann (arndb@de.ibm.com) * Cornelia Huck (cornelia.huck@de.ibm.com) */ + +#define KMSG_COMPONENT "cio" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include @@ -128,8 +132,8 @@ css_free_subchannel(struct subchannel *sch) { if (sch) { /* Reset intparm to zeroes. */ - sch->schib.pmcw.intparm = 0; - cio_modify(sch); + sch->config.intparm = 0; + cio_commit_config(sch); kfree(sch->lock); kfree(sch); } @@ -844,8 +848,8 @@ init_channel_subsystem (void) s390_unregister_crw_handler(CRW_RSC_CSS); chsc_free_sei_area(); kfree(slow_subchannel_set); - printk(KERN_WARNING"cio: failed to initialize css driver (%d)!\n", - ret); + pr_alert("The CSS device driver initialization failed with " + "errno=%d\n", ret); return ret; } diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 4e4008325e281edc58f11b3a211506b3f8bac35a..23d5752349b59d0f85b3274c206eea556123e10e 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -376,19 +376,23 @@ int ccw_device_set_offline(struct ccw_device *cdev) dev_fsm_event(cdev, DEV_EVENT_NOTOPER); } spin_unlock_irq(cdev->ccwlock); + /* Give up reference from ccw_device_set_online(). */ + put_device(&cdev->dev); return ret; } spin_unlock_irq(cdev->ccwlock); - if (ret == 0) + if (ret == 0) { wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev)); - else { + /* Give up reference from ccw_device_set_online(). */ + put_device(&cdev->dev); + } else { CIO_MSG_EVENT(0, "ccw_device_offline returned %d, " "device 0.%x.%04x\n", ret, cdev->private->dev_id.ssid, cdev->private->dev_id.devno); cdev->online = 1; } - return ret; + return ret; } /** @@ -411,6 +415,9 @@ int ccw_device_set_online(struct ccw_device *cdev) return -ENODEV; if (cdev->online || !cdev->drv) return -EINVAL; + /* Hold on to an extra reference while device is online. */ + if (!get_device(&cdev->dev)) + return -ENODEV; spin_lock_irq(cdev->ccwlock); ret = ccw_device_online(cdev); @@ -422,10 +429,15 @@ int ccw_device_set_online(struct ccw_device *cdev) "device 0.%x.%04x\n", ret, cdev->private->dev_id.ssid, cdev->private->dev_id.devno); + /* Give up online reference since onlining failed. */ + put_device(&cdev->dev); return ret; } - if (cdev->private->state != DEV_STATE_ONLINE) + if (cdev->private->state != DEV_STATE_ONLINE) { + /* Give up online reference since onlining failed. */ + put_device(&cdev->dev); return -ENODEV; + } if (!cdev->drv->set_online || cdev->drv->set_online(cdev) == 0) { cdev->online = 1; return 0; @@ -440,6 +452,8 @@ int ccw_device_set_online(struct ccw_device *cdev) "device 0.%x.%04x\n", ret, cdev->private->dev_id.ssid, cdev->private->dev_id.devno); + /* Give up online reference since onlining failed. */ + put_device(&cdev->dev); return (ret == 0) ? -ENODEV : ret; } @@ -704,6 +718,8 @@ ccw_device_release(struct device *dev) struct ccw_device *cdev; cdev = to_ccwdev(dev); + /* Release reference of parent subchannel. */ + put_device(cdev->dev.parent); kfree(cdev->private); kfree(cdev); } @@ -735,8 +751,8 @@ static int io_subchannel_initialize_dev(struct subchannel *sch, /* Do first half of device_register. */ device_initialize(&cdev->dev); if (!get_device(&sch->dev)) { - if (cdev->dev.release) - cdev->dev.release(&cdev->dev); + /* Release reference from device_initialize(). */ + put_device(&cdev->dev); return -ENODEV; } return 0; @@ -778,37 +794,55 @@ static void sch_attach_disconnected_device(struct subchannel *sch, struct subchannel *other_sch; int ret; - other_sch = to_subchannel(get_device(cdev->dev.parent)); + /* Get reference for new parent. */ + if (!get_device(&sch->dev)) + return; + other_sch = to_subchannel(cdev->dev.parent); + /* Note: device_move() changes cdev->dev.parent */ ret = device_move(&cdev->dev, &sch->dev); if (ret) { CIO_MSG_EVENT(0, "Moving disconnected device 0.%x.%04x failed " "(ret=%d)!\n", cdev->private->dev_id.ssid, cdev->private->dev_id.devno, ret); - put_device(&other_sch->dev); + /* Put reference for new parent. */ + put_device(&sch->dev); return; } sch_set_cdev(other_sch, NULL); /* No need to keep a subchannel without ccw device around. */ css_sch_device_unregister(other_sch); - put_device(&other_sch->dev); sch_attach_device(sch, cdev); + /* Put reference for old parent. */ + put_device(&other_sch->dev); } static void sch_attach_orphaned_device(struct subchannel *sch, struct ccw_device *cdev) { int ret; + struct subchannel *pseudo_sch; - /* Try to move the ccw device to its new subchannel. */ + /* Get reference for new parent. */ + if (!get_device(&sch->dev)) + return; + pseudo_sch = to_subchannel(cdev->dev.parent); + /* + * Try to move the ccw device to its new subchannel. + * Note: device_move() changes cdev->dev.parent + */ ret = device_move(&cdev->dev, &sch->dev); if (ret) { CIO_MSG_EVENT(0, "Moving device 0.%x.%04x from orphanage " "failed (ret=%d)!\n", cdev->private->dev_id.ssid, cdev->private->dev_id.devno, ret); + /* Put reference for new parent. */ + put_device(&sch->dev); return; } sch_attach_device(sch, cdev); + /* Put reference on pseudo subchannel. */ + put_device(&pseudo_sch->dev); } static void sch_create_and_recog_new_device(struct subchannel *sch) @@ -830,9 +864,11 @@ static void sch_create_and_recog_new_device(struct subchannel *sch) spin_lock_irq(sch->lock); sch_set_cdev(sch, NULL); spin_unlock_irq(sch->lock); - if (cdev->dev.release) - cdev->dev.release(&cdev->dev); css_sch_device_unregister(sch); + /* Put reference from io_subchannel_create_ccwdev(). */ + put_device(&sch->dev); + /* Give up initial reference. */ + put_device(&cdev->dev); } } @@ -854,15 +890,20 @@ void ccw_device_move_to_orphanage(struct work_struct *work) dev_id.devno = sch->schib.pmcw.dev; dev_id.ssid = sch->schid.ssid; + /* Increase refcount for pseudo subchannel. */ + get_device(&css->pseudo_subchannel->dev); /* * Move the orphaned ccw device to the orphanage so the replacing * ccw device can take its place on the subchannel. + * Note: device_move() changes cdev->dev.parent */ ret = device_move(&cdev->dev, &css->pseudo_subchannel->dev); if (ret) { CIO_MSG_EVENT(0, "Moving device 0.%x.%04x to orphanage failed " "(ret=%d)!\n", cdev->private->dev_id.ssid, cdev->private->dev_id.devno, ret); + /* Decrease refcount for pseudo subchannel again. */ + put_device(&css->pseudo_subchannel->dev); return; } cdev->ccwlock = css->pseudo_subchannel->lock; @@ -875,17 +916,23 @@ void ccw_device_move_to_orphanage(struct work_struct *work) if (replacing_cdev) { sch_attach_disconnected_device(sch, replacing_cdev); /* Release reference from get_disc_ccwdev_by_dev_id() */ - put_device(&cdev->dev); + put_device(&replacing_cdev->dev); + /* Release reference of subchannel from old cdev. */ + put_device(&sch->dev); return; } replacing_cdev = get_orphaned_ccwdev_by_dev_id(css, &dev_id); if (replacing_cdev) { sch_attach_orphaned_device(sch, replacing_cdev); /* Release reference from get_orphaned_ccwdev_by_dev_id() */ - put_device(&cdev->dev); + put_device(&replacing_cdev->dev); + /* Release reference of subchannel from old cdev. */ + put_device(&sch->dev); return; } sch_create_and_recog_new_device(sch); + /* Release reference of subchannel from old cdev. */ + put_device(&sch->dev); } /* @@ -903,6 +950,14 @@ io_subchannel_register(struct work_struct *work) priv = container_of(work, struct ccw_device_private, kick_work); cdev = priv->cdev; sch = to_subchannel(cdev->dev.parent); + /* + * Check if subchannel is still registered. It may have become + * unregistered if a machine check hit us after finishing + * device recognition but before the register work could be + * queued. + */ + if (!device_is_registered(&sch->dev)) + goto out_err; css_update_ssd_info(sch); /* * io_subchannel_register() will also be called after device @@ -910,7 +965,7 @@ io_subchannel_register(struct work_struct *work) * be registered). We need to reprobe since we may now have sense id * information. */ - if (klist_node_attached(&cdev->dev.knode_parent)) { + if (device_is_registered(&cdev->dev)) { if (!cdev->drv) { ret = device_reprobe(&cdev->dev); if (ret) @@ -934,22 +989,19 @@ io_subchannel_register(struct work_struct *work) CIO_MSG_EVENT(0, "Could not register ccw dev 0.%x.%04x: %d\n", cdev->private->dev_id.ssid, cdev->private->dev_id.devno, ret); - put_device(&cdev->dev); spin_lock_irqsave(sch->lock, flags); sch_set_cdev(sch, NULL); spin_unlock_irqrestore(sch->lock, flags); - kfree (cdev->private); - kfree (cdev); - put_device(&sch->dev); - if (atomic_dec_and_test(&ccw_device_init_count)) - wake_up(&ccw_device_init_wq); - return; + /* Release initial device reference. */ + put_device(&cdev->dev); + goto out_err; } - put_device(&cdev->dev); out: cdev->private->flags.recog_done = 1; - put_device(&sch->dev); wake_up(&cdev->private->wait_q); +out_err: + /* Release reference for workqueue processing. */ + put_device(&cdev->dev); if (atomic_dec_and_test(&ccw_device_init_count)) wake_up(&ccw_device_init_wq); } @@ -968,8 +1020,8 @@ static void ccw_device_call_sch_unregister(struct work_struct *work) sch = to_subchannel(cdev->dev.parent); css_sch_device_unregister(sch); /* Reset intparm to zeroes. */ - sch->schib.pmcw.intparm = 0; - cio_modify(sch); + sch->config.intparm = 0; + cio_commit_config(sch); /* Release cdev reference for workqueue processing.*/ put_device(&cdev->dev); /* Release subchannel reference for local processing. */ @@ -998,8 +1050,6 @@ io_subchannel_recog_done(struct ccw_device *cdev) PREPARE_WORK(&cdev->private->kick_work, ccw_device_call_sch_unregister); queue_work(slow_path_wq, &cdev->private->kick_work); - /* Release subchannel reference for asynchronous recognition. */ - put_device(&sch->dev); if (atomic_dec_and_test(&ccw_device_init_count)) wake_up(&ccw_device_init_wq); break; @@ -1070,10 +1120,15 @@ static void ccw_device_move_to_sch(struct work_struct *work) priv = container_of(work, struct ccw_device_private, kick_work); sch = priv->sch; cdev = priv->cdev; - former_parent = ccw_device_is_orphan(cdev) ? - NULL : to_subchannel(get_device(cdev->dev.parent)); + former_parent = to_subchannel(cdev->dev.parent); + /* Get reference for new parent. */ + if (!get_device(&sch->dev)) + return; mutex_lock(&sch->reg_mutex); - /* Try to move the ccw device to its new subchannel. */ + /* + * Try to move the ccw device to its new subchannel. + * Note: device_move() changes cdev->dev.parent + */ rc = device_move(&cdev->dev, &sch->dev); mutex_unlock(&sch->reg_mutex); if (rc) { @@ -1083,21 +1138,23 @@ static void ccw_device_move_to_sch(struct work_struct *work) cdev->private->dev_id.devno, sch->schid.ssid, sch->schid.sch_no, rc); css_sch_device_unregister(sch); + /* Put reference for new parent again. */ + put_device(&sch->dev); goto out; } - if (former_parent) { + if (!sch_is_pseudo_sch(former_parent)) { spin_lock_irq(former_parent->lock); sch_set_cdev(former_parent, NULL); spin_unlock_irq(former_parent->lock); css_sch_device_unregister(former_parent); /* Reset intparm to zeroes. */ - former_parent->schib.pmcw.intparm = 0; - cio_modify(former_parent); + former_parent->config.intparm = 0; + cio_commit_config(former_parent); } sch_attach_device(sch, cdev); out: - if (former_parent) - put_device(&former_parent->dev); + /* Put reference for old parent. */ + put_device(&former_parent->dev); put_device(&cdev->dev); } @@ -1113,6 +1170,15 @@ static void io_subchannel_irq(struct subchannel *sch) dev_fsm_event(cdev, DEV_EVENT_INTERRUPT); } +void io_subchannel_init_config(struct subchannel *sch) +{ + memset(&sch->config, 0, sizeof(sch->config)); + sch->config.csense = 1; + /* Use subchannel mp mode when there is more than 1 installed CHPID. */ + if ((sch->schib.pmcw.pim & (sch->schib.pmcw.pim - 1)) != 0) + sch->config.mp = 1; +} + static void io_subchannel_init_fields(struct subchannel *sch) { if (cio_is_console(sch->schid)) @@ -1127,18 +1193,34 @@ static void io_subchannel_init_fields(struct subchannel *sch) sch->schib.pmcw.dev, sch->schid.ssid, sch->schid.sch_no, sch->schib.pmcw.pim, sch->schib.pmcw.pam, sch->schib.pmcw.pom); - /* Initially set up some fields in the pmcw. */ - sch->schib.pmcw.ena = 0; - sch->schib.pmcw.csense = 1; /* concurrent sense */ - if ((sch->lpm & (sch->lpm - 1)) != 0) - sch->schib.pmcw.mp = 1; /* multipath mode */ - /* clean up possible residual cmf stuff */ - sch->schib.pmcw.mme = 0; - sch->schib.pmcw.mbfc = 0; - sch->schib.pmcw.mbi = 0; - sch->schib.mba = 0; + + io_subchannel_init_config(sch); } +static void io_subchannel_do_unreg(struct work_struct *work) +{ + struct subchannel *sch; + + sch = container_of(work, struct subchannel, work); + css_sch_device_unregister(sch); + /* Reset intparm to zeroes. */ + sch->config.intparm = 0; + cio_commit_config(sch); + put_device(&sch->dev); +} + +/* Schedule unregister if we have no cdev. */ +static void io_subchannel_schedule_removal(struct subchannel *sch) +{ + get_device(&sch->dev); + INIT_WORK(&sch->work, io_subchannel_do_unreg); + queue_work(slow_path_wq, &sch->work); +} + +/* + * Note: We always return 0 so that we bind to the device even on error. + * This is needed so that our remove function is called on unregister. + */ static int io_subchannel_probe(struct subchannel *sch) { struct ccw_device *cdev; @@ -1168,9 +1250,8 @@ static int io_subchannel_probe(struct subchannel *sch) ccw_device_register(cdev); /* * Check if the device is already online. If it is - * the reference count needs to be corrected - * (see ccw_device_online and css_init_done for the - * ugly details). + * the reference count needs to be corrected since we + * didn't obtain a reference in ccw_device_set_online. */ if (cdev->private->state != DEV_STATE_NOT_OPER && cdev->private->state != DEV_STATE_OFFLINE && @@ -1179,23 +1260,24 @@ static int io_subchannel_probe(struct subchannel *sch) return 0; } io_subchannel_init_fields(sch); - /* - * First check if a fitting device may be found amongst the - * disconnected devices or in the orphanage. - */ - dev_id.devno = sch->schib.pmcw.dev; - dev_id.ssid = sch->schid.ssid; + rc = cio_commit_config(sch); + if (rc) + goto out_schedule; rc = sysfs_create_group(&sch->dev.kobj, &io_subchannel_attr_group); if (rc) - return rc; + goto out_schedule; /* Allocate I/O subchannel private data. */ sch->private = kzalloc(sizeof(struct io_subchannel_private), GFP_KERNEL | GFP_DMA); - if (!sch->private) { - rc = -ENOMEM; + if (!sch->private) goto out_err; - } + /* + * First check if a fitting device may be found amongst the + * disconnected devices or in the orphanage. + */ + dev_id.devno = sch->schib.pmcw.dev; + dev_id.ssid = sch->schid.ssid; cdev = get_disc_ccwdev_by_dev_id(&dev_id, NULL); if (!cdev) cdev = get_orphaned_ccwdev_by_dev_id(to_css(sch->dev.parent), @@ -1213,24 +1295,21 @@ static int io_subchannel_probe(struct subchannel *sch) return 0; } cdev = io_subchannel_create_ccwdev(sch); - if (IS_ERR(cdev)) { - rc = PTR_ERR(cdev); + if (IS_ERR(cdev)) goto out_err; - } rc = io_subchannel_recog(cdev, sch); if (rc) { spin_lock_irqsave(sch->lock, flags); - sch_set_cdev(sch, NULL); + io_subchannel_recog_done(cdev); spin_unlock_irqrestore(sch->lock, flags); - if (cdev->dev.release) - cdev->dev.release(&cdev->dev); - goto out_err; } return 0; out_err: kfree(sch->private); sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group); - return rc; +out_schedule: + io_subchannel_schedule_removal(sch); + return 0; } static int @@ -1275,10 +1354,7 @@ static void io_subchannel_verify(struct subchannel *sch) static int check_for_io_on_path(struct subchannel *sch, int mask) { - int cc; - - cc = stsch(sch->schid, &sch->schib); - if (cc) + if (cio_update_schib(sch)) return 0; if (scsw_actl(&sch->schib.scsw) && sch->schib.pmcw.lpum == mask) return 1; @@ -1347,15 +1423,13 @@ static int io_subchannel_chp_event(struct subchannel *sch, io_subchannel_verify(sch); break; case CHP_OFFLINE: - if (stsch(sch->schid, &sch->schib)) - return -ENXIO; - if (!css_sch_is_valid(&sch->schib)) + if (cio_update_schib(sch)) return -ENODEV; io_subchannel_terminate_path(sch, mask); break; case CHP_ONLINE: - if (stsch(sch->schid, &sch->schib)) - return -ENXIO; + if (cio_update_schib(sch)) + return -ENODEV; sch->lpm |= mask & sch->opm; io_subchannel_verify(sch); break; @@ -1610,8 +1684,8 @@ static int io_subchannel_sch_event(struct subchannel *sch, int slow) spin_lock_irqsave(sch->lock, flags); /* Reset intparm to zeroes. */ - sch->schib.pmcw.intparm = 0; - cio_modify(sch); + sch->config.intparm = 0; + cio_commit_config(sch); break; case REPROBE: ccw_device_trigger_reprobe(cdev); @@ -1652,6 +1726,9 @@ static int ccw_device_console_enable(struct ccw_device *cdev, sch->private = cio_get_console_priv(); memset(sch->private, 0, sizeof(struct io_subchannel_private)); io_subchannel_init_fields(sch); + rc = cio_commit_config(sch); + if (rc) + return rc; sch->driver = &io_subchannel_driver; /* Initialize the ccw_device structure. */ cdev->dev.parent= &sch->dev; @@ -1723,7 +1800,7 @@ __ccwdev_check_busid(struct device *dev, void *id) bus_id = id; - return (strncmp(bus_id, dev_name(dev), BUS_ID_SIZE) == 0); + return (strcmp(bus_id, dev_name(dev)) == 0); } @@ -1806,6 +1883,8 @@ ccw_device_remove (struct device *dev) "device 0.%x.%04x\n", ret, cdev->private->dev_id.ssid, cdev->private->dev_id.devno); + /* Give up reference obtained in ccw_device_set_online(). */ + put_device(&cdev->dev); } ccw_device_set_timeout(cdev, 0); cdev->drv = NULL; diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h index 104ed669db43946a0656fe5adaac51a8374cc4f1..0f2e63ea48deee03511be167208aa5d2742b4d09 100644 --- a/drivers/s390/cio/device.h +++ b/drivers/s390/cio/device.h @@ -76,6 +76,7 @@ extern wait_queue_head_t ccw_device_init_wq; extern atomic_t ccw_device_init_count; void io_subchannel_recog_done(struct ccw_device *cdev); +void io_subchannel_init_config(struct subchannel *sch); int ccw_device_cancel_halt_clear(struct ccw_device *); diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 10bc03940fb3144fd412e1625eaaa003fd64459d..8df5eaafc5ab6a4c4518f5eacaa3b22e680e5af0 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -140,8 +140,7 @@ ccw_device_cancel_halt_clear(struct ccw_device *cdev) int ret; sch = to_subchannel(cdev->dev.parent); - ret = stsch(sch->schid, &sch->schib); - if (ret || !sch->schib.pmcw.dnv) + if (cio_update_schib(sch)) return -ENODEV; if (!sch->schib.pmcw.ena) /* Not operational -> done. */ @@ -245,11 +244,13 @@ ccw_device_recog_done(struct ccw_device *cdev, int state) * through ssch() and the path information is up to date. */ old_lpm = sch->lpm; - stsch(sch->schid, &sch->schib); - sch->lpm = sch->schib.pmcw.pam & sch->opm; + /* Check since device may again have become not operational. */ - if (!sch->schib.pmcw.dnv) + if (cio_update_schib(sch)) state = DEV_STATE_NOT_OPER; + else + sch->lpm = sch->schib.pmcw.pam & sch->opm; + if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID) /* Force reprobe on all chpids. */ old_lpm = 0; @@ -399,9 +400,6 @@ ccw_device_done(struct ccw_device *cdev, int state) ccw_device_oper_notify(cdev); } wake_up(&cdev->private->wait_q); - - if (css_init_done && state != DEV_STATE_ONLINE) - put_device (&cdev->dev); } static int cmp_pgid(struct pgid *p1, struct pgid *p2) @@ -552,7 +550,11 @@ ccw_device_verify_done(struct ccw_device *cdev, int err) sch = to_subchannel(cdev->dev.parent); /* Update schib - pom may have changed. */ - stsch(sch->schid, &sch->schib); + if (cio_update_schib(sch)) { + cdev->private->flags.donotify = 0; + ccw_device_done(cdev, DEV_STATE_NOT_OPER); + return; + } /* Update lpm with verified path mask. */ sch->lpm = sch->vpm; /* Repeat path verification? */ @@ -611,8 +613,6 @@ ccw_device_online(struct ccw_device *cdev) (cdev->private->state != DEV_STATE_BOXED)) return -EINVAL; sch = to_subchannel(cdev->dev.parent); - if (css_init_done && !get_device(&cdev->dev)) - return -ENODEV; ret = cio_enable_subchannel(sch, (u32)(addr_t)sch); if (ret != 0) { /* Couldn't enable the subchannel for i/o. Sick device. */ @@ -672,7 +672,7 @@ ccw_device_offline(struct ccw_device *cdev) return 0; } sch = to_subchannel(cdev->dev.parent); - if (stsch(sch->schid, &sch->schib) || !sch->schib.pmcw.dnv) + if (cio_update_schib(sch)) return -ENODEV; if (scsw_actl(&sch->schib.scsw) != 0) return -EBUSY; @@ -750,7 +750,10 @@ ccw_device_online_verify(struct ccw_device *cdev, enum dev_event dev_event) * Since we might not just be coming from an interrupt from the * subchannel we have to update the schib. */ - stsch(sch->schid, &sch->schib); + if (cio_update_schib(sch)) { + ccw_device_verify_done(cdev, -ENODEV); + return; + } if (scsw_actl(&sch->schib.scsw) != 0 || (scsw_stctl(&sch->schib.scsw) & SCSW_STCTL_STATUS_PEND) || @@ -1016,20 +1019,21 @@ void ccw_device_trigger_reprobe(struct ccw_device *cdev) sch = to_subchannel(cdev->dev.parent); /* Update some values. */ - if (stsch(sch->schid, &sch->schib)) - return; - if (!sch->schib.pmcw.dnv) + if (cio_update_schib(sch)) return; /* * The pim, pam, pom values may not be accurate, but they are the best * we have before performing device selection :/ */ sch->lpm = sch->schib.pmcw.pam & sch->opm; - /* Re-set some bits in the pmcw that were lost. */ - sch->schib.pmcw.csense = 1; - sch->schib.pmcw.ena = 0; - if ((sch->lpm & (sch->lpm - 1)) != 0) - sch->schib.pmcw.mp = 1; + /* + * Use the initial configuration since we can't be shure that the old + * paths are valid. + */ + io_subchannel_init_config(sch); + if (cio_commit_config(sch)) + return; + /* We should also udate ssd info, but this has to wait. */ /* Check if this is another device which appeared on the same sch. */ if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) { diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c index 86bc94eb607f4b35f1094cd2148314f2e99932b2..fc5ca1dd52b39dfd4fd3727e40598228479c7ec9 100644 --- a/drivers/s390/cio/device_pgid.c +++ b/drivers/s390/cio/device_pgid.c @@ -504,7 +504,7 @@ ccw_device_verify_start(struct ccw_device *cdev) sch->vpm = 0; /* Get current pam. */ - if (stsch(sch->schid, &sch->schib)) { + if (cio_update_schib(sch)) { ccw_device_verify_done(cdev, -ENODEV); return; } diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c index 1b03c5423be207152d01786d41ccb1c799f8795d..5814dbee241000d6dff5f723624bc3c7a3635ac4 100644 --- a/drivers/s390/cio/device_status.c +++ b/drivers/s390/cio/device_status.c @@ -56,7 +56,8 @@ ccw_device_path_notoper(struct ccw_device *cdev) struct subchannel *sch; sch = to_subchannel(cdev->dev.parent); - stsch (sch->schid, &sch->schib); + if (cio_update_schib(sch)) + goto doverify; CIO_MSG_EVENT(0, "%s(0.%x.%04x) - path(s) %02x are " "not operational \n", __func__, @@ -64,6 +65,7 @@ ccw_device_path_notoper(struct ccw_device *cdev) sch->schib.pmcw.pnom); sch->lpm &= ~sch->schib.pmcw.pnom; +doverify: cdev->private->flags.doverify = 1; } diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index e3ea1d5f2810bae11a9b0918f547339b5c88e314..42f2b09631b6caa947ac66f0c0c285a9f4baa653 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -10,10 +10,10 @@ #include #include +#include #include "chsc.h" #define QDIO_BUSY_BIT_PATIENCE 100 /* 100 microseconds */ -#define QDIO_BUSY_BIT_GIVE_UP 2000000 /* 2 seconds = eternity */ #define QDIO_INPUT_THRESHOLD 500 /* 500 microseconds */ /* @@ -111,12 +111,12 @@ static inline int do_sqbs(u64 token, unsigned char state, int queue, } static inline int do_eqbs(u64 token, unsigned char *state, int queue, - int *start, int *count) + int *start, int *count, int ack) { register unsigned long _ccq asm ("0") = *count; register unsigned long _token asm ("1") = token; unsigned long _queuestart = ((unsigned long)queue << 32) | *start; - unsigned long _state = 0; + unsigned long _state = (unsigned long)ack << 63; asm volatile( " .insn rrf,0xB99c0000,%1,%2,0,0" @@ -133,7 +133,7 @@ static inline int do_eqbs(u64 token, unsigned char *state, int queue, static inline int do_sqbs(u64 token, unsigned char state, int queue, int *start, int *count) { return 0; } static inline int do_eqbs(u64 token, unsigned char *state, int queue, - int *start, int *count) { return 0; } + int *start, int *count, int ack) { return 0; } #endif /* CONFIG_64BIT */ struct qdio_irq; @@ -186,20 +186,14 @@ struct qdio_input_q { /* input buffer acknowledgement flag */ int polling; + /* how much sbals are acknowledged with qebsm */ + int ack_count; + /* last time of noticing incoming data */ u64 timestamp; - - /* lock for clearing the acknowledgement */ - spinlock_t lock; }; struct qdio_output_q { - /* failed siga-w attempts*/ - atomic_t busy_siga_counter; - - /* start time of busy condition */ - u64 timestamp; - /* PCIs are enabled for the queue */ int pci_out_enabled; @@ -250,6 +244,7 @@ struct qdio_q { struct qdio_irq *irq_ptr; struct tasklet_struct tasklet; + spinlock_t lock; /* error condition during a data transfer */ unsigned int qdio_error; @@ -300,11 +295,13 @@ struct qdio_irq { struct qdio_q *input_qs[QDIO_MAX_QUEUES_PER_IRQ]; struct qdio_q *output_qs[QDIO_MAX_QUEUES_PER_IRQ]; + debug_info_t *debug_area; struct mutex setup_mutex; }; /* helper functions */ #define queue_type(q) q->irq_ptr->qib.qfmt +#define SCH_NO(q) (q->irq_ptr->schid.sch_no) #define is_thinint_irq(irq) \ (irq->qib.qfmt == QDIO_IQDIO_QFMT || \ @@ -348,10 +345,13 @@ static inline unsigned long long get_usecs(void) ((bufnr + 1) & QDIO_MAX_BUFFERS_MASK) #define add_buf(bufnr, inc) \ ((bufnr + inc) & QDIO_MAX_BUFFERS_MASK) +#define sub_buf(bufnr, dec) \ + ((bufnr - dec) & QDIO_MAX_BUFFERS_MASK) /* prototypes for thin interrupt */ void qdio_sync_after_thinint(struct qdio_q *q); -int get_buf_state(struct qdio_q *q, unsigned int bufnr, unsigned char *state); +int get_buf_state(struct qdio_q *q, unsigned int bufnr, unsigned char *state, + int auto_ack); void qdio_check_outbound_after_thinint(struct qdio_q *q); int qdio_inbound_q_moved(struct qdio_q *q); void qdio_kick_inbound_handler(struct qdio_q *q); @@ -378,10 +378,15 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm, int qdio_allocate_qs(struct qdio_irq *irq_ptr, int nr_input_qs, int nr_output_qs); void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr); +int qdio_setup_get_ssqd(struct qdio_irq *irq_ptr, + struct subchannel_id *schid, + struct qdio_ssqd_desc *data); int qdio_setup_irq(struct qdio_initialize *init_data); void qdio_print_subchannel_info(struct qdio_irq *irq_ptr, struct ccw_device *cdev); void qdio_release_memory(struct qdio_irq *irq_ptr); +int qdio_setup_create_sysfs(struct ccw_device *cdev); +void qdio_setup_destroy_sysfs(struct ccw_device *cdev); int qdio_setup_init(void); void qdio_setup_exit(void); diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c index f05590355be80b6bde17993e1032dadb9f3b4cd1..f8a3b6967f691aa504711cf6b49867c8879ace5c 100644 --- a/drivers/s390/cio/qdio_debug.c +++ b/drivers/s390/cio/qdio_debug.c @@ -14,7 +14,7 @@ #include "qdio.h" debug_info_t *qdio_dbf_setup; -debug_info_t *qdio_dbf_trace; +debug_info_t *qdio_dbf_error; static struct dentry *debugfs_root; #define MAX_DEBUGFS_QUEUES 32 @@ -22,59 +22,33 @@ static struct dentry *debugfs_queues[MAX_DEBUGFS_QUEUES] = { NULL }; static DEFINE_MUTEX(debugfs_mutex); #define QDIO_DEBUGFS_NAME_LEN 40 -void qdio_allocate_do_dbf(struct qdio_initialize *init_data) +void qdio_allocate_dbf(struct qdio_initialize *init_data, + struct qdio_irq *irq_ptr) { - char dbf_text[20]; - - sprintf(dbf_text, "qfmt:%x", init_data->q_format); - QDIO_DBF_TEXT0(0, setup, dbf_text); - QDIO_DBF_HEX0(0, setup, init_data->adapter_name, 8); - sprintf(dbf_text, "qpff%4x", init_data->qib_param_field_format); - QDIO_DBF_TEXT0(0, setup, dbf_text); - QDIO_DBF_HEX0(0, setup, &init_data->qib_param_field, sizeof(void *)); - QDIO_DBF_HEX0(0, setup, &init_data->input_slib_elements, sizeof(void *)); - QDIO_DBF_HEX0(0, setup, &init_data->output_slib_elements, sizeof(void *)); - sprintf(dbf_text, "niq:%4x", init_data->no_input_qs); - QDIO_DBF_TEXT0(0, setup, dbf_text); - sprintf(dbf_text, "noq:%4x", init_data->no_output_qs); - QDIO_DBF_TEXT0(0, setup, dbf_text); - QDIO_DBF_HEX0(0, setup, &init_data->input_handler, sizeof(void *)); - QDIO_DBF_HEX0(0, setup, &init_data->output_handler, sizeof(void *)); - QDIO_DBF_HEX0(0, setup, &init_data->int_parm, sizeof(long)); - QDIO_DBF_HEX0(0, setup, &init_data->flags, sizeof(long)); - QDIO_DBF_HEX0(0, setup, &init_data->input_sbal_addr_array, sizeof(void *)); - QDIO_DBF_HEX0(0, setup, &init_data->output_sbal_addr_array, sizeof(void *)); -} - -static void qdio_unregister_dbf_views(void) -{ - if (qdio_dbf_setup) - debug_unregister(qdio_dbf_setup); - if (qdio_dbf_trace) - debug_unregister(qdio_dbf_trace); -} - -static int qdio_register_dbf_views(void) -{ - qdio_dbf_setup = debug_register("qdio_setup", QDIO_DBF_SETUP_PAGES, - QDIO_DBF_SETUP_NR_AREAS, - QDIO_DBF_SETUP_LEN); - if (!qdio_dbf_setup) - goto oom; - debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view); - debug_set_level(qdio_dbf_setup, QDIO_DBF_SETUP_LEVEL); - - qdio_dbf_trace = debug_register("qdio_trace", QDIO_DBF_TRACE_PAGES, - QDIO_DBF_TRACE_NR_AREAS, - QDIO_DBF_TRACE_LEN); - if (!qdio_dbf_trace) - goto oom; - debug_register_view(qdio_dbf_trace, &debug_hex_ascii_view); - debug_set_level(qdio_dbf_trace, QDIO_DBF_TRACE_LEVEL); - return 0; -oom: - qdio_unregister_dbf_views(); - return -ENOMEM; + char text[20]; + + DBF_EVENT("qfmt:%1d", init_data->q_format); + DBF_HEX(init_data->adapter_name, 8); + DBF_EVENT("qpff%4x", init_data->qib_param_field_format); + DBF_HEX(&init_data->qib_param_field, sizeof(void *)); + DBF_HEX(&init_data->input_slib_elements, sizeof(void *)); + DBF_HEX(&init_data->output_slib_elements, sizeof(void *)); + DBF_EVENT("niq:%1d noq:%1d", init_data->no_input_qs, + init_data->no_output_qs); + DBF_HEX(&init_data->input_handler, sizeof(void *)); + DBF_HEX(&init_data->output_handler, sizeof(void *)); + DBF_HEX(&init_data->int_parm, sizeof(long)); + DBF_HEX(&init_data->flags, sizeof(long)); + DBF_HEX(&init_data->input_sbal_addr_array, sizeof(void *)); + DBF_HEX(&init_data->output_sbal_addr_array, sizeof(void *)); + DBF_EVENT("irq:%8lx", (unsigned long)irq_ptr); + + /* allocate trace view for the interface */ + snprintf(text, 20, "qdio_%s", dev_name(&init_data->cdev->dev)); + irq_ptr->debug_area = debug_register(text, 2, 1, 16); + debug_register_view(irq_ptr->debug_area, &debug_hex_ascii_view); + debug_set_level(irq_ptr->debug_area, DBF_WARN); + DBF_DEV_EVENT(DBF_ERR, irq_ptr, "dbf created"); } static int qstat_show(struct seq_file *m, void *v) @@ -86,16 +60,18 @@ static int qstat_show(struct seq_file *m, void *v) if (!q) return 0; - seq_printf(m, "device state indicator: %d\n", *q->irq_ptr->dsci); + seq_printf(m, "device state indicator: %d\n", *(u32 *)q->irq_ptr->dsci); seq_printf(m, "nr_used: %d\n", atomic_read(&q->nr_buf_used)); seq_printf(m, "ftc: %d\n", q->first_to_check); seq_printf(m, "last_move_ftc: %d\n", q->last_move_ftc); seq_printf(m, "polling: %d\n", q->u.in.polling); + seq_printf(m, "ack count: %d\n", q->u.in.ack_count); seq_printf(m, "slsb buffer states:\n"); + seq_printf(m, "|0 |8 |16 |24 |32 |40 |48 |56 63|\n"); qdio_siga_sync_q(q); for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) { - get_buf_state(q, i, &state); + get_buf_state(q, i, &state, 0); switch (state) { case SLSB_P_INPUT_NOT_INIT: case SLSB_P_OUTPUT_NOT_INIT: @@ -127,6 +103,7 @@ static int qstat_show(struct seq_file *m, void *v) seq_printf(m, "\n"); } seq_printf(m, "\n"); + seq_printf(m, "|64 |72 |80 |88 |96 |104 |112 | 127|\n"); return 0; } @@ -223,11 +200,24 @@ void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cd int __init qdio_debug_init(void) { debugfs_root = debugfs_create_dir("qdio_queues", NULL); - return qdio_register_dbf_views(); + + qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16); + debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view); + debug_set_level(qdio_dbf_setup, DBF_INFO); + DBF_EVENT("dbf created\n"); + + qdio_dbf_error = debug_register("qdio_error", 4, 1, 16); + debug_register_view(qdio_dbf_error, &debug_hex_ascii_view); + debug_set_level(qdio_dbf_error, DBF_INFO); + DBF_ERROR("dbf created\n"); + return 0; } void qdio_debug_exit(void) { debugfs_remove(debugfs_root); - qdio_unregister_dbf_views(); + if (qdio_dbf_setup) + debug_unregister(qdio_dbf_setup); + if (qdio_dbf_error) + debug_unregister(qdio_dbf_error); } diff --git a/drivers/s390/cio/qdio_debug.h b/drivers/s390/cio/qdio_debug.h index 5a4d85b829adf11884f92cac93f9317b7ad4c064..5d70bd162ae9598cc078fbc5c948b4d38fe28d74 100644 --- a/drivers/s390/cio/qdio_debug.h +++ b/drivers/s390/cio/qdio_debug.h @@ -12,80 +12,72 @@ #include #include "qdio.h" -#define QDIO_DBF_HEX(ex, name, level, addr, len) \ +/* that gives us 15 characters in the text event views */ +#define QDIO_DBF_LEN 16 + +extern debug_info_t *qdio_dbf_setup; +extern debug_info_t *qdio_dbf_error; + +/* sort out low debug levels early to avoid wasted sprints */ +static inline int qdio_dbf_passes(debug_info_t *dbf_grp, int level) +{ + return (level <= dbf_grp->level); +} + +#define DBF_ERR 3 /* error conditions */ +#define DBF_WARN 4 /* warning conditions */ +#define DBF_INFO 6 /* informational */ + +#undef DBF_EVENT +#undef DBF_ERROR +#undef DBF_DEV_EVENT + +#define DBF_EVENT(text...) \ do { \ - if (ex) \ - debug_exception(qdio_dbf_##name, level, (void *)(addr), len); \ - else \ - debug_event(qdio_dbf_##name, level, (void *)(addr), len); \ + char debug_buffer[QDIO_DBF_LEN]; \ + snprintf(debug_buffer, QDIO_DBF_LEN, text); \ + debug_text_event(qdio_dbf_setup, DBF_ERR, debug_buffer); \ } while (0) -#define QDIO_DBF_TEXT(ex, name, level, text) \ + +#define DBF_HEX(addr, len) \ do { \ - if (ex) \ - debug_text_exception(qdio_dbf_##name, level, text); \ - else \ - debug_text_event(qdio_dbf_##name, level, text); \ + debug_event(qdio_dbf_setup, DBF_ERR, (void*)(addr), len); \ } while (0) -#define QDIO_DBF_HEX0(ex, name, addr, len) QDIO_DBF_HEX(ex, name, 0, addr, len) -#define QDIO_DBF_HEX1(ex, name, addr, len) QDIO_DBF_HEX(ex, name, 1, addr, len) -#define QDIO_DBF_HEX2(ex, name, addr, len) QDIO_DBF_HEX(ex, name, 2, addr, len) - -#ifdef CONFIG_QDIO_DEBUG -#define QDIO_DBF_HEX3(ex, name, addr, len) QDIO_DBF_HEX(ex, name, 3, addr, len) -#define QDIO_DBF_HEX4(ex, name, addr, len) QDIO_DBF_HEX(ex, name, 4, addr, len) -#define QDIO_DBF_HEX5(ex, name, addr, len) QDIO_DBF_HEX(ex, name, 5, addr, len) -#define QDIO_DBF_HEX6(ex, name, addr, len) QDIO_DBF_HEX(ex, name, 6, addr, len) -#else -#define QDIO_DBF_HEX3(ex, name, addr, len) do {} while (0) -#define QDIO_DBF_HEX4(ex, name, addr, len) do {} while (0) -#define QDIO_DBF_HEX5(ex, name, addr, len) do {} while (0) -#define QDIO_DBF_HEX6(ex, name, addr, len) do {} while (0) -#endif /* CONFIG_QDIO_DEBUG */ - -#define QDIO_DBF_TEXT0(ex, name, text) QDIO_DBF_TEXT(ex, name, 0, text) -#define QDIO_DBF_TEXT1(ex, name, text) QDIO_DBF_TEXT(ex, name, 1, text) -#define QDIO_DBF_TEXT2(ex, name, text) QDIO_DBF_TEXT(ex, name, 2, text) - -#ifdef CONFIG_QDIO_DEBUG -#define QDIO_DBF_TEXT3(ex, name, text) QDIO_DBF_TEXT(ex, name, 3, text) -#define QDIO_DBF_TEXT4(ex, name, text) QDIO_DBF_TEXT(ex, name, 4, text) -#define QDIO_DBF_TEXT5(ex, name, text) QDIO_DBF_TEXT(ex, name, 5, text) -#define QDIO_DBF_TEXT6(ex, name, text) QDIO_DBF_TEXT(ex, name, 6, text) -#else -#define QDIO_DBF_TEXT3(ex, name, text) do {} while (0) -#define QDIO_DBF_TEXT4(ex, name, text) do {} while (0) -#define QDIO_DBF_TEXT5(ex, name, text) do {} while (0) -#define QDIO_DBF_TEXT6(ex, name, text) do {} while (0) -#endif /* CONFIG_QDIO_DEBUG */ +#define DBF_ERROR(text...) \ + do { \ + char debug_buffer[QDIO_DBF_LEN]; \ + snprintf(debug_buffer, QDIO_DBF_LEN, text); \ + debug_text_event(qdio_dbf_error, DBF_ERR, debug_buffer); \ + } while (0) -/* s390dbf views */ -#define QDIO_DBF_SETUP_LEN 8 -#define QDIO_DBF_SETUP_PAGES 8 -#define QDIO_DBF_SETUP_NR_AREAS 1 +#define DBF_ERROR_HEX(addr, len) \ + do { \ + debug_event(qdio_dbf_error, DBF_ERR, (void*)(addr), len); \ + } while (0) -#define QDIO_DBF_TRACE_LEN 8 -#define QDIO_DBF_TRACE_NR_AREAS 2 -#ifdef CONFIG_QDIO_DEBUG -#define QDIO_DBF_TRACE_PAGES 32 -#define QDIO_DBF_SETUP_LEVEL 6 -#define QDIO_DBF_TRACE_LEVEL 4 -#else /* !CONFIG_QDIO_DEBUG */ -#define QDIO_DBF_TRACE_PAGES 8 -#define QDIO_DBF_SETUP_LEVEL 2 -#define QDIO_DBF_TRACE_LEVEL 2 -#endif /* CONFIG_QDIO_DEBUG */ +#define DBF_DEV_EVENT(level, device, text...) \ + do { \ + char debug_buffer[QDIO_DBF_LEN]; \ + if (qdio_dbf_passes(device->debug_area, level)) { \ + snprintf(debug_buffer, QDIO_DBF_LEN, text); \ + debug_text_event(device->debug_area, level, debug_buffer); \ + } \ + } while (0) -extern debug_info_t *qdio_dbf_setup; -extern debug_info_t *qdio_dbf_trace; +#define DBF_DEV_HEX(level, device, addr, len) \ + do { \ + debug_event(device->debug_area, level, (void*)(addr), len); \ + } while (0) -void qdio_allocate_do_dbf(struct qdio_initialize *init_data); -void debug_print_bstat(struct qdio_q *q); +void qdio_allocate_dbf(struct qdio_initialize *init_data, + struct qdio_irq *irq_ptr); void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev); void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev); int qdio_debug_init(void); void qdio_debug_exit(void); + #endif diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 7c8659151993d8acfc12d0f02a0b60eb56c91eff..744f928a59eac4c3df9c3564fef85bece0b88ff3 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -74,7 +74,7 @@ static inline int do_siga_input(struct subchannel_id schid, unsigned int mask) * Note: For IQDC unicast queues only the highest priority queue is processed. */ static inline int do_siga_output(unsigned long schid, unsigned long mask, - u32 *bb, unsigned int fc) + unsigned int *bb, unsigned int fc) { register unsigned long __fc asm("0") = fc; register unsigned long __schid asm("1") = schid; @@ -95,8 +95,6 @@ static inline int do_siga_output(unsigned long schid, unsigned long mask, static inline int qdio_check_ccq(struct qdio_q *q, unsigned int ccq) { - char dbf_text[15]; - /* all done or next buffer state different */ if (ccq == 0 || ccq == 32) return 0; @@ -104,8 +102,7 @@ static inline int qdio_check_ccq(struct qdio_q *q, unsigned int ccq) if (ccq == 96 || ccq == 97) return 1; /* notify devices immediately */ - sprintf(dbf_text, "%d", ccq); - QDIO_DBF_TEXT2(1, trace, dbf_text); + DBF_ERROR("%4x ccq:%3d", SCH_NO(q), ccq); return -EIO; } @@ -115,41 +112,45 @@ static inline int qdio_check_ccq(struct qdio_q *q, unsigned int ccq) * @state: state of the extracted buffers * @start: buffer number to start at * @count: count of buffers to examine + * @auto_ack: automatically acknowledge buffers * * Returns the number of successfull extracted equal buffer states. * Stops processing if a state is different from the last buffers state. */ static int qdio_do_eqbs(struct qdio_q *q, unsigned char *state, - int start, int count) + int start, int count, int auto_ack) { unsigned int ccq = 0; int tmp_count = count, tmp_start = start; int nr = q->nr; int rc; - char dbf_text[15]; BUG_ON(!q->irq_ptr->sch_token); + qdio_perf_stat_inc(&perf_stats.debug_eqbs_all); if (!q->is_input_q) nr += q->irq_ptr->nr_input_qs; again: - ccq = do_eqbs(q->irq_ptr->sch_token, state, nr, &tmp_start, &tmp_count); + ccq = do_eqbs(q->irq_ptr->sch_token, state, nr, &tmp_start, &tmp_count, + auto_ack); rc = qdio_check_ccq(q, ccq); /* At least one buffer was processed, return and extract the remaining * buffers later. */ - if ((ccq == 96) && (count != tmp_count)) + if ((ccq == 96) && (count != tmp_count)) { + qdio_perf_stat_inc(&perf_stats.debug_eqbs_incomplete); return (count - tmp_count); + } + if (rc == 1) { - QDIO_DBF_TEXT5(1, trace, "eqAGAIN"); + DBF_DEV_EVENT(DBF_WARN, q->irq_ptr, "EQBS again:%2d", ccq); goto again; } if (rc < 0) { - QDIO_DBF_TEXT2(1, trace, "eqberr"); - sprintf(dbf_text, "%2x,%2x,%d,%d", count, tmp_count, ccq, nr); - QDIO_DBF_TEXT2(1, trace, dbf_text); + DBF_ERROR("%4x EQBS ERROR", SCH_NO(q)); + DBF_ERROR("%3d%3d%2d", count, tmp_count, nr); q->handler(q->irq_ptr->cdev, QDIO_ERROR_ACTIVATE_CHECK_CONDITION, 0, -1, -1, q->irq_ptr->int_parm); @@ -176,9 +177,12 @@ static int qdio_do_sqbs(struct qdio_q *q, unsigned char state, int start, int tmp_count = count, tmp_start = start; int nr = q->nr; int rc; - char dbf_text[15]; + + if (!count) + return 0; BUG_ON(!q->irq_ptr->sch_token); + qdio_perf_stat_inc(&perf_stats.debug_sqbs_all); if (!q->is_input_q) nr += q->irq_ptr->nr_input_qs; @@ -186,16 +190,13 @@ static int qdio_do_sqbs(struct qdio_q *q, unsigned char state, int start, ccq = do_sqbs(q->irq_ptr->sch_token, state, nr, &tmp_start, &tmp_count); rc = qdio_check_ccq(q, ccq); if (rc == 1) { - QDIO_DBF_TEXT5(1, trace, "sqAGAIN"); + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "SQBS again:%2d", ccq); + qdio_perf_stat_inc(&perf_stats.debug_sqbs_incomplete); goto again; } if (rc < 0) { - QDIO_DBF_TEXT3(1, trace, "sqberr"); - sprintf(dbf_text, "%2x,%2x", count, tmp_count); - QDIO_DBF_TEXT3(1, trace, dbf_text); - sprintf(dbf_text, "%d,%d", ccq, nr); - QDIO_DBF_TEXT3(1, trace, dbf_text); - + DBF_ERROR("%4x SQBS ERROR", SCH_NO(q)); + DBF_ERROR("%3d%3d%2d", count, tmp_count, nr); q->handler(q->irq_ptr->cdev, QDIO_ERROR_ACTIVATE_CHECK_CONDITION, 0, -1, -1, q->irq_ptr->int_parm); @@ -207,7 +208,8 @@ static int qdio_do_sqbs(struct qdio_q *q, unsigned char state, int start, /* returns number of examined buffers and their common state in *state */ static inline int get_buf_states(struct qdio_q *q, unsigned int bufnr, - unsigned char *state, unsigned int count) + unsigned char *state, unsigned int count, + int auto_ack) { unsigned char __state = 0; int i; @@ -216,7 +218,7 @@ static inline int get_buf_states(struct qdio_q *q, unsigned int bufnr, BUG_ON(count > QDIO_MAX_BUFFERS_PER_Q); if (is_qebsm(q)) - return qdio_do_eqbs(q, state, bufnr, count); + return qdio_do_eqbs(q, state, bufnr, count, auto_ack); for (i = 0; i < count; i++) { if (!__state) @@ -230,9 +232,9 @@ static inline int get_buf_states(struct qdio_q *q, unsigned int bufnr, } inline int get_buf_state(struct qdio_q *q, unsigned int bufnr, - unsigned char *state) + unsigned char *state, int auto_ack) { - return get_buf_states(q, bufnr, state, 1); + return get_buf_states(q, bufnr, state, 1, auto_ack); } /* wrap-around safe setting of slsb states, returns number of changed buffers */ @@ -282,14 +284,12 @@ static int qdio_siga_sync(struct qdio_q *q, unsigned int output, if (!need_siga_sync(q)) return 0; + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-s:%1d", q->nr); qdio_perf_stat_inc(&perf_stats.siga_sync); cc = do_siga_sync(q->irq_ptr->schid, output, input); - if (cc) { - QDIO_DBF_TEXT4(0, trace, "sigasync"); - QDIO_DBF_HEX4(0, trace, &q, sizeof(void *)); - QDIO_DBF_HEX3(0, trace, &cc, sizeof(int *)); - } + if (cc) + DBF_ERROR("%4x SIGA-S:%2d", SCH_NO(q), cc); return cc; } @@ -311,50 +311,37 @@ static inline int qdio_siga_sync_all(struct qdio_q *q) return qdio_siga_sync(q, ~0U, ~0U); } -static inline int qdio_do_siga_output(struct qdio_q *q, unsigned int *busy_bit) +static int qdio_siga_output(struct qdio_q *q, unsigned int *busy_bit) { - unsigned int fc = 0; unsigned long schid; + unsigned int fc = 0; + u64 start_time = 0; + int cc; - if (q->u.out.use_enh_siga) { + if (q->u.out.use_enh_siga) fc = 3; - } - if (!is_qebsm(q)) - schid = *((u32 *)&q->irq_ptr->schid); - else { + + if (is_qebsm(q)) { schid = q->irq_ptr->sch_token; fc |= 0x80; } - return do_siga_output(schid, q->mask, busy_bit, fc); -} - -static int qdio_siga_output(struct qdio_q *q) -{ - int cc; - u32 busy_bit; - u64 start_time = 0; - char dbf_text[15]; - - QDIO_DBF_TEXT5(0, trace, "sigaout"); - QDIO_DBF_HEX5(0, trace, &q, sizeof(void *)); + else + schid = *((u32 *)&q->irq_ptr->schid); - qdio_perf_stat_inc(&perf_stats.siga_out); again: - cc = qdio_do_siga_output(q, &busy_bit); - if (queue_type(q) == QDIO_IQDIO_QFMT && cc == 2 && busy_bit) { - sprintf(dbf_text, "bb%4x%2x", q->irq_ptr->schid.sch_no, q->nr); - QDIO_DBF_TEXT3(0, trace, dbf_text); + cc = do_siga_output(schid, q->mask, busy_bit, fc); - if (!start_time) + /* hipersocket busy condition */ + if (*busy_bit) { + WARN_ON(queue_type(q) != QDIO_IQDIO_QFMT || cc != 2); + + if (!start_time) { start_time = get_usecs(); - else if ((get_usecs() - start_time) < QDIO_BUSY_BIT_PATIENCE) + goto again; + } + if ((get_usecs() - start_time) < QDIO_BUSY_BIT_PATIENCE) goto again; } - - if (cc == 2 && busy_bit) - cc |= QDIO_ERROR_SIGA_BUSY; - if (cc) - QDIO_DBF_HEX3(0, trace, &cc, sizeof(int *)); return cc; } @@ -362,14 +349,12 @@ static inline int qdio_siga_input(struct qdio_q *q) { int cc; - QDIO_DBF_TEXT4(0, trace, "sigain"); - QDIO_DBF_HEX4(0, trace, &q, sizeof(void *)); - + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-r:%1d", q->nr); qdio_perf_stat_inc(&perf_stats.siga_in); cc = do_siga_input(q->irq_ptr->schid, q->mask); if (cc) - QDIO_DBF_HEX3(0, trace, &cc, sizeof(int *)); + DBF_ERROR("%4x SIGA-R:%2d", SCH_NO(q), cc); return cc; } @@ -387,35 +372,91 @@ void qdio_sync_after_thinint(struct qdio_q *q) inline void qdio_stop_polling(struct qdio_q *q) { - spin_lock_bh(&q->u.in.lock); - if (!q->u.in.polling) { - spin_unlock_bh(&q->u.in.lock); + if (!q->u.in.polling) return; - } + q->u.in.polling = 0; qdio_perf_stat_inc(&perf_stats.debug_stop_polling); /* show the card that we are not polling anymore */ - set_buf_state(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT); - spin_unlock_bh(&q->u.in.lock); + if (is_qebsm(q)) { + set_buf_states(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT, + q->u.in.ack_count); + q->u.in.ack_count = 0; + } else + set_buf_state(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT); } -static void announce_buffer_error(struct qdio_q *q) +static void announce_buffer_error(struct qdio_q *q, int count) { - char dbf_text[15]; + q->qdio_error |= QDIO_ERROR_SLSB_STATE; + + /* special handling for no target buffer empty */ + if ((!q->is_input_q && + (q->sbal[q->first_to_check]->element[15].flags & 0xff) == 0x10)) { + qdio_perf_stat_inc(&perf_stats.outbound_target_full); + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "OUTFULL FTC:%3d", + q->first_to_check); + return; + } - if (q->is_input_q) - QDIO_DBF_TEXT3(1, trace, "inperr"); - else - QDIO_DBF_TEXT3(0, trace, "outperr"); + DBF_ERROR("%4x BUF ERROR", SCH_NO(q)); + DBF_ERROR((q->is_input_q) ? "IN:%2d" : "OUT:%2d", q->nr); + DBF_ERROR("FTC:%3d C:%3d", q->first_to_check, count); + DBF_ERROR("F14:%2x F15:%2x", + q->sbal[q->first_to_check]->element[14].flags & 0xff, + q->sbal[q->first_to_check]->element[15].flags & 0xff); +} + +static inline void inbound_primed(struct qdio_q *q, int count) +{ + int new; + + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in prim: %3d", count); + + /* for QEBSM the ACK was already set by EQBS */ + if (is_qebsm(q)) { + if (!q->u.in.polling) { + q->u.in.polling = 1; + q->u.in.ack_count = count; + q->last_move_ftc = q->first_to_check; + return; + } + + /* delete the previous ACK's */ + set_buf_states(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT, + q->u.in.ack_count); + q->u.in.ack_count = count; + q->last_move_ftc = q->first_to_check; + return; + } + + /* + * ACK the newest buffer. The ACK will be removed in qdio_stop_polling + * or by the next inbound run. + */ + new = add_buf(q->first_to_check, count - 1); + if (q->u.in.polling) { + /* reset the previous ACK but first set the new one */ + set_buf_state(q, new, SLSB_P_INPUT_ACK); + set_buf_state(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT); + } + else { + q->u.in.polling = 1; + set_buf_state(q, q->first_to_check, SLSB_P_INPUT_ACK); + } - sprintf(dbf_text, "%x-%x-%x", q->first_to_check, - q->sbal[q->first_to_check]->element[14].flags, - q->sbal[q->first_to_check]->element[15].flags); - QDIO_DBF_TEXT3(1, trace, dbf_text); - QDIO_DBF_HEX2(1, trace, q->sbal[q->first_to_check], 256); + q->last_move_ftc = new; + count--; + if (!count) + return; - q->qdio_error = QDIO_ERROR_SLSB_STATE; + /* + * Need to change all PRIMED buffers to NOT_INIT, otherwise + * we're loosing initiative in the thinint code. + */ + set_buf_states(q, next_buf(q->first_to_check), SLSB_P_INPUT_NOT_INIT, + count); } static int get_inbound_buffer_frontier(struct qdio_q *q) @@ -423,13 +464,6 @@ static int get_inbound_buffer_frontier(struct qdio_q *q) int count, stop; unsigned char state; - /* - * If we still poll don't update last_move_ftc, keep the - * previously ACK buffer there. - */ - if (!q->u.in.polling) - q->last_move_ftc = q->first_to_check; - /* * Don't check 128 buffers, as otherwise qdio_inbound_q_moved * would return 0. @@ -450,34 +484,13 @@ static int get_inbound_buffer_frontier(struct qdio_q *q) if (q->first_to_check == stop) goto out; - count = get_buf_states(q, q->first_to_check, &state, count); + count = get_buf_states(q, q->first_to_check, &state, count, 1); if (!count) goto out; switch (state) { case SLSB_P_INPUT_PRIMED: - QDIO_DBF_TEXT5(0, trace, "inptprim"); - - /* - * Only ACK the first buffer. The ACK will be removed in - * qdio_stop_polling. - */ - if (q->u.in.polling) - state = SLSB_P_INPUT_NOT_INIT; - else { - q->u.in.polling = 1; - state = SLSB_P_INPUT_ACK; - } - set_buf_state(q, q->first_to_check, state); - - /* - * Need to change all PRIMED buffers to NOT_INIT, otherwise - * we're loosing initiative in the thinint code. - */ - if (count > 1) - set_buf_states(q, next_buf(q->first_to_check), - SLSB_P_INPUT_NOT_INIT, count - 1); - + inbound_primed(q, count); /* * No siga-sync needed for non-qebsm here, as the inbound queue * will be synced on the next siga-r, resp. @@ -487,7 +500,7 @@ static int get_inbound_buffer_frontier(struct qdio_q *q) atomic_sub(count, &q->nr_buf_used); goto check_next; case SLSB_P_INPUT_ERROR: - announce_buffer_error(q); + announce_buffer_error(q, count); /* process the buffer, the upper layer will take care of it */ q->first_to_check = add_buf(q->first_to_check, count); atomic_sub(count, &q->nr_buf_used); @@ -495,13 +508,12 @@ static int get_inbound_buffer_frontier(struct qdio_q *q) case SLSB_CU_INPUT_EMPTY: case SLSB_P_INPUT_NOT_INIT: case SLSB_P_INPUT_ACK: - QDIO_DBF_TEXT5(0, trace, "inpnipro"); + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in nop"); break; default: BUG(); } out: - QDIO_DBF_HEX4(0, trace, &q->first_to_check, sizeof(int)); return q->first_to_check; } @@ -515,8 +527,7 @@ int qdio_inbound_q_moved(struct qdio_q *q) if (!need_siga_sync(q) && !pci_out_supported(q)) q->u.in.timestamp = get_usecs(); - QDIO_DBF_TEXT4(0, trace, "inhasmvd"); - QDIO_DBF_HEX4(0, trace, &q, sizeof(void *)); + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in moved"); return 1; } else return 0; @@ -524,10 +535,7 @@ int qdio_inbound_q_moved(struct qdio_q *q) static int qdio_inbound_q_done(struct qdio_q *q) { - unsigned char state; -#ifdef CONFIG_QDIO_DEBUG - char dbf_text[15]; -#endif + unsigned char state = 0; if (!atomic_read(&q->nr_buf_used)) return 1; @@ -538,7 +546,7 @@ static int qdio_inbound_q_done(struct qdio_q *q) */ qdio_siga_sync_q(q); - get_buf_state(q, q->first_to_check, &state); + get_buf_state(q, q->first_to_check, &state, 0); if (state == SLSB_P_INPUT_PRIMED) /* we got something to do */ return 0; @@ -552,20 +560,12 @@ static int qdio_inbound_q_done(struct qdio_q *q) * has (probably) not moved (see qdio_inbound_processing). */ if (get_usecs() > q->u.in.timestamp + QDIO_INPUT_THRESHOLD) { -#ifdef CONFIG_QDIO_DEBUG - QDIO_DBF_TEXT4(0, trace, "inqisdon"); - QDIO_DBF_HEX4(0, trace, &q, sizeof(void *)); - sprintf(dbf_text, "pf%02x", q->first_to_check); - QDIO_DBF_TEXT4(0, trace, dbf_text); -#endif /* CONFIG_QDIO_DEBUG */ + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in done:%3d", + q->first_to_check); return 1; } else { -#ifdef CONFIG_QDIO_DEBUG - QDIO_DBF_TEXT4(0, trace, "inqisntd"); - QDIO_DBF_HEX4(0, trace, &q, sizeof(void *)); - sprintf(dbf_text, "pf%02x", q->first_to_check); - QDIO_DBF_TEXT4(0, trace, dbf_text); -#endif /* CONFIG_QDIO_DEBUG */ + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in notd:%3d", + q->first_to_check); return 0; } } @@ -573,9 +573,6 @@ static int qdio_inbound_q_done(struct qdio_q *q) void qdio_kick_inbound_handler(struct qdio_q *q) { int count, start, end; -#ifdef CONFIG_QDIO_DEBUG - char dbf_text[15]; -#endif qdio_perf_stat_inc(&perf_stats.inbound_handler); @@ -586,10 +583,7 @@ void qdio_kick_inbound_handler(struct qdio_q *q) else count = end + QDIO_MAX_BUFFERS_PER_Q - start; -#ifdef CONFIG_QDIO_DEBUG - sprintf(dbf_text, "s=%2xc=%2x", start, count); - QDIO_DBF_TEXT4(0, trace, dbf_text); -#endif /* CONFIG_QDIO_DEBUG */ + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kih s:%3d c:%3d", start, count); if (unlikely(q->irq_ptr->state != QDIO_IRQ_STATE_ACTIVE)) return; @@ -655,14 +649,14 @@ static int get_outbound_buffer_frontier(struct qdio_q *q) if (q->first_to_check == stop) return q->first_to_check; - count = get_buf_states(q, q->first_to_check, &state, count); + count = get_buf_states(q, q->first_to_check, &state, count, 0); if (!count) return q->first_to_check; switch (state) { case SLSB_P_OUTPUT_EMPTY: /* the adapter got it */ - QDIO_DBF_TEXT5(0, trace, "outpempt"); + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out empty:%1d %3d", q->nr, count); atomic_sub(count, &q->nr_buf_used); q->first_to_check = add_buf(q->first_to_check, count); @@ -674,14 +668,14 @@ static int get_outbound_buffer_frontier(struct qdio_q *q) break; goto check_next; case SLSB_P_OUTPUT_ERROR: - announce_buffer_error(q); + announce_buffer_error(q, count); /* process the buffer, the upper layer will take care of it */ q->first_to_check = add_buf(q->first_to_check, count); atomic_sub(count, &q->nr_buf_used); break; case SLSB_CU_OUTPUT_PRIMED: /* the adapter has not fetched the output yet */ - QDIO_DBF_TEXT5(0, trace, "outpprim"); + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out primed:%1d", q->nr); break; case SLSB_P_OUTPUT_NOT_INIT: case SLSB_P_OUTPUT_HALTED: @@ -706,99 +700,48 @@ static inline int qdio_outbound_q_moved(struct qdio_q *q) if ((bufnr != q->last_move_ftc) || q->qdio_error) { q->last_move_ftc = bufnr; - QDIO_DBF_TEXT4(0, trace, "oqhasmvd"); - QDIO_DBF_HEX4(0, trace, &q, sizeof(void *)); + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out moved:%1d", q->nr); return 1; } else return 0; } -/* - * VM could present us cc=2 and busy bit set on SIGA-write - * during reconfiguration of their Guest LAN (only in iqdio mode, - * otherwise qdio is asynchronous and cc=2 and busy bit there will take - * the queues down immediately). - * - * Therefore qdio_siga_output will try for a short time constantly, - * if such a condition occurs. If it doesn't change, it will - * increase the busy_siga_counter and save the timestamp, and - * schedule the queue for later processing. qdio_outbound_processing - * will check out the counter. If non-zero, it will call qdio_kick_outbound_q - * as often as the value of the counter. This will attempt further SIGA - * instructions. For each successful SIGA, the counter is - * decreased, for failing SIGAs the counter remains the same, after - * all. After some time of no movement, qdio_kick_outbound_q will - * finally fail and reflect corresponding error codes to call - * the upper layer module and have it take the queues down. - * - * Note that this is a change from the original HiperSockets design - * (saying cc=2 and busy bit means take the queues down), but in - * these days Guest LAN didn't exist... excessive cc=2 with busy bit - * conditions will still take the queues down, but the threshold is - * higher due to the Guest LAN environment. - * - * Called from outbound tasklet and do_QDIO handler. - */ static void qdio_kick_outbound_q(struct qdio_q *q) { - int rc; -#ifdef CONFIG_QDIO_DEBUG - char dbf_text[15]; - - QDIO_DBF_TEXT5(0, trace, "kickoutq"); - QDIO_DBF_HEX5(0, trace, &q, sizeof(void *)); -#endif /* CONFIG_QDIO_DEBUG */ + unsigned int busy_bit; + int cc; if (!need_siga_out(q)) return; - rc = qdio_siga_output(q); - switch (rc) { + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w:%1d", q->nr); + qdio_perf_stat_inc(&perf_stats.siga_out); + + cc = qdio_siga_output(q, &busy_bit); + switch (cc) { case 0: - /* TODO: improve error handling for CC=0 case */ -#ifdef CONFIG_QDIO_DEBUG - if (q->u.out.timestamp) { - QDIO_DBF_TEXT3(0, trace, "cc2reslv"); - sprintf(dbf_text, "%4x%2x%2x", q->irq_ptr->schid.sch_no, - q->nr, - atomic_read(&q->u.out.busy_siga_counter)); - QDIO_DBF_TEXT3(0, trace, dbf_text); - } -#endif /* CONFIG_QDIO_DEBUG */ - /* went smooth this time, reset timestamp */ - q->u.out.timestamp = 0; break; - /* cc=2 and busy bit */ - case (2 | QDIO_ERROR_SIGA_BUSY): - atomic_inc(&q->u.out.busy_siga_counter); - - /* if the last siga was successful, save timestamp here */ - if (!q->u.out.timestamp) - q->u.out.timestamp = get_usecs(); - - /* if we're in time, don't touch qdio_error */ - if (get_usecs() - q->u.out.timestamp < QDIO_BUSY_BIT_GIVE_UP) { - tasklet_schedule(&q->tasklet); - break; + case 2: + if (busy_bit) { + DBF_ERROR("%4x cc2 REP:%1d", SCH_NO(q), q->nr); + q->qdio_error = cc | QDIO_ERROR_SIGA_BUSY; + } else { + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w cc2:%1d", + q->nr); + q->qdio_error = cc; } - QDIO_DBF_TEXT2(0, trace, "cc2REPRT"); -#ifdef CONFIG_QDIO_DEBUG - sprintf(dbf_text, "%4x%2x%2x", q->irq_ptr->schid.sch_no, q->nr, - atomic_read(&q->u.out.busy_siga_counter)); - QDIO_DBF_TEXT3(0, trace, dbf_text); -#endif /* CONFIG_QDIO_DEBUG */ - default: - /* for plain cc=1, 2 or 3 */ - q->qdio_error = rc; + break; + case 1: + case 3: + DBF_ERROR("%4x SIGA-W:%1d", SCH_NO(q), cc); + q->qdio_error = cc; + break; } } static void qdio_kick_outbound_handler(struct qdio_q *q) { int start, end, count; -#ifdef CONFIG_QDIO_DEBUG - char dbf_text[15]; -#endif start = q->first_to_kick; end = q->last_move_ftc; @@ -807,13 +750,8 @@ static void qdio_kick_outbound_handler(struct qdio_q *q) else count = end + QDIO_MAX_BUFFERS_PER_Q - start; -#ifdef CONFIG_QDIO_DEBUG - QDIO_DBF_TEXT4(0, trace, "kickouth"); - QDIO_DBF_HEX4(0, trace, &q, sizeof(void *)); - - sprintf(dbf_text, "s=%2xc=%2x", start, count); - QDIO_DBF_TEXT4(0, trace, dbf_text); -#endif /* CONFIG_QDIO_DEBUG */ + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kickouth: %1d", q->nr); + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "s:%3d c:%3d", start, count); if (unlikely(q->irq_ptr->state != QDIO_IRQ_STATE_ACTIVE)) return; @@ -828,22 +766,18 @@ static void qdio_kick_outbound_handler(struct qdio_q *q) static void __qdio_outbound_processing(struct qdio_q *q) { - int siga_attempts; + unsigned long flags; qdio_perf_stat_inc(&perf_stats.tasklet_outbound); - - /* see comment in qdio_kick_outbound_q */ - siga_attempts = atomic_read(&q->u.out.busy_siga_counter); - while (siga_attempts--) { - atomic_dec(&q->u.out.busy_siga_counter); - qdio_kick_outbound_q(q); - } + spin_lock_irqsave(&q->lock, flags); BUG_ON(atomic_read(&q->nr_buf_used) < 0); if (qdio_outbound_q_moved(q)) qdio_kick_outbound_handler(q); + spin_unlock_irqrestore(&q->lock, flags); + if (queue_type(q) == QDIO_ZFCP_QFMT) { if (!pci_out_supported(q) && !qdio_outbound_q_done(q)) tasklet_schedule(&q->tasklet); @@ -908,27 +842,18 @@ void qdio_check_outbound_after_thinint(struct qdio_q *q) static inline void qdio_set_state(struct qdio_irq *irq_ptr, enum qdio_irq_states state) { -#ifdef CONFIG_QDIO_DEBUG - char dbf_text[15]; - - QDIO_DBF_TEXT5(0, trace, "newstate"); - sprintf(dbf_text, "%4x%4x", irq_ptr->schid.sch_no, state); - QDIO_DBF_TEXT5(0, trace, dbf_text); -#endif /* CONFIG_QDIO_DEBUG */ + DBF_DEV_EVENT(DBF_INFO, irq_ptr, "newstate: %1d", state); irq_ptr->state = state; mb(); } -static void qdio_irq_check_sense(struct subchannel_id schid, struct irb *irb) +static void qdio_irq_check_sense(struct qdio_irq *irq_ptr, struct irb *irb) { - char dbf_text[15]; - if (irb->esw.esw0.erw.cons) { - sprintf(dbf_text, "sens%4x", schid.sch_no); - QDIO_DBF_TEXT2(1, trace, dbf_text); - QDIO_DBF_HEX0(0, trace, irb, 64); - QDIO_DBF_HEX0(0, trace, irb->ecw, 64); + DBF_ERROR("%4x sense:", irq_ptr->schid.sch_no); + DBF_ERROR_HEX(irb, 64); + DBF_ERROR_HEX(irb->ecw, 64); } } @@ -962,14 +887,10 @@ static void qdio_handle_activate_check(struct ccw_device *cdev, { struct qdio_irq *irq_ptr = cdev->private->qdio_data; struct qdio_q *q; - char dbf_text[15]; - QDIO_DBF_TEXT2(1, trace, "ick2"); - sprintf(dbf_text, "%s", dev_name(&cdev->dev)); - QDIO_DBF_TEXT2(1, trace, dbf_text); - QDIO_DBF_HEX2(0, trace, &intparm, sizeof(int)); - QDIO_DBF_HEX2(0, trace, &dstat, sizeof(int)); - QDIO_DBF_HEX2(0, trace, &cstat, sizeof(int)); + DBF_ERROR("%4x ACT CHECK", irq_ptr->schid.sch_no); + DBF_ERROR("intp :%lx", intparm); + DBF_ERROR("ds: %2x cs:%2x", dstat, cstat); if (irq_ptr->nr_input_qs) { q = irq_ptr->input_qs[0]; @@ -1022,28 +943,29 @@ static void qdio_int_error(struct ccw_device *cdev) } static int qdio_establish_check_errors(struct ccw_device *cdev, int cstat, - int dstat) + int dstat) { struct qdio_irq *irq_ptr = cdev->private->qdio_data; if (cstat || (dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END))) { - QDIO_DBF_TEXT2(1, setup, "eq:ckcon"); + DBF_ERROR("EQ:ck con"); goto error; } if (!(dstat & DEV_STAT_DEV_END)) { - QDIO_DBF_TEXT2(1, setup, "eq:no de"); + DBF_ERROR("EQ:no dev"); goto error; } if (dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) { - QDIO_DBF_TEXT2(1, setup, "eq:badio"); + DBF_ERROR("EQ: bad io"); goto error; } return 0; error: - QDIO_DBF_HEX2(0, trace, &cstat, sizeof(int)); - QDIO_DBF_HEX2(0, trace, &dstat, sizeof(int)); + DBF_ERROR("%4x EQ:error", irq_ptr->schid.sch_no); + DBF_ERROR("ds: %2x cs:%2x", dstat, cstat); + qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ERR); return 1; } @@ -1052,12 +974,8 @@ static void qdio_establish_handle_irq(struct ccw_device *cdev, int cstat, int dstat) { struct qdio_irq *irq_ptr = cdev->private->qdio_data; - char dbf_text[15]; - - sprintf(dbf_text, "qehi%4x", cdev->private->schid.sch_no); - QDIO_DBF_TEXT0(0, setup, dbf_text); - QDIO_DBF_TEXT0(0, trace, dbf_text); + DBF_DEV_EVENT(DBF_INFO, irq_ptr, "qest irq"); if (!qdio_establish_check_errors(cdev, cstat, dstat)) qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ESTABLISHED); } @@ -1068,25 +986,21 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm, { struct qdio_irq *irq_ptr = cdev->private->qdio_data; int cstat, dstat; - char dbf_text[15]; qdio_perf_stat_inc(&perf_stats.qdio_int); if (!intparm || !irq_ptr) { - sprintf(dbf_text, "qihd%4x", cdev->private->schid.sch_no); - QDIO_DBF_TEXT2(1, setup, dbf_text); + DBF_ERROR("qint:%4x", cdev->private->schid.sch_no); return; } if (IS_ERR(irb)) { switch (PTR_ERR(irb)) { case -EIO: - sprintf(dbf_text, "ierr%4x", irq_ptr->schid.sch_no); - QDIO_DBF_TEXT2(1, setup, dbf_text); + DBF_ERROR("%4x IO error", irq_ptr->schid.sch_no); return; case -ETIMEDOUT: - sprintf(dbf_text, "qtoh%4x", irq_ptr->schid.sch_no); - QDIO_DBF_TEXT2(1, setup, dbf_text); + DBF_ERROR("%4x IO timeout", irq_ptr->schid.sch_no); qdio_int_error(cdev); return; default: @@ -1094,7 +1008,7 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm, return; } } - qdio_irq_check_sense(irq_ptr->schid, irb); + qdio_irq_check_sense(irq_ptr, irb); cstat = irb->scsw.cmd.cstat; dstat = irb->scsw.cmd.dstat; @@ -1129,23 +1043,20 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm, /** * qdio_get_ssqd_desc - get qdio subchannel description * @cdev: ccw device to get description for + * @data: where to store the ssqd * - * Returns a pointer to the saved qdio subchannel description, - * or NULL for not setup qdio devices. + * Returns 0 or an error code. The results of the chsc are stored in the + * specified structure. */ -struct qdio_ssqd_desc *qdio_get_ssqd_desc(struct ccw_device *cdev) +int qdio_get_ssqd_desc(struct ccw_device *cdev, + struct qdio_ssqd_desc *data) { - struct qdio_irq *irq_ptr; - char dbf_text[15]; - - sprintf(dbf_text, "qssq%4x", cdev->private->schid.sch_no); - QDIO_DBF_TEXT0(0, setup, dbf_text); - irq_ptr = cdev->private->qdio_data; - if (!irq_ptr) - return NULL; + if (!cdev || !cdev->private) + return -EINVAL; - return &irq_ptr->ssqd_desc; + DBF_EVENT("get ssqd:%4x", cdev->private->schid.sch_no); + return qdio_setup_get_ssqd(NULL, &cdev->private->schid, data); } EXPORT_SYMBOL_GPL(qdio_get_ssqd_desc); @@ -1159,14 +1070,9 @@ EXPORT_SYMBOL_GPL(qdio_get_ssqd_desc); */ int qdio_cleanup(struct ccw_device *cdev, int how) { - struct qdio_irq *irq_ptr; - char dbf_text[15]; + struct qdio_irq *irq_ptr = cdev->private->qdio_data; int rc; - sprintf(dbf_text, "qcln%4x", cdev->private->schid.sch_no); - QDIO_DBF_TEXT0(0, setup, dbf_text); - - irq_ptr = cdev->private->qdio_data; if (!irq_ptr) return -ENODEV; @@ -1199,18 +1105,15 @@ static void qdio_shutdown_queues(struct ccw_device *cdev) */ int qdio_shutdown(struct ccw_device *cdev, int how) { - struct qdio_irq *irq_ptr; + struct qdio_irq *irq_ptr = cdev->private->qdio_data; int rc; unsigned long flags; - char dbf_text[15]; - sprintf(dbf_text, "qshu%4x", cdev->private->schid.sch_no); - QDIO_DBF_TEXT0(0, setup, dbf_text); - - irq_ptr = cdev->private->qdio_data; if (!irq_ptr) return -ENODEV; + DBF_EVENT("qshutdown:%4x", cdev->private->schid.sch_no); + mutex_lock(&irq_ptr->setup_mutex); /* * Subchannel was already shot down. We cannot prevent being called @@ -1234,10 +1137,8 @@ int qdio_shutdown(struct ccw_device *cdev, int how) /* default behaviour is halt */ rc = ccw_device_halt(cdev, QDIO_DOING_CLEANUP); if (rc) { - sprintf(dbf_text, "sher%4x", irq_ptr->schid.sch_no); - QDIO_DBF_TEXT0(0, setup, dbf_text); - sprintf(dbf_text, "rc=%d", rc); - QDIO_DBF_TEXT0(0, setup, dbf_text); + DBF_ERROR("%4x SHUTD ERR", irq_ptr->schid.sch_no); + DBF_ERROR("rc:%4d", rc); goto no_cleanup; } @@ -1271,17 +1172,18 @@ EXPORT_SYMBOL_GPL(qdio_shutdown); */ int qdio_free(struct ccw_device *cdev) { - struct qdio_irq *irq_ptr; - char dbf_text[15]; - - sprintf(dbf_text, "qfre%4x", cdev->private->schid.sch_no); - QDIO_DBF_TEXT0(0, setup, dbf_text); + struct qdio_irq *irq_ptr = cdev->private->qdio_data; - irq_ptr = cdev->private->qdio_data; if (!irq_ptr) return -ENODEV; + DBF_EVENT("qfree:%4x", cdev->private->schid.sch_no); mutex_lock(&irq_ptr->setup_mutex); + + if (irq_ptr->debug_area != NULL) { + debug_unregister(irq_ptr->debug_area); + irq_ptr->debug_area = NULL; + } cdev->private->qdio_data = NULL; mutex_unlock(&irq_ptr->setup_mutex); @@ -1300,10 +1202,6 @@ EXPORT_SYMBOL_GPL(qdio_free); int qdio_initialize(struct qdio_initialize *init_data) { int rc; - char dbf_text[15]; - - sprintf(dbf_text, "qini%4x", init_data->cdev->private->schid.sch_no); - QDIO_DBF_TEXT0(0, setup, dbf_text); rc = qdio_allocate(init_data); if (rc) @@ -1323,10 +1221,8 @@ EXPORT_SYMBOL_GPL(qdio_initialize); int qdio_allocate(struct qdio_initialize *init_data) { struct qdio_irq *irq_ptr; - char dbf_text[15]; - sprintf(dbf_text, "qalc%4x", init_data->cdev->private->schid.sch_no); - QDIO_DBF_TEXT0(0, setup, dbf_text); + DBF_EVENT("qallocate:%4x", init_data->cdev->private->schid.sch_no); if ((init_data->no_input_qs && !init_data->input_handler) || (init_data->no_output_qs && !init_data->output_handler)) @@ -1340,16 +1236,13 @@ int qdio_allocate(struct qdio_initialize *init_data) (!init_data->output_sbal_addr_array)) return -EINVAL; - qdio_allocate_do_dbf(init_data); - /* irq_ptr must be in GFP_DMA since it contains ccw1.cda */ irq_ptr = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); if (!irq_ptr) goto out_err; - QDIO_DBF_TEXT0(0, setup, "irq_ptr:"); - QDIO_DBF_HEX0(0, setup, &irq_ptr, sizeof(void *)); mutex_init(&irq_ptr->setup_mutex); + qdio_allocate_dbf(init_data, irq_ptr); /* * Allocate a page for the chsc calls in qdio_establish. @@ -1367,9 +1260,6 @@ int qdio_allocate(struct qdio_initialize *init_data) goto out_rel; WARN_ON((unsigned long)irq_ptr->qdr & 0xfff); - QDIO_DBF_TEXT0(0, setup, "qdr:"); - QDIO_DBF_HEX0(0, setup, &irq_ptr->qdr, sizeof(void *)); - if (qdio_allocate_qs(irq_ptr, init_data->no_input_qs, init_data->no_output_qs)) goto out_rel; @@ -1390,14 +1280,12 @@ EXPORT_SYMBOL_GPL(qdio_allocate); */ int qdio_establish(struct qdio_initialize *init_data) { - char dbf_text[20]; struct qdio_irq *irq_ptr; struct ccw_device *cdev = init_data->cdev; unsigned long saveflags; int rc; - sprintf(dbf_text, "qest%4x", cdev->private->schid.sch_no); - QDIO_DBF_TEXT0(0, setup, dbf_text); + DBF_EVENT("qestablish:%4x", cdev->private->schid.sch_no); irq_ptr = cdev->private->qdio_data; if (!irq_ptr) @@ -1427,10 +1315,8 @@ int qdio_establish(struct qdio_initialize *init_data) rc = ccw_device_start(cdev, &irq_ptr->ccw, QDIO_DOING_ESTABLISH, 0, 0); if (rc) { - sprintf(dbf_text, "eq:io%4x", irq_ptr->schid.sch_no); - QDIO_DBF_TEXT2(1, setup, dbf_text); - sprintf(dbf_text, "eq:rc%4x", rc); - QDIO_DBF_TEXT2(1, setup, dbf_text); + DBF_ERROR("%4x est IO ERR", irq_ptr->schid.sch_no); + DBF_ERROR("rc:%4x", rc); } spin_unlock_irqrestore(get_ccwdev_lock(cdev), saveflags); @@ -1451,10 +1337,8 @@ int qdio_establish(struct qdio_initialize *init_data) } qdio_setup_ssqd_info(irq_ptr); - sprintf(dbf_text, "qDmmwc%2x", irq_ptr->ssqd_desc.mmwc); - QDIO_DBF_TEXT2(0, setup, dbf_text); - sprintf(dbf_text, "qib ac%2x", irq_ptr->qib.ac); - QDIO_DBF_TEXT2(0, setup, dbf_text); + DBF_EVENT("qDmmwc:%2x", irq_ptr->ssqd_desc.mmwc); + DBF_EVENT("qib ac:%4x", irq_ptr->qib.ac); /* qebsm is now setup if available, initialize buffer states */ qdio_init_buf_states(irq_ptr); @@ -1475,10 +1359,8 @@ int qdio_activate(struct ccw_device *cdev) struct qdio_irq *irq_ptr; int rc; unsigned long saveflags; - char dbf_text[20]; - sprintf(dbf_text, "qact%4x", cdev->private->schid.sch_no); - QDIO_DBF_TEXT0(0, setup, dbf_text); + DBF_EVENT("qactivate:%4x", cdev->private->schid.sch_no); irq_ptr = cdev->private->qdio_data; if (!irq_ptr) @@ -1504,10 +1386,8 @@ int qdio_activate(struct ccw_device *cdev) rc = ccw_device_start(cdev, &irq_ptr->ccw, QDIO_DOING_ACTIVATE, 0, DOIO_DENY_PREFETCH); if (rc) { - sprintf(dbf_text, "aq:io%4x", irq_ptr->schid.sch_no); - QDIO_DBF_TEXT2(1, setup, dbf_text); - sprintf(dbf_text, "aq:rc%4x", rc); - QDIO_DBF_TEXT2(1, setup, dbf_text); + DBF_ERROR("%4x act IO ERR", irq_ptr->schid.sch_no); + DBF_ERROR("rc:%4x", rc); } spin_unlock_irqrestore(get_ccwdev_lock(cdev), saveflags); @@ -1565,23 +1445,38 @@ static inline int buf_in_between(int bufnr, int start, int count) static void handle_inbound(struct qdio_q *q, unsigned int callflags, int bufnr, int count) { - unsigned long flags; - int used, rc; + int used, cc, diff; - /* - * do_QDIO could run in parallel with the queue tasklet so the - * upper-layer programm could empty the ACK'ed buffer here. - * If that happens we must clear the polling flag, otherwise - * qdio_stop_polling() could set the buffer to NOT_INIT after - * it was set to EMPTY which would kill us. - */ - spin_lock_irqsave(&q->u.in.lock, flags); - if (q->u.in.polling) - if (buf_in_between(q->last_move_ftc, bufnr, count)) + if (!q->u.in.polling) + goto set; + + /* protect against stop polling setting an ACK for an emptied slsb */ + if (count == QDIO_MAX_BUFFERS_PER_Q) { + /* overwriting everything, just delete polling status */ + q->u.in.polling = 0; + q->u.in.ack_count = 0; + goto set; + } else if (buf_in_between(q->last_move_ftc, bufnr, count)) { + if (is_qebsm(q)) { + /* partial overwrite, just update last_move_ftc */ + diff = add_buf(bufnr, count); + diff = sub_buf(diff, q->last_move_ftc); + q->u.in.ack_count -= diff; + if (q->u.in.ack_count <= 0) { + q->u.in.polling = 0; + q->u.in.ack_count = 0; + /* TODO: must we set last_move_ftc to something meaningful? */ + goto set; + } + q->last_move_ftc = add_buf(q->last_move_ftc, diff); + } + else + /* the only ACK will be deleted, so stop polling */ q->u.in.polling = 0; + } +set: count = set_buf_states(q, bufnr, SLSB_CU_INPUT_EMPTY, count); - spin_unlock_irqrestore(&q->u.in.lock, flags); used = atomic_add_return(count, &q->nr_buf_used) - count; BUG_ON(used + count > QDIO_MAX_BUFFERS_PER_Q); @@ -1591,9 +1486,9 @@ static void handle_inbound(struct qdio_q *q, unsigned int callflags, return; if (need_siga_in(q)) { - rc = qdio_siga_input(q); - if (rc) - q->qdio_error = rc; + cc = qdio_siga_input(q); + if (cc) + q->qdio_error = cc; } } @@ -1640,6 +1535,10 @@ static void handle_outbound(struct qdio_q *q, unsigned int callflags, while (count--) qdio_kick_outbound_q(q); } + + /* report CC=2 conditions synchronously */ + if (q->qdio_error) + __qdio_outbound_processing(q); goto out; } @@ -1649,11 +1548,11 @@ static void handle_outbound(struct qdio_q *q, unsigned int callflags, } /* try to fast requeue buffers */ - get_buf_state(q, prev_buf(bufnr), &state); + get_buf_state(q, prev_buf(bufnr), &state, 0); if (state != SLSB_CU_OUTPUT_PRIMED) qdio_kick_outbound_q(q); else { - QDIO_DBF_TEXT5(0, trace, "fast-req"); + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "fast-req"); qdio_perf_stat_inc(&perf_stats.fast_requeue); } out: @@ -1673,12 +1572,6 @@ int do_QDIO(struct ccw_device *cdev, unsigned int callflags, int q_nr, int bufnr, int count) { struct qdio_irq *irq_ptr; -#ifdef CONFIG_QDIO_DEBUG - char dbf_text[20]; - - sprintf(dbf_text, "doQD%4x", cdev->private->schid.sch_no); - QDIO_DBF_TEXT3(0, trace, dbf_text); -#endif /* CONFIG_QDIO_DEBUG */ if ((bufnr > QDIO_MAX_BUFFERS_PER_Q) || (count > QDIO_MAX_BUFFERS_PER_Q) || @@ -1692,33 +1585,24 @@ int do_QDIO(struct ccw_device *cdev, unsigned int callflags, if (!irq_ptr) return -ENODEV; -#ifdef CONFIG_QDIO_DEBUG if (callflags & QDIO_FLAG_SYNC_INPUT) - QDIO_DBF_HEX3(0, trace, &irq_ptr->input_qs[q_nr], - sizeof(void *)); + DBF_DEV_EVENT(DBF_INFO, irq_ptr, "doQDIO input"); else - QDIO_DBF_HEX3(0, trace, &irq_ptr->output_qs[q_nr], - sizeof(void *)); - - sprintf(dbf_text, "flag%04x", callflags); - QDIO_DBF_TEXT3(0, trace, dbf_text); - sprintf(dbf_text, "qi%02xct%02x", bufnr, count); - QDIO_DBF_TEXT3(0, trace, dbf_text); -#endif /* CONFIG_QDIO_DEBUG */ + DBF_DEV_EVENT(DBF_INFO, irq_ptr, "doQDIO output"); + DBF_DEV_EVENT(DBF_INFO, irq_ptr, "q:%1d flag:%4x", q_nr, callflags); + DBF_DEV_EVENT(DBF_INFO, irq_ptr, "buf:%2d cnt:%3d", bufnr, count); if (irq_ptr->state != QDIO_IRQ_STATE_ACTIVE) return -EBUSY; if (callflags & QDIO_FLAG_SYNC_INPUT) - handle_inbound(irq_ptr->input_qs[q_nr], - callflags, bufnr, count); + handle_inbound(irq_ptr->input_qs[q_nr], callflags, bufnr, + count); else if (callflags & QDIO_FLAG_SYNC_OUTPUT) - handle_outbound(irq_ptr->output_qs[q_nr], - callflags, bufnr, count); - else { - QDIO_DBF_TEXT3(1, trace, "doQD:inv"); + handle_outbound(irq_ptr->output_qs[q_nr], callflags, bufnr, + count); + else return -EINVAL; - } return 0; } EXPORT_SYMBOL_GPL(do_QDIO); diff --git a/drivers/s390/cio/qdio_perf.c b/drivers/s390/cio/qdio_perf.c index ec5c4a41423521bfa30c06f64aee6e5ae75597f6..136d0f0b1e93e7e155172caf55c2fabc31bccb8a 100644 --- a/drivers/s390/cio/qdio_perf.c +++ b/drivers/s390/cio/qdio_perf.c @@ -74,12 +74,20 @@ static int qdio_perf_proc_show(struct seq_file *m, void *v) seq_printf(m, "\n"); seq_printf(m, "Number of fast requeues (outg. SBAL w/o SIGA)\t: %li\n", (long)atomic_long_read(&perf_stats.fast_requeue)); + seq_printf(m, "Number of outbound target full condition\t: %li\n", + (long)atomic_long_read(&perf_stats.outbound_target_full)); seq_printf(m, "Number of outbound tasklet mod_timer calls\t: %li\n", (long)atomic_long_read(&perf_stats.debug_tl_out_timer)); seq_printf(m, "Number of stop polling calls\t\t\t: %li\n", (long)atomic_long_read(&perf_stats.debug_stop_polling)); seq_printf(m, "AI inbound tasklet loops after stop polling\t: %li\n", (long)atomic_long_read(&perf_stats.thinint_inbound_loop2)); + seq_printf(m, "QEBSM EQBS total/incomplete\t\t\t: %li/%li\n", + (long)atomic_long_read(&perf_stats.debug_eqbs_all), + (long)atomic_long_read(&perf_stats.debug_eqbs_incomplete)); + seq_printf(m, "QEBSM SQBS total/incomplete\t\t\t: %li/%li\n", + (long)atomic_long_read(&perf_stats.debug_sqbs_all), + (long)atomic_long_read(&perf_stats.debug_sqbs_incomplete)); seq_printf(m, "\n"); return 0; } diff --git a/drivers/s390/cio/qdio_perf.h b/drivers/s390/cio/qdio_perf.h index 5c406a8b73870127c4be66fa8c0ef8ed8aa0619f..7821ac4fa51759196f6dbdc0bf56045aef9140aa 100644 --- a/drivers/s390/cio/qdio_perf.h +++ b/drivers/s390/cio/qdio_perf.h @@ -36,10 +36,15 @@ struct qdio_perf_stats { atomic_long_t inbound_handler; atomic_long_t outbound_handler; atomic_long_t fast_requeue; + atomic_long_t outbound_target_full; /* for debugging */ atomic_long_t debug_tl_out_timer; atomic_long_t debug_stop_polling; + atomic_long_t debug_eqbs_all; + atomic_long_t debug_eqbs_incomplete; + atomic_long_t debug_sqbs_all; + atomic_long_t debug_sqbs_incomplete; }; extern struct qdio_perf_stats perf_stats; diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index a0b6b46e746647ae5451d5099c5a8ccde5e89175..c08356b95bf5f9d2f41ef93e77ecd1b360781908 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c @@ -117,17 +117,16 @@ static void setup_queues_misc(struct qdio_q *q, struct qdio_irq *irq_ptr, q->mask = 1 << (31 - i); q->nr = i; q->handler = handler; + spin_lock_init(&q->lock); } static void setup_storage_lists(struct qdio_q *q, struct qdio_irq *irq_ptr, - void **sbals_array, char *dbf_text, int i) + void **sbals_array, int i) { struct qdio_q *prev; int j; - QDIO_DBF_TEXT0(0, setup, dbf_text); - QDIO_DBF_HEX0(0, setup, &q, sizeof(void *)); - + DBF_HEX(&q, sizeof(void *)); q->sl = (struct sl *)((char *)q->slib + PAGE_SIZE / 2); /* fill in sbal */ @@ -150,31 +149,26 @@ static void setup_storage_lists(struct qdio_q *q, struct qdio_irq *irq_ptr, for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; j++) q->sl->element[j].sbal = (unsigned long)q->sbal[j]; - QDIO_DBF_TEXT2(0, setup, "sl-sb-b0"); - QDIO_DBF_HEX2(0, setup, q->sl, sizeof(void *)); - QDIO_DBF_HEX2(0, setup, &q->slsb, sizeof(void *)); - QDIO_DBF_HEX2(0, setup, q->sbal, sizeof(void *)); + DBF_EVENT("sl-slsb-sbal"); + DBF_HEX(q->sl, sizeof(void *)); + DBF_HEX(&q->slsb, sizeof(void *)); + DBF_HEX(q->sbal, sizeof(void *)); } static void setup_queues(struct qdio_irq *irq_ptr, struct qdio_initialize *qdio_init) { - char dbf_text[20]; struct qdio_q *q; void **input_sbal_array = qdio_init->input_sbal_addr_array; void **output_sbal_array = qdio_init->output_sbal_addr_array; int i; - sprintf(dbf_text, "qset%4x", qdio_init->cdev->private->schid.sch_no); - QDIO_DBF_TEXT0(0, setup, dbf_text); - for_each_input_queue(irq_ptr, q, i) { - sprintf(dbf_text, "in-q%4x", i); + DBF_EVENT("in-q:%1d", i); setup_queues_misc(q, irq_ptr, qdio_init->input_handler, i); q->is_input_q = 1; - spin_lock_init(&q->u.in.lock); - setup_storage_lists(q, irq_ptr, input_sbal_array, dbf_text, i); + setup_storage_lists(q, irq_ptr, input_sbal_array, i); input_sbal_array += QDIO_MAX_BUFFERS_PER_Q; if (is_thinint_irq(irq_ptr)) @@ -186,12 +180,11 @@ static void setup_queues(struct qdio_irq *irq_ptr, } for_each_output_queue(irq_ptr, q, i) { - sprintf(dbf_text, "outq%4x", i); + DBF_EVENT("outq:%1d", i); setup_queues_misc(q, irq_ptr, qdio_init->output_handler, i); q->is_input_q = 0; - setup_storage_lists(q, irq_ptr, output_sbal_array, - dbf_text, i); + setup_storage_lists(q, irq_ptr, output_sbal_array, i); output_sbal_array += QDIO_MAX_BUFFERS_PER_Q; tasklet_init(&q->tasklet, qdio_outbound_processing, @@ -222,8 +215,6 @@ static void process_ac_flags(struct qdio_irq *irq_ptr, unsigned char qdioac) static void check_and_setup_qebsm(struct qdio_irq *irq_ptr, unsigned char qdioac, unsigned long token) { - char dbf_text[15]; - if (!(irq_ptr->qib.rflags & QIB_RFLAGS_ENABLE_QEBSM)) goto no_qebsm; if (!(qdioac & AC1_SC_QEBSM_AVAILABLE) || @@ -232,33 +223,41 @@ static void check_and_setup_qebsm(struct qdio_irq *irq_ptr, irq_ptr->sch_token = token; - QDIO_DBF_TEXT0(0, setup, "V=V:1"); - sprintf(dbf_text, "%8lx", irq_ptr->sch_token); - QDIO_DBF_TEXT0(0, setup, dbf_text); + DBF_EVENT("V=V:1"); + DBF_EVENT("%8lx", irq_ptr->sch_token); return; no_qebsm: irq_ptr->sch_token = 0; irq_ptr->qib.rflags &= ~QIB_RFLAGS_ENABLE_QEBSM; - QDIO_DBF_TEXT0(0, setup, "noV=V"); + DBF_EVENT("noV=V"); } -static int __get_ssqd_info(struct qdio_irq *irq_ptr) +/* + * If there is a qdio_irq we use the chsc_page and store the information + * in the qdio_irq, otherwise we copy it to the specified structure. + */ +int qdio_setup_get_ssqd(struct qdio_irq *irq_ptr, + struct subchannel_id *schid, + struct qdio_ssqd_desc *data) { struct chsc_ssqd_area *ssqd; int rc; - QDIO_DBF_TEXT0(0, setup, "getssqd"); - ssqd = (struct chsc_ssqd_area *)irq_ptr->chsc_page; + DBF_EVENT("getssqd:%4x", schid->sch_no); + if (irq_ptr != NULL) + ssqd = (struct chsc_ssqd_area *)irq_ptr->chsc_page; + else + ssqd = (struct chsc_ssqd_area *)__get_free_page(GFP_KERNEL); memset(ssqd, 0, PAGE_SIZE); ssqd->request = (struct chsc_header) { .length = 0x0010, .code = 0x0024, }; - ssqd->first_sch = irq_ptr->schid.sch_no; - ssqd->last_sch = irq_ptr->schid.sch_no; - ssqd->ssid = irq_ptr->schid.ssid; + ssqd->first_sch = schid->sch_no; + ssqd->last_sch = schid->sch_no; + ssqd->ssid = schid->ssid; if (chsc(ssqd)) return -EIO; @@ -268,27 +267,29 @@ static int __get_ssqd_info(struct qdio_irq *irq_ptr) if (!(ssqd->qdio_ssqd.flags & CHSC_FLAG_QDIO_CAPABILITY) || !(ssqd->qdio_ssqd.flags & CHSC_FLAG_VALIDITY) || - (ssqd->qdio_ssqd.sch != irq_ptr->schid.sch_no)) + (ssqd->qdio_ssqd.sch != schid->sch_no)) return -EINVAL; - memcpy(&irq_ptr->ssqd_desc, &ssqd->qdio_ssqd, - sizeof(struct qdio_ssqd_desc)); + if (irq_ptr != NULL) + memcpy(&irq_ptr->ssqd_desc, &ssqd->qdio_ssqd, + sizeof(struct qdio_ssqd_desc)); + else { + memcpy(data, &ssqd->qdio_ssqd, + sizeof(struct qdio_ssqd_desc)); + free_page((unsigned long)ssqd); + } return 0; } void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr) { unsigned char qdioac; - char dbf_text[15]; int rc; - rc = __get_ssqd_info(irq_ptr); + rc = qdio_setup_get_ssqd(irq_ptr, &irq_ptr->schid, NULL); if (rc) { - QDIO_DBF_TEXT2(0, setup, "ssqdasig"); - sprintf(dbf_text, "schn%4x", irq_ptr->schid.sch_no); - QDIO_DBF_TEXT2(0, setup, dbf_text); - sprintf(dbf_text, "rc:%d", rc); - QDIO_DBF_TEXT2(0, setup, dbf_text); + DBF_ERROR("%4x ssqd ERR", irq_ptr->schid.sch_no); + DBF_ERROR("rc:%x", rc); /* all flags set, worst case */ qdioac = AC1_SIGA_INPUT_NEEDED | AC1_SIGA_OUTPUT_NEEDED | AC1_SIGA_SYNC_NEEDED; @@ -297,9 +298,7 @@ void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr) check_and_setup_qebsm(irq_ptr, qdioac, irq_ptr->ssqd_desc.sch_token); process_ac_flags(irq_ptr, qdioac); - - sprintf(dbf_text, "qdioac%2x", qdioac); - QDIO_DBF_TEXT2(0, setup, dbf_text); + DBF_EVENT("qdioac:%4x", qdioac); } void qdio_release_memory(struct qdio_irq *irq_ptr) @@ -419,7 +418,7 @@ int qdio_setup_irq(struct qdio_initialize *init_data) /* get qdio commands */ ciw = ccw_device_get_ciw(init_data->cdev, CIW_TYPE_EQUEUE); if (!ciw) { - QDIO_DBF_TEXT2(1, setup, "no eq"); + DBF_ERROR("%4x NO EQ", irq_ptr->schid.sch_no); rc = -EINVAL; goto out_err; } @@ -427,7 +426,7 @@ int qdio_setup_irq(struct qdio_initialize *init_data) ciw = ccw_device_get_ciw(init_data->cdev, CIW_TYPE_AQUEUE); if (!ciw) { - QDIO_DBF_TEXT2(1, setup, "no aq"); + DBF_ERROR("%4x NO AQ", irq_ptr->schid.sch_no); rc = -EINVAL; goto out_err; } @@ -447,56 +446,38 @@ void qdio_print_subchannel_info(struct qdio_irq *irq_ptr, { char s[80]; - sprintf(s, "qdio: %s ", dev_name(&cdev->dev)); - switch (irq_ptr->qib.qfmt) { - case QDIO_QETH_QFMT: - sprintf(s + strlen(s), "OSA "); - break; - case QDIO_ZFCP_QFMT: - sprintf(s + strlen(s), "ZFCP "); - break; - case QDIO_IQDIO_QFMT: - sprintf(s + strlen(s), "HS "); - break; - } - sprintf(s + strlen(s), "on SC %x using ", irq_ptr->schid.sch_no); - sprintf(s + strlen(s), "AI:%d ", is_thinint_irq(irq_ptr)); - sprintf(s + strlen(s), "QEBSM:%d ", (irq_ptr->sch_token) ? 1 : 0); - sprintf(s + strlen(s), "PCI:%d ", - (irq_ptr->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED) ? 1 : 0); - sprintf(s + strlen(s), "TDD:%d ", css_general_characteristics.aif_tdd); - sprintf(s + strlen(s), "SIGA:"); - sprintf(s + strlen(s), "%s", (irq_ptr->siga_flag.input) ? "R" : " "); - sprintf(s + strlen(s), "%s", (irq_ptr->siga_flag.output) ? "W" : " "); - sprintf(s + strlen(s), "%s", (irq_ptr->siga_flag.sync) ? "S" : " "); - sprintf(s + strlen(s), "%s", - (!irq_ptr->siga_flag.no_sync_ti) ? "A" : " "); - sprintf(s + strlen(s), "%s", - (!irq_ptr->siga_flag.no_sync_out_ti) ? "O" : " "); - sprintf(s + strlen(s), "%s", - (!irq_ptr->siga_flag.no_sync_out_pci) ? "P" : " "); - sprintf(s + strlen(s), "\n"); + snprintf(s, 80, "qdio: %s %s on SC %x using " + "AI:%d QEBSM:%d PCI:%d TDD:%d SIGA:%s%s%s%s%s%s\n", + dev_name(&cdev->dev), + (irq_ptr->qib.qfmt == QDIO_QETH_QFMT) ? "OSA" : + ((irq_ptr->qib.qfmt == QDIO_ZFCP_QFMT) ? "ZFCP" : "HS"), + irq_ptr->schid.sch_no, + is_thinint_irq(irq_ptr), + (irq_ptr->sch_token) ? 1 : 0, + (irq_ptr->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED) ? 1 : 0, + css_general_characteristics.aif_tdd, + (irq_ptr->siga_flag.input) ? "R" : " ", + (irq_ptr->siga_flag.output) ? "W" : " ", + (irq_ptr->siga_flag.sync) ? "S" : " ", + (!irq_ptr->siga_flag.no_sync_ti) ? "A" : " ", + (!irq_ptr->siga_flag.no_sync_out_ti) ? "O" : " ", + (!irq_ptr->siga_flag.no_sync_out_pci) ? "P" : " "); printk(KERN_INFO "%s", s); } int __init qdio_setup_init(void) { - char dbf_text[15]; - qdio_q_cache = kmem_cache_create("qdio_q", sizeof(struct qdio_q), 256, 0, NULL); if (!qdio_q_cache) return -ENOMEM; /* Check for OSA/FCP thin interrupts (bit 67). */ - sprintf(dbf_text, "thini%1x", - (css_general_characteristics.aif_osa) ? 1 : 0); - QDIO_DBF_TEXT0(0, setup, dbf_text); + DBF_EVENT("thinint:%1d", + (css_general_characteristics.aif_osa) ? 1 : 0); /* Check for QEBSM support in general (bit 58). */ - sprintf(dbf_text, "cssQBS:%1x", - (qebsm_possible()) ? 1 : 0); - QDIO_DBF_TEXT0(0, setup, dbf_text); + DBF_EVENT("cssQEBSM:%1d", (qebsm_possible()) ? 1 : 0); return 0; } diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c index ea7f614002670024f766d887062ff4824029556d..8e90e147b746834c6af2c87da10fbdb8c3fc2f93 100644 --- a/drivers/s390/cio/qdio_thinint.c +++ b/drivers/s390/cio/qdio_thinint.c @@ -125,13 +125,13 @@ void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr) static inline int tiqdio_inbound_q_done(struct qdio_q *q) { - unsigned char state; + unsigned char state = 0; if (!atomic_read(&q->nr_buf_used)) return 1; qdio_siga_sync_q(q); - get_buf_state(q, q->first_to_check, &state); + get_buf_state(q, q->first_to_check, &state, 0); if (state == SLSB_P_INPUT_PRIMED) /* more work coming */ @@ -258,8 +258,6 @@ static void tiqdio_thinint_handler(void *ind, void *drv_data) static int set_subchannel_ind(struct qdio_irq *irq_ptr, int reset) { struct scssc_area *scssc_area; - char dbf_text[15]; - void *ptr; int rc; scssc_area = (struct scssc_area *)irq_ptr->chsc_page; @@ -294,19 +292,15 @@ static int set_subchannel_ind(struct qdio_irq *irq_ptr, int reset) rc = chsc_error_from_response(scssc_area->response.code); if (rc) { - sprintf(dbf_text, "sidR%4x", scssc_area->response.code); - QDIO_DBF_TEXT1(0, trace, dbf_text); - QDIO_DBF_TEXT1(0, setup, dbf_text); - ptr = &scssc_area->response; - QDIO_DBF_HEX2(1, setup, &ptr, QDIO_DBF_SETUP_LEN); + DBF_ERROR("%4x SSI r:%4x", irq_ptr->schid.sch_no, + scssc_area->response.code); + DBF_ERROR_HEX(&scssc_area->response, sizeof(void *)); return rc; } - QDIO_DBF_TEXT2(0, setup, "setscind"); - QDIO_DBF_HEX2(0, setup, &scssc_area->summary_indicator_addr, - sizeof(unsigned long)); - QDIO_DBF_HEX2(0, setup, &scssc_area->subchannel_indicator_addr, - sizeof(unsigned long)); + DBF_EVENT("setscind"); + DBF_HEX(&scssc_area->summary_indicator_addr, sizeof(unsigned long)); + DBF_HEX(&scssc_area->subchannel_indicator_addr, sizeof(unsigned long)); return 0; } @@ -327,14 +321,11 @@ void tiqdio_free_memory(void) int __init tiqdio_register_thinints(void) { - char dbf_text[20]; - isc_register(QDIO_AIRQ_ISC); tiqdio_alsi = s390_register_adapter_interrupt(&tiqdio_thinint_handler, NULL, QDIO_AIRQ_ISC); if (IS_ERR(tiqdio_alsi)) { - sprintf(dbf_text, "regthn%lx", PTR_ERR(tiqdio_alsi)); - QDIO_DBF_TEXT0(0, setup, dbf_text); + DBF_EVENT("RTI:%lx", PTR_ERR(tiqdio_alsi)); tiqdio_alsi = NULL; isc_unregister(QDIO_AIRQ_ISC); return -ENOMEM; @@ -360,7 +351,7 @@ void qdio_setup_thinint(struct qdio_irq *irq_ptr) if (!is_thinint_irq(irq_ptr)) return; irq_ptr->dsci = get_indicator(); - QDIO_DBF_HEX1(0, setup, &irq_ptr->dsci, sizeof(void *)); + DBF_HEX(&irq_ptr->dsci, sizeof(void *)); } void qdio_shutdown_thinint(struct qdio_irq *irq_ptr) diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index e3fe6838293ad4f238cd9bb81df92a59ec61d72b..1f5f5d2d87d94b8fb3123f5c1d9855492b22b122 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -5,6 +5,7 @@ * Author(s): Cornelia Huck * Martin Schwidefsky * Ralph Wuerthner + * Felix Beck * * Adjunct processor bus. * @@ -23,6 +24,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define KMSG_COMPONENT "ap" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include @@ -34,6 +38,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -46,6 +54,7 @@ static enum hrtimer_restart ap_poll_timeout(struct hrtimer *); static int ap_poll_thread_start(void); static void ap_poll_thread_stop(void); static void ap_request_timeout(unsigned long); +static inline void ap_schedule_poll_timer(void); /* * Module description. @@ -68,7 +77,7 @@ module_param_named(poll_thread, ap_thread_flag, int, 0000); MODULE_PARM_DESC(poll_thread, "Turn on/off poll thread, default is 0 (off)."); static struct device *ap_root_device = NULL; -static DEFINE_SPINLOCK(ap_device_lock); +static DEFINE_SPINLOCK(ap_device_list_lock); static LIST_HEAD(ap_device_list); /* @@ -80,18 +89,28 @@ static int ap_config_time = AP_CONFIG_TIME; static DECLARE_WORK(ap_config_work, ap_scan_bus); /* - * Tasklet & timer for AP request polling. + * Tasklet & timer for AP request polling and interrupts */ static DECLARE_TASKLET(ap_tasklet, ap_poll_all, 0); static atomic_t ap_poll_requests = ATOMIC_INIT(0); static DECLARE_WAIT_QUEUE_HEAD(ap_poll_wait); static struct task_struct *ap_poll_kthread = NULL; static DEFINE_MUTEX(ap_poll_thread_mutex); +static void *ap_interrupt_indicator; static struct hrtimer ap_poll_timer; /* In LPAR poll with 4kHz frequency. Poll every 250000 nanoseconds. * If z/VM change to 1500000 nanoseconds to adjust to z/VM polling.*/ static unsigned long long poll_timeout = 250000; +/** + * ap_using_interrupts() - Returns non-zero if interrupt support is + * available. + */ +static inline int ap_using_interrupts(void) +{ + return ap_interrupt_indicator != NULL; +} + /** * ap_intructions_available() - Test if AP instructions are available. * @@ -112,6 +131,23 @@ static inline int ap_instructions_available(void) return reg1; } +/** + * ap_interrupts_available(): Test if AP interrupts are available. + * + * Returns 1 if AP interrupts are available. + */ +static int ap_interrupts_available(void) +{ + unsigned long long facility_bits[2]; + + if (stfle(facility_bits, 2) <= 1) + return 0; + if (!(facility_bits[0] & (1ULL << 61)) || + !(facility_bits[1] & (1ULL << 62))) + return 0; + return 1; +} + /** * ap_test_queue(): Test adjunct processor queue. * @qid: The AP queue number @@ -152,6 +188,80 @@ static inline struct ap_queue_status ap_reset_queue(ap_qid_t qid) return reg1; } +#ifdef CONFIG_64BIT +/** + * ap_queue_interruption_control(): Enable interruption for a specific AP. + * @qid: The AP queue number + * @ind: The notification indicator byte + * + * Returns AP queue status. + */ +static inline struct ap_queue_status +ap_queue_interruption_control(ap_qid_t qid, void *ind) +{ + register unsigned long reg0 asm ("0") = qid | 0x03000000UL; + register unsigned long reg1_in asm ("1") = 0x0000800000000000UL | AP_ISC; + register struct ap_queue_status reg1_out asm ("1"); + register void *reg2 asm ("2") = ind; + asm volatile( + ".long 0xb2af0000" /* PQAP(RAPQ) */ + : "+d" (reg0), "+d" (reg1_in), "=d" (reg1_out), "+d" (reg2) + : + : "cc" ); + return reg1_out; +} +#endif + +/** + * ap_queue_enable_interruption(): Enable interruption on an AP. + * @qid: The AP queue number + * @ind: the notification indicator byte + * + * Enables interruption on AP queue via ap_queue_interruption_control(). Based + * on the return value it waits a while and tests the AP queue if interrupts + * have been switched on using ap_test_queue(). + */ +static int ap_queue_enable_interruption(ap_qid_t qid, void *ind) +{ +#ifdef CONFIG_64BIT + struct ap_queue_status status; + int t_depth, t_device_type, rc, i; + + rc = -EBUSY; + status = ap_queue_interruption_control(qid, ind); + + for (i = 0; i < AP_MAX_RESET; i++) { + switch (status.response_code) { + case AP_RESPONSE_NORMAL: + if (status.int_enabled) + return 0; + break; + case AP_RESPONSE_RESET_IN_PROGRESS: + case AP_RESPONSE_BUSY: + break; + case AP_RESPONSE_Q_NOT_AVAIL: + case AP_RESPONSE_DECONFIGURED: + case AP_RESPONSE_CHECKSTOPPED: + case AP_RESPONSE_INVALID_ADDRESS: + return -ENODEV; + case AP_RESPONSE_OTHERWISE_CHANGED: + if (status.int_enabled) + return 0; + break; + default: + break; + } + if (i < AP_MAX_RESET - 1) { + udelay(5); + status = ap_test_queue(qid, &t_depth, &t_device_type); + } + } + return rc; +#else + return -EINVAL; +#endif +} + /** * __ap_send(): Send message to adjunct processor queue. * @qid: The AP queue number @@ -295,6 +405,11 @@ static int ap_query_queue(ap_qid_t qid, int *queue_depth, int *device_type) case AP_RESPONSE_CHECKSTOPPED: rc = -ENODEV; break; + case AP_RESPONSE_INVALID_ADDRESS: + rc = -ENODEV; + break; + case AP_RESPONSE_OTHERWISE_CHANGED: + break; case AP_RESPONSE_BUSY: break; default: @@ -345,6 +460,15 @@ static int ap_init_queue(ap_qid_t qid) status = ap_test_queue(qid, &dummy, &dummy); } } + if (rc == 0 && ap_using_interrupts()) { + rc = ap_queue_enable_interruption(qid, ap_interrupt_indicator); + /* If interruption mode is supported by the machine, + * but an AP can not be enabled for interruption then + * the AP will be discarded. */ + if (rc) + pr_err("Registering adapter interrupts for " + "AP %d failed\n", AP_QID_DEVICE(qid)); + } return rc; } @@ -397,16 +521,16 @@ static ssize_t ap_hwtype_show(struct device *dev, struct ap_device *ap_dev = to_ap_dev(dev); return snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->device_type); } -static DEVICE_ATTR(hwtype, 0444, ap_hwtype_show, NULL); +static DEVICE_ATTR(hwtype, 0444, ap_hwtype_show, NULL); static ssize_t ap_depth_show(struct device *dev, struct device_attribute *attr, char *buf) { struct ap_device *ap_dev = to_ap_dev(dev); return snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->queue_depth); } -static DEVICE_ATTR(depth, 0444, ap_depth_show, NULL); +static DEVICE_ATTR(depth, 0444, ap_depth_show, NULL); static ssize_t ap_request_count_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -509,9 +633,9 @@ static int ap_device_probe(struct device *dev) ap_dev->drv = ap_drv; rc = ap_drv->probe ? ap_drv->probe(ap_dev) : -ENODEV; if (!rc) { - spin_lock_bh(&ap_device_lock); + spin_lock_bh(&ap_device_list_lock); list_add(&ap_dev->list, &ap_device_list); - spin_unlock_bh(&ap_device_lock); + spin_unlock_bh(&ap_device_list_lock); } return rc; } @@ -553,9 +677,9 @@ static int ap_device_remove(struct device *dev) ap_flush_queue(ap_dev); del_timer_sync(&ap_dev->timeout); - spin_lock_bh(&ap_device_lock); + spin_lock_bh(&ap_device_list_lock); list_del_init(&ap_dev->list); - spin_unlock_bh(&ap_device_lock); + spin_unlock_bh(&ap_device_list_lock); if (ap_drv->remove) ap_drv->remove(ap_dev); spin_lock_bh(&ap_dev->lock); @@ -599,6 +723,14 @@ static ssize_t ap_config_time_show(struct bus_type *bus, char *buf) return snprintf(buf, PAGE_SIZE, "%d\n", ap_config_time); } +static ssize_t ap_interrupts_show(struct bus_type *bus, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", + ap_using_interrupts() ? 1 : 0); +} + +static BUS_ATTR(ap_interrupts, 0444, ap_interrupts_show, NULL); + static ssize_t ap_config_time_store(struct bus_type *bus, const char *buf, size_t count) { @@ -653,7 +785,8 @@ static ssize_t poll_timeout_store(struct bus_type *bus, const char *buf, ktime_t hr_time; /* 120 seconds = maximum poll interval */ - if (sscanf(buf, "%llu\n", &time) != 1 || time < 1 || time > 120000000000) + if (sscanf(buf, "%llu\n", &time) != 1 || time < 1 || + time > 120000000000ULL) return -EINVAL; poll_timeout = time; hr_time = ktime_set(0, poll_timeout); @@ -672,6 +805,7 @@ static struct bus_attribute *const ap_bus_attrs[] = { &bus_attr_ap_domain, &bus_attr_config_time, &bus_attr_poll_thread, + &bus_attr_ap_interrupts, &bus_attr_poll_timeout, NULL, }; @@ -814,6 +948,11 @@ static int ap_probe_device_type(struct ap_device *ap_dev) return rc; } +static void ap_interrupt_handler(void *unused1, void *unused2) +{ + tasklet_schedule(&ap_tasklet); +} + /** * __ap_scan_bus(): Scan the AP bus. * @dev: Pointer to device @@ -928,6 +1067,8 @@ ap_config_timeout(unsigned long ptr) */ static inline void ap_schedule_poll_timer(void) { + if (ap_using_interrupts()) + return; if (hrtimer_is_queued(&ap_poll_timer)) return; hrtimer_start(&ap_poll_timer, ktime_set(0, poll_timeout), @@ -1181,7 +1322,7 @@ static void ap_reset(struct ap_device *ap_dev) ap_dev->unregistered = 1; } -static int __ap_poll_all(struct ap_device *ap_dev, unsigned long *flags) +static int __ap_poll_device(struct ap_device *ap_dev, unsigned long *flags) { spin_lock(&ap_dev->lock); if (!ap_dev->unregistered) { @@ -1207,13 +1348,19 @@ static void ap_poll_all(unsigned long dummy) unsigned long flags; struct ap_device *ap_dev; + /* Reset the indicator if interrupts are used. Thus new interrupts can + * be received. Doing it in the beginning of the tasklet is therefor + * important that no requests on any AP get lost. + */ + if (ap_using_interrupts()) + xchg((u8 *)ap_interrupt_indicator, 0); do { flags = 0; - spin_lock(&ap_device_lock); + spin_lock(&ap_device_list_lock); list_for_each_entry(ap_dev, &ap_device_list, list) { - __ap_poll_all(ap_dev, &flags); + __ap_poll_device(ap_dev, &flags); } - spin_unlock(&ap_device_lock); + spin_unlock(&ap_device_list_lock); } while (flags & 1); if (flags & 2) ap_schedule_poll_timer(); @@ -1253,11 +1400,11 @@ static int ap_poll_thread(void *data) remove_wait_queue(&ap_poll_wait, &wait); flags = 0; - spin_lock_bh(&ap_device_lock); + spin_lock_bh(&ap_device_list_lock); list_for_each_entry(ap_dev, &ap_device_list, list) { - __ap_poll_all(ap_dev, &flags); + __ap_poll_device(ap_dev, &flags); } - spin_unlock_bh(&ap_device_lock); + spin_unlock_bh(&ap_device_list_lock); } set_current_state(TASK_RUNNING); remove_wait_queue(&ap_poll_wait, &wait); @@ -1268,6 +1415,8 @@ static int ap_poll_thread_start(void) { int rc; + if (ap_using_interrupts()) + return 0; mutex_lock(&ap_poll_thread_mutex); if (!ap_poll_kthread) { ap_poll_kthread = kthread_run(ap_poll_thread, NULL, "appoll"); @@ -1301,8 +1450,12 @@ static void ap_request_timeout(unsigned long data) { struct ap_device *ap_dev = (struct ap_device *) data; - if (ap_dev->reset == AP_RESET_ARMED) + if (ap_dev->reset == AP_RESET_ARMED) { ap_dev->reset = AP_RESET_DO; + + if (ap_using_interrupts()) + tasklet_schedule(&ap_tasklet); + } } static void ap_reset_domain(void) @@ -1337,14 +1490,25 @@ int __init ap_module_init(void) int rc, i; if (ap_domain_index < -1 || ap_domain_index >= AP_DOMAINS) { - printk(KERN_WARNING "Invalid param: domain = %d. " - " Not loading.\n", ap_domain_index); + pr_warning("%d is not a valid cryptographic domain\n", + ap_domain_index); return -EINVAL; } if (ap_instructions_available() != 0) { - printk(KERN_WARNING "AP instructions not installed.\n"); + pr_warning("The hardware system does not support " + "AP instructions\n"); return -ENODEV; } + if (ap_interrupts_available()) { + isc_register(AP_ISC); + ap_interrupt_indicator = s390_register_adapter_interrupt( + &ap_interrupt_handler, NULL, AP_ISC); + if (IS_ERR(ap_interrupt_indicator)) { + ap_interrupt_indicator = NULL; + isc_unregister(AP_ISC); + } + } + register_reset_call(&ap_reset_call); /* Create /sys/bus/ap. */ @@ -1408,6 +1572,10 @@ int __init ap_module_init(void) bus_unregister(&ap_bus_type); out: unregister_reset_call(&ap_reset_call); + if (ap_using_interrupts()) { + s390_unregister_adapter_interrupt(ap_interrupt_indicator, AP_ISC); + isc_unregister(AP_ISC); + } return rc; } @@ -1443,6 +1611,10 @@ void ap_module_exit(void) bus_remove_file(&ap_bus_type, ap_bus_attrs[i]); bus_unregister(&ap_bus_type); unregister_reset_call(&ap_reset_call); + if (ap_using_interrupts()) { + s390_unregister_adapter_interrupt(ap_interrupt_indicator, AP_ISC); + isc_unregister(AP_ISC); + } } #ifndef CONFIG_ZCRYPT_MONOLITHIC diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h index 446378b308fcf2ca6447816cfc2daab59c481536..a353622418054befbf096a9dc22ea65d49891306 100644 --- a/drivers/s390/crypto/ap_bus.h +++ b/drivers/s390/crypto/ap_bus.h @@ -5,6 +5,7 @@ * Author(s): Cornelia Huck * Martin Schwidefsky * Ralph Wuerthner + * Felix Beck * * Adjunct processor bus header file. * @@ -67,7 +68,8 @@ struct ap_queue_status { unsigned int queue_empty : 1; unsigned int replies_waiting : 1; unsigned int queue_full : 1; - unsigned int pad1 : 5; + unsigned int pad1 : 4; + unsigned int int_enabled : 1; unsigned int response_code : 8; unsigned int pad2 : 16; }; @@ -78,6 +80,8 @@ struct ap_queue_status { #define AP_RESPONSE_DECONFIGURED 0x03 #define AP_RESPONSE_CHECKSTOPPED 0x04 #define AP_RESPONSE_BUSY 0x05 +#define AP_RESPONSE_INVALID_ADDRESS 0x06 +#define AP_RESPONSE_OTHERWISE_CHANGED 0x07 #define AP_RESPONSE_Q_FULL 0x10 #define AP_RESPONSE_NO_PENDING_REPLY 0x10 #define AP_RESPONSE_INDEX_TOO_BIG 0x11 diff --git a/drivers/s390/crypto/zcrypt_cex2a.c b/drivers/s390/crypto/zcrypt_cex2a.c index 54f4cbc3be9e44eae1d56902df6d68c5adc6c531..326ea08f67c985d059ef7d93cdd1d66f13b33b37 100644 --- a/drivers/s390/crypto/zcrypt_cex2a.c +++ b/drivers/s390/crypto/zcrypt_cex2a.c @@ -264,17 +264,21 @@ static void zcrypt_cex2a_receive(struct ap_device *ap_dev, .type = TYPE82_RSP_CODE, .reply_code = REP82_ERROR_MACHINE_FAILURE, }; - struct type80_hdr *t80h = reply->message; + struct type80_hdr *t80h; int length; /* Copy the reply message to the request message buffer. */ - if (IS_ERR(reply)) + if (IS_ERR(reply)) { memcpy(msg->message, &error_reply, sizeof(error_reply)); - else if (t80h->type == TYPE80_RSP_CODE) { + goto out; + } + t80h = reply->message; + if (t80h->type == TYPE80_RSP_CODE) { length = min(CEX2A_MAX_RESPONSE_SIZE, (int) t80h->len); memcpy(msg->message, reply->message, length); } else memcpy(msg->message, reply->message, sizeof error_reply); +out: complete((struct completion *) msg->private); } diff --git a/drivers/s390/crypto/zcrypt_pcica.c b/drivers/s390/crypto/zcrypt_pcica.c index 12da4815ba8eea3ffa8fbdbf773661dbb5650697..17ba81b58c78f473974f7ecfa7c0d714861a6c54 100644 --- a/drivers/s390/crypto/zcrypt_pcica.c +++ b/drivers/s390/crypto/zcrypt_pcica.c @@ -247,17 +247,21 @@ static void zcrypt_pcica_receive(struct ap_device *ap_dev, .type = TYPE82_RSP_CODE, .reply_code = REP82_ERROR_MACHINE_FAILURE, }; - struct type84_hdr *t84h = reply->message; + struct type84_hdr *t84h; int length; /* Copy the reply message to the request message buffer. */ - if (IS_ERR(reply)) + if (IS_ERR(reply)) { memcpy(msg->message, &error_reply, sizeof(error_reply)); - else if (t84h->code == TYPE84_RSP_CODE) { + goto out; + } + t84h = reply->message; + if (t84h->code == TYPE84_RSP_CODE) { length = min(PCICA_MAX_RESPONSE_SIZE, (int) t84h->len); memcpy(msg->message, reply->message, length); } else memcpy(msg->message, reply->message, sizeof error_reply); +out: complete((struct completion *) msg->private); } diff --git a/drivers/s390/crypto/zcrypt_pcicc.c b/drivers/s390/crypto/zcrypt_pcicc.c index 779952cb19fc85a101485461077d75448387d89c..f4b0c47954341d4fcc5d88af1119d4064580db92 100644 --- a/drivers/s390/crypto/zcrypt_pcicc.c +++ b/drivers/s390/crypto/zcrypt_pcicc.c @@ -447,19 +447,23 @@ static void zcrypt_pcicc_receive(struct ap_device *ap_dev, .type = TYPE82_RSP_CODE, .reply_code = REP82_ERROR_MACHINE_FAILURE, }; - struct type86_reply *t86r = reply->message; + struct type86_reply *t86r; int length; /* Copy the reply message to the request message buffer. */ - if (IS_ERR(reply)) + if (IS_ERR(reply)) { memcpy(msg->message, &error_reply, sizeof(error_reply)); - else if (t86r->hdr.type == TYPE86_RSP_CODE && + goto out; + } + t86r = reply->message; + if (t86r->hdr.type == TYPE86_RSP_CODE && t86r->cprb.cprb_ver_id == 0x01) { length = sizeof(struct type86_reply) + t86r->length - 2; length = min(PCICC_MAX_RESPONSE_SIZE, length); memcpy(msg->message, reply->message, length); } else memcpy(msg->message, reply->message, sizeof error_reply); +out: complete((struct completion *) msg->private); } diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c index d8ad36f8154032ae5fab9e4cd998a2752aded0fb..e7a1e22e77acf82425b8a60c5d25426f83c6aca4 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.c +++ b/drivers/s390/crypto/zcrypt_pcixcc.c @@ -635,13 +635,16 @@ static void zcrypt_pcixcc_receive(struct ap_device *ap_dev, }; struct response_type *resp_type = (struct response_type *) msg->private; - struct type86x_reply *t86r = reply->message; + struct type86x_reply *t86r; int length; /* Copy the reply message to the request message buffer. */ - if (IS_ERR(reply)) + if (IS_ERR(reply)) { memcpy(msg->message, &error_reply, sizeof(error_reply)); - else if (t86r->hdr.type == TYPE86_RSP_CODE && + goto out; + } + t86r = reply->message; + if (t86r->hdr.type == TYPE86_RSP_CODE && t86r->cprbx.cprb_ver_id == 0x02) { switch (resp_type->type) { case PCIXCC_RESPONSE_TYPE_ICA: @@ -660,6 +663,7 @@ static void zcrypt_pcixcc_receive(struct ap_device *ap_dev, } } else memcpy(msg->message, reply->message, sizeof error_reply); +out: complete(&(resp_type->work)); } diff --git a/drivers/s390/net/ctcm_fsms.c b/drivers/s390/net/ctcm_fsms.c index 42776550acfd936dc797b473b3e6e74b14f2a4ca..f29c7086fc19829540bf72d5bcea996514908449 100644 --- a/drivers/s390/net/ctcm_fsms.c +++ b/drivers/s390/net/ctcm_fsms.c @@ -13,6 +13,9 @@ #undef DEBUGDATA #undef DEBUGCCW +#define KMSG_COMPONENT "ctcm" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include @@ -190,21 +193,22 @@ static void ctcmpc_chx_send_sweep(fsm_instance *fsm, int event, void *arg); void ctcm_ccw_check_rc(struct channel *ch, int rc, char *msg) { CTCM_DBF_TEXT_(ERROR, CTC_DBF_ERROR, - "%s(%s): %s: %04x\n", - CTCM_FUNTAIL, ch->id, msg, rc); + "%s(%s): %s: %04x\n", + CTCM_FUNTAIL, ch->id, msg, rc); switch (rc) { case -EBUSY: - ctcm_pr_warn("%s (%s): Busy !\n", ch->id, msg); + pr_info("%s: The communication peer is busy\n", + ch->id); fsm_event(ch->fsm, CTC_EVENT_IO_EBUSY, ch); break; case -ENODEV: - ctcm_pr_emerg("%s (%s): Invalid device called for IO\n", - ch->id, msg); + pr_err("%s: The specified target device is not valid\n", + ch->id); fsm_event(ch->fsm, CTC_EVENT_IO_ENODEV, ch); break; default: - ctcm_pr_emerg("%s (%s): Unknown error in do_IO %04x\n", - ch->id, msg, rc); + pr_err("An I/O operation resulted in error %04x\n", + rc); fsm_event(ch->fsm, CTC_EVENT_IO_UNKNOWN, ch); } } @@ -886,8 +890,15 @@ static void ctcm_chx_rxiniterr(fsm_instance *fi, int event, void *arg) fsm_newstate(fi, CTC_STATE_RXERR); fsm_event(priv->fsm, DEV_EVENT_RXDOWN, dev); } - } else - ctcm_pr_warn("%s: Error during RX init handshake\n", dev->name); + } else { + CTCM_DBF_TEXT_(ERROR, CTC_DBF_ERROR, + "%s(%s): %s in %s", CTCM_FUNTAIL, ch->id, + ctc_ch_event_names[event], fsm_getstate_str(fi)); + + dev_warn(&dev->dev, + "Initialization failed with RX/TX init handshake " + "error %s\n", ctc_ch_event_names[event]); + } } /** @@ -969,7 +980,9 @@ static void ctcm_chx_txiniterr(fsm_instance *fi, int event, void *arg) "%s(%s): %s in %s", CTCM_FUNTAIL, ch->id, ctc_ch_event_names[event], fsm_getstate_str(fi)); - ctcm_pr_warn("%s: Error during TX init handshake\n", dev->name); + dev_warn(&dev->dev, + "Initialization failed with RX/TX init handshake " + "error %s\n", ctc_ch_event_names[event]); } } @@ -2101,14 +2114,11 @@ static void dev_action_restart(fsm_instance *fi, int event, void *arg) CTCMY_DBF_DEV_NAME(TRACE, dev, ""); if (IS_MPC(priv)) { - ctcm_pr_info("ctcm: %s Restarting Device and " - "MPC Group in 5 seconds\n", - dev->name); restart_timer = CTCM_TIME_1_SEC; } else { - ctcm_pr_info("%s: Restarting\n", dev->name); restart_timer = CTCM_TIME_5_SEC; } + dev_info(&dev->dev, "Restarting device\n"); dev_action_stop(fi, event, arg); fsm_event(priv->fsm, DEV_EVENT_STOP, dev); @@ -2150,16 +2160,16 @@ static void dev_action_chup(fsm_instance *fi, int event, void *arg) case DEV_STATE_STARTWAIT_RX: if (event == DEV_EVENT_RXUP) { fsm_newstate(fi, DEV_STATE_RUNNING); - ctcm_pr_info("%s: connected with remote side\n", - dev->name); + dev_info(&dev->dev, + "Connected with remote side\n"); ctcm_clear_busy(dev); } break; case DEV_STATE_STARTWAIT_TX: if (event == DEV_EVENT_TXUP) { fsm_newstate(fi, DEV_STATE_RUNNING); - ctcm_pr_info("%s: connected with remote side\n", - dev->name); + dev_info(&dev->dev, + "Connected with remote side\n"); ctcm_clear_busy(dev); } break; diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index a4e29836a2aae6ffd15ab35c09c4d48f07b2eb3a..2678573becec0f625cf58ea92ba904a1128a22d7 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c @@ -21,6 +21,9 @@ #undef DEBUGDATA #undef DEBUGCCW +#define KMSG_COMPONENT "ctcm" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include @@ -281,14 +284,16 @@ static long ctcm_check_irb_error(struct ccw_device *cdev, struct irb *irb) switch (PTR_ERR(irb)) { case -EIO: - ctcm_pr_warn("i/o-error on device %s\n", dev_name(&cdev->dev)); + dev_err(&cdev->dev, + "An I/O-error occurred on the CTCM device\n"); break; case -ETIMEDOUT: - ctcm_pr_warn("timeout on device %s\n", dev_name(&cdev->dev)); + dev_err(&cdev->dev, + "An adapter hardware operation timed out\n"); break; default: - ctcm_pr_warn("unknown error %ld on device %s\n", - PTR_ERR(irb), dev_name(&cdev->dev)); + dev_err(&cdev->dev, + "An error occurred on the adapter hardware\n"); } return PTR_ERR(irb); } @@ -309,15 +314,17 @@ static inline void ccw_unit_check(struct channel *ch, __u8 sense) if (sense & SNS0_INTERVENTION_REQ) { if (sense & 0x01) { if (ch->sense_rc != 0x01) { - ctcm_pr_debug("%s: Interface disc. or Sel. " - "reset (remote)\n", ch->id); + pr_notice( + "%s: The communication peer has " + "disconnected\n", ch->id); ch->sense_rc = 0x01; } fsm_event(ch->fsm, CTC_EVENT_UC_RCRESET, ch); } else { if (ch->sense_rc != SNS0_INTERVENTION_REQ) { - ctcm_pr_debug("%s: System reset (remote)\n", - ch->id); + pr_notice( + "%s: The remote operating system is " + "not available\n", ch->id); ch->sense_rc = SNS0_INTERVENTION_REQ; } fsm_event(ch->fsm, CTC_EVENT_UC_RSRESET, ch); @@ -1194,8 +1201,11 @@ static void ctcm_irq_handler(struct ccw_device *cdev, /* Check for unsolicited interrupts. */ if (cgdev == NULL) { - ctcm_pr_warn("ctcm: Got unsolicited irq: c-%02x d-%02x\n", - cstat, dstat); + CTCM_DBF_TEXT_(TRACE, CTC_DBF_ERROR, + "%s(%s) unsolicited irq: c-%02x d-%02x\n", + CTCM_FUNTAIL, dev_name(&cdev->dev), cstat, dstat); + dev_warn(&cdev->dev, + "The adapter received a non-specific IRQ\n"); return; } @@ -1207,31 +1217,34 @@ static void ctcm_irq_handler(struct ccw_device *cdev, else if (priv->channel[WRITE]->cdev == cdev) ch = priv->channel[WRITE]; else { - ctcm_pr_err("ctcm: Can't determine channel for interrupt, " - "device %s\n", dev_name(&cdev->dev)); + dev_err(&cdev->dev, + "%s: Internal error: Can't determine channel for " + "interrupt device %s\n", + __func__, dev_name(&cdev->dev)); + /* Explain: inconsistent internal structures */ return; } dev = ch->netdev; if (dev == NULL) { - ctcm_pr_crit("ctcm: %s dev=NULL bus_id=%s, ch=0x%p\n", - __func__, dev_name(&cdev->dev), ch); + dev_err(&cdev->dev, + "%s Internal error: net_device is NULL, ch = 0x%p\n", + __func__, ch); + /* Explain: inconsistent internal structures */ return; } - CTCM_DBF_TEXT_(TRACE, CTC_DBF_DEBUG, - "%s(%s): int. for %s: cstat=%02x dstat=%02x", - CTCM_FUNTAIL, dev->name, ch->id, cstat, dstat); - /* Copy interruption response block. */ memcpy(ch->irb, irb, sizeof(struct irb)); + /* Issue error message and return on subchannel error code */ if (irb->scsw.cmd.cstat) { - /* Check for good subchannel return code, otherwise error message */ fsm_event(ch->fsm, CTC_EVENT_SC_UNKNOWN, ch); - ctcm_pr_warn("%s: subchannel check for dev: %s - %02x %02x\n", - dev->name, ch->id, irb->scsw.cmd.cstat, - irb->scsw.cmd.dstat); + CTCM_DBF_TEXT_(TRACE, CTC_DBF_WARN, + "%s(%s): sub-ch check %s: cs=%02x ds=%02x", + CTCM_FUNTAIL, dev->name, ch->id, cstat, dstat); + dev_warn(&cdev->dev, + "A check occurred on the subchannel\n"); return; } @@ -1239,7 +1252,7 @@ static void ctcm_irq_handler(struct ccw_device *cdev, if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) { if ((irb->ecw[0] & ch->sense_rc) == 0) /* print it only once */ - CTCM_DBF_TEXT_(TRACE, CTC_DBF_INFO, + CTCM_DBF_TEXT_(TRACE, CTC_DBF_WARN, "%s(%s): sense=%02x, ds=%02x", CTCM_FUNTAIL, ch->id, irb->ecw[0], dstat); ccw_unit_check(ch, irb->ecw[0]); @@ -1574,6 +1587,11 @@ static int ctcm_new_device(struct ccwgroup_device *cgdev) strlcpy(priv->fsm->name, dev->name, sizeof(priv->fsm->name)); + dev_info(&dev->dev, + "setup OK : r/w = %s/%s, protocol : %d\n", + priv->channel[READ]->id, + priv->channel[WRITE]->id, priv->protocol); + CTCM_DBF_TEXT_(SETUP, CTC_DBF_INFO, "setup(%s) OK : r/w = %s/%s, protocol : %d", dev->name, priv->channel[READ]->id, @@ -1687,7 +1705,7 @@ static void __exit ctcm_exit(void) { unregister_cu3088_discipline(&ctcm_group_driver); ctcm_unregister_dbf_views(); - ctcm_pr_info("CTCM driver unloaded\n"); + pr_info("CTCM driver unloaded\n"); } /* @@ -1695,7 +1713,7 @@ static void __exit ctcm_exit(void) */ static void print_banner(void) { - printk(KERN_INFO "CTCM driver initialized\n"); + pr_info("CTCM driver initialized\n"); } /** @@ -1717,8 +1735,8 @@ static int __init ctcm_init(void) ret = register_cu3088_discipline(&ctcm_group_driver); if (ret) { ctcm_unregister_dbf_views(); - ctcm_pr_crit("ctcm_init failed with register_cu3088_discipline " - "(rc = %d)\n", ret); + pr_err("%s / register_cu3088_discipline failed, ret = %d\n", + __func__, ret); return ret; } print_banner(); diff --git a/drivers/s390/net/ctcm_main.h b/drivers/s390/net/ctcm_main.h index d77cce3fe4d48a8bbc6cc97b5346299873f9eeb3..d925e732b7d8f69fbf46785e2d4ee24cb3db8f34 100644 --- a/drivers/s390/net/ctcm_main.h +++ b/drivers/s390/net/ctcm_main.h @@ -41,12 +41,6 @@ #define LOG_FLAG_NOMEM 8 #define ctcm_pr_debug(fmt, arg...) printk(KERN_DEBUG fmt, ##arg) -#define ctcm_pr_info(fmt, arg...) printk(KERN_INFO fmt, ##arg) -#define ctcm_pr_notice(fmt, arg...) printk(KERN_NOTICE fmt, ##arg) -#define ctcm_pr_warn(fmt, arg...) printk(KERN_WARNING fmt, ##arg) -#define ctcm_pr_emerg(fmt, arg...) printk(KERN_EMERG fmt, ##arg) -#define ctcm_pr_err(fmt, arg...) printk(KERN_ERR fmt, ##arg) -#define ctcm_pr_crit(fmt, arg...) printk(KERN_CRIT fmt, ##arg) #define CTCM_PR_DEBUG(fmt, arg...) \ do { \ diff --git a/drivers/s390/net/ctcm_mpc.c b/drivers/s390/net/ctcm_mpc.c index 19f5d5ed85e087b73cce2e24db1bcbc8d92d6a02..3db5f846bbf686f9473b3dbc99c1d1e60b039551 100644 --- a/drivers/s390/net/ctcm_mpc.c +++ b/drivers/s390/net/ctcm_mpc.c @@ -19,6 +19,9 @@ #undef DEBUGDATA #undef DEBUGCCW +#define KMSG_COMPONENT "ctcm" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include @@ -386,7 +389,7 @@ int ctc_mpc_alloc_channel(int port_num, void (*callback)(int, int)) if (grp->allocchan_callback_retries < 4) { if (grp->allochanfunc) grp->allochanfunc(grp->port_num, - grp->group_max_buflen); + grp->group_max_buflen); } else { /* there are problems...bail out */ /* there may be a state mismatch so restart */ @@ -1232,8 +1235,9 @@ static void ctcmpc_unpack_skb(struct channel *ch, struct sk_buff *pskb) dev_kfree_skb_any(pskb); if (sendrc == NET_RX_DROP) { - printk(KERN_WARNING "%s %s() NETWORK BACKLOG EXCEEDED" - " - PACKET DROPPED\n", dev->name, __func__); + dev_warn(&dev->dev, + "The network backlog for %s is exceeded, " + "package dropped\n", __func__); fsm_event(grp->fsm, MPCG_EVENT_INOP, dev); } @@ -1670,10 +1674,11 @@ static int mpc_validate_xid(struct mpcg_info *mpcginfo) CTCM_FUNTAIL, ch->id); } } - done: if (rc) { - ctcm_pr_info("ctcmpc : %s() failed\n", __func__); + dev_warn(&dev->dev, + "The XID used in the MPC protocol is not valid, " + "rc = %d\n", rc); priv->xid->xid2_flag2 = 0x40; grp->saved_xid2->xid2_flag2 = 0x40; } diff --git a/drivers/s390/net/ctcm_sysfs.c b/drivers/s390/net/ctcm_sysfs.c index bb2d13721d3472a8ca27036132aa91a793b95ac7..8452bb052d68aa80f64c6fd10971fc3d4ea31969 100644 --- a/drivers/s390/net/ctcm_sysfs.c +++ b/drivers/s390/net/ctcm_sysfs.c @@ -10,6 +10,9 @@ #undef DEBUGDATA #undef DEBUGCCW +#define KMSG_COMPONENT "ctcm" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include "ctcm_main.h" diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 0825be87e5a00d47812cfef79eee1d784599993c..acca6678cb2bb721c6a433c311fd099779e0dc6d 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -26,6 +26,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define KMSG_COMPONENT "lcs" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include @@ -54,8 +57,6 @@ #error Cannot compile lcs.c without some net devices switched on. #endif -#define PRINTK_HEADER " lcs: " - /** * initialization string for output */ @@ -96,7 +97,7 @@ lcs_register_debug_facility(void) lcs_dbf_setup = debug_register("lcs_setup", 2, 1, 8); lcs_dbf_trace = debug_register("lcs_trace", 4, 1, 8); if (lcs_dbf_setup == NULL || lcs_dbf_trace == NULL) { - PRINT_ERR("Not enough memory for debug facility.\n"); + pr_err("Not enough memory for debug facility.\n"); lcs_unregister_debug_facility(); return -ENOMEM; } @@ -503,7 +504,9 @@ lcs_start_channel(struct lcs_channel *channel) if (rc) { LCS_DBF_TEXT_(4,trace,"essh%s", dev_name(&channel->ccwdev->dev)); - PRINT_ERR("Error in starting channel, rc=%d!\n", rc); + dev_err(&channel->ccwdev->dev, + "Starting an LCS device resulted in an error," + " rc=%d!\n", rc); } return rc; } @@ -640,7 +643,9 @@ __lcs_resume_channel(struct lcs_channel *channel) if (rc) { LCS_DBF_TEXT_(4, trace, "ersc%s", dev_name(&channel->ccwdev->dev)); - PRINT_ERR("Error in lcs_resume_channel: rc=%d\n",rc); + dev_err(&channel->ccwdev->dev, + "Sending data from the LCS device to the LAN failed" + " with rc=%d\n",rc); } else channel->state = LCS_CH_STATE_RUNNING; return rc; @@ -1086,7 +1091,7 @@ lcs_check_multicast_support(struct lcs_card *card) cmd->cmd.lcs_qipassist.num_ip_pairs = 1; rc = lcs_send_lancmd(card, buffer, __lcs_check_multicast_cb); if (rc != 0) { - PRINT_ERR("Query IPAssist failed. Assuming unsupported!\n"); + pr_err("Query IPAssist failed. Assuming unsupported!\n"); return -EOPNOTSUPP; } if (card->ip_assists_supported & LCS_IPASS_MULTICAST_SUPPORT) @@ -1119,8 +1124,8 @@ lcs_fix_multicast_list(struct lcs_card *card) rc = lcs_send_setipm(card, ipm); spin_lock_irqsave(&card->ipm_lock, flags); if (rc) { - PRINT_INFO("Adding multicast address failed. " - "Table possibly full!\n"); + pr_info("Adding multicast address failed." + " Table possibly full!\n"); /* store ipm in failed list -> will be added * to ipm_list again, so a retry will be done * during the next call of this function */ @@ -1231,8 +1236,8 @@ lcs_set_mc_addresses(struct lcs_card *card, struct in_device *in4_dev) ipm = (struct lcs_ipm_list *) kzalloc(sizeof(struct lcs_ipm_list), GFP_ATOMIC); if (ipm == NULL) { - PRINT_INFO("Not enough memory to add " - "new multicast entry!\n"); + pr_info("Not enough memory to add" + " new multicast entry!\n"); break; } memcpy(&ipm->ipm.mac_addr, buf, LCS_MAC_LENGTH); @@ -1290,7 +1295,7 @@ lcs_set_multicast_list(struct net_device *dev) struct lcs_card *card; LCS_DBF_TEXT(4, trace, "setmulti"); - card = (struct lcs_card *) dev->priv; + card = (struct lcs_card *) dev->ml_priv; if (!lcs_set_thread_start_bit(card, LCS_SET_MC_THREAD)) schedule_work(&card->kernel_thread_starter); @@ -1306,18 +1311,21 @@ lcs_check_irb_error(struct ccw_device *cdev, struct irb *irb) switch (PTR_ERR(irb)) { case -EIO: - PRINT_WARN("i/o-error on device %s\n", dev_name(&cdev->dev)); + dev_warn(&cdev->dev, + "An I/O-error occurred on the LCS device\n"); LCS_DBF_TEXT(2, trace, "ckirberr"); LCS_DBF_TEXT_(2, trace, " rc%d", -EIO); break; case -ETIMEDOUT: - PRINT_WARN("timeout on device %s\n", dev_name(&cdev->dev)); + dev_warn(&cdev->dev, + "A command timed out on the LCS device\n"); LCS_DBF_TEXT(2, trace, "ckirberr"); LCS_DBF_TEXT_(2, trace, " rc%d", -ETIMEDOUT); break; default: - PRINT_WARN("unknown error %ld on device %s\n", PTR_ERR(irb), - dev_name(&cdev->dev)); + dev_warn(&cdev->dev, + "An error occurred on the LCS device, rc=%ld\n", + PTR_ERR(irb)); LCS_DBF_TEXT(2, trace, "ckirberr"); LCS_DBF_TEXT(2, trace, " rc???"); } @@ -1403,8 +1411,10 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) /* Check for channel and device errors presented */ rc = lcs_get_problem(cdev, irb); if (rc || (dstat & DEV_STAT_UNIT_EXCEP)) { - PRINT_WARN("check on device %s, dstat=0x%X, cstat=0x%X \n", - dev_name(&cdev->dev), dstat, cstat); + dev_warn(&cdev->dev, + "The LCS device stopped because of an error," + " dstat=0x%X, cstat=0x%X \n", + dstat, cstat); if (rc) { channel->state = LCS_CH_STATE_ERROR; } @@ -1607,7 +1617,7 @@ lcs_start_xmit(struct sk_buff *skb, struct net_device *dev) int rc; LCS_DBF_TEXT(5, trace, "pktxmit"); - card = (struct lcs_card *) dev->priv; + card = (struct lcs_card *) dev->ml_priv; rc = __lcs_start_xmit(card, skb, dev); return rc; } @@ -1761,8 +1771,8 @@ lcs_get_control(struct lcs_card *card, struct lcs_cmd *cmd) lcs_schedule_recovery(card); break; case LCS_CMD_STOPLAN: - PRINT_WARN("Stoplan for %s initiated by LGW.\n", - card->dev->name); + pr_warning("Stoplan for %s initiated by LGW.\n", + card->dev->name); if (card->dev) netif_carrier_off(card->dev); break; @@ -1790,7 +1800,8 @@ lcs_get_skb(struct lcs_card *card, char *skb_data, unsigned int skb_len) skb = dev_alloc_skb(skb_len); if (skb == NULL) { - PRINT_ERR("LCS: alloc_skb failed for device=%s\n", + dev_err(&card->dev->dev, + " Allocating a socket buffer to interface %s failed\n", card->dev->name); card->stats.rx_dropped++; return; @@ -1863,7 +1874,7 @@ lcs_getstats(struct net_device *dev) struct lcs_card *card; LCS_DBF_TEXT(4, trace, "netstats"); - card = (struct lcs_card *) dev->priv; + card = (struct lcs_card *) dev->ml_priv; return &card->stats; } @@ -1878,7 +1889,7 @@ lcs_stop_device(struct net_device *dev) int rc; LCS_DBF_TEXT(2, trace, "stopdev"); - card = (struct lcs_card *) dev->priv; + card = (struct lcs_card *) dev->ml_priv; netif_carrier_off(dev); netif_tx_disable(dev); dev->flags &= ~IFF_UP; @@ -1886,7 +1897,8 @@ lcs_stop_device(struct net_device *dev) (card->write.state != LCS_CH_STATE_RUNNING)); rc = lcs_stopcard(card); if (rc) - PRINT_ERR("Try it again!\n "); + dev_err(&card->dev->dev, + " Shutting down the LCS device failed\n "); return rc; } @@ -1901,11 +1913,11 @@ lcs_open_device(struct net_device *dev) int rc; LCS_DBF_TEXT(2, trace, "opendev"); - card = (struct lcs_card *) dev->priv; + card = (struct lcs_card *) dev->ml_priv; /* initialize statistics */ rc = lcs_detect(card); if (rc) { - PRINT_ERR("LCS:Error in opening device!\n"); + pr_err("Error in opening device!\n"); } else { dev->flags |= IFF_UP; @@ -2113,8 +2125,9 @@ lcs_new_device(struct ccwgroup_device *ccwgdev) rc = lcs_detect(card); if (rc) { LCS_DBF_TEXT(2, setup, "dtctfail"); - PRINT_WARN("Detection of LCS card failed with return code " - "%d (0x%x)\n", rc, rc); + dev_err(&card->dev->dev, + "Detecting a network adapter for LCS devices" + " failed with rc=%d (0x%x)\n", rc, rc); lcs_stopcard(card); goto out; } @@ -2144,13 +2157,13 @@ lcs_new_device(struct ccwgroup_device *ccwgdev) #endif default: LCS_DBF_TEXT(3, setup, "errinit"); - PRINT_ERR("LCS: Initialization failed\n"); + pr_err(" Initialization failed\n"); goto out; } if (!dev) goto out; card->dev = dev; - card->dev->priv = card; + card->dev->ml_priv = card; card->dev->open = lcs_open_device; card->dev->stop = lcs_stop_device; card->dev->hard_start_xmit = lcs_start_xmit; @@ -2176,13 +2189,13 @@ lcs_new_device(struct ccwgroup_device *ccwgdev) goto out; /* Print out supported assists: IPv6 */ - PRINT_INFO("LCS device %s %s IPv6 support\n", card->dev->name, - (card->ip_assists_supported & LCS_IPASS_IPV6_SUPPORT) ? - "with" : "without"); + pr_info("LCS device %s %s IPv6 support\n", card->dev->name, + (card->ip_assists_supported & LCS_IPASS_IPV6_SUPPORT) ? + "with" : "without"); /* Print out supported assist: Multicast */ - PRINT_INFO("LCS device %s %s Multicast support\n", card->dev->name, - (card->ip_assists_supported & LCS_IPASS_MULTICAST_SUPPORT) ? - "with" : "without"); + pr_info("LCS device %s %s Multicast support\n", card->dev->name, + (card->ip_assists_supported & LCS_IPASS_MULTICAST_SUPPORT) ? + "with" : "without"); return 0; out: @@ -2248,15 +2261,16 @@ lcs_recovery(void *ptr) return 0; LCS_DBF_TEXT(4, trace, "recover2"); gdev = card->gdev; - PRINT_WARN("Recovery of device %s started...\n", dev_name(&gdev->dev)); + dev_warn(&gdev->dev, + "A recovery process has been started for the LCS device\n"); rc = __lcs_shutdown_device(gdev, 1); rc = lcs_new_device(gdev); if (!rc) - PRINT_INFO("Device %s successfully recovered!\n", - card->dev->name); + pr_info("Device %s successfully recovered!\n", + card->dev->name); else - PRINT_INFO("Device %s could not be recovered!\n", - card->dev->name); + pr_info("Device %s could not be recovered!\n", + card->dev->name); lcs_clear_thread_running_bit(card, LCS_RECOVERY_THREAD); return 0; } @@ -2308,17 +2322,17 @@ __init lcs_init_module(void) { int rc; - PRINT_INFO("Loading %s\n",version); + pr_info("Loading %s\n", version); rc = lcs_register_debug_facility(); LCS_DBF_TEXT(0, setup, "lcsinit"); if (rc) { - PRINT_ERR("Initialization failed\n"); + pr_err("Initialization failed\n"); return rc; } rc = register_cu3088_discipline(&lcs_group_driver); if (rc) { - PRINT_ERR("Initialization failed\n"); + pr_err("Initialization failed\n"); return rc; } return 0; @@ -2331,7 +2345,7 @@ __init lcs_init_module(void) static void __exit lcs_cleanup_module(void) { - PRINT_INFO("Terminating lcs module.\n"); + pr_info("Terminating lcs module.\n"); LCS_DBF_TEXT(0, trace, "cleanup"); unregister_cu3088_discipline(&lcs_group_driver); lcs_unregister_debug_facility(); diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index 0fea51e34b5751b06f2ddc728c2116c8d6d3f3b7..930e2fc2a011a39fea837fa8435d3b1622e31fac 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -31,6 +31,9 @@ * */ +#define KMSG_COMPONENT "netiucv" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #undef DEBUG #include @@ -846,7 +849,8 @@ static void conn_action_connsever(fsm_instance *fi, int event, void *arg) fsm_deltimer(&conn->timer); iucv_path_sever(conn->path, NULL); - PRINT_INFO("%s: Remote dropped connection\n", netdev->name); + dev_info(privptr->dev, "The peer interface of the IUCV device" + " has closed the connection\n"); IUCV_DBF_TEXT(data, 2, "conn_action_connsever: Remote dropped connection\n"); fsm_newstate(fi, CONN_STATE_STARTWAIT); @@ -856,13 +860,15 @@ static void conn_action_connsever(fsm_instance *fi, int event, void *arg) static void conn_action_start(fsm_instance *fi, int event, void *arg) { struct iucv_connection *conn = arg; + struct net_device *netdev = conn->netdev; + struct netiucv_priv *privptr = netdev_priv(netdev); int rc; IUCV_DBF_TEXT(trace, 3, __func__); fsm_newstate(fi, CONN_STATE_STARTWAIT); IUCV_DBF_TEXT_(setup, 2, "%s('%s'): connecting ...\n", - conn->netdev->name, conn->userid); + netdev->name, conn->userid); /* * We must set the state before calling iucv_connect because the @@ -876,41 +882,45 @@ static void conn_action_start(fsm_instance *fi, int event, void *arg) NULL, iucvMagic, conn); switch (rc) { case 0: - conn->netdev->tx_queue_len = conn->path->msglim; + netdev->tx_queue_len = conn->path->msglim; fsm_addtimer(&conn->timer, NETIUCV_TIMEOUT_5SEC, CONN_EVENT_TIMER, conn); return; case 11: - PRINT_INFO("%s: User %s is currently not available.\n", - conn->netdev->name, - netiucv_printname(conn->userid)); + dev_warn(privptr->dev, + "The IUCV device failed to connect to z/VM guest %s\n", + netiucv_printname(conn->userid)); fsm_newstate(fi, CONN_STATE_STARTWAIT); break; case 12: - PRINT_INFO("%s: User %s is currently not ready.\n", - conn->netdev->name, - netiucv_printname(conn->userid)); + dev_warn(privptr->dev, + "The IUCV device failed to connect to the peer on z/VM" + " guest %s\n", netiucv_printname(conn->userid)); fsm_newstate(fi, CONN_STATE_STARTWAIT); break; case 13: - PRINT_WARN("%s: Too many IUCV connections.\n", - conn->netdev->name); + dev_err(privptr->dev, + "Connecting the IUCV device would exceed the maximum" + " number of IUCV connections\n"); fsm_newstate(fi, CONN_STATE_CONNERR); break; case 14: - PRINT_WARN("%s: User %s has too many IUCV connections.\n", - conn->netdev->name, - netiucv_printname(conn->userid)); + dev_err(privptr->dev, + "z/VM guest %s has too many IUCV connections" + " to connect with the IUCV device\n", + netiucv_printname(conn->userid)); fsm_newstate(fi, CONN_STATE_CONNERR); break; case 15: - PRINT_WARN("%s: No IUCV authorization in CP directory.\n", - conn->netdev->name); + dev_err(privptr->dev, + "The IUCV device cannot connect to a z/VM guest with no" + " IUCV authorization\n"); fsm_newstate(fi, CONN_STATE_CONNERR); break; default: - PRINT_WARN("%s: iucv_connect returned error %d\n", - conn->netdev->name, rc); + dev_err(privptr->dev, + "Connecting the IUCV device failed with error %d\n", + rc); fsm_newstate(fi, CONN_STATE_CONNERR); break; } @@ -1059,8 +1069,9 @@ dev_action_connup(fsm_instance *fi, int event, void *arg) switch (fsm_getstate(fi)) { case DEV_STATE_STARTWAIT: fsm_newstate(fi, DEV_STATE_RUNNING); - PRINT_INFO("%s: connected with remote side %s\n", - dev->name, privptr->conn->userid); + dev_info(privptr->dev, + "The IUCV device has been connected" + " successfully to %s\n", privptr->conn->userid); IUCV_DBF_TEXT(setup, 3, "connection is up and running\n"); break; @@ -1982,6 +1993,8 @@ static ssize_t conn_write(struct device_driver *drv, if (rc) goto out_unreg; + dev_info(priv->dev, "The IUCV interface to %s has been" + " established successfully\n", netiucv_printname(username)); return count; @@ -2027,10 +2040,9 @@ static ssize_t remove_write (struct device_driver *drv, continue; read_unlock_bh(&iucv_connection_rwlock); if (ndev->flags & (IFF_UP | IFF_RUNNING)) { - PRINT_WARN("netiucv: net device %s active with peer " - "%s\n", ndev->name, priv->conn->userid); - PRINT_WARN("netiucv: %s cannot be removed\n", - ndev->name); + dev_warn(dev, "The IUCV device is connected" + " to %s and cannot be removed\n", + priv->conn->userid); IUCV_DBF_TEXT(data, 2, "remove_write: still active\n"); return -EPERM; } @@ -2062,7 +2074,7 @@ static struct attribute_group *netiucv_drv_attr_groups[] = { static void netiucv_banner(void) { - PRINT_INFO("NETIUCV driver initialized\n"); + pr_info("driver initialized\n"); } static void __exit netiucv_exit(void) @@ -2088,7 +2100,7 @@ static void __exit netiucv_exit(void) iucv_unregister(&netiucv_handler, 1); iucv_unregister_dbf_views(); - PRINT_INFO("NETIUCV driver unloaded\n"); + pr_info("driver unloaded\n"); return; } diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index af6d6045851394f94d9234af65ac115b4c37a9ef..d5ccce1643e43a9fc477ccda2ede4cbbf6ad2a73 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -31,11 +31,10 @@ #include #include #include +#include #include "qeth_core_mpc.h" -#define KMSG_COMPONENT "qeth" - /** * Debug Facility stuff */ @@ -74,11 +73,6 @@ struct qeth_dbf_info { #define QETH_DBF_TEXT_(name, level, text...) \ qeth_dbf_longtext(QETH_DBF_##name, level, text) -/** - * some more debug stuff - */ -#define PRINTK_HEADER "qeth: " - #define SENSE_COMMAND_REJECT_BYTE 0 #define SENSE_COMMAND_REJECT_FLAG 0x80 #define SENSE_RESETTING_EVENT_BYTE 1 @@ -733,6 +727,7 @@ struct qeth_card { struct qeth_osn_info osn_info; struct qeth_discipline discipline; atomic_t force_alloc_skb; + struct service_level qeth_service_level; }; struct qeth_card_list_struct { diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 52d26592c72c1a03ee640710d148d3aa44a1b781..e783644a2105b41d7b45e2fda6318f72badae3da 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -8,6 +8,9 @@ * Frank Blaschka */ +#define KMSG_COMPONENT "qeth" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include @@ -319,7 +322,10 @@ static int qeth_issue_next_read(struct qeth_card *card) return -EIO; iob = qeth_get_buffer(&card->read); if (!iob) { - PRINT_WARN("issue_next_read failed: no iob available!\n"); + dev_warn(&card->gdev->dev, "The qeth device driver " + "failed to recover an error on the device\n"); + QETH_DBF_MESSAGE(2, "%s issue_next_read failed: no iob " + "available\n", dev_name(&card->gdev->dev)); return -ENOMEM; } qeth_setup_ccw(&card->read, iob->data, QETH_BUFSIZE); @@ -327,7 +333,8 @@ static int qeth_issue_next_read(struct qeth_card *card) rc = ccw_device_start(card->read.ccwdev, &card->read.ccw, (addr_t) iob, 0, 0); if (rc) { - PRINT_ERR("Error in starting next read ccw! rc=%i\n", rc); + QETH_DBF_MESSAGE(2, "%s error in starting next read ccw! " + "rc=%i\n", dev_name(&card->gdev->dev), rc); atomic_set(&card->read.irq_pending, 0); qeth_schedule_recovery(card); wake_up(&card->wait_q); @@ -393,10 +400,9 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card, } else { switch (cmd->hdr.command) { case IPA_CMD_STOPLAN: - PRINT_WARN("Link failure on %s (CHPID 0x%X) - " - "there is a network problem or " - "someone pulled the cable or " - "disabled the port.\n", + dev_warn(&card->gdev->dev, + "The link for interface %s on CHPID" + " 0x%X failed\n", QETH_CARD_IFNAME(card), card->info.chpid); card->lan_online = 0; @@ -404,9 +410,9 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card, netif_carrier_off(card->dev); return NULL; case IPA_CMD_STARTLAN: - PRINT_INFO("Link reestablished on %s " - "(CHPID 0x%X). Scheduling " - "IP address reset.\n", + dev_info(&card->gdev->dev, + "The link for %s on CHPID 0x%X has" + " been restored\n", QETH_CARD_IFNAME(card), card->info.chpid); netif_carrier_on(card->dev); @@ -458,7 +464,7 @@ static int qeth_check_idx_response(unsigned char *buffer) QETH_DBF_HEX(CTRL, 2, buffer, QETH_DBF_CTRL_LEN); if ((buffer[2] & 0xc0) == 0xc0) { - PRINT_WARN("received an IDX TERMINATE " + QETH_DBF_MESSAGE(2, "received an IDX TERMINATE " "with cause code 0x%02x%s\n", buffer[4], ((buffer[4] == 0x22) ? @@ -744,8 +750,10 @@ static int qeth_get_problem(struct ccw_device *cdev, struct irb *irb) SCHN_STAT_CHN_DATA_CHK | SCHN_STAT_CHAIN_CHECK | SCHN_STAT_PROT_CHECK | SCHN_STAT_PROG_CHECK)) { QETH_DBF_TEXT(TRACE, 2, "CGENCHK"); - PRINT_WARN("check on device %s, dstat=x%x, cstat=x%x ", - dev_name(&cdev->dev), dstat, cstat); + dev_warn(&cdev->dev, "The qeth device driver " + "failed to recover an error on the device\n"); + QETH_DBF_MESSAGE(2, "%s check on device dstat=x%x, cstat=x%x ", + dev_name(&cdev->dev), dstat, cstat); print_hex_dump(KERN_WARNING, "qeth: irb ", DUMP_PREFIX_OFFSET, 16, 1, irb, 64, 1); return 1; @@ -784,12 +792,14 @@ static long __qeth_check_irb_error(struct ccw_device *cdev, switch (PTR_ERR(irb)) { case -EIO: - PRINT_WARN("i/o-error on device %s\n", dev_name(&cdev->dev)); + QETH_DBF_MESSAGE(2, "%s i/o-error on device\n", + dev_name(&cdev->dev)); QETH_DBF_TEXT(TRACE, 2, "ckirberr"); QETH_DBF_TEXT_(TRACE, 2, " rc%d", -EIO); break; case -ETIMEDOUT: - PRINT_WARN("timeout on device %s\n", dev_name(&cdev->dev)); + dev_warn(&cdev->dev, "A hardware operation timed out" + " on the device\n"); QETH_DBF_TEXT(TRACE, 2, "ckirberr"); QETH_DBF_TEXT_(TRACE, 2, " rc%d", -ETIMEDOUT); if (intparm == QETH_RCD_PARM) { @@ -802,8 +812,8 @@ static long __qeth_check_irb_error(struct ccw_device *cdev, } break; default: - PRINT_WARN("unknown error %ld on device %s\n", PTR_ERR(irb), - dev_name(&cdev->dev)); + QETH_DBF_MESSAGE(2, "%s unknown error %ld on device\n", + dev_name(&cdev->dev), PTR_ERR(irb)); QETH_DBF_TEXT(TRACE, 2, "ckirberr"); QETH_DBF_TEXT(TRACE, 2, " rc???"); } @@ -869,10 +879,12 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm, (dstat & DEV_STAT_UNIT_CHECK) || (cstat)) { if (irb->esw.esw0.erw.cons) { - /* TODO: we should make this s390dbf */ - PRINT_WARN("sense data available on channel %s.\n", - CHANNEL_ID(channel)); - PRINT_WARN(" cstat 0x%X\n dstat 0x%X\n", cstat, dstat); + dev_warn(&channel->ccwdev->dev, + "The qeth device driver failed to recover " + "an error on the device\n"); + QETH_DBF_MESSAGE(2, "%s sense data available. cstat " + "0x%X dstat 0x%X\n", + dev_name(&channel->ccwdev->dev), cstat, dstat); print_hex_dump(KERN_WARNING, "qeth: irb ", DUMP_PREFIX_OFFSET, 16, 1, irb, 32, 1); print_hex_dump(KERN_WARNING, "qeth: sense data ", @@ -1138,6 +1150,14 @@ static int qeth_setup_card(struct qeth_card *card) return 0; } +static void qeth_core_sl_print(struct seq_file *m, struct service_level *slr) +{ + struct qeth_card *card = container_of(slr, struct qeth_card, + qeth_service_level); + seq_printf(m, "qeth: %s firmware level %s\n", CARD_BUS_ID(card), + card->info.mcl_level); +} + static struct qeth_card *qeth_alloc_card(void) { struct qeth_card *card; @@ -1157,6 +1177,8 @@ static struct qeth_card *qeth_alloc_card(void) return NULL; } card->options.layer2 = -1; + card->qeth_service_level.seq_print = qeth_core_sl_print; + register_service_level(&card->qeth_service_level); return card; } @@ -1175,8 +1197,8 @@ static int qeth_determine_card_type(struct qeth_card *card) card->qdio.no_out_queues = known_devices[i][8]; card->info.is_multicast_different = known_devices[i][9]; if (qeth_is_1920_device(card)) { - PRINT_INFO("Priority Queueing not able " - "due to hardware limitations!\n"); + dev_info(&card->gdev->dev, + "Priority Queueing not supported\n"); card->qdio.no_out_queues = 1; card->qdio.default_out_queue = 0; } @@ -1185,7 +1207,8 @@ static int qeth_determine_card_type(struct qeth_card *card) i++; } card->info.type = QETH_CARD_TYPE_UNKNOWN; - PRINT_ERR("unknown card type on device %s\n", CARD_BUS_ID(card)); + dev_err(&card->gdev->dev, "The adapter hardware is of an " + "unknown type\n"); return -ENOENT; } @@ -1368,8 +1391,8 @@ static int qeth_get_unitaddr(struct qeth_card *card) QETH_DBF_TEXT(SETUP, 2, "getunit"); rc = qeth_read_conf_data(card, (void **) &prcd, &length); if (rc) { - PRINT_ERR("qeth_read_conf_data for device %s returned %i\n", - CARD_DDEV_ID(card), rc); + QETH_DBF_MESSAGE(2, "%s qeth_read_conf_data returned %i\n", + dev_name(&card->gdev->dev), rc); return rc; } card->info.chpid = prcd[30]; @@ -1519,7 +1542,10 @@ static int qeth_idx_activate_channel(struct qeth_channel *channel, if (rc == -ERESTARTSYS) return rc; if (channel->state != CH_STATE_ACTIVATING) { - PRINT_WARN("IDX activate timed out!\n"); + dev_warn(&channel->ccwdev->dev, "The qeth device driver" + " failed to recover an error on the device\n"); + QETH_DBF_MESSAGE(2, "%s IDX activate timed out\n", + dev_name(&channel->ccwdev->dev)); QETH_DBF_TEXT_(SETUP, 2, "2err%d", -ETIME); qeth_clear_cmd_buffers(channel); return -ETIME; @@ -1552,20 +1578,21 @@ static void qeth_idx_write_cb(struct qeth_channel *channel, if (!(QETH_IS_IDX_ACT_POS_REPLY(iob->data))) { if (QETH_IDX_ACT_CAUSE_CODE(iob->data) == 0x19) - PRINT_ERR("IDX_ACTIVATE on write channel device %s: " - "adapter exclusively used by another host\n", - CARD_WDEV_ID(card)); + dev_err(&card->write.ccwdev->dev, + "The adapter is used exclusively by another " + "host\n"); else - PRINT_ERR("IDX_ACTIVATE on write channel device %s: " - "negative reply\n", CARD_WDEV_ID(card)); + QETH_DBF_MESSAGE(2, "%s IDX_ACTIVATE on write channel:" + " negative reply\n", + dev_name(&card->write.ccwdev->dev)); goto out; } memcpy(&temp, QETH_IDX_ACT_FUNC_LEVEL(iob->data), 2); if ((temp & ~0x0100) != qeth_peer_func_level(card->info.func_level)) { - PRINT_WARN("IDX_ACTIVATE on write channel device %s: " - "function level mismatch " - "(sent: 0x%x, received: 0x%x)\n", - CARD_WDEV_ID(card), card->info.func_level, temp); + QETH_DBF_MESSAGE(2, "%s IDX_ACTIVATE on write channel: " + "function level mismatch (sent: 0x%x, received: " + "0x%x)\n", dev_name(&card->write.ccwdev->dev), + card->info.func_level, temp); goto out; } channel->state = CH_STATE_UP; @@ -1591,12 +1618,13 @@ static void qeth_idx_read_cb(struct qeth_channel *channel, if (!(QETH_IS_IDX_ACT_POS_REPLY(iob->data))) { if (QETH_IDX_ACT_CAUSE_CODE(iob->data) == 0x19) - PRINT_ERR("IDX_ACTIVATE on read channel device %s: " - "adapter exclusively used by another host\n", - CARD_RDEV_ID(card)); + dev_err(&card->write.ccwdev->dev, + "The adapter is used exclusively by another " + "host\n"); else - PRINT_ERR("IDX_ACTIVATE on read channel device %s: " - "negative reply\n", CARD_RDEV_ID(card)); + QETH_DBF_MESSAGE(2, "%s IDX_ACTIVATE on read channel:" + " negative reply\n", + dev_name(&card->read.ccwdev->dev)); goto out; } @@ -1610,9 +1638,10 @@ static void qeth_idx_read_cb(struct qeth_channel *channel, memcpy(&temp, QETH_IDX_ACT_FUNC_LEVEL(iob->data), 2); if (temp != qeth_peer_func_level(card->info.func_level)) { - PRINT_WARN("IDX_ACTIVATE on read channel device %s: function " - "level mismatch (sent: 0x%x, received: 0x%x)\n", - CARD_RDEV_ID(card), card->info.func_level, temp); + QETH_DBF_MESSAGE(2, "%s IDX_ACTIVATE on read channel: function " + "level mismatch (sent: 0x%x, received: 0x%x)\n", + dev_name(&card->read.ccwdev->dev), + card->info.func_level, temp); goto out; } memcpy(&card->token.issuer_rm_r, @@ -1686,8 +1715,9 @@ int qeth_send_control_data(struct qeth_card *card, int len, (addr_t) iob, 0, 0); spin_unlock_irqrestore(get_ccwdev_lock(card->write.ccwdev), flags); if (rc) { - PRINT_WARN("qeth_send_control_data: " - "ccw_device_start rc = %i\n", rc); + QETH_DBF_MESSAGE(2, "%s qeth_send_control_data: " + "ccw_device_start rc = %i\n", + dev_name(&card->write.ccwdev->dev), rc); QETH_DBF_TEXT_(TRACE, 2, " err%d", rc); spin_lock_irqsave(&card->lock, flags); list_del_init(&reply->list); @@ -2170,11 +2200,8 @@ static void qeth_print_status_with_portname(struct qeth_card *card) dbf_text[i] = (char) _ebcasc[(__u8) dbf_text[i]]; dbf_text[8] = 0; - PRINT_INFO("Device %s/%s/%s is a%s card%s%s%s\n" + dev_info(&card->gdev->dev, "Device is a%s card%s%s%s\n" "with link type %s (portname: %s)\n", - CARD_RDEV_ID(card), - CARD_WDEV_ID(card), - CARD_DDEV_ID(card), qeth_get_cardname(card), (card->info.mcl_level[0]) ? " (level: " : "", (card->info.mcl_level[0]) ? card->info.mcl_level : "", @@ -2187,23 +2214,17 @@ static void qeth_print_status_with_portname(struct qeth_card *card) static void qeth_print_status_no_portname(struct qeth_card *card) { if (card->info.portname[0]) - PRINT_INFO("Device %s/%s/%s is a%s " + dev_info(&card->gdev->dev, "Device is a%s " "card%s%s%s\nwith link type %s " "(no portname needed by interface).\n", - CARD_RDEV_ID(card), - CARD_WDEV_ID(card), - CARD_DDEV_ID(card), qeth_get_cardname(card), (card->info.mcl_level[0]) ? " (level: " : "", (card->info.mcl_level[0]) ? card->info.mcl_level : "", (card->info.mcl_level[0]) ? ")" : "", qeth_get_cardname_short(card)); else - PRINT_INFO("Device %s/%s/%s is a%s " + dev_info(&card->gdev->dev, "Device is a%s " "card%s%s%s\nwith link type %s.\n", - CARD_RDEV_ID(card), - CARD_WDEV_ID(card), - CARD_DDEV_ID(card), qeth_get_cardname(card), (card->info.mcl_level[0]) ? " (level: " : "", (card->info.mcl_level[0]) ? card->info.mcl_level : "", @@ -2325,7 +2346,6 @@ static int qeth_init_input_buffer(struct qeth_card *card, * the QETH_IN_BUF_REQUEUE_THRESHOLD we should never run out off * buffers */ - BUG_ON(!pool_entry); buf->pool_entry = pool_entry; for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i) { @@ -2630,9 +2650,8 @@ void qeth_queue_input_buffer(struct qeth_card *card, int index) qeth_get_micros() - card->perf_stats.inbound_do_qdio_start_time; if (rc) { - PRINT_WARN("qeth_queue_input_buffer's do_QDIO " - "return %i (device %s).\n", - rc, CARD_DDEV_ID(card)); + dev_warn(&card->gdev->dev, + "QDIO reported an error, rc=%i\n", rc); QETH_DBF_TEXT(TRACE, 2, "qinberr"); QETH_DBF_TEXT_(TRACE, 2, "%s", CARD_BUS_ID(card)); } @@ -3730,6 +3749,7 @@ static void qeth_core_free_card(struct qeth_card *card) free_netdev(card->dev); kfree(card->ip_tbd_list); qeth_free_qdio_buffers(card); + unregister_service_level(&card->qeth_service_level); kfree(card); } @@ -3757,7 +3777,7 @@ static int qeth_core_driver_group(const char *buf, struct device *root_dev, int qeth_core_hardsetup_card(struct qeth_card *card) { - struct qdio_ssqd_desc *qdio_ssqd; + struct qdio_ssqd_desc *ssqd; int retries = 3; int mpno = 0; int rc; @@ -3766,7 +3786,8 @@ int qeth_core_hardsetup_card(struct qeth_card *card) atomic_set(&card->force_alloc_skb, 0); retry: if (retries < 3) { - PRINT_WARN("Retrying to do IDX activates.\n"); + QETH_DBF_MESSAGE(2, "%s Retrying to do IDX activates.\n", + dev_name(&card->gdev->dev)); ccw_device_set_offline(CARD_DDEV(card)); ccw_device_set_offline(CARD_WDEV(card)); ccw_device_set_offline(CARD_RDEV(card)); @@ -3792,9 +3813,16 @@ int qeth_core_hardsetup_card(struct qeth_card *card) return rc; } - qdio_ssqd = qdio_get_ssqd_desc(CARD_DDEV(card)); - if (qdio_ssqd) - mpno = qdio_ssqd->pcnt; + ssqd = kmalloc(sizeof(struct qdio_ssqd_desc), GFP_KERNEL); + if (!ssqd) { + rc = -ENOMEM; + goto out; + } + rc = qdio_get_ssqd_desc(CARD_DDEV(card), ssqd); + if (rc == 0) + mpno = ssqd->pcnt; + kfree(ssqd); + if (mpno) mpno = min(mpno - 1, QETH_MAX_PORTNO); if (card->info.portno > mpno) { @@ -3834,7 +3862,10 @@ int qeth_core_hardsetup_card(struct qeth_card *card) } return 0; out: - PRINT_ERR("Initialization in hardsetup failed! rc=%d\n", rc); + dev_warn(&card->gdev->dev, "The qeth device driver failed to recover " + "an error on the device\n"); + QETH_DBF_MESSAGE(2, "%s Initialization in hardsetup failed! rc=%d\n", + dev_name(&card->gdev->dev), rc); return rc; } EXPORT_SYMBOL_GPL(qeth_core_hardsetup_card); @@ -4054,8 +4085,8 @@ int qeth_core_load_discipline(struct qeth_card *card, break; } if (!card->discipline.ccwgdriver) { - PRINT_ERR("Support for discipline %d not present\n", - discipline); + dev_err(&card->gdev->dev, "There is no kernel module to " + "support discipline %d\n", discipline); rc = -EINVAL; } return rc; @@ -4448,7 +4479,7 @@ static int __init qeth_core_init(void) { int rc; - PRINT_INFO("loading core functions\n"); + pr_info("loading core functions\n"); INIT_LIST_HEAD(&qeth_core_card_list.list); rwlock_init(&qeth_core_card_list.rwlock); @@ -4488,9 +4519,10 @@ static int __init qeth_core_init(void) ccwgroup_err: ccw_driver_unregister(&qeth_ccw_driver); ccw_err: + QETH_DBF_MESSAGE(2, "Initialization failed with code %d\n", rc); qeth_unregister_dbf_views(); out_err: - PRINT_ERR("Initialization failed with code %d\n", rc); + pr_err("Initializing the qeth device driver failed\n"); return rc; } @@ -4503,7 +4535,7 @@ static void __exit qeth_core_exit(void) ccw_driver_unregister(&qeth_ccw_driver); kmem_cache_destroy(qeth_core_header_cache); qeth_unregister_dbf_views(); - PRINT_INFO("core functions removed\n"); + pr_info("core functions removed\n"); } module_init(qeth_core_init); diff --git a/drivers/s390/net/qeth_core_offl.c b/drivers/s390/net/qeth_core_offl.c index 452874e897400fbf340c57bfdd46ab30b0dbd173..4080126ca48c916352e8a44e94932b6586528cc7 100644 --- a/drivers/s390/net/qeth_core_offl.c +++ b/drivers/s390/net/qeth_core_offl.c @@ -350,7 +350,7 @@ static __wsum qeth_eddp_check_tcp4_hdr(struct qeth_eddp_data *eddp, phcsum = csum_tcpudp_nofold(eddp->nh.ip4.h.saddr, eddp->nh.ip4.h.daddr, eddp->thl + data_len, IPPROTO_TCP, 0); /* compute checksum of tcp header */ - return csum_partial((u8 *)&eddp->th, eddp->thl, phcsum); + return csum_partial(&eddp->th, eddp->thl, phcsum); } static __wsum qeth_eddp_check_tcp6_hdr(struct qeth_eddp_data *eddp, @@ -362,12 +362,12 @@ static __wsum qeth_eddp_check_tcp6_hdr(struct qeth_eddp_data *eddp, QETH_DBF_TEXT(TRACE, 5, "eddpckt6"); eddp->th.tcp.h.check = 0; /* compute pseudo header checksum */ - phcsum = csum_partial((u8 *)&eddp->nh.ip6.h.saddr, + phcsum = csum_partial(&eddp->nh.ip6.h.saddr, sizeof(struct in6_addr), 0); - phcsum = csum_partial((u8 *)&eddp->nh.ip6.h.daddr, + phcsum = csum_partial(&eddp->nh.ip6.h.daddr, sizeof(struct in6_addr), phcsum); proto = htonl(IPPROTO_TCP); - phcsum = csum_partial((u8 *)&proto, sizeof(u32), phcsum); + phcsum = csum_partial(&proto, sizeof(u32), phcsum); return phcsum; } diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 1b1e80336d2c516deffc59eff87e08b9e03706cf..2c48591ced444530448b01c1881109da4acc34d5 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -8,6 +8,9 @@ * Frank Blaschka */ +#define KMSG_COMPONENT "qeth" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include @@ -131,17 +134,13 @@ static int qeth_l2_send_setgroupmac_cb(struct qeth_card *card, mac = &cmd->data.setdelmac.mac[0]; /* MAC already registered, needed in couple/uncouple case */ if (cmd->hdr.return_code == 0x2005) { - QETH_DBF_MESSAGE(2, "Group MAC %02x:%02x:%02x:%02x:%02x:%02x " - "already existing on %s \n", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], - QETH_CARD_IFNAME(card)); + QETH_DBF_MESSAGE(2, "Group MAC %pM already existing on %s \n", + mac, QETH_CARD_IFNAME(card)); cmd->hdr.return_code = 0; } if (cmd->hdr.return_code) - QETH_DBF_MESSAGE(2, "Could not set group MAC " - "%02x:%02x:%02x:%02x:%02x:%02x on %s: %x\n", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], - QETH_CARD_IFNAME(card), cmd->hdr.return_code); + QETH_DBF_MESSAGE(2, "Could not set group MAC %pM on %s: %x\n", + mac, QETH_CARD_IFNAME(card), cmd->hdr.return_code); return 0; } @@ -163,10 +162,8 @@ static int qeth_l2_send_delgroupmac_cb(struct qeth_card *card, cmd = (struct qeth_ipa_cmd *) data; mac = &cmd->data.setdelmac.mac[0]; if (cmd->hdr.return_code) - QETH_DBF_MESSAGE(2, "Could not delete group MAC " - "%02x:%02x:%02x:%02x:%02x:%02x on %s: %x\n", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], - QETH_CARD_IFNAME(card), cmd->hdr.return_code); + QETH_DBF_MESSAGE(2, "Could not delete group MAC %pM on %s: %x\n", + mac, QETH_CARD_IFNAME(card), cmd->hdr.return_code); return 0; } @@ -503,12 +500,13 @@ static int qeth_l2_send_setmac_cb(struct qeth_card *card, card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED; memcpy(card->dev->dev_addr, cmd->data.setdelmac.mac, OSA_ADDR_LEN); - PRINT_INFO("MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x " - "successfully registered on device %s\n", - card->dev->dev_addr[0], card->dev->dev_addr[1], - card->dev->dev_addr[2], card->dev->dev_addr[3], - card->dev->dev_addr[4], card->dev->dev_addr[5], - card->dev->name); + dev_info(&card->gdev->dev, + "MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x " + "successfully registered on device %s\n", + card->dev->dev_addr[0], card->dev->dev_addr[1], + card->dev->dev_addr[2], card->dev->dev_addr[3], + card->dev->dev_addr[4], card->dev->dev_addr[5], + card->dev->name); } return 0; } @@ -1015,9 +1013,8 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode) if (rc) { QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc); if (rc == 0xe080) { - PRINT_WARN("LAN on card %s if offline! " - "Waiting for STARTLAN from card.\n", - CARD_BUS_ID(card)); + dev_warn(&card->gdev->dev, + "The LAN is offline\n"); card->lan_online = 0; } return rc; @@ -1117,8 +1114,8 @@ static int qeth_l2_recover(void *ptr) if (!qeth_do_run_thread(card, QETH_RECOVER_THREAD)) return 0; QETH_DBF_TEXT(TRACE, 2, "recover2"); - PRINT_WARN("Recovery of device %s started ...\n", - CARD_BUS_ID(card)); + dev_warn(&card->gdev->dev, + "A recovery process has been started for the device\n"); card->use_hard_stop = 1; __qeth_l2_set_offline(card->gdev, 1); rc = __qeth_l2_set_online(card->gdev, 1); @@ -1126,27 +1123,27 @@ static int qeth_l2_recover(void *ptr) qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD); qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD); if (!rc) - PRINT_INFO("Device %s successfully recovered!\n", - CARD_BUS_ID(card)); + dev_info(&card->gdev->dev, + "Device successfully recovered!\n"); else { rtnl_lock(); dev_close(card->dev); rtnl_unlock(); - PRINT_INFO("Device %s could not be recovered!\n", - CARD_BUS_ID(card)); + dev_warn(&card->gdev->dev, "The qeth device driver " + "failed to recover an error on the device\n"); } return 0; } static int __init qeth_l2_init(void) { - PRINT_INFO("register layer 2 discipline\n"); + pr_info("register layer 2 discipline\n"); return 0; } static void __exit qeth_l2_exit(void) { - PRINT_INFO("unregister layer 2 discipline\n"); + pr_info("unregister layer 2 discipline\n"); } static void qeth_l2_shutdown(struct ccwgroup_device *gdev) diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index ed59fedd5922398746d4def415268f369217dc1b..c0b30b25a5f19c6ec0d39f44ccc49c2007b731e8 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -8,6 +8,9 @@ * Frank Blaschka */ +#define KMSG_COMPONENT "qeth" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include @@ -917,8 +920,8 @@ static int qeth_l3_register_addr_entry(struct qeth_card *card, if (rc) { QETH_DBF_TEXT(TRACE, 2, "FAILED"); qeth_l3_ipaddr_to_string(addr->proto, (u8 *)&addr->u, buf); - PRINT_WARN("Could not register IP address %s (rc=0x%x/%d)\n", - buf, rc, rc); + dev_warn(&card->gdev->dev, + "Registering IP address %s failed\n", buf); } return rc; } @@ -1029,24 +1032,22 @@ static int qeth_l3_setadapter_parms(struct qeth_card *card) QETH_DBF_TEXT(SETUP, 2, "setadprm"); if (!qeth_is_supported(card, IPA_SETADAPTERPARMS)) { - PRINT_WARN("set adapter parameters not supported " - "on device %s.\n", - CARD_BUS_ID(card)); + dev_info(&card->gdev->dev, + "set adapter parameters not supported.\n"); QETH_DBF_TEXT(SETUP, 2, " notsupp"); return 0; } rc = qeth_query_setadapterparms(card); if (rc) { - PRINT_WARN("couldn't set adapter parameters on device %s: " - "x%x\n", CARD_BUS_ID(card), rc); + QETH_DBF_MESSAGE(2, "%s couldn't set adapter parameters: " + "0x%x\n", card->gdev->dev.bus_id, rc); return rc; } if (qeth_adp_supported(card, IPA_SETADP_ALTER_MAC_ADDRESS)) { rc = qeth_setadpparms_change_macaddr(card); if (rc) - PRINT_WARN("couldn't get MAC address on " - "device %s: x%x\n", - CARD_BUS_ID(card), rc); + dev_warn(&card->gdev->dev, "Reading the adapter MAC" + " address failed\n", rc); } if ((card->info.link_type == QETH_LINK_TYPE_HSTR) || @@ -1160,16 +1161,17 @@ static int qeth_l3_start_ipa_arp_processing(struct qeth_card *card) QETH_DBF_TEXT(TRACE, 3, "ipaarp"); if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) { - PRINT_WARN("ARP processing not supported " - "on %s!\n", QETH_CARD_IFNAME(card)); + dev_info(&card->gdev->dev, + "ARP processing not supported on %s!\n", + QETH_CARD_IFNAME(card)); return 0; } rc = qeth_l3_send_simple_setassparms(card, IPA_ARP_PROCESSING, IPA_CMD_ASS_START, 0); if (rc) { - PRINT_WARN("Could not start ARP processing " - "assist on %s: 0x%x\n", - QETH_CARD_IFNAME(card), rc); + dev_warn(&card->gdev->dev, + "Starting ARP processing support for %s failed\n", + QETH_CARD_IFNAME(card)); } return rc; } @@ -1181,19 +1183,21 @@ static int qeth_l3_start_ipa_ip_fragmentation(struct qeth_card *card) QETH_DBF_TEXT(TRACE, 3, "ipaipfrg"); if (!qeth_is_supported(card, IPA_IP_FRAGMENTATION)) { - PRINT_INFO("Hardware IP fragmentation not supported on %s\n", - QETH_CARD_IFNAME(card)); + dev_info(&card->gdev->dev, + "Hardware IP fragmentation not supported on %s\n", + QETH_CARD_IFNAME(card)); return -EOPNOTSUPP; } rc = qeth_l3_send_simple_setassparms(card, IPA_IP_FRAGMENTATION, IPA_CMD_ASS_START, 0); if (rc) { - PRINT_WARN("Could not start Hardware IP fragmentation " - "assist on %s: 0x%x\n", - QETH_CARD_IFNAME(card), rc); + dev_warn(&card->gdev->dev, + "Starting IP fragmentation support for %s failed\n", + QETH_CARD_IFNAME(card)); } else - PRINT_INFO("Hardware IP fragmentation enabled \n"); + dev_info(&card->gdev->dev, + "Hardware IP fragmentation enabled \n"); return rc; } @@ -1207,17 +1211,18 @@ static int qeth_l3_start_ipa_source_mac(struct qeth_card *card) return -EOPNOTSUPP; if (!qeth_is_supported(card, IPA_SOURCE_MAC)) { - PRINT_INFO("Inbound source address not " - "supported on %s\n", QETH_CARD_IFNAME(card)); + dev_info(&card->gdev->dev, + "Inbound source address not supported on %s\n", + QETH_CARD_IFNAME(card)); return -EOPNOTSUPP; } rc = qeth_l3_send_simple_setassparms(card, IPA_SOURCE_MAC, IPA_CMD_ASS_START, 0); if (rc) - PRINT_WARN("Could not start inbound source " - "assist on %s: 0x%x\n", - QETH_CARD_IFNAME(card), rc); + dev_warn(&card->gdev->dev, + "Starting proxy ARP support for %s failed\n", + QETH_CARD_IFNAME(card)); return rc; } @@ -1228,19 +1233,19 @@ static int qeth_l3_start_ipa_vlan(struct qeth_card *card) QETH_DBF_TEXT(TRACE, 3, "strtvlan"); if (!qeth_is_supported(card, IPA_FULL_VLAN)) { - PRINT_WARN("VLAN not supported on %s\n", - QETH_CARD_IFNAME(card)); + dev_info(&card->gdev->dev, + "VLAN not supported on %s\n", QETH_CARD_IFNAME(card)); return -EOPNOTSUPP; } rc = qeth_l3_send_simple_setassparms(card, IPA_VLAN_PRIO, IPA_CMD_ASS_START, 0); if (rc) { - PRINT_WARN("Could not start vlan " - "assist on %s: 0x%x\n", - QETH_CARD_IFNAME(card), rc); + dev_warn(&card->gdev->dev, + "Starting VLAN support for %s failed\n", + QETH_CARD_IFNAME(card)); } else { - PRINT_INFO("VLAN enabled \n"); + dev_info(&card->gdev->dev, "VLAN enabled\n"); } return rc; } @@ -1252,19 +1257,20 @@ static int qeth_l3_start_ipa_multicast(struct qeth_card *card) QETH_DBF_TEXT(TRACE, 3, "stmcast"); if (!qeth_is_supported(card, IPA_MULTICASTING)) { - PRINT_WARN("Multicast not supported on %s\n", - QETH_CARD_IFNAME(card)); + dev_info(&card->gdev->dev, + "Multicast not supported on %s\n", + QETH_CARD_IFNAME(card)); return -EOPNOTSUPP; } rc = qeth_l3_send_simple_setassparms(card, IPA_MULTICASTING, IPA_CMD_ASS_START, 0); if (rc) { - PRINT_WARN("Could not start multicast " - "assist on %s: rc=%i\n", - QETH_CARD_IFNAME(card), rc); + dev_warn(&card->gdev->dev, + "Starting multicast support for %s failed\n", + QETH_CARD_IFNAME(card)); } else { - PRINT_INFO("Multicast enabled\n"); + dev_info(&card->gdev->dev, "Multicast enabled\n"); card->dev->flags |= IFF_MULTICAST; } return rc; @@ -1315,36 +1321,37 @@ static int qeth_l3_softsetup_ipv6(struct qeth_card *card) rc = qeth_l3_query_ipassists(card, QETH_PROT_IPV6); if (rc) { - PRINT_ERR("IPv6 query ipassist failed on %s\n", - QETH_CARD_IFNAME(card)); + dev_err(&card->gdev->dev, + "Activating IPv6 support for %s failed\n", + QETH_CARD_IFNAME(card)); return rc; } rc = qeth_l3_send_simple_setassparms(card, IPA_IPV6, IPA_CMD_ASS_START, 3); if (rc) { - PRINT_WARN("IPv6 start assist (version 4) failed " - "on %s: 0x%x\n", - QETH_CARD_IFNAME(card), rc); + dev_err(&card->gdev->dev, + "Activating IPv6 support for %s failed\n", + QETH_CARD_IFNAME(card)); return rc; } rc = qeth_l3_send_simple_setassparms_ipv6(card, IPA_IPV6, IPA_CMD_ASS_START); if (rc) { - PRINT_WARN("IPV6 start assist (version 6) failed " - "on %s: 0x%x\n", - QETH_CARD_IFNAME(card), rc); + dev_err(&card->gdev->dev, + "Activating IPv6 support for %s failed\n", + QETH_CARD_IFNAME(card)); return rc; } rc = qeth_l3_send_simple_setassparms_ipv6(card, IPA_PASSTHRU, IPA_CMD_ASS_START); if (rc) { - PRINT_WARN("Could not enable passthrough " - "on %s: 0x%x\n", - QETH_CARD_IFNAME(card), rc); + dev_warn(&card->gdev->dev, + "Enabling the passthrough mode for %s failed\n", + QETH_CARD_IFNAME(card)); return rc; } out: - PRINT_INFO("IPV6 enabled \n"); + dev_info(&card->gdev->dev, "IPV6 enabled\n"); return 0; } #endif @@ -1356,8 +1363,8 @@ static int qeth_l3_start_ipa_ipv6(struct qeth_card *card) QETH_DBF_TEXT(TRACE, 3, "strtipv6"); if (!qeth_is_supported(card, IPA_IPV6)) { - PRINT_WARN("IPv6 not supported on %s\n", - QETH_CARD_IFNAME(card)); + dev_info(&card->gdev->dev, + "IPv6 not supported on %s\n", QETH_CARD_IFNAME(card)); return 0; } #ifdef CONFIG_QETH_IPV6 @@ -1373,34 +1380,35 @@ static int qeth_l3_start_ipa_broadcast(struct qeth_card *card) QETH_DBF_TEXT(TRACE, 3, "stbrdcst"); card->info.broadcast_capable = 0; if (!qeth_is_supported(card, IPA_FILTERING)) { - PRINT_WARN("Broadcast not supported on %s\n", - QETH_CARD_IFNAME(card)); + dev_info(&card->gdev->dev, + "Broadcast not supported on %s\n", + QETH_CARD_IFNAME(card)); rc = -EOPNOTSUPP; goto out; } rc = qeth_l3_send_simple_setassparms(card, IPA_FILTERING, IPA_CMD_ASS_START, 0); if (rc) { - PRINT_WARN("Could not enable broadcasting filtering " - "on %s: 0x%x\n", - QETH_CARD_IFNAME(card), rc); + dev_warn(&card->gdev->dev, "Enabling broadcast filtering for " + "%s failed\n", QETH_CARD_IFNAME(card)); goto out; } rc = qeth_l3_send_simple_setassparms(card, IPA_FILTERING, IPA_CMD_ASS_CONFIGURE, 1); if (rc) { - PRINT_WARN("Could not set up broadcast filtering on %s: 0x%x\n", - QETH_CARD_IFNAME(card), rc); + dev_warn(&card->gdev->dev, + "Setting up broadcast filtering for %s failed\n", + QETH_CARD_IFNAME(card)); goto out; } card->info.broadcast_capable = QETH_BROADCAST_WITH_ECHO; - PRINT_INFO("Broadcast enabled \n"); + dev_info(&card->gdev->dev, "Broadcast enabled\n"); rc = qeth_l3_send_simple_setassparms(card, IPA_FILTERING, IPA_CMD_ASS_ENABLE, 1); if (rc) { - PRINT_WARN("Could not set up broadcast echo filtering on " - "%s: 0x%x\n", QETH_CARD_IFNAME(card), rc); + dev_warn(&card->gdev->dev, "Setting up broadcast echo " + "filtering for %s failed\n", QETH_CARD_IFNAME(card)); goto out; } card->info.broadcast_capable = QETH_BROADCAST_WITHOUT_ECHO; @@ -1419,18 +1427,18 @@ static int qeth_l3_send_checksum_command(struct qeth_card *card) rc = qeth_l3_send_simple_setassparms(card, IPA_INBOUND_CHECKSUM, IPA_CMD_ASS_START, 0); if (rc) { - PRINT_WARN("Starting Inbound HW Checksumming failed on %s: " - "0x%x,\ncontinuing using Inbound SW Checksumming\n", - QETH_CARD_IFNAME(card), rc); + dev_warn(&card->gdev->dev, "Starting HW checksumming for %s " + "failed, using SW checksumming\n", + QETH_CARD_IFNAME(card)); return rc; } rc = qeth_l3_send_simple_setassparms(card, IPA_INBOUND_CHECKSUM, IPA_CMD_ASS_ENABLE, card->info.csum_mask); if (rc) { - PRINT_WARN("Enabling Inbound HW Checksumming failed on %s: " - "0x%x,\ncontinuing using Inbound SW Checksumming\n", - QETH_CARD_IFNAME(card), rc); + dev_warn(&card->gdev->dev, "Enabling HW checksumming for %s " + "failed, using SW checksumming\n", + QETH_CARD_IFNAME(card)); return rc; } return 0; @@ -1443,26 +1451,30 @@ static int qeth_l3_start_ipa_checksum(struct qeth_card *card) QETH_DBF_TEXT(TRACE, 3, "strtcsum"); if (card->options.checksum_type == NO_CHECKSUMMING) { - PRINT_WARN("Using no checksumming on %s.\n", - QETH_CARD_IFNAME(card)); + dev_info(&card->gdev->dev, + "Using no checksumming on %s.\n", + QETH_CARD_IFNAME(card)); return 0; } if (card->options.checksum_type == SW_CHECKSUMMING) { - PRINT_WARN("Using SW checksumming on %s.\n", - QETH_CARD_IFNAME(card)); + dev_info(&card->gdev->dev, + "Using SW checksumming on %s.\n", + QETH_CARD_IFNAME(card)); return 0; } if (!qeth_is_supported(card, IPA_INBOUND_CHECKSUM)) { - PRINT_WARN("Inbound HW Checksumming not " - "supported on %s,\ncontinuing " - "using Inbound SW Checksumming\n", - QETH_CARD_IFNAME(card)); + dev_info(&card->gdev->dev, + "Inbound HW Checksumming not " + "supported on %s,\ncontinuing " + "using Inbound SW Checksumming\n", + QETH_CARD_IFNAME(card)); card->options.checksum_type = SW_CHECKSUMMING; return 0; } rc = qeth_l3_send_checksum_command(card); if (!rc) - PRINT_INFO("HW Checksumming (inbound) enabled \n"); + dev_info(&card->gdev->dev, + "HW Checksumming (inbound) enabled\n"); return rc; } @@ -1474,18 +1486,20 @@ static int qeth_l3_start_ipa_tso(struct qeth_card *card) QETH_DBF_TEXT(TRACE, 3, "sttso"); if (!qeth_is_supported(card, IPA_OUTBOUND_TSO)) { - PRINT_WARN("Outbound TSO not supported on %s\n", - QETH_CARD_IFNAME(card)); + dev_info(&card->gdev->dev, + "Outbound TSO not supported on %s\n", + QETH_CARD_IFNAME(card)); rc = -EOPNOTSUPP; } else { rc = qeth_l3_send_simple_setassparms(card, IPA_OUTBOUND_TSO, IPA_CMD_ASS_START, 0); if (rc) - PRINT_WARN("Could not start outbound TSO " - "assist on %s: rc=%i\n", - QETH_CARD_IFNAME(card), rc); + dev_warn(&card->gdev->dev, "Starting outbound TCP " + "segmentation offload for %s failed\n", + QETH_CARD_IFNAME(card)); else - PRINT_INFO("Outbound TSO enabled\n"); + dev_info(&card->gdev->dev, + "Outbound TSO enabled\n"); } if (rc && (card->options.large_send == QETH_LARGE_SEND_TSO)) { card->options.large_send = QETH_LARGE_SEND_NO; @@ -1578,12 +1592,8 @@ static int qeth_l3_get_unique_id_cb(struct qeth_card *card, else { card->info.unique_id = UNIQUE_ID_IF_CREATE_ADDR_FAILED | UNIQUE_ID_NOT_BY_CARD; - PRINT_WARN("couldn't get a unique id from the card on device " - "%s (result=x%x), using default id. ipv6 " - "autoconfig on other lpars may lead to duplicate " - "ip addresses. please use manually " - "configured ones.\n", - CARD_BUS_ID(card), cmd->hdr.return_code); + dev_warn(&card->gdev->dev, "The network adapter failed to " + "generate a unique ID\n"); } return 0; } @@ -3086,9 +3096,8 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) if (rc) { QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc); if (rc == 0xe080) { - PRINT_WARN("LAN on card %s if offline! " - "Waiting for STARTLAN from card.\n", - CARD_BUS_ID(card)); + dev_warn(&card->gdev->dev, + "The LAN is offline\n"); card->lan_online = 0; } return rc; @@ -3194,8 +3203,8 @@ static int qeth_l3_recover(void *ptr) if (!qeth_do_run_thread(card, QETH_RECOVER_THREAD)) return 0; QETH_DBF_TEXT(TRACE, 2, "recover2"); - PRINT_WARN("Recovery of device %s started ...\n", - CARD_BUS_ID(card)); + dev_warn(&card->gdev->dev, + "A recovery process has been started for the device\n"); card->use_hard_stop = 1; __qeth_l3_set_offline(card->gdev, 1); rc = __qeth_l3_set_online(card->gdev, 1); @@ -3203,14 +3212,14 @@ static int qeth_l3_recover(void *ptr) qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD); qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD); if (!rc) - PRINT_INFO("Device %s successfully recovered!\n", - CARD_BUS_ID(card)); + dev_info(&card->gdev->dev, + "Device successfully recovered!\n"); else { rtnl_lock(); dev_close(card->dev); rtnl_unlock(); - PRINT_INFO("Device %s could not be recovered!\n", - CARD_BUS_ID(card)); + dev_warn(&card->gdev->dev, "The qeth device driver " + "failed to recover an error on the device\n"); } return 0; } @@ -3344,7 +3353,7 @@ static int qeth_l3_register_notifiers(void) return rc; } #else - PRINT_WARN("layer 3 discipline no IPv6 support\n"); + pr_warning("There is no IPv6 support for the layer 3 discipline\n"); #endif return 0; } @@ -3363,7 +3372,7 @@ static int __init qeth_l3_init(void) { int rc = 0; - PRINT_INFO("register layer 3 discipline\n"); + pr_info("register layer 3 discipline\n"); rc = qeth_l3_register_notifiers(); return rc; } @@ -3371,7 +3380,7 @@ static int __init qeth_l3_init(void) static void __exit qeth_l3_exit(void) { qeth_l3_unregister_notifiers(); - PRINT_INFO("unregister layer 3 discipline\n"); + pr_info("unregister layer 3 discipline\n"); } module_init(qeth_l3_init); diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 3d4e3e3f3fc07c873846d75b56d6e338c54475ce..e529b55b3ce9b486d1bfb55101c7de6981989998 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -25,9 +25,15 @@ * Sven Schuetz */ +#define KMSG_COMPONENT "zfcp" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include +#include #include "zfcp_ext.h" +#define ZFCP_BUS_ID_SIZE 20 + static char *device; MODULE_AUTHOR("IBM Deutschland Entwicklung GmbH - linux390@de.ibm.com"); @@ -83,9 +89,9 @@ static int __init zfcp_device_setup(char *devstr) strcpy(str, devstr); token = strsep(&str, ","); - if (!token || strlen(token) >= BUS_ID_SIZE) + if (!token || strlen(token) >= ZFCP_BUS_ID_SIZE) goto err_out; - strncpy(zfcp_data.init_busid, token, BUS_ID_SIZE); + strncpy(zfcp_data.init_busid, token, ZFCP_BUS_ID_SIZE); token = strsep(&str, ","); if (!token || strict_strtoull(token, 0, @@ -102,7 +108,7 @@ static int __init zfcp_device_setup(char *devstr) err_out: kfree(str); - pr_err("zfcp: %s is not a valid SCSI device\n", devstr); + pr_err("%s is not a valid SCSI device\n", devstr); return 0; } @@ -186,13 +192,13 @@ static int __init zfcp_module_init(void) retval = misc_register(&zfcp_cfdc_misc); if (retval) { - pr_err("zfcp: Registering the misc device zfcp_cfdc failed\n"); + pr_err("Registering the misc device zfcp_cfdc failed\n"); goto out_misc; } retval = zfcp_ccw_register(); if (retval) { - pr_err("zfcp: The zfcp device driver could not register with " + pr_err("The zfcp device driver could not register with " "the common I/O layer\n"); goto out_ccw_register; } @@ -436,6 +442,16 @@ static void _zfcp_status_read_scheduler(struct work_struct *work) stat_work)); } +static void zfcp_print_sl(struct seq_file *m, struct service_level *sl) +{ + struct zfcp_adapter *adapter = + container_of(sl, struct zfcp_adapter, service_level); + + seq_printf(m, "zfcp: %s microcode level %x\n", + dev_name(&adapter->ccw_device->dev), + adapter->fsf_lic_version); +} + /** * zfcp_adapter_enqueue - enqueue a new adapter to the list * @ccw_device: pointer to the struct cc_device @@ -500,6 +516,8 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler); INIT_WORK(&adapter->scan_work, _zfcp_scan_ports_later); + adapter->service_level.seq_print = zfcp_print_sl; + /* mark adapter unusable as long as sysfs registration is not complete */ atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index 951a8d409d1d5faa787a058d3f3542f13c9852c6..728147131e1d426801198bde6ca10cda10141a9c 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c @@ -6,6 +6,9 @@ * Copyright IBM Corporation 2002, 2008 */ +#define KMSG_COMPONENT "zfcp" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include "zfcp_ext.h" /** diff --git a/drivers/s390/scsi/zfcp_cfdc.c b/drivers/s390/scsi/zfcp_cfdc.c index ec2abceca6dcaf7adb687c47e7b64d3a5c8256f0..f1a7518e67ed62025e74248e5d355a25aa138edc 100644 --- a/drivers/s390/scsi/zfcp_cfdc.c +++ b/drivers/s390/scsi/zfcp_cfdc.c @@ -7,6 +7,9 @@ * Copyright IBM Corporation 2008 */ +#define KMSG_COMPONENT "zfcp" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 31012d58cfb760fb457862bfd596da12f8532310..735d675623f8887a47e260badcabcbdbd91b6ca0 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -6,6 +6,9 @@ * Copyright IBM Corporation 2002, 2008 */ +#define KMSG_COMPONENT "zfcp" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include "zfcp_ext.h" diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 9ce4c75bd190b1a269726da0f761053c5bde100e..e19e46ae4a68a24b5803f2dc8ef9be994b6f99e5 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -33,6 +33,7 @@ #include #include #include +#include #include "zfcp_dbf.h" #include "zfcp_fsf.h" @@ -515,6 +516,7 @@ struct zfcp_adapter { struct fsf_qtcb_bottom_port *stats_reset_data; unsigned long stats_reset; struct work_struct scan_work; + struct service_level service_level; atomic_t qdio_outb_full; /* queue full incidents */ }; diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index c557ba34e1aab5b2c5b7d732e9e076620e9dcc94..4ed4950d994b4331256666361ed5a8c7a0cc7271 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -6,6 +6,9 @@ * Copyright IBM Corporation 2002, 2008 */ +#define KMSG_COMPONENT "zfcp" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include "zfcp_ext.h" #define ZFCP_MAX_ERPS 3 @@ -1281,10 +1284,13 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) break; case ZFCP_ERP_ACTION_REOPEN_ADAPTER: - if (result != ZFCP_ERP_SUCCEEDED) + if (result != ZFCP_ERP_SUCCEEDED) { + unregister_service_level(&adapter->service_level); zfcp_erp_rports_del(adapter); - else + } else { + register_service_level(&adapter->service_level); schedule_work(&adapter->scan_work); + } zfcp_adapter_put(adapter); break; } diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 8aab3091a7b1045488887b352e4eebcecf23a21c..f009f2a7ec3ecea35874c04ffd4c2d643a053a7c 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -6,6 +6,9 @@ * Copyright IBM Corporation 2008 */ +#define KMSG_COMPONENT "zfcp" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include "zfcp_ext.h" struct ct_iu_gpn_ft_req { diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index dc0367690405e864538d33b0d96f088b0047e80a..9c72e083559d4d9d963eb939ebc3ad5dce25ed20 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -6,6 +6,9 @@ * Copyright IBM Corporation 2002, 2008 */ +#define KMSG_COMPONENT "zfcp" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include "zfcp_ext.h" diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index 664752f90b2007667212aa749e09c231b2860826..d3b55fb66f130739715e0a694b4719accaed2f2d 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -6,6 +6,9 @@ * Copyright IBM Corporation 2002, 2008 */ +#define KMSG_COMPONENT "zfcp" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include "zfcp_ext.h" /* FIXME(tune): free space should be one max. SBAL chain plus what? */ diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 468c880f8b6d6db3df67ff382855886e2b056a4a..9dc42a68fbdd5194fa2ab62d978ab73f81b2cde0 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -6,6 +6,9 @@ * Copyright IBM Corporation 2002, 2008 */ +#define KMSG_COMPONENT "zfcp" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include "zfcp_ext.h" #include diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c index ca9293ba1766681c7bcc24721a29b4ac37a4f5bc..899af2b45b1e3e862a047e18c8c3740e5c60c288 100644 --- a/drivers/s390/scsi/zfcp_sysfs.c +++ b/drivers/s390/scsi/zfcp_sysfs.c @@ -6,6 +6,9 @@ * Copyright IBM Corporation 2008 */ +#define KMSG_COMPONENT "zfcp" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include "zfcp_ext.h" #define ZFCP_DEV_ATTR(_feat, _name, _mode, _show, _store) \ diff --git a/drivers/s390/sysinfo.c b/drivers/s390/sysinfo.c index c3e4ab07b9ccc4e9e1df807ada9e0c5341f76ad2..0eea90781385784ae4ab838dce905dcaf4942a89 100644 --- a/drivers/s390/sysinfo.c +++ b/drivers/s390/sysinfo.c @@ -1,17 +1,21 @@ /* * drivers/s390/sysinfo.c * - * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Ulrich Weigand (Ulrich.Weigand@de.ibm.com) + * Copyright IBM Corp. 2001, 2008 + * Author(s): Ulrich Weigand (Ulrich.Weigand@de.ibm.com) + * Martin Schwidefsky */ #include #include #include +#include #include #include +#include #include #include +#include /* Sigh, math-emu. Don't ask. */ #include @@ -271,6 +275,125 @@ static __init int create_proc_sysinfo(void) __initcall(create_proc_sysinfo); +/* + * Service levels interface. + */ + +static DECLARE_RWSEM(service_level_sem); +static LIST_HEAD(service_level_list); + +int register_service_level(struct service_level *slr) +{ + struct service_level *ptr; + + down_write(&service_level_sem); + list_for_each_entry(ptr, &service_level_list, list) + if (ptr == slr) { + up_write(&service_level_sem); + return -EEXIST; + } + list_add_tail(&slr->list, &service_level_list); + up_write(&service_level_sem); + return 0; +} +EXPORT_SYMBOL(register_service_level); + +int unregister_service_level(struct service_level *slr) +{ + struct service_level *ptr, *next; + int rc = -ENOENT; + + down_write(&service_level_sem); + list_for_each_entry_safe(ptr, next, &service_level_list, list) { + if (ptr != slr) + continue; + list_del(&ptr->list); + rc = 0; + break; + } + up_write(&service_level_sem); + return rc; +} +EXPORT_SYMBOL(unregister_service_level); + +static void *service_level_start(struct seq_file *m, loff_t *pos) +{ + down_read(&service_level_sem); + return seq_list_start(&service_level_list, *pos); +} + +static void *service_level_next(struct seq_file *m, void *p, loff_t *pos) +{ + return seq_list_next(p, &service_level_list, pos); +} + +static void service_level_stop(struct seq_file *m, void *p) +{ + up_read(&service_level_sem); +} + +static int service_level_show(struct seq_file *m, void *p) +{ + struct service_level *slr; + + slr = list_entry(p, struct service_level, list); + slr->seq_print(m, slr); + return 0; +} + +static const struct seq_operations service_level_seq_ops = { + .start = service_level_start, + .next = service_level_next, + .stop = service_level_stop, + .show = service_level_show +}; + +static int service_level_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &service_level_seq_ops); +} + +static const struct file_operations service_level_ops = { + .open = service_level_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release +}; + +static void service_level_vm_print(struct seq_file *m, + struct service_level *slr) +{ + char *query_buffer, *str; + + query_buffer = kmalloc(1024, GFP_KERNEL | GFP_DMA); + if (!query_buffer) + return; + cpcmd("QUERY CPLEVEL", query_buffer, 1024, NULL); + str = strchr(query_buffer, '\n'); + if (str) + *str = 0; + seq_printf(m, "VM: %s\n", query_buffer); + kfree(query_buffer); +} + +static struct service_level service_level_vm = { + .seq_print = service_level_vm_print +}; + +static __init int create_proc_service_level(void) +{ + proc_create("service_levels", 0, NULL, &service_level_ops); + if (MACHINE_IS_VM) + register_service_level(&service_level_vm); + return 0; +} + +subsys_initcall(create_proc_service_level); + +/* + * Bogomips calculation based on cpu capability. + */ + int get_cpu_capability(unsigned int *capability) { struct sysinfo_1_2_2 *info; diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index ed6c54cae7b14a132c19241859470559c4a6b7aa..e11bce6ab63c7bd5290883d517f556979cedaf2a 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -1601,14 +1601,14 @@ static int iscsi_tcp_get_addr(struct iscsi_conn *conn, struct socket *sock, case AF_INET: sin = (struct sockaddr_in *)addr; spin_lock_bh(&conn->session->lock); - sprintf(buf, NIPQUAD_FMT, NIPQUAD(sin->sin_addr.s_addr)); + sprintf(buf, "%pI4", &sin->sin_addr.s_addr); *port = be16_to_cpu(sin->sin_port); spin_unlock_bh(&conn->session->lock); break; case AF_INET6: sin6 = (struct sockaddr_in6 *)addr; spin_lock_bh(&conn->session->lock); - sprintf(buf, NIP6_FMT, NIP6(sin6->sin6_addr)); + sprintf(buf, "%pI6", &sin6->sin6_addr); *port = be16_to_cpu(sin6->sin6_port); spin_unlock_bh(&conn->session->lock); break; diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c index 0248919bc2df47b3ed8aac6dc14384f78b098a66..bf2a1c516293dd413bc78515256034aa79b76fff 100644 --- a/drivers/scsi/mac_scsi.c +++ b/drivers/scsi/mac_scsi.c @@ -47,7 +47,6 @@ #include #include -#include #include #include "scsi.h" diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index db7ea3bb4e833afb50884b92c74f1b98c4b5d6ec..eb3a414b189a111f8110385440c0911300085210 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -206,8 +206,7 @@ static int qla4xxx_conn_get_param(struct iscsi_cls_conn *conn, break; case ISCSI_PARAM_CONN_ADDRESS: /* TODO: what are the ipv6 bits */ - len = sprintf(buf, "%u.%u.%u.%u\n", - NIPQUAD(ddb_entry->ip_addr)); + len = sprintf(buf, "%pI4\n", &ddb_entry->ip_addr); break; default: return -ENOSYS; diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c index 28c00c3d58f58273af3e1ab9bacd6f2df9e401c8..0c3a2ab1612c25b38b1b9a8f40d933e51792bbc4 100644 --- a/drivers/serial/mpc52xx_uart.c +++ b/drivers/serial/mpc52xx_uart.c @@ -429,14 +429,24 @@ mpc52xx_uart_tx_empty(struct uart_port *port) static void mpc52xx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) { - /* Not implemented */ + if (mctrl & TIOCM_RTS) + out_8(&PSC(port)->op1, MPC52xx_PSC_OP_RTS); + else + out_8(&PSC(port)->op0, MPC52xx_PSC_OP_RTS); } static unsigned int mpc52xx_uart_get_mctrl(struct uart_port *port) { - /* Not implemented */ - return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; + unsigned int ret = TIOCM_DSR; + u8 status = in_8(&PSC(port)->mpc52xx_psc_ipcr); + + if (!(status & MPC52xx_PSC_CTS)) + ret |= TIOCM_CTS; + if (!(status & MPC52xx_PSC_DCD)) + ret |= TIOCM_CAR; + + return ret; } static void @@ -479,7 +489,15 @@ mpc52xx_uart_stop_rx(struct uart_port *port) static void mpc52xx_uart_enable_ms(struct uart_port *port) { - /* Not implemented */ + struct mpc52xx_psc __iomem *psc = PSC(port); + + /* clear D_*-bits by reading them */ + in_8(&psc->mpc52xx_psc_ipcr); + /* enable CTS and DCD as IPC interrupts */ + out_8(&psc->mpc52xx_psc_acr, MPC52xx_PSC_IEC_CTS | MPC52xx_PSC_IEC_DCD); + + port->read_status_mask |= MPC52xx_PSC_IMR_IPC; + out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask); } static void @@ -580,6 +598,10 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new, MPC52xx_PSC_MODE_ONE_STOP_5_BITS : MPC52xx_PSC_MODE_ONE_STOP; + if (new->c_cflag & CRTSCTS) { + mr1 |= MPC52xx_PSC_MODE_RXRTS; + mr2 |= MPC52xx_PSC_MODE_TXCTS; + } baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16); quot = uart_get_divisor(port, baud); @@ -617,6 +639,9 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new, out_8(&psc->ctur, ctr >> 8); out_8(&psc->ctlr, ctr & 0xff); + if (UART_ENABLE_MS(port, new->c_cflag)) + mpc52xx_uart_enable_ms(port); + /* Reenable TX & RX */ out_8(&psc->command, MPC52xx_PSC_TX_ENABLE); out_8(&psc->command, MPC52xx_PSC_RX_ENABLE); @@ -752,10 +777,15 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port) if (status & MPC52xx_PSC_SR_RB) { flag = TTY_BREAK; uart_handle_break(port); - } else if (status & MPC52xx_PSC_SR_PE) + port->icount.brk++; + } else if (status & MPC52xx_PSC_SR_PE) { flag = TTY_PARITY; - else if (status & MPC52xx_PSC_SR_FE) + port->icount.parity++; + } + else if (status & MPC52xx_PSC_SR_FE) { flag = TTY_FRAME; + port->icount.frame++; + } /* Clear error condition */ out_8(&PSC(port)->command, MPC52xx_PSC_RST_ERR_STAT); @@ -769,6 +799,7 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port) * affect the current character */ tty_insert_flip_char(tty, 0, TTY_OVERRUN); + port->icount.overrun++; } } @@ -826,6 +857,7 @@ mpc52xx_uart_int(int irq, void *dev_id) struct uart_port *port = dev_id; unsigned long pass = ISR_PASS_LIMIT; unsigned int keepgoing; + u8 status; spin_lock(&port->lock); @@ -842,6 +874,13 @@ mpc52xx_uart_int(int irq, void *dev_id) if (psc_ops->tx_rdy(port)) keepgoing |= mpc52xx_uart_int_tx_chars(port); + status = in_8(&PSC(port)->mpc52xx_psc_ipcr); + if (status & MPC52xx_PSC_D_DCD) + uart_handle_dcd_change(port, !(status & MPC52xx_PSC_DCD)); + + if (status & MPC52xx_PSC_D_CTS) + uart_handle_cts_change(port, !(status & MPC52xx_PSC_CTS)); + /* Limit number of iteration */ if (!(--pass)) keepgoing = 0; @@ -1109,22 +1148,29 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match) return ret; port->mapbase = res.start; + if (!port->mapbase) { + dev_dbg(&op->dev, "Could not allocate resources for PSC\n"); + return -EINVAL; + } + port->irq = irq_of_parse_and_map(op->node, 0); + if (port->irq == NO_IRQ) { + dev_dbg(&op->dev, "Could not get irq\n"); + return -EINVAL; + } dev_dbg(&op->dev, "mpc52xx-psc uart at %p, irq=%x, freq=%i\n", (void *)port->mapbase, port->irq, port->uartclk); - if ((port->irq == NO_IRQ) || !port->mapbase) { - printk(KERN_ERR "Could not allocate resources for PSC\n"); - return -EINVAL; - } - /* Add the port to the uart sub-system */ ret = uart_add_one_port(&mpc52xx_uart_driver, port); - if (!ret) - dev_set_drvdata(&op->dev, (void *)port); + if (ret) { + irq_dispose_mapping(port->irq); + return ret; + } - return ret; + dev_set_drvdata(&op->dev, (void *)port); + return 0; } static int diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c index 317b061f7641f3036ebb5bb01a928784aa0f7c1c..ad3488504010f2ebe66055fa3878eae07fcacabb 100644 --- a/drivers/serial/pmac_zilog.c +++ b/drivers/serial/pmac_zilog.c @@ -1383,6 +1383,29 @@ static int pmz_verify_port(struct uart_port *port, struct serial_struct *ser) return -EINVAL; } +#ifdef CONFIG_CONSOLE_POLL + +static int pmz_poll_get_char(struct uart_port *port) +{ + struct uart_pmac_port *uap = (struct uart_pmac_port *)port; + + while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0) + udelay(5); + return read_zsdata(uap); +} + +static void pmz_poll_put_char(struct uart_port *port, unsigned char c) +{ + struct uart_pmac_port *uap = (struct uart_pmac_port *)port; + + /* Wait for the transmit buffer to empty. */ + while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0) + udelay(5); + write_zsdata(uap, c); +} + +#endif + static struct uart_ops pmz_pops = { .tx_empty = pmz_tx_empty, .set_mctrl = pmz_set_mctrl, @@ -1400,6 +1423,10 @@ static struct uart_ops pmz_pops = { .request_port = pmz_request_port, .config_port = pmz_config_port, .verify_port = pmz_verify_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = pmz_poll_get_char, + .poll_put_char = pmz_poll_put_char, +#endif }; /* diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 165fc010978c2624a7a45730f403b505ed48e726..557b54ab2f25d22b0f623b7f6dde18cb12cc47f2 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -51,7 +51,6 @@ #ifdef CONFIG_SUPERH #include #include -#include #endif #include "sh-sci.h" @@ -65,10 +64,6 @@ struct sci_port { /* Port IRQs: ERI, RXI, TXI, BRI (optional) */ unsigned int irqs[SCIx_NR_IRQS]; - /* Port pin configuration */ - void (*init_pins)(struct uart_port *port, - unsigned int cflag); - /* Port enable callback */ void (*enable)(struct uart_port *port); @@ -85,10 +80,6 @@ struct sci_port { #endif }; -#ifdef CONFIG_SH_KGDB -static struct sci_port *kgdb_sci_port; -#endif - #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE static struct sci_port *serial_console_port; #endif @@ -101,21 +92,26 @@ static void sci_stop_tx(struct uart_port *port); static struct sci_port sci_ports[SCI_NPORTS]; static struct uart_driver sci_uart_driver; -#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) && \ - defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB) +static inline struct sci_port * +to_sci_port(struct uart_port *uart) +{ + return container_of(uart, struct sci_port, port); +} + +#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_SH_SCI_CONSOLE) + +#ifdef CONFIG_CONSOLE_POLL static inline void handle_error(struct uart_port *port) { /* Clear error flags */ sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); } -static int get_char(struct uart_port *port) +static int sci_poll_get_char(struct uart_port *port) { - unsigned long flags; unsigned short status; int c; - spin_lock_irqsave(&port->lock, flags); do { status = sci_in(port, SCxSR); if (status & SCxSR_ERRORS(port)) { @@ -123,23 +119,21 @@ static int get_char(struct uart_port *port) continue; } } while (!(status & SCxSR_RDxF(port))); + c = sci_in(port, SCxRDR); - sci_in(port, SCxSR); /* Dummy read */ + + /* Dummy read */ + sci_in(port, SCxSR); sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); - spin_unlock_irqrestore(&port->lock, flags); return c; } -#endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */ +#endif -#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) || defined(CONFIG_SH_KGDB) -static void put_char(struct uart_port *port, char c) +static void sci_poll_put_char(struct uart_port *port, unsigned char c) { - unsigned long flags; unsigned short status; - spin_lock_irqsave(&port->lock, flags); - do { status = sci_in(port, SCxSR); } while (!(status & SCxSR_TDxE(port))); @@ -147,96 +141,22 @@ static void put_char(struct uart_port *port, char c) sci_in(port, SCxSR); /* Dummy read */ sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); sci_out(port, SCxTDR, c); - - spin_unlock_irqrestore(&port->lock, flags); } -#endif - -#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE -static void put_string(struct sci_port *sci_port, const char *buffer, int count) -{ - struct uart_port *port = &sci_port->port; - const unsigned char *p = buffer; - int i; - -#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB) - int checksum; - int usegdb=0; - -#ifdef CONFIG_SH_STANDARD_BIOS - /* This call only does a trap the first time it is - * called, and so is safe to do here unconditionally - */ - usegdb |= sh_bios_in_gdb_mode(); -#endif -#ifdef CONFIG_SH_KGDB - usegdb |= (kgdb_in_gdb_mode && (sci_port == kgdb_sci_port)); -#endif - - if (usegdb) { - /* $#. */ - do { - unsigned char c; - put_char(port, '$'); - put_char(port, 'O'); /* 'O'utput to console */ - checksum = 'O'; - - for (i=0; iport)) < 0) - cpu_relax(); - - return c; -} - -static inline void kgdb_sci_putchar(int c) -{ - put_char(&kgdb_sci_port->port, c); -} -#endif /* CONFIG_SH_KGDB */ +#endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE */ #if defined(__H8300S__) enum { sci_disable, sci_enable }; -static void h8300_sci_config(struct uart_port* port, unsigned int ctrl) +static void h8300_sci_config(struct uart_port *port, unsigned int ctrl) { - volatile unsigned char *mstpcrl=(volatile unsigned char *)MSTPCRL; + volatile unsigned char *mstpcrl = (volatile unsigned char *)MSTPCRL; int ch = (port->mapbase - SMR0) >> 3; unsigned char mask = 1 << (ch+1); - if (ctrl == sci_disable) { + if (ctrl == sci_disable) *mstpcrl |= mask; - } else { + else *mstpcrl &= ~mask; - } } static inline void h8300_sci_enable(struct uart_port *port) @@ -251,7 +171,7 @@ static inline void h8300_sci_disable(struct uart_port *port) #endif #if defined(__H8300H__) || defined(__H8300S__) -static void sci_init_pins_sci(struct uart_port* port, unsigned int cflag) +static void sci_init_pins(struct uart_port *port, unsigned int cflag) { int ch = (port->mapbase - SMR0) >> 3; @@ -266,141 +186,99 @@ static void sci_init_pins_sci(struct uart_port* port, unsigned int cflag) /* tx mark output*/ H8300_SCI_DR(ch) |= h8300_sci_pins[ch].tx; } -#else -#define sci_init_pins_sci NULL -#endif - -#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) -static void sci_init_pins_irda(struct uart_port *port, unsigned int cflag) +#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712) +static inline void sci_init_pins(struct uart_port *port, unsigned int cflag) { - unsigned int fcr_val = 0; - - if (cflag & CRTSCTS) - fcr_val |= SCFCR_MCE; - - sci_out(port, SCFCR, fcr_val); -} -#else -#define sci_init_pins_irda NULL -#endif - -#if defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712) -static void sci_init_pins_scif(struct uart_port* port, unsigned int cflag) -{ - unsigned int fcr_val = 0; - - set_sh771x_scif_pfc(port); - if (cflag & CRTSCTS) { - fcr_val |= SCFCR_MCE; - } - sci_out(port, SCFCR, fcr_val); + if (port->mapbase == 0xA4400000) { + __raw_writew(__raw_readw(PACR) & 0xffc0, PACR); + __raw_writew(__raw_readw(PBCR) & 0x0fff, PBCR); + } else if (port->mapbase == 0xA4410000) + __raw_writew(__raw_readw(PBCR) & 0xf003, PBCR); } #elif defined(CONFIG_CPU_SUBTYPE_SH7720) || defined(CONFIG_CPU_SUBTYPE_SH7721) -static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) +static inline void sci_init_pins(struct uart_port *port, unsigned int cflag) { - unsigned int fcr_val = 0; unsigned short data; if (cflag & CRTSCTS) { /* enable RTS/CTS */ if (port->mapbase == 0xa4430000) { /* SCIF0 */ /* Clear PTCR bit 9-2; enable all scif pins but sck */ - data = ctrl_inw(PORT_PTCR); - ctrl_outw((data & 0xfc03), PORT_PTCR); + data = __raw_readw(PORT_PTCR); + __raw_writew((data & 0xfc03), PORT_PTCR); } else if (port->mapbase == 0xa4438000) { /* SCIF1 */ /* Clear PVCR bit 9-2 */ - data = ctrl_inw(PORT_PVCR); - ctrl_outw((data & 0xfc03), PORT_PVCR); + data = __raw_readw(PORT_PVCR); + __raw_writew((data & 0xfc03), PORT_PVCR); } - fcr_val |= SCFCR_MCE; } else { if (port->mapbase == 0xa4430000) { /* SCIF0 */ /* Clear PTCR bit 5-2; enable only tx and rx */ - data = ctrl_inw(PORT_PTCR); - ctrl_outw((data & 0xffc3), PORT_PTCR); + data = __raw_readw(PORT_PTCR); + __raw_writew((data & 0xffc3), PORT_PTCR); } else if (port->mapbase == 0xa4438000) { /* SCIF1 */ /* Clear PVCR bit 5-2 */ - data = ctrl_inw(PORT_PVCR); - ctrl_outw((data & 0xffc3), PORT_PVCR); + data = __raw_readw(PORT_PVCR); + __raw_writew((data & 0xffc3), PORT_PVCR); } } - sci_out(port, SCFCR, fcr_val); } #elif defined(CONFIG_CPU_SH3) /* For SH7705, SH7706, SH7707, SH7709, SH7709A, SH7729 */ -static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) +static inline void sci_init_pins(struct uart_port *port, unsigned int cflag) { - unsigned int fcr_val = 0; unsigned short data; /* We need to set SCPCR to enable RTS/CTS */ - data = ctrl_inw(SCPCR); + data = __raw_readw(SCPCR); /* Clear out SCP7MD1,0, SCP6MD1,0, SCP4MD1,0*/ - ctrl_outw(data & 0x0fcf, SCPCR); + __raw_writew(data & 0x0fcf, SCPCR); - if (cflag & CRTSCTS) - fcr_val |= SCFCR_MCE; - else { + if (!(cflag & CRTSCTS)) { /* We need to set SCPCR to enable RTS/CTS */ - data = ctrl_inw(SCPCR); + data = __raw_readw(SCPCR); /* Clear out SCP7MD1,0, SCP4MD1,0, Set SCP6MD1,0 = {01} (output) */ - ctrl_outw((data & 0x0fcf) | 0x1000, SCPCR); + __raw_writew((data & 0x0fcf) | 0x1000, SCPCR); data = ctrl_inb(SCPDR); /* Set /RTS2 (bit6) = 0 */ ctrl_outb(data & 0xbf, SCPDR); } - - sci_out(port, SCFCR, fcr_val); } #elif defined(CONFIG_CPU_SUBTYPE_SH7722) -static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) +static inline void sci_init_pins(struct uart_port *port, unsigned int cflag) { - unsigned int fcr_val = 0; unsigned short data; if (port->mapbase == 0xffe00000) { - data = ctrl_inw(PSCR); + data = __raw_readw(PSCR); data &= ~0x03cf; - if (cflag & CRTSCTS) - fcr_val |= SCFCR_MCE; - else + if (!(cflag & CRTSCTS)) data |= 0x0340; - ctrl_outw(data, PSCR); + __raw_writew(data, PSCR); } - /* SCIF1 and SCIF2 should be setup by board code */ - - sci_out(port, SCFCR, fcr_val); -} -#elif defined(CONFIG_CPU_SUBTYPE_SH7723) -static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) -{ - /* Nothing to do here.. */ - sci_out(port, SCFCR, 0); } -#else -/* For SH7750 */ -static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) -{ - unsigned int fcr_val = 0; - - if (cflag & CRTSCTS) { - fcr_val |= SCFCR_MCE; - } else { -#if defined(CONFIG_CPU_SUBTYPE_SH7343) || defined(CONFIG_CPU_SUBTYPE_SH7366) - /* Nothing */ #elif defined(CONFIG_CPU_SUBTYPE_SH7763) || \ defined(CONFIG_CPU_SUBTYPE_SH7780) || \ defined(CONFIG_CPU_SUBTYPE_SH7785) || \ defined(CONFIG_CPU_SUBTYPE_SHX3) - ctrl_outw(0x0080, SCSPTR0); /* Set RTS = 1 */ +static inline void sci_init_pins(struct uart_port *port, unsigned int cflag) +{ + if (!(cflag & CRTSCTS)) + __raw_writew(0x0080, SCSPTR0); /* Set RTS = 1 */ +} +#elif defined(CONFIG_CPU_SH4) && !defined(CONFIG_CPU_SH4A) +static inline void sci_init_pins(struct uart_port *port, unsigned int cflag) +{ + if (!(cflag & CRTSCTS)) + __raw_writew(0x0080, SCSPTR2); /* Set RTS = 1 */ +} #else - ctrl_outw(0x0080, SCSPTR2); /* Set RTS = 1 */ -#endif - } - sci_out(port, SCFCR, fcr_val); +static inline void sci_init_pins(struct uart_port *port, unsigned int cflag) +{ + /* Nothing to do */ } #endif @@ -419,18 +297,26 @@ static inline int scif_rxroom(struct uart_port *port) #elif defined(CONFIG_CPU_SUBTYPE_SH7763) static inline int scif_txroom(struct uart_port *port) { - if((port->mapbase == 0xffe00000) || (port->mapbase == 0xffe08000)) /* SCIF0/1*/ + if ((port->mapbase == 0xffe00000) || + (port->mapbase == 0xffe08000)) { + /* SCIF0/1*/ return SCIF_TXROOM_MAX - (sci_in(port, SCTFDR) & 0xff); - else /* SCIF2 */ + } else { + /* SCIF2 */ return SCIF2_TXROOM_MAX - (sci_in(port, SCFDR) >> 8); + } } static inline int scif_rxroom(struct uart_port *port) { - if((port->mapbase == 0xffe00000) || (port->mapbase == 0xffe08000)) /* SCIF0/1*/ + if ((port->mapbase == 0xffe00000) || + (port->mapbase == 0xffe08000)) { + /* SCIF0/1*/ return sci_in(port, SCRFDR) & 0xff; - else /* SCIF2 */ + } else { + /* SCIF2 */ return sci_in(port, SCFDR) & SCIF2_RFDC_MASK; + } } #else static inline int scif_txroom(struct uart_port *port) @@ -446,12 +332,12 @@ static inline int scif_rxroom(struct uart_port *port) static inline int sci_txroom(struct uart_port *port) { - return ((sci_in(port, SCxSR) & SCI_TDRE) != 0); + return (sci_in(port, SCxSR) & SCI_TDRE) != 0; } static inline int sci_rxroom(struct uart_port *port) { - return ((sci_in(port, SCxSR) & SCxSR_RDxF(port)) != 0); + return (sci_in(port, SCxSR) & SCxSR_RDxF(port)) != 0; } /* ********************************************************************** * @@ -469,11 +355,10 @@ static void sci_transmit_chars(struct uart_port *port) status = sci_in(port, SCxSR); if (!(status & SCxSR_TDxE(port))) { ctrl = sci_in(port, SCSCR); - if (uart_circ_empty(xmit)) { + if (uart_circ_empty(xmit)) ctrl &= ~SCI_CTRL_FLAGS_TIE; - } else { + else ctrl |= SCI_CTRL_FLAGS_TIE; - } sci_out(port, SCSCR, ctrl); return; } @@ -521,11 +406,11 @@ static void sci_transmit_chars(struct uart_port *port) } /* On SH3, SCIF may read end-of-break as a space->mark char */ -#define STEPFN(c) ({int __c=(c); (((__c-1)|(__c)) == -1); }) +#define STEPFN(c) ({int __c = (c); (((__c-1)|(__c)) == -1); }) static inline void sci_receive_chars(struct uart_port *port) { - struct sci_port *sci_port = (struct sci_port *)port; + struct sci_port *sci_port = to_sci_port(port); struct tty_struct *tty = port->info->port.tty; int i, count, copied = 0; unsigned short status; @@ -550,13 +435,13 @@ static inline void sci_receive_chars(struct uart_port *port) if (port->type == PORT_SCI) { char c = sci_in(port, SCxRDR); - if (uart_handle_sysrq_char(port, c) || sci_port->break_flag) + if (uart_handle_sysrq_char(port, c) || + sci_port->break_flag) count = 0; - else { + else tty_insert_flip_char(tty, c, TTY_NORMAL); - } } else { - for (i=0; i end-of-break */ - pr_debug("scif: debounce<%02x>\n", c); + dev_dbg(port->dev, "debounce<%02x>\n", c); sci_port->break_flag = 0; if (STEPFN(c)) { @@ -586,12 +471,13 @@ static inline void sci_receive_chars(struct uart_port *port) /* Store data and status */ if (status&SCxSR_FER(port)) { flag = TTY_FRAME; - pr_debug("sci: frame error\n"); + dev_notice(port->dev, "frame error\n"); } else if (status&SCxSR_PER(port)) { flag = TTY_PARITY; - pr_debug("sci: parity error\n"); + dev_notice(port->dev, "parity error\n"); } else flag = TTY_NORMAL; + tty_insert_flip_char(tty, c, flag); } } @@ -651,13 +537,14 @@ static inline int sci_handle_errors(struct uart_port *port) /* overrun error */ if (tty_insert_flip_char(tty, 0, TTY_OVERRUN)) copied++; - pr_debug("sci: overrun error\n"); + + dev_notice(port->dev, "overrun error"); } if (status & SCxSR_FER(port)) { if (sci_rxd_in(port) == 0) { /* Notify of BREAK */ - struct sci_port *sci_port = (struct sci_port *)port; + struct sci_port *sci_port = to_sci_port(port); if (!sci_port->break_flag) { sci_port->break_flag = 1; @@ -666,15 +553,19 @@ static inline int sci_handle_errors(struct uart_port *port) /* Do sysrq handling. */ if (uart_handle_break(port)) return 0; - pr_debug("sci: BREAK detected\n"); + + dev_dbg(port->dev, "BREAK detected\n"); + if (tty_insert_flip_char(tty, 0, TTY_BREAK)) - copied++; - } + copied++; + } + } else { /* frame error */ if (tty_insert_flip_char(tty, 0, TTY_FRAME)) copied++; - pr_debug("sci: frame error\n"); + + dev_notice(port->dev, "frame error\n"); } } @@ -682,7 +573,8 @@ static inline int sci_handle_errors(struct uart_port *port) /* parity error */ if (tty_insert_flip_char(tty, 0, TTY_PARITY)) copied++; - pr_debug("sci: parity error\n"); + + dev_notice(port->dev, "parity error"); } if (copied) @@ -691,6 +583,27 @@ static inline int sci_handle_errors(struct uart_port *port) return copied; } +static inline int sci_handle_fifo_overrun(struct uart_port *port) +{ + struct tty_struct *tty = port->info->port.tty; + int copied = 0; + + if (port->type != PORT_SCIF) + return 0; + + if ((sci_in(port, SCLSR) & SCIF_ORER) != 0) { + sci_out(port, SCLSR, 0); + + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + tty_flip_buffer_push(tty); + + dev_notice(port->dev, "overrun error\n"); + copied++; + } + + return copied; +} + static inline int sci_handle_breaks(struct uart_port *port) { int copied = 0; @@ -709,23 +622,15 @@ static inline int sci_handle_breaks(struct uart_port *port) /* Notify of BREAK */ if (tty_insert_flip_char(tty, 0, TTY_BREAK)) copied++; - pr_debug("sci: BREAK detected\n"); - } -#if defined(SCIF_ORER) - /* XXX: Handle SCIF overrun error */ - if (port->type != PORT_SCI && (sci_in(port, SCLSR) & SCIF_ORER) != 0) { - sci_out(port, SCLSR, 0); - if (tty_insert_flip_char(tty, 0, TTY_OVERRUN)) { - copied++; - pr_debug("sci: overrun error\n"); - } + dev_dbg(port->dev, "BREAK detected\n"); } -#endif if (copied) tty_flip_buffer_push(tty); + copied += sci_handle_fifo_overrun(port); + return copied; } @@ -763,16 +668,7 @@ static irqreturn_t sci_er_interrupt(int irq, void *ptr) sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); } } else { -#if defined(SCIF_ORER) - if((sci_in(port, SCLSR) & SCIF_ORER) != 0) { - struct tty_struct *tty = port->info->port.tty; - - sci_out(port, SCLSR, 0); - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - tty_flip_buffer_push(tty); - pr_debug("scif: overrun error\n"); - } -#endif + sci_handle_fifo_overrun(port); sci_rx_interrupt(irq, ptr); } @@ -801,8 +697,8 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) struct uart_port *port = ptr; irqreturn_t ret = IRQ_NONE; - ssr_status = sci_in(port,SCxSR); - scr_status = sci_in(port,SCSCR); + ssr_status = sci_in(port, SCxSR); + scr_status = sci_in(port, SCSCR); /* Tx Interrupt */ if ((ssr_status & 0x0020) && (scr_status & SCI_CTRL_FLAGS_TIE)) @@ -820,7 +716,7 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) return ret; } -#if defined(CONFIG_CPU_FREQ) && defined(CONFIG_HAVE_CLK) +#ifdef CONFIG_HAVE_CLK /* * Here we define a transistion notifier so that we can update all of our * ports' baud rate when the peripheral clock changes. @@ -828,41 +724,20 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) static int sci_notifier(struct notifier_block *self, unsigned long phase, void *p) { - struct cpufreq_freqs *freqs = p; int i; if ((phase == CPUFREQ_POSTCHANGE) || - (phase == CPUFREQ_RESUMECHANGE)){ + (phase == CPUFREQ_RESUMECHANGE)) for (i = 0; i < SCI_NPORTS; i++) { - struct uart_port *port = &sci_ports[i].port; - struct clk *clk; - - /* - * Update the uartclk per-port if frequency has - * changed, since it will no longer necessarily be - * consistent with the old frequency. - * - * Really we want to be able to do something like - * uart_change_speed() or something along those lines - * here to implicitly reset the per-port baud rate.. - * - * Clean this up later.. - */ - clk = clk_get(NULL, "module_clk"); - port->uartclk = clk_get_rate(clk); - clk_put(clk); + struct sci_port *s = &sci_ports[i]; + s->port.uartclk = clk_get_rate(s->clk); } - printk(KERN_INFO "%s: got a postchange notification " - "for cpu %d (old %d, new %d)\n", - __func__, freqs->cpu, freqs->old, freqs->new); - } - return NOTIFY_OK; } static struct notifier_block sci_nb = { &sci_notifier, NULL, 0 }; -#endif /* CONFIG_CPU_FREQ && CONFIG_HAVE_CLK */ +#endif static int sci_request_irq(struct sci_port *port) { @@ -875,23 +750,22 @@ static int sci_request_irq(struct sci_port *port) "SCI Transmit Data Empty", "SCI Break" }; if (port->irqs[0] == port->irqs[1]) { - if (!port->irqs[0]) { - printk(KERN_ERR "sci: Cannot allocate irq.(IRQ=0)\n"); + if (unlikely(!port->irqs[0])) return -ENODEV; - } if (request_irq(port->irqs[0], sci_mpxed_interrupt, IRQF_DISABLED, "sci", port)) { - printk(KERN_ERR "sci: Cannot allocate irq.\n"); + dev_err(port->port.dev, "Can't allocate IRQ\n"); return -ENODEV; } } else { for (i = 0; i < ARRAY_SIZE(handlers); i++) { - if (!port->irqs[i]) + if (unlikely(!port->irqs[i])) continue; + if (request_irq(port->irqs[i], handlers[i], IRQF_DISABLED, desc[i], port)) { - printk(KERN_ERR "sci: Cannot allocate irq.\n"); + dev_err(port->port.dev, "Can't allocate IRQ\n"); return -ENODEV; } } @@ -904,12 +778,9 @@ static void sci_free_irq(struct sci_port *port) { int i; - if (port->irqs[0] == port->irqs[1]) { - if (!port->irqs[0]) - printk("sci: sci_free_irq error\n"); - else - free_irq(port->irqs[0], port); - } else { + if (port->irqs[0] == port->irqs[1]) + free_irq(port->irqs[0], port); + else { for (i = 0; i < ARRAY_SIZE(port->irqs); i++) { if (!port->irqs[i]) continue; @@ -1028,7 +899,6 @@ static void sci_shutdown(struct uart_port *port) static void sci_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { - struct sci_port *s = &sci_ports[port->line]; unsigned int status, baud, smr_val; int t = -1; @@ -1060,32 +930,36 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, sci_out(port, SCSMR, smr_val); if (t > 0) { - if(t >= 256) { + if (t >= 256) { sci_out(port, SCSMR, (sci_in(port, SCSMR) & ~3) | 1); t >>= 2; - } else { + } else sci_out(port, SCSMR, sci_in(port, SCSMR) & ~3); - } + sci_out(port, SCBRR, t); udelay((1000000+(baud-1)) / baud); /* Wait one bit interval */ } - if (likely(s->init_pins)) - s->init_pins(port, termios->c_cflag); + sci_init_pins(port, termios->c_cflag); + sci_out(port, SCFCR, (termios->c_cflag & CRTSCTS) ? SCFCR_MCE : 0); sci_out(port, SCSCR, SCSCR_INIT(port)); if ((termios->c_cflag & CREAD) != 0) - sci_start_rx(port,0); + sci_start_rx(port, 0); } static const char *sci_type(struct uart_port *port) { switch (port->type) { - case PORT_SCI: return "sci"; - case PORT_SCIF: return "scif"; - case PORT_IRDA: return "irda"; - case PORT_SCIFA: return "scifa"; + case PORT_IRDA: + return "irda"; + case PORT_SCI: + return "sci"; + case PORT_SCIF: + return "scif"; + case PORT_SCIFA: + return "scifa"; } return NULL; @@ -1108,19 +982,6 @@ static void sci_config_port(struct uart_port *port, int flags) port->type = s->type; - switch (port->type) { - case PORT_SCI: - s->init_pins = sci_init_pins_sci; - break; - case PORT_SCIF: - case PORT_SCIFA: - s->init_pins = sci_init_pins_scif; - break; - case PORT_IRDA: - s->init_pins = sci_init_pins_irda; - break; - } - if (port->flags & UPF_IOREMAP && !port->membase) { #if defined(CONFIG_SUPERH64) port->mapbase = onchip_remap(SCIF_ADDR_SH5, 1024, "SCIF"); @@ -1129,7 +990,7 @@ static void sci_config_port(struct uart_port *port, int flags) port->membase = ioremap_nocache(port->mapbase, 0x40); #endif - printk(KERN_ERR "sci: can't remap port#%d\n", port->line); + dev_err(port->dev, "can't remap port#%d\n", port->line); } } @@ -1163,6 +1024,10 @@ static struct uart_ops sci_uart_ops = { .request_port = sci_request_port, .config_port = sci_config_port, .verify_port = sci_verify_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = sci_poll_get_char, + .poll_put_char = sci_poll_put_char, +#endif }; static void __init sci_init_ports(void) @@ -1229,7 +1094,15 @@ int __init early_sci_setup(struct uart_port *port) static void serial_console_write(struct console *co, const char *s, unsigned count) { - put_string(serial_console_port, s, count); + struct uart_port *port = &serial_console_port->port; + int i; + + for (i = 0; i < count; i++) { + if (*s == 10) + sci_poll_put_char(port, '\r'); + + sci_poll_put_char(port, *s++); + } } static int __init serial_console_setup(struct console *co, char *options) @@ -1307,89 +1180,8 @@ static int __init sci_console_init(void) console_initcall(sci_console_init); #endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */ -#ifdef CONFIG_SH_KGDB_CONSOLE -/* - * FIXME: Most of this can go away.. at the moment, we rely on - * arch/sh/kernel/setup.c to do the command line parsing for kgdb, though - * most of that can easily be done here instead. - * - * For the time being, just accept the values that were parsed earlier.. - */ -static void __init kgdb_console_get_options(struct uart_port *port, int *baud, - int *parity, int *bits) -{ - *baud = kgdb_baud; - *parity = tolower(kgdb_parity); - *bits = kgdb_bits - '0'; -} - -/* - * The naming here is somewhat misleading, since kgdb_console_setup() takes - * care of the early-on initialization for kgdb, regardless of whether we - * actually use kgdb as a console or not. - * - * On the plus side, this lets us kill off the old kgdb_sci_setup() nonsense. - */ -int __init kgdb_console_setup(struct console *co, char *options) -{ - struct uart_port *port = &sci_ports[kgdb_portnum].port; - int baud = 38400; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - if (co->index != kgdb_portnum) - co->index = kgdb_portnum; - - kgdb_sci_port = &sci_ports[co->index]; - port = &kgdb_sci_port->port; - - /* - * Also need to check port->type, we don't actually have any - * UPIO_PORT ports, but uart_report_port() handily misreports - * it anyways if we don't have a port available by the time this is - * called. - */ - if (!port->type) - return -ENODEV; - if (!port->membase || !port->mapbase) - return -ENODEV; - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - else - kgdb_console_get_options(port, &baud, &parity, &bits); - - kgdb_getchar = kgdb_sci_getchar; - kgdb_putchar = kgdb_sci_putchar; - - return uart_set_options(port, co, baud, parity, bits, flow); -} - -static struct console kgdb_console = { - .name = "ttySC", - .device = uart_console_device, - .write = kgdb_console_write, - .setup = kgdb_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &sci_uart_driver, -}; - -/* Register the KGDB console so we get messages (d'oh!) */ -static int __init kgdb_console_init(void) -{ - sci_init_ports(); - register_console(&kgdb_console); - return 0; -} -console_initcall(kgdb_console_init); -#endif /* CONFIG_SH_KGDB_CONSOLE */ - -#if defined(CONFIG_SH_KGDB_CONSOLE) -#define SCI_CONSOLE &kgdb_console -#elif defined(CONFIG_SERIAL_SH_SCI_CONSOLE) -#define SCI_CONSOLE &serial_console +#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) +#define SCI_CONSOLE (&serial_console) #else #define SCI_CONSOLE 0 #endif @@ -1463,15 +1255,8 @@ static int __devinit sci_probe(struct platform_device *dev) uart_add_one_port(&sci_uart_driver, &sciport->port); } -#if defined(CONFIG_SH_KGDB) && !defined(CONFIG_SH_KGDB_CONSOLE) - kgdb_sci_port = &sci_ports[kgdb_portnum]; - kgdb_getchar = kgdb_sci_getchar; - kgdb_putchar = kgdb_sci_putchar; -#endif - -#if defined(CONFIG_CPU_FREQ) && defined(CONFIG_HAVE_CLK) +#ifdef CONFIG_HAVE_CLK cpufreq_register_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER); - dev_info(&dev->dev, "CPU frequency notifier registered\n"); #endif #ifdef CONFIG_SH_STANDARD_BIOS @@ -1491,6 +1276,10 @@ static int __devexit sci_remove(struct platform_device *dev) { int i; +#ifdef CONFIG_HAVE_CLK + cpufreq_unregister_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER); +#endif + for (i = 0; i < SCI_NPORTS; i++) uart_remove_one_port(&sci_uart_driver, &sci_ports[i].port); diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h index 9f33b064172e86607e607ae69afbfaf595c21da9..38c600c0dbbf4f6ae98e9f006ecefdbbe028b6cb 100644 --- a/drivers/serial/sh-sci.h +++ b/drivers/serial/sh-sci.h @@ -133,13 +133,20 @@ # define SCSPTR5 0xffef0024 /* 16 bit SCIF */ # define SCIF_OPER 0x0001 /* Overrun error bit */ # define SCSCR_INIT(port) 0x3a /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ -#elif defined(CONFIG_CPU_SUBTYPE_SH7203) || \ +#elif defined(CONFIG_CPU_SUBTYPE_SH7201) || \ + defined(CONFIG_CPU_SUBTYPE_SH7203) || \ defined(CONFIG_CPU_SUBTYPE_SH7206) || \ defined(CONFIG_CPU_SUBTYPE_SH7263) # define SCSPTR0 0xfffe8020 /* 16 bit SCIF */ # define SCSPTR1 0xfffe8820 /* 16 bit SCIF */ # define SCSPTR2 0xfffe9020 /* 16 bit SCIF */ # define SCSPTR3 0xfffe9820 /* 16 bit SCIF */ +# if defined(CONFIG_CPU_SUBTYPE_SH7201) +# define SCSPTR4 0xfffeA020 /* 16 bit SCIF */ +# define SCSPTR5 0xfffeA820 /* 16 bit SCIF */ +# define SCSPTR6 0xfffeB020 /* 16 bit SCIF */ +# define SCSPTR7 0xfffeB820 /* 16 bit SCIF */ +# endif # define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ #elif defined(CONFIG_CPU_SUBTYPE_SH7619) # define SCSPTR0 0xf8400020 /* 16 bit SCIF */ @@ -225,6 +232,10 @@ # define SCIF_TXROOM_MAX 16 #endif +#ifndef SCIF_ORER +#define SCIF_ORER 0x0000 +#endif + #define SCxSR_TEND(port) (((port)->type == PORT_SCI) ? SCI_TEND : SCIF_TEND) #define SCxSR_ERRORS(port) (((port)->type == PORT_SCI) ? SCI_ERRORS : SCIF_ERRORS) #define SCxSR_RDxF(port) (((port)->type == PORT_SCI) ? SCI_RDRF : SCIF_RDF) @@ -232,12 +243,7 @@ #define SCxSR_FER(port) (((port)->type == PORT_SCI) ? SCI_FER : SCIF_FER) #define SCxSR_PER(port) (((port)->type == PORT_SCI) ? SCI_PER : SCIF_PER) #define SCxSR_BRK(port) (((port)->type == PORT_SCI) ? 0x00 : SCIF_BRK) - -#if defined(CONFIG_CPU_SUBTYPE_SH7705) -# define SCxSR_ORER(port) (((port)->type == PORT_SCI) ? SCI_ORER : SCIF_ORER) -#else -# define SCxSR_ORER(port) (((port)->type == PORT_SCI) ? SCI_ORER : 0x0000) -#endif +#define SCxSR_ORER(port) (((port)->type == PORT_SCI) ? SCI_ORER : SCIF_ORER) #if defined(CONFIG_CPU_SUBTYPE_SH7705) || \ defined(CONFIG_CPU_SUBTYPE_SH7720) || \ @@ -501,18 +507,6 @@ static inline int sci_rxd_in(struct uart_port *port) { return sci_in(port,SCxSR)&0x0010 ? 1 : 0; } -static inline void set_sh771x_scif_pfc(struct uart_port *port) -{ - if (port->mapbase == 0xA4400000){ - ctrl_outw(ctrl_inw(PACR)&0xffc0,PACR); - ctrl_outw(ctrl_inw(PBCR)&0x0fff,PBCR); - return; - } - if (port->mapbase == 0xA4410000){ - ctrl_outw(ctrl_inw(PBCR)&0xf003,PBCR); - return; - } -} #elif defined(CONFIG_CPU_SUBTYPE_SH7720) || \ defined(CONFIG_CPU_SUBTYPE_SH7721) static inline int sci_rxd_in(struct uart_port *port) @@ -664,7 +658,8 @@ static inline int sci_rxd_in(struct uart_port *port) return ctrl_inw(SCSPTR5) & 0x0001 ? 1 : 0; /* SCIF */ return 1; } -#elif defined(CONFIG_CPU_SUBTYPE_SH7203) || \ +#elif defined(CONFIG_CPU_SUBTYPE_SH7201) || \ + defined(CONFIG_CPU_SUBTYPE_SH7203) || \ defined(CONFIG_CPU_SUBTYPE_SH7206) || \ defined(CONFIG_CPU_SUBTYPE_SH7263) static inline int sci_rxd_in(struct uart_port *port) @@ -677,6 +672,16 @@ static inline int sci_rxd_in(struct uart_port *port) return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */ if (port->mapbase == 0xfffe9800) return ctrl_inw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */ +#if defined(CONFIG_CPU_SUBTYPE_SH7201) + if (port->mapbase == 0xfffeA000) + return ctrl_inw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */ + if (port->mapbase == 0xfffeA800) + return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */ + if (port->mapbase == 0xfffeB000) + return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */ + if (port->mapbase == 0xfffeB800) + return ctrl_inw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */ +#endif return 1; } #elif defined(CONFIG_CPU_SUBTYPE_SH7619) diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 0ffabf5c0b60dd9892b5b9c45e2a1d8881129108..65a1ed951a1daa80abe1c9ac2b091af8664b38ad 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -226,7 +226,7 @@ int ssb_devices_freeze(struct ssb_bus *bus) err = drv->suspend(dev, state); if (err) { ssb_printk(KERN_ERR PFX "Failed to freeze device %s\n", - dev->dev->bus_id); + dev_name(dev->dev)); goto err_unwind; } } @@ -269,7 +269,7 @@ int ssb_devices_thaw(struct ssb_bus *bus) err = drv->resume(dev); if (err) { ssb_printk(KERN_ERR PFX "Failed to thaw device %s\n", - dev->dev->bus_id); + dev_name(dev->dev)); } } @@ -454,8 +454,7 @@ static int ssb_devices_register(struct ssb_bus *bus) dev->release = ssb_release_dev; dev->bus = &ssb_bustype; - snprintf(dev->bus_id, sizeof(dev->bus_id), - "ssb%u:%d", bus->busnumber, dev_idx); + dev_set_name(dev, "ssb%u:%d", bus->busnumber, dev_idx); switch (bus->bustype) { case SSB_BUSTYPE_PCI: @@ -480,7 +479,7 @@ static int ssb_devices_register(struct ssb_bus *bus) if (err) { ssb_printk(KERN_ERR PFX "Could not register %s\n", - dev->bus_id); + dev_name(dev)); /* Set dev to NULL to not unregister * dev on error unwinding. */ sdev->dev = NULL; @@ -796,7 +795,7 @@ int ssb_bus_pcibus_register(struct ssb_bus *bus, err = ssb_bus_register(bus, ssb_pci_get_invariants, 0); if (!err) { ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on " - "PCI device %s\n", host_pci->dev.bus_id); + "PCI device %s\n", dev_name(&host_pci->dev)); } return err; diff --git a/drivers/ssb/pcihost_wrapper.c b/drivers/ssb/pcihost_wrapper.c index e82db4aaa050ad5902f04de679c04b0bc6261013..26737a010c6d03080f345955ecfa97c30cc8fa27 100644 --- a/drivers/ssb/pcihost_wrapper.c +++ b/drivers/ssb/pcihost_wrapper.c @@ -65,7 +65,7 @@ static int ssb_pcihost_probe(struct pci_dev *dev, err = pci_enable_device(dev); if (err) goto err_kfree_ssb; - name = dev->dev.bus_id; + name = dev_name(&dev->dev); if (dev->driver && dev->driver->name) name = dev->driver->name; err = pci_request_regions(dev, name); diff --git a/drivers/staging/slicoss/slicoss.c b/drivers/staging/slicoss/slicoss.c index 8fa9490b3e2ca707320e3ccafc28d21089a07b26..00390362f10ff9c8f71981bc4eb267881f573380 100644 --- a/drivers/staging/slicoss/slicoss.c +++ b/drivers/staging/slicoss/slicoss.c @@ -765,8 +765,7 @@ static int slic_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) #ifdef SLIC_USER_REQUEST_DUMP_ENABLED case SIOCSLICDUMPCARD: { - struct adapter *adapter = (struct adapter *) - dev->priv; + struct adapter *adapter = netdev_priv(dev); struct sliccard *card; ASSERT(adapter); @@ -1685,7 +1684,7 @@ static void slic_timer_ping(ulong dev) struct sliccard *card; ASSERT(dev); - adapter = (struct adapter *)((struct net_device *) dev)->priv; + adapter = netdev_priv((struct net_device *)dev); ASSERT(adapter); card = adapter->card; ASSERT(card); @@ -3136,7 +3135,7 @@ static void slic_timer_get_stats(ulong dev) struct slic_shmem *pshmem; ASSERT(dev); - adapter = (struct adapter *)((struct net_device *)dev)->priv; + adapter = netdev_priv((struct net_device *)dev); ASSERT(adapter); card = adapter->card; ASSERT(card); diff --git a/drivers/staging/winbond/linux/wbusb.c b/drivers/staging/winbond/linux/wbusb.c index f4a7875f2389673d146c7d840be4383156eb6a9c..39ca9b9878f8111765b7936e9a045f72c3694720 100644 --- a/drivers/staging/winbond/linux/wbusb.c +++ b/drivers/staging/winbond/linux/wbusb.c @@ -336,7 +336,11 @@ WbUsb_destroy(phw_data_t pHwData) int wb35_open(struct net_device *netdev) { - PADAPTER Adapter = (PADAPTER)netdev->priv; + /* netdev_priv() or netdev->ml_priv should reference to the address of + * private data(PADAPTER). It depends on whether private data memory is + * allocated when alloc_netdev(). + */ + PADAPTER Adapter = (PADAPTER)netdev_priv(netdev); phw_data_t pHwData = &Adapter->sHwData; netif_start_queue(netdev); diff --git a/drivers/staging/wlan-ng/p80211netdev.c b/drivers/staging/wlan-ng/p80211netdev.c index 11f84a829e14a4d4595259c6184963b0a0e00cd7..2b705eaa50e8d40d3c545bf882a6e75369a39306 100644 --- a/drivers/staging/wlan-ng/p80211netdev.c +++ b/drivers/staging/wlan-ng/p80211netdev.c @@ -244,7 +244,7 @@ static int p80211knetdev_init( netdevice_t *netdev) static struct net_device_stats* p80211knetdev_get_stats(netdevice_t *netdev) { - wlandevice_t *wlandev = (wlandevice_t*)netdev->priv; + wlandevice_t *wlandev = netdev->ml_priv; DBFENTER; /* TODO: review the MIB stats for items that correspond to @@ -272,7 +272,7 @@ p80211knetdev_get_stats(netdevice_t *netdev) static int p80211knetdev_open( netdevice_t *netdev ) { int result = 0; /* success */ - wlandevice_t *wlandev = (wlandevice_t*)(netdev->priv); + wlandevice_t *wlandev = netdev->ml_priv; DBFENTER; @@ -315,7 +315,7 @@ static int p80211knetdev_open( netdevice_t *netdev ) static int p80211knetdev_stop( netdevice_t *netdev ) { int result = 0; - wlandevice_t *wlandev = (wlandevice_t*)(netdev->priv); + wlandevice_t *wlandev = netdev->ml_priv; DBFENTER; @@ -460,7 +460,7 @@ static int p80211knetdev_hard_start_xmit( struct sk_buff *skb, netdevice_t *netd { int result = 0; int txresult = -1; - wlandevice_t *wlandev = (wlandevice_t*)netdev->priv; + wlandevice_t *wlandev = netdev->ml_priv; p80211_hdr_t p80211_hdr; p80211_metawep_t p80211_wep; @@ -603,7 +603,7 @@ static int p80211knetdev_hard_start_xmit( struct sk_buff *skb, netdevice_t *netd ----------------------------------------------------------------*/ static void p80211knetdev_set_multicast_list(netdevice_t *dev) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; DBFENTER; @@ -696,7 +696,7 @@ static int p80211knetdev_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd) { int result = 0; p80211ioctl_req_t *req = (p80211ioctl_req_t*)ifr; - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; UINT8 *msgbuf; DBFENTER; @@ -812,7 +812,7 @@ static int p80211knetdev_set_mac_address(netdevice_t *dev, void *addr) dot11req.msgcode = DIDmsg_dot11req_mibset; dot11req.msglen = sizeof(p80211msg_dot11req_mibset_t); memcpy(dot11req.devname, - ((wlandevice_t*)(dev->priv))->name, + ((wlandevice_t *)dev->ml_priv)->name, WLAN_DEVNAMELEN_MAX - 1); /* Set up the mibattribute argument */ @@ -833,7 +833,7 @@ static int p80211knetdev_set_mac_address(netdevice_t *dev, void *addr) resultcode->data = 0; /* now fire the request */ - result = p80211req_dorequest(dev->priv, (UINT8*)&dot11req); + result = p80211req_dorequest(dev->ml_priv, (UINT8 *)&dot11req); /* If the request wasn't successful, report an error and don't * change the netdev address @@ -917,7 +917,7 @@ int wlan_setup(wlandevice_t *wlandev) memset( dev, 0, sizeof(netdevice_t)); ether_setup(dev); wlandev->netdev = dev; - dev->priv = wlandev; + dev->ml_priv = wlandev; dev->hard_start_xmit = p80211knetdev_hard_start_xmit; dev->get_stats = p80211knetdev_get_stats; #ifdef HAVE_PRIVATE_IOCTL @@ -1487,7 +1487,7 @@ void p80211_resume(wlandevice_t *wlandev) static void p80211knetdev_tx_timeout( netdevice_t *netdev) { - wlandevice_t *wlandev = (wlandevice_t*)netdev->priv; + wlandevice_t *wlandev = netdev->ml_priv; DBFENTER; if (wlandev->tx_timeout) { diff --git a/drivers/staging/wlan-ng/p80211wext.c b/drivers/staging/wlan-ng/p80211wext.c index 906ba439237669b0150f12fb0f57cd42afd36ea4..b2c9ea25fa425a3558bff9ab5b1c96da01de841c 100644 --- a/drivers/staging/wlan-ng/p80211wext.c +++ b/drivers/staging/wlan-ng/p80211wext.c @@ -218,7 +218,7 @@ static int p80211wext_autojoin(wlandevice_t *wlandev) struct iw_statistics* p80211wext_get_wireless_stats (netdevice_t *dev) { p80211msg_lnxreq_commsquality_t quality; - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; struct iw_statistics* wstats = &wlandev->wstats; int retval; @@ -301,7 +301,7 @@ static int p80211wext_giwfreq(netdevice_t *dev, struct iw_request_info *info, struct iw_freq *freq, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; p80211item_uint32_t mibitem; p80211msg_dot11req_mibset_t msg; int result; @@ -339,7 +339,7 @@ static int p80211wext_siwfreq(netdevice_t *dev, struct iw_request_info *info, struct iw_freq *freq, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; p80211item_uint32_t mibitem; p80211msg_dot11req_mibset_t msg; int result; @@ -380,7 +380,7 @@ static int p80211wext_giwmode(netdevice_t *dev, struct iw_request_info *info, __u32 *mode, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; DBFENTER; @@ -407,7 +407,7 @@ static int p80211wext_siwmode(netdevice_t *dev, struct iw_request_info *info, __u32 *mode, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; p80211item_uint32_t mibitem; p80211msg_dot11req_mibset_t msg; int result; @@ -550,7 +550,7 @@ static int p80211wext_giwap(netdevice_t *dev, struct sockaddr *ap_addr, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; DBFENTER; @@ -566,7 +566,7 @@ static int p80211wext_giwencode(netdevice_t *dev, struct iw_request_info *info, struct iw_point *erq, char *key) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; int err = 0; int i; @@ -607,7 +607,7 @@ static int p80211wext_siwencode(netdevice_t *dev, struct iw_request_info *info, struct iw_point *erq, char *key) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; p80211msg_dot11req_mibset_t msg; p80211item_pstr32_t pstr; @@ -736,7 +736,7 @@ static int p80211wext_giwessid(netdevice_t *dev, struct iw_request_info *info, struct iw_point *data, char *essid) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; DBFENTER; @@ -762,7 +762,7 @@ static int p80211wext_siwessid(netdevice_t *dev, struct iw_request_info *info, struct iw_point *data, char *essid) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; p80211msg_lnxreq_autojoin_t msg; int result; @@ -816,7 +816,7 @@ static int p80211wext_siwcommit(netdevice_t *dev, struct iw_request_info *info, struct iw_point *data, char *essid) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; int err = 0; DBFENTER; @@ -839,7 +839,7 @@ static int p80211wext_giwrate(netdevice_t *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; p80211item_uint32_t mibitem; p80211msg_dot11req_mibset_t msg; int result; @@ -893,7 +893,7 @@ static int p80211wext_giwrts(netdevice_t *dev, struct iw_request_info *info, struct iw_param *rts, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; p80211item_uint32_t mibitem; p80211msg_dot11req_mibset_t msg; int result; @@ -927,7 +927,7 @@ static int p80211wext_siwrts(netdevice_t *dev, struct iw_request_info *info, struct iw_param *rts, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; p80211item_uint32_t mibitem; p80211msg_dot11req_mibset_t msg; int result; @@ -964,7 +964,7 @@ static int p80211wext_giwfrag(netdevice_t *dev, struct iw_request_info *info, struct iw_param *frag, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; p80211item_uint32_t mibitem; p80211msg_dot11req_mibset_t msg; int result; @@ -997,7 +997,7 @@ static int p80211wext_siwfrag(netdevice_t *dev, struct iw_request_info *info, struct iw_param *frag, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; p80211item_uint32_t mibitem; p80211msg_dot11req_mibset_t msg; int result; @@ -1047,7 +1047,7 @@ static int p80211wext_giwretry(netdevice_t *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; p80211item_uint32_t mibitem; p80211msg_dot11req_mibset_t msg; int result; @@ -1126,7 +1126,7 @@ static int p80211wext_siwretry(netdevice_t *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; p80211item_uint32_t mibitem; p80211msg_dot11req_mibset_t msg; int result; @@ -1198,7 +1198,7 @@ static int p80211wext_siwtxpow(netdevice_t *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; p80211item_uint32_t mibitem; p80211msg_dot11req_mibset_t msg; int result; @@ -1243,7 +1243,7 @@ static int p80211wext_giwtxpow(netdevice_t *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; p80211item_uint32_t mibitem; p80211msg_dot11req_mibset_t msg; int result; @@ -1281,7 +1281,7 @@ static int p80211wext_siwspy(netdevice_t *dev, struct iw_request_info *info, struct iw_point *srq, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; struct sockaddr address[IW_MAX_SPY]; int number = srq->length; int i; @@ -1317,7 +1317,7 @@ static int p80211wext_giwspy(netdevice_t *dev, struct iw_request_info *info, struct iw_point *srq, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; struct sockaddr address[IW_MAX_SPY]; struct iw_quality spy_stat[IW_MAX_SPY]; @@ -1378,7 +1378,7 @@ static int p80211wext_siwscan(netdevice_t *dev, struct iw_request_info *info, struct iw_point *srq, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; p80211msg_dot11req_scan_t msg; int result; int err = 0; @@ -1501,7 +1501,7 @@ static int p80211wext_giwscan(netdevice_t *dev, struct iw_request_info *info, struct iw_point *srq, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; p80211msg_dot11req_scan_results_t msg; int result = 0; int err = 0; @@ -1551,7 +1551,7 @@ static int p80211wext_set_encodeext(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; p80211msg_dot11req_mibset_t msg; p80211item_pstr32_t *pstr; @@ -1627,7 +1627,7 @@ static int p80211wext_get_encodeext(struct net_device *dev, union iwreq_data *wrqu, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; struct iw_point *encoding = &wrqu->encoding; @@ -1682,7 +1682,7 @@ static int p80211_wext_set_iwauth (struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; struct iw_param *param = &wrqu->param; int result =0; @@ -1734,7 +1734,7 @@ static int p80211_wext_get_iwauth (struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; struct iw_param *param = &wrqu->param; int result =0; @@ -1868,7 +1868,7 @@ struct iw_handler_def p80211wext_handler_def = { /* wireless extensions' ioctls */ int p80211wext_support_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; #if WIRELESS_EXT < 13 struct iwreq *iwr = (struct iwreq*)ifr; diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index 9aea43a8c4adce959b3aafcc1b171f807b2fc1a7..5ed4ae07bac108cd5f3f3999676c7031e6d5f2a5 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -286,9 +286,7 @@ static ssize_t cxacru_sysfs_show_mac_address(struct device *dev, struct usbatm_data *usbatm_instance = usb_get_intfdata(intf); struct atm_dev *atm_dev = usbatm_instance->atm_dev; - return snprintf(buf, PAGE_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x\n", - atm_dev->esi[0], atm_dev->esi[1], atm_dev->esi[2], - atm_dev->esi[3], atm_dev->esi[4], atm_dev->esi[5]); + return snprintf(buf, PAGE_SIZE, "%pM\n", atm_dev->esi); } static ssize_t cxacru_sysfs_show_adsl_state(struct device *dev, diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c index 06dd114910d45ac4cda3a080c375459329cada0d..fbea8563df1ede695f0ccf7b5dc8d367c6f623dc 100644 --- a/drivers/usb/atm/usbatm.c +++ b/drivers/usb/atm/usbatm.c @@ -770,10 +770,7 @@ static int usbatm_atm_proc_read(struct atm_dev *atm_dev, loff_t * pos, char *pag return sprintf(page, "%s\n", instance->description); if (!left--) - return sprintf(page, "MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", - atm_dev->esi[0], atm_dev->esi[1], - atm_dev->esi[2], atm_dev->esi[3], - atm_dev->esi[4], atm_dev->esi[5]); + return sprintf(page, "MAC: %pM\n", atm_dev->esi); if (!left--) return sprintf(page, diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 2bccefebff1b4a05caf7f07961751c68e73cc462..aa79280df15dbe2419cadbaf234113f3d1a774a7 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -574,6 +574,7 @@ static int usbdev_open(struct inode *inode, struct file *file) { struct usb_device *dev = NULL; struct dev_state *ps; + const struct cred *cred = current_cred(); int ret; lock_kernel(); @@ -617,8 +618,8 @@ static int usbdev_open(struct inode *inode, struct file *file) init_waitqueue_head(&ps->wait); ps->discsignr = 0; ps->disc_pid = get_pid(task_pid(current)); - ps->disc_uid = current->uid; - ps->disc_euid = current->euid; + ps->disc_uid = cred->uid; + ps->disc_euid = cred->euid; ps->disccontext = NULL; ps->ifclaimed = 0; security_task_getsecid(current, &ps->secid); @@ -967,6 +968,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, struct usb_host_endpoint *ep; struct async *as; struct usb_ctrlrequest *dr = NULL; + const struct cred *cred = current_cred(); unsigned int u, totlen, isofrmlen; int ret, ifnum = -1; int is_in; @@ -1174,8 +1176,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, as->signr = uurb->signr; as->ifnum = ifnum; as->pid = get_pid(task_pid(current)); - as->uid = current->uid; - as->euid = current->euid; + as->uid = cred->uid; + as->euid = cred->euid; security_task_getsecid(current, &as->secid); if (!is_in) { if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index 94632264dccf253edf9a07e8278f4b33fa28eaad..185be760833e8b05a2940f13d90af0f9bdcec946 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -277,8 +277,8 @@ static struct inode *usbfs_get_inode (struct super_block *sb, int mode, dev_t de if (inode) { inode->i_mode = mode; - inode->i_uid = current->fsuid; - inode->i_gid = current->fsgid; + inode->i_uid = current_fsuid(); + inode->i_gid = current_fsgid(); inode->i_blocks = 0; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; switch (mode & S_IFMT) { diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c new file mode 100644 index 0000000000000000000000000000000000000000..d8fc9b32fe3682c52b9ad060fa3862a6ab557143 --- /dev/null +++ b/drivers/usb/gadget/f_phonet.c @@ -0,0 +1,621 @@ +/* + * f_phonet.c -- USB CDC Phonet function + * + * Copyright (C) 2007-2008 Nokia Corporation. All rights reserved. + * + * Author: Rémi Denis-Courmont + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "u_phonet.h" + +#define PN_MEDIA_USB 0x1B + +/*-------------------------------------------------------------------------*/ + +struct phonet_port { + struct f_phonet *usb; + spinlock_t lock; +}; + +struct f_phonet { + struct usb_function function; + struct net_device *dev; + struct usb_ep *in_ep, *out_ep; + + struct usb_request *in_req; + struct usb_request *out_reqv[0]; +}; + +static int phonet_rxq_size = 2; + +static inline struct f_phonet *func_to_pn(struct usb_function *f) +{ + return container_of(f, struct f_phonet, function); +} + +/*-------------------------------------------------------------------------*/ + +#define USB_CDC_SUBCLASS_PHONET 0xfe +#define USB_CDC_PHONET_TYPE 0xab + +static struct usb_interface_descriptor +pn_control_intf_desc = { + .bLength = sizeof pn_control_intf_desc, + .bDescriptorType = USB_DT_INTERFACE, + + /* .bInterfaceNumber = DYNAMIC, */ + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = USB_CDC_SUBCLASS_PHONET, +}; + +static const struct usb_cdc_header_desc +pn_header_desc = { + .bLength = sizeof pn_header_desc, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_HEADER_TYPE, + .bcdCDC = __constant_cpu_to_le16(0x0110), +}; + +static const struct usb_cdc_header_desc +pn_phonet_desc = { + .bLength = sizeof pn_phonet_desc, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_PHONET_TYPE, + .bcdCDC = __constant_cpu_to_le16(0x1505), /* ??? */ +}; + +static struct usb_cdc_union_desc +pn_union_desc = { + .bLength = sizeof pn_union_desc, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_UNION_TYPE, + + /* .bMasterInterface0 = DYNAMIC, */ + /* .bSlaveInterface0 = DYNAMIC, */ +}; + +static struct usb_interface_descriptor +pn_data_nop_intf_desc = { + .bLength = sizeof pn_data_nop_intf_desc, + .bDescriptorType = USB_DT_INTERFACE, + + /* .bInterfaceNumber = DYNAMIC, */ + .bAlternateSetting = 0, + .bNumEndpoints = 0, + .bInterfaceClass = USB_CLASS_CDC_DATA, +}; + +static struct usb_interface_descriptor +pn_data_intf_desc = { + .bLength = sizeof pn_data_intf_desc, + .bDescriptorType = USB_DT_INTERFACE, + + /* .bInterfaceNumber = DYNAMIC, */ + .bAlternateSetting = 1, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_CDC_DATA, +}; + +static struct usb_endpoint_descriptor +pn_fs_sink_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, +}; + +static struct usb_endpoint_descriptor +pn_hs_sink_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __constant_cpu_to_le16(512), +}; + +static struct usb_endpoint_descriptor +pn_fs_source_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, +}; + +static struct usb_endpoint_descriptor +pn_hs_source_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __constant_cpu_to_le16(512), +}; + +static struct usb_descriptor_header *fs_pn_function[] = { + (struct usb_descriptor_header *) &pn_control_intf_desc, + (struct usb_descriptor_header *) &pn_header_desc, + (struct usb_descriptor_header *) &pn_phonet_desc, + (struct usb_descriptor_header *) &pn_union_desc, + (struct usb_descriptor_header *) &pn_data_nop_intf_desc, + (struct usb_descriptor_header *) &pn_data_intf_desc, + (struct usb_descriptor_header *) &pn_fs_sink_desc, + (struct usb_descriptor_header *) &pn_fs_source_desc, + NULL, +}; + +static struct usb_descriptor_header *hs_pn_function[] = { + (struct usb_descriptor_header *) &pn_control_intf_desc, + (struct usb_descriptor_header *) &pn_header_desc, + (struct usb_descriptor_header *) &pn_phonet_desc, + (struct usb_descriptor_header *) &pn_union_desc, + (struct usb_descriptor_header *) &pn_data_nop_intf_desc, + (struct usb_descriptor_header *) &pn_data_intf_desc, + (struct usb_descriptor_header *) &pn_hs_sink_desc, + (struct usb_descriptor_header *) &pn_hs_source_desc, + NULL, +}; + +/*-------------------------------------------------------------------------*/ + +static int pn_net_open(struct net_device *dev) +{ + if (netif_carrier_ok(dev)) + netif_wake_queue(dev); + return 0; +} + +static int pn_net_close(struct net_device *dev) +{ + netif_stop_queue(dev); + return 0; +} + +static void pn_tx_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct f_phonet *fp = ep->driver_data; + struct net_device *dev = fp->dev; + struct sk_buff *skb = req->context; + + switch (req->status) { + case 0: + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; + break; + + case -ESHUTDOWN: /* disconnected */ + case -ECONNRESET: /* disabled */ + dev->stats.tx_aborted_errors++; + default: + dev->stats.tx_errors++; + } + + dev_kfree_skb_any(skb); + if (netif_carrier_ok(dev)) + netif_wake_queue(dev); +} + +static int pn_net_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct phonet_port *port = netdev_priv(dev); + struct f_phonet *fp; + struct usb_request *req; + unsigned long flags; + + if (skb->protocol != htons(ETH_P_PHONET)) + goto out; + + spin_lock_irqsave(&port->lock, flags); + fp = port->usb; + if (unlikely(!fp)) /* race with carrier loss */ + goto out_unlock; + + req = fp->in_req; + req->buf = skb->data; + req->length = skb->len; + req->complete = pn_tx_complete; + req->zero = 1; + req->context = skb; + + if (unlikely(usb_ep_queue(fp->in_ep, req, GFP_ATOMIC))) + goto out_unlock; + + netif_stop_queue(dev); + skb = NULL; + +out_unlock: + spin_unlock_irqrestore(&port->lock, flags); +out: + if (unlikely(skb)) { + dev_kfree_skb_any(skb); + dev->stats.tx_dropped++; + } + return 0; +} + +static int pn_net_mtu(struct net_device *dev, int new_mtu) +{ + struct phonet_port *port = netdev_priv(dev); + unsigned long flags; + int err = -EBUSY; + + if ((new_mtu < PHONET_MIN_MTU) || (new_mtu > PHONET_MAX_MTU)) + return -EINVAL; + + spin_lock_irqsave(&port->lock, flags); + if (!netif_carrier_ok(dev)) { + dev->mtu = new_mtu; + err = 0; + } + spin_unlock_irqrestore(&port->lock, flags); + return err; +} + +static void pn_net_setup(struct net_device *dev) +{ + dev->features = 0; + dev->type = ARPHRD_PHONET; + dev->flags = IFF_POINTOPOINT | IFF_NOARP; + dev->mtu = PHONET_DEV_MTU; + dev->hard_header_len = 1; + dev->dev_addr[0] = PN_MEDIA_USB; + dev->addr_len = 1; + dev->tx_queue_len = 1; + + dev->destructor = free_netdev; + dev->header_ops = &phonet_header_ops; + dev->open = pn_net_open; + dev->stop = pn_net_close; + dev->hard_start_xmit = pn_net_xmit; /* mandatory */ + dev->change_mtu = pn_net_mtu; +} + +/*-------------------------------------------------------------------------*/ + +/* + * Queue buffer for data from the host + */ +static int +pn_rx_submit(struct f_phonet *fp, struct usb_request *req, gfp_t gfp_flags) +{ + struct sk_buff *skb; + const size_t size = fp->dev->mtu; + int err; + + skb = alloc_skb(size, gfp_flags); + if (!skb) + return -ENOMEM; + + req->buf = skb->data; + req->length = size; + req->context = skb; + + err = usb_ep_queue(fp->out_ep, req, gfp_flags); + if (unlikely(err)) + dev_kfree_skb_any(skb); + return err; +} + +static void pn_rx_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct f_phonet *fp = ep->driver_data; + struct net_device *dev = fp->dev; + struct sk_buff *skb = req->context; + int status = req->status; + + switch (status) { + case 0: + if (unlikely(!netif_running(dev))) + break; + if (unlikely(req->actual < 1)) + break; + skb_put(skb, req->actual); + skb->protocol = htons(ETH_P_PHONET); + skb_reset_mac_header(skb); + __skb_pull(skb, 1); + skb->dev = dev; + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; + + netif_rx(skb); + skb = NULL; + break; + + /* Do not resubmit in these cases: */ + case -ESHUTDOWN: /* disconnect */ + case -ECONNABORTED: /* hw reset */ + case -ECONNRESET: /* dequeued (unlink or netif down) */ + req = NULL; + break; + + /* Do resubmit in these cases: */ + case -EOVERFLOW: /* request buffer overflow */ + dev->stats.rx_over_errors++; + default: + dev->stats.rx_errors++; + break; + } + + if (skb) + dev_kfree_skb_any(skb); + if (req) + pn_rx_submit(fp, req, GFP_ATOMIC); +} + +/*-------------------------------------------------------------------------*/ + +static void __pn_reset(struct usb_function *f) +{ + struct f_phonet *fp = func_to_pn(f); + struct net_device *dev = fp->dev; + struct phonet_port *port = netdev_priv(dev); + + netif_carrier_off(dev); + netif_stop_queue(dev); + port->usb = NULL; + + usb_ep_disable(fp->out_ep); + usb_ep_disable(fp->in_ep); +} + +static int pn_set_alt(struct usb_function *f, unsigned intf, unsigned alt) +{ + struct f_phonet *fp = func_to_pn(f); + struct usb_gadget *gadget = fp->function.config->cdev->gadget; + + if (intf == pn_control_intf_desc.bInterfaceNumber) + /* control interface, no altsetting */ + return (alt > 0) ? -EINVAL : 0; + + if (intf == pn_data_intf_desc.bInterfaceNumber) { + struct net_device *dev = fp->dev; + struct phonet_port *port = netdev_priv(dev); + + /* data intf (0: inactive, 1: active) */ + if (alt > 1) + return -EINVAL; + + spin_lock(&port->lock); + __pn_reset(f); + if (alt == 1) { + struct usb_endpoint_descriptor *out, *in; + int i; + + out = ep_choose(gadget, + &pn_hs_sink_desc, + &pn_fs_sink_desc); + in = ep_choose(gadget, + &pn_hs_source_desc, + &pn_fs_source_desc); + usb_ep_enable(fp->out_ep, out); + usb_ep_enable(fp->in_ep, in); + + port->usb = fp; + fp->out_ep->driver_data = fp; + fp->in_ep->driver_data = fp; + + netif_carrier_on(dev); + if (netif_running(dev)) + netif_wake_queue(dev); + for (i = 0; i < phonet_rxq_size; i++) + pn_rx_submit(fp, fp->out_reqv[i], GFP_ATOMIC); + } + spin_unlock(&port->lock); + return 0; + } + + return -EINVAL; +} + +static int pn_get_alt(struct usb_function *f, unsigned intf) +{ + struct f_phonet *fp = func_to_pn(f); + + if (intf == pn_control_intf_desc.bInterfaceNumber) + return 0; + + if (intf == pn_data_intf_desc.bInterfaceNumber) { + struct phonet_port *port = netdev_priv(fp->dev); + u8 alt; + + spin_lock(&port->lock); + alt = port->usb != NULL; + spin_unlock(&port->lock); + return alt; + } + + return -EINVAL; +} + +static void pn_disconnect(struct usb_function *f) +{ + struct f_phonet *fp = func_to_pn(f); + struct phonet_port *port = netdev_priv(fp->dev); + unsigned long flags; + + /* remain disabled until set_alt */ + spin_lock_irqsave(&port->lock, flags); + __pn_reset(f); + spin_unlock_irqrestore(&port->lock, flags); +} + +/*-------------------------------------------------------------------------*/ + +static __init +int pn_bind(struct usb_configuration *c, struct usb_function *f) +{ + struct usb_composite_dev *cdev = c->cdev; + struct usb_gadget *gadget = cdev->gadget; + struct f_phonet *fp = func_to_pn(f); + struct usb_ep *ep; + int status, i; + + /* Reserve interface IDs */ + status = usb_interface_id(c, f); + if (status < 0) + goto err; + pn_control_intf_desc.bInterfaceNumber = status; + pn_union_desc.bMasterInterface0 = status; + + status = usb_interface_id(c, f); + if (status < 0) + goto err; + pn_data_nop_intf_desc.bInterfaceNumber = status; + pn_data_intf_desc.bInterfaceNumber = status; + pn_union_desc.bSlaveInterface0 = status; + + /* Reserve endpoints */ + status = -ENODEV; + ep = usb_ep_autoconfig(gadget, &pn_fs_sink_desc); + if (!ep) + goto err; + fp->out_ep = ep; + ep->driver_data = fp; /* Claim */ + + ep = usb_ep_autoconfig(gadget, &pn_fs_source_desc); + if (!ep) + goto err; + fp->in_ep = ep; + ep->driver_data = fp; /* Claim */ + + pn_hs_sink_desc.bEndpointAddress = + pn_fs_sink_desc.bEndpointAddress; + pn_hs_source_desc.bEndpointAddress = + pn_fs_source_desc.bEndpointAddress; + + /* Do not try to bind Phonet twice... */ + fp->function.descriptors = fs_pn_function; + fp->function.hs_descriptors = hs_pn_function; + + /* Incoming USB requests */ + status = -ENOMEM; + for (i = 0; i < phonet_rxq_size; i++) { + struct usb_request *req; + + req = usb_ep_alloc_request(fp->out_ep, GFP_KERNEL); + if (!req) + goto err; + + req->complete = pn_rx_complete; + fp->out_reqv[i] = req; + } + + /* Outgoing USB requests */ + fp->in_req = usb_ep_alloc_request(fp->in_ep, GFP_KERNEL); + if (!fp->in_req) + goto err; + + INFO(cdev, "USB CDC Phonet function\n"); + INFO(cdev, "using %s, OUT %s, IN %s\n", cdev->gadget->name, + fp->out_ep->name, fp->in_ep->name); + return 0; + +err: + if (fp->out_ep) + fp->out_ep->driver_data = NULL; + if (fp->in_ep) + fp->in_ep->driver_data = NULL; + ERROR(cdev, "USB CDC Phonet: cannot autoconfigure\n"); + return status; +} + +static void +pn_unbind(struct usb_configuration *c, struct usb_function *f) +{ + struct f_phonet *fp = func_to_pn(f); + int i; + + /* We are already disconnected */ + if (fp->in_req) + usb_ep_free_request(fp->in_ep, fp->in_req); + for (i = 0; i < phonet_rxq_size; i++) + if (fp->out_reqv[i]) + usb_ep_free_request(fp->out_ep, fp->out_reqv[i]); + + kfree(fp); +} + +/*-------------------------------------------------------------------------*/ + +static struct net_device *dev; + +int __init phonet_bind_config(struct usb_configuration *c) +{ + struct f_phonet *fp; + int err; + + fp = kzalloc(sizeof(*fp), GFP_KERNEL); + if (!fp) + return -ENOMEM; + + fp->dev = dev; + fp->function.name = "phonet"; + fp->function.bind = pn_bind; + fp->function.unbind = pn_unbind; + fp->function.set_alt = pn_set_alt; + fp->function.get_alt = pn_get_alt; + fp->function.disable = pn_disconnect; + + err = usb_add_function(c, &fp->function); + if (err) + kfree(fp); + return err; +} + +int __init gphonet_setup(struct usb_gadget *gadget) +{ + struct phonet_port *port; + int err; + + /* Create net device */ + BUG_ON(dev); + dev = alloc_netdev(sizeof(*port) + + (phonet_rxq_size * sizeof(struct usb_request *)), + "upnlink%d", pn_net_setup); + if (!dev) + return -ENOMEM; + + port = netdev_priv(dev); + spin_lock_init(&port->lock); + netif_carrier_off(dev); + netif_stop_queue(dev); + SET_NETDEV_DEV(dev, &gadget->dev); + + err = register_netdev(dev); + if (err) + free_netdev(dev); + return err; +} + +void gphonet_cleanup(void) +{ + unregister_netdev(dev); +} diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index 77b44fb48f0a2d6ef6d86aba704fdb4dcd7c41f0..3a8879ec2061495f7abdd5c28ede45dfdf23e11d 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -623,7 +623,6 @@ static void start_ep0(struct m66592_ep *ep, struct m66592_request *req) #if defined(CONFIG_SUPERH_BUILT_IN_M66592) static void init_controller(struct m66592 *m66592) { - usbf_start_clock(); m66592_bset(m66592, M66592_HSE, M66592_SYSCFG); /* High spd */ m66592_bclr(m66592, M66592_USBE, M66592_SYSCFG); m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG); @@ -671,9 +670,7 @@ static void init_controller(struct m66592 *m66592) static void disable_controller(struct m66592 *m66592) { -#if defined(CONFIG_SUPERH_BUILT_IN_M66592) - usbf_stop_clock(); -#else +#if !defined(CONFIG_SUPERH_BUILT_IN_M66592) m66592_bclr(m66592, M66592_SCKE, M66592_SYSCFG); udelay(1); m66592_bclr(m66592, M66592_PLLC, M66592_SYSCFG); @@ -686,9 +683,7 @@ static void disable_controller(struct m66592 *m66592) static void m66592_start_xclock(struct m66592 *m66592) { -#if defined(CONFIG_SUPERH_BUILT_IN_M66592) - usbf_start_clock(); -#else +#if !defined(CONFIG_SUPERH_BUILT_IN_M66592) u16 tmp; tmp = m66592_read(m66592, M66592_SYSCFG); @@ -1539,7 +1534,10 @@ static int __exit m66592_remove(struct platform_device *pdev) iounmap(m66592->reg); free_irq(platform_get_irq(pdev, 0), m66592); m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req); - usbf_stop_clock(); +#if defined(CONFIG_SUPERH_BUILT_IN_M66592) && defined(CONFIG_HAVE_CLK) + clk_disable(m66592->clk); + clk_put(m66592->clk); +#endif kfree(m66592); return 0; } @@ -1556,6 +1554,9 @@ static int __init m66592_probe(struct platform_device *pdev) int irq; void __iomem *reg = NULL; struct m66592 *m66592 = NULL; +#if defined(CONFIG_SUPERH_BUILT_IN_M66592) && defined(CONFIG_HAVE_CLK) + char clk_name[8]; +#endif int ret = 0; int i; @@ -1614,6 +1615,16 @@ static int __init m66592_probe(struct platform_device *pdev) goto clean_up; } +#if defined(CONFIG_SUPERH_BUILT_IN_M66592) && defined(CONFIG_HAVE_CLK) + snprintf(clk_name, sizeof(clk_name), "usbf%d", pdev->id); + m66592->clk = clk_get(&pdev->dev, clk_name); + if (IS_ERR(m66592->clk)) { + dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name); + ret = PTR_ERR(m66592->clk); + goto clean_up2; + } + clk_enable(m66592->clk); +#endif INIT_LIST_HEAD(&m66592->gadget.ep_list); m66592->gadget.ep0 = &m66592->ep[0].ep; INIT_LIST_HEAD(&m66592->gadget.ep0->ep_list); @@ -1645,7 +1656,7 @@ static int __init m66592_probe(struct platform_device *pdev) m66592->ep0_req = m66592_alloc_request(&m66592->ep[0].ep, GFP_KERNEL); if (m66592->ep0_req == NULL) - goto clean_up2; + goto clean_up3; m66592->ep0_req->complete = nop_completion; init_controller(m66592); @@ -1653,7 +1664,12 @@ static int __init m66592_probe(struct platform_device *pdev) dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION); return 0; +clean_up3: +#if defined(CONFIG_SUPERH_BUILT_IN_M66592) && defined(CONFIG_HAVE_CLK) + clk_disable(m66592->clk); + clk_put(m66592->clk); clean_up2: +#endif free_irq(irq, m66592); clean_up: if (m66592) { diff --git a/drivers/usb/gadget/m66592-udc.h b/drivers/usb/gadget/m66592-udc.h index f118f00f14662e4b884671cb4f4084be4e56cc48..286ce07e7960423ac2a18f4b2075c440fab1b010 100644 --- a/drivers/usb/gadget/m66592-udc.h +++ b/drivers/usb/gadget/m66592-udc.h @@ -23,6 +23,10 @@ #ifndef __M66592_UDC_H__ #define __M66592_UDC_H__ +#if defined(CONFIG_SUPERH_BUILT_IN_M66592) && defined(CONFIG_HAVE_CLK) +#include +#endif + #define M66592_SYSCFG 0x00 #define M66592_XTAL 0xC000 /* b15-14: Crystal selection */ #define M66592_XTAL48 0x8000 /* 48MHz */ @@ -476,6 +480,9 @@ struct m66592_ep { struct m66592 { spinlock_t lock; void __iomem *reg; +#if defined(CONFIG_SUPERH_BUILT_IN_M66592) && defined(CONFIG_HAVE_CLK) + struct clk *clk; +#endif struct usb_gadget gadget; struct usb_gadget_driver *driver; @@ -604,26 +611,6 @@ static inline void m66592_mdfy(struct m66592 *m66592, u16 val, u16 pat, #define m66592_bset(m66592, val, offset) \ m66592_mdfy(m66592, val, 0, offset) -#if defined(CONFIG_SUPERH_BUILT_IN_M66592) -#include -#define MSTPCR2 0xA4150038 /* for SH7722 */ -#define MSTPCR2_USB 0x00000800 - -static inline void usbf_start_clock(void) -{ - ctrl_outl(ctrl_inl(MSTPCR2) & ~MSTPCR2_USB, MSTPCR2); -} - -static inline void usbf_stop_clock(void) -{ - ctrl_outl(ctrl_inl(MSTPCR2) | MSTPCR2_USB, MSTPCR2); -} - -#else -#define usbf_start_clock(x) -#define usbf_stop_clock(x) -#endif /* if defined(CONFIG_SUPERH_BUILT_IN_M66592) */ - #endif /* ifndef __M66592_UDC_H__ */ diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index 66948b72bb9b06e5c73345322b800af69a9618db..d9739d52f8f55ad6f2106037c1805b3aadc41ab4 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -146,7 +146,7 @@ static inline int qlen(struct usb_gadget *gadget) /* NETWORK DRIVER HOOKUP (to the layer above this driver) */ -static int eth_change_mtu(struct net_device *net, int new_mtu) +static int ueth_change_mtu(struct net_device *net, int new_mtu) { struct eth_dev *dev = netdev_priv(net); unsigned long flags; @@ -764,7 +764,7 @@ int __init gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN]) if (ethaddr) memcpy(ethaddr, dev->host_mac, ETH_ALEN); - net->change_mtu = eth_change_mtu; + net->change_mtu = ueth_change_mtu; net->hard_start_xmit = eth_start_xmit; net->open = eth_open; net->stop = eth_stop; @@ -787,10 +787,8 @@ int __init gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN]) dev_dbg(&g->dev, "register_netdev failed, %d\n", status); free_netdev(net); } else { - DECLARE_MAC_BUF(tmp); - - INFO(dev, "MAC %s\n", print_mac(tmp, net->dev_addr)); - INFO(dev, "HOST MAC %s\n", print_mac(tmp, dev->host_mac)); + INFO(dev, "MAC %pM\n", net->dev_addr); + INFO(dev, "HOST MAC %pM\n", dev->host_mac); the_dev = dev; } diff --git a/drivers/usb/gadget/u_phonet.h b/drivers/usb/gadget/u_phonet.h new file mode 100644 index 0000000000000000000000000000000000000000..09a75259b6cd4f790bb62954f34880bb180050be --- /dev/null +++ b/drivers/usb/gadget/u_phonet.h @@ -0,0 +1,21 @@ +/* + * u_phonet.h - interface to Phonet + * + * Copyright (C) 2007-2008 by Nokia Corporation + * + * This software is distributed under the terms of the GNU General + * Public License ("GPL") as published by the Free Software Foundation, + * either version 2 of that License or (at your option) any later version. + */ + +#ifndef __U_PHONET_H +#define __U_PHONET_H + +#include +#include + +int gphonet_setup(struct usb_gadget *gadget); +int phonet_bind_config(struct usb_configuration *c); +void gphonet_cleanup(void); + +#endif /* __U_PHONET_H */ diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 2376f24f3c83dc964f03286a66a88ab195434179..c21f14e0666a379d15a8cbf1a14326b7803bdaf6 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -114,6 +114,9 @@ static int r8a66597_clock_enable(struct r8a66597 *r8a66597) int i = 0; #if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) +#if defined(CONFIG_HAVE_CLK) + clk_enable(r8a66597->clk); +#endif do { r8a66597_write(r8a66597, SCKE, SYSCFG0); tmp = r8a66597_read(r8a66597, SYSCFG0); @@ -154,7 +157,11 @@ static void r8a66597_clock_disable(struct r8a66597 *r8a66597) { r8a66597_bclr(r8a66597, SCKE, SYSCFG0); udelay(1); -#if !defined(CONFIG_SUPERH_ON_CHIP_R8A66597) +#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) +#if defined(CONFIG_HAVE_CLK) + clk_disable(r8a66597->clk); +#endif +#else r8a66597_bclr(r8a66597, PLLC, SYSCFG0); r8a66597_bclr(r8a66597, XCKE, SYSCFG0); r8a66597_bclr(r8a66597, USBE, SYSCFG0); @@ -2261,6 +2268,9 @@ static int __init_or_module r8a66597_remove(struct platform_device *pdev) del_timer_sync(&r8a66597->rh_timer); usb_remove_hcd(hcd); iounmap((void *)r8a66597->reg); +#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK) + clk_put(r8a66597->clk); +#endif usb_put_hcd(hcd); return 0; } @@ -2268,6 +2278,9 @@ static int __init_or_module r8a66597_remove(struct platform_device *pdev) #define resource_len(r) (((r)->end - (r)->start) + 1) static int __init r8a66597_probe(struct platform_device *pdev) { +#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK) + char clk_name[8]; +#endif struct resource *res = NULL, *ires; int irq = -1; void __iomem *reg = NULL; @@ -2320,6 +2333,16 @@ static int __init r8a66597_probe(struct platform_device *pdev) memset(r8a66597, 0, sizeof(struct r8a66597)); dev_set_drvdata(&pdev->dev, r8a66597); +#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK) + snprintf(clk_name, sizeof(clk_name), "usb%d", pdev->id); + r8a66597->clk = clk_get(&pdev->dev, clk_name); + if (IS_ERR(r8a66597->clk)) { + dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name); + ret = PTR_ERR(r8a66597->clk); + goto clean_up2; + } +#endif + spin_lock_init(&r8a66597->lock); init_timer(&r8a66597->rh_timer); r8a66597->rh_timer.function = r8a66597_timer; @@ -2365,11 +2388,18 @@ static int __init r8a66597_probe(struct platform_device *pdev) ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | irq_trigger); if (ret != 0) { dev_err(&pdev->dev, "Failed to add hcd\n"); - goto clean_up; + goto clean_up3; } return 0; +clean_up3: +#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK) + clk_put(r8a66597->clk); +clean_up2: +#endif + usb_put_hcd(hcd); + clean_up: if (reg) iounmap(reg); diff --git a/drivers/usb/host/r8a66597.h b/drivers/usb/host/r8a66597.h index 84ee014173151cd4f541cd5b798cf2800682afb7..ecacde4d69b0801fcf67a0d9a7d316e015829b83 100644 --- a/drivers/usb/host/r8a66597.h +++ b/drivers/usb/host/r8a66597.h @@ -26,6 +26,10 @@ #ifndef __R8A66597_H__ #define __R8A66597_H__ +#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK) +#include +#endif + #define SYSCFG0 0x00 #define SYSCFG1 0x02 #define SYSSTS0 0x04 @@ -481,7 +485,9 @@ struct r8a66597_root_hub { struct r8a66597 { spinlock_t lock; unsigned long reg; - +#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK) + struct clk *clk; +#endif struct r8a66597_device device0; struct r8a66597_root_hub root_hub[R8A66597_MAX_ROOT_HUB]; struct list_head pipe_queue[R8A66597_MAX_NUM_PIPE]; diff --git a/drivers/uwb/wlp/eda.c b/drivers/uwb/wlp/eda.c index cdfe8dfc4340a7317272737ca5c254602ff9d27f..10985fa233ccfc038e66abc5e5fad9cbe8362e4e 100644 --- a/drivers/uwb/wlp/eda.c +++ b/drivers/uwb/wlp/eda.c @@ -313,12 +313,9 @@ int wlp_eda_for_virtual(struct wlp_eda *eda, list_for_each_entry(itr, &eda->cache, list_node) { if (!memcmp(itr->virt_addr, virt_addr, sizeof(itr->virt_addr))) { - d_printf(6, dev, "EDA: looking for " - "%02x:%02x:%02x:%02x:%02x:%02x hit %02x:%02x " + d_printf(6, dev, "EDA: looking for %pM hit %02x:%02x " "wss %p tag 0x%02x state %u\n", - virt_addr[0], virt_addr[1], - virt_addr[2], virt_addr[3], - virt_addr[4], virt_addr[5], + virt_addr, itr->dev_addr.data[1], itr->dev_addr.data[0], itr->wss, itr->tag, itr->state); @@ -327,24 +324,13 @@ int wlp_eda_for_virtual(struct wlp_eda *eda, found = 1; break; } else - d_printf(6, dev, "EDA: looking for " - "%02x:%02x:%02x:%02x:%02x:%02x " - "against " - "%02x:%02x:%02x:%02x:%02x:%02x miss\n", - virt_addr[0], virt_addr[1], - virt_addr[2], virt_addr[3], - virt_addr[4], virt_addr[5], - itr->virt_addr[0], itr->virt_addr[1], - itr->virt_addr[2], itr->virt_addr[3], - itr->virt_addr[4], itr->virt_addr[5]); + d_printf(6, dev, "EDA: looking for %pM against %pM miss\n", + virt_addr, itr->virt_addr); } if (!found) { if (printk_ratelimit()) - dev_err(dev, "EDA: Eth addr %02x:%02x:%02x" - ":%02x:%02x:%02x not found.\n", - virt_addr[0], virt_addr[1], - virt_addr[2], virt_addr[3], - virt_addr[4], virt_addr[5]); + dev_err(dev, "EDA: Eth addr %pM not found.\n", + virt_addr); result = -ENODEV; } spin_unlock_irqrestore(&eda->lock, flags); @@ -380,19 +366,13 @@ ssize_t wlp_eda_show(struct wlp *wlp, char *buf) "tag state virt_addr\n"); list_for_each_entry(entry, &eda->cache, list_node) { result += scnprintf(buf + result, PAGE_SIZE - result, - "%02x:%02x:%02x:%02x:%02x:%02x %02x:%02x " - "%p 0x%02x %s " - "%02x:%02x:%02x:%02x:%02x:%02x\n", - entry->eth_addr[0], entry->eth_addr[1], - entry->eth_addr[2], entry->eth_addr[3], - entry->eth_addr[4], entry->eth_addr[5], + "%pM %02x:%02x %p 0x%02x %s %pM\n", + entry->eth_addr, entry->dev_addr.data[1], entry->dev_addr.data[0], entry->wss, entry->tag, wlp_wss_connect_state_str(entry->state), - entry->virt_addr[0], entry->virt_addr[1], - entry->virt_addr[2], entry->virt_addr[3], - entry->virt_addr[4], entry->virt_addr[5]); + entry->virt_addr); if (result >= PAGE_SIZE) break; } diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 3f3ce13fef431450909e12cb91646534c68cf46f..d0c821992a99ca0dcba772eba1ff6aaf5c63f3ad 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -1889,10 +1889,11 @@ config FB_W100 config FB_SH_MOBILE_LCDC tristate "SuperH Mobile LCDC framebuffer support" depends on FB && SUPERH - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - default m + select FB_SYS_FILLRECT + select FB_SYS_COPYAREA + select FB_SYS_IMAGEBLIT + select FB_SYS_FOPS + select FB_DEFERRED_IO ---help--- Frame buffer driver for the on-chip SH-Mobile LCD controller. @@ -2021,17 +2022,19 @@ config FB_COBALT depends on FB && MIPS_COBALT config FB_SH7760 - bool "SH7760/SH7763 LCDC support" - depends on FB && (CPU_SUBTYPE_SH7760 || CPU_SUBTYPE_SH7763) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - Support for the SH7760/SH7763 integrated (D)STN/TFT LCD Controller. - Supports display resolutions up to 1024x1024 pixel, grayscale and - color operation, with depths ranging from 1 bpp to 8 bpp monochrome - and 8, 15 or 16 bpp color; 90 degrees clockwise display rotation for - panels <= 320 pixel horizontal resolution. + bool "SH7760/SH7763/SH7720/SH7721 LCDC support" + depends on FB && (CPU_SUBTYPE_SH7760 || CPU_SUBTYPE_SH7763 \ + || CPU_SUBTYPE_SH7720 || CPU_SUBTYPE_SH7721) + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + ---help--- + Support for the SH7760/SH7763/SH7720/SH7721 integrated + (D)STN/TFT LCD Controller. + Supports display resolutions up to 1024x1024 pixel, grayscale and + color operation, with depths ranging from 1 bpp to 8 bpp monochrome + and 8, 15 or 16 bpp color; 90 degrees clockwise display rotation for + panels <= 320 pixel horizontal resolution. config FB_VIRTUAL tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)" diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 0b2adefe9e3d55f3b20e3e668a8d5e7969058948..4bcff81b50e03afa91f6dbf8eeef0784a2f12f12 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -81,9 +81,6 @@ #ifdef CONFIG_ATARI #include #endif -#ifdef CONFIG_MAC -#include -#endif #if defined(__mc68000__) #include #include @@ -160,8 +157,6 @@ static int fbcon_set_origin(struct vc_data *); /* # VBL ints between cursor state changes */ #define ATARI_CURSOR_BLINK_RATE (42) -#define MAC_CURSOR_BLINK_RATE (32) -#define DEFAULT_CURSOR_BLINK_RATE (20) static int vbl_cursor_cnt; static int fbcon_cursor_noblink; @@ -210,19 +205,6 @@ static void fbcon_start(void); static void fbcon_exit(void); static struct device *fbcon_device; -#ifdef CONFIG_MAC -/* - * On the Macintoy, there may or may not be a working VBL int. We need to probe - */ -static int vbl_detected; - -static irqreturn_t fb_vbl_detect(int irq, void *dummy) -{ - vbl_detected++; - return IRQ_HANDLED; -} -#endif - #ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION static inline void fbcon_set_rotation(struct fb_info *info) { @@ -421,7 +403,7 @@ static void fb_flashcursor(struct work_struct *work) release_console_sem(); } -#if defined(CONFIG_ATARI) || defined(CONFIG_MAC) +#ifdef CONFIG_ATARI static int cursor_blink_rate; static irqreturn_t fb_vbl_handler(int irq, void *dev_id) { @@ -949,9 +931,7 @@ static const char *fbcon_startup(void) struct fb_info *info = NULL; struct fbcon_ops *ops; int rows, cols; - int irqres; - irqres = 1; /* * If num_registered_fb is zero, this is a call for the dummy part. * The frame buffer devices weren't initialized yet. @@ -1040,56 +1020,11 @@ static const char *fbcon_startup(void) #ifdef CONFIG_ATARI if (MACH_IS_ATARI) { cursor_blink_rate = ATARI_CURSOR_BLINK_RATE; - irqres = - request_irq(IRQ_AUTO_4, fb_vbl_handler, + (void)request_irq(IRQ_AUTO_4, fb_vbl_handler, IRQ_TYPE_PRIO, "framebuffer vbl", info); } -#endif /* CONFIG_ATARI */ - -#ifdef CONFIG_MAC - /* - * On a Macintoy, the VBL interrupt may or may not be active. - * As interrupt based cursor is more reliable and race free, we - * probe for VBL interrupts. - */ - if (MACH_IS_MAC) { - int ct = 0; - /* - * Probe for VBL: set temp. handler ... - */ - irqres = request_irq(IRQ_MAC_VBL, fb_vbl_detect, 0, - "framebuffer vbl", info); - vbl_detected = 0; - - /* - * ... and spin for 20 ms ... - */ - while (!vbl_detected && ++ct < 1000) - udelay(20); - - if (ct == 1000) - printk - ("fbcon_startup: No VBL detected, using timer based cursor.\n"); - - free_irq(IRQ_MAC_VBL, fb_vbl_detect); - - if (vbl_detected) { - /* - * interrupt based cursor ok - */ - cursor_blink_rate = MAC_CURSOR_BLINK_RATE; - irqres = - request_irq(IRQ_MAC_VBL, fb_vbl_handler, 0, - "framebuffer vbl", info); - } else { - /* - * VBL not detected: fall through, use timer based cursor - */ - irqres = 1; - } - } -#endif /* CONFIG_MAC */ +#endif /* CONFIG_ATARI */ fbcon_add_cursor_timer(info); fbcon_has_exited = 0; @@ -3520,11 +3455,8 @@ static void fbcon_exit(void) return; #ifdef CONFIG_ATARI - free_irq(IRQ_AUTO_4, fb_vbl_handler); -#endif -#ifdef CONFIG_MAC - if (MACH_IS_MAC && vbl_detected) - free_irq(IRQ_MAC_VBL, fb_vbl_handler); + if (MACH_IS_ATARI) + free_irq(IRQ_AUTO_4, fb_vbl_handler); #endif kfree((void *)softback_buf); diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c index b0be7eac32d817c8cec0255374ae80ab87483d87..49fcbe8f18ac4dbbd958f5e1973be85dda2875ae 100644 --- a/drivers/video/controlfb.c +++ b/drivers/video/controlfb.c @@ -298,10 +298,10 @@ static int controlfb_mmap(struct fb_info *info, return -EINVAL; start = info->fix.mmio_start; len = PAGE_ALIGN((start & ~PAGE_MASK)+info->fix.mmio_len); - pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE|_PAGE_GUARDED; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); } else { /* framebuffer */ - pgprot_val(vma->vm_page_prot) |= _PAGE_WRITETHRU; + vma->vm_page_prot = pgprot_cached_wthru(vma->vm_page_prot); } start &= PAGE_MASK; if ((vma->vm_end - vma->vm_start + off) > len) diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c index 4835bdc4e9f1819615ab2454549f9a637d01a0e1..082026546aee979e9bee1f2e8f4a440df02d20a6 100644 --- a/drivers/video/fb_defio.c +++ b/drivers/video/fb_defio.c @@ -24,6 +24,19 @@ #include #include +struct page *fb_deferred_io_page(struct fb_info *info, unsigned long offs) +{ + void *screen_base = (void __force *) info->screen_base; + struct page *page; + + if (is_vmalloc_addr(screen_base + offs)) + page = vmalloc_to_page(screen_base + offs); + else + page = pfn_to_page((info->fix.smem_start + offs) >> PAGE_SHIFT); + + return page; +} + /* this is to find and return the vmalloc-ed fb pages */ static int fb_deferred_io_fault(struct vm_area_struct *vma, struct vm_fault *vmf) @@ -31,14 +44,12 @@ static int fb_deferred_io_fault(struct vm_area_struct *vma, unsigned long offset; struct page *page; struct fb_info *info = vma->vm_private_data; - /* info->screen_base is virtual memory */ - void *screen_base = (void __force *) info->screen_base; offset = vmf->pgoff << PAGE_SHIFT; if (offset >= info->fix.smem_len) return VM_FAULT_SIGBUS; - page = vmalloc_to_page(screen_base + offset); + page = fb_deferred_io_page(info, offset); if (!page) return VM_FAULT_SIGBUS; @@ -60,6 +71,10 @@ int fb_deferred_io_fsync(struct file *file, struct dentry *dentry, int datasync) { struct fb_info *info = file->private_data; + /* Skip if deferred io is complied-in but disabled on this fbdev */ + if (!info->fbdefio) + return 0; + /* Kill off the delayed work */ cancel_rearming_delayed_work(&info->deferred_work); @@ -184,7 +199,6 @@ EXPORT_SYMBOL_GPL(fb_deferred_io_open); void fb_deferred_io_cleanup(struct fb_info *info) { - void *screen_base = (void __force *) info->screen_base; struct fb_deferred_io *fbdefio = info->fbdefio; struct page *page; int i; @@ -195,9 +209,12 @@ void fb_deferred_io_cleanup(struct fb_info *info) /* clear out the mapping that we setup */ for (i = 0 ; i < info->fix.smem_len; i += PAGE_SIZE) { - page = vmalloc_to_page(screen_base + i); + page = fb_deferred_io_page(info, i); page->mapping = NULL; } + + info->fbops->fb_mmap = NULL; + mutex_destroy(&fbdefio->lock); } EXPORT_SYMBOL_GPL(fb_deferred_io_cleanup); diff --git a/drivers/video/macfb.c b/drivers/video/macfb.c index ee380d5f34107d0713b582b9a29cd6259a327119..d66887e8cbb177c6bec6512066de84617be56d15 100644 --- a/drivers/video/macfb.c +++ b/drivers/video/macfb.c @@ -36,7 +36,6 @@ #include #include #include -#include /* Common DAC base address for the LC, RBV, Valkyrie, and IIvx */ #define DAC_BASE 0x50f24000 @@ -78,34 +77,34 @@ static int csc_setpalette (unsigned int regno, unsigned int red, unsigned int green, unsigned int blue, struct fb_info *fb_info); -static volatile struct { +static struct { unsigned char addr; /* Note: word-aligned */ char pad[3]; unsigned char lut; -} *valkyrie_cmap_regs; +} __iomem *valkyrie_cmap_regs; -static volatile struct { +static struct { unsigned char addr; unsigned char lut; -} *v8_brazil_cmap_regs; +} __iomem *v8_brazil_cmap_regs; -static volatile struct { +static struct { unsigned char addr; char pad1[3]; /* word aligned */ unsigned char lut; char pad2[3]; /* word aligned */ unsigned char cntl; /* a guess as to purpose */ -} *rbv_cmap_regs; +} __iomem *rbv_cmap_regs; -static volatile struct { +static struct { unsigned long reset; unsigned long pad1[3]; unsigned char pad2[3]; unsigned char lut; -} *dafb_cmap_regs; +} __iomem *dafb_cmap_regs; -static volatile struct { +static struct { unsigned char addr; /* OFFSET: 0x00 */ unsigned char pad1[15]; unsigned char lut; /* OFFSET: 0x10 */ @@ -114,16 +113,16 @@ static volatile struct { unsigned char pad3[7]; unsigned long vbl_addr; /* OFFSET: 0x28 */ unsigned int status2; /* OFFSET: 0x2C */ -} *civic_cmap_regs; +} __iomem *civic_cmap_regs; -static volatile struct { +static struct { char pad1[0x40]; unsigned char clut_waddr; /* 0x40 */ char pad2; unsigned char clut_data; /* 0x42 */ char pad3[0x3]; unsigned char clut_raddr; /* 0x46 */ -} *csc_cmap_regs; +} __iomem *csc_cmap_regs; /* We will leave these the way they are for the time being */ struct mdc_cmap_regs { @@ -507,10 +506,10 @@ static int csc_setpalette (unsigned int regno, unsigned int red, struct fb_info *info) { mdelay(1); - csc_cmap_regs->clut_waddr = regno; - csc_cmap_regs->clut_data = red; - csc_cmap_regs->clut_data = green; - csc_cmap_regs->clut_data = blue; + nubus_writeb(regno, &csc_cmap_regs->clut_waddr); + nubus_writeb(red, &csc_cmap_regs->clut_data); + nubus_writeb(green, &csc_cmap_regs->clut_data); + nubus_writeb(blue, &csc_cmap_regs->clut_data); return 0; } diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c index 4b5d807719041e99aa7f1d70afb1b9a308c21fa6..38ac805db97d4bcb5cdca4866f0fd3cfb430dce3 100644 --- a/drivers/video/ps3fb.c +++ b/drivers/video/ps3fb.c @@ -460,12 +460,16 @@ static void ps3fb_sync_image(struct device *dev, u64 frame_offset, line_length |= (u64)src_line_length << 32; src_offset += GPU_FB_START; + + mutex_lock(&ps3_gpu_mutex); status = lv1_gpu_context_attribute(ps3fb.context_handle, L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, dst_offset, GPU_IOIF + src_offset, L1GPU_FB_BLIT_WAIT_FOR_COMPLETION | (width << 16) | height, line_length); + mutex_unlock(&ps3_gpu_mutex); + if (status) dev_err(dev, "%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n", @@ -784,15 +788,6 @@ static int ps3fb_wait_for_vsync(u32 crtc) return 0; } -static void ps3fb_flip_ctl(int on, void *data) -{ - struct ps3fb_priv *priv = data; - if (on) - atomic_dec_if_positive(&priv->ext_flip); - else - atomic_inc(&priv->ext_flip); -} - /* * ioctl @@ -1228,7 +1223,6 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) } ps3fb.task = task; - ps3av_register_flip_ctl(ps3fb_flip_ctl, &ps3fb); return 0; @@ -1258,10 +1252,9 @@ static int ps3fb_shutdown(struct ps3_system_bus_device *dev) dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__); - ps3fb_flip_ctl(0, &ps3fb); /* flip off */ + atomic_inc(&ps3fb.ext_flip); /* flip off */ ps3fb.dinfo->irq.mask = 0; - ps3av_register_flip_ctl(NULL, NULL); if (ps3fb.task) { struct task_struct *task = ps3fb.task; ps3fb.task = NULL; @@ -1296,8 +1289,8 @@ static int ps3fb_shutdown(struct ps3_system_bus_device *dev) } static struct ps3_system_bus_driver ps3fb_driver = { - .match_id = PS3_MATCH_ID_GRAPHICS, - .match_sub_id = PS3_MATCH_SUB_ID_FB, + .match_id = PS3_MATCH_ID_GPU, + .match_sub_id = PS3_MATCH_SUB_ID_GPU_FB, .core.name = DEVICE_NAME, .core.owner = THIS_MODULE, .probe = ps3fb_probe, @@ -1355,4 +1348,4 @@ module_exit(ps3fb_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("PS3 GPU Frame Buffer Driver"); MODULE_AUTHOR("Sony Computer Entertainment Inc."); -MODULE_ALIAS(PS3_MODULE_ALIAS_GRAPHICS); +MODULE_ALIAS(PS3_MODULE_ALIAS_GPU_FB); diff --git a/drivers/video/sh7760fb.c b/drivers/video/sh7760fb.c index 8d0212da4514eb3e98a614b7139f48391f00f779..653bdfee30578fa9b6732f286b0c4fb435c5fd05 100644 --- a/drivers/video/sh7760fb.c +++ b/drivers/video/sh7760fb.c @@ -13,6 +13,8 @@ * * Thanks to Siegfried Schaefer * for his original source and testing! + * + * sh7760_setcolreg get from drivers/video/sh_mobile_lcdcfb.c */ #include @@ -53,29 +55,6 @@ static irqreturn_t sh7760fb_irq(int irq, void *data) return IRQ_HANDLED; } -static void sh7760fb_wait_vsync(struct fb_info *info) -{ - struct sh7760fb_par *par = info->par; - - if (par->pd->novsync) - return; - - iowrite16(ioread16(par->base + LDINTR) & ~VINT_CHECK, - par->base + LDINTR); - - if (par->irq < 0) { - /* poll for vert. retrace: status bit is sticky */ - while (!(ioread16(par->base + LDINTR) & VINT_CHECK)) - cpu_relax(); - } else { - /* a "wait_for_irq_event(par->irq)" would be extremely nice */ - init_completion(&par->vsync); - enable_irq(par->irq); - wait_for_completion(&par->vsync); - disable_irq_nosync(par->irq); - } -} - /* wait_for_lps - wait until power supply has reached a certain state. */ static int wait_for_lps(struct sh7760fb_par *par, int val) { @@ -117,55 +96,28 @@ static int sh7760fb_blank(int blank, struct fb_info *info) return wait_for_lps(par, lps); } -/* set color registers */ -static int sh7760fb_setcmap(struct fb_cmap *cmap, struct fb_info *info) +static int sh7760_setcolreg (u_int regno, + u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) { - struct sh7760fb_par *par = info->par; - u32 s = cmap->start; - u32 l = cmap->len; - u16 *r = cmap->red; - u16 *g = cmap->green; - u16 *b = cmap->blue; - u32 col, tmo; - int ret; + u32 *palette = info->pseudo_palette; - ret = 0; + if (regno >= 16) + return -EINVAL; - sh7760fb_wait_vsync(info); + /* only FB_VISUAL_TRUECOLOR supported */ - /* request palette access */ - iowrite16(LDPALCR_PALEN, par->base + LDPALCR); + red >>= 16 - info->var.red.length; + green >>= 16 - info->var.green.length; + blue >>= 16 - info->var.blue.length; + transp >>= 16 - info->var.transp.length; - /* poll for access grant */ - tmo = 100; - while (!(ioread16(par->base + LDPALCR) & LDPALCR_PALS) && (--tmo)) - cpu_relax(); + palette[regno] = (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset) | + (transp << info->var.transp.offset); - if (!tmo) { - ret = 1; - dev_dbg(info->dev, "no palette access!\n"); - goto out; - } - - while (l && (s < 256)) { - col = ((*r) & 0xff) << 16; - col |= ((*g) & 0xff) << 8; - col |= ((*b) & 0xff); - col &= SH7760FB_PALETTE_MASK; - iowrite32(col, par->base + LDPR(s)); - - if (s < 16) - ((u32 *) (info->pseudo_palette))[s] = s; - - s++; - l--; - r++; - g++; - b++; - } -out: - iowrite16(0, par->base + LDPALCR); - return ret; + return 0; } static void encode_fix(struct fb_fix_screeninfo *fix, struct fb_info *info, @@ -406,7 +358,7 @@ static struct fb_ops sh7760fb_ops = { .owner = THIS_MODULE, .fb_blank = sh7760fb_blank, .fb_check_var = sh7760fb_check_var, - .fb_setcmap = sh7760fb_setcmap, + .fb_setcolreg = sh7760_setcolreg, .fb_set_par = sh7760fb_set_par, .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index efff672fd7b8e580657440f6bb84744ae05ef1bf..0e2b8fd24df1ed0d1d2de77751fbcfd0cbe2a047 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -16,7 +16,9 @@ #include #include #include +#include #include