Index: trunk/ath_hal/alq.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ trunk/ath_hal/alq.h 2007-10-17 06:50:03.781893143 +0200 @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2002, Jeffrey Roberson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: src/sys/sys/alq.h,v 1.4 2003/06/22 22:28:55 rwatson Exp $ + * + */ +#ifndef _SYS_ALQ_H_ +#define _SYS_ALQ_H_ + +/* + * Opaque type for the Async. Logging Queue + */ +struct alq; + +/* + * Async. Logging Entry + */ +struct ale { + struct ale *ae_next; /* Next Entry */ + char *ae_data; /* Entry buffer */ + int ae_flags; /* Entry flags */ +}; + +#define AE_VALID 1 /* Entry has valid data */ + + +/* waitok options */ +#define ALQ_NOWAIT 0x0001 +#define ALQ_WAITOK 0x0002 + +/* + * alq_open: Creates a new queue + * + * Arguments: + * alq Storage for a pointer to the newly created queue. + * file The filename to open for logging. + * size The size of each entry in the queue. + * count The number of items in the buffer, this should be large enough + * to store items over the period of a disk write. + * limit The maximum number of items to store + * Returns: + * error from open or 0 on success + */ +int alq_open(struct alq **, const char *file, int size, int count, int limit); + +/* + * alq_write: Write data into the queue + * + * Arguments: + * alq The queue we're writing to + * data The entry to be recorded + * waitok Are we permitted to wait? + * + * Returns: + * EWOULDBLOCK if: + * Waitok is ALQ_NOWAIT and the queue is full. + * The system is shutting down. + * 0 on success. + */ +int alq_write(struct alq *alq, void *data, int waitok); + +/* + * alq_flush: Flush the queue out to disk + */ +void alq_flush(struct alq *alq); + +/* + * alq_close: Flush the queue and free all resources. + */ +void alq_close(struct alq *alq); + +/* + * alq_get: Return an entry for direct access + * + * Arguments: + * alq The queue to retrieve an entry from + * waitok Are we permitted to wait? + * + * Returns: + * The next available ale on success. + * NULL if: + * Waitok is ALQ_NOWAIT and the queue is full. + * The system is shutting down. + * + * This leaves the queue locked until a subsequent alq_post. + */ +struct ale *alq_get(struct alq *alq, int waitok); + +/* + * alq_post: Schedule the ale retrieved by alq_get for writing. + * alq The queue to post the entry to. + * ale An asynch logging entry returned by alq_get. + */ +void alq_post(struct alq *, struct ale *); + +#endif /* _SYS_ALQ_H_ */ Index: trunk/ath_hal/kern_alq.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ trunk/ath_hal/kern_alq.c 2007-10-17 06:50:03.785893371 +0200 @@ -0,0 +1,559 @@ +/* + * Copyright (c) 2002-2004, Jeffrey Roberson + * Copyright (c) 2004 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "alq.h" + +/* Async. Logging Queue */ +struct alq { + int aq_entmax; /* Max entries */ + int aq_entlen; /* Entry length */ + char *aq_entbuf; /* Buffer for stored entries */ + int aq_flags; /* Queue flags */ + spinlock_t aq_lock; /* Queue lock */ + wait_queue_head_t aq_waitq; /* sleep/wakeup */ + struct file *aq_fp; /* Open file handle */ + struct ale *aq_first; /* First ent */ + struct ale *aq_entfree; /* First free ent */ + struct ale *aq_entvalid; /* First ent valid for writing */ + int aq_entlimit; /* Max. number of entries per file */ + LIST_ENTRY(alq) aq_act; /* List of active queues */ + LIST_ENTRY(alq) aq_link; /* List of all queues */ +}; + +#define AQ_WANTED 0x0001 /* Wakeup sleeper when io is done */ +#define AQ_ACTIVE 0x0002 /* on the active list */ +#define AQ_FLUSHING 0x0004 /* doing IO */ +#define AQ_SHUTDOWN 0x0008 /* Queue no longer valid */ + +/* + * The ald_lock protects the ald_queues list and the ald_active list. + */ +static spinlock_t ald_lock; +static ATH_LIST_HEAD(, alq) ald_queues; +static ATH_LIST_HEAD(, alq) ald_active; +static int ald_shutingdown = 0; +static pid_t ald_proc = -1; + +#define ALD_LOCK() spin_lock(&ald_lock) +#define ALD_UNLOCK() spin_unlock(&ald_lock) + +DECLARE_WAIT_QUEUE_HEAD(ald_waitq); +#define ALD_WAIT(condition) do { \ + ALD_UNLOCK(); \ + wait_event_interruptible(ald_waitq, condition); \ + ALD_LOCK(); \ +} while (0) +#define ALD_WAKEUP() wake_up_interruptible(&ald_waitq) + +/* Daemon functions */ +static int ald_add(struct alq *); +static int ald_rem(struct alq *); +static void ald_startup(void *); +static int ald_daemon(void *); +static void ald_shutdown(void *, int); +static void ald_activate(struct alq *); +static void ald_deactivate(struct alq *); + +/* Internal queue functions */ +static void alq_shutdown(struct alq *); +static int alq_doio(struct alq *); + + +/* + * Add a new queue to the global list. Fail if we're shutting down. + */ +static int +ald_add(struct alq *alq) +{ + int error; + + error = 0; + + ALD_LOCK(); + if (ald_shutingdown) { + error = -EBUSY; + goto done; + } + LIST_INSERT_HEAD(&ald_queues, alq, aq_link); +done: + ALD_UNLOCK(); + return (error); +} + +/* + * Remove a queue from the global list unless we're shutting down. If so, + * the ald will take care of cleaning up it's resources. + */ +static int +ald_rem(struct alq *alq) +{ + int error; + + error = 0; + + ALD_LOCK(); + if (ald_shutingdown) { + error = -EBUSY; + goto done; + } + LIST_REMOVE(alq, aq_link); +done: + ALD_UNLOCK(); + return (error); +} + +/* + * Put a queue on the active list. This will schedule it for writing. + */ +static void +ald_activate(struct alq *alq) +{ + LIST_INSERT_HEAD(&ald_active, alq, aq_act); + ALD_WAKEUP(); +} + +static void +ald_deactivate(struct alq *alq) +{ + LIST_REMOVE(alq, aq_act); + alq->aq_flags &= ~AQ_ACTIVE; +} + +static void +ald_startup(void *arg) +{ + spin_lock_init(&ald_lock); + LIST_INIT(&ald_queues); + LIST_INIT(&ald_active); +} + +static int +ald_daemon(void *arg) +{ + int needwakeup; + struct alq *alq; + + daemonize("ALQ Daemon"); + allow_signal(SIGKILL); + + ALD_LOCK(); + + for (;;) { + if ((alq = LIST_FIRST(&ald_active)) == NULL) + ALD_WAIT((alq = LIST_FIRST(&ald_active)) != NULL); + + if (signal_pending(current)) + break; + + spin_lock_irq(&alq->aq_lock); + ald_deactivate(alq); + ALD_UNLOCK(); + needwakeup = alq_doio(alq); + spin_unlock_irq(&alq->aq_lock); + if (needwakeup) + wake_up_interruptible(&alq->aq_waitq); + ALD_LOCK(); + } + + ALD_UNLOCK(); + + return 0; +} + +static void +ald_shutdown(void *arg, int howto) +{ + struct alq *alq; + + ALD_LOCK(); + + ald_shutingdown = 1; + + while ((alq = LIST_FIRST(&ald_queues)) != NULL) { + LIST_REMOVE(alq, aq_link); + ALD_UNLOCK(); + alq_shutdown(alq); + ALD_LOCK(); + } + ALD_UNLOCK(); +} + +static void +alq_shutdown(struct alq *alq) +{ + unsigned long flags; + + spin_lock_irqsave(&alq->aq_lock, flags); + + /* Stop any new writers. */ + alq->aq_flags |= AQ_SHUTDOWN; + + /* Drain IO */ + if (alq->aq_flags & (AQ_FLUSHING|AQ_ACTIVE)) { + alq->aq_flags |= AQ_WANTED; + spin_unlock_irqrestore(&alq->aq_lock, flags); + wait_event_interruptible(alq->aq_waitq, + (alq->aq_flags & (AQ_FLUSHING|AQ_ACTIVE)) == 0); + } else + spin_unlock_irqrestore(&alq->aq_lock, flags); + + filp_close(alq->aq_fp, /*XXX*/0); +} + +/* + * Flush all pending data to disk. This operation will block. + */ +static int +alq_doio(struct alq *alq) +{ + mm_segment_t oldfs; + struct iovec aiov[2]; + struct file *fp; + struct ale *ale; + struct ale *alstart; + int totlen; + int iov; + int err; + + fp = alq->aq_fp; + totlen = 0; + iov = 0; + + alstart = ale = alq->aq_entvalid; + alq->aq_entvalid = NULL; + + memset(&aiov, 0, sizeof(aiov)); + + do { + if (aiov[iov].iov_base == NULL) + aiov[iov].iov_base = ale->ae_data; + aiov[iov].iov_len += alq->aq_entlen; + totlen += alq->aq_entlen; + /* Check to see if we're wrapping the buffer */ + if (ale->ae_data + alq->aq_entlen != ale->ae_next->ae_data) + iov++; + ale->ae_flags = 0; + ale = ale->ae_next; + } while (ale->ae_flags & AE_VALID); + + alq->aq_flags |= AQ_FLUSHING; + spin_unlock_irq(&alq->aq_lock); + + if (iov == 2 || aiov[iov].iov_base == NULL) + iov--; + + oldfs = get_fs(); set_fs(KERNEL_DS); + /* XXX ignore errors */ + err = vfs_writev(fp, aiov, iov + 1, &fp->f_pos); + set_fs(oldfs); + if (err >= 0) + dnotify_parent(fp->f_dentry, DN_MODIFY); + + spin_lock_irq(&alq->aq_lock); + alq->aq_flags &= ~AQ_FLUSHING; + + if (alq->aq_entfree == NULL) + alq->aq_entfree = alstart; + + if (alq->aq_flags & AQ_WANTED) { + alq->aq_flags &= ~AQ_WANTED; + return (1); + } + + return(0); +} + + +/* User visible queue functions */ + +/* + * Create the queue data structure, allocate the buffer, and open the file. + */ +int +alq_open(struct alq **alqp, const char *file, int size, int count, int limit) +{ + struct file *f; + struct ale *ale; + struct ale *alp; + struct alq *alq; + char *bufp; + int error; + int i; + + *alqp = NULL; + + /* NB: no O_TRUNC */ + f = filp_open(file, O_WRONLY | O_LARGEFILE | O_CREAT, 0644); + if (IS_ERR(f)) + return PTR_ERR(f); + + alq = kmalloc(sizeof(*alq), GFP_KERNEL); + if (alq == NULL) { + printk("%s: no memory for alq structure\n", __func__); + error = -ENOMEM; + goto bad1; + } + memset(alq, 0, sizeof(*alq)); + alq->aq_entbuf = kmalloc(count * size, GFP_KERNEL); + if (alq->aq_entbuf == NULL) { + printk("%s: no memory for alq entbuf\n", __func__); + error = -ENOMEM; + goto bad2; + } + memset(alq->aq_entbuf, 0, count * size); + alq->aq_first = kmalloc(sizeof(*ale) * count, GFP_KERNEL); + if (alq->aq_first == NULL) { + printk("%s: no memory for alq entries\n", __func__); + error = -ENOMEM; + goto bad3; + } + memset(alq->aq_first, 0, sizeof(*ale) * count); + alq->aq_fp = f; + alq->aq_entmax = count; + alq->aq_entlen = size; + alq->aq_entlimit = limit; + alq->aq_entfree = alq->aq_first; + spin_lock_init(&alq->aq_lock); + init_waitqueue_head(&alq->aq_waitq); + + bufp = alq->aq_entbuf; + ale = alq->aq_first; + alp = NULL; + + /* Match up entries with buffers */ + for (i = 0; i < count; i++) { + if (alp) + alp->ae_next = ale; + ale->ae_data = bufp; + alp = ale; + ale++; + bufp += size; + } + + alp->ae_next = alq->aq_first; + + if ((error = ald_add(alq)) != 0) { + printk("%s: unable to add alq, probably shutting down\n", + __func__); + goto bad4; + } + *alqp = alq; + + /* XXX bump module refcnt */ + + return (0); +bad4: + kfree(alq->aq_first); +bad3: + kfree(alq->aq_entbuf); +bad2: + kfree(alq); +bad1: + filp_close(f, /*XXX*/0); + return error; +} +EXPORT_SYMBOL(alq_open); + +/* + * Copy a new entry into the queue. If the operation would block either + * wait or return an error depending on the value of waitok. + */ +int +alq_write(struct alq *alq, void *data, int waitok) +{ + unsigned long flags; + struct ale *ale; + + local_irq_save(flags); + if ((ale = alq_get(alq, waitok)) == NULL) { + local_irq_restore(flags); + return EWOULDBLOCK; + } + memcpy(ale->ae_data, data, alq->aq_entlen); + alq_post(alq, ale); + local_irq_restore(flags); + + return 0; +} +EXPORT_SYMBOL(alq_write); + +struct ale * +alq_get(struct alq *alq, int waitok) +{ + struct ale *ale; + struct ale *aln; + + ale = NULL; + + /* XXX caller must block irq */ + spin_lock(&alq->aq_lock); + + /* Loop until we get an entry or we're shutting down */ + if ((alq->aq_entlimit > 0) && + (alq->aq_flags & AQ_SHUTDOWN) == 0 && + (ale = alq->aq_entfree) == NULL && + (waitok & ALQ_WAITOK)) { + alq->aq_flags |= AQ_WANTED; + spin_unlock(&alq->aq_lock); + wait_event_interruptible(alq->aq_waitq, + (alq->aq_flags & AQ_SHUTDOWN) || + (ale = alq->aq_entfree) != NULL || + (waitok & ALQ_WAITOK) == 0); + spin_lock(&alq->aq_lock); + } + + if (ale != NULL) { + alq->aq_entlimit--; + aln = ale->ae_next; + if ((aln->ae_flags & AE_VALID) == 0) + alq->aq_entfree = aln; + else + alq->aq_entfree = NULL; + } else + spin_unlock(&alq->aq_lock); + + return (ale); +} +EXPORT_SYMBOL(alq_get); + +void +alq_post(struct alq *alq, struct ale *ale) +{ + int activate; + + ale->ae_flags |= AE_VALID; + + if (alq->aq_entvalid == NULL) + alq->aq_entvalid = ale; + + if ((alq->aq_flags & AQ_ACTIVE) == 0) { + alq->aq_flags |= AQ_ACTIVE; + activate = 1; + } else + activate = 0; + + spin_unlock(&alq->aq_lock); + if (activate) { + ALD_LOCK(); + ald_activate(alq); + ALD_UNLOCK(); + } +} +EXPORT_SYMBOL(alq_post); + +void +alq_flush(struct alq *alq) +{ + int needwakeup = 0; + + ALD_LOCK(); + spin_lock_irq(&alq->aq_lock); + if (alq->aq_flags & AQ_ACTIVE) { + ald_deactivate(alq); + ALD_UNLOCK(); + needwakeup = alq_doio(alq); + } else + ALD_UNLOCK(); + spin_unlock_irq(&alq->aq_lock); + + if (needwakeup) + wake_up_interruptible(&alq->aq_waitq); +} +EXPORT_SYMBOL(alq_flush); + +/* + * Flush remaining data, close the file and free all resources. + */ +void +alq_close(struct alq *alq) +{ + /* + * If we're already shuting down someone else will flush and close + * the vnode. + */ + if (ald_rem(alq) != 0) + return; + + /* + * Drain all pending IO. + */ + alq_shutdown(alq); + + /* XXX drop module refcnt */ + + kfree(alq->aq_first); + kfree(alq->aq_entbuf); + kfree(alq); +} +EXPORT_SYMBOL(alq_close); + +/* + * Module glue. + */ +static char *version = "0.1"; +static char *mod_info = "alq"; + +MODULE_AUTHOR("Errno Consulting, Sam Leffler"); +MODULE_DESCRIPTION("Low-overhead event collection package"); +#ifdef MODULE_LICENSE +MODULE_LICENSE("Dual BSD/GPL"); +#endif + +static int __init +init_alq(void) +{ + printk(KERN_INFO "%s: version %s\n", mod_info, version); + ald_startup(NULL); + ald_proc = kernel_thread(ald_daemon, NULL, CLONE_KERNEL); + return 0; +} +module_init(init_alq); + +static void __exit +exit_alq(void) +{ + if (ald_proc != -1) + kill_proc(ald_proc, SIGKILL, -1); + ald_shutdown(NULL, 0); + printk(KERN_INFO "%s: driver unloaded\n", mod_info); +} +module_exit(exit_alq); Index: trunk/ath_hal/Makefile =================================================================== --- trunk.orig/ath_hal/Makefile 2007-10-17 06:49:13.207011046 +0200 +++ trunk/ath_hal/Makefile 2007-10-17 06:50:03.793893828 +0200 @@ -60,9 +60,15 @@ export-objs := ah_os.o endif +ifdef ALQ +obj-m += alq.o +alq-objs := kern_alq.o +EXTRA_CFLAGS += -DAH_DEBUG_ALQ -DAH_DEBUG +endif + INCS += -I$(ATH_HAL) -I$(HAL) -EXTRA_CFLAGS+= $(INCS) $(COPTS) -DOPT_AH_H=\"public/$(TARGET).opt_ah.h\" +EXTRA_CFLAGS+= $(INCS) $(COPTS) -DOPT_AH_H=\"public/$(TARGET).opt_ah.h\" $(if $(MMIOTRACE),-DMMIOTRACE=1) ifneq (,$(filter xscale% arm%,$(TARGET))) LDFLAGS += --no-warn-mismatch Index: trunk/ath_hal/ah_os.c =================================================================== --- trunk.orig/ath_hal/ah_os.c 2007-10-17 06:49:13.203010817 +0200 +++ trunk/ath_hal/ah_os.c 2007-10-17 07:00:34.009807788 +0200 @@ -147,6 +147,13 @@ } #endif /* AH_ASSERT */ +#ifdef AH_DEBUG +/* Store the current function name (should be called by wrapper functions) + * useful for debugging and figuring out, which hal function sets which + * registers */ +char *ath_hal_func = NULL; +#endif + #ifdef AH_DEBUG_ALQ /* * ALQ register tracing support. @@ -161,15 +168,15 @@ * NB: doesn't handle multiple devices properly; only one DEVICE record * is emitted and the different devices are not identified. */ -#include "alq/alq.h" -#include "ah_decode.h" +#include "alq.h" -static struct alq *ath_hal_alq; -static int ath_hal_alq_emitdev; /* need to emit DEVICE record */ +static struct alq *ath_hal_alq = NULL; static u_int ath_hal_alq_lost; /* count of lost records */ static const char *ath_hal_logfile = "/tmp/ath_hal.log"; static u_int ath_hal_alq_qsize = 8*1024; +#define MSG_MAXLEN 64 + static int ath_hal_setlogging(int enable) { @@ -179,9 +186,8 @@ if (!capable(CAP_NET_ADMIN)) return -EPERM; error = alq_open(&ath_hal_alq, ath_hal_logfile, - sizeof (struct athregrec), ath_hal_alq_qsize); + MSG_MAXLEN, ath_hal_alq_qsize, (enable == 1 ? 0x7fffffff : enable)); ath_hal_alq_lost = 0; - ath_hal_alq_emitdev = 1; printk("ath_hal: logging to %s %s\n", ath_hal_logfile, error == 0 ? "enabled" : "could not be setup"); } else { @@ -224,110 +230,35 @@ return ath_hal_setlogging(enable); } -/* -This should only be called while holding the lock, sc->sc_hal_lock. -*/ -static struct ale * -ath_hal_alq_get(struct ath_hal *ah) +void ath_hal_logmsg(struct ath_hal *ah, u8 write, u_int reg, u_int32_t val) { struct ale *ale; - if (ath_hal_alq_emitdev) { - ale = alq_get(ath_hal_alq, ALQ_NOWAIT); - if (ale) { - struct athregrec *r = - (struct athregrec *) ale->ae_data; - r->op = OP_DEVICE; - r->reg = 0; - r->val = ah->ah_devid; - alq_post(ath_hal_alq, ale); - ath_hal_alq_emitdev = 0; - } else - ath_hal_alq_lost++; - } + + if (!ath_hal_alq) + return; + ale = alq_get(ath_hal_alq, ALQ_NOWAIT); - if (!ale) + if (!ale) { ath_hal_alq_lost++; - return ale; -} - -/* -This should only be called while holding the lock, sc->sc_hal_lock. -*/ -void __ahdecl -ath_hal_reg_write(struct ath_hal *ah, u_int32_t reg, u_int32_t val) -{ - if (ath_hal_alq) { - unsigned long flags; - struct ale *ale; - - local_irq_save(flags); - ale = ath_hal_alq_get(ah); - if (ale) { - struct athregrec *r = (struct athregrec *) ale->ae_data; - r->op = OP_WRITE; - r->reg = reg; - r->val = val; - alq_post(ath_hal_alq, ale); - } - local_irq_restore(flags); + return; } - _OS_REG_WRITE(ah, reg, val); + + memset(ale->ae_data, 0, MSG_MAXLEN); + sprintf(ale->ae_data, "%s:0x%05x = 0x%08x - %s\n", (write ? "W" : "R"), reg, val, (ath_hal_func ?: "unknown")); + alq_post(ath_hal_alq, ale); } -EXPORT_SYMBOL(ath_hal_reg_write); +EXPORT_SYMBOL(ath_hal_logmsg); -/* -This should only be called while holding the lock, sc->sc_hal_lock. -*/ -u_int32_t __ahdecl -ath_hal_reg_read(struct ath_hal *ah, u_int32_t reg) -{ - u_int32_t val; - val = _OS_REG_READ(ah, reg); - if (ath_hal_alq) { - unsigned long flags; - struct ale *ale; - - ale = ath_hal_alq_get(ah); - if (ale) { - struct athregrec *r = (struct athregrec *) ale->ae_data; - r->op = OP_READ; - r->reg = reg; - r->val = val; - alq_post(ath_hal_alq, ale); - } - } - return val; -} -EXPORT_SYMBOL(ath_hal_reg_read); +#elif defined(AH_DEBUG) || defined(AH_REGOPS_FUNC) -/* - * This should only be called while holding the lock, sc->sc_hal_lock. - */ -void __ahdecl -OS_MARK(struct ath_hal *ah, u_int id, u_int32_t v) +void ath_hal_logmsg(struct ath_hal *ah, u8 write, u_int reg, u_int32_t val) { - if (ath_hal_alq) { - struct ale *ale; - - ale = ath_hal_alq_get(ah); - if (ale) { - struct athregrec *r = (struct athregrec *) ale->ae_data; - r->op = OP_MARK; - r->reg = id; - r->val = v; - alq_post(ath_hal_alq, ale); - } - } + if (!ah) + return; + ath_hal_printf(ah, "%s:0x%04x = 0x%08x - %s\n", (write ? "W" : "R"), reg, val, (ath_hal_func ?: "unknown")); } -EXPORT_SYMBOL(OS_MARK); -#elif defined(AH_DEBUG) || defined(AH_REGOPS_FUNC) +EXPORT_SYMBOL(ath_hal_logmsg); -#ifdef AH_DEBUG -/* Store the current function name (should be called by wrapper functions) - * useful for debugging and figuring out, which hal function sets which - * registers */ -char *ath_hal_func = NULL; -#endif /* * Memory-mapped device register read/write. These are here @@ -346,8 +277,7 @@ { #ifdef AH_DEBUG if (ath_hal_debug > 1) - ath_hal_printf(ah, "%s: WRITE 0x%x <= 0x%x\n", - (ath_hal_func ?: "unknown"), reg, val); + ath_hal_logmsg(ah, 0, reg, val); #endif _OS_REG_WRITE(ah, reg, val); } @@ -362,8 +292,7 @@ val = _OS_REG_READ(ah, reg); #ifdef AH_DEBUG if (ath_hal_debug > 1) - ath_hal_printf(ah, "%s: READ 0x%x => 0x%x\n", - (ath_hal_func ?: "unknown"), reg, val); + ath_hal_logmsg(ah, 1, reg, val); #endif return val; } @@ -580,11 +509,18 @@ EXPORT_SYMBOL(ath_hal_mhz2ieee); EXPORT_SYMBOL(ath_hal_process_noisefloor); +#ifdef MMIOTRACE +extern void (*kmmio_logmsg)(struct ath_hal *ah, u8 write, u_int reg, u_int32_t val); +#endif + static int __init init_ath_hal(void) { const char *sep; int i; +#ifdef MMIOTRACE + kmmio_logmsg = ath_hal_logmsg; +#endif printk(KERN_INFO "%s: %s (", dev_info, ath_hal_version); sep = ""; @@ -601,6 +537,9 @@ static void __exit exit_ath_hal(void) { +#ifdef MMIOTRACE + kmmio_logmsg = NULL; +#endif ath_hal_sysctl_unregister(); printk(KERN_INFO "%s: driver unloaded\n", dev_info); }